1/* resbin.c -- manipulate the Windows binary resource format.
2   Copyright 1997, 1998, 1999, 2002, 2003, 2007
3   Free Software Foundation, Inc.
4   Written by Ian Lance Taylor, Cygnus Support.
5   Rewritten by Kai Tietz, Onevision.
6
7   This file is part of GNU Binutils.
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22   02110-1301, USA.  */
23
24/* This file contains functions to convert between the binary resource
25   format and the internal structures that we want to use.  The same
26   binary resource format is used in both res and COFF files.  */
27
28#include "sysdep.h"
29#include "bfd.h"
30#include "bucomm.h"
31#include "libiberty.h"
32#include "windres.h"
33
34/* Local functions.  */
35
36static void toosmall (const char *);
37
38static unichar *get_unicode (windres_bfd *, const bfd_byte *, rc_uint_type, rc_uint_type *);
39static int get_resid (windres_bfd *, rc_res_id *, const bfd_byte *, rc_uint_type);
40static rc_res_resource *bin_to_res_generic (windres_bfd *, enum rc_res_type,
41					    const bfd_byte *, rc_uint_type);
42static rc_res_resource *bin_to_res_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
43static rc_res_resource *bin_to_res_menu (windres_bfd *,const bfd_byte *, rc_uint_type);
44static rc_menuitem *bin_to_res_menuitems (windres_bfd *, const bfd_byte *, rc_uint_type,
45					  rc_uint_type *);
46static rc_menuitem *bin_to_res_menuexitems (windres_bfd *, const bfd_byte *, rc_uint_type,
47					    rc_uint_type *);
48static rc_res_resource *bin_to_res_dialog (windres_bfd *, const bfd_byte *, rc_uint_type);
49static rc_res_resource *bin_to_res_string (windres_bfd *,const bfd_byte *, rc_uint_type);
50static rc_res_resource *bin_to_res_fontdir (windres_bfd *, const bfd_byte *, rc_uint_type);
51static rc_res_resource *bin_to_res_accelerators (windres_bfd *, const bfd_byte *, rc_uint_type);
52static rc_res_resource *bin_to_res_rcdata (windres_bfd *, const bfd_byte *, rc_uint_type, int);
53static rc_res_resource *bin_to_res_group_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
54static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *, rc_uint_type);
55static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
56static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
57static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
58static void get_version_header (windres_bfd *, const bfd_byte *, rc_uint_type, const char *,
59				unichar **, rc_uint_type *, rc_uint_type *, rc_uint_type *,
60				rc_uint_type *);
61
62/* Given a resource type ID, a pointer to data, a length, return a
63   rc_res_resource structure which represents that resource.  The caller
64   is responsible for initializing the res_info and coff_info fields
65   of the returned structure.  */
66
67rc_res_resource *
68bin_to_res (windres_bfd *wrbfd, rc_res_id type, const bfd_byte *data,
69	    rc_uint_type length)
70{
71  if (type.named)
72    return bin_to_res_userdata (wrbfd, data, length);
73  else
74    {
75      switch (type.u.id)
76	{
77	default:
78	  return bin_to_res_userdata (wrbfd, data, length);
79	case RT_CURSOR:
80	  return bin_to_res_cursor (wrbfd, data, length);
81	case RT_BITMAP:
82	  return bin_to_res_generic (wrbfd, RES_TYPE_BITMAP, data, length);
83	case RT_ICON:
84	  return bin_to_res_generic (wrbfd, RES_TYPE_ICON, data, length);
85	case RT_MENU:
86	  return bin_to_res_menu (wrbfd, data, length);
87	case RT_DIALOG:
88	  return bin_to_res_dialog (wrbfd, data, length);
89	case RT_STRING:
90	  return bin_to_res_string (wrbfd, data, length);
91	case RT_FONTDIR:
92	  return bin_to_res_fontdir (wrbfd, data, length);
93	case RT_FONT:
94	  return bin_to_res_generic (wrbfd, RES_TYPE_FONT, data, length);
95	case RT_ACCELERATOR:
96	  return bin_to_res_accelerators (wrbfd, data, length);
97	case RT_RCDATA:
98	  return bin_to_res_rcdata (wrbfd, data, length, RES_TYPE_RCDATA);
99	case RT_MESSAGETABLE:
100	  return bin_to_res_generic (wrbfd, RES_TYPE_MESSAGETABLE, data, length);
101	case RT_GROUP_CURSOR:
102	  return bin_to_res_group_cursor (wrbfd, data, length);
103	case RT_GROUP_ICON:
104	  return bin_to_res_group_icon (wrbfd, data, length);
105	case RT_VERSION:
106	  return bin_to_res_version (wrbfd, data, length);
107	case RT_TOOLBAR:
108	  return  bin_to_res_toolbar (wrbfd, data, length);
109
110	}
111    }
112}
113
114/* Give an error if the binary data is too small.  */
115
116static void
117toosmall (const char *msg)
118{
119  fatal (_("%s: not enough binary data"), msg);
120}
121
122/* Swap in a NULL terminated unicode string.  */
123
124static unichar *
125get_unicode (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
126	     rc_uint_type *retlen)
127{
128  rc_uint_type c, i;
129  unichar *ret;
130
131  c = 0;
132  while (1)
133    {
134      if (length < c * 2 + 2)
135	toosmall (_("null terminated unicode string"));
136      if (windres_get_16 (wrbfd, data + c * 2, 2) == 0)
137	break;
138      ++c;
139    }
140
141  ret = (unichar *) res_alloc ((c + 1) * sizeof (unichar));
142
143  for (i = 0; i < c; i++)
144    ret[i] = windres_get_16 (wrbfd, data + i * 2, 2);
145  ret[i] = 0;
146
147  if (retlen != NULL)
148    *retlen = c;
149
150  return ret;
151}
152
153/* Get a resource identifier.  This returns the number of bytes used.  */
154
155static int
156get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
157	   rc_uint_type length)
158{
159  rc_uint_type first;
160
161  if (length < 2)
162    toosmall (_("resource ID"));
163
164  first = windres_get_16 (wrbfd, data, 2);
165  if (first == 0xffff)
166    {
167      if (length < 4)
168	toosmall (_("resource ID"));
169      id->named = 0;
170      id->u.id = windres_get_16 (wrbfd, data + 2, 2);
171      return 4;
172    }
173  else
174    {
175      id->named = 1;
176      id->u.n.name = get_unicode (wrbfd, data, length, &id->u.n.length);
177      return id->u.n.length * 2 + 2;
178    }
179}
180
181/* Convert a resource which just stores uninterpreted data from
182   binary.  */
183
184rc_res_resource *
185bin_to_res_generic (windres_bfd *wrbfd ATTRIBUTE_UNUSED, enum rc_res_type type,
186		    const bfd_byte *data, rc_uint_type length)
187{
188  rc_res_resource *r;
189
190  r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
191  r->type = type;
192  r->u.data.data = data;
193  r->u.data.length = length;
194
195  return r;
196}
197
198/* Convert a cursor resource from binary.  */
199
200rc_res_resource *
201bin_to_res_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
202{
203  rc_cursor *c;
204  rc_res_resource *r;
205
206  if (length < 4)
207    toosmall (_("cursor"));
208
209  c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
210  c->xhotspot = windres_get_16 (wrbfd, data, 2);
211  c->yhotspot = windres_get_16 (wrbfd, data + 2, 2);
212  c->length = length - 4;
213  c->data = data + 4;
214
215  r = (rc_res_resource *) res_alloc (sizeof *r);
216  r->type = RES_TYPE_CURSOR;
217  r->u.cursor = c;
218
219  return r;
220}
221
222/* Convert a menu resource from binary.  */
223
224rc_res_resource *
225bin_to_res_menu (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
226{
227  rc_res_resource *r;
228  rc_menu *m;
229  rc_uint_type version, read;
230
231  r = (rc_res_resource *) res_alloc (sizeof *r);
232  r->type = RES_TYPE_MENU;
233
234  m = (rc_menu *) res_alloc (sizeof (rc_menu));
235  r->u.menu = m;
236
237  if (length < 2)
238    toosmall (_("menu header"));
239
240  version = windres_get_16 (wrbfd, data, 2);
241
242  if (version == 0)
243    {
244      if (length < 4)
245	toosmall (_("menu header"));
246      m->help = 0;
247      m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &read);
248    }
249  else if (version == 1)
250    {
251      rc_uint_type offset;
252
253      if (length < 8)
254	toosmall (_("menuex header"));
255      m->help = windres_get_32 (wrbfd, data + 4, 4);
256      offset = windres_get_16 (wrbfd, data + 2, 2);
257      if (offset + 4 >= length)
258	toosmall (_("menuex offset"));
259      m->items = bin_to_res_menuexitems (wrbfd, data + 4 + offset,
260					 length - (4 + offset), &read);
261    }
262  else
263    fatal (_("unsupported menu version %d"), (int) version);
264
265  return r;
266}
267
268/* Convert menu items from binary.  */
269
270static rc_menuitem *
271bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
272		      rc_uint_type *read)
273{
274  rc_menuitem *first, **pp;
275
276  first = NULL;
277  pp = &first;
278
279  *read = 0;
280
281  while (length > 0)
282    {
283      rc_uint_type flags, slen, itemlen;
284      rc_uint_type stroff;
285      rc_menuitem *mi;
286
287      if (length < 4)
288	toosmall (_("menuitem header"));
289
290      mi = (rc_menuitem *) res_alloc (sizeof *mi);
291      mi->state = 0;
292      mi->help = 0;
293
294      flags = windres_get_16 (wrbfd, data, 2);
295      mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);
296
297      if ((flags & MENUITEM_POPUP) == 0)
298	stroff = 4;
299      else
300	stroff = 2;
301
302      if (length < stroff + 2)
303	toosmall (_("menuitem header"));
304
305      if (windres_get_16 (wrbfd, data + stroff, 2) == 0)
306	{
307	  slen = 0;
308	  mi->text = NULL;
309	}
310      else
311	mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
312
313      itemlen = stroff + slen * 2 + 2;
314
315      if ((flags & MENUITEM_POPUP) == 0)
316	{
317	  mi->popup = NULL;
318	  mi->id = windres_get_16 (wrbfd, data + 2, 2);
319	}
320      else
321	{
322	  rc_uint_type subread;
323
324	  mi->id = 0;
325	  mi->popup = bin_to_res_menuitems (wrbfd, data + itemlen, length - itemlen,
326	  				    &subread);
327	  itemlen += subread;
328	}
329
330      mi->next = NULL;
331      *pp = mi;
332      pp = &mi->next;
333
334      data += itemlen;
335      length -= itemlen;
336      *read += itemlen;
337
338      if ((flags & MENUITEM_ENDMENU) != 0)
339	return first;
340    }
341
342  return first;
343}
344
345/* Convert menuex items from binary.  */
346
347static rc_menuitem *
348bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
349			rc_uint_type *read)
350{
351  rc_menuitem *first, **pp;
352
353  first = NULL;
354  pp = &first;
355
356  *read = 0;
357
358  while (length > 0)
359    {
360      rc_uint_type flags, slen;
361      rc_uint_type itemlen;
362      rc_menuitem *mi;
363
364      if (length < 16)
365	toosmall (_("menuitem header"));
366
367      mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
368      mi->type = windres_get_32 (wrbfd, data, 4);
369      mi->state = windres_get_32 (wrbfd, data + 4, 4);
370      mi->id = windres_get_32 (wrbfd, data + 8, 4);
371
372      flags = windres_get_16 (wrbfd, data + 12, 2);
373
374      if (windres_get_16 (wrbfd, data + 14, 2) == 0)
375	{
376	  slen = 0;
377	  mi->text = NULL;
378	}
379      else
380	mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
381
382      itemlen = 14 + slen * 2 + 2;
383      itemlen = (itemlen + 3) &~ 3;
384
385      if ((flags & 1) == 0)
386	{
387	  mi->popup = NULL;
388	  mi->help = 0;
389	}
390      else
391	{
392	  rc_uint_type subread;
393
394	  if (length < itemlen + 4)
395	    toosmall (_("menuitem"));
396	  mi->help = windres_get_32 (wrbfd, data + itemlen, 4);
397	  itemlen += 4;
398
399	  mi->popup = bin_to_res_menuexitems (wrbfd, data + itemlen,
400					      length - itemlen, &subread);
401	  itemlen += subread;
402	}
403
404      mi->next = NULL;
405      *pp = mi;
406      pp = &mi->next;
407
408      data += itemlen;
409      length -= itemlen;
410      *read += itemlen;
411
412      if ((flags & 0x80) != 0)
413	return first;
414    }
415
416  return first;
417}
418
419/* Convert a dialog resource from binary.  */
420
421static rc_res_resource *
422bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
423{
424  rc_uint_type signature;
425  rc_dialog *d;
426  rc_uint_type c, sublen, i;
427  rc_uint_type off;
428  rc_dialog_control **pp;
429  rc_res_resource *r;
430
431  if (length < 18)
432    toosmall (_("dialog header"));
433
434  d = (rc_dialog *) res_alloc (sizeof (rc_dialog));
435
436  signature = windres_get_16 (wrbfd, data + 2, 2);
437  if (signature != 0xffff)
438    {
439      d->ex = NULL;
440      d->style = windres_get_32 (wrbfd, data, 4);
441      d->exstyle = windres_get_32 (wrbfd, data + 4, 4);
442      off = 8;
443    }
444  else
445    {
446      int version;
447
448      version = windres_get_16 (wrbfd, data, 2);
449      if (version != 1)
450	fatal (_("unexpected DIALOGEX version %d"), version);
451
452      d->ex = (rc_dialog_ex *) res_alloc (sizeof (rc_dialog_ex));
453      d->ex->help = windres_get_32 (wrbfd, data + 4, 4);
454      d->exstyle = windres_get_32 (wrbfd, data + 8, 4);
455      d->style = windres_get_32 (wrbfd, data + 12, 4);
456      off = 16;
457    }
458
459  if (length < off + 10)
460    toosmall (_("dialog header"));
461
462  c = windres_get_16 (wrbfd, data + off, 2);
463  d->x = windres_get_16 (wrbfd, data + off + 2, 2);
464  d->y = windres_get_16 (wrbfd, data + off + 4, 2);
465  d->width = windres_get_16 (wrbfd, data + off + 6, 2);
466  d->height = windres_get_16 (wrbfd, data + off + 8, 2);
467
468  off += 10;
469
470  sublen = get_resid (wrbfd, &d->menu, data + off, length - off);
471  off += sublen;
472
473  sublen = get_resid (wrbfd, &d->class, data + off, length - off);
474  off += sublen;
475
476  d->caption = get_unicode (wrbfd, data + off, length - off, &sublen);
477  off += sublen * 2 + 2;
478  if (sublen == 0)
479    d->caption = NULL;
480
481  if ((d->style & DS_SETFONT) == 0)
482    {
483      d->pointsize = 0;
484      d->font = NULL;
485      if (d->ex != NULL)
486	{
487	  d->ex->weight = 0;
488	  d->ex->italic = 0;
489	  d->ex->charset = 1; /* Default charset.  */
490	}
491    }
492  else
493    {
494      if (length < off + 2)
495	toosmall (_("dialog font point size"));
496
497      d->pointsize = windres_get_16 (wrbfd, data + off, 2);
498      off += 2;
499
500      if (d->ex != NULL)
501	{
502	  if (length < off + 4)
503	    toosmall (_("dialogex font information"));
504	  d->ex->weight = windres_get_16 (wrbfd, data + off, 2);
505	  d->ex->italic = windres_get_8 (wrbfd, data + off + 2, 1);
506	  d->ex->charset = windres_get_8 (wrbfd, data + off + 3, 1);
507	  off += 4;
508	}
509
510      d->font = get_unicode (wrbfd, data + off, length - off, &sublen);
511      off += sublen * 2 + 2;
512    }
513
514  d->controls = NULL;
515  pp = &d->controls;
516
517  for (i = 0; i < c; i++)
518    {
519      rc_dialog_control *dc;
520      int datalen;
521
522      off = (off + 3) &~ 3;
523
524      dc = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
525
526      if (d->ex == NULL)
527	{
528	  if (length < off + 8)
529	    toosmall (_("dialog control"));
530
531	  dc->style = windres_get_32 (wrbfd, data + off, 4);
532	  dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
533	  dc->help = 0;
534	  off += 8;
535	}
536      else
537	{
538	  if (length < off + 12)
539	    toosmall (_("dialogex control"));
540	  dc->help = windres_get_32 (wrbfd, data + off, 4);
541	  dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
542	  dc->style = windres_get_32 (wrbfd, data + off + 8, 4);
543	  off += 12;
544	}
545
546      if (length < off + (d->ex != NULL ? 2 : 0) + 10)
547	toosmall (_("dialog control"));
548
549      dc->x = windres_get_16 (wrbfd, data + off, 2);
550      dc->y = windres_get_16 (wrbfd, data + off + 2, 2);
551      dc->width = windres_get_16 (wrbfd, data + off + 4, 2);
552      dc->height = windres_get_16 (wrbfd, data + off + 6, 2);
553
554      if (d->ex != NULL)
555	dc->id = windres_get_32 (wrbfd, data + off + 8, 4);
556      else
557	dc->id = windres_get_16 (wrbfd, data + off + 8, 2);
558
559      off += 10 + (d->ex != NULL ? 2 : 0);
560
561      sublen = get_resid (wrbfd, &dc->class, data + off, length - off);
562      off += sublen;
563
564      sublen = get_resid (wrbfd, &dc->text, data + off, length - off);
565      off += sublen;
566
567      if (length < off + 2)
568	toosmall (_("dialog control end"));
569
570      datalen = windres_get_16 (wrbfd, data + off, 2);
571      off += 2;
572
573      if (datalen == 0)
574	dc->data = NULL;
575      else
576	{
577	  off = (off + 3) &~ 3;
578
579	  if (length < off + datalen)
580	    toosmall (_("dialog control data"));
581
582	  dc->data = ((rc_rcdata_item *)
583		      res_alloc (sizeof (rc_rcdata_item)));
584	  dc->data->next = NULL;
585	  dc->data->type = RCDATA_BUFFER;
586	  dc->data->u.buffer.length = datalen;
587	  dc->data->u.buffer.data = data + off;
588
589	  off += datalen;
590	}
591
592      dc->next = NULL;
593      *pp = dc;
594      pp = &dc->next;
595    }
596
597  r = (rc_res_resource *) res_alloc (sizeof *r);
598  r->type = RES_TYPE_DIALOG;
599  r->u.dialog = d;
600
601  return r;
602}
603
604/* Convert a stringtable resource from binary.  */
605
606static rc_res_resource *
607bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
608{
609  rc_stringtable *st;
610  int i;
611  rc_res_resource *r;
612
613  st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
614
615  for (i = 0; i < 16; i++)
616    {
617      unsigned int slen;
618
619      if (length < 2)
620	toosmall (_("stringtable string length"));
621      slen = windres_get_16 (wrbfd, data, 2);
622      st->strings[i].length = slen;
623
624      if (slen > 0)
625	{
626	  unichar *s;
627	  unsigned int j;
628
629	  if (length < 2 + 2 * slen)
630	    toosmall (_("stringtable string"));
631
632	  s = (unichar *) res_alloc (slen * sizeof (unichar));
633	  st->strings[i].string = s;
634
635	  for (j = 0; j < slen; j++)
636	    s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
637	}
638
639      data += 2 + 2 * slen;
640      length -= 2 + 2 * slen;
641    }
642
643  r = (rc_res_resource *) res_alloc (sizeof *r);
644  r->type = RES_TYPE_STRINGTABLE;
645  r->u.stringtable = st;
646
647  return r;
648}
649
650/* Convert a fontdir resource from binary.  */
651
652static rc_res_resource *
653bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
654{
655  rc_uint_type c, i;
656  rc_fontdir *first, **pp;
657  rc_res_resource *r;
658
659  if (length < 2)
660    toosmall (_("fontdir header"));
661
662  c = windres_get_16 (wrbfd, data, 2);
663
664  first = NULL;
665  pp = &first;
666
667  for (i = 0; i < c; i++)
668    {
669      const struct bin_fontdir_item *bfi;
670      rc_fontdir *fd;
671      unsigned int off;
672
673      if (length < 56)
674	toosmall (_("fontdir"));
675
676      bfi = (const struct bin_fontdir_item *) data;
677      fd = (rc_fontdir *) res_alloc (sizeof *fd);
678      fd->index = windres_get_16 (wrbfd, bfi->index, 2);
679
680      /* To work out the length of the fontdir data, we must get the
681         length of the device name and face name strings, even though
682         we don't store them in the rc_fontdir.  The
683         documentation says that these are NULL terminated char
684         strings, not Unicode strings.  */
685
686      off = 56;
687
688      while (off < length && data[off] != '\0')
689	++off;
690      if (off >= length)
691	toosmall (_("fontdir device name"));
692      ++off;
693
694      while (off < length && data[off] != '\0')
695	++off;
696      if (off >= length)
697	toosmall (_("fontdir face name"));
698      ++off;
699
700      fd->length = off;
701      fd->data = data;
702
703      fd->next = NULL;
704      *pp = fd;
705      pp = &fd->next;
706
707      /* The documentation does not indicate that any rounding is
708         required.  */
709
710      data += off;
711      length -= off;
712    }
713
714  r = (rc_res_resource *) res_alloc (sizeof *r);
715  r->type = RES_TYPE_FONTDIR;
716  r->u.fontdir = first;
717
718  return r;
719}
720
721/* Convert an accelerators resource from binary.  */
722
723static rc_res_resource *
724bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
725{
726  rc_accelerator *first, **pp;
727  rc_res_resource *r;
728
729  first = NULL;
730  pp = &first;
731
732  while (1)
733    {
734      rc_accelerator *a;
735
736      if (length < 8)
737	toosmall (_("accelerator"));
738
739      a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
740
741      a->flags = windres_get_16 (wrbfd, data, 2);
742      a->key = windres_get_16 (wrbfd, data + 2, 2);
743      a->id = windres_get_16 (wrbfd, data + 4, 2);
744
745      a->next = NULL;
746      *pp = a;
747      pp = &a->next;
748
749      if ((a->flags & ACC_LAST) != 0)
750	break;
751
752      data += 8;
753      length -= 8;
754    }
755
756  r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
757  r->type = RES_TYPE_ACCELERATOR;
758  r->u.acc = first;
759
760  return r;
761}
762
763/* Convert an rcdata resource from binary.  */
764
765static rc_res_resource *
766bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
767		   rc_uint_type length, int rctyp)
768{
769  rc_rcdata_item *ri;
770  rc_res_resource *r;
771
772  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
773
774  ri->next = NULL;
775  ri->type = RCDATA_BUFFER;
776  ri->u.buffer.length = length;
777  ri->u.buffer.data = data;
778
779  r = (rc_res_resource *) res_alloc (sizeof *r);
780  r->type = rctyp;
781  r->u.rcdata = ri;
782
783  return r;
784}
785
786/* Convert a group cursor resource from binary.  */
787
788static rc_res_resource *
789bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
790{
791  int type, c, i;
792  rc_group_cursor *first, **pp;
793  rc_res_resource *r;
794
795  if (length < 6)
796    toosmall (_("group cursor header"));
797
798  type = windres_get_16 (wrbfd, data + 2, 2);
799  if (type != 2)
800    fatal (_("unexpected group cursor type %d"), type);
801
802  c = windres_get_16 (wrbfd, data + 4, 2);
803
804  data += 6;
805  length -= 6;
806
807  first = NULL;
808  pp = &first;
809
810  for (i = 0; i < c; i++)
811    {
812      rc_group_cursor *gc;
813
814      if (length < 14)
815	toosmall (_("group cursor"));
816
817      gc = (rc_group_cursor *) res_alloc (sizeof *gc);
818
819      gc->width = windres_get_16 (wrbfd, data, 2);
820      gc->height = windres_get_16 (wrbfd, data + 2, 2);
821      gc->planes = windres_get_16 (wrbfd, data + 4, 2);
822      gc->bits = windres_get_16 (wrbfd, data + 6, 2);
823      gc->bytes = windres_get_32 (wrbfd, data + 8, 4);
824      gc->index = windres_get_16 (wrbfd, data + 12, 2);
825
826      gc->next = NULL;
827      *pp = gc;
828      pp = &gc->next;
829
830      data += 14;
831      length -= 14;
832    }
833
834  r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
835  r->type = RES_TYPE_GROUP_CURSOR;
836  r->u.group_cursor = first;
837
838  return r;
839}
840
841/* Convert a group icon resource from binary.  */
842
843static rc_res_resource *
844bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
845{
846  int type, c, i;
847  rc_group_icon *first, **pp;
848  rc_res_resource *r;
849
850  if (length < 6)
851    toosmall (_("group icon header"));
852
853  type = windres_get_16 (wrbfd, data + 2, 2);
854  if (type != 1)
855    fatal (_("unexpected group icon type %d"), type);
856
857  c = windres_get_16 (wrbfd, data + 4, 2);
858
859  data += 6;
860  length -= 6;
861
862  first = NULL;
863  pp = &first;
864
865  for (i = 0; i < c; i++)
866    {
867      rc_group_icon *gi;
868
869      if (length < 14)
870	toosmall (_("group icon"));
871
872      gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
873
874      gi->width = windres_get_8 (wrbfd, data, 1);
875      gi->height = windres_get_8 (wrbfd, data + 1, 1);
876      gi->colors = windres_get_8 (wrbfd, data + 2, 1);
877      gi->planes = windres_get_16 (wrbfd, data + 4, 2);
878      gi->bits = windres_get_16 (wrbfd, data + 6, 2);
879      gi->bytes = windres_get_32 (wrbfd, data + 8, 4);
880      gi->index = windres_get_16 (wrbfd, data + 12, 2);
881
882      gi->next = NULL;
883      *pp = gi;
884      pp = &gi->next;
885
886      data += 14;
887      length -= 14;
888    }
889
890  r = (rc_res_resource *) res_alloc (sizeof *r);
891  r->type = RES_TYPE_GROUP_ICON;
892  r->u.group_icon = first;
893
894  return r;
895}
896
897/* Extract data from a version header.  If KEY is not NULL, then the
898   key must be KEY; otherwise, the key is returned in *PKEY.  This
899   sets *LEN to the total length, *VALLEN to the value length, *TYPE
900   to the type, and *OFF to the offset to the children.  */
901
902static void
903get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
904		    const char *key, unichar **pkey,
905		    rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
906		    rc_uint_type *off)
907{
908  if (length < 8)
909    toosmall (key);
910
911  *len = windres_get_16 (wrbfd, data, 2);
912  *vallen = windres_get_16 (wrbfd, data + 2, 2);
913  *type = windres_get_16 (wrbfd, data + 4, 2);
914
915  *off = 6;
916
917  length -= 6;
918  data += 6;
919
920  if (key == NULL)
921    {
922      rc_uint_type sublen;
923
924      *pkey = get_unicode (wrbfd, data, length, &sublen);
925      *off += (sublen + 1) * sizeof (unichar);
926    }
927  else
928    {
929      while (1)
930	{
931	  if (length < 2)
932	    toosmall (key);
933	  if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
934	    fatal (_("unexpected version string"));
935
936	  *off += 2;
937	  length -= 2;
938	  data += 2;
939
940	  if (*key == '\0')
941	    break;
942
943	  ++key;
944	}
945    }
946
947  *off = (*off + 3) &~ 3;
948}
949
950/* Convert a version resource from binary.  */
951
952static rc_res_resource *
953bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
954{
955  rc_uint_type verlen, vallen, type, off;
956  rc_fixed_versioninfo *fi;
957  rc_ver_info *first, **pp;
958  rc_versioninfo *v;
959  rc_res_resource *r;
960
961  get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
962		      (unichar **) NULL, &verlen, &vallen, &type, &off);
963
964  if ((unsigned int) verlen != length)
965    fatal (_("version length %d does not match resource length %lu"),
966	   (int) verlen, (unsigned long) length);
967
968  if (type != 0)
969    fatal (_("unexpected version type %d"), (int) type);
970
971  data += off;
972  length -= off;
973
974  if (vallen == 0)
975    fi = NULL;
976  else
977    {
978      unsigned long signature, fiv;
979
980      if (vallen != 52)
981	fatal (_("unexpected fixed version information length %ld"), (long) vallen);
982
983      if (length < 52)
984	toosmall (_("fixed version info"));
985
986      signature = windres_get_32 (wrbfd, data, 4);
987      if (signature != 0xfeef04bd)
988	fatal (_("unexpected fixed version signature %lu"), signature);
989
990      fiv = windres_get_32 (wrbfd, data + 4, 4);
991      if (fiv != 0 && fiv != 0x10000)
992	fatal (_("unexpected fixed version info version %lu"), fiv);
993
994      fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
995
996      fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
997      fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
998      fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
999      fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
1000      fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1001      fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1002      fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1003      fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1004      fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1005      fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1006      fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
1007
1008      data += 52;
1009      length -= 52;
1010    }
1011
1012  first = NULL;
1013  pp = &first;
1014
1015  while (length > 0)
1016    {
1017      rc_ver_info *vi;
1018      int ch;
1019
1020      if (length < 8)
1021	toosmall (_("version var info"));
1022
1023      vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1024
1025      ch = windres_get_16 (wrbfd, data + 6, 2);
1026
1027      if (ch == 'S')
1028	{
1029	  rc_ver_stringinfo **ppvs;
1030
1031	  vi->type = VERINFO_STRING;
1032
1033	  get_version_header (wrbfd, data, length, "StringFileInfo",
1034			      (unichar **) NULL, &verlen, &vallen, &type,
1035			      &off);
1036
1037	  if (vallen != 0)
1038	    fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1039
1040	  data += off;
1041	  length -= off;
1042
1043	  get_version_header (wrbfd, data, length, (const char *) NULL,
1044			      &vi->u.string.language, &verlen, &vallen,
1045			      &type, &off);
1046
1047	  if (vallen != 0)
1048	    fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1049
1050	  data += off;
1051	  length -= off;
1052	  verlen -= off;
1053
1054	  vi->u.string.strings = NULL;
1055	  ppvs = &vi->u.string.strings;
1056
1057	  /* It's convenient to round verlen to a 4 byte alignment,
1058             since we round the subvariables in the loop.  */
1059	  verlen = (verlen + 3) &~ 3;
1060
1061	  while (verlen > 0)
1062	    {
1063	      rc_ver_stringinfo *vs;
1064	      rc_uint_type subverlen, vslen, valoff;
1065
1066	      vs = (rc_ver_stringinfo *) res_alloc (sizeof *vs);
1067
1068	      get_version_header (wrbfd, data, length,
1069				  (const char *) NULL, &vs->key, &subverlen,
1070				  &vallen, &type, &off);
1071
1072	      subverlen = (subverlen + 3) &~ 3;
1073
1074	      data += off;
1075	      length -= off;
1076
1077	      vs->value = get_unicode (wrbfd, data, length, &vslen);
1078	      valoff = vslen * 2 + 2;
1079	      valoff = (valoff + 3) &~ 3;
1080
1081	      if (off + valoff != subverlen)
1082		fatal (_("unexpected version string length %ld != %ld + %ld"),
1083		       (long) subverlen, (long) off, (long) valoff);
1084
1085	      vs->next = NULL;
1086	      *ppvs = vs;
1087	      ppvs = &vs->next;
1088
1089	      data += valoff;
1090	      length -= valoff;
1091
1092	      if (verlen < subverlen)
1093		fatal (_("unexpected version string length %ld < %ld"),
1094		       (long) verlen, (long) subverlen);
1095
1096	      verlen -= subverlen;
1097	    }
1098	}
1099      else if (ch == 'V')
1100	{
1101	  rc_ver_varinfo **ppvv;
1102
1103	  vi->type = VERINFO_VAR;
1104
1105	  get_version_header (wrbfd, data, length, "VarFileInfo",
1106			      (unichar **) NULL, &verlen, &vallen, &type,
1107			      &off);
1108
1109	  if (vallen != 0)
1110	    fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1111
1112	  data += off;
1113	  length -= off;
1114
1115	  get_version_header (wrbfd, data, length, (const char *) NULL,
1116			      &vi->u.var.key, &verlen, &vallen, &type, &off);
1117
1118	  data += off;
1119	  length -= off;
1120
1121	  vi->u.var.var = NULL;
1122	  ppvv = &vi->u.var.var;
1123
1124	  while (vallen > 0)
1125	    {
1126	      rc_ver_varinfo *vv;
1127
1128	      if (length < 4)
1129		toosmall (_("version varfileinfo"));
1130
1131	      vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1132
1133	      vv->language = windres_get_16 (wrbfd, data, 2);
1134	      vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1135
1136	      vv->next = NULL;
1137	      *ppvv = vv;
1138	      ppvv = &vv->next;
1139
1140	      data += 4;
1141	      length -= 4;
1142
1143	      if (vallen < 4)
1144		fatal (_("unexpected version value length %ld"), (long) vallen);
1145
1146	      vallen -= 4;
1147	    }
1148	}
1149      else
1150	fatal (_("unexpected version string"));
1151
1152      vi->next = NULL;
1153      *pp = vi;
1154      pp = &vi->next;
1155    }
1156
1157  v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1158  v->fixed = fi;
1159  v->var = first;
1160
1161  r = (rc_res_resource *) res_alloc (sizeof *r);
1162  r->type = RES_TYPE_VERSIONINFO;
1163  r->u.versioninfo = v;
1164
1165  return r;
1166}
1167
1168/* Convert an arbitrary user defined resource from binary.  */
1169
1170static rc_res_resource *
1171bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1172		     rc_uint_type length)
1173{
1174  rc_rcdata_item *ri;
1175  rc_res_resource *r;
1176
1177  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1178
1179  ri->next = NULL;
1180  ri->type = RCDATA_BUFFER;
1181  ri->u.buffer.length = length;
1182  ri->u.buffer.data = data;
1183
1184  r = (rc_res_resource *) res_alloc (sizeof *r);
1185  r->type = RES_TYPE_USERDATA;
1186  r->u.rcdata = ri;
1187
1188  return r;
1189}
1190
1191static rc_res_resource *
1192bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1193{
1194  rc_toolbar *ri;
1195  rc_res_resource *r;
1196  rc_uint_type i;
1197
1198  ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1199  ri->button_width = windres_get_32 (wrbfd, data, 4);
1200  ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1201  ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1202  ri->items = NULL;
1203
1204  data += 12;
1205  length -= 12;
1206  for (i=0 ; i < ri->nitems; i++)
1207  {
1208    rc_toolbar_item *it;
1209    it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1210    it->id.named = 0;
1211    it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1212    it->prev = it->next = NULL;
1213    data += 4;
1214    length -= 4;
1215    if(ri->items) {
1216      rc_toolbar_item *ii = ri->items;
1217      while (ii->next != NULL)
1218	ii = ii->next;
1219      it->prev = ii;
1220      ii->next = it;
1221    }
1222    else
1223      ri->items = it;
1224  }
1225  r = (rc_res_resource *) res_alloc (sizeof *r);
1226  r->type = RES_TYPE_TOOLBAR;
1227  r->u.toolbar = ri;
1228  return r;
1229}
1230
1231
1232/* Local functions used to convert resources to binary format.  */
1233
1234static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1235static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1236static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1237static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1238static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1239static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1240static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1241static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1242static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1243static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1244static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1245static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1246static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1247static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1248static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1249static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1250static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1251					const bfd_byte *);
1252
1253/* Convert a resource to binary.  */
1254
1255rc_uint_type
1256res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1257{
1258  switch (res->type)
1259    {
1260    case RES_TYPE_BITMAP:
1261    case RES_TYPE_FONT:
1262    case RES_TYPE_ICON:
1263    case RES_TYPE_MESSAGETABLE:
1264      return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1265    case RES_TYPE_ACCELERATOR:
1266      return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1267    case RES_TYPE_CURSOR:
1268      return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1269    case RES_TYPE_GROUP_CURSOR:
1270      return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1271    case RES_TYPE_DIALOG:
1272      return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1273    case RES_TYPE_FONTDIR:
1274      return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1275    case RES_TYPE_GROUP_ICON:
1276      return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1277    case RES_TYPE_MENU:
1278      return res_to_bin_menu (wrbfd, off, res->u.menu);
1279    case RES_TYPE_STRINGTABLE:
1280      return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1281    case RES_TYPE_VERSIONINFO:
1282      return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1283    case RES_TYPE_TOOLBAR:
1284      return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1285    case RES_TYPE_USERDATA:
1286    case RES_TYPE_RCDATA:
1287    default:
1288      return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1289    }
1290}
1291
1292/* Convert a resource ID to binary.  This always returns exactly one
1293   bindata structure.  */
1294
1295static rc_uint_type
1296resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1297{
1298  if (! id.named)
1299    {
1300      if (wrbfd)
1301	{
1302	  struct bin_res_id bri;
1303
1304	  windres_put_16 (wrbfd, bri.sig, 0xffff);
1305	  windres_put_16 (wrbfd, bri.id, id.u.id);
1306	  set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1307	}
1308      off += BIN_RES_ID;
1309    }
1310  else
1311    {
1312      rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1313      if (wrbfd)
1314	{
1315	  bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1316	  rc_uint_type i;
1317	  for (i = 0; i < len; i++)
1318	    windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1319	  windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1320	  set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1321    }
1322      off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1323    }
1324  return off;
1325}
1326
1327/* Convert a null terminated unicode string to binary.  This always
1328   returns exactly one bindata structure.  */
1329
1330static rc_uint_type
1331unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1332{
1333  rc_uint_type len = 0;
1334
1335  if (str != NULL)
1336    len = unichar_len (str);
1337
1338  if (wrbfd)
1339    {
1340      bfd_byte *d;
1341      rc_uint_type i;
1342      d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1343      for (i = 0; i < len; i++)
1344	windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1345      windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1346      set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1347    }
1348  off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1349
1350  return off;
1351}
1352
1353/* Convert an accelerator resource to binary.  */
1354
1355static rc_uint_type
1356res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1357			const rc_accelerator *accelerators)
1358{
1359  bindata *first, **pp;
1360  const rc_accelerator *a;
1361
1362  first = NULL;
1363  pp = &first;
1364
1365  for (a = accelerators; a != NULL; a = a->next)
1366    {
1367      if (wrbfd)
1368	{
1369	  struct bin_accelerator ba;
1370
1371	  windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1372	  windres_put_16 (wrbfd, ba.key, a->key);
1373	  windres_put_16 (wrbfd, ba.id, a->id);
1374	  windres_put_16 (wrbfd, ba.pad, 0);
1375	  set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1376    }
1377      off += BIN_ACCELERATOR_SIZE;
1378    }
1379  return off;
1380}
1381
1382/* Convert a cursor resource to binary.  */
1383
1384static rc_uint_type
1385res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1386{
1387  if (wrbfd)
1388    {
1389      struct bin_cursor bc;
1390
1391      windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1392      windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1393      set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1394      if (c->length)
1395	set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1396    }
1397  off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1398  return off;
1399}
1400
1401/* Convert a group cursor resource to binary.  */
1402
1403static rc_uint_type
1404res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1405			 const rc_group_cursor *group_cursors)
1406{
1407  int c = 0;
1408  const rc_group_cursor *gc;
1409  struct bin_group_cursor bgc;
1410  struct bin_group_cursor_item bgci;
1411  rc_uint_type start = off;
1412
1413  off += BIN_GROUP_CURSOR_SIZE;
1414
1415  for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1416    {
1417      if (wrbfd)
1418	{
1419	  windres_put_16 (wrbfd, bgci.width, gc->width);
1420	  windres_put_16 (wrbfd, bgci.height, gc->height);
1421	  windres_put_16 (wrbfd, bgci.planes, gc->planes);
1422	  windres_put_16 (wrbfd, bgci.bits, gc->bits);
1423	  windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1424	  windres_put_16 (wrbfd, bgci.index, gc->index);
1425	  set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1426    }
1427
1428      off += BIN_GROUP_CURSOR_ITEM_SIZE;
1429    }
1430  if (wrbfd)
1431    {
1432      windres_put_16 (wrbfd, bgc.sig1, 0);
1433      windres_put_16 (wrbfd, bgc.sig2, 2);
1434      windres_put_16 (wrbfd, bgc.nitems, c);
1435      set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1436    }
1437  return off;
1438}
1439
1440/* Convert a dialog resource to binary.  */
1441
1442static rc_uint_type
1443res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1444{
1445  rc_uint_type off_delta;
1446  rc_uint_type start, marker;
1447  int dialogex;
1448  int c;
1449  rc_dialog_control *dc;
1450  struct bin_dialogex bdx;
1451  struct bin_dialog bd;
1452
1453  off_delta = off;
1454  start = off;
1455  dialogex = extended_dialog (dialog);
1456
1457  if (wrbfd)
1458    {
1459  if (! dialogex)
1460    {
1461	  windres_put_32 (wrbfd, bd.style, dialog->style);
1462	  windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1463	  windres_put_16 (wrbfd, bd.x, dialog->x);
1464	  windres_put_16 (wrbfd, bd.y, dialog->y);
1465	  windres_put_16 (wrbfd, bd.width, dialog->width);
1466	  windres_put_16 (wrbfd, bd.height, dialog->height);
1467    }
1468  else
1469    {
1470	  windres_put_16 (wrbfd, bdx.sig1, 1);
1471	  windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1472	  windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1473	  windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1474	  windres_put_32 (wrbfd, bdx.style, dialog->style);
1475	  windres_put_16 (wrbfd, bdx.x, dialog->x);
1476	  windres_put_16 (wrbfd, bdx.y, dialog->y);
1477	  windres_put_16 (wrbfd, bdx.width, dialog->width);
1478	  windres_put_16 (wrbfd, bdx.height, dialog->height);
1479	}
1480    }
1481
1482  off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1483
1484  off = resid_to_bin (wrbfd, off, dialog->menu);
1485  off = resid_to_bin (wrbfd, off, dialog->class);
1486  off = unicode_to_bin (wrbfd, off, dialog->caption);
1487
1488  if ((dialog->style & DS_SETFONT) != 0)
1489    {
1490      if (wrbfd)
1491	{
1492	  if (! dialogex)
1493	    {
1494	      struct bin_dialogfont bdf;
1495	      windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1496	      set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1497	    }
1498	  else
1499	    {
1500	      struct bin_dialogexfont bdxf;
1501	      windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1502	      windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1503	      windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1504	      windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1505	      set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1506	    }
1507	}
1508      off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1509      off = unicode_to_bin (wrbfd, off, dialog->font);
1510    }
1511  for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1512    {
1513      bfd_byte dc_rclen[2];
1514
1515      off += (4 - ((off - off_delta) & 3)) & 3;
1516      if (wrbfd)
1517	{
1518      if (! dialogex)
1519	{
1520	      struct bin_dialog_control bdc;
1521
1522	      windres_put_32 (wrbfd, bdc.style, dc->style);
1523	      windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1524	      windres_put_16 (wrbfd, bdc.x, dc->x);
1525	      windres_put_16 (wrbfd, bdc.y, dc->y);
1526	      windres_put_16 (wrbfd, bdc.width, dc->width);
1527	      windres_put_16 (wrbfd, bdc.height, dc->height);
1528	      windres_put_16 (wrbfd, bdc.id, dc->id);
1529	      set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1530	}
1531      else
1532	{
1533	      struct bin_dialogex_control bdc;
1534
1535	      windres_put_32 (wrbfd, bdc.help, dc->help);
1536	      windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1537	      windres_put_32 (wrbfd, bdc.style, dc->style);
1538	      windres_put_16 (wrbfd, bdc.x, dc->x);
1539	      windres_put_16 (wrbfd, bdc.y, dc->y);
1540	      windres_put_16 (wrbfd, bdc.width, dc->width);
1541	      windres_put_16 (wrbfd, bdc.height, dc->height);
1542	      windres_put_32 (wrbfd, bdc.id, dc->id);
1543	      set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1544	    }
1545	}
1546      off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1547
1548      off = resid_to_bin (wrbfd, off, dc->class);
1549      off = resid_to_bin (wrbfd, off, dc->text);
1550
1551      marker = off; /* Save two bytes for size of optional data.  */
1552      off += 2;
1553
1554      if (dc->data == NULL)
1555        {
1556	  if (wrbfd)
1557	    windres_put_16 (wrbfd, dc_rclen, 0);
1558	}
1559      else
1560	{
1561	  rc_uint_type saved_off = off;
1562	  rc_uint_type old_off;
1563	  off += (4 - ((off - off_delta) & 3)) & 3;
1564
1565	  old_off = off;
1566	  off = res_to_bin_rcdata (wrbfd, off, dc->data);
1567	  if ((off - old_off) == 0)
1568	    old_off = off = saved_off;
1569	  if (wrbfd)
1570	    windres_put_16 (wrbfd, dc_rclen, off - old_off);
1571	    }
1572      if (wrbfd)
1573	set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1574	}
1575
1576  if (wrbfd)
1577    {
1578      windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1579      if (! dialogex)
1580	set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1581      else
1582	set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1583    }
1584
1585  return off;
1586}
1587
1588/* Convert a fontdir resource to binary.  */
1589static rc_uint_type
1590res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
1591{
1592  rc_uint_type start;
1593  int c;
1594  const rc_fontdir *fd;
1595
1596  start = off;
1597  off += 2;
1598
1599  for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1600    {
1601      if (wrbfd)
1602	{
1603	  bfd_byte d[2];
1604	  windres_put_16 (wrbfd, d, fd->index);
1605	  set_windres_bfd_content (wrbfd, d, off, 2);
1606	  if (fd->length)
1607	    set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1608	}
1609      off += (rc_uint_type) fd->length + 2;
1610    }
1611
1612  if (wrbfd)
1613    {
1614      bfd_byte d[2];
1615      windres_put_16 (wrbfd, d, c);
1616      set_windres_bfd_content (wrbfd, d, start, 2);
1617    }
1618  return off;
1619}
1620
1621/* Convert a group icon resource to binary.  */
1622
1623static rc_uint_type
1624res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1625{
1626  rc_uint_type start;
1627  struct bin_group_icon bgi;
1628  int c;
1629  const rc_group_icon *gi;
1630
1631  start = off;
1632  off += BIN_GROUP_ICON_SIZE;
1633
1634  for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1635    {
1636      struct bin_group_icon_item bgii;
1637
1638      if (wrbfd)
1639	{
1640	  windres_put_8 (wrbfd, bgii.width, gi->width);
1641	  windres_put_8 (wrbfd, bgii.height, gi->height);
1642	  windres_put_8 (wrbfd, bgii.colors, gi->colors);
1643	  windres_put_8 (wrbfd, bgii.pad, 0);
1644	  windres_put_16 (wrbfd, bgii.planes, gi->planes);
1645	  windres_put_16 (wrbfd, bgii.bits, gi->bits);
1646	  windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1647	  windres_put_16 (wrbfd, bgii.index, gi->index);
1648	  set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1649	}
1650      off += BIN_GROUP_ICON_ITEM_SIZE;
1651    }
1652
1653  if (wrbfd)
1654    {
1655      windres_put_16 (wrbfd, bgi.sig1, 0);
1656      windres_put_16 (wrbfd, bgi.sig2, 1);
1657      windres_put_16 (wrbfd, bgi.count, c);
1658      set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1659    }
1660  return off;
1661}
1662
1663/* Convert a menu resource to binary.  */
1664
1665static rc_uint_type
1666res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1667{
1668  int menuex;
1669
1670  menuex = extended_menu (menu);
1671
1672  if (wrbfd)
1673    {
1674  if (! menuex)
1675    {
1676	  struct bin_menu bm;
1677	  windres_put_16 (wrbfd, bm.sig1, 0);
1678	  windres_put_16 (wrbfd, bm.sig2, 0);
1679	  set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1680    }
1681  else
1682    {
1683	  struct bin_menuex bm;
1684	  windres_put_16 (wrbfd, bm.sig1, 1);
1685	  windres_put_16 (wrbfd, bm.sig2, 4);
1686	  windres_put_32 (wrbfd, bm.help, menu->help);
1687	  set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1688    }
1689    }
1690  off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1691  if (! menuex)
1692    {
1693      off = res_to_bin_menuitems (wrbfd, off, menu->items);
1694    }
1695  else
1696    {
1697      off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1698    }
1699  return off;
1700}
1701
1702/* Convert menu items to binary.  */
1703
1704static rc_uint_type
1705res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1706{
1707  const rc_menuitem *mi;
1708
1709  for (mi = items; mi != NULL; mi = mi->next)
1710    {
1711      struct bin_menuitem bmi;
1712      int flags;
1713
1714      flags = mi->type;
1715      if (mi->next == NULL)
1716	flags |= MENUITEM_ENDMENU;
1717      if (mi->popup != NULL)
1718	flags |= MENUITEM_POPUP;
1719
1720      if (wrbfd)
1721	{
1722	  windres_put_16 (wrbfd, bmi.flags, flags);
1723      if (mi->popup == NULL)
1724	    windres_put_16 (wrbfd, bmi.id, mi->id);
1725	  set_windres_bfd_content (wrbfd, &bmi, off,
1726				   mi->popup == NULL ? BIN_MENUITEM_SIZE
1727				   		     : BIN_MENUITEM_POPUP_SIZE);
1728	}
1729      off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1730
1731      off = unicode_to_bin (wrbfd, off, mi->text);
1732
1733      if (mi->popup != NULL)
1734	{
1735	  off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1736	}
1737    }
1738  return off;
1739}
1740
1741/* Convert menuex items to binary.  */
1742
1743static rc_uint_type
1744res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1745{
1746  rc_uint_type off_delta = off;
1747  const rc_menuitem *mi;
1748
1749  for (mi = items; mi != NULL; mi = mi->next)
1750    {
1751      struct bin_menuitemex bmi;
1752      int flags;
1753
1754      off += (4 - ((off - off_delta) & 3)) & 3;
1755
1756      flags = 0;
1757      if (mi->next == NULL)
1758	flags |= 0x80;
1759      if (mi->popup != NULL)
1760	flags |= 1;
1761
1762      if (wrbfd)
1763	{
1764	  windres_put_32 (wrbfd, bmi.type, mi->type);
1765	  windres_put_32 (wrbfd, bmi.state, mi->state);
1766	  windres_put_32 (wrbfd, bmi.id, mi->id);
1767	  windres_put_16 (wrbfd, bmi.flags, flags);
1768	  set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1769	}
1770      off += BIN_MENUITEMEX_SIZE;
1771
1772      off = unicode_to_bin (wrbfd, off, mi->text);
1773
1774      if (mi->popup != NULL)
1775	{
1776	  bfd_byte help[4];
1777
1778	  off += (4 - ((off - off_delta) & 3)) & 3;
1779
1780	  if (wrbfd)
1781	    {
1782	      windres_put_32 (wrbfd, help, mi->help);
1783	      set_windres_bfd_content (wrbfd, help, off, 4);
1784	    }
1785	  off += 4;
1786	  off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1787	}
1788    }
1789  return off;
1790}
1791
1792/* Convert an rcdata resource to binary.  This is also used to convert
1793   other information which happens to be stored in rc_rcdata_item lists
1794   to binary.  */
1795
1796static rc_uint_type
1797res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1798{
1799  const rc_rcdata_item *ri;
1800
1801  for (ri = items; ri != NULL; ri = ri->next)
1802    {
1803      rc_uint_type len;
1804      switch (ri->type)
1805	{
1806	default:
1807	  abort ();
1808	case RCDATA_WORD:
1809	  len = 2;
1810	  break;
1811	case RCDATA_DWORD:
1812	  len = 4;
1813	  break;
1814	case RCDATA_STRING:
1815	  len = ri->u.string.length;
1816	  break;
1817	case RCDATA_WSTRING:
1818	  len = ri->u.wstring.length * sizeof (unichar);
1819	  break;
1820	case RCDATA_BUFFER:
1821	  len = ri->u.buffer.length;
1822	  break;
1823	}
1824      if (wrbfd)
1825	{
1826	  bfd_byte h[4];
1827	  bfd_byte *hp = &h[0];
1828	  switch (ri->type)
1829	    {
1830	    case RCDATA_WORD:
1831	      windres_put_16 (wrbfd, hp, ri->u.word);
1832	      break;
1833	    case RCDATA_DWORD:
1834	      windres_put_32 (wrbfd, hp, ri->u.dword);
1835	      break;
1836	    case RCDATA_STRING:
1837	      hp = (bfd_byte *) ri->u.string.s;
1838	  break;
1839	case RCDATA_WSTRING:
1840	  {
1841		rc_uint_type i;
1842
1843		hp = (bfd_byte *) reswr_alloc (len);
1844	    for (i = 0; i < ri->u.wstring.length; i++)
1845		  windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
1846	  }
1847	      break;
1848	case RCDATA_BUFFER:
1849	      hp = (bfd_byte *) ri->u.buffer.data;
1850	  break;
1851	}
1852	  set_windres_bfd_content (wrbfd, hp, off, len);
1853    }
1854      off += len;
1855    }
1856  return off;
1857}
1858
1859/* Convert a stringtable resource to binary.  */
1860
1861static rc_uint_type
1862res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1863			const rc_stringtable *st)
1864{
1865  int i;
1866
1867  for (i = 0; i < 16; i++)
1868    {
1869      rc_uint_type slen, length;
1870      unichar *s;
1871
1872      slen = (rc_uint_type) st->strings[i].length;
1873      s = st->strings[i].string;
1874
1875      length = 2 + slen * 2;
1876      if (wrbfd)
1877	{
1878	  bfd_byte *hp;
1879	  rc_uint_type j;
1880
1881	  hp = (bfd_byte *) reswr_alloc (length);
1882	  windres_put_16 (wrbfd, hp, slen);
1883
1884      for (j = 0; j < slen; j++)
1885	    windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1886	  set_windres_bfd_content (wrbfd, hp, off, length);
1887    }
1888      off += length;
1889    }
1890  return off;
1891}
1892
1893/* Convert an ASCII string to a unicode binary string.  This always
1894   returns exactly one bindata structure.  */
1895
1896static rc_uint_type
1897string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1898{
1899  rc_uint_type len;
1900
1901  len = (rc_uint_type) strlen (s);
1902
1903  if (wrbfd)
1904    {
1905      rc_uint_type i;
1906      bfd_byte *hp;
1907
1908      hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1909
1910      for (i = 0; i < len; i++)
1911	windres_put_16 (wrbfd, hp + i * 2, s[i]);
1912      windres_put_16 (wrbfd, hp + i * 2, 0);
1913      set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1914    }
1915  off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1916  return off;
1917}
1918
1919static rc_uint_type
1920res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1921{
1922  if (wrbfd)
1923    {
1924      struct bin_toolbar bt;
1925      windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1926      windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1927      windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1928      set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1929      if (tb->nitems > 0)
1930	{
1931	  rc_toolbar_item *it;
1932	  bfd_byte *ids;
1933	  rc_uint_type i = 0;
1934
1935	  ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1936	  it=tb->items;
1937	  while(it != NULL)
1938	    {
1939	      windres_put_32 (wrbfd, ids + i, it->id.u.id);
1940	      i += 4;
1941	      it = it->next;
1942	    }
1943	  set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1944 	}
1945    }
1946  off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1947
1948  return off;
1949}
1950
1951/* Convert a versioninfo resource to binary.  */
1952
1953static rc_uint_type
1954res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1955			const rc_versioninfo *versioninfo)
1956{
1957  rc_uint_type off_delta = off;
1958  rc_uint_type start;
1959  struct bin_versioninfo bvi;
1960  rc_ver_info *vi;
1961
1962  start = off;
1963  off += BIN_VERSIONINFO_SIZE;
1964  off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1965  off += (4 - ((off - off_delta) & 3)) & 3;
1966
1967  if (versioninfo->fixed != NULL)
1968    {
1969      if (wrbfd)
1970	{
1971	  struct bin_fixed_versioninfo bfv;
1972	  const rc_fixed_versioninfo *fi;
1973
1974      fi = versioninfo->fixed;
1975	  windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1976	  windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1977	  windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1978	  windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
1979	  windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
1980	  windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
1981	  windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
1982	  windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
1983	  windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
1984	  windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
1985	  windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
1986	  windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
1987	  windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
1988	  set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
1989	}
1990      off += BIN_FIXED_VERSIONINFO_SIZE;
1991    }
1992
1993  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
1994    {
1995      struct bin_ver_info bv;
1996      rc_uint_type bv_off;
1997
1998      off += (4 - ((off - off_delta) & 3)) & 3;
1999
2000      bv_off = off;
2001
2002      off += BIN_VER_INFO_SIZE;
2003
2004      switch (vi->type)
2005	{
2006	default:
2007	  abort ();
2008	case VERINFO_STRING:
2009	  {
2010	    struct bin_ver_info bvsd;
2011	    rc_uint_type vs_off;
2012	    const rc_ver_stringinfo *vs;
2013
2014	    off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2015	    off += (4 - ((off - off_delta) & 3)) & 3;
2016
2017	    vs_off = off;
2018
2019	    off += BIN_VER_INFO_SIZE;
2020
2021	    off = unicode_to_bin (wrbfd, off, vi->u.string.language);
2022
2023	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2024	      {
2025		struct bin_ver_info bvss;
2026		rc_uint_type vss_off,str_off;
2027
2028		off += (4 - ((off - off_delta) & 3)) & 3;
2029
2030		vss_off = off;
2031		off += BIN_VER_INFO_SIZE;
2032
2033		off = unicode_to_bin (wrbfd, off, vs->key);
2034
2035		off += (4 - ((off - off_delta) & 3)) & 3;
2036
2037		str_off = off;
2038		off = unicode_to_bin (wrbfd, off, vs->value);
2039		if (wrbfd)
2040		  {
2041		    windres_put_16 (wrbfd, bvss.size, off - vss_off);
2042		    windres_put_16 (wrbfd, bvss.sig1, (off - str_off) / 2);
2043		    windres_put_16 (wrbfd, bvss.sig2, 1);
2044		    set_windres_bfd_content (wrbfd, &bvss, vss_off,
2045		    			     BIN_VER_INFO_SIZE);
2046		  }
2047	      }
2048	    if (wrbfd)
2049	      {
2050		windres_put_16 (wrbfd, bvsd.size, off - vs_off);
2051		windres_put_16 (wrbfd, bvsd.sig1, 0);
2052		windres_put_16 (wrbfd, bvsd.sig2, 0);
2053		set_windres_bfd_content (wrbfd, &bvsd, vs_off,
2054					 BIN_VER_INFO_SIZE);
2055	      }
2056	    break;
2057	  }
2058
2059	case VERINFO_VAR:
2060	  {
2061	    rc_uint_type vvd_off, vvvd_off;
2062	    struct bin_ver_info bvvd;
2063	    const rc_ver_varinfo *vv;
2064
2065	    off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2066
2067	    off += (4 - ((off - off_delta) & 3)) & 3;
2068
2069	    vvd_off = off;
2070	    off += BIN_VER_INFO_SIZE;
2071
2072	    off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2073
2074	    off += (4 - ((off - off_delta) & 3)) & 3;
2075
2076	    vvvd_off = off;
2077
2078	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2079	      {
2080		if (wrbfd)
2081		  {
2082		    bfd_byte vvsd[4];
2083
2084		    windres_put_16 (wrbfd, &vvsd[0], vv->language);
2085		    windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2086		    set_windres_bfd_content (wrbfd, vvsd, off, 4);
2087		  }
2088		off += 4;
2089	      }
2090	    if (wrbfd)
2091	    {
2092		windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2093		windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2094		windres_put_16 (wrbfd, bvvd.sig2, 0);
2095		set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2096					 BIN_VER_INFO_SIZE);
2097	    }
2098
2099	    break;
2100	  }
2101	}
2102
2103      if (wrbfd)
2104	{
2105	  windres_put_16 (wrbfd, bv.size, off-bv_off);
2106	  windres_put_16 (wrbfd, bv.sig1, 0);
2107	  windres_put_16 (wrbfd, bv.sig2, 0);
2108	  set_windres_bfd_content (wrbfd, &bv, bv_off,
2109	  			   BIN_VER_INFO_SIZE);
2110	}
2111    }
2112
2113  if (wrbfd)
2114    {
2115      windres_put_16 (wrbfd, bvi.size, off - start);
2116      windres_put_16 (wrbfd, bvi.fixed_size,
2117		      versioninfo->fixed == NULL ? 0
2118		      				 : BIN_FIXED_VERSIONINFO_SIZE);
2119      windres_put_16 (wrbfd, bvi.sig2, 0);
2120      set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2121    }
2122  return off;
2123}
2124
2125/* Convert a generic resource to binary.  */
2126
2127static rc_uint_type
2128res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2129		    const bfd_byte *data)
2130{
2131  if (wrbfd && length != 0)
2132    set_windres_bfd_content (wrbfd, data, off, length);
2133  return off + (rc_uint_type) length;
2134}
2135