Release 2.33.1
[external/binutils.git] / binutils / resbin.c
1 /* resbin.c -- manipulate the Windows binary resource format.
2    Copyright (C) 1997-2019 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Cygnus Support.
4    Rewritten by Kai Tietz, Onevision.
5
6    This file is part of GNU Binutils.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21    02110-1301, USA.  */
22
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
36 static void toosmall (const char *);
37
38 static unichar *get_unicode (windres_bfd *, const bfd_byte *, rc_uint_type, rc_uint_type *);
39 static int get_resid (windres_bfd *, rc_res_id *, const bfd_byte *, rc_uint_type);
40 static rc_res_resource *bin_to_res_generic (windres_bfd *, enum rc_res_type,
41                                             const bfd_byte *, rc_uint_type);
42 static rc_res_resource *bin_to_res_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
43 static rc_res_resource *bin_to_res_menu (windres_bfd *,const bfd_byte *, rc_uint_type);
44 static rc_menuitem *bin_to_res_menuitems (windres_bfd *, const bfd_byte *, rc_uint_type,
45                                           rc_uint_type *);
46 static rc_menuitem *bin_to_res_menuexitems (windres_bfd *, const bfd_byte *, rc_uint_type,
47                                             rc_uint_type *);
48 static rc_res_resource *bin_to_res_dialog (windres_bfd *, const bfd_byte *, rc_uint_type);
49 static rc_res_resource *bin_to_res_string (windres_bfd *,const bfd_byte *, rc_uint_type);
50 static rc_res_resource *bin_to_res_fontdir (windres_bfd *, const bfd_byte *, rc_uint_type);
51 static rc_res_resource *bin_to_res_accelerators (windres_bfd *, const bfd_byte *, rc_uint_type);
52 static rc_res_resource *bin_to_res_rcdata (windres_bfd *, const bfd_byte *, rc_uint_type, int);
53 static rc_res_resource *bin_to_res_group_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
54 static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *, rc_uint_type);
55 static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
56 static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
57 static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
58 static 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
67 rc_res_resource *
68 bin_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
116 static void
117 toosmall (const char *msg)
118 {
119   fatal (_("%s: not enough binary data"), msg);
120 }
121
122 /* Swap in a NULL terminated unicode string.  */
123
124 static unichar *
125 get_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
155 static int
156 get_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
184 rc_res_resource *
185 bin_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
200 rc_res_resource *
201 bin_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
224 rc_res_resource *
225 bin_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, got;
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, &got);
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), &got);
261     }
262   else
263     fatal (_("unsupported menu version %d"), (int) version);
264
265   return r;
266 }
267
268 /* Convert menu items from binary.  */
269
270 static rc_menuitem *
271 bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
272                       rc_uint_type *got)
273 {
274   rc_menuitem *first, **pp;
275
276   first = NULL;
277   pp = &first;
278
279   *got = 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       *got += 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
347 static rc_menuitem *
348 bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
349                         rc_uint_type *got)
350 {
351   rc_menuitem *first, **pp;
352
353   first = NULL;
354   pp = &first;
355
356   *got = 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       *got += 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
421 static rc_res_resource *
422 bin_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           if (length < off + datalen)
578             toosmall (_("dialog control data"));
579
580           dc->data = ((rc_rcdata_item *)
581                       res_alloc (sizeof (rc_rcdata_item)));
582           dc->data->next = NULL;
583           dc->data->type = RCDATA_BUFFER;
584           dc->data->u.buffer.length = datalen;
585           dc->data->u.buffer.data = data + off;
586
587           off += datalen;
588         }
589
590       dc->next = NULL;
591       *pp = dc;
592       pp = &dc->next;
593     }
594
595   r = (rc_res_resource *) res_alloc (sizeof *r);
596   r->type = RES_TYPE_DIALOG;
597   r->u.dialog = d;
598
599   return r;
600 }
601
602 /* Convert a stringtable resource from binary.  */
603
604 static rc_res_resource *
605 bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
606 {
607   rc_stringtable *st;
608   int i;
609   rc_res_resource *r;
610
611   st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
612
613   for (i = 0; i < 16; i++)
614     {
615       unsigned int slen;
616
617       if (length < 2)
618         toosmall (_("stringtable string length"));
619       slen = windres_get_16 (wrbfd, data, 2);
620       st->strings[i].length = slen;
621
622       if (slen > 0)
623         {
624           unichar *s;
625           unsigned int j;
626
627           if (length < 2 + 2 * slen)
628             toosmall (_("stringtable string"));
629
630           s = (unichar *) res_alloc (slen * sizeof (unichar));
631           st->strings[i].string = s;
632
633           for (j = 0; j < slen; j++)
634             s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
635         }
636
637       data += 2 + 2 * slen;
638       length -= 2 + 2 * slen;
639     }
640
641   r = (rc_res_resource *) res_alloc (sizeof *r);
642   r->type = RES_TYPE_STRINGTABLE;
643   r->u.stringtable = st;
644
645   return r;
646 }
647
648 /* Convert a fontdir resource from binary.  */
649
650 static rc_res_resource *
651 bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
652 {
653   rc_uint_type c, i;
654   rc_fontdir *first, **pp;
655   rc_res_resource *r;
656
657   if (length < 2)
658     toosmall (_("fontdir header"));
659
660   c = windres_get_16 (wrbfd, data, 2);
661
662   first = NULL;
663   pp = &first;
664
665   for (i = 0; i < c; i++)
666     {
667       const struct bin_fontdir_item *bfi;
668       rc_fontdir *fd;
669       unsigned int off;
670
671       if (length < 56)
672         toosmall (_("fontdir"));
673
674       bfi = (const struct bin_fontdir_item *) data;
675       fd = (rc_fontdir *) res_alloc (sizeof *fd);
676       fd->index = windres_get_16 (wrbfd, bfi->index, 2);
677
678       /* To work out the length of the fontdir data, we must get the
679          length of the device name and face name strings, even though
680          we don't store them in the rc_fontdir.  The
681          documentation says that these are NULL terminated char
682          strings, not Unicode strings.  */
683
684       off = 56;
685
686       while (off < length && data[off] != '\0')
687         ++off;
688       if (off >= length)
689         toosmall (_("fontdir device name"));
690       ++off;
691
692       while (off < length && data[off] != '\0')
693         ++off;
694       if (off >= length)
695         toosmall (_("fontdir face name"));
696       ++off;
697
698       fd->length = off;
699       fd->data = data;
700
701       fd->next = NULL;
702       *pp = fd;
703       pp = &fd->next;
704
705       /* The documentation does not indicate that any rounding is
706          required.  */
707
708       data += off;
709       length -= off;
710     }
711
712   r = (rc_res_resource *) res_alloc (sizeof *r);
713   r->type = RES_TYPE_FONTDIR;
714   r->u.fontdir = first;
715
716   return r;
717 }
718
719 /* Convert an accelerators resource from binary.  */
720
721 static rc_res_resource *
722 bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
723 {
724   rc_accelerator *first, **pp;
725   rc_res_resource *r;
726
727   first = NULL;
728   pp = &first;
729
730   while (1)
731     {
732       rc_accelerator *a;
733
734       if (length < 8)
735         toosmall (_("accelerator"));
736
737       a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
738
739       a->flags = windres_get_16 (wrbfd, data, 2);
740       a->key = windres_get_16 (wrbfd, data + 2, 2);
741       a->id = windres_get_16 (wrbfd, data + 4, 2);
742
743       a->next = NULL;
744       *pp = a;
745       pp = &a->next;
746
747       if ((a->flags & ACC_LAST) != 0)
748         break;
749
750       data += 8;
751       length -= 8;
752     }
753
754   r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
755   r->type = RES_TYPE_ACCELERATOR;
756   r->u.acc = first;
757
758   return r;
759 }
760
761 /* Convert an rcdata resource from binary.  */
762
763 static rc_res_resource *
764 bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
765                    rc_uint_type length, int rctyp)
766 {
767   rc_rcdata_item *ri;
768   rc_res_resource *r;
769
770   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
771
772   ri->next = NULL;
773   ri->type = RCDATA_BUFFER;
774   ri->u.buffer.length = length;
775   ri->u.buffer.data = data;
776
777   r = (rc_res_resource *) res_alloc (sizeof *r);
778   r->type = rctyp;
779   r->u.rcdata = ri;
780
781   return r;
782 }
783
784 /* Convert a group cursor resource from binary.  */
785
786 static rc_res_resource *
787 bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
788 {
789   int type, c, i;
790   rc_group_cursor *first, **pp;
791   rc_res_resource *r;
792
793   if (length < 6)
794     toosmall (_("group cursor header"));
795
796   type = windres_get_16 (wrbfd, data + 2, 2);
797   if (type != 2)
798     fatal (_("unexpected group cursor type %d"), type);
799
800   c = windres_get_16 (wrbfd, data + 4, 2);
801
802   data += 6;
803   length -= 6;
804
805   first = NULL;
806   pp = &first;
807
808   for (i = 0; i < c; i++)
809     {
810       rc_group_cursor *gc;
811
812       if (length < 14)
813         toosmall (_("group cursor"));
814
815       gc = (rc_group_cursor *) res_alloc (sizeof *gc);
816
817       gc->width = windres_get_16 (wrbfd, data, 2);
818       gc->height = windres_get_16 (wrbfd, data + 2, 2);
819       gc->planes = windres_get_16 (wrbfd, data + 4, 2);
820       gc->bits = windres_get_16 (wrbfd, data + 6, 2);
821       gc->bytes = windres_get_32 (wrbfd, data + 8, 4);
822       gc->index = windres_get_16 (wrbfd, data + 12, 2);
823
824       gc->next = NULL;
825       *pp = gc;
826       pp = &gc->next;
827
828       data += 14;
829       length -= 14;
830     }
831
832   r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
833   r->type = RES_TYPE_GROUP_CURSOR;
834   r->u.group_cursor = first;
835
836   return r;
837 }
838
839 /* Convert a group icon resource from binary.  */
840
841 static rc_res_resource *
842 bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
843 {
844   int type, c, i;
845   rc_group_icon *first, **pp;
846   rc_res_resource *r;
847
848   if (length < 6)
849     toosmall (_("group icon header"));
850
851   type = windres_get_16 (wrbfd, data + 2, 2);
852   if (type != 1)
853     fatal (_("unexpected group icon type %d"), type);
854
855   c = windres_get_16 (wrbfd, data + 4, 2);
856
857   data += 6;
858   length -= 6;
859
860   first = NULL;
861   pp = &first;
862
863   for (i = 0; i < c; i++)
864     {
865       rc_group_icon *gi;
866
867       if (length < 14)
868         toosmall (_("group icon"));
869
870       gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
871
872       gi->width = windres_get_8 (wrbfd, data, 1);
873       gi->height = windres_get_8 (wrbfd, data + 1, 1);
874       gi->colors = windres_get_8 (wrbfd, data + 2, 1);
875       gi->planes = windres_get_16 (wrbfd, data + 4, 2);
876       gi->bits = windres_get_16 (wrbfd, data + 6, 2);
877       gi->bytes = windres_get_32 (wrbfd, data + 8, 4);
878       gi->index = windres_get_16 (wrbfd, data + 12, 2);
879
880       gi->next = NULL;
881       *pp = gi;
882       pp = &gi->next;
883
884       data += 14;
885       length -= 14;
886     }
887
888   r = (rc_res_resource *) res_alloc (sizeof *r);
889   r->type = RES_TYPE_GROUP_ICON;
890   r->u.group_icon = first;
891
892   return r;
893 }
894
895 /* Extract data from a version header.  If KEY is not NULL, then the
896    key must be KEY; otherwise, the key is returned in *PKEY.  This
897    sets *LEN to the total length, *VALLEN to the value length, *TYPE
898    to the type, and *OFF to the offset to the children.  */
899
900 static void
901 get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
902                     const char *key, unichar **pkey,
903                     rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
904                     rc_uint_type *off)
905 {
906   if (length < 8)
907     toosmall (key);
908
909   *len = (windres_get_16 (wrbfd, data, 2) + 3) & ~3;
910   *vallen = windres_get_16 (wrbfd, data + 2, 2);
911   *type = windres_get_16 (wrbfd, data + 4, 2);
912
913   *off = 6;
914
915   length -= 6;
916   data += 6;
917
918   if (key == NULL)
919     {
920       rc_uint_type sublen;
921
922       *pkey = get_unicode (wrbfd, data, length, &sublen);
923       *off += (sublen + 1) * sizeof (unichar);
924     }
925   else
926     {
927       while (1)
928         {
929           if (length < 2)
930             toosmall (key);
931           if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
932             fatal (_("unexpected version string"));
933
934           *off += 2;
935           length -= 2;
936           data += 2;
937
938           if (*key == '\0')
939             break;
940
941           ++key;
942         }
943     }
944
945   *off = (*off + 3) &~ 3;
946 }
947
948 /* Convert a version resource from binary.  */
949
950 static rc_res_resource *
951 bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
952 {
953   rc_uint_type verlen, vallen, type, off;
954   rc_fixed_versioninfo *fi;
955   rc_ver_info *first, **pp;
956   rc_versioninfo *v;
957   rc_res_resource *r;
958
959   get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
960                       (unichar **) NULL, &verlen, &vallen, &type, &off);
961
962   /* PR 17512: The verlen field does not include padding length.  */
963   if (verlen > length)
964     fatal (_("version length %lu greater than resource length %lu"),
965            (unsigned long) verlen, (unsigned long) length);
966
967   if (type != 0)
968     fatal (_("unexpected version type %d"), (int) type);
969
970   data += off;
971   length -= off;
972
973   if (vallen == 0)
974     fi = NULL;
975   else
976     {
977       unsigned long signature, fiv;
978
979       if (vallen != 52)
980         fatal (_("unexpected fixed version information length %ld"), (long) vallen);
981
982       if (length < 52)
983         toosmall (_("fixed version info"));
984
985       signature = windres_get_32 (wrbfd, data, 4);
986       if (signature != 0xfeef04bd)
987         fatal (_("unexpected fixed version signature %lu"), signature);
988
989       fiv = windres_get_32 (wrbfd, data + 4, 4);
990       if (fiv != 0 && fiv != 0x10000)
991         fatal (_("unexpected fixed version info version %lu"), fiv);
992
993       fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
994
995       fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
996       fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
997       fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
998       fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
999       fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1000       fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1001       fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1002       fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1003       fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1004       fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1005       fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
1006
1007       data += 52;
1008       length -= 52;
1009     }
1010
1011   first = NULL;
1012   pp = &first;
1013
1014   while (length > 0)
1015     {
1016       rc_ver_info *vi;
1017       int ch;
1018
1019       if (length < 8)
1020         toosmall (_("version var info"));
1021
1022       vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1023
1024       ch = windres_get_16 (wrbfd, data + 6, 2);
1025
1026       if (ch == 'S')
1027         {
1028           rc_ver_stringtable **ppvst;
1029
1030           vi->type = VERINFO_STRING;
1031
1032           get_version_header (wrbfd, data, length, "StringFileInfo",
1033                               (unichar **) NULL, &verlen, &vallen, &type,
1034                               &off);
1035
1036           if (vallen != 0)
1037             fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1038
1039           data += off;
1040           length -= off;
1041
1042           verlen -= off;
1043
1044           vi->u.string.stringtables = NULL;
1045           ppvst = &vi->u.string.stringtables;
1046
1047           while (verlen > 0)
1048             {
1049               rc_ver_stringtable *vst;
1050               rc_uint_type stverlen;
1051               rc_ver_stringinfo **ppvs;
1052
1053               if (length < 8)
1054                 toosmall (_("version stringtable"));
1055
1056               vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1057
1058               get_version_header (wrbfd, data, length, (const char *) NULL,
1059                                   &vst->language, &stverlen, &vallen, &type, &off);
1060
1061               if (vallen != 0)
1062                 fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1063
1064               data += off;
1065               length -= off;
1066               verlen -= off;
1067
1068           stverlen -= off;
1069
1070           vst->strings = NULL;
1071           ppvs = &vst->strings;
1072
1073           while (stverlen > 0)
1074             {
1075               rc_ver_stringinfo *vs;
1076               rc_uint_type sverlen, vslen, valoff;
1077
1078               if (length < 8)
1079                 toosmall (_("version string"));
1080
1081               vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1082
1083               get_version_header (wrbfd, data, length, (const char *) NULL,
1084                                   &vs->key, &sverlen, &vallen, &type, &off);
1085
1086               data += off;
1087               length -= off;
1088
1089               vs->value = get_unicode (wrbfd, data, length, &vslen);
1090               valoff = vslen * 2 + 2;
1091               valoff = (valoff + 3) & ~3;
1092
1093               if (off + valoff != sverlen)
1094                 fatal (_("unexpected version string length %ld != %ld + %ld"),
1095                        (long) sverlen, (long) off, (long) valoff);
1096
1097               data += valoff;
1098               length -= valoff;
1099
1100               if (stverlen < sverlen)
1101                 fatal (_("unexpected version string length %ld < %ld"),
1102                        (long) verlen, (long) sverlen);
1103               stverlen -= sverlen;
1104               verlen -= sverlen;
1105
1106               vs->next = NULL;
1107               *ppvs = vs;
1108               ppvs = &vs->next;
1109             }
1110
1111           vst->next = NULL;
1112           *ppvst = vst;
1113           ppvst = &vst->next;
1114             }
1115         }
1116       else if (ch == 'V')
1117         {
1118           rc_ver_varinfo **ppvv;
1119
1120           vi->type = VERINFO_VAR;
1121
1122           get_version_header (wrbfd, data, length, "VarFileInfo",
1123                               (unichar **) NULL, &verlen, &vallen, &type,
1124                               &off);
1125
1126           if (vallen != 0)
1127             fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1128
1129           data += off;
1130           length -= off;
1131
1132           get_version_header (wrbfd, data, length, (const char *) NULL,
1133                               &vi->u.var.key, &verlen, &vallen, &type, &off);
1134
1135           data += off;
1136           length -= off;
1137
1138           vi->u.var.var = NULL;
1139           ppvv = &vi->u.var.var;
1140
1141           while (vallen > 0)
1142             {
1143               rc_ver_varinfo *vv;
1144
1145               if (length < 4)
1146                 toosmall (_("version varfileinfo"));
1147
1148               vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1149
1150               vv->language = windres_get_16 (wrbfd, data, 2);
1151               vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1152
1153               vv->next = NULL;
1154               *ppvv = vv;
1155               ppvv = &vv->next;
1156
1157               data += 4;
1158               length -= 4;
1159
1160               if (vallen < 4)
1161                 fatal (_("unexpected version value length %ld"), (long) vallen);
1162
1163               vallen -= 4;
1164             }
1165         }
1166       else if (ch == 0)
1167         {
1168           if (length == 8)
1169             /* Padding - skip.  */
1170             break;
1171           fatal (_("nul bytes found in version string"));
1172         }
1173       else
1174         fatal (_("unexpected version string character: %x"), ch);
1175
1176       vi->next = NULL;
1177       *pp = vi;
1178       pp = &vi->next;
1179     }
1180
1181   v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1182   v->fixed = fi;
1183   v->var = first;
1184
1185   r = (rc_res_resource *) res_alloc (sizeof *r);
1186   r->type = RES_TYPE_VERSIONINFO;
1187   r->u.versioninfo = v;
1188
1189   return r;
1190 }
1191
1192 /* Convert an arbitrary user defined resource from binary.  */
1193
1194 static rc_res_resource *
1195 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1196                      rc_uint_type length)
1197 {
1198   rc_rcdata_item *ri;
1199   rc_res_resource *r;
1200
1201   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1202
1203   ri->next = NULL;
1204   ri->type = RCDATA_BUFFER;
1205   ri->u.buffer.length = length;
1206   ri->u.buffer.data = data;
1207
1208   r = (rc_res_resource *) res_alloc (sizeof *r);
1209   r->type = RES_TYPE_USERDATA;
1210   r->u.rcdata = ri;
1211
1212   return r;
1213 }
1214 \f
1215 static rc_res_resource *
1216 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1217 {
1218   rc_toolbar *ri;
1219   rc_res_resource *r;
1220   rc_uint_type i;
1221
1222   ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1223   ri->button_width = windres_get_32 (wrbfd, data, 4);
1224   ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1225   ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1226   ri->items = NULL;
1227
1228   data += 12;
1229   length -= 12;
1230   for (i=0 ; i < ri->nitems; i++)
1231   {
1232     rc_toolbar_item *it;
1233     it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1234     it->id.named = 0;
1235     it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1236     it->prev = it->next = NULL;
1237     data += 4;
1238     length -= 4;
1239     if(ri->items) {
1240       rc_toolbar_item *ii = ri->items;
1241       while (ii->next != NULL)
1242         ii = ii->next;
1243       it->prev = ii;
1244       ii->next = it;
1245     }
1246     else
1247       ri->items = it;
1248   }
1249   r = (rc_res_resource *) res_alloc (sizeof *r);
1250   r->type = RES_TYPE_TOOLBAR;
1251   r->u.toolbar = ri;
1252   return r;
1253 }
1254
1255
1256 /* Local functions used to convert resources to binary format.  */
1257
1258 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1259 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1260 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1261 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1262 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1263 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1264 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1265 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1266 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1267 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1268 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1269 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1270 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1271 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1272 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1273 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1274 static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1275                                         const bfd_byte *);
1276
1277 /* Convert a resource to binary.  */
1278
1279 rc_uint_type
1280 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1281 {
1282   switch (res->type)
1283     {
1284     case RES_TYPE_BITMAP:
1285     case RES_TYPE_FONT:
1286     case RES_TYPE_ICON:
1287     case RES_TYPE_MESSAGETABLE:
1288       return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1289     case RES_TYPE_ACCELERATOR:
1290       return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1291     case RES_TYPE_CURSOR:
1292       return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1293     case RES_TYPE_GROUP_CURSOR:
1294       return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1295     case RES_TYPE_DIALOG:
1296       return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1297     case RES_TYPE_FONTDIR:
1298       return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1299     case RES_TYPE_GROUP_ICON:
1300       return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1301     case RES_TYPE_MENU:
1302       return res_to_bin_menu (wrbfd, off, res->u.menu);
1303     case RES_TYPE_STRINGTABLE:
1304       return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1305     case RES_TYPE_VERSIONINFO:
1306       return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1307     case RES_TYPE_TOOLBAR:
1308       return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1309     case RES_TYPE_USERDATA:
1310     case RES_TYPE_RCDATA:
1311     default:
1312       return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1313     }
1314 }
1315
1316 /* Convert a resource ID to binary.  This always returns exactly one
1317    bindata structure.  */
1318
1319 static rc_uint_type
1320 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1321 {
1322   if (! id.named)
1323     {
1324       if (wrbfd)
1325         {
1326           struct bin_res_id bri;
1327
1328           windres_put_16 (wrbfd, bri.sig, 0xffff);
1329           windres_put_16 (wrbfd, bri.id, id.u.id);
1330           set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1331         }
1332       off += BIN_RES_ID;
1333     }
1334   else
1335     {
1336       rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1337       if (wrbfd)
1338         {
1339           bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1340           rc_uint_type i;
1341           for (i = 0; i < len; i++)
1342             windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1343           windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1344           set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1345     }
1346       off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1347     }
1348   return off;
1349 }
1350
1351 /* Convert a null terminated unicode string to binary.  This always
1352    returns exactly one bindata structure.  */
1353
1354 static rc_uint_type
1355 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1356 {
1357   rc_uint_type len = 0;
1358
1359   if (str != NULL)
1360     len = unichar_len (str);
1361
1362   if (wrbfd)
1363     {
1364       bfd_byte *d;
1365       rc_uint_type i;
1366       d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1367       for (i = 0; i < len; i++)
1368         windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1369       windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1370       set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1371     }
1372   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1373
1374   return off;
1375 }
1376
1377 /* Convert an accelerator resource to binary.  */
1378
1379 static rc_uint_type
1380 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1381                         const rc_accelerator *accelerators)
1382 {
1383   const rc_accelerator *a;
1384
1385   for (a = accelerators; a != NULL; a = a->next)
1386     {
1387       if (wrbfd)
1388         {
1389           struct bin_accelerator ba;
1390
1391           windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1392           windres_put_16 (wrbfd, ba.key, a->key);
1393           windres_put_16 (wrbfd, ba.id, a->id);
1394           windres_put_16 (wrbfd, ba.pad, 0);
1395           set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1396     }
1397       off += BIN_ACCELERATOR_SIZE;
1398     }
1399   return off;
1400 }
1401
1402 /* Convert a cursor resource to binary.  */
1403
1404 static rc_uint_type
1405 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1406 {
1407   if (wrbfd)
1408     {
1409       struct bin_cursor bc;
1410
1411       windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1412       windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1413       set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1414       if (c->length)
1415         set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1416     }
1417   off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1418   return off;
1419 }
1420
1421 /* Convert a group cursor resource to binary.  */
1422
1423 static rc_uint_type
1424 res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1425                          const rc_group_cursor *group_cursors)
1426 {
1427   int c = 0;
1428   const rc_group_cursor *gc;
1429   struct bin_group_cursor bgc;
1430   struct bin_group_cursor_item bgci;
1431   rc_uint_type start = off;
1432
1433   off += BIN_GROUP_CURSOR_SIZE;
1434
1435   for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1436     {
1437       if (wrbfd)
1438         {
1439           windres_put_16 (wrbfd, bgci.width, gc->width);
1440           windres_put_16 (wrbfd, bgci.height, gc->height);
1441           windres_put_16 (wrbfd, bgci.planes, gc->planes);
1442           windres_put_16 (wrbfd, bgci.bits, gc->bits);
1443           windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1444           windres_put_16 (wrbfd, bgci.index, gc->index);
1445           set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1446     }
1447
1448       off += BIN_GROUP_CURSOR_ITEM_SIZE;
1449     }
1450   if (wrbfd)
1451     {
1452       windres_put_16 (wrbfd, bgc.sig1, 0);
1453       windres_put_16 (wrbfd, bgc.sig2, 2);
1454       windres_put_16 (wrbfd, bgc.nitems, c);
1455       set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1456     }
1457   return off;
1458 }
1459
1460 /* Convert a dialog resource to binary.  */
1461
1462 static rc_uint_type
1463 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1464 {
1465   rc_uint_type off_delta;
1466   rc_uint_type start, marker;
1467   int dialogex;
1468   int c;
1469   rc_dialog_control *dc;
1470   struct bin_dialogex bdx;
1471   struct bin_dialog bd;
1472
1473   off_delta = off;
1474   start = off;
1475   dialogex = extended_dialog (dialog);
1476
1477   if (wrbfd)
1478     {
1479   if (! dialogex)
1480     {
1481           windres_put_32 (wrbfd, bd.style, dialog->style);
1482           windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1483           windres_put_16 (wrbfd, bd.x, dialog->x);
1484           windres_put_16 (wrbfd, bd.y, dialog->y);
1485           windres_put_16 (wrbfd, bd.width, dialog->width);
1486           windres_put_16 (wrbfd, bd.height, dialog->height);
1487     }
1488   else
1489     {
1490           windres_put_16 (wrbfd, bdx.sig1, 1);
1491           windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1492           windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1493           windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1494           windres_put_32 (wrbfd, bdx.style, dialog->style);
1495           windres_put_16 (wrbfd, bdx.x, dialog->x);
1496           windres_put_16 (wrbfd, bdx.y, dialog->y);
1497           windres_put_16 (wrbfd, bdx.width, dialog->width);
1498           windres_put_16 (wrbfd, bdx.height, dialog->height);
1499         }
1500     }
1501
1502   off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1503
1504   off = resid_to_bin (wrbfd, off, dialog->menu);
1505   off = resid_to_bin (wrbfd, off, dialog->class);
1506   off = unicode_to_bin (wrbfd, off, dialog->caption);
1507
1508   if ((dialog->style & DS_SETFONT) != 0)
1509     {
1510       if (wrbfd)
1511         {
1512           if (! dialogex)
1513             {
1514               struct bin_dialogfont bdf;
1515               windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1516               set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1517             }
1518           else
1519             {
1520               struct bin_dialogexfont bdxf;
1521               windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1522               windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1523               windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1524               windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1525               set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1526             }
1527         }
1528       off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1529       off = unicode_to_bin (wrbfd, off, dialog->font);
1530     }
1531   for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1532     {
1533       bfd_byte dc_rclen[2];
1534
1535       off += (4 - ((off - off_delta) & 3)) & 3;
1536       if (wrbfd)
1537         {
1538       if (! dialogex)
1539         {
1540               struct bin_dialog_control bdc;
1541
1542               windres_put_32 (wrbfd, bdc.style, dc->style);
1543               windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1544               windres_put_16 (wrbfd, bdc.x, dc->x);
1545               windres_put_16 (wrbfd, bdc.y, dc->y);
1546               windres_put_16 (wrbfd, bdc.width, dc->width);
1547               windres_put_16 (wrbfd, bdc.height, dc->height);
1548               windres_put_16 (wrbfd, bdc.id, dc->id);
1549               set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1550         }
1551       else
1552         {
1553               struct bin_dialogex_control bdc;
1554
1555               windres_put_32 (wrbfd, bdc.help, dc->help);
1556               windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1557               windres_put_32 (wrbfd, bdc.style, dc->style);
1558               windres_put_16 (wrbfd, bdc.x, dc->x);
1559               windres_put_16 (wrbfd, bdc.y, dc->y);
1560               windres_put_16 (wrbfd, bdc.width, dc->width);
1561               windres_put_16 (wrbfd, bdc.height, dc->height);
1562               windres_put_32 (wrbfd, bdc.id, dc->id);
1563               set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1564             }
1565         }
1566       off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1567
1568       off = resid_to_bin (wrbfd, off, dc->class);
1569       off = resid_to_bin (wrbfd, off, dc->text);
1570
1571       marker = off; /* Save two bytes for size of optional data.  */
1572       off += 2;
1573
1574       if (dc->data == NULL)
1575         {
1576           if (wrbfd)
1577             windres_put_16 (wrbfd, dc_rclen, 0);
1578         }
1579       else
1580         {
1581           rc_uint_type saved_off = off;
1582           rc_uint_type old_off;
1583
1584           old_off = off;
1585           off = res_to_bin_rcdata (wrbfd, off, dc->data);
1586           if ((off - old_off) == 0)
1587             old_off = off = saved_off;
1588           if (wrbfd)
1589             windres_put_16 (wrbfd, dc_rclen, off - old_off);
1590         }
1591       if (wrbfd)
1592         set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1593     }
1594
1595   if (wrbfd)
1596     {
1597       windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1598       if (! dialogex)
1599         set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1600       else
1601         set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1602     }
1603
1604   return off;
1605 }
1606
1607 /* Convert a fontdir resource to binary.  */
1608 static rc_uint_type
1609 res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
1610 {
1611   rc_uint_type start;
1612   int c;
1613   const rc_fontdir *fd;
1614
1615   start = off;
1616   off += 2;
1617
1618   for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1619     {
1620       if (wrbfd)
1621         {
1622           bfd_byte d[2];
1623           windres_put_16 (wrbfd, d, fd->index);
1624           set_windres_bfd_content (wrbfd, d, off, 2);
1625           if (fd->length)
1626             set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1627         }
1628       off += (rc_uint_type) fd->length + 2;
1629     }
1630
1631   if (wrbfd)
1632     {
1633       bfd_byte d[2];
1634       windres_put_16 (wrbfd, d, c);
1635       set_windres_bfd_content (wrbfd, d, start, 2);
1636     }
1637   return off;
1638 }
1639
1640 /* Convert a group icon resource to binary.  */
1641
1642 static rc_uint_type
1643 res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1644 {
1645   rc_uint_type start;
1646   struct bin_group_icon bgi;
1647   int c;
1648   const rc_group_icon *gi;
1649
1650   start = off;
1651   off += BIN_GROUP_ICON_SIZE;
1652
1653   for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1654     {
1655       struct bin_group_icon_item bgii;
1656
1657       if (wrbfd)
1658         {
1659           windres_put_8 (wrbfd, bgii.width, gi->width);
1660           windres_put_8 (wrbfd, bgii.height, gi->height);
1661           windres_put_8 (wrbfd, bgii.colors, gi->colors);
1662           windres_put_8 (wrbfd, bgii.pad, 0);
1663           windres_put_16 (wrbfd, bgii.planes, gi->planes);
1664           windres_put_16 (wrbfd, bgii.bits, gi->bits);
1665           windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1666           windres_put_16 (wrbfd, bgii.index, gi->index);
1667           set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1668         }
1669       off += BIN_GROUP_ICON_ITEM_SIZE;
1670     }
1671
1672   if (wrbfd)
1673     {
1674       windres_put_16 (wrbfd, bgi.sig1, 0);
1675       windres_put_16 (wrbfd, bgi.sig2, 1);
1676       windres_put_16 (wrbfd, bgi.count, c);
1677       set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1678     }
1679   return off;
1680 }
1681
1682 /* Convert a menu resource to binary.  */
1683
1684 static rc_uint_type
1685 res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1686 {
1687   int menuex;
1688
1689   menuex = extended_menu (menu);
1690
1691   if (wrbfd)
1692     {
1693   if (! menuex)
1694     {
1695           struct bin_menu bm;
1696           windres_put_16 (wrbfd, bm.sig1, 0);
1697           windres_put_16 (wrbfd, bm.sig2, 0);
1698           set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1699     }
1700   else
1701     {
1702           struct bin_menuex bm;
1703           windres_put_16 (wrbfd, bm.sig1, 1);
1704           windres_put_16 (wrbfd, bm.sig2, 4);
1705           windres_put_32 (wrbfd, bm.help, menu->help);
1706           set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1707     }
1708     }
1709   off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1710   if (! menuex)
1711     {
1712       off = res_to_bin_menuitems (wrbfd, off, menu->items);
1713     }
1714   else
1715     {
1716       off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1717     }
1718   return off;
1719 }
1720
1721 /* Convert menu items to binary.  */
1722
1723 static rc_uint_type
1724 res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1725 {
1726   const rc_menuitem *mi;
1727
1728   for (mi = items; mi != NULL; mi = mi->next)
1729     {
1730       struct bin_menuitem bmi;
1731       int flags;
1732
1733       flags = mi->type;
1734       if (mi->next == NULL)
1735         flags |= MENUITEM_ENDMENU;
1736       if (mi->popup != NULL)
1737         flags |= MENUITEM_POPUP;
1738
1739       if (wrbfd)
1740         {
1741           windres_put_16 (wrbfd, bmi.flags, flags);
1742       if (mi->popup == NULL)
1743             windres_put_16 (wrbfd, bmi.id, mi->id);
1744           set_windres_bfd_content (wrbfd, &bmi, off,
1745                                    mi->popup == NULL ? BIN_MENUITEM_SIZE
1746                                                      : BIN_MENUITEM_POPUP_SIZE);
1747         }
1748       off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1749
1750       off = unicode_to_bin (wrbfd, off, mi->text);
1751
1752       if (mi->popup != NULL)
1753         {
1754           off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1755         }
1756     }
1757   return off;
1758 }
1759
1760 /* Convert menuex items to binary.  */
1761
1762 static rc_uint_type
1763 res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1764 {
1765   rc_uint_type off_delta = off;
1766   const rc_menuitem *mi;
1767
1768   for (mi = items; mi != NULL; mi = mi->next)
1769     {
1770       struct bin_menuitemex bmi;
1771       int flags;
1772
1773       off += (4 - ((off - off_delta) & 3)) & 3;
1774
1775       flags = 0;
1776       if (mi->next == NULL)
1777         flags |= 0x80;
1778       if (mi->popup != NULL)
1779         flags |= 1;
1780
1781       if (wrbfd)
1782         {
1783           windres_put_32 (wrbfd, bmi.type, mi->type);
1784           windres_put_32 (wrbfd, bmi.state, mi->state);
1785           windres_put_32 (wrbfd, bmi.id, mi->id);
1786           windres_put_16 (wrbfd, bmi.flags, flags);
1787           set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1788         }
1789       off += BIN_MENUITEMEX_SIZE;
1790
1791       off = unicode_to_bin (wrbfd, off, mi->text);
1792
1793       if (mi->popup != NULL)
1794         {
1795           bfd_byte help[4];
1796
1797           off += (4 - ((off - off_delta) & 3)) & 3;
1798
1799           if (wrbfd)
1800             {
1801               windres_put_32 (wrbfd, help, mi->help);
1802               set_windres_bfd_content (wrbfd, help, off, 4);
1803             }
1804           off += 4;
1805           off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1806         }
1807     }
1808   return off;
1809 }
1810
1811 /* Convert an rcdata resource to binary.  This is also used to convert
1812    other information which happens to be stored in rc_rcdata_item lists
1813    to binary.  */
1814
1815 static rc_uint_type
1816 res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1817 {
1818   const rc_rcdata_item *ri;
1819
1820   for (ri = items; ri != NULL; ri = ri->next)
1821     {
1822       rc_uint_type len;
1823       switch (ri->type)
1824         {
1825         default:
1826           abort ();
1827         case RCDATA_WORD:
1828           len = 2;
1829           break;
1830         case RCDATA_DWORD:
1831           len = 4;
1832           break;
1833         case RCDATA_STRING:
1834           len = ri->u.string.length;
1835           break;
1836         case RCDATA_WSTRING:
1837           len = ri->u.wstring.length * sizeof (unichar);
1838           break;
1839         case RCDATA_BUFFER:
1840           len = ri->u.buffer.length;
1841           break;
1842         }
1843       if (wrbfd)
1844         {
1845           bfd_byte h[4];
1846           bfd_byte *hp = &h[0];
1847           switch (ri->type)
1848             {
1849             case RCDATA_WORD:
1850               windres_put_16 (wrbfd, hp, ri->u.word);
1851               break;
1852             case RCDATA_DWORD:
1853               windres_put_32 (wrbfd, hp, ri->u.dword);
1854               break;
1855             case RCDATA_STRING:
1856               hp = (bfd_byte *) ri->u.string.s;
1857           break;
1858         case RCDATA_WSTRING:
1859           {
1860                 rc_uint_type i;
1861
1862                 hp = (bfd_byte *) reswr_alloc (len);
1863             for (i = 0; i < ri->u.wstring.length; i++)
1864                   windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
1865           }
1866               break;
1867         case RCDATA_BUFFER:
1868               hp = (bfd_byte *) ri->u.buffer.data;
1869           break;
1870         }
1871           set_windres_bfd_content (wrbfd, hp, off, len);
1872     }
1873       off += len;
1874     }
1875   return off;
1876 }
1877
1878 /* Convert a stringtable resource to binary.  */
1879
1880 static rc_uint_type
1881 res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1882                         const rc_stringtable *st)
1883 {
1884   int i;
1885
1886   for (i = 0; i < 16; i++)
1887     {
1888       rc_uint_type slen, length;
1889       unichar *s;
1890
1891       slen = (rc_uint_type) st->strings[i].length;
1892       if (slen == 0xffffffff) slen = 0;
1893       s = st->strings[i].string;
1894
1895       length = 2 + slen * 2;
1896       if (wrbfd)
1897         {
1898           bfd_byte *hp;
1899           rc_uint_type j;
1900
1901           hp = (bfd_byte *) reswr_alloc (length);
1902           windres_put_16 (wrbfd, hp, slen);
1903
1904       for (j = 0; j < slen; j++)
1905             windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1906           set_windres_bfd_content (wrbfd, hp, off, length);
1907     }
1908       off += length;
1909     }
1910   return off;
1911 }
1912
1913 /* Convert an ASCII string to a unicode binary string.  This always
1914    returns exactly one bindata structure.  */
1915
1916 static rc_uint_type
1917 string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1918 {
1919   rc_uint_type len;
1920
1921   len = (rc_uint_type) strlen (s);
1922
1923   if (wrbfd)
1924     {
1925       rc_uint_type i;
1926       bfd_byte *hp;
1927
1928       hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1929
1930       for (i = 0; i < len; i++)
1931         windres_put_16 (wrbfd, hp + i * 2, s[i]);
1932       windres_put_16 (wrbfd, hp + i * 2, 0);
1933       set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1934     }
1935   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1936   return off;
1937 }
1938
1939 static rc_uint_type
1940 res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1941 {
1942   if (wrbfd)
1943     {
1944       struct bin_toolbar bt;
1945       windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1946       windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1947       windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1948       set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1949       if (tb->nitems > 0)
1950         {
1951           rc_toolbar_item *it;
1952           bfd_byte *ids;
1953           rc_uint_type i = 0;
1954
1955           ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1956           it=tb->items;
1957           while(it != NULL)
1958             {
1959               windres_put_32 (wrbfd, ids + i, it->id.u.id);
1960               i += 4;
1961               it = it->next;
1962             }
1963           set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1964         }
1965     }
1966   off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1967
1968   return off;
1969 }
1970
1971 /* Convert a versioninfo resource to binary.  */
1972
1973 static rc_uint_type
1974 res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1975                         const rc_versioninfo *versioninfo)
1976 {
1977   rc_uint_type off_delta = off;
1978   rc_uint_type start;
1979   struct bin_versioninfo bvi;
1980   rc_ver_info *vi;
1981
1982   start = off;
1983   off += BIN_VERSIONINFO_SIZE;
1984   off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1985   off += (4 - ((off - off_delta) & 3)) & 3;
1986
1987   if (versioninfo->fixed != NULL)
1988     {
1989       if (wrbfd)
1990         {
1991           struct bin_fixed_versioninfo bfv;
1992           const rc_fixed_versioninfo *fi;
1993
1994       fi = versioninfo->fixed;
1995           windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1996           windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1997           windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1998           windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
1999           windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
2000           windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
2001           windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
2002           windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
2003           windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
2004           windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
2005           windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
2006           windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
2007           windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
2008           set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
2009         }
2010       off += BIN_FIXED_VERSIONINFO_SIZE;
2011     }
2012
2013   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2014     {
2015       struct bin_ver_info bv;
2016       rc_uint_type bv_off;
2017
2018       off += (4 - ((off - off_delta) & 3)) & 3;
2019
2020       bv_off = off;
2021
2022       off += BIN_VER_INFO_SIZE;
2023
2024       switch (vi->type)
2025         {
2026         default:
2027           abort ();
2028         case VERINFO_STRING:
2029           {
2030             const rc_ver_stringtable *vst;
2031
2032             off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2033
2034             if (!vi->u.string.stringtables)
2035               off += (4 - ((off - off_delta) & 3)) & 3;
2036
2037             for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
2038               {
2039                 struct bin_ver_info bvst;
2040                 rc_uint_type vst_off;
2041                 const rc_ver_stringinfo *vs;
2042
2043                 off += (4 - ((off - off_delta) & 3)) & 3;
2044
2045                 vst_off = off;
2046                 off += BIN_VER_INFO_SIZE;
2047
2048                 off = unicode_to_bin (wrbfd, off, vst->language);
2049
2050                 for (vs = vst->strings; vs != NULL; vs = vs->next)
2051                   {
2052                     struct bin_ver_info bvs;
2053                     rc_uint_type vs_off, str_off;
2054
2055                     off += (4 - ((off - off_delta) & 3)) & 3;
2056
2057                     vs_off = off;
2058                     off += BIN_VER_INFO_SIZE;
2059
2060                     off = unicode_to_bin (wrbfd, off, vs->key);
2061
2062                     off += (4 - ((off - off_delta) & 3)) & 3;
2063
2064                     str_off = off;
2065                     off = unicode_to_bin (wrbfd, off, vs->value);
2066
2067                     if (wrbfd)
2068                       {
2069                         windres_put_16 (wrbfd, bvs.size, off - vs_off);
2070                         windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
2071                         windres_put_16 (wrbfd, bvs.sig2, 1);
2072                         set_windres_bfd_content (wrbfd, &bvs, vs_off,
2073                                                  BIN_VER_INFO_SIZE);
2074                       }
2075                   }
2076
2077                 if (wrbfd)
2078                   {
2079                     windres_put_16 (wrbfd, bvst.size, off - vst_off);
2080                     windres_put_16 (wrbfd, bvst.sig1, 0);
2081                     windres_put_16 (wrbfd, bvst.sig2, 1);
2082                     set_windres_bfd_content (wrbfd, &bvst, vst_off,
2083                                              BIN_VER_INFO_SIZE);
2084                   }
2085               }
2086             break;
2087           }
2088
2089         case VERINFO_VAR:
2090           {
2091             rc_uint_type vvd_off, vvvd_off;
2092             struct bin_ver_info bvvd;
2093             const rc_ver_varinfo *vv;
2094
2095             off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2096
2097             off += (4 - ((off - off_delta) & 3)) & 3;
2098
2099             vvd_off = off;
2100             off += BIN_VER_INFO_SIZE;
2101
2102             off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2103
2104             off += (4 - ((off - off_delta) & 3)) & 3;
2105
2106             vvvd_off = off;
2107
2108             for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2109               {
2110                 if (wrbfd)
2111                   {
2112                     bfd_byte vvsd[4];
2113
2114                     windres_put_16 (wrbfd, &vvsd[0], vv->language);
2115                     windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2116                     set_windres_bfd_content (wrbfd, vvsd, off, 4);
2117                   }
2118                 off += 4;
2119               }
2120             if (wrbfd)
2121             {
2122                 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2123                 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2124                 windres_put_16 (wrbfd, bvvd.sig2, 0);
2125                 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2126                                          BIN_VER_INFO_SIZE);
2127             }
2128
2129             break;
2130           }
2131         }
2132
2133       if (wrbfd)
2134         {
2135           windres_put_16 (wrbfd, bv.size, off - bv_off);
2136           windres_put_16 (wrbfd, bv.sig1, 0);
2137           windres_put_16 (wrbfd, bv.sig2, 1);
2138           set_windres_bfd_content (wrbfd, &bv, bv_off,
2139                                    BIN_VER_INFO_SIZE);
2140         }
2141     }
2142
2143   if (wrbfd)
2144     {
2145       windres_put_16 (wrbfd, bvi.size, off - start);
2146       windres_put_16 (wrbfd, bvi.fixed_size,
2147                       versioninfo->fixed == NULL ? 0
2148                                                  : BIN_FIXED_VERSIONINFO_SIZE);
2149       windres_put_16 (wrbfd, bvi.sig2, 0);
2150       set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2151     }
2152   return off;
2153 }
2154
2155 /* Convert a generic resource to binary.  */
2156
2157 static rc_uint_type
2158 res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2159                     const bfd_byte *data)
2160 {
2161   if (wrbfd && length != 0)
2162     set_windres_bfd_content (wrbfd, data, off, length);
2163   return off + (rc_uint_type) length;
2164 }