]> Git Repo - binutils.git/blob - binutils/resbin.c
Automatic date update in version.in
[binutils.git] / binutils / resbin.c
1 /* resbin.c -- manipulate the Windows binary resource format.
2    Copyright (C) 1997-2022 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           if (length < off + datalen)
578             toosmall (_("dialog control data"));
579
580           dc->data = ((rc_rcdata_item *)
581                       res_alloc (sizeof (rc_rcdata_item)));
582           dc->data->next = NULL;
583           dc->data->type = RCDATA_BUFFER;
584           dc->data->u.buffer.length = datalen;
585           dc->data->u.buffer.data = data + off;
586
587           off += datalen;
588         }
589
590       dc->next = NULL;
591       *pp = dc;
592       pp = &dc->next;
593     }
594
595   r = (rc_res_resource *) res_alloc (sizeof *r);
596   r->type = RES_TYPE_DIALOG;
597   r->u.dialog = d;
598
599   return r;
600 }
601
602 /* Convert a stringtable resource from binary.  */
603
604 static rc_res_resource *
605 bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
606 {
607   rc_stringtable *st;
608   int i;
609   rc_res_resource *r;
610
611   st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
612
613   for (i = 0; i < 16; i++)
614     {
615       unsigned int slen;
616
617       if (length < 2)
618         toosmall (_("stringtable string length"));
619       slen = windres_get_16 (wrbfd, data, 2);
620       st->strings[i].length = slen;
621
622       if (slen > 0)
623         {
624           unichar *s;
625           unsigned int j;
626
627           if (length < 2 + 2 * slen)
628             toosmall (_("stringtable string"));
629
630           s = (unichar *) res_alloc (slen * sizeof (unichar));
631           st->strings[i].string = s;
632
633           for (j = 0; j < slen; j++)
634             s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
635         }
636
637       data += 2 + 2 * slen;
638       length -= 2 + 2 * slen;
639     }
640
641   r = (rc_res_resource *) res_alloc (sizeof *r);
642   r->type = RES_TYPE_STRINGTABLE;
643   r->u.stringtable = st;
644
645   return r;
646 }
647
648 /* Convert a fontdir resource from binary.  */
649
650 static rc_res_resource *
651 bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
652 {
653   rc_uint_type c, i;
654   rc_fontdir *first, **pp;
655   rc_res_resource *r;
656
657   if (length < 2)
658     toosmall (_("fontdir header"));
659
660   c = windres_get_16 (wrbfd, data, 2);
661
662   first = NULL;
663   pp = &first;
664
665   for (i = 0; i < c; i++)
666     {
667       const struct bin_fontdir_item *bfi;
668       rc_fontdir *fd;
669       unsigned int off;
670
671       if (length < 56)
672         toosmall (_("fontdir"));
673
674       bfi = (const struct bin_fontdir_item *) data;
675       fd = (rc_fontdir *) res_alloc (sizeof *fd);
676       fd->index = windres_get_16 (wrbfd, bfi->index, 2);
677
678       /* To work out the length of the fontdir data, we must get the
679          length of the device name and face name strings, even though
680          we don't store them in the rc_fontdir.  The
681          documentation says that these are NULL terminated char
682          strings, not Unicode strings.  */
683
684       off = 56;
685
686       while (off < length && data[off] != '\0')
687         ++off;
688       if (off >= length)
689         toosmall (_("fontdir device name"));
690       ++off;
691
692       while (off < length && data[off] != '\0')
693         ++off;
694       if (off >= length)
695         toosmall (_("fontdir face name"));
696       ++off;
697
698       fd->length = off;
699       fd->data = data;
700
701       fd->next = NULL;
702       *pp = fd;
703       pp = &fd->next;
704
705       /* The documentation does not indicate that any rounding is
706          required.  */
707
708       data += off;
709       length -= off;
710     }
711
712   r = (rc_res_resource *) res_alloc (sizeof *r);
713   r->type = RES_TYPE_FONTDIR;
714   r->u.fontdir = first;
715
716   return r;
717 }
718
719 /* Convert an accelerators resource from binary.  */
720
721 static rc_res_resource *
722 bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
723 {
724   rc_accelerator *first, **pp;
725   rc_res_resource *r;
726
727   first = NULL;
728   pp = &first;
729
730   while (1)
731     {
732       rc_accelerator *a;
733
734       if (length < 8)
735         toosmall (_("accelerator"));
736
737       a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
738
739       a->flags = windres_get_16 (wrbfd, data, 2);
740       a->key = windres_get_16 (wrbfd, data + 2, 2);
741       a->id = windres_get_16 (wrbfd, data + 4, 2);
742
743       a->next = NULL;
744       *pp = a;
745       pp = &a->next;
746
747       if ((a->flags & ACC_LAST) != 0)
748         break;
749
750       data += 8;
751       length -= 8;
752     }
753
754   r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
755   r->type = RES_TYPE_ACCELERATOR;
756   r->u.acc = first;
757
758   return r;
759 }
760
761 /* Convert an rcdata resource from binary.  */
762
763 static rc_res_resource *
764 bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
765                    rc_uint_type length, int rctyp)
766 {
767   rc_rcdata_item *ri;
768   rc_res_resource *r;
769
770   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
771
772   ri->next = NULL;
773   ri->type = RCDATA_BUFFER;
774   ri->u.buffer.length = length;
775   ri->u.buffer.data = data;
776
777   r = (rc_res_resource *) res_alloc (sizeof *r);
778   r->type = rctyp;
779   r->u.rcdata = ri;
780
781   return r;
782 }
783
784 /* Convert a group cursor resource from binary.  */
785
786 static rc_res_resource *
787 bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
788 {
789   int type, c, i;
790   rc_group_cursor *first, **pp;
791   rc_res_resource *r;
792
793   if (length < 6)
794     toosmall (_("group cursor header"));
795
796   type = windres_get_16 (wrbfd, data + 2, 2);
797   if (type != 2)
798     fatal (_("unexpected group cursor type %d"), type);
799
800   c = windres_get_16 (wrbfd, data + 4, 2);
801
802   data += 6;
803   length -= 6;
804
805   first = NULL;
806   pp = &first;
807
808   for (i = 0; i < c; i++)
809     {
810       rc_group_cursor *gc;
811
812       if (length < 14)
813         toosmall (_("group cursor"));
814
815       gc = (rc_group_cursor *) res_alloc (sizeof *gc);
816
817       gc->width = windres_get_16 (wrbfd, data, 2);
818       gc->height = windres_get_16 (wrbfd, data + 2, 2);
819       gc->planes = windres_get_16 (wrbfd, data + 4, 2);
820       gc->bits = windres_get_16 (wrbfd, data + 6, 2);
821       gc->bytes = windres_get_32 (wrbfd, data + 8, 4);
822       gc->index = windres_get_16 (wrbfd, data + 12, 2);
823
824       gc->next = NULL;
825       *pp = gc;
826       pp = &gc->next;
827
828       data += 14;
829       length -= 14;
830     }
831
832   r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
833   r->type = RES_TYPE_GROUP_CURSOR;
834   r->u.group_cursor = first;
835
836   return r;
837 }
838
839 /* Convert a group icon resource from binary.  */
840
841 static rc_res_resource *
842 bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
843 {
844   int type, c, i;
845   rc_group_icon *first, **pp;
846   rc_res_resource *r;
847
848   if (length < 6)
849     toosmall (_("group icon header"));
850
851   type = windres_get_16 (wrbfd, data + 2, 2);
852   if (type != 1)
853     fatal (_("unexpected group icon type %d"), type);
854
855   c = windres_get_16 (wrbfd, data + 4, 2);
856
857   data += 6;
858   length -= 6;
859
860   first = NULL;
861   pp = &first;
862
863   for (i = 0; i < c; i++)
864     {
865       rc_group_icon *gi;
866
867       if (length < 14)
868         toosmall (_("group icon"));
869
870       gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
871
872       gi->width = windres_get_8 (wrbfd, data, 1);
873       gi->height = windres_get_8 (wrbfd, data + 1, 1);
874       gi->colors = windres_get_8 (wrbfd, data + 2, 1);
875       gi->planes = windres_get_16 (wrbfd, data + 4, 2);
876       gi->bits = windres_get_16 (wrbfd, data + 6, 2);
877       gi->bytes = windres_get_32 (wrbfd, data + 8, 4);
878       gi->index = windres_get_16 (wrbfd, data + 12, 2);
879
880       gi->next = NULL;
881       *pp = gi;
882       pp = &gi->next;
883
884       data += 14;
885       length -= 14;
886     }
887
888   r = (rc_res_resource *) res_alloc (sizeof *r);
889   r->type = RES_TYPE_GROUP_ICON;
890   r->u.group_icon = first;
891
892   return r;
893 }
894
895 /* Extract data from a version header.  If KEY is not NULL, then the
896    key must be KEY; otherwise, the key is returned in *PKEY.  This
897    sets *LEN to the total length, *VALLEN to the value length, *TYPE
898    to the type, and *OFF to the offset to the children.  */
899
900 static void
901 get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
902                     const char *key, unichar **pkey,
903                     rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
904                     rc_uint_type *off)
905 {
906   if (length < 8)
907     toosmall (key);
908
909   *len = (windres_get_16 (wrbfd, data, 2) + 3) & ~3;
910   *vallen = windres_get_16 (wrbfd, data + 2, 2);
911   *type = windres_get_16 (wrbfd, data + 4, 2);
912
913   *off = 6;
914
915   length -= 6;
916   data += 6;
917
918   if (key == NULL)
919     {
920       rc_uint_type sublen;
921
922       *pkey = get_unicode (wrbfd, data, length, &sublen);
923       *off += (sublen + 1) * sizeof (unichar);
924     }
925   else
926     {
927       while (1)
928         {
929           if (length < 2)
930             toosmall (key);
931           if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
932             fatal (_("unexpected version string"));
933
934           *off += 2;
935           length -= 2;
936           data += 2;
937
938           if (*key == '\0')
939             break;
940
941           ++key;
942         }
943     }
944
945   *off = (*off + 3) &~ 3;
946 }
947
948 /* Convert a version resource from binary.  */
949
950 static rc_res_resource *
951 bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
952 {
953   rc_uint_type verlen, vallen, type, off;
954   rc_fixed_versioninfo *fi;
955   rc_ver_info *first, **pp;
956   rc_versioninfo *v;
957   rc_res_resource *r;
958
959   get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
960                       (unichar **) NULL, &verlen, &vallen, &type, &off);
961
962   /* PR 17512: The verlen field does not include padding length.  */
963   if (verlen > length)
964     fatal (_("version length %lu greater than resource length %lu"),
965            (unsigned long) verlen, (unsigned long) length);
966
967   if (type != 0)
968     fatal (_("unexpected version type %d"), (int) type);
969
970   /* PR 27686: Ignore any padding bytes after the end of the version structure.  */
971   length = verlen;
972
973   data += off;
974   length -= off;
975
976   if (vallen == 0)
977     fi = NULL;
978   else
979     {
980       unsigned long signature, fiv;
981
982       if (vallen != 52)
983         fatal (_("unexpected fixed version information length %ld"), (long) vallen);
984
985       if (length < 52)
986         toosmall (_("fixed version info"));
987
988       signature = windres_get_32 (wrbfd, data, 4);
989       if (signature != 0xfeef04bd)
990         fatal (_("unexpected fixed version signature %lu"), signature);
991
992       fiv = windres_get_32 (wrbfd, data + 4, 4);
993       if (fiv != 0 && fiv != 0x10000)
994         fatal (_("unexpected fixed version info version %lu"), fiv);
995
996       fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
997
998       fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
999       fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
1000       fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
1001       fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
1002       fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1003       fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1004       fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1005       fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1006       fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1007       fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1008       fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
1009
1010       data += 52;
1011       length -= 52;
1012     }
1013
1014   first = NULL;
1015   pp = &first;
1016
1017   while (length > 0)
1018     {
1019       rc_ver_info *vi;
1020       int ch;
1021
1022       if (length < 8)
1023         toosmall (_("version var info"));
1024
1025       vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1026
1027       ch = windres_get_16 (wrbfd, data + 6, 2);
1028
1029       if (ch == 'S')
1030         {
1031           rc_ver_stringtable **ppvst;
1032
1033           vi->type = VERINFO_STRING;
1034
1035           get_version_header (wrbfd, data, length, "StringFileInfo",
1036                               (unichar **) NULL, &verlen, &vallen, &type,
1037                               &off);
1038
1039           if (vallen != 0)
1040             fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1041
1042           data += off;
1043           length -= off;
1044
1045           verlen -= off;
1046
1047           vi->u.string.stringtables = NULL;
1048           ppvst = &vi->u.string.stringtables;
1049
1050           while (verlen > 0)
1051             {
1052               rc_ver_stringtable *vst;
1053               rc_uint_type stverlen;
1054               rc_ver_stringinfo **ppvs;
1055
1056               if (length < 8)
1057                 toosmall (_("version stringtable"));
1058
1059               vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1060
1061               get_version_header (wrbfd, data, length, (const char *) NULL,
1062                                   &vst->language, &stverlen, &vallen, &type, &off);
1063
1064               if (vallen != 0)
1065                 fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1066
1067               data += off;
1068               length -= off;
1069               verlen -= off;
1070
1071           stverlen -= off;
1072
1073           vst->strings = NULL;
1074           ppvs = &vst->strings;
1075
1076           while (stverlen > 0)
1077             {
1078               rc_ver_stringinfo *vs;
1079               rc_uint_type sverlen, vslen, valoff;
1080
1081               if (length < 8)
1082                 toosmall (_("version string"));
1083
1084               vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1085
1086               get_version_header (wrbfd, data, length, (const char *) NULL,
1087                                   &vs->key, &sverlen, &vallen, &type, &off);
1088
1089               data += off;
1090               length -= off;
1091
1092               vs->value = get_unicode (wrbfd, data, length, &vslen);
1093               valoff = vslen * 2 + 2;
1094               valoff = (valoff + 3) & ~3;
1095
1096               if (off + valoff != sverlen)
1097                 fatal (_("unexpected version string length %ld != %ld + %ld"),
1098                        (long) sverlen, (long) off, (long) valoff);
1099
1100               data += valoff;
1101               length -= valoff;
1102
1103               if (stverlen < sverlen)
1104                 fatal (_("unexpected version string length %ld < %ld"),
1105                        (long) verlen, (long) sverlen);
1106               stverlen -= sverlen;
1107               verlen -= sverlen;
1108
1109               vs->next = NULL;
1110               *ppvs = vs;
1111               ppvs = &vs->next;
1112             }
1113
1114           vst->next = NULL;
1115           *ppvst = vst;
1116           ppvst = &vst->next;
1117             }
1118         }
1119       else if (ch == 'V')
1120         {
1121           rc_ver_varinfo **ppvv;
1122
1123           vi->type = VERINFO_VAR;
1124
1125           get_version_header (wrbfd, data, length, "VarFileInfo",
1126                               (unichar **) NULL, &verlen, &vallen, &type,
1127                               &off);
1128
1129           if (vallen != 0)
1130             fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1131
1132           data += off;
1133           length -= off;
1134
1135           get_version_header (wrbfd, data, length, (const char *) NULL,
1136                               &vi->u.var.key, &verlen, &vallen, &type, &off);
1137
1138           data += off;
1139           length -= off;
1140
1141           vi->u.var.var = NULL;
1142           ppvv = &vi->u.var.var;
1143
1144           while (vallen > 0)
1145             {
1146               rc_ver_varinfo *vv;
1147
1148               if (length < 4)
1149                 toosmall (_("version varfileinfo"));
1150
1151               vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1152
1153               vv->language = windres_get_16 (wrbfd, data, 2);
1154               vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1155
1156               vv->next = NULL;
1157               *ppvv = vv;
1158               ppvv = &vv->next;
1159
1160               data += 4;
1161               length -= 4;
1162
1163               if (vallen < 4)
1164                 fatal (_("unexpected version value length %ld"), (long) vallen);
1165
1166               vallen -= 4;
1167             }
1168         }
1169       else if (ch == 0)
1170         {
1171           if (length == 8)
1172             /* Padding - skip.  */
1173             break;
1174           fatal (_("nul bytes found in version string"));
1175         }
1176       else
1177         fatal (_("unexpected version string character: %x"), ch);
1178
1179       vi->next = NULL;
1180       *pp = vi;
1181       pp = &vi->next;
1182     }
1183
1184   v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1185   v->fixed = fi;
1186   v->var = first;
1187
1188   r = (rc_res_resource *) res_alloc (sizeof *r);
1189   r->type = RES_TYPE_VERSIONINFO;
1190   r->u.versioninfo = v;
1191
1192   return r;
1193 }
1194
1195 /* Convert an arbitrary user defined resource from binary.  */
1196
1197 static rc_res_resource *
1198 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1199                      rc_uint_type length)
1200 {
1201   rc_rcdata_item *ri;
1202   rc_res_resource *r;
1203
1204   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1205
1206   ri->next = NULL;
1207   ri->type = RCDATA_BUFFER;
1208   ri->u.buffer.length = length;
1209   ri->u.buffer.data = data;
1210
1211   r = (rc_res_resource *) res_alloc (sizeof *r);
1212   r->type = RES_TYPE_USERDATA;
1213   r->u.rcdata = ri;
1214
1215   return r;
1216 }
1217 \f
1218 static rc_res_resource *
1219 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1220 {
1221   rc_toolbar *ri;
1222   rc_res_resource *r;
1223   rc_uint_type i;
1224
1225   ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1226   ri->button_width = windres_get_32 (wrbfd, data, 4);
1227   ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1228   ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1229   ri->items = NULL;
1230
1231   data += 12;
1232   length -= 12;
1233   for (i=0 ; i < ri->nitems; i++)
1234   {
1235     rc_toolbar_item *it;
1236     it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1237     it->id.named = 0;
1238     it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1239     it->prev = it->next = NULL;
1240     data += 4;
1241     length -= 4;
1242     if(ri->items) {
1243       rc_toolbar_item *ii = ri->items;
1244       while (ii->next != NULL)
1245         ii = ii->next;
1246       it->prev = ii;
1247       ii->next = it;
1248     }
1249     else
1250       ri->items = it;
1251   }
1252   r = (rc_res_resource *) res_alloc (sizeof *r);
1253   r->type = RES_TYPE_TOOLBAR;
1254   r->u.toolbar = ri;
1255   return r;
1256 }
1257
1258
1259 /* Local functions used to convert resources to binary format.  */
1260
1261 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1262 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1263 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1264 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1265 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1266 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1267 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1268 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1269 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1270 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1271 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1272 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1273 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1274 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1275 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1276 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1277 static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1278                                         const bfd_byte *);
1279
1280 /* Convert a resource to binary.  */
1281
1282 rc_uint_type
1283 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1284 {
1285   switch (res->type)
1286     {
1287     case RES_TYPE_BITMAP:
1288     case RES_TYPE_FONT:
1289     case RES_TYPE_ICON:
1290     case RES_TYPE_MESSAGETABLE:
1291       return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1292     case RES_TYPE_ACCELERATOR:
1293       return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1294     case RES_TYPE_CURSOR:
1295       return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1296     case RES_TYPE_GROUP_CURSOR:
1297       return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1298     case RES_TYPE_DIALOG:
1299       return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1300     case RES_TYPE_FONTDIR:
1301       return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1302     case RES_TYPE_GROUP_ICON:
1303       return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1304     case RES_TYPE_MENU:
1305       return res_to_bin_menu (wrbfd, off, res->u.menu);
1306     case RES_TYPE_STRINGTABLE:
1307       return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1308     case RES_TYPE_VERSIONINFO:
1309       return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1310     case RES_TYPE_TOOLBAR:
1311       return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1312     case RES_TYPE_USERDATA:
1313     case RES_TYPE_RCDATA:
1314     default:
1315       return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1316     }
1317 }
1318
1319 /* Convert a resource ID to binary.  This always returns exactly one
1320    bindata structure.  */
1321
1322 static rc_uint_type
1323 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1324 {
1325   if (! id.named)
1326     {
1327       if (wrbfd)
1328         {
1329           struct bin_res_id bri;
1330
1331           windres_put_16 (wrbfd, bri.sig, 0xffff);
1332           windres_put_16 (wrbfd, bri.id, id.u.id);
1333           set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1334         }
1335       off += BIN_RES_ID;
1336     }
1337   else
1338     {
1339       rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1340       if (wrbfd)
1341         {
1342           bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1343           rc_uint_type i;
1344           for (i = 0; i < len; i++)
1345             windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1346           windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1347           set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1348     }
1349       off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1350     }
1351   return off;
1352 }
1353
1354 /* Convert a null terminated unicode string to binary.  This always
1355    returns exactly one bindata structure.  */
1356
1357 static rc_uint_type
1358 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1359 {
1360   rc_uint_type len = 0;
1361
1362   if (str != NULL)
1363     len = unichar_len (str);
1364
1365   if (wrbfd)
1366     {
1367       bfd_byte *d;
1368       rc_uint_type i;
1369       d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1370       for (i = 0; i < len; i++)
1371         windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1372       windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1373       set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1374     }
1375   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1376
1377   return off;
1378 }
1379
1380 /* Convert an accelerator resource to binary.  */
1381
1382 static rc_uint_type
1383 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1384                         const rc_accelerator *accelerators)
1385 {
1386   const rc_accelerator *a;
1387
1388   for (a = accelerators; a != NULL; a = a->next)
1389     {
1390       if (wrbfd)
1391         {
1392           struct bin_accelerator ba;
1393
1394           windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1395           windres_put_16 (wrbfd, ba.key, a->key);
1396           windres_put_16 (wrbfd, ba.id, a->id);
1397           windres_put_16 (wrbfd, ba.pad, 0);
1398           set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1399     }
1400       off += BIN_ACCELERATOR_SIZE;
1401     }
1402   return off;
1403 }
1404
1405 /* Convert a cursor resource to binary.  */
1406
1407 static rc_uint_type
1408 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1409 {
1410   if (wrbfd)
1411     {
1412       struct bin_cursor bc;
1413
1414       windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1415       windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1416       set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1417       if (c->length)
1418         set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1419     }
1420   off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1421   return off;
1422 }
1423
1424 /* Convert a group cursor resource to binary.  */
1425
1426 static rc_uint_type
1427 res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1428                          const rc_group_cursor *group_cursors)
1429 {
1430   int c = 0;
1431   const rc_group_cursor *gc;
1432   struct bin_group_cursor bgc;
1433   struct bin_group_cursor_item bgci;
1434   rc_uint_type start = off;
1435
1436   off += BIN_GROUP_CURSOR_SIZE;
1437
1438   for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1439     {
1440       if (wrbfd)
1441         {
1442           windres_put_16 (wrbfd, bgci.width, gc->width);
1443           windres_put_16 (wrbfd, bgci.height, gc->height);
1444           windres_put_16 (wrbfd, bgci.planes, gc->planes);
1445           windres_put_16 (wrbfd, bgci.bits, gc->bits);
1446           windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1447           windres_put_16 (wrbfd, bgci.index, gc->index);
1448           set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1449     }
1450
1451       off += BIN_GROUP_CURSOR_ITEM_SIZE;
1452     }
1453   if (wrbfd)
1454     {
1455       windres_put_16 (wrbfd, bgc.sig1, 0);
1456       windres_put_16 (wrbfd, bgc.sig2, 2);
1457       windres_put_16 (wrbfd, bgc.nitems, c);
1458       set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1459     }
1460   return off;
1461 }
1462
1463 /* Convert a dialog resource to binary.  */
1464
1465 static rc_uint_type
1466 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1467 {
1468   rc_uint_type off_delta;
1469   rc_uint_type start, marker;
1470   int dialogex;
1471   int c;
1472   rc_dialog_control *dc;
1473   struct bin_dialogex bdx;
1474   struct bin_dialog bd;
1475
1476   off_delta = off;
1477   start = off;
1478   dialogex = extended_dialog (dialog);
1479
1480   if (wrbfd)
1481     {
1482   if (! dialogex)
1483     {
1484           windres_put_32 (wrbfd, bd.style, dialog->style);
1485           windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1486           windres_put_16 (wrbfd, bd.x, dialog->x);
1487           windres_put_16 (wrbfd, bd.y, dialog->y);
1488           windres_put_16 (wrbfd, bd.width, dialog->width);
1489           windres_put_16 (wrbfd, bd.height, dialog->height);
1490     }
1491   else
1492     {
1493           windres_put_16 (wrbfd, bdx.sig1, 1);
1494           windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1495           windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1496           windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1497           windres_put_32 (wrbfd, bdx.style, dialog->style);
1498           windres_put_16 (wrbfd, bdx.x, dialog->x);
1499           windres_put_16 (wrbfd, bdx.y, dialog->y);
1500           windres_put_16 (wrbfd, bdx.width, dialog->width);
1501           windres_put_16 (wrbfd, bdx.height, dialog->height);
1502         }
1503     }
1504
1505   off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1506
1507   off = resid_to_bin (wrbfd, off, dialog->menu);
1508   off = resid_to_bin (wrbfd, off, dialog->class);
1509   off = unicode_to_bin (wrbfd, off, dialog->caption);
1510
1511   if ((dialog->style & DS_SETFONT) != 0)
1512     {
1513       if (wrbfd)
1514         {
1515           if (! dialogex)
1516             {
1517               struct bin_dialogfont bdf;
1518               windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1519               set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1520             }
1521           else
1522             {
1523               struct bin_dialogexfont bdxf;
1524               windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1525               windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1526               windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1527               windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1528               set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1529             }
1530         }
1531       off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1532       off = unicode_to_bin (wrbfd, off, dialog->font);
1533     }
1534   for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1535     {
1536       bfd_byte dc_rclen[2];
1537
1538       off += (4 - ((off - off_delta) & 3)) & 3;
1539       if (wrbfd)
1540         {
1541       if (! dialogex)
1542         {
1543               struct bin_dialog_control bdc;
1544
1545               windres_put_32 (wrbfd, bdc.style, dc->style);
1546               windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1547               windres_put_16 (wrbfd, bdc.x, dc->x);
1548               windres_put_16 (wrbfd, bdc.y, dc->y);
1549               windres_put_16 (wrbfd, bdc.width, dc->width);
1550               windres_put_16 (wrbfd, bdc.height, dc->height);
1551               windres_put_16 (wrbfd, bdc.id, dc->id);
1552               set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1553         }
1554       else
1555         {
1556               struct bin_dialogex_control bdc;
1557
1558               windres_put_32 (wrbfd, bdc.help, dc->help);
1559               windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1560               windres_put_32 (wrbfd, bdc.style, dc->style);
1561               windres_put_16 (wrbfd, bdc.x, dc->x);
1562               windres_put_16 (wrbfd, bdc.y, dc->y);
1563               windres_put_16 (wrbfd, bdc.width, dc->width);
1564               windres_put_16 (wrbfd, bdc.height, dc->height);
1565               windres_put_32 (wrbfd, bdc.id, dc->id);
1566               set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1567             }
1568         }
1569       off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1570
1571       off = resid_to_bin (wrbfd, off, dc->class);
1572       off = resid_to_bin (wrbfd, off, dc->text);
1573
1574       marker = off; /* Save two bytes for size of optional data.  */
1575       off += 2;
1576
1577       if (dc->data == NULL)
1578         {
1579           if (wrbfd)
1580             windres_put_16 (wrbfd, dc_rclen, 0);
1581         }
1582       else
1583         {
1584           rc_uint_type saved_off = off;
1585           rc_uint_type old_off;
1586
1587           old_off = off;
1588           off = res_to_bin_rcdata (wrbfd, off, dc->data);
1589           if ((off - old_off) == 0)
1590             old_off = off = saved_off;
1591           if (wrbfd)
1592             windres_put_16 (wrbfd, dc_rclen, off - old_off);
1593         }
1594       if (wrbfd)
1595         set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1596     }
1597
1598   if (wrbfd)
1599     {
1600       windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1601       if (! dialogex)
1602         set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1603       else
1604         set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1605     }
1606
1607   return off;
1608 }
1609
1610 /* Convert a fontdir resource to binary.  */
1611 static rc_uint_type
1612 res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
1613 {
1614   rc_uint_type start;
1615   int c;
1616   const rc_fontdir *fd;
1617
1618   start = off;
1619   off += 2;
1620
1621   for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1622     {
1623       if (wrbfd)
1624         {
1625           bfd_byte d[2];
1626           windres_put_16 (wrbfd, d, fd->index);
1627           set_windres_bfd_content (wrbfd, d, off, 2);
1628           if (fd->length)
1629             set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1630         }
1631       off += (rc_uint_type) fd->length + 2;
1632     }
1633
1634   if (wrbfd)
1635     {
1636       bfd_byte d[2];
1637       windres_put_16 (wrbfd, d, c);
1638       set_windres_bfd_content (wrbfd, d, start, 2);
1639     }
1640   return off;
1641 }
1642
1643 /* Convert a group icon resource to binary.  */
1644
1645 static rc_uint_type
1646 res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1647 {
1648   rc_uint_type start;
1649   struct bin_group_icon bgi;
1650   int c;
1651   const rc_group_icon *gi;
1652
1653   start = off;
1654   off += BIN_GROUP_ICON_SIZE;
1655
1656   for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1657     {
1658       struct bin_group_icon_item bgii;
1659
1660       if (wrbfd)
1661         {
1662           windres_put_8 (wrbfd, bgii.width, gi->width);
1663           windres_put_8 (wrbfd, bgii.height, gi->height);
1664           windres_put_8 (wrbfd, bgii.colors, gi->colors);
1665           windres_put_8 (wrbfd, bgii.pad, 0);
1666           windres_put_16 (wrbfd, bgii.planes, gi->planes);
1667           windres_put_16 (wrbfd, bgii.bits, gi->bits);
1668           windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1669           windres_put_16 (wrbfd, bgii.index, gi->index);
1670           set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1671         }
1672       off += BIN_GROUP_ICON_ITEM_SIZE;
1673     }
1674
1675   if (wrbfd)
1676     {
1677       windres_put_16 (wrbfd, bgi.sig1, 0);
1678       windres_put_16 (wrbfd, bgi.sig2, 1);
1679       windres_put_16 (wrbfd, bgi.count, c);
1680       set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1681     }
1682   return off;
1683 }
1684
1685 /* Convert a menu resource to binary.  */
1686
1687 static rc_uint_type
1688 res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1689 {
1690   int menuex;
1691
1692   menuex = extended_menu (menu);
1693
1694   if (wrbfd)
1695     {
1696   if (! menuex)
1697     {
1698           struct bin_menu bm;
1699           windres_put_16 (wrbfd, bm.sig1, 0);
1700           windres_put_16 (wrbfd, bm.sig2, 0);
1701           set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1702     }
1703   else
1704     {
1705           struct bin_menuex bm;
1706           windres_put_16 (wrbfd, bm.sig1, 1);
1707           windres_put_16 (wrbfd, bm.sig2, 4);
1708           windres_put_32 (wrbfd, bm.help, menu->help);
1709           set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1710     }
1711     }
1712   off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1713   if (! menuex)
1714     {
1715       off = res_to_bin_menuitems (wrbfd, off, menu->items);
1716     }
1717   else
1718     {
1719       off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1720     }
1721   return off;
1722 }
1723
1724 /* Convert menu items to binary.  */
1725
1726 static rc_uint_type
1727 res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1728 {
1729   const rc_menuitem *mi;
1730
1731   for (mi = items; mi != NULL; mi = mi->next)
1732     {
1733       struct bin_menuitem bmi;
1734       int flags;
1735
1736       flags = mi->type;
1737       if (mi->next == NULL)
1738         flags |= MENUITEM_ENDMENU;
1739       if (mi->popup != NULL)
1740         flags |= MENUITEM_POPUP;
1741
1742       if (wrbfd)
1743         {
1744           windres_put_16 (wrbfd, bmi.flags, flags);
1745       if (mi->popup == NULL)
1746             windres_put_16 (wrbfd, bmi.id, mi->id);
1747           set_windres_bfd_content (wrbfd, &bmi, off,
1748                                    mi->popup == NULL ? BIN_MENUITEM_SIZE
1749                                                      : BIN_MENUITEM_POPUP_SIZE);
1750         }
1751       off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1752
1753       off = unicode_to_bin (wrbfd, off, mi->text);
1754
1755       if (mi->popup != NULL)
1756         {
1757           off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1758         }
1759     }
1760   return off;
1761 }
1762
1763 /* Convert menuex items to binary.  */
1764
1765 static rc_uint_type
1766 res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1767 {
1768   rc_uint_type off_delta = off;
1769   const rc_menuitem *mi;
1770
1771   for (mi = items; mi != NULL; mi = mi->next)
1772     {
1773       struct bin_menuitemex bmi;
1774       int flags;
1775
1776       off += (4 - ((off - off_delta) & 3)) & 3;
1777
1778       flags = 0;
1779       if (mi->next == NULL)
1780         flags |= 0x80;
1781       if (mi->popup != NULL)
1782         flags |= 1;
1783
1784       if (wrbfd)
1785         {
1786           windres_put_32 (wrbfd, bmi.type, mi->type);
1787           windres_put_32 (wrbfd, bmi.state, mi->state);
1788           windres_put_32 (wrbfd, bmi.id, mi->id);
1789           windres_put_16 (wrbfd, bmi.flags, flags);
1790           set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1791         }
1792       off += BIN_MENUITEMEX_SIZE;
1793
1794       off = unicode_to_bin (wrbfd, off, mi->text);
1795
1796       if (mi->popup != NULL)
1797         {
1798           bfd_byte help[4];
1799
1800           off += (4 - ((off - off_delta) & 3)) & 3;
1801
1802           if (wrbfd)
1803             {
1804               windres_put_32 (wrbfd, help, mi->help);
1805               set_windres_bfd_content (wrbfd, help, off, 4);
1806             }
1807           off += 4;
1808           off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1809         }
1810     }
1811   return off;
1812 }
1813
1814 /* Convert an rcdata resource to binary.  This is also used to convert
1815    other information which happens to be stored in rc_rcdata_item lists
1816    to binary.  */
1817
1818 static rc_uint_type
1819 res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1820 {
1821   const rc_rcdata_item *ri;
1822
1823   for (ri = items; ri != NULL; ri = ri->next)
1824     {
1825       rc_uint_type len;
1826       switch (ri->type)
1827         {
1828         default:
1829           abort ();
1830         case RCDATA_WORD:
1831           len = 2;
1832           break;
1833         case RCDATA_DWORD:
1834           len = 4;
1835           break;
1836         case RCDATA_STRING:
1837           len = ri->u.string.length;
1838           break;
1839         case RCDATA_WSTRING:
1840           len = ri->u.wstring.length * sizeof (unichar);
1841           break;
1842         case RCDATA_BUFFER:
1843           len = ri->u.buffer.length;
1844           break;
1845         }
1846       if (wrbfd)
1847         {
1848           bfd_byte h[4];
1849           bfd_byte *hp = &h[0];
1850           switch (ri->type)
1851             {
1852             case RCDATA_WORD:
1853               windres_put_16 (wrbfd, hp, ri->u.word);
1854               break;
1855             case RCDATA_DWORD:
1856               windres_put_32 (wrbfd, hp, ri->u.dword);
1857               break;
1858             case RCDATA_STRING:
1859               hp = (bfd_byte *) ri->u.string.s;
1860           break;
1861         case RCDATA_WSTRING:
1862           {
1863                 rc_uint_type i;
1864
1865                 hp = (bfd_byte *) reswr_alloc (len);
1866             for (i = 0; i < ri->u.wstring.length; i++)
1867                   windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
1868           }
1869               break;
1870         case RCDATA_BUFFER:
1871               hp = (bfd_byte *) ri->u.buffer.data;
1872           break;
1873         }
1874           set_windres_bfd_content (wrbfd, hp, off, len);
1875     }
1876       off += len;
1877     }
1878   return off;
1879 }
1880
1881 /* Convert a stringtable resource to binary.  */
1882
1883 static rc_uint_type
1884 res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1885                         const rc_stringtable *st)
1886 {
1887   int i;
1888
1889   for (i = 0; i < 16; i++)
1890     {
1891       rc_uint_type slen, length;
1892       unichar *s;
1893
1894       slen = (rc_uint_type) st->strings[i].length;
1895       if (slen == 0xffffffff) slen = 0;
1896       s = st->strings[i].string;
1897
1898       length = 2 + slen * 2;
1899       if (wrbfd)
1900         {
1901           bfd_byte *hp;
1902           rc_uint_type j;
1903
1904           hp = (bfd_byte *) reswr_alloc (length);
1905           windres_put_16 (wrbfd, hp, slen);
1906
1907       for (j = 0; j < slen; j++)
1908             windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1909           set_windres_bfd_content (wrbfd, hp, off, length);
1910     }
1911       off += length;
1912     }
1913   return off;
1914 }
1915
1916 /* Convert an ASCII string to a unicode binary string.  This always
1917    returns exactly one bindata structure.  */
1918
1919 static rc_uint_type
1920 string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1921 {
1922   rc_uint_type len;
1923
1924   len = (rc_uint_type) strlen (s);
1925
1926   if (wrbfd)
1927     {
1928       rc_uint_type i;
1929       bfd_byte *hp;
1930
1931       hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1932
1933       for (i = 0; i < len; i++)
1934         windres_put_16 (wrbfd, hp + i * 2, s[i]);
1935       windres_put_16 (wrbfd, hp + i * 2, 0);
1936       set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1937     }
1938   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1939   return off;
1940 }
1941
1942 static rc_uint_type
1943 res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1944 {
1945   if (wrbfd)
1946     {
1947       struct bin_toolbar bt;
1948       windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1949       windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1950       windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1951       set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1952       if (tb->nitems > 0)
1953         {
1954           rc_toolbar_item *it;
1955           bfd_byte *ids;
1956           rc_uint_type i = 0;
1957
1958           ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1959           it=tb->items;
1960           while(it != NULL)
1961             {
1962               windres_put_32 (wrbfd, ids + i, it->id.u.id);
1963               i += 4;
1964               it = it->next;
1965             }
1966           set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1967         }
1968     }
1969   off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1970
1971   return off;
1972 }
1973
1974 /* Convert a versioninfo resource to binary.  */
1975
1976 static rc_uint_type
1977 res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1978                         const rc_versioninfo *versioninfo)
1979 {
1980   rc_uint_type off_delta = off;
1981   rc_uint_type start;
1982   struct bin_versioninfo bvi;
1983   rc_ver_info *vi;
1984
1985   start = off;
1986   off += BIN_VERSIONINFO_SIZE;
1987   off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1988   off += (4 - ((off - off_delta) & 3)) & 3;
1989
1990   if (versioninfo->fixed != NULL)
1991     {
1992       if (wrbfd)
1993         {
1994           struct bin_fixed_versioninfo bfv;
1995           const rc_fixed_versioninfo *fi;
1996
1997       fi = versioninfo->fixed;
1998           windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1999           windres_put_32 (wrbfd, bfv.sig2, 0x10000);
2000           windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
2001           windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
2002           windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
2003           windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
2004           windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
2005           windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
2006           windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
2007           windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
2008           windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
2009           windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
2010           windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
2011           set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
2012         }
2013       off += BIN_FIXED_VERSIONINFO_SIZE;
2014     }
2015
2016   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2017     {
2018       struct bin_ver_info bv;
2019       rc_uint_type bv_off;
2020
2021       off += (4 - ((off - off_delta) & 3)) & 3;
2022
2023       bv_off = off;
2024
2025       off += BIN_VER_INFO_SIZE;
2026
2027       switch (vi->type)
2028         {
2029         default:
2030           abort ();
2031         case VERINFO_STRING:
2032           {
2033             const rc_ver_stringtable *vst;
2034
2035             off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2036
2037             if (!vi->u.string.stringtables)
2038               off += (4 - ((off - off_delta) & 3)) & 3;
2039
2040             for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
2041               {
2042                 struct bin_ver_info bvst;
2043                 rc_uint_type vst_off;
2044                 const rc_ver_stringinfo *vs;
2045
2046                 off += (4 - ((off - off_delta) & 3)) & 3;
2047
2048                 vst_off = off;
2049                 off += BIN_VER_INFO_SIZE;
2050
2051                 off = unicode_to_bin (wrbfd, off, vst->language);
2052
2053                 for (vs = vst->strings; vs != NULL; vs = vs->next)
2054                   {
2055                     struct bin_ver_info bvs;
2056                     rc_uint_type vs_off, str_off;
2057
2058                     off += (4 - ((off - off_delta) & 3)) & 3;
2059
2060                     vs_off = off;
2061                     off += BIN_VER_INFO_SIZE;
2062
2063                     off = unicode_to_bin (wrbfd, off, vs->key);
2064
2065                     off += (4 - ((off - off_delta) & 3)) & 3;
2066
2067                     str_off = off;
2068                     off = unicode_to_bin (wrbfd, off, vs->value);
2069
2070                     if (wrbfd)
2071                       {
2072                         windres_put_16 (wrbfd, bvs.size, off - vs_off);
2073                         windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
2074                         windres_put_16 (wrbfd, bvs.sig2, 1);
2075                         set_windres_bfd_content (wrbfd, &bvs, vs_off,
2076                                                  BIN_VER_INFO_SIZE);
2077                       }
2078                   }
2079
2080                 if (wrbfd)
2081                   {
2082                     windres_put_16 (wrbfd, bvst.size, off - vst_off);
2083                     windres_put_16 (wrbfd, bvst.sig1, 0);
2084                     windres_put_16 (wrbfd, bvst.sig2, 1);
2085                     set_windres_bfd_content (wrbfd, &bvst, vst_off,
2086                                              BIN_VER_INFO_SIZE);
2087                   }
2088               }
2089             break;
2090           }
2091
2092         case VERINFO_VAR:
2093           {
2094             rc_uint_type vvd_off, vvvd_off;
2095             struct bin_ver_info bvvd;
2096             const rc_ver_varinfo *vv;
2097
2098             off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2099
2100             off += (4 - ((off - off_delta) & 3)) & 3;
2101
2102             vvd_off = off;
2103             off += BIN_VER_INFO_SIZE;
2104
2105             off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2106
2107             off += (4 - ((off - off_delta) & 3)) & 3;
2108
2109             vvvd_off = off;
2110
2111             for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2112               {
2113                 if (wrbfd)
2114                   {
2115                     bfd_byte vvsd[4];
2116
2117                     windres_put_16 (wrbfd, &vvsd[0], vv->language);
2118                     windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2119                     set_windres_bfd_content (wrbfd, vvsd, off, 4);
2120                   }
2121                 off += 4;
2122               }
2123             if (wrbfd)
2124             {
2125                 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2126                 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2127                 windres_put_16 (wrbfd, bvvd.sig2, 0);
2128                 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2129                                          BIN_VER_INFO_SIZE);
2130             }
2131
2132             break;
2133           }
2134         }
2135
2136       if (wrbfd)
2137         {
2138           windres_put_16 (wrbfd, bv.size, off - bv_off);
2139           windres_put_16 (wrbfd, bv.sig1, 0);
2140           windres_put_16 (wrbfd, bv.sig2, 1);
2141           set_windres_bfd_content (wrbfd, &bv, bv_off,
2142                                    BIN_VER_INFO_SIZE);
2143         }
2144     }
2145
2146   if (wrbfd)
2147     {
2148       windres_put_16 (wrbfd, bvi.size, off - start);
2149       windres_put_16 (wrbfd, bvi.fixed_size,
2150                       versioninfo->fixed == NULL ? 0
2151                                                  : BIN_FIXED_VERSIONINFO_SIZE);
2152       windres_put_16 (wrbfd, bvi.sig2, 0);
2153       set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2154     }
2155   return off;
2156 }
2157
2158 /* Convert a generic resource to binary.  */
2159
2160 static rc_uint_type
2161 res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2162                     const bfd_byte *data)
2163 {
2164   if (wrbfd && length != 0)
2165     set_windres_bfd_content (wrbfd, data, off, length);
2166   return off + (rc_uint_type) length;
2167 }
This page took 0.144305 seconds and 4 git commands to generate.