S/390: arch13: Adjust to recent changes
[binutils-gdb.git] / binutils / resbin.c
blobcd562a550e9dc82a0a72085b02510bf3e940865d
1 /* resbin.c -- manipulate the Windows binary resource format.
2 Copyright (C) 1997-2019 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Cygnus Support.
4 Rewritten by Kai Tietz, Onevision.
6 This file is part of GNU Binutils.
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.
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.
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. */
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. */
28 #include "sysdep.h"
29 #include "bfd.h"
30 #include "bucomm.h"
31 #include "libiberty.h"
32 #include "windres.h"
34 /* Local functions. */
36 static void toosmall (const char *);
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 *);
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. */
67 rc_res_resource *
68 bin_to_res (windres_bfd *wrbfd, rc_res_id type, const bfd_byte *data,
69 rc_uint_type length)
71 if (type.named)
72 return bin_to_res_userdata (wrbfd, data, length);
73 else
75 switch (type.u.id)
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);
114 /* Give an error if the binary data is too small. */
116 static void
117 toosmall (const char *msg)
119 fatal (_("%s: not enough binary data"), msg);
122 /* Swap in a NULL terminated unicode string. */
124 static unichar *
125 get_unicode (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
126 rc_uint_type *retlen)
128 rc_uint_type c, i;
129 unichar *ret;
131 c = 0;
132 while (1)
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;
141 ret = (unichar *) res_alloc ((c + 1) * sizeof (unichar));
143 for (i = 0; i < c; i++)
144 ret[i] = windres_get_16 (wrbfd, data + i * 2, 2);
145 ret[i] = 0;
147 if (retlen != NULL)
148 *retlen = c;
150 return ret;
153 /* Get a resource identifier. This returns the number of bytes used. */
155 static int
156 get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
157 rc_uint_type length)
159 rc_uint_type first;
161 if (length < 2)
162 toosmall (_("resource ID"));
164 first = windres_get_16 (wrbfd, data, 2);
165 if (first == 0xffff)
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;
173 else
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;
181 /* Convert a resource which just stores uninterpreted data from
182 binary. */
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)
188 rc_res_resource *r;
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;
195 return r;
198 /* Convert a cursor resource from binary. */
200 rc_res_resource *
201 bin_to_res_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
203 rc_cursor *c;
204 rc_res_resource *r;
206 if (length < 4)
207 toosmall (_("cursor"));
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;
215 r = (rc_res_resource *) res_alloc (sizeof *r);
216 r->type = RES_TYPE_CURSOR;
217 r->u.cursor = c;
219 return r;
222 /* Convert a menu resource from binary. */
224 rc_res_resource *
225 bin_to_res_menu (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
227 rc_res_resource *r;
228 rc_menu *m;
229 rc_uint_type version, got;
231 r = (rc_res_resource *) res_alloc (sizeof *r);
232 r->type = RES_TYPE_MENU;
234 m = (rc_menu *) res_alloc (sizeof (rc_menu));
235 r->u.menu = m;
237 if (length < 2)
238 toosmall (_("menu header"));
240 version = windres_get_16 (wrbfd, data, 2);
242 if (version == 0)
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);
249 else if (version == 1)
251 rc_uint_type offset;
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);
262 else
263 fatal (_("unsupported menu version %d"), (int) version);
265 return r;
268 /* Convert menu items from binary. */
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)
274 rc_menuitem *first, **pp;
276 first = NULL;
277 pp = &first;
279 *got = 0;
281 while (length > 0)
283 rc_uint_type flags, slen, itemlen;
284 rc_uint_type stroff;
285 rc_menuitem *mi;
287 if (length < 4)
288 toosmall (_("menuitem header"));
290 mi = (rc_menuitem *) res_alloc (sizeof *mi);
291 mi->state = 0;
292 mi->help = 0;
294 flags = windres_get_16 (wrbfd, data, 2);
295 mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);
297 if ((flags & MENUITEM_POPUP) == 0)
298 stroff = 4;
299 else
300 stroff = 2;
302 if (length < stroff + 2)
303 toosmall (_("menuitem header"));
305 if (windres_get_16 (wrbfd, data + stroff, 2) == 0)
307 slen = 0;
308 mi->text = NULL;
310 else
311 mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
313 itemlen = stroff + slen * 2 + 2;
315 if ((flags & MENUITEM_POPUP) == 0)
317 mi->popup = NULL;
318 mi->id = windres_get_16 (wrbfd, data + 2, 2);
320 else
322 rc_uint_type subread;
324 mi->id = 0;
325 mi->popup = bin_to_res_menuitems (wrbfd, data + itemlen, length - itemlen,
326 &subread);
327 itemlen += subread;
330 mi->next = NULL;
331 *pp = mi;
332 pp = &mi->next;
334 data += itemlen;
335 length -= itemlen;
336 *got += itemlen;
338 if ((flags & MENUITEM_ENDMENU) != 0)
339 return first;
342 return first;
345 /* Convert menuex items from binary. */
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)
351 rc_menuitem *first, **pp;
353 first = NULL;
354 pp = &first;
356 *got = 0;
358 while (length > 0)
360 rc_uint_type flags, slen;
361 rc_uint_type itemlen;
362 rc_menuitem *mi;
364 if (length < 16)
365 toosmall (_("menuitem header"));
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);
372 flags = windres_get_16 (wrbfd, data + 12, 2);
374 if (windres_get_16 (wrbfd, data + 14, 2) == 0)
376 slen = 0;
377 mi->text = NULL;
379 else
380 mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
382 itemlen = 14 + slen * 2 + 2;
383 itemlen = (itemlen + 3) &~ 3;
385 if ((flags & 1) == 0)
387 mi->popup = NULL;
388 mi->help = 0;
390 else
392 rc_uint_type subread;
394 if (length < itemlen + 4)
395 toosmall (_("menuitem"));
396 mi->help = windres_get_32 (wrbfd, data + itemlen, 4);
397 itemlen += 4;
399 mi->popup = bin_to_res_menuexitems (wrbfd, data + itemlen,
400 length - itemlen, &subread);
401 itemlen += subread;
404 mi->next = NULL;
405 *pp = mi;
406 pp = &mi->next;
408 data += itemlen;
409 length -= itemlen;
410 *got += itemlen;
412 if ((flags & 0x80) != 0)
413 return first;
416 return first;
419 /* Convert a dialog resource from binary. */
421 static rc_res_resource *
422 bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
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;
431 if (length < 18)
432 toosmall (_("dialog header"));
434 d = (rc_dialog *) res_alloc (sizeof (rc_dialog));
436 signature = windres_get_16 (wrbfd, data + 2, 2);
437 if (signature != 0xffff)
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;
444 else
446 int version;
448 version = windres_get_16 (wrbfd, data, 2);
449 if (version != 1)
450 fatal (_("unexpected DIALOGEX version %d"), version);
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;
459 if (length < off + 10)
460 toosmall (_("dialog header"));
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);
468 off += 10;
470 sublen = get_resid (wrbfd, &d->menu, data + off, length - off);
471 off += sublen;
473 sublen = get_resid (wrbfd, &d->class, data + off, length - off);
474 off += sublen;
476 d->caption = get_unicode (wrbfd, data + off, length - off, &sublen);
477 off += sublen * 2 + 2;
478 if (sublen == 0)
479 d->caption = NULL;
481 if ((d->style & DS_SETFONT) == 0)
483 d->pointsize = 0;
484 d->font = NULL;
485 if (d->ex != NULL)
487 d->ex->weight = 0;
488 d->ex->italic = 0;
489 d->ex->charset = 1; /* Default charset. */
492 else
494 if (length < off + 2)
495 toosmall (_("dialog font point size"));
497 d->pointsize = windres_get_16 (wrbfd, data + off, 2);
498 off += 2;
500 if (d->ex != NULL)
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;
510 d->font = get_unicode (wrbfd, data + off, length - off, &sublen);
511 off += sublen * 2 + 2;
514 d->controls = NULL;
515 pp = &d->controls;
517 for (i = 0; i < c; i++)
519 rc_dialog_control *dc;
520 int datalen;
522 off = (off + 3) &~ 3;
524 dc = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
526 if (d->ex == NULL)
528 if (length < off + 8)
529 toosmall (_("dialog control"));
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;
536 else
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;
546 if (length < off + (d->ex != NULL ? 2 : 0) + 10)
547 toosmall (_("dialog control"));
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);
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);
559 off += 10 + (d->ex != NULL ? 2 : 0);
561 sublen = get_resid (wrbfd, &dc->class, data + off, length - off);
562 off += sublen;
564 sublen = get_resid (wrbfd, &dc->text, data + off, length - off);
565 off += sublen;
567 if (length < off + 2)
568 toosmall (_("dialog control end"));
570 datalen = windres_get_16 (wrbfd, data + off, 2);
571 off += 2;
573 if (datalen == 0)
574 dc->data = NULL;
575 else
577 if (length < off + datalen)
578 toosmall (_("dialog control data"));
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;
587 off += datalen;
590 dc->next = NULL;
591 *pp = dc;
592 pp = &dc->next;
595 r = (rc_res_resource *) res_alloc (sizeof *r);
596 r->type = RES_TYPE_DIALOG;
597 r->u.dialog = d;
599 return r;
602 /* Convert a stringtable resource from binary. */
604 static rc_res_resource *
605 bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
607 rc_stringtable *st;
608 int i;
609 rc_res_resource *r;
611 st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
613 for (i = 0; i < 16; i++)
615 unsigned int slen;
617 if (length < 2)
618 toosmall (_("stringtable string length"));
619 slen = windres_get_16 (wrbfd, data, 2);
620 st->strings[i].length = slen;
622 if (slen > 0)
624 unichar *s;
625 unsigned int j;
627 if (length < 2 + 2 * slen)
628 toosmall (_("stringtable string"));
630 s = (unichar *) res_alloc (slen * sizeof (unichar));
631 st->strings[i].string = s;
633 for (j = 0; j < slen; j++)
634 s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
637 data += 2 + 2 * slen;
638 length -= 2 + 2 * slen;
641 r = (rc_res_resource *) res_alloc (sizeof *r);
642 r->type = RES_TYPE_STRINGTABLE;
643 r->u.stringtable = st;
645 return r;
648 /* Convert a fontdir resource from binary. */
650 static rc_res_resource *
651 bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
653 rc_uint_type c, i;
654 rc_fontdir *first, **pp;
655 rc_res_resource *r;
657 if (length < 2)
658 toosmall (_("fontdir header"));
660 c = windres_get_16 (wrbfd, data, 2);
662 first = NULL;
663 pp = &first;
665 for (i = 0; i < c; i++)
667 const struct bin_fontdir_item *bfi;
668 rc_fontdir *fd;
669 unsigned int off;
671 if (length < 56)
672 toosmall (_("fontdir"));
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);
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. */
684 off = 56;
686 while (off < length && data[off] != '\0')
687 ++off;
688 if (off >= length)
689 toosmall (_("fontdir device name"));
690 ++off;
692 while (off < length && data[off] != '\0')
693 ++off;
694 if (off >= length)
695 toosmall (_("fontdir face name"));
696 ++off;
698 fd->length = off;
699 fd->data = data;
701 fd->next = NULL;
702 *pp = fd;
703 pp = &fd->next;
705 /* The documentation does not indicate that any rounding is
706 required. */
708 data += off;
709 length -= off;
712 r = (rc_res_resource *) res_alloc (sizeof *r);
713 r->type = RES_TYPE_FONTDIR;
714 r->u.fontdir = first;
716 return r;
719 /* Convert an accelerators resource from binary. */
721 static rc_res_resource *
722 bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
724 rc_accelerator *first, **pp;
725 rc_res_resource *r;
727 first = NULL;
728 pp = &first;
730 while (1)
732 rc_accelerator *a;
734 if (length < 8)
735 toosmall (_("accelerator"));
737 a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
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);
743 a->next = NULL;
744 *pp = a;
745 pp = &a->next;
747 if ((a->flags & ACC_LAST) != 0)
748 break;
750 data += 8;
751 length -= 8;
754 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
755 r->type = RES_TYPE_ACCELERATOR;
756 r->u.acc = first;
758 return r;
761 /* Convert an rcdata resource from binary. */
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)
767 rc_rcdata_item *ri;
768 rc_res_resource *r;
770 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
772 ri->next = NULL;
773 ri->type = RCDATA_BUFFER;
774 ri->u.buffer.length = length;
775 ri->u.buffer.data = data;
777 r = (rc_res_resource *) res_alloc (sizeof *r);
778 r->type = rctyp;
779 r->u.rcdata = ri;
781 return r;
784 /* Convert a group cursor resource from binary. */
786 static rc_res_resource *
787 bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
789 int type, c, i;
790 rc_group_cursor *first, **pp;
791 rc_res_resource *r;
793 if (length < 6)
794 toosmall (_("group cursor header"));
796 type = windres_get_16 (wrbfd, data + 2, 2);
797 if (type != 2)
798 fatal (_("unexpected group cursor type %d"), type);
800 c = windres_get_16 (wrbfd, data + 4, 2);
802 data += 6;
803 length -= 6;
805 first = NULL;
806 pp = &first;
808 for (i = 0; i < c; i++)
810 rc_group_cursor *gc;
812 if (length < 14)
813 toosmall (_("group cursor"));
815 gc = (rc_group_cursor *) res_alloc (sizeof *gc);
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);
824 gc->next = NULL;
825 *pp = gc;
826 pp = &gc->next;
828 data += 14;
829 length -= 14;
832 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
833 r->type = RES_TYPE_GROUP_CURSOR;
834 r->u.group_cursor = first;
836 return r;
839 /* Convert a group icon resource from binary. */
841 static rc_res_resource *
842 bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
844 int type, c, i;
845 rc_group_icon *first, **pp;
846 rc_res_resource *r;
848 if (length < 6)
849 toosmall (_("group icon header"));
851 type = windres_get_16 (wrbfd, data + 2, 2);
852 if (type != 1)
853 fatal (_("unexpected group icon type %d"), type);
855 c = windres_get_16 (wrbfd, data + 4, 2);
857 data += 6;
858 length -= 6;
860 first = NULL;
861 pp = &first;
863 for (i = 0; i < c; i++)
865 rc_group_icon *gi;
867 if (length < 14)
868 toosmall (_("group icon"));
870 gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
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);
880 gi->next = NULL;
881 *pp = gi;
882 pp = &gi->next;
884 data += 14;
885 length -= 14;
888 r = (rc_res_resource *) res_alloc (sizeof *r);
889 r->type = RES_TYPE_GROUP_ICON;
890 r->u.group_icon = first;
892 return r;
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. */
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)
906 if (length < 8)
907 toosmall (key);
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);
913 *off = 6;
915 length -= 6;
916 data += 6;
918 if (key == NULL)
920 rc_uint_type sublen;
922 *pkey = get_unicode (wrbfd, data, length, &sublen);
923 *off += (sublen + 1) * sizeof (unichar);
925 else
927 while (1)
929 if (length < 2)
930 toosmall (key);
931 if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
932 fatal (_("unexpected version string"));
934 *off += 2;
935 length -= 2;
936 data += 2;
938 if (*key == '\0')
939 break;
941 ++key;
945 *off = (*off + 3) &~ 3;
948 /* Convert a version resource from binary. */
950 static rc_res_resource *
951 bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
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;
959 get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
960 (unichar **) NULL, &verlen, &vallen, &type, &off);
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);
967 if (type != 0)
968 fatal (_("unexpected version type %d"), (int) type);
970 data += off;
971 length -= off;
973 if (vallen == 0)
974 fi = NULL;
975 else
977 unsigned long signature, fiv;
979 if (vallen != 52)
980 fatal (_("unexpected fixed version information length %ld"), (long) vallen);
982 if (length < 52)
983 toosmall (_("fixed version info"));
985 signature = windres_get_32 (wrbfd, data, 4);
986 if (signature != 0xfeef04bd)
987 fatal (_("unexpected fixed version signature %lu"), signature);
989 fiv = windres_get_32 (wrbfd, data + 4, 4);
990 if (fiv != 0 && fiv != 0x10000)
991 fatal (_("unexpected fixed version info version %lu"), fiv);
993 fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
995 fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
996 fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
997 fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
998 fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
999 fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1000 fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1001 fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1002 fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1003 fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1004 fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1005 fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
1007 data += 52;
1008 length -= 52;
1011 first = NULL;
1012 pp = &first;
1014 while (length > 0)
1016 rc_ver_info *vi;
1017 int ch;
1019 if (length < 8)
1020 toosmall (_("version var info"));
1022 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1024 ch = windres_get_16 (wrbfd, data + 6, 2);
1026 if (ch == 'S')
1028 rc_ver_stringtable **ppvst;
1030 vi->type = VERINFO_STRING;
1032 get_version_header (wrbfd, data, length, "StringFileInfo",
1033 (unichar **) NULL, &verlen, &vallen, &type,
1034 &off);
1036 if (vallen != 0)
1037 fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1039 data += off;
1040 length -= off;
1042 verlen -= off;
1044 vi->u.string.stringtables = NULL;
1045 ppvst = &vi->u.string.stringtables;
1047 while (verlen > 0)
1049 rc_ver_stringtable *vst;
1050 rc_uint_type stverlen;
1051 rc_ver_stringinfo **ppvs;
1053 if (length < 8)
1054 toosmall (_("version stringtable"));
1056 vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1058 get_version_header (wrbfd, data, length, (const char *) NULL,
1059 &vst->language, &stverlen, &vallen, &type, &off);
1061 if (vallen != 0)
1062 fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1064 data += off;
1065 length -= off;
1066 verlen -= off;
1068 stverlen -= off;
1070 vst->strings = NULL;
1071 ppvs = &vst->strings;
1073 while (stverlen > 0)
1075 rc_ver_stringinfo *vs;
1076 rc_uint_type sverlen, vslen, valoff;
1078 if (length < 8)
1079 toosmall (_("version string"));
1081 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1083 get_version_header (wrbfd, data, length, (const char *) NULL,
1084 &vs->key, &sverlen, &vallen, &type, &off);
1086 data += off;
1087 length -= off;
1089 vs->value = get_unicode (wrbfd, data, length, &vslen);
1090 valoff = vslen * 2 + 2;
1091 valoff = (valoff + 3) & ~3;
1093 if (off + valoff != sverlen)
1094 fatal (_("unexpected version string length %ld != %ld + %ld"),
1095 (long) sverlen, (long) off, (long) valoff);
1097 data += valoff;
1098 length -= valoff;
1100 if (stverlen < sverlen)
1101 fatal (_("unexpected version string length %ld < %ld"),
1102 (long) verlen, (long) sverlen);
1103 stverlen -= sverlen;
1104 verlen -= sverlen;
1106 vs->next = NULL;
1107 *ppvs = vs;
1108 ppvs = &vs->next;
1111 vst->next = NULL;
1112 *ppvst = vst;
1113 ppvst = &vst->next;
1116 else if (ch == 'V')
1118 rc_ver_varinfo **ppvv;
1120 vi->type = VERINFO_VAR;
1122 get_version_header (wrbfd, data, length, "VarFileInfo",
1123 (unichar **) NULL, &verlen, &vallen, &type,
1124 &off);
1126 if (vallen != 0)
1127 fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1129 data += off;
1130 length -= off;
1132 get_version_header (wrbfd, data, length, (const char *) NULL,
1133 &vi->u.var.key, &verlen, &vallen, &type, &off);
1135 data += off;
1136 length -= off;
1138 vi->u.var.var = NULL;
1139 ppvv = &vi->u.var.var;
1141 while (vallen > 0)
1143 rc_ver_varinfo *vv;
1145 if (length < 4)
1146 toosmall (_("version varfileinfo"));
1148 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1150 vv->language = windres_get_16 (wrbfd, data, 2);
1151 vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1153 vv->next = NULL;
1154 *ppvv = vv;
1155 ppvv = &vv->next;
1157 data += 4;
1158 length -= 4;
1160 if (vallen < 4)
1161 fatal (_("unexpected version value length %ld"), (long) vallen);
1163 vallen -= 4;
1166 else if (ch == 0)
1168 if (length == 8)
1169 /* Padding - skip. */
1170 break;
1171 fatal (_("nul bytes found in version string"));
1173 else
1174 fatal (_("unexpected version string character: %x"), ch);
1176 vi->next = NULL;
1177 *pp = vi;
1178 pp = &vi->next;
1181 v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1182 v->fixed = fi;
1183 v->var = first;
1185 r = (rc_res_resource *) res_alloc (sizeof *r);
1186 r->type = RES_TYPE_VERSIONINFO;
1187 r->u.versioninfo = v;
1189 return r;
1192 /* Convert an arbitrary user defined resource from binary. */
1194 static rc_res_resource *
1195 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1196 rc_uint_type length)
1198 rc_rcdata_item *ri;
1199 rc_res_resource *r;
1201 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1203 ri->next = NULL;
1204 ri->type = RCDATA_BUFFER;
1205 ri->u.buffer.length = length;
1206 ri->u.buffer.data = data;
1208 r = (rc_res_resource *) res_alloc (sizeof *r);
1209 r->type = RES_TYPE_USERDATA;
1210 r->u.rcdata = ri;
1212 return r;
1215 static rc_res_resource *
1216 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1218 rc_toolbar *ri;
1219 rc_res_resource *r;
1220 rc_uint_type i;
1222 ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1223 ri->button_width = windres_get_32 (wrbfd, data, 4);
1224 ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1225 ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1226 ri->items = NULL;
1228 data += 12;
1229 length -= 12;
1230 for (i=0 ; i < ri->nitems; i++)
1232 rc_toolbar_item *it;
1233 it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1234 it->id.named = 0;
1235 it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1236 it->prev = it->next = NULL;
1237 data += 4;
1238 length -= 4;
1239 if(ri->items) {
1240 rc_toolbar_item *ii = ri->items;
1241 while (ii->next != NULL)
1242 ii = ii->next;
1243 it->prev = ii;
1244 ii->next = it;
1246 else
1247 ri->items = it;
1249 r = (rc_res_resource *) res_alloc (sizeof *r);
1250 r->type = RES_TYPE_TOOLBAR;
1251 r->u.toolbar = ri;
1252 return r;
1256 /* Local functions used to convert resources to binary format. */
1258 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1259 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1260 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1261 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1262 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1263 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1264 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1265 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1266 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1267 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1268 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1269 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1270 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1271 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1272 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1273 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1274 static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1275 const bfd_byte *);
1277 /* Convert a resource to binary. */
1279 rc_uint_type
1280 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1282 switch (res->type)
1284 case RES_TYPE_BITMAP:
1285 case RES_TYPE_FONT:
1286 case RES_TYPE_ICON:
1287 case RES_TYPE_MESSAGETABLE:
1288 return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1289 case RES_TYPE_ACCELERATOR:
1290 return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1291 case RES_TYPE_CURSOR:
1292 return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1293 case RES_TYPE_GROUP_CURSOR:
1294 return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1295 case RES_TYPE_DIALOG:
1296 return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1297 case RES_TYPE_FONTDIR:
1298 return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1299 case RES_TYPE_GROUP_ICON:
1300 return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1301 case RES_TYPE_MENU:
1302 return res_to_bin_menu (wrbfd, off, res->u.menu);
1303 case RES_TYPE_STRINGTABLE:
1304 return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1305 case RES_TYPE_VERSIONINFO:
1306 return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1307 case RES_TYPE_TOOLBAR:
1308 return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1309 case RES_TYPE_USERDATA:
1310 case RES_TYPE_RCDATA:
1311 default:
1312 return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1316 /* Convert a resource ID to binary. This always returns exactly one
1317 bindata structure. */
1319 static rc_uint_type
1320 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1322 if (! id.named)
1324 if (wrbfd)
1326 struct bin_res_id bri;
1328 windres_put_16 (wrbfd, bri.sig, 0xffff);
1329 windres_put_16 (wrbfd, bri.id, id.u.id);
1330 set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1332 off += BIN_RES_ID;
1334 else
1336 rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1337 if (wrbfd)
1339 bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1340 rc_uint_type i;
1341 for (i = 0; i < len; i++)
1342 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1343 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1344 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1346 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1348 return off;
1351 /* Convert a null terminated unicode string to binary. This always
1352 returns exactly one bindata structure. */
1354 static rc_uint_type
1355 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1357 rc_uint_type len = 0;
1359 if (str != NULL)
1360 len = unichar_len (str);
1362 if (wrbfd)
1364 bfd_byte *d;
1365 rc_uint_type i;
1366 d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1367 for (i = 0; i < len; i++)
1368 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1369 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1370 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1372 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1374 return off;
1377 /* Convert an accelerator resource to binary. */
1379 static rc_uint_type
1380 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1381 const rc_accelerator *accelerators)
1383 const rc_accelerator *a;
1385 for (a = accelerators; a != NULL; a = a->next)
1387 if (wrbfd)
1389 struct bin_accelerator ba;
1391 windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1392 windres_put_16 (wrbfd, ba.key, a->key);
1393 windres_put_16 (wrbfd, ba.id, a->id);
1394 windres_put_16 (wrbfd, ba.pad, 0);
1395 set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1397 off += BIN_ACCELERATOR_SIZE;
1399 return off;
1402 /* Convert a cursor resource to binary. */
1404 static rc_uint_type
1405 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1407 if (wrbfd)
1409 struct bin_cursor bc;
1411 windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1412 windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1413 set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1414 if (c->length)
1415 set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1417 off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1418 return off;
1421 /* Convert a group cursor resource to binary. */
1423 static rc_uint_type
1424 res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1425 const rc_group_cursor *group_cursors)
1427 int c = 0;
1428 const rc_group_cursor *gc;
1429 struct bin_group_cursor bgc;
1430 struct bin_group_cursor_item bgci;
1431 rc_uint_type start = off;
1433 off += BIN_GROUP_CURSOR_SIZE;
1435 for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1437 if (wrbfd)
1439 windres_put_16 (wrbfd, bgci.width, gc->width);
1440 windres_put_16 (wrbfd, bgci.height, gc->height);
1441 windres_put_16 (wrbfd, bgci.planes, gc->planes);
1442 windres_put_16 (wrbfd, bgci.bits, gc->bits);
1443 windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1444 windres_put_16 (wrbfd, bgci.index, gc->index);
1445 set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1448 off += BIN_GROUP_CURSOR_ITEM_SIZE;
1450 if (wrbfd)
1452 windres_put_16 (wrbfd, bgc.sig1, 0);
1453 windres_put_16 (wrbfd, bgc.sig2, 2);
1454 windres_put_16 (wrbfd, bgc.nitems, c);
1455 set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1457 return off;
1460 /* Convert a dialog resource to binary. */
1462 static rc_uint_type
1463 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1465 rc_uint_type off_delta;
1466 rc_uint_type start, marker;
1467 int dialogex;
1468 int c;
1469 rc_dialog_control *dc;
1470 struct bin_dialogex bdx;
1471 struct bin_dialog bd;
1473 off_delta = off;
1474 start = off;
1475 dialogex = extended_dialog (dialog);
1477 if (wrbfd)
1479 if (! dialogex)
1481 windres_put_32 (wrbfd, bd.style, dialog->style);
1482 windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1483 windres_put_16 (wrbfd, bd.x, dialog->x);
1484 windres_put_16 (wrbfd, bd.y, dialog->y);
1485 windres_put_16 (wrbfd, bd.width, dialog->width);
1486 windres_put_16 (wrbfd, bd.height, dialog->height);
1488 else
1490 windres_put_16 (wrbfd, bdx.sig1, 1);
1491 windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1492 windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1493 windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1494 windres_put_32 (wrbfd, bdx.style, dialog->style);
1495 windres_put_16 (wrbfd, bdx.x, dialog->x);
1496 windres_put_16 (wrbfd, bdx.y, dialog->y);
1497 windres_put_16 (wrbfd, bdx.width, dialog->width);
1498 windres_put_16 (wrbfd, bdx.height, dialog->height);
1502 off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1504 off = resid_to_bin (wrbfd, off, dialog->menu);
1505 off = resid_to_bin (wrbfd, off, dialog->class);
1506 off = unicode_to_bin (wrbfd, off, dialog->caption);
1508 if ((dialog->style & DS_SETFONT) != 0)
1510 if (wrbfd)
1512 if (! dialogex)
1514 struct bin_dialogfont bdf;
1515 windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1516 set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1518 else
1520 struct bin_dialogexfont bdxf;
1521 windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1522 windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1523 windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1524 windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1525 set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1528 off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1529 off = unicode_to_bin (wrbfd, off, dialog->font);
1531 for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1533 bfd_byte dc_rclen[2];
1535 off += (4 - ((off - off_delta) & 3)) & 3;
1536 if (wrbfd)
1538 if (! dialogex)
1540 struct bin_dialog_control bdc;
1542 windres_put_32 (wrbfd, bdc.style, dc->style);
1543 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1544 windres_put_16 (wrbfd, bdc.x, dc->x);
1545 windres_put_16 (wrbfd, bdc.y, dc->y);
1546 windres_put_16 (wrbfd, bdc.width, dc->width);
1547 windres_put_16 (wrbfd, bdc.height, dc->height);
1548 windres_put_16 (wrbfd, bdc.id, dc->id);
1549 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1551 else
1553 struct bin_dialogex_control bdc;
1555 windres_put_32 (wrbfd, bdc.help, dc->help);
1556 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1557 windres_put_32 (wrbfd, bdc.style, dc->style);
1558 windres_put_16 (wrbfd, bdc.x, dc->x);
1559 windres_put_16 (wrbfd, bdc.y, dc->y);
1560 windres_put_16 (wrbfd, bdc.width, dc->width);
1561 windres_put_16 (wrbfd, bdc.height, dc->height);
1562 windres_put_32 (wrbfd, bdc.id, dc->id);
1563 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1566 off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1568 off = resid_to_bin (wrbfd, off, dc->class);
1569 off = resid_to_bin (wrbfd, off, dc->text);
1571 marker = off; /* Save two bytes for size of optional data. */
1572 off += 2;
1574 if (dc->data == NULL)
1576 if (wrbfd)
1577 windres_put_16 (wrbfd, dc_rclen, 0);
1579 else
1581 rc_uint_type saved_off = off;
1582 rc_uint_type old_off;
1584 old_off = off;
1585 off = res_to_bin_rcdata (wrbfd, off, dc->data);
1586 if ((off - old_off) == 0)
1587 old_off = off = saved_off;
1588 if (wrbfd)
1589 windres_put_16 (wrbfd, dc_rclen, off - old_off);
1591 if (wrbfd)
1592 set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1595 if (wrbfd)
1597 windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1598 if (! dialogex)
1599 set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1600 else
1601 set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1604 return off;
1607 /* Convert a fontdir resource to binary. */
1608 static rc_uint_type
1609 res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
1611 rc_uint_type start;
1612 int c;
1613 const rc_fontdir *fd;
1615 start = off;
1616 off += 2;
1618 for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1620 if (wrbfd)
1622 bfd_byte d[2];
1623 windres_put_16 (wrbfd, d, fd->index);
1624 set_windres_bfd_content (wrbfd, d, off, 2);
1625 if (fd->length)
1626 set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1628 off += (rc_uint_type) fd->length + 2;
1631 if (wrbfd)
1633 bfd_byte d[2];
1634 windres_put_16 (wrbfd, d, c);
1635 set_windres_bfd_content (wrbfd, d, start, 2);
1637 return off;
1640 /* Convert a group icon resource to binary. */
1642 static rc_uint_type
1643 res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1645 rc_uint_type start;
1646 struct bin_group_icon bgi;
1647 int c;
1648 const rc_group_icon *gi;
1650 start = off;
1651 off += BIN_GROUP_ICON_SIZE;
1653 for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1655 struct bin_group_icon_item bgii;
1657 if (wrbfd)
1659 windres_put_8 (wrbfd, bgii.width, gi->width);
1660 windres_put_8 (wrbfd, bgii.height, gi->height);
1661 windres_put_8 (wrbfd, bgii.colors, gi->colors);
1662 windres_put_8 (wrbfd, bgii.pad, 0);
1663 windres_put_16 (wrbfd, bgii.planes, gi->planes);
1664 windres_put_16 (wrbfd, bgii.bits, gi->bits);
1665 windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1666 windres_put_16 (wrbfd, bgii.index, gi->index);
1667 set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1669 off += BIN_GROUP_ICON_ITEM_SIZE;
1672 if (wrbfd)
1674 windres_put_16 (wrbfd, bgi.sig1, 0);
1675 windres_put_16 (wrbfd, bgi.sig2, 1);
1676 windres_put_16 (wrbfd, bgi.count, c);
1677 set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1679 return off;
1682 /* Convert a menu resource to binary. */
1684 static rc_uint_type
1685 res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1687 int menuex;
1689 menuex = extended_menu (menu);
1691 if (wrbfd)
1693 if (! menuex)
1695 struct bin_menu bm;
1696 windres_put_16 (wrbfd, bm.sig1, 0);
1697 windres_put_16 (wrbfd, bm.sig2, 0);
1698 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1700 else
1702 struct bin_menuex bm;
1703 windres_put_16 (wrbfd, bm.sig1, 1);
1704 windres_put_16 (wrbfd, bm.sig2, 4);
1705 windres_put_32 (wrbfd, bm.help, menu->help);
1706 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1709 off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1710 if (! menuex)
1712 off = res_to_bin_menuitems (wrbfd, off, menu->items);
1714 else
1716 off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1718 return off;
1721 /* Convert menu items to binary. */
1723 static rc_uint_type
1724 res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1726 const rc_menuitem *mi;
1728 for (mi = items; mi != NULL; mi = mi->next)
1730 struct bin_menuitem bmi;
1731 int flags;
1733 flags = mi->type;
1734 if (mi->next == NULL)
1735 flags |= MENUITEM_ENDMENU;
1736 if (mi->popup != NULL)
1737 flags |= MENUITEM_POPUP;
1739 if (wrbfd)
1741 windres_put_16 (wrbfd, bmi.flags, flags);
1742 if (mi->popup == NULL)
1743 windres_put_16 (wrbfd, bmi.id, mi->id);
1744 set_windres_bfd_content (wrbfd, &bmi, off,
1745 mi->popup == NULL ? BIN_MENUITEM_SIZE
1746 : BIN_MENUITEM_POPUP_SIZE);
1748 off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1750 off = unicode_to_bin (wrbfd, off, mi->text);
1752 if (mi->popup != NULL)
1754 off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1757 return off;
1760 /* Convert menuex items to binary. */
1762 static rc_uint_type
1763 res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1765 rc_uint_type off_delta = off;
1766 const rc_menuitem *mi;
1768 for (mi = items; mi != NULL; mi = mi->next)
1770 struct bin_menuitemex bmi;
1771 int flags;
1773 off += (4 - ((off - off_delta) & 3)) & 3;
1775 flags = 0;
1776 if (mi->next == NULL)
1777 flags |= 0x80;
1778 if (mi->popup != NULL)
1779 flags |= 1;
1781 if (wrbfd)
1783 windres_put_32 (wrbfd, bmi.type, mi->type);
1784 windres_put_32 (wrbfd, bmi.state, mi->state);
1785 windres_put_32 (wrbfd, bmi.id, mi->id);
1786 windres_put_16 (wrbfd, bmi.flags, flags);
1787 set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1789 off += BIN_MENUITEMEX_SIZE;
1791 off = unicode_to_bin (wrbfd, off, mi->text);
1793 if (mi->popup != NULL)
1795 bfd_byte help[4];
1797 off += (4 - ((off - off_delta) & 3)) & 3;
1799 if (wrbfd)
1801 windres_put_32 (wrbfd, help, mi->help);
1802 set_windres_bfd_content (wrbfd, help, off, 4);
1804 off += 4;
1805 off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1808 return off;
1811 /* Convert an rcdata resource to binary. This is also used to convert
1812 other information which happens to be stored in rc_rcdata_item lists
1813 to binary. */
1815 static rc_uint_type
1816 res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1818 const rc_rcdata_item *ri;
1820 for (ri = items; ri != NULL; ri = ri->next)
1822 rc_uint_type len;
1823 switch (ri->type)
1825 default:
1826 abort ();
1827 case RCDATA_WORD:
1828 len = 2;
1829 break;
1830 case RCDATA_DWORD:
1831 len = 4;
1832 break;
1833 case RCDATA_STRING:
1834 len = ri->u.string.length;
1835 break;
1836 case RCDATA_WSTRING:
1837 len = ri->u.wstring.length * sizeof (unichar);
1838 break;
1839 case RCDATA_BUFFER:
1840 len = ri->u.buffer.length;
1841 break;
1843 if (wrbfd)
1845 bfd_byte h[4];
1846 bfd_byte *hp = &h[0];
1847 switch (ri->type)
1849 case RCDATA_WORD:
1850 windres_put_16 (wrbfd, hp, ri->u.word);
1851 break;
1852 case RCDATA_DWORD:
1853 windres_put_32 (wrbfd, hp, ri->u.dword);
1854 break;
1855 case RCDATA_STRING:
1856 hp = (bfd_byte *) ri->u.string.s;
1857 break;
1858 case RCDATA_WSTRING:
1860 rc_uint_type i;
1862 hp = (bfd_byte *) reswr_alloc (len);
1863 for (i = 0; i < ri->u.wstring.length; i++)
1864 windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
1866 break;
1867 case RCDATA_BUFFER:
1868 hp = (bfd_byte *) ri->u.buffer.data;
1869 break;
1871 set_windres_bfd_content (wrbfd, hp, off, len);
1873 off += len;
1875 return off;
1878 /* Convert a stringtable resource to binary. */
1880 static rc_uint_type
1881 res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1882 const rc_stringtable *st)
1884 int i;
1886 for (i = 0; i < 16; i++)
1888 rc_uint_type slen, length;
1889 unichar *s;
1891 slen = (rc_uint_type) st->strings[i].length;
1892 if (slen == 0xffffffff) slen = 0;
1893 s = st->strings[i].string;
1895 length = 2 + slen * 2;
1896 if (wrbfd)
1898 bfd_byte *hp;
1899 rc_uint_type j;
1901 hp = (bfd_byte *) reswr_alloc (length);
1902 windres_put_16 (wrbfd, hp, slen);
1904 for (j = 0; j < slen; j++)
1905 windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1906 set_windres_bfd_content (wrbfd, hp, off, length);
1908 off += length;
1910 return off;
1913 /* Convert an ASCII string to a unicode binary string. This always
1914 returns exactly one bindata structure. */
1916 static rc_uint_type
1917 string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1919 rc_uint_type len;
1921 len = (rc_uint_type) strlen (s);
1923 if (wrbfd)
1925 rc_uint_type i;
1926 bfd_byte *hp;
1928 hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1930 for (i = 0; i < len; i++)
1931 windres_put_16 (wrbfd, hp + i * 2, s[i]);
1932 windres_put_16 (wrbfd, hp + i * 2, 0);
1933 set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1935 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1936 return off;
1939 static rc_uint_type
1940 res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1942 if (wrbfd)
1944 struct bin_toolbar bt;
1945 windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1946 windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1947 windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1948 set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1949 if (tb->nitems > 0)
1951 rc_toolbar_item *it;
1952 bfd_byte *ids;
1953 rc_uint_type i = 0;
1955 ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1956 it=tb->items;
1957 while(it != NULL)
1959 windres_put_32 (wrbfd, ids + i, it->id.u.id);
1960 i += 4;
1961 it = it->next;
1963 set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1966 off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1968 return off;
1971 /* Convert a versioninfo resource to binary. */
1973 static rc_uint_type
1974 res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1975 const rc_versioninfo *versioninfo)
1977 rc_uint_type off_delta = off;
1978 rc_uint_type start;
1979 struct bin_versioninfo bvi;
1980 rc_ver_info *vi;
1982 start = off;
1983 off += BIN_VERSIONINFO_SIZE;
1984 off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1985 off += (4 - ((off - off_delta) & 3)) & 3;
1987 if (versioninfo->fixed != NULL)
1989 if (wrbfd)
1991 struct bin_fixed_versioninfo bfv;
1992 const rc_fixed_versioninfo *fi;
1994 fi = versioninfo->fixed;
1995 windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1996 windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1997 windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1998 windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
1999 windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
2000 windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
2001 windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
2002 windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
2003 windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
2004 windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
2005 windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
2006 windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
2007 windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
2008 set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
2010 off += BIN_FIXED_VERSIONINFO_SIZE;
2013 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2015 struct bin_ver_info bv;
2016 rc_uint_type bv_off;
2018 off += (4 - ((off - off_delta) & 3)) & 3;
2020 bv_off = off;
2022 off += BIN_VER_INFO_SIZE;
2024 switch (vi->type)
2026 default:
2027 abort ();
2028 case VERINFO_STRING:
2030 const rc_ver_stringtable *vst;
2032 off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2034 if (!vi->u.string.stringtables)
2035 off += (4 - ((off - off_delta) & 3)) & 3;
2037 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
2039 struct bin_ver_info bvst;
2040 rc_uint_type vst_off;
2041 const rc_ver_stringinfo *vs;
2043 off += (4 - ((off - off_delta) & 3)) & 3;
2045 vst_off = off;
2046 off += BIN_VER_INFO_SIZE;
2048 off = unicode_to_bin (wrbfd, off, vst->language);
2050 for (vs = vst->strings; vs != NULL; vs = vs->next)
2052 struct bin_ver_info bvs;
2053 rc_uint_type vs_off, str_off;
2055 off += (4 - ((off - off_delta) & 3)) & 3;
2057 vs_off = off;
2058 off += BIN_VER_INFO_SIZE;
2060 off = unicode_to_bin (wrbfd, off, vs->key);
2062 off += (4 - ((off - off_delta) & 3)) & 3;
2064 str_off = off;
2065 off = unicode_to_bin (wrbfd, off, vs->value);
2067 if (wrbfd)
2069 windres_put_16 (wrbfd, bvs.size, off - vs_off);
2070 windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
2071 windres_put_16 (wrbfd, bvs.sig2, 1);
2072 set_windres_bfd_content (wrbfd, &bvs, vs_off,
2073 BIN_VER_INFO_SIZE);
2077 if (wrbfd)
2079 windres_put_16 (wrbfd, bvst.size, off - vst_off);
2080 windres_put_16 (wrbfd, bvst.sig1, 0);
2081 windres_put_16 (wrbfd, bvst.sig2, 1);
2082 set_windres_bfd_content (wrbfd, &bvst, vst_off,
2083 BIN_VER_INFO_SIZE);
2086 break;
2089 case VERINFO_VAR:
2091 rc_uint_type vvd_off, vvvd_off;
2092 struct bin_ver_info bvvd;
2093 const rc_ver_varinfo *vv;
2095 off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2097 off += (4 - ((off - off_delta) & 3)) & 3;
2099 vvd_off = off;
2100 off += BIN_VER_INFO_SIZE;
2102 off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2104 off += (4 - ((off - off_delta) & 3)) & 3;
2106 vvvd_off = off;
2108 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2110 if (wrbfd)
2112 bfd_byte vvsd[4];
2114 windres_put_16 (wrbfd, &vvsd[0], vv->language);
2115 windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2116 set_windres_bfd_content (wrbfd, vvsd, off, 4);
2118 off += 4;
2120 if (wrbfd)
2122 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2123 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2124 windres_put_16 (wrbfd, bvvd.sig2, 0);
2125 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2126 BIN_VER_INFO_SIZE);
2129 break;
2133 if (wrbfd)
2135 windres_put_16 (wrbfd, bv.size, off - bv_off);
2136 windres_put_16 (wrbfd, bv.sig1, 0);
2137 windres_put_16 (wrbfd, bv.sig2, 1);
2138 set_windres_bfd_content (wrbfd, &bv, bv_off,
2139 BIN_VER_INFO_SIZE);
2143 if (wrbfd)
2145 windres_put_16 (wrbfd, bvi.size, off - start);
2146 windres_put_16 (wrbfd, bvi.fixed_size,
2147 versioninfo->fixed == NULL ? 0
2148 : BIN_FIXED_VERSIONINFO_SIZE);
2149 windres_put_16 (wrbfd, bvi.sig2, 0);
2150 set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2152 return off;
2155 /* Convert a generic resource to binary. */
2157 static rc_uint_type
2158 res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2159 const bfd_byte *data)
2161 if (wrbfd && length != 0)
2162 set_windres_bfd_content (wrbfd, data, off, length);
2163 return off + (rc_uint_type) length;