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