Upload Tizen:Base source
[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
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);
913   *vallen = windres_get_16 (wrbfd, data + 2, 2);
914   *type = windres_get_16 (wrbfd, data + 4, 2);
915
916   *off = 6;
917
918   length -= 6;
919   data += 6;
920
921   if (key == NULL)
922     {
923       rc_uint_type sublen;
924
925       *pkey = get_unicode (wrbfd, data, length, &sublen);
926       *off += (sublen + 1) * sizeof (unichar);
927     }
928   else
929     {
930       while (1)
931         {
932           if (length < 2)
933             toosmall (key);
934           if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
935             fatal (_("unexpected version string"));
936
937           *off += 2;
938           length -= 2;
939           data += 2;
940
941           if (*key == '\0')
942             break;
943
944           ++key;
945         }
946     }
947
948   *off = (*off + 3) &~ 3;
949 }
950
951 /* Convert a version resource from binary.  */
952
953 static rc_res_resource *
954 bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
955 {
956   rc_uint_type verlen, vallen, type, off;
957   rc_fixed_versioninfo *fi;
958   rc_ver_info *first, **pp;
959   rc_versioninfo *v;
960   rc_res_resource *r;
961
962   get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
963                       (unichar **) NULL, &verlen, &vallen, &type, &off);
964
965   if ((unsigned int) verlen != length)
966     fatal (_("version length %d does not match resource length %lu"),
967            (int) verlen, (unsigned long) length);
968
969   if (type != 0)
970     fatal (_("unexpected version type %d"), (int) type);
971
972   data += off;
973   length -= off;
974
975   if (vallen == 0)
976     fi = NULL;
977   else
978     {
979       unsigned long signature, fiv;
980
981       if (vallen != 52)
982         fatal (_("unexpected fixed version information length %ld"), (long) vallen);
983
984       if (length < 52)
985         toosmall (_("fixed version info"));
986
987       signature = windres_get_32 (wrbfd, data, 4);
988       if (signature != 0xfeef04bd)
989         fatal (_("unexpected fixed version signature %lu"), signature);
990
991       fiv = windres_get_32 (wrbfd, data + 4, 4);
992       if (fiv != 0 && fiv != 0x10000)
993         fatal (_("unexpected fixed version info version %lu"), fiv);
994
995       fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
996
997       fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
998       fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
999       fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
1000       fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
1001       fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1002       fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1003       fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1004       fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1005       fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1006       fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1007       fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
1008
1009       data += 52;
1010       length -= 52;
1011     }
1012
1013   first = NULL;
1014   pp = &first;
1015
1016   while (length > 0)
1017     {
1018       rc_ver_info *vi;
1019       int ch;
1020
1021       if (length < 8)
1022         toosmall (_("version var info"));
1023
1024       vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1025
1026       ch = windres_get_16 (wrbfd, data + 6, 2);
1027
1028       if (ch == 'S')
1029         {
1030           rc_ver_stringinfo **ppvs;
1031
1032           vi->type = VERINFO_STRING;
1033
1034           get_version_header (wrbfd, data, length, "StringFileInfo",
1035                               (unichar **) NULL, &verlen, &vallen, &type,
1036                               &off);
1037
1038           if (vallen != 0)
1039             fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1040
1041           data += off;
1042           length -= off;
1043
1044           get_version_header (wrbfd, data, length, (const char *) NULL,
1045                               &vi->u.string.language, &verlen, &vallen,
1046                               &type, &off);
1047
1048           if (vallen != 0)
1049             fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1050
1051           data += off;
1052           length -= off;
1053           verlen -= off;
1054
1055           vi->u.string.strings = NULL;
1056           ppvs = &vi->u.string.strings;
1057
1058           /* It's convenient to round verlen to a 4 byte alignment,
1059              since we round the subvariables in the loop.  */
1060           verlen = (verlen + 3) &~ 3;
1061
1062           while (verlen > 0)
1063             {
1064               rc_ver_stringinfo *vs;
1065               rc_uint_type subverlen, vslen, valoff;
1066
1067               vs = (rc_ver_stringinfo *) res_alloc (sizeof *vs);
1068
1069               get_version_header (wrbfd, data, length,
1070                                   (const char *) NULL, &vs->key, &subverlen,
1071                                   &vallen, &type, &off);
1072
1073               subverlen = (subverlen + 3) &~ 3;
1074
1075               data += off;
1076               length -= off;
1077
1078               vs->value = get_unicode (wrbfd, data, length, &vslen);
1079               valoff = vslen * 2 + 2;
1080               valoff = (valoff + 3) &~ 3;
1081
1082               if (off + valoff != subverlen)
1083                 fatal (_("unexpected version string length %ld != %ld + %ld"),
1084                        (long) subverlen, (long) off, (long) valoff);
1085
1086               vs->next = NULL;
1087               *ppvs = vs;
1088               ppvs = &vs->next;
1089
1090               data += valoff;
1091               length -= valoff;
1092
1093               if (verlen < subverlen)
1094                 fatal (_("unexpected version string length %ld < %ld"),
1095                        (long) verlen, (long) subverlen);
1096
1097               verlen -= subverlen;
1098             }
1099         }
1100       else if (ch == 'V')
1101         {
1102           rc_ver_varinfo **ppvv;
1103
1104           vi->type = VERINFO_VAR;
1105
1106           get_version_header (wrbfd, data, length, "VarFileInfo",
1107                               (unichar **) NULL, &verlen, &vallen, &type,
1108                               &off);
1109
1110           if (vallen != 0)
1111             fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1112
1113           data += off;
1114           length -= off;
1115
1116           get_version_header (wrbfd, data, length, (const char *) NULL,
1117                               &vi->u.var.key, &verlen, &vallen, &type, &off);
1118
1119           data += off;
1120           length -= off;
1121
1122           vi->u.var.var = NULL;
1123           ppvv = &vi->u.var.var;
1124
1125           while (vallen > 0)
1126             {
1127               rc_ver_varinfo *vv;
1128
1129               if (length < 4)
1130                 toosmall (_("version varfileinfo"));
1131
1132               vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1133
1134               vv->language = windres_get_16 (wrbfd, data, 2);
1135               vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1136
1137               vv->next = NULL;
1138               *ppvv = vv;
1139               ppvv = &vv->next;
1140
1141               data += 4;
1142               length -= 4;
1143
1144               if (vallen < 4)
1145                 fatal (_("unexpected version value length %ld"), (long) vallen);
1146
1147               vallen -= 4;
1148             }
1149         }
1150       else
1151         fatal (_("unexpected version string"));
1152
1153       vi->next = NULL;
1154       *pp = vi;
1155       pp = &vi->next;
1156     }
1157
1158   v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1159   v->fixed = fi;
1160   v->var = first;
1161
1162   r = (rc_res_resource *) res_alloc (sizeof *r);
1163   r->type = RES_TYPE_VERSIONINFO;
1164   r->u.versioninfo = v;
1165
1166   return r;
1167 }
1168
1169 /* Convert an arbitrary user defined resource from binary.  */
1170
1171 static rc_res_resource *
1172 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1173                      rc_uint_type length)
1174 {
1175   rc_rcdata_item *ri;
1176   rc_res_resource *r;
1177
1178   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1179
1180   ri->next = NULL;
1181   ri->type = RCDATA_BUFFER;
1182   ri->u.buffer.length = length;
1183   ri->u.buffer.data = data;
1184
1185   r = (rc_res_resource *) res_alloc (sizeof *r);
1186   r->type = RES_TYPE_USERDATA;
1187   r->u.rcdata = ri;
1188
1189   return r;
1190 }
1191 \f
1192 static rc_res_resource *
1193 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1194 {
1195   rc_toolbar *ri;
1196   rc_res_resource *r;
1197   rc_uint_type i;
1198
1199   ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1200   ri->button_width = windres_get_32 (wrbfd, data, 4);
1201   ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1202   ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1203   ri->items = NULL;
1204
1205   data += 12;
1206   length -= 12;
1207   for (i=0 ; i < ri->nitems; i++)
1208   {
1209     rc_toolbar_item *it;
1210     it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1211     it->id.named = 0;
1212     it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1213     it->prev = it->next = NULL;
1214     data += 4;
1215     length -= 4;
1216     if(ri->items) {
1217       rc_toolbar_item *ii = ri->items;
1218       while (ii->next != NULL)
1219         ii = ii->next;
1220       it->prev = ii;
1221       ii->next = it;
1222     }
1223     else
1224       ri->items = it;
1225   }
1226   r = (rc_res_resource *) res_alloc (sizeof *r);
1227   r->type = RES_TYPE_TOOLBAR;
1228   r->u.toolbar = ri;
1229   return r;
1230 }
1231
1232
1233 /* Local functions used to convert resources to binary format.  */
1234
1235 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1236 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1237 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1238 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1239 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1240 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1241 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1242 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1243 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1244 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1245 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1246 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1247 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1248 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1249 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1250 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1251 static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1252                                         const bfd_byte *);
1253
1254 /* Convert a resource to binary.  */
1255
1256 rc_uint_type
1257 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1258 {
1259   switch (res->type)
1260     {
1261     case RES_TYPE_BITMAP:
1262     case RES_TYPE_FONT:
1263     case RES_TYPE_ICON:
1264     case RES_TYPE_MESSAGETABLE:
1265       return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1266     case RES_TYPE_ACCELERATOR:
1267       return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1268     case RES_TYPE_CURSOR:
1269       return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1270     case RES_TYPE_GROUP_CURSOR:
1271       return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1272     case RES_TYPE_DIALOG:
1273       return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1274     case RES_TYPE_FONTDIR:
1275       return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1276     case RES_TYPE_GROUP_ICON:
1277       return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1278     case RES_TYPE_MENU:
1279       return res_to_bin_menu (wrbfd, off, res->u.menu);
1280     case RES_TYPE_STRINGTABLE:
1281       return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1282     case RES_TYPE_VERSIONINFO:
1283       return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1284     case RES_TYPE_TOOLBAR:
1285       return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1286     case RES_TYPE_USERDATA:
1287     case RES_TYPE_RCDATA:
1288     default:
1289       return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1290     }
1291 }
1292
1293 /* Convert a resource ID to binary.  This always returns exactly one
1294    bindata structure.  */
1295
1296 static rc_uint_type
1297 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1298 {
1299   if (! id.named)
1300     {
1301       if (wrbfd)
1302         {
1303           struct bin_res_id bri;
1304           
1305           windres_put_16 (wrbfd, bri.sig, 0xffff);
1306           windres_put_16 (wrbfd, bri.id, id.u.id);
1307           set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1308         }
1309       off += BIN_RES_ID;
1310     }
1311   else
1312     {
1313       rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1314       if (wrbfd)
1315         {
1316           bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1317           rc_uint_type i;
1318           for (i = 0; i < len; i++)
1319             windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1320           windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1321           set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1322     }
1323       off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1324     }
1325   return off;
1326 }
1327
1328 /* Convert a null terminated unicode string to binary.  This always
1329    returns exactly one bindata structure.  */
1330
1331 static rc_uint_type
1332 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1333 {
1334   rc_uint_type len = 0;
1335
1336   if (str != NULL)
1337     len = unichar_len (str);
1338
1339   if (wrbfd)
1340     {
1341       bfd_byte *d;
1342       rc_uint_type i;
1343       d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1344       for (i = 0; i < len; i++)
1345         windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1346       windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1347       set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1348     }
1349   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1350
1351   return off;
1352 }
1353
1354 /* Convert an accelerator resource to binary.  */
1355
1356 static rc_uint_type
1357 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1358                         const rc_accelerator *accelerators)
1359 {
1360   const rc_accelerator *a;
1361
1362   for (a = accelerators; a != NULL; a = a->next)
1363     {
1364       if (wrbfd)
1365         {
1366           struct bin_accelerator ba;
1367
1368           windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1369           windres_put_16 (wrbfd, ba.key, a->key);
1370           windres_put_16 (wrbfd, ba.id, a->id);
1371           windres_put_16 (wrbfd, ba.pad, 0);
1372           set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1373     }
1374       off += BIN_ACCELERATOR_SIZE;
1375     }
1376   return off;
1377 }
1378
1379 /* Convert a cursor resource to binary.  */
1380
1381 static rc_uint_type
1382 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1383 {
1384   if (wrbfd)
1385     {
1386       struct bin_cursor bc;
1387
1388       windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1389       windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1390       set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1391       if (c->length)
1392         set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1393     }
1394   off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1395   return off;
1396 }
1397
1398 /* Convert a group cursor resource to binary.  */
1399
1400 static rc_uint_type
1401 res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1402                          const rc_group_cursor *group_cursors)
1403 {
1404   int c = 0;
1405   const rc_group_cursor *gc;
1406   struct bin_group_cursor bgc;
1407   struct bin_group_cursor_item bgci;
1408   rc_uint_type start = off;
1409
1410   off += BIN_GROUP_CURSOR_SIZE;
1411
1412   for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1413     {
1414       if (wrbfd)
1415         {
1416           windres_put_16 (wrbfd, bgci.width, gc->width);
1417           windres_put_16 (wrbfd, bgci.height, gc->height);
1418           windres_put_16 (wrbfd, bgci.planes, gc->planes);
1419           windres_put_16 (wrbfd, bgci.bits, gc->bits);
1420           windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1421           windres_put_16 (wrbfd, bgci.index, gc->index);
1422           set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1423     }
1424
1425       off += BIN_GROUP_CURSOR_ITEM_SIZE;
1426     }
1427   if (wrbfd)
1428     {
1429       windres_put_16 (wrbfd, bgc.sig1, 0);
1430       windres_put_16 (wrbfd, bgc.sig2, 2);
1431       windres_put_16 (wrbfd, bgc.nitems, c);
1432       set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1433     }
1434   return off;
1435 }
1436
1437 /* Convert a dialog resource to binary.  */
1438
1439 static rc_uint_type
1440 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1441 {
1442   rc_uint_type off_delta;
1443   rc_uint_type start, marker;
1444   int dialogex;
1445   int c;
1446   rc_dialog_control *dc;
1447   struct bin_dialogex bdx;
1448   struct bin_dialog bd;
1449
1450   off_delta = off;
1451   start = off;
1452   dialogex = extended_dialog (dialog);
1453
1454   if (wrbfd)
1455     {
1456   if (! dialogex)
1457     {
1458           windres_put_32 (wrbfd, bd.style, dialog->style);
1459           windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1460           windres_put_16 (wrbfd, bd.x, dialog->x);
1461           windres_put_16 (wrbfd, bd.y, dialog->y);
1462           windres_put_16 (wrbfd, bd.width, dialog->width);
1463           windres_put_16 (wrbfd, bd.height, dialog->height);
1464     }
1465   else
1466     {
1467           windres_put_16 (wrbfd, bdx.sig1, 1);
1468           windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1469           windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1470           windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1471           windres_put_32 (wrbfd, bdx.style, dialog->style);
1472           windres_put_16 (wrbfd, bdx.x, dialog->x);
1473           windres_put_16 (wrbfd, bdx.y, dialog->y);
1474           windres_put_16 (wrbfd, bdx.width, dialog->width);
1475           windres_put_16 (wrbfd, bdx.height, dialog->height);
1476         }
1477     }
1478
1479   off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1480
1481   off = resid_to_bin (wrbfd, off, dialog->menu);
1482   off = resid_to_bin (wrbfd, off, dialog->class);
1483   off = unicode_to_bin (wrbfd, off, dialog->caption);
1484
1485   if ((dialog->style & DS_SETFONT) != 0)
1486     {
1487       if (wrbfd)
1488         {
1489           if (! dialogex)
1490             {
1491               struct bin_dialogfont bdf;
1492               windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1493               set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1494             }
1495           else
1496             {
1497               struct bin_dialogexfont bdxf;
1498               windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1499               windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1500               windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1501               windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1502               set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1503             }
1504         }
1505       off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1506       off = unicode_to_bin (wrbfd, off, dialog->font);
1507     }
1508   for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1509     {
1510       bfd_byte dc_rclen[2];
1511
1512       off += (4 - ((off - off_delta) & 3)) & 3;
1513       if (wrbfd)
1514         {
1515       if (! dialogex)
1516         {
1517               struct bin_dialog_control bdc;
1518
1519               windres_put_32 (wrbfd, bdc.style, dc->style);
1520               windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1521               windres_put_16 (wrbfd, bdc.x, dc->x);
1522               windres_put_16 (wrbfd, bdc.y, dc->y);
1523               windres_put_16 (wrbfd, bdc.width, dc->width);
1524               windres_put_16 (wrbfd, bdc.height, dc->height);
1525               windres_put_16 (wrbfd, bdc.id, dc->id);
1526               set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1527         }
1528       else
1529         {
1530               struct bin_dialogex_control bdc;
1531
1532               windres_put_32 (wrbfd, bdc.help, dc->help);
1533               windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1534               windres_put_32 (wrbfd, bdc.style, dc->style);
1535               windres_put_16 (wrbfd, bdc.x, dc->x);
1536               windres_put_16 (wrbfd, bdc.y, dc->y);
1537               windres_put_16 (wrbfd, bdc.width, dc->width);
1538               windres_put_16 (wrbfd, bdc.height, dc->height);
1539               windres_put_32 (wrbfd, bdc.id, dc->id);
1540               set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1541             }
1542         }      
1543       off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1544
1545       off = resid_to_bin (wrbfd, off, dc->class);
1546       off = resid_to_bin (wrbfd, off, dc->text);
1547
1548       marker = off; /* Save two bytes for size of optional data.  */
1549       off += 2;
1550
1551       if (dc->data == NULL)
1552         {
1553           if (wrbfd)
1554             windres_put_16 (wrbfd, dc_rclen, 0);
1555         }
1556       else
1557         {
1558           rc_uint_type saved_off = off;
1559           rc_uint_type old_off;
1560           off += (4 - ((off - off_delta) & 3)) & 3;
1561
1562           old_off = off;
1563           off = res_to_bin_rcdata (wrbfd, off, dc->data);
1564           if ((off - old_off) == 0)
1565             old_off = off = saved_off;
1566           if (wrbfd)
1567             windres_put_16 (wrbfd, dc_rclen, off - old_off);
1568             }
1569       if (wrbfd)
1570         set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1571         }
1572
1573   if (wrbfd)
1574     {
1575       windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1576       if (! dialogex)
1577         set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1578       else
1579         set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1580     }
1581
1582   return off;
1583 }
1584
1585 /* Convert a fontdir resource to binary.  */
1586 static rc_uint_type
1587 res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
1588 {
1589   rc_uint_type start;
1590   int c;
1591   const rc_fontdir *fd;
1592
1593   start = off;
1594   off += 2;
1595
1596   for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1597     {
1598       if (wrbfd)
1599         {
1600           bfd_byte d[2];
1601           windres_put_16 (wrbfd, d, fd->index);
1602           set_windres_bfd_content (wrbfd, d, off, 2);
1603           if (fd->length)
1604             set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1605         }
1606       off += (rc_uint_type) fd->length + 2;
1607     }
1608
1609   if (wrbfd)
1610     {
1611       bfd_byte d[2];
1612       windres_put_16 (wrbfd, d, c);
1613       set_windres_bfd_content (wrbfd, d, start, 2);
1614     }
1615   return off;
1616 }
1617
1618 /* Convert a group icon resource to binary.  */
1619
1620 static rc_uint_type
1621 res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1622 {
1623   rc_uint_type start;
1624   struct bin_group_icon bgi;
1625   int c;
1626   const rc_group_icon *gi;
1627
1628   start = off;
1629   off += BIN_GROUP_ICON_SIZE;
1630
1631   for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1632     {
1633       struct bin_group_icon_item bgii;
1634
1635       if (wrbfd)
1636         {
1637           windres_put_8 (wrbfd, bgii.width, gi->width);
1638           windres_put_8 (wrbfd, bgii.height, gi->height);
1639           windres_put_8 (wrbfd, bgii.colors, gi->colors);
1640           windres_put_8 (wrbfd, bgii.pad, 0);
1641           windres_put_16 (wrbfd, bgii.planes, gi->planes);
1642           windres_put_16 (wrbfd, bgii.bits, gi->bits);
1643           windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1644           windres_put_16 (wrbfd, bgii.index, gi->index);
1645           set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1646         }
1647       off += BIN_GROUP_ICON_ITEM_SIZE;
1648     }
1649
1650   if (wrbfd)
1651     {
1652       windres_put_16 (wrbfd, bgi.sig1, 0);
1653       windres_put_16 (wrbfd, bgi.sig2, 1);
1654       windres_put_16 (wrbfd, bgi.count, c);
1655       set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1656     }
1657   return off;
1658 }
1659
1660 /* Convert a menu resource to binary.  */
1661
1662 static rc_uint_type
1663 res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1664 {
1665   int menuex;
1666
1667   menuex = extended_menu (menu);
1668
1669   if (wrbfd)
1670     {
1671   if (! menuex)
1672     {
1673           struct bin_menu bm;
1674           windres_put_16 (wrbfd, bm.sig1, 0);
1675           windres_put_16 (wrbfd, bm.sig2, 0);
1676           set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1677     }
1678   else
1679     {
1680           struct bin_menuex bm;
1681           windres_put_16 (wrbfd, bm.sig1, 1);
1682           windres_put_16 (wrbfd, bm.sig2, 4);
1683           windres_put_32 (wrbfd, bm.help, menu->help);
1684           set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1685     }
1686     }
1687   off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1688   if (! menuex)
1689     {
1690       off = res_to_bin_menuitems (wrbfd, off, menu->items);
1691     }
1692   else
1693     {
1694       off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1695     }
1696   return off;
1697 }
1698
1699 /* Convert menu items to binary.  */
1700
1701 static rc_uint_type
1702 res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1703 {
1704   const rc_menuitem *mi;
1705
1706   for (mi = items; mi != NULL; mi = mi->next)
1707     {
1708       struct bin_menuitem bmi;
1709       int flags;
1710
1711       flags = mi->type;
1712       if (mi->next == NULL)
1713         flags |= MENUITEM_ENDMENU;
1714       if (mi->popup != NULL)
1715         flags |= MENUITEM_POPUP;
1716
1717       if (wrbfd)
1718         {
1719           windres_put_16 (wrbfd, bmi.flags, flags);
1720       if (mi->popup == NULL)
1721             windres_put_16 (wrbfd, bmi.id, mi->id);
1722           set_windres_bfd_content (wrbfd, &bmi, off,
1723                                    mi->popup == NULL ? BIN_MENUITEM_SIZE
1724                                                      : BIN_MENUITEM_POPUP_SIZE);
1725         }
1726       off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1727
1728       off = unicode_to_bin (wrbfd, off, mi->text);
1729
1730       if (mi->popup != NULL)
1731         {
1732           off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1733         }
1734     }
1735   return off;
1736 }
1737
1738 /* Convert menuex items to binary.  */
1739
1740 static rc_uint_type
1741 res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1742 {
1743   rc_uint_type off_delta = off;
1744   const rc_menuitem *mi;
1745
1746   for (mi = items; mi != NULL; mi = mi->next)
1747     {
1748       struct bin_menuitemex bmi;
1749       int flags;
1750
1751       off += (4 - ((off - off_delta) & 3)) & 3;
1752
1753       flags = 0;
1754       if (mi->next == NULL)
1755         flags |= 0x80;
1756       if (mi->popup != NULL)
1757         flags |= 1;
1758
1759       if (wrbfd)
1760         {
1761           windres_put_32 (wrbfd, bmi.type, mi->type);
1762           windres_put_32 (wrbfd, bmi.state, mi->state);
1763           windres_put_32 (wrbfd, bmi.id, mi->id);
1764           windres_put_16 (wrbfd, bmi.flags, flags);
1765           set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1766         }
1767       off += BIN_MENUITEMEX_SIZE;
1768
1769       off = unicode_to_bin (wrbfd, off, mi->text);
1770
1771       if (mi->popup != NULL)
1772         {
1773           bfd_byte help[4];
1774
1775           off += (4 - ((off - off_delta) & 3)) & 3;
1776
1777           if (wrbfd)
1778             {
1779               windres_put_32 (wrbfd, help, mi->help);
1780               set_windres_bfd_content (wrbfd, help, off, 4);
1781             }
1782           off += 4;
1783           off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1784         }
1785     }
1786   return off;
1787 }
1788
1789 /* Convert an rcdata resource to binary.  This is also used to convert
1790    other information which happens to be stored in rc_rcdata_item lists
1791    to binary.  */
1792
1793 static rc_uint_type
1794 res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1795 {
1796   const rc_rcdata_item *ri;
1797
1798   for (ri = items; ri != NULL; ri = ri->next)
1799     {
1800       rc_uint_type len;
1801       switch (ri->type)
1802         {
1803         default:
1804           abort ();
1805         case RCDATA_WORD:
1806           len = 2;
1807           break;
1808         case RCDATA_DWORD:
1809           len = 4;
1810           break;
1811         case RCDATA_STRING:
1812           len = ri->u.string.length;
1813           break;
1814         case RCDATA_WSTRING:
1815           len = ri->u.wstring.length * sizeof (unichar);
1816           break;
1817         case RCDATA_BUFFER:
1818           len = ri->u.buffer.length;
1819           break;
1820         }
1821       if (wrbfd)
1822         {
1823           bfd_byte h[4];
1824           bfd_byte *hp = &h[0];
1825           switch (ri->type)
1826             {
1827             case RCDATA_WORD:
1828               windres_put_16 (wrbfd, hp, ri->u.word);
1829               break;
1830             case RCDATA_DWORD:
1831               windres_put_32 (wrbfd, hp, ri->u.dword);
1832               break;
1833             case RCDATA_STRING:
1834               hp = (bfd_byte *) ri->u.string.s;
1835           break;
1836         case RCDATA_WSTRING:
1837           {
1838                 rc_uint_type i;
1839
1840                 hp = (bfd_byte *) reswr_alloc (len);
1841             for (i = 0; i < ri->u.wstring.length; i++)
1842                   windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
1843           }
1844               break;
1845         case RCDATA_BUFFER:
1846               hp = (bfd_byte *) ri->u.buffer.data;
1847           break;
1848         }
1849           set_windres_bfd_content (wrbfd, hp, off, len);
1850     }
1851       off += len;
1852     }
1853   return off;
1854 }
1855
1856 /* Convert a stringtable resource to binary.  */
1857
1858 static rc_uint_type
1859 res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1860                         const rc_stringtable *st)
1861 {
1862   int i;
1863
1864   for (i = 0; i < 16; i++)
1865     {
1866       rc_uint_type slen, length;
1867       unichar *s;
1868
1869       slen = (rc_uint_type) st->strings[i].length;
1870       if (slen == 0xffffffff) slen = 0;
1871       s = st->strings[i].string;
1872
1873       length = 2 + slen * 2;
1874       if (wrbfd)
1875         {
1876           bfd_byte *hp;
1877           rc_uint_type j;
1878
1879           hp = (bfd_byte *) reswr_alloc (length);
1880           windres_put_16 (wrbfd, hp, slen);
1881
1882       for (j = 0; j < slen; j++)
1883             windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1884           set_windres_bfd_content (wrbfd, hp, off, length);
1885     }
1886       off += length;
1887     }
1888   return off;
1889 }
1890
1891 /* Convert an ASCII string to a unicode binary string.  This always
1892    returns exactly one bindata structure.  */
1893
1894 static rc_uint_type
1895 string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1896 {
1897   rc_uint_type len;
1898
1899   len = (rc_uint_type) strlen (s);
1900
1901   if (wrbfd)
1902     {
1903       rc_uint_type i;
1904       bfd_byte *hp;
1905
1906       hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1907
1908       for (i = 0; i < len; i++)
1909         windres_put_16 (wrbfd, hp + i * 2, s[i]);
1910       windres_put_16 (wrbfd, hp + i * 2, 0);
1911       set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1912     }
1913   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1914   return off;
1915 }
1916
1917 static rc_uint_type
1918 res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1919 {
1920   if (wrbfd)
1921     {
1922       struct bin_toolbar bt;
1923       windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1924       windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1925       windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1926       set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1927       if (tb->nitems > 0)
1928         {
1929           rc_toolbar_item *it;
1930           bfd_byte *ids;
1931           rc_uint_type i = 0;
1932
1933           ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1934           it=tb->items;
1935           while(it != NULL)
1936             {
1937               windres_put_32 (wrbfd, ids + i, it->id.u.id);
1938               i += 4;
1939               it = it->next;
1940             }
1941           set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1942         }
1943     }
1944   off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1945
1946   return off;
1947 }
1948
1949 /* Convert a versioninfo resource to binary.  */
1950
1951 static rc_uint_type
1952 res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1953                         const rc_versioninfo *versioninfo)
1954 {
1955   rc_uint_type off_delta = off;
1956   rc_uint_type start;
1957   struct bin_versioninfo bvi;
1958   rc_ver_info *vi;
1959
1960   start = off;
1961   off += BIN_VERSIONINFO_SIZE;
1962   off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1963   off += (4 - ((off - off_delta) & 3)) & 3;
1964
1965   if (versioninfo->fixed != NULL)
1966     {
1967       if (wrbfd)
1968         {
1969           struct bin_fixed_versioninfo bfv;
1970           const rc_fixed_versioninfo *fi;
1971
1972       fi = versioninfo->fixed;
1973           windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1974           windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1975           windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1976           windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
1977           windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
1978           windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
1979           windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
1980           windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
1981           windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
1982           windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
1983           windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
1984           windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
1985           windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
1986           set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
1987         }
1988       off += BIN_FIXED_VERSIONINFO_SIZE;
1989     }
1990
1991   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
1992     {
1993       struct bin_ver_info bv;
1994       rc_uint_type bv_off;
1995
1996       off += (4 - ((off - off_delta) & 3)) & 3;
1997
1998       bv_off = off;
1999
2000       off += BIN_VER_INFO_SIZE;
2001
2002       switch (vi->type)
2003         {
2004         default:
2005           abort ();
2006         case VERINFO_STRING:
2007           {
2008             struct bin_ver_info bvsd;
2009             rc_uint_type vs_off;
2010             const rc_ver_stringinfo *vs;
2011
2012             off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2013             off += (4 - ((off - off_delta) & 3)) & 3;
2014
2015             vs_off = off;
2016
2017             off += BIN_VER_INFO_SIZE;
2018
2019             off = unicode_to_bin (wrbfd, off, vi->u.string.language);
2020
2021             for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2022               {
2023                 struct bin_ver_info bvss;
2024                 rc_uint_type vss_off,str_off;
2025
2026                 off += (4 - ((off - off_delta) & 3)) & 3;
2027
2028                 vss_off = off;
2029                 off += BIN_VER_INFO_SIZE;
2030
2031                 off = unicode_to_bin (wrbfd, off, vs->key);
2032
2033                 off += (4 - ((off - off_delta) & 3)) & 3;
2034
2035                 str_off = off;
2036                 off = unicode_to_bin (wrbfd, off, vs->value);
2037                 if (wrbfd)
2038                   {
2039                     windres_put_16 (wrbfd, bvss.size, off - vss_off);
2040                     windres_put_16 (wrbfd, bvss.sig1, (off - str_off) / 2);
2041                     windres_put_16 (wrbfd, bvss.sig2, 1);
2042                     set_windres_bfd_content (wrbfd, &bvss, vss_off,
2043                                              BIN_VER_INFO_SIZE);
2044                   }
2045               }
2046             if (wrbfd)
2047               {
2048                 windres_put_16 (wrbfd, bvsd.size, off - vs_off);
2049                 windres_put_16 (wrbfd, bvsd.sig1, 0);
2050                 windres_put_16 (wrbfd, bvsd.sig2, 0);
2051                 set_windres_bfd_content (wrbfd, &bvsd, vs_off,
2052                                          BIN_VER_INFO_SIZE);
2053               }
2054             break;
2055           }
2056
2057         case VERINFO_VAR:
2058           {
2059             rc_uint_type vvd_off, vvvd_off;
2060             struct bin_ver_info bvvd;
2061             const rc_ver_varinfo *vv;
2062
2063             off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2064
2065             off += (4 - ((off - off_delta) & 3)) & 3;
2066
2067             vvd_off = off;
2068             off += BIN_VER_INFO_SIZE;
2069
2070             off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2071
2072             off += (4 - ((off - off_delta) & 3)) & 3;
2073
2074             vvvd_off = off;
2075
2076             for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2077               {
2078                 if (wrbfd)
2079                   {
2080                     bfd_byte vvsd[4];
2081
2082                     windres_put_16 (wrbfd, &vvsd[0], vv->language);
2083                     windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2084                     set_windres_bfd_content (wrbfd, vvsd, off, 4);
2085                   }
2086                 off += 4;
2087               }
2088             if (wrbfd)
2089             {
2090                 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2091                 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2092                 windres_put_16 (wrbfd, bvvd.sig2, 0);
2093                 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2094                                          BIN_VER_INFO_SIZE);
2095             }
2096
2097             break;
2098           }
2099         }
2100
2101       if (wrbfd)
2102         {
2103           windres_put_16 (wrbfd, bv.size, off-bv_off);
2104           windres_put_16 (wrbfd, bv.sig1, 0);
2105           windres_put_16 (wrbfd, bv.sig2, 0);
2106           set_windres_bfd_content (wrbfd, &bv, bv_off,
2107                                    BIN_VER_INFO_SIZE);
2108         }
2109     }
2110
2111   if (wrbfd)
2112     {
2113       windres_put_16 (wrbfd, bvi.size, off - start);
2114       windres_put_16 (wrbfd, bvi.fixed_size,
2115                       versioninfo->fixed == NULL ? 0
2116                                                  : BIN_FIXED_VERSIONINFO_SIZE);
2117       windres_put_16 (wrbfd, bvi.sig2, 0);
2118       set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2119     }
2120   return off;
2121 }
2122
2123 /* Convert a generic resource to binary.  */
2124
2125 static rc_uint_type
2126 res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2127                     const bfd_byte *data)
2128 {
2129   if (wrbfd && length != 0)
2130     set_windres_bfd_content (wrbfd, data, off, length);
2131   return off + (rc_uint_type) length;
2132 }