OSDN Git Service

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