struct / union in initializer, RFE #901.
[sdcc.git] / sdcc / support / sdbinutils / binutils / resbin.c
blobf4df65cc2752241009fc2f8f353397b9b55513f9
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.
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 /* PR 27686: Ignore any padding bytes after the end of the version structure. */
971 length = verlen;
973 data += off;
974 length -= off;
976 if (vallen == 0)
977 fi = NULL;
978 else
980 unsigned long signature, fiv;
982 if (vallen != 52)
983 fatal (_("unexpected fixed version information length %ld"), (long) vallen);
985 if (length < 52)
986 toosmall (_("fixed version info"));
988 signature = windres_get_32 (wrbfd, data, 4);
989 if (signature != 0xfeef04bd)
990 fatal (_("unexpected fixed version signature %lu"), signature);
992 fiv = windres_get_32 (wrbfd, data + 4, 4);
993 if (fiv != 0 && fiv != 0x10000)
994 fatal (_("unexpected fixed version info version %lu"), fiv);
996 fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
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);
1010 data += 52;
1011 length -= 52;
1014 first = NULL;
1015 pp = &first;
1017 while (length > 0)
1019 rc_ver_info *vi;
1020 int ch;
1022 if (length < 8)
1023 toosmall (_("version var info"));
1025 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1027 ch = windres_get_16 (wrbfd, data + 6, 2);
1029 if (ch == 'S')
1031 rc_ver_stringtable **ppvst;
1033 vi->type = VERINFO_STRING;
1035 get_version_header (wrbfd, data, length, "StringFileInfo",
1036 (unichar **) NULL, &verlen, &vallen, &type,
1037 &off);
1039 if (vallen != 0)
1040 fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1042 data += off;
1043 length -= off;
1045 verlen -= off;
1047 vi->u.string.stringtables = NULL;
1048 ppvst = &vi->u.string.stringtables;
1050 while (verlen > 0)
1052 rc_ver_stringtable *vst;
1053 rc_uint_type stverlen;
1054 rc_ver_stringinfo **ppvs;
1056 if (length < 8)
1057 toosmall (_("version stringtable"));
1059 vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1061 get_version_header (wrbfd, data, length, (const char *) NULL,
1062 &vst->language, &stverlen, &vallen, &type, &off);
1064 if (vallen != 0)
1065 fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1067 data += off;
1068 length -= off;
1069 verlen -= off;
1071 stverlen -= off;
1073 vst->strings = NULL;
1074 ppvs = &vst->strings;
1076 while (stverlen > 0)
1078 rc_ver_stringinfo *vs;
1079 rc_uint_type sverlen, vslen, valoff;
1081 if (length < 8)
1082 toosmall (_("version string"));
1084 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1086 get_version_header (wrbfd, data, length, (const char *) NULL,
1087 &vs->key, &sverlen, &vallen, &type, &off);
1089 data += off;
1090 length -= off;
1092 vs->value = get_unicode (wrbfd, data, length, &vslen);
1093 valoff = vslen * 2 + 2;
1094 valoff = (valoff + 3) & ~3;
1096 if (off + valoff != sverlen)
1097 fatal (_("unexpected version string length %ld != %ld + %ld"),
1098 (long) sverlen, (long) off, (long) valoff);
1100 data += valoff;
1101 length -= valoff;
1103 if (stverlen < sverlen)
1104 fatal (_("unexpected version string length %ld < %ld"),
1105 (long) verlen, (long) sverlen);
1106 stverlen -= sverlen;
1107 verlen -= sverlen;
1109 vs->next = NULL;
1110 *ppvs = vs;
1111 ppvs = &vs->next;
1114 vst->next = NULL;
1115 *ppvst = vst;
1116 ppvst = &vst->next;
1119 else if (ch == 'V')
1121 rc_ver_varinfo **ppvv;
1123 vi->type = VERINFO_VAR;
1125 get_version_header (wrbfd, data, length, "VarFileInfo",
1126 (unichar **) NULL, &verlen, &vallen, &type,
1127 &off);
1129 if (vallen != 0)
1130 fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1132 data += off;
1133 length -= off;
1135 get_version_header (wrbfd, data, length, (const char *) NULL,
1136 &vi->u.var.key, &verlen, &vallen, &type, &off);
1138 data += off;
1139 length -= off;
1141 vi->u.var.var = NULL;
1142 ppvv = &vi->u.var.var;
1144 while (vallen > 0)
1146 rc_ver_varinfo *vv;
1148 if (length < 4)
1149 toosmall (_("version varfileinfo"));
1151 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1153 vv->language = windres_get_16 (wrbfd, data, 2);
1154 vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1156 vv->next = NULL;
1157 *ppvv = vv;
1158 ppvv = &vv->next;
1160 data += 4;
1161 length -= 4;
1163 if (vallen < 4)
1164 fatal (_("unexpected version value length %ld"), (long) vallen);
1166 vallen -= 4;
1169 else if (ch == 0)
1171 if (length == 8)
1172 /* Padding - skip. */
1173 break;
1174 fatal (_("nul bytes found in version string"));
1176 else
1177 fatal (_("unexpected version string character: %x"), ch);
1179 vi->next = NULL;
1180 *pp = vi;
1181 pp = &vi->next;
1184 v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1185 v->fixed = fi;
1186 v->var = first;
1188 r = (rc_res_resource *) res_alloc (sizeof *r);
1189 r->type = RES_TYPE_VERSIONINFO;
1190 r->u.versioninfo = v;
1192 return r;
1195 /* Convert an arbitrary user defined resource from binary. */
1197 static rc_res_resource *
1198 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1199 rc_uint_type length)
1201 rc_rcdata_item *ri;
1202 rc_res_resource *r;
1204 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1206 ri->next = NULL;
1207 ri->type = RCDATA_BUFFER;
1208 ri->u.buffer.length = length;
1209 ri->u.buffer.data = data;
1211 r = (rc_res_resource *) res_alloc (sizeof *r);
1212 r->type = RES_TYPE_USERDATA;
1213 r->u.rcdata = ri;
1215 return r;
1218 static rc_res_resource *
1219 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1221 rc_toolbar *ri;
1222 rc_res_resource *r;
1223 rc_uint_type i;
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;
1231 data += 12;
1232 length -= 12;
1233 for (i=0 ; i < ri->nitems; i++)
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;
1249 else
1250 ri->items = it;
1252 r = (rc_res_resource *) res_alloc (sizeof *r);
1253 r->type = RES_TYPE_TOOLBAR;
1254 r->u.toolbar = ri;
1255 return r;
1259 /* Local functions used to convert resources to binary format. */
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 *);
1280 /* Convert a resource to binary. */
1282 rc_uint_type
1283 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1285 switch (res->type)
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);
1319 /* Convert a resource ID to binary. This always returns exactly one
1320 bindata structure. */
1322 static rc_uint_type
1323 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1325 if (! id.named)
1327 if (wrbfd)
1329 struct bin_res_id bri;
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);
1335 off += BIN_RES_ID;
1337 else
1339 rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1340 if (wrbfd)
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));
1349 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1351 return off;
1354 /* Convert a null terminated unicode string to binary. This always
1355 returns exactly one bindata structure. */
1357 static rc_uint_type
1358 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1360 rc_uint_type len = 0;
1362 if (str != NULL)
1363 len = unichar_len (str);
1365 if (wrbfd)
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));
1375 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1377 return off;
1380 /* Convert an accelerator resource to binary. */
1382 static rc_uint_type
1383 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1384 const rc_accelerator *accelerators)
1386 const rc_accelerator *a;
1388 for (a = accelerators; a != NULL; a = a->next)
1390 if (wrbfd)
1392 struct bin_accelerator ba;
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);
1400 off += BIN_ACCELERATOR_SIZE;
1402 return off;
1405 /* Convert a cursor resource to binary. */
1407 static rc_uint_type
1408 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1410 if (wrbfd)
1412 struct bin_cursor bc;
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);
1420 off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1421 return off;
1424 /* Convert a group cursor resource to binary. */
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)
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;
1436 off += BIN_GROUP_CURSOR_SIZE;
1438 for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1440 if (wrbfd)
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);
1451 off += BIN_GROUP_CURSOR_ITEM_SIZE;
1453 if (wrbfd)
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);
1460 return off;
1463 /* Convert a dialog resource to binary. */
1465 static rc_uint_type
1466 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
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;
1476 off_delta = off;
1477 start = off;
1478 dialogex = extended_dialog (dialog);
1480 if (wrbfd)
1482 if (! dialogex)
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);
1491 else
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);
1505 off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
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);
1511 if ((dialog->style & DS_SETFONT) != 0)
1513 if (wrbfd)
1515 if (! dialogex)
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);
1521 else
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);
1531 off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1532 off = unicode_to_bin (wrbfd, off, dialog->font);
1534 for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1536 bfd_byte dc_rclen[2];
1538 off += (4 - ((off - off_delta) & 3)) & 3;
1539 if (wrbfd)
1541 if (! dialogex)
1543 struct bin_dialog_control bdc;
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);
1554 else
1556 struct bin_dialogex_control bdc;
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);
1569 off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1571 off = resid_to_bin (wrbfd, off, dc->class);
1572 off = resid_to_bin (wrbfd, off, dc->text);
1574 marker = off; /* Save two bytes for size of optional data. */
1575 off += 2;
1577 if (dc->data == NULL)
1579 if (wrbfd)
1580 windres_put_16 (wrbfd, dc_rclen, 0);
1582 else
1584 rc_uint_type saved_off = off;
1585 rc_uint_type old_off;
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);
1594 if (wrbfd)
1595 set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1598 if (wrbfd)
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);
1607 return off;
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)
1614 rc_uint_type start;
1615 int c;
1616 const rc_fontdir *fd;
1618 start = off;
1619 off += 2;
1621 for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1623 if (wrbfd)
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);
1631 off += (rc_uint_type) fd->length + 2;
1634 if (wrbfd)
1636 bfd_byte d[2];
1637 windres_put_16 (wrbfd, d, c);
1638 set_windres_bfd_content (wrbfd, d, start, 2);
1640 return off;
1643 /* Convert a group icon resource to binary. */
1645 static rc_uint_type
1646 res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1648 rc_uint_type start;
1649 struct bin_group_icon bgi;
1650 int c;
1651 const rc_group_icon *gi;
1653 start = off;
1654 off += BIN_GROUP_ICON_SIZE;
1656 for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1658 struct bin_group_icon_item bgii;
1660 if (wrbfd)
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);
1672 off += BIN_GROUP_ICON_ITEM_SIZE;
1675 if (wrbfd)
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);
1682 return off;
1685 /* Convert a menu resource to binary. */
1687 static rc_uint_type
1688 res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1690 int menuex;
1692 menuex = extended_menu (menu);
1694 if (wrbfd)
1696 if (! menuex)
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);
1703 else
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);
1712 off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1713 if (! menuex)
1715 off = res_to_bin_menuitems (wrbfd, off, menu->items);
1717 else
1719 off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1721 return off;
1724 /* Convert menu items to binary. */
1726 static rc_uint_type
1727 res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1729 const rc_menuitem *mi;
1731 for (mi = items; mi != NULL; mi = mi->next)
1733 struct bin_menuitem bmi;
1734 int flags;
1736 flags = mi->type;
1737 if (mi->next == NULL)
1738 flags |= MENUITEM_ENDMENU;
1739 if (mi->popup != NULL)
1740 flags |= MENUITEM_POPUP;
1742 if (wrbfd)
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);
1751 off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1753 off = unicode_to_bin (wrbfd, off, mi->text);
1755 if (mi->popup != NULL)
1757 off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1760 return off;
1763 /* Convert menuex items to binary. */
1765 static rc_uint_type
1766 res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1768 rc_uint_type off_delta = off;
1769 const rc_menuitem *mi;
1771 for (mi = items; mi != NULL; mi = mi->next)
1773 struct bin_menuitemex bmi;
1774 int flags;
1776 off += (4 - ((off - off_delta) & 3)) & 3;
1778 flags = 0;
1779 if (mi->next == NULL)
1780 flags |= 0x80;
1781 if (mi->popup != NULL)
1782 flags |= 1;
1784 if (wrbfd)
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);
1792 off += BIN_MENUITEMEX_SIZE;
1794 off = unicode_to_bin (wrbfd, off, mi->text);
1796 if (mi->popup != NULL)
1798 bfd_byte help[4];
1800 off += (4 - ((off - off_delta) & 3)) & 3;
1802 if (wrbfd)
1804 windres_put_32 (wrbfd, help, mi->help);
1805 set_windres_bfd_content (wrbfd, help, off, 4);
1807 off += 4;
1808 off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1811 return off;
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. */
1818 static rc_uint_type
1819 res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1821 const rc_rcdata_item *ri;
1823 for (ri = items; ri != NULL; ri = ri->next)
1825 rc_uint_type len;
1826 switch (ri->type)
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;
1846 if (wrbfd)
1848 bfd_byte h[4];
1849 bfd_byte *hp = &h[0];
1850 switch (ri->type)
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:
1863 rc_uint_type i;
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]);
1869 break;
1870 case RCDATA_BUFFER:
1871 hp = (bfd_byte *) ri->u.buffer.data;
1872 break;
1874 set_windres_bfd_content (wrbfd, hp, off, len);
1876 off += len;
1878 return off;
1881 /* Convert a stringtable resource to binary. */
1883 static rc_uint_type
1884 res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1885 const rc_stringtable *st)
1887 int i;
1889 for (i = 0; i < 16; i++)
1891 rc_uint_type slen, length;
1892 unichar *s;
1894 slen = (rc_uint_type) st->strings[i].length;
1895 if (slen == 0xffffffff) slen = 0;
1896 s = st->strings[i].string;
1898 length = 2 + slen * 2;
1899 if (wrbfd)
1901 bfd_byte *hp;
1902 rc_uint_type j;
1904 hp = (bfd_byte *) reswr_alloc (length);
1905 windres_put_16 (wrbfd, hp, slen);
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);
1911 off += length;
1913 return off;
1916 /* Convert an ASCII string to a unicode binary string. This always
1917 returns exactly one bindata structure. */
1919 static rc_uint_type
1920 string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1922 rc_uint_type len;
1924 len = (rc_uint_type) strlen (s);
1926 if (wrbfd)
1928 rc_uint_type i;
1929 bfd_byte *hp;
1931 hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
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));
1938 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1939 return off;
1942 static rc_uint_type
1943 res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1945 if (wrbfd)
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)
1954 rc_toolbar_item *it;
1955 bfd_byte *ids;
1956 rc_uint_type i = 0;
1958 ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1959 it=tb->items;
1960 while(it != NULL)
1962 windres_put_32 (wrbfd, ids + i, it->id.u.id);
1963 i += 4;
1964 it = it->next;
1966 set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1969 off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1971 return off;
1974 /* Convert a versioninfo resource to binary. */
1976 static rc_uint_type
1977 res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1978 const rc_versioninfo *versioninfo)
1980 rc_uint_type off_delta = off;
1981 rc_uint_type start;
1982 struct bin_versioninfo bvi;
1983 rc_ver_info *vi;
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;
1990 if (versioninfo->fixed != NULL)
1992 if (wrbfd)
1994 struct bin_fixed_versioninfo bfv;
1995 const rc_fixed_versioninfo *fi;
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);
2013 off += BIN_FIXED_VERSIONINFO_SIZE;
2016 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2018 struct bin_ver_info bv;
2019 rc_uint_type bv_off;
2021 off += (4 - ((off - off_delta) & 3)) & 3;
2023 bv_off = off;
2025 off += BIN_VER_INFO_SIZE;
2027 switch (vi->type)
2029 default:
2030 abort ();
2031 case VERINFO_STRING:
2033 const rc_ver_stringtable *vst;
2035 off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2037 if (!vi->u.string.stringtables)
2038 off += (4 - ((off - off_delta) & 3)) & 3;
2040 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
2042 struct bin_ver_info bvst;
2043 rc_uint_type vst_off;
2044 const rc_ver_stringinfo *vs;
2046 off += (4 - ((off - off_delta) & 3)) & 3;
2048 vst_off = off;
2049 off += BIN_VER_INFO_SIZE;
2051 off = unicode_to_bin (wrbfd, off, vst->language);
2053 for (vs = vst->strings; vs != NULL; vs = vs->next)
2055 struct bin_ver_info bvs;
2056 rc_uint_type vs_off, str_off;
2058 off += (4 - ((off - off_delta) & 3)) & 3;
2060 vs_off = off;
2061 off += BIN_VER_INFO_SIZE;
2063 off = unicode_to_bin (wrbfd, off, vs->key);
2065 off += (4 - ((off - off_delta) & 3)) & 3;
2067 str_off = off;
2068 off = unicode_to_bin (wrbfd, off, vs->value);
2070 if (wrbfd)
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);
2080 if (wrbfd)
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);
2089 break;
2092 case VERINFO_VAR:
2094 rc_uint_type vvd_off, vvvd_off;
2095 struct bin_ver_info bvvd;
2096 const rc_ver_varinfo *vv;
2098 off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2100 off += (4 - ((off - off_delta) & 3)) & 3;
2102 vvd_off = off;
2103 off += BIN_VER_INFO_SIZE;
2105 off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2107 off += (4 - ((off - off_delta) & 3)) & 3;
2109 vvvd_off = off;
2111 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2113 if (wrbfd)
2115 bfd_byte vvsd[4];
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);
2121 off += 4;
2123 if (wrbfd)
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);
2132 break;
2136 if (wrbfd)
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);
2146 if (wrbfd)
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);
2155 return off;
2158 /* Convert a generic resource to binary. */
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)
2164 if (wrbfd && length != 0)
2165 set_windres_bfd_content (wrbfd, data, off, length);
2166 return off + (rc_uint_type) length;