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