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