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