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