* options.cc (version_script): Fix small typo in previous
[binutils.git] / binutils / resbin.c
blobc35af98180506ee4d23c75eb0eb5f7e976a70960
1 /* resbin.c -- manipulate the Windows binary resource format.
2 Copyright 1997, 1998, 1999, 2002, 2003, 2005, 2006, 2007, 2009, 2010
3 Free Software Foundation, Inc.
4 Written by Ian Lance Taylor, Cygnus Support.
5 Rewritten by Kai Tietz, Onevision.
7 This file is part of GNU Binutils.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
25 /* This file contains functions to convert between the binary resource
26 format and the internal structures that we want to use. The same
27 binary resource format is used in both res and COFF files. */
29 #include "sysdep.h"
30 #include "bfd.h"
31 #include "bucomm.h"
32 #include "libiberty.h"
33 #include "windres.h"
35 /* Local functions. */
37 static void toosmall (const char *);
39 static unichar *get_unicode (windres_bfd *, const bfd_byte *, rc_uint_type, rc_uint_type *);
40 static int get_resid (windres_bfd *, rc_res_id *, const bfd_byte *, rc_uint_type);
41 static rc_res_resource *bin_to_res_generic (windres_bfd *, enum rc_res_type,
42 const bfd_byte *, rc_uint_type);
43 static rc_res_resource *bin_to_res_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
44 static rc_res_resource *bin_to_res_menu (windres_bfd *,const bfd_byte *, rc_uint_type);
45 static rc_menuitem *bin_to_res_menuitems (windres_bfd *, const bfd_byte *, rc_uint_type,
46 rc_uint_type *);
47 static rc_menuitem *bin_to_res_menuexitems (windres_bfd *, const bfd_byte *, rc_uint_type,
48 rc_uint_type *);
49 static rc_res_resource *bin_to_res_dialog (windres_bfd *, const bfd_byte *, rc_uint_type);
50 static rc_res_resource *bin_to_res_string (windres_bfd *,const bfd_byte *, rc_uint_type);
51 static rc_res_resource *bin_to_res_fontdir (windres_bfd *, const bfd_byte *, rc_uint_type);
52 static rc_res_resource *bin_to_res_accelerators (windres_bfd *, const bfd_byte *, rc_uint_type);
53 static rc_res_resource *bin_to_res_rcdata (windres_bfd *, const bfd_byte *, rc_uint_type, int);
54 static rc_res_resource *bin_to_res_group_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
55 static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *, rc_uint_type);
56 static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
57 static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
58 static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
59 static void get_version_header (windres_bfd *, const bfd_byte *, rc_uint_type, const char *,
60 unichar **, rc_uint_type *, rc_uint_type *, rc_uint_type *,
61 rc_uint_type *);
63 /* Given a resource type ID, a pointer to data, a length, return a
64 rc_res_resource structure which represents that resource. The caller
65 is responsible for initializing the res_info and coff_info fields
66 of the returned structure. */
68 rc_res_resource *
69 bin_to_res (windres_bfd *wrbfd, rc_res_id type, const bfd_byte *data,
70 rc_uint_type length)
72 if (type.named)
73 return bin_to_res_userdata (wrbfd, data, length);
74 else
76 switch (type.u.id)
78 default:
79 return bin_to_res_userdata (wrbfd, data, length);
80 case RT_CURSOR:
81 return bin_to_res_cursor (wrbfd, data, length);
82 case RT_BITMAP:
83 return bin_to_res_generic (wrbfd, RES_TYPE_BITMAP, data, length);
84 case RT_ICON:
85 return bin_to_res_generic (wrbfd, RES_TYPE_ICON, data, length);
86 case RT_MENU:
87 return bin_to_res_menu (wrbfd, data, length);
88 case RT_DIALOG:
89 return bin_to_res_dialog (wrbfd, data, length);
90 case RT_STRING:
91 return bin_to_res_string (wrbfd, data, length);
92 case RT_FONTDIR:
93 return bin_to_res_fontdir (wrbfd, data, length);
94 case RT_FONT:
95 return bin_to_res_generic (wrbfd, RES_TYPE_FONT, data, length);
96 case RT_ACCELERATOR:
97 return bin_to_res_accelerators (wrbfd, data, length);
98 case RT_RCDATA:
99 return bin_to_res_rcdata (wrbfd, data, length, RES_TYPE_RCDATA);
100 case RT_MESSAGETABLE:
101 return bin_to_res_generic (wrbfd, RES_TYPE_MESSAGETABLE, data, length);
102 case RT_GROUP_CURSOR:
103 return bin_to_res_group_cursor (wrbfd, data, length);
104 case RT_GROUP_ICON:
105 return bin_to_res_group_icon (wrbfd, data, length);
106 case RT_VERSION:
107 return bin_to_res_version (wrbfd, data, length);
108 case RT_TOOLBAR:
109 return bin_to_res_toolbar (wrbfd, data, length);
115 /* Give an error if the binary data is too small. */
117 static void
118 toosmall (const char *msg)
120 fatal (_("%s: not enough binary data"), msg);
123 /* Swap in a NULL terminated unicode string. */
125 static unichar *
126 get_unicode (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
127 rc_uint_type *retlen)
129 rc_uint_type c, i;
130 unichar *ret;
132 c = 0;
133 while (1)
135 if (length < c * 2 + 2)
136 toosmall (_("null terminated unicode string"));
137 if (windres_get_16 (wrbfd, data + c * 2, 2) == 0)
138 break;
139 ++c;
142 ret = (unichar *) res_alloc ((c + 1) * sizeof (unichar));
144 for (i = 0; i < c; i++)
145 ret[i] = windres_get_16 (wrbfd, data + i * 2, 2);
146 ret[i] = 0;
148 if (retlen != NULL)
149 *retlen = c;
151 return ret;
154 /* Get a resource identifier. This returns the number of bytes used. */
156 static int
157 get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
158 rc_uint_type length)
160 rc_uint_type first;
162 if (length < 2)
163 toosmall (_("resource ID"));
165 first = windres_get_16 (wrbfd, data, 2);
166 if (first == 0xffff)
168 if (length < 4)
169 toosmall (_("resource ID"));
170 id->named = 0;
171 id->u.id = windres_get_16 (wrbfd, data + 2, 2);
172 return 4;
174 else
176 id->named = 1;
177 id->u.n.name = get_unicode (wrbfd, data, length, &id->u.n.length);
178 return id->u.n.length * 2 + 2;
182 /* Convert a resource which just stores uninterpreted data from
183 binary. */
185 rc_res_resource *
186 bin_to_res_generic (windres_bfd *wrbfd ATTRIBUTE_UNUSED, enum rc_res_type type,
187 const bfd_byte *data, rc_uint_type length)
189 rc_res_resource *r;
191 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
192 r->type = type;
193 r->u.data.data = data;
194 r->u.data.length = length;
196 return r;
199 /* Convert a cursor resource from binary. */
201 rc_res_resource *
202 bin_to_res_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
204 rc_cursor *c;
205 rc_res_resource *r;
207 if (length < 4)
208 toosmall (_("cursor"));
210 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
211 c->xhotspot = windres_get_16 (wrbfd, data, 2);
212 c->yhotspot = windres_get_16 (wrbfd, data + 2, 2);
213 c->length = length - 4;
214 c->data = data + 4;
216 r = (rc_res_resource *) res_alloc (sizeof *r);
217 r->type = RES_TYPE_CURSOR;
218 r->u.cursor = c;
220 return r;
223 /* Convert a menu resource from binary. */
225 rc_res_resource *
226 bin_to_res_menu (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
228 rc_res_resource *r;
229 rc_menu *m;
230 rc_uint_type version, got;
232 r = (rc_res_resource *) res_alloc (sizeof *r);
233 r->type = RES_TYPE_MENU;
235 m = (rc_menu *) res_alloc (sizeof (rc_menu));
236 r->u.menu = m;
238 if (length < 2)
239 toosmall (_("menu header"));
241 version = windres_get_16 (wrbfd, data, 2);
243 if (version == 0)
245 if (length < 4)
246 toosmall (_("menu header"));
247 m->help = 0;
248 m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &got);
250 else if (version == 1)
252 rc_uint_type offset;
254 if (length < 8)
255 toosmall (_("menuex header"));
256 m->help = windres_get_32 (wrbfd, data + 4, 4);
257 offset = windres_get_16 (wrbfd, data + 2, 2);
258 if (offset + 4 >= length)
259 toosmall (_("menuex offset"));
260 m->items = bin_to_res_menuexitems (wrbfd, data + 4 + offset,
261 length - (4 + offset), &got);
263 else
264 fatal (_("unsupported menu version %d"), (int) version);
266 return r;
269 /* Convert menu items from binary. */
271 static rc_menuitem *
272 bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
273 rc_uint_type *got)
275 rc_menuitem *first, **pp;
277 first = NULL;
278 pp = &first;
280 *got = 0;
282 while (length > 0)
284 rc_uint_type flags, slen, itemlen;
285 rc_uint_type stroff;
286 rc_menuitem *mi;
288 if (length < 4)
289 toosmall (_("menuitem header"));
291 mi = (rc_menuitem *) res_alloc (sizeof *mi);
292 mi->state = 0;
293 mi->help = 0;
295 flags = windres_get_16 (wrbfd, data, 2);
296 mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);
298 if ((flags & MENUITEM_POPUP) == 0)
299 stroff = 4;
300 else
301 stroff = 2;
303 if (length < stroff + 2)
304 toosmall (_("menuitem header"));
306 if (windres_get_16 (wrbfd, data + stroff, 2) == 0)
308 slen = 0;
309 mi->text = NULL;
311 else
312 mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
314 itemlen = stroff + slen * 2 + 2;
316 if ((flags & MENUITEM_POPUP) == 0)
318 mi->popup = NULL;
319 mi->id = windres_get_16 (wrbfd, data + 2, 2);
321 else
323 rc_uint_type subread;
325 mi->id = 0;
326 mi->popup = bin_to_res_menuitems (wrbfd, data + itemlen, length - itemlen,
327 &subread);
328 itemlen += subread;
331 mi->next = NULL;
332 *pp = mi;
333 pp = &mi->next;
335 data += itemlen;
336 length -= itemlen;
337 *got += itemlen;
339 if ((flags & MENUITEM_ENDMENU) != 0)
340 return first;
343 return first;
346 /* Convert menuex items from binary. */
348 static rc_menuitem *
349 bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
350 rc_uint_type *got)
352 rc_menuitem *first, **pp;
354 first = NULL;
355 pp = &first;
357 *got = 0;
359 while (length > 0)
361 rc_uint_type flags, slen;
362 rc_uint_type itemlen;
363 rc_menuitem *mi;
365 if (length < 16)
366 toosmall (_("menuitem header"));
368 mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
369 mi->type = windres_get_32 (wrbfd, data, 4);
370 mi->state = windres_get_32 (wrbfd, data + 4, 4);
371 mi->id = windres_get_32 (wrbfd, data + 8, 4);
373 flags = windres_get_16 (wrbfd, data + 12, 2);
375 if (windres_get_16 (wrbfd, data + 14, 2) == 0)
377 slen = 0;
378 mi->text = NULL;
380 else
381 mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
383 itemlen = 14 + slen * 2 + 2;
384 itemlen = (itemlen + 3) &~ 3;
386 if ((flags & 1) == 0)
388 mi->popup = NULL;
389 mi->help = 0;
391 else
393 rc_uint_type subread;
395 if (length < itemlen + 4)
396 toosmall (_("menuitem"));
397 mi->help = windres_get_32 (wrbfd, data + itemlen, 4);
398 itemlen += 4;
400 mi->popup = bin_to_res_menuexitems (wrbfd, data + itemlen,
401 length - itemlen, &subread);
402 itemlen += subread;
405 mi->next = NULL;
406 *pp = mi;
407 pp = &mi->next;
409 data += itemlen;
410 length -= itemlen;
411 *got += itemlen;
413 if ((flags & 0x80) != 0)
414 return first;
417 return first;
420 /* Convert a dialog resource from binary. */
422 static rc_res_resource *
423 bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
425 rc_uint_type signature;
426 rc_dialog *d;
427 rc_uint_type c, sublen, i;
428 rc_uint_type off;
429 rc_dialog_control **pp;
430 rc_res_resource *r;
432 if (length < 18)
433 toosmall (_("dialog header"));
435 d = (rc_dialog *) res_alloc (sizeof (rc_dialog));
437 signature = windres_get_16 (wrbfd, data + 2, 2);
438 if (signature != 0xffff)
440 d->ex = NULL;
441 d->style = windres_get_32 (wrbfd, data, 4);
442 d->exstyle = windres_get_32 (wrbfd, data + 4, 4);
443 off = 8;
445 else
447 int version;
449 version = windres_get_16 (wrbfd, data, 2);
450 if (version != 1)
451 fatal (_("unexpected DIALOGEX version %d"), version);
453 d->ex = (rc_dialog_ex *) res_alloc (sizeof (rc_dialog_ex));
454 d->ex->help = windres_get_32 (wrbfd, data + 4, 4);
455 d->exstyle = windres_get_32 (wrbfd, data + 8, 4);
456 d->style = windres_get_32 (wrbfd, data + 12, 4);
457 off = 16;
460 if (length < off + 10)
461 toosmall (_("dialog header"));
463 c = windres_get_16 (wrbfd, data + off, 2);
464 d->x = windres_get_16 (wrbfd, data + off + 2, 2);
465 d->y = windres_get_16 (wrbfd, data + off + 4, 2);
466 d->width = windres_get_16 (wrbfd, data + off + 6, 2);
467 d->height = windres_get_16 (wrbfd, data + off + 8, 2);
469 off += 10;
471 sublen = get_resid (wrbfd, &d->menu, data + off, length - off);
472 off += sublen;
474 sublen = get_resid (wrbfd, &d->class, data + off, length - off);
475 off += sublen;
477 d->caption = get_unicode (wrbfd, data + off, length - off, &sublen);
478 off += sublen * 2 + 2;
479 if (sublen == 0)
480 d->caption = NULL;
482 if ((d->style & DS_SETFONT) == 0)
484 d->pointsize = 0;
485 d->font = NULL;
486 if (d->ex != NULL)
488 d->ex->weight = 0;
489 d->ex->italic = 0;
490 d->ex->charset = 1; /* Default charset. */
493 else
495 if (length < off + 2)
496 toosmall (_("dialog font point size"));
498 d->pointsize = windres_get_16 (wrbfd, data + off, 2);
499 off += 2;
501 if (d->ex != NULL)
503 if (length < off + 4)
504 toosmall (_("dialogex font information"));
505 d->ex->weight = windres_get_16 (wrbfd, data + off, 2);
506 d->ex->italic = windres_get_8 (wrbfd, data + off + 2, 1);
507 d->ex->charset = windres_get_8 (wrbfd, data + off + 3, 1);
508 off += 4;
511 d->font = get_unicode (wrbfd, data + off, length - off, &sublen);
512 off += sublen * 2 + 2;
515 d->controls = NULL;
516 pp = &d->controls;
518 for (i = 0; i < c; i++)
520 rc_dialog_control *dc;
521 int datalen;
523 off = (off + 3) &~ 3;
525 dc = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
527 if (d->ex == NULL)
529 if (length < off + 8)
530 toosmall (_("dialog control"));
532 dc->style = windres_get_32 (wrbfd, data + off, 4);
533 dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
534 dc->help = 0;
535 off += 8;
537 else
539 if (length < off + 12)
540 toosmall (_("dialogex control"));
541 dc->help = windres_get_32 (wrbfd, data + off, 4);
542 dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
543 dc->style = windres_get_32 (wrbfd, data + off + 8, 4);
544 off += 12;
547 if (length < off + (d->ex != NULL ? 2 : 0) + 10)
548 toosmall (_("dialog control"));
550 dc->x = windres_get_16 (wrbfd, data + off, 2);
551 dc->y = windres_get_16 (wrbfd, data + off + 2, 2);
552 dc->width = windres_get_16 (wrbfd, data + off + 4, 2);
553 dc->height = windres_get_16 (wrbfd, data + off + 6, 2);
555 if (d->ex != NULL)
556 dc->id = windres_get_32 (wrbfd, data + off + 8, 4);
557 else
558 dc->id = windres_get_16 (wrbfd, data + off + 8, 2);
560 off += 10 + (d->ex != NULL ? 2 : 0);
562 sublen = get_resid (wrbfd, &dc->class, data + off, length - off);
563 off += sublen;
565 sublen = get_resid (wrbfd, &dc->text, data + off, length - off);
566 off += sublen;
568 if (length < off + 2)
569 toosmall (_("dialog control end"));
571 datalen = windres_get_16 (wrbfd, data + off, 2);
572 off += 2;
574 if (datalen == 0)
575 dc->data = NULL;
576 else
578 off = (off + 3) &~ 3;
580 if (length < off + datalen)
581 toosmall (_("dialog control data"));
583 dc->data = ((rc_rcdata_item *)
584 res_alloc (sizeof (rc_rcdata_item)));
585 dc->data->next = NULL;
586 dc->data->type = RCDATA_BUFFER;
587 dc->data->u.buffer.length = datalen;
588 dc->data->u.buffer.data = data + off;
590 off += datalen;
593 dc->next = NULL;
594 *pp = dc;
595 pp = &dc->next;
598 r = (rc_res_resource *) res_alloc (sizeof *r);
599 r->type = RES_TYPE_DIALOG;
600 r->u.dialog = d;
602 return r;
605 /* Convert a stringtable resource from binary. */
607 static rc_res_resource *
608 bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
610 rc_stringtable *st;
611 int i;
612 rc_res_resource *r;
614 st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
616 for (i = 0; i < 16; i++)
618 unsigned int slen;
620 if (length < 2)
621 toosmall (_("stringtable string length"));
622 slen = windres_get_16 (wrbfd, data, 2);
623 st->strings[i].length = slen;
625 if (slen > 0)
627 unichar *s;
628 unsigned int j;
630 if (length < 2 + 2 * slen)
631 toosmall (_("stringtable string"));
633 s = (unichar *) res_alloc (slen * sizeof (unichar));
634 st->strings[i].string = s;
636 for (j = 0; j < slen; j++)
637 s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
640 data += 2 + 2 * slen;
641 length -= 2 + 2 * slen;
644 r = (rc_res_resource *) res_alloc (sizeof *r);
645 r->type = RES_TYPE_STRINGTABLE;
646 r->u.stringtable = st;
648 return r;
651 /* Convert a fontdir resource from binary. */
653 static rc_res_resource *
654 bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
656 rc_uint_type c, i;
657 rc_fontdir *first, **pp;
658 rc_res_resource *r;
660 if (length < 2)
661 toosmall (_("fontdir header"));
663 c = windres_get_16 (wrbfd, data, 2);
665 first = NULL;
666 pp = &first;
668 for (i = 0; i < c; i++)
670 const struct bin_fontdir_item *bfi;
671 rc_fontdir *fd;
672 unsigned int off;
674 if (length < 56)
675 toosmall (_("fontdir"));
677 bfi = (const struct bin_fontdir_item *) data;
678 fd = (rc_fontdir *) res_alloc (sizeof *fd);
679 fd->index = windres_get_16 (wrbfd, bfi->index, 2);
681 /* To work out the length of the fontdir data, we must get the
682 length of the device name and face name strings, even though
683 we don't store them in the rc_fontdir. The
684 documentation says that these are NULL terminated char
685 strings, not Unicode strings. */
687 off = 56;
689 while (off < length && data[off] != '\0')
690 ++off;
691 if (off >= length)
692 toosmall (_("fontdir device name"));
693 ++off;
695 while (off < length && data[off] != '\0')
696 ++off;
697 if (off >= length)
698 toosmall (_("fontdir face name"));
699 ++off;
701 fd->length = off;
702 fd->data = data;
704 fd->next = NULL;
705 *pp = fd;
706 pp = &fd->next;
708 /* The documentation does not indicate that any rounding is
709 required. */
711 data += off;
712 length -= off;
715 r = (rc_res_resource *) res_alloc (sizeof *r);
716 r->type = RES_TYPE_FONTDIR;
717 r->u.fontdir = first;
719 return r;
722 /* Convert an accelerators resource from binary. */
724 static rc_res_resource *
725 bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
727 rc_accelerator *first, **pp;
728 rc_res_resource *r;
730 first = NULL;
731 pp = &first;
733 while (1)
735 rc_accelerator *a;
737 if (length < 8)
738 toosmall (_("accelerator"));
740 a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
742 a->flags = windres_get_16 (wrbfd, data, 2);
743 a->key = windres_get_16 (wrbfd, data + 2, 2);
744 a->id = windres_get_16 (wrbfd, data + 4, 2);
746 a->next = NULL;
747 *pp = a;
748 pp = &a->next;
750 if ((a->flags & ACC_LAST) != 0)
751 break;
753 data += 8;
754 length -= 8;
757 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
758 r->type = RES_TYPE_ACCELERATOR;
759 r->u.acc = first;
761 return r;
764 /* Convert an rcdata resource from binary. */
766 static rc_res_resource *
767 bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
768 rc_uint_type length, int rctyp)
770 rc_rcdata_item *ri;
771 rc_res_resource *r;
773 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
775 ri->next = NULL;
776 ri->type = RCDATA_BUFFER;
777 ri->u.buffer.length = length;
778 ri->u.buffer.data = data;
780 r = (rc_res_resource *) res_alloc (sizeof *r);
781 r->type = rctyp;
782 r->u.rcdata = ri;
784 return r;
787 /* Convert a group cursor resource from binary. */
789 static rc_res_resource *
790 bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
792 int type, c, i;
793 rc_group_cursor *first, **pp;
794 rc_res_resource *r;
796 if (length < 6)
797 toosmall (_("group cursor header"));
799 type = windres_get_16 (wrbfd, data + 2, 2);
800 if (type != 2)
801 fatal (_("unexpected group cursor type %d"), type);
803 c = windres_get_16 (wrbfd, data + 4, 2);
805 data += 6;
806 length -= 6;
808 first = NULL;
809 pp = &first;
811 for (i = 0; i < c; i++)
813 rc_group_cursor *gc;
815 if (length < 14)
816 toosmall (_("group cursor"));
818 gc = (rc_group_cursor *) res_alloc (sizeof *gc);
820 gc->width = windres_get_16 (wrbfd, data, 2);
821 gc->height = windres_get_16 (wrbfd, data + 2, 2);
822 gc->planes = windres_get_16 (wrbfd, data + 4, 2);
823 gc->bits = windres_get_16 (wrbfd, data + 6, 2);
824 gc->bytes = windres_get_32 (wrbfd, data + 8, 4);
825 gc->index = windres_get_16 (wrbfd, data + 12, 2);
827 gc->next = NULL;
828 *pp = gc;
829 pp = &gc->next;
831 data += 14;
832 length -= 14;
835 r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
836 r->type = RES_TYPE_GROUP_CURSOR;
837 r->u.group_cursor = first;
839 return r;
842 /* Convert a group icon resource from binary. */
844 static rc_res_resource *
845 bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
847 int type, c, i;
848 rc_group_icon *first, **pp;
849 rc_res_resource *r;
851 if (length < 6)
852 toosmall (_("group icon header"));
854 type = windres_get_16 (wrbfd, data + 2, 2);
855 if (type != 1)
856 fatal (_("unexpected group icon type %d"), type);
858 c = windres_get_16 (wrbfd, data + 4, 2);
860 data += 6;
861 length -= 6;
863 first = NULL;
864 pp = &first;
866 for (i = 0; i < c; i++)
868 rc_group_icon *gi;
870 if (length < 14)
871 toosmall (_("group icon"));
873 gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
875 gi->width = windres_get_8 (wrbfd, data, 1);
876 gi->height = windres_get_8 (wrbfd, data + 1, 1);
877 gi->colors = windres_get_8 (wrbfd, data + 2, 1);
878 gi->planes = windres_get_16 (wrbfd, data + 4, 2);
879 gi->bits = windres_get_16 (wrbfd, data + 6, 2);
880 gi->bytes = windres_get_32 (wrbfd, data + 8, 4);
881 gi->index = windres_get_16 (wrbfd, data + 12, 2);
883 gi->next = NULL;
884 *pp = gi;
885 pp = &gi->next;
887 data += 14;
888 length -= 14;
891 r = (rc_res_resource *) res_alloc (sizeof *r);
892 r->type = RES_TYPE_GROUP_ICON;
893 r->u.group_icon = first;
895 return r;
898 /* Extract data from a version header. If KEY is not NULL, then the
899 key must be KEY; otherwise, the key is returned in *PKEY. This
900 sets *LEN to the total length, *VALLEN to the value length, *TYPE
901 to the type, and *OFF to the offset to the children. */
903 static void
904 get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
905 const char *key, unichar **pkey,
906 rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
907 rc_uint_type *off)
909 if (length < 8)
910 toosmall (key);
912 *len = windres_get_16 (wrbfd, data, 2);
913 *vallen = windres_get_16 (wrbfd, data + 2, 2);
914 *type = windres_get_16 (wrbfd, data + 4, 2);
916 *off = 6;
918 length -= 6;
919 data += 6;
921 if (key == NULL)
923 rc_uint_type sublen;
925 *pkey = get_unicode (wrbfd, data, length, &sublen);
926 *off += (sublen + 1) * sizeof (unichar);
928 else
930 while (1)
932 if (length < 2)
933 toosmall (key);
934 if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
935 fatal (_("unexpected version string"));
937 *off += 2;
938 length -= 2;
939 data += 2;
941 if (*key == '\0')
942 break;
944 ++key;
948 *off = (*off + 3) &~ 3;
951 /* Convert a version resource from binary. */
953 static rc_res_resource *
954 bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
956 rc_uint_type verlen, vallen, type, off;
957 rc_fixed_versioninfo *fi;
958 rc_ver_info *first, **pp;
959 rc_versioninfo *v;
960 rc_res_resource *r;
962 get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
963 (unichar **) NULL, &verlen, &vallen, &type, &off);
965 if ((unsigned int) verlen != length)
966 fatal (_("version length %d does not match resource length %lu"),
967 (int) verlen, (unsigned long) length);
969 if (type != 0)
970 fatal (_("unexpected version type %d"), (int) type);
972 data += off;
973 length -= off;
975 if (vallen == 0)
976 fi = NULL;
977 else
979 unsigned long signature, fiv;
981 if (vallen != 52)
982 fatal (_("unexpected fixed version information length %ld"), (long) vallen);
984 if (length < 52)
985 toosmall (_("fixed version info"));
987 signature = windres_get_32 (wrbfd, data, 4);
988 if (signature != 0xfeef04bd)
989 fatal (_("unexpected fixed version signature %lu"), signature);
991 fiv = windres_get_32 (wrbfd, data + 4, 4);
992 if (fiv != 0 && fiv != 0x10000)
993 fatal (_("unexpected fixed version info version %lu"), fiv);
995 fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
997 fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
998 fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
999 fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
1000 fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
1001 fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1002 fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1003 fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1004 fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1005 fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1006 fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1007 fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
1009 data += 52;
1010 length -= 52;
1013 first = NULL;
1014 pp = &first;
1016 while (length > 0)
1018 rc_ver_info *vi;
1019 int ch;
1021 if (length < 8)
1022 toosmall (_("version var info"));
1024 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1026 ch = windres_get_16 (wrbfd, data + 6, 2);
1028 if (ch == 'S')
1030 rc_ver_stringinfo **ppvs;
1032 vi->type = VERINFO_STRING;
1034 get_version_header (wrbfd, data, length, "StringFileInfo",
1035 (unichar **) NULL, &verlen, &vallen, &type,
1036 &off);
1038 if (vallen != 0)
1039 fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1041 data += off;
1042 length -= off;
1044 get_version_header (wrbfd, data, length, (const char *) NULL,
1045 &vi->u.string.language, &verlen, &vallen,
1046 &type, &off);
1048 if (vallen != 0)
1049 fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1051 data += off;
1052 length -= off;
1053 verlen -= off;
1055 vi->u.string.strings = NULL;
1056 ppvs = &vi->u.string.strings;
1058 /* It's convenient to round verlen to a 4 byte alignment,
1059 since we round the subvariables in the loop. */
1060 verlen = (verlen + 3) &~ 3;
1062 while (verlen > 0)
1064 rc_ver_stringinfo *vs;
1065 rc_uint_type subverlen, vslen, valoff;
1067 vs = (rc_ver_stringinfo *) res_alloc (sizeof *vs);
1069 get_version_header (wrbfd, data, length,
1070 (const char *) NULL, &vs->key, &subverlen,
1071 &vallen, &type, &off);
1073 subverlen = (subverlen + 3) &~ 3;
1075 data += off;
1076 length -= off;
1078 vs->value = get_unicode (wrbfd, data, length, &vslen);
1079 valoff = vslen * 2 + 2;
1080 valoff = (valoff + 3) &~ 3;
1082 if (off + valoff != subverlen)
1083 fatal (_("unexpected version string length %ld != %ld + %ld"),
1084 (long) subverlen, (long) off, (long) valoff);
1086 vs->next = NULL;
1087 *ppvs = vs;
1088 ppvs = &vs->next;
1090 data += valoff;
1091 length -= valoff;
1093 if (verlen < subverlen)
1094 fatal (_("unexpected version string length %ld < %ld"),
1095 (long) verlen, (long) subverlen);
1097 verlen -= subverlen;
1100 else if (ch == 'V')
1102 rc_ver_varinfo **ppvv;
1104 vi->type = VERINFO_VAR;
1106 get_version_header (wrbfd, data, length, "VarFileInfo",
1107 (unichar **) NULL, &verlen, &vallen, &type,
1108 &off);
1110 if (vallen != 0)
1111 fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1113 data += off;
1114 length -= off;
1116 get_version_header (wrbfd, data, length, (const char *) NULL,
1117 &vi->u.var.key, &verlen, &vallen, &type, &off);
1119 data += off;
1120 length -= off;
1122 vi->u.var.var = NULL;
1123 ppvv = &vi->u.var.var;
1125 while (vallen > 0)
1127 rc_ver_varinfo *vv;
1129 if (length < 4)
1130 toosmall (_("version varfileinfo"));
1132 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1134 vv->language = windres_get_16 (wrbfd, data, 2);
1135 vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1137 vv->next = NULL;
1138 *ppvv = vv;
1139 ppvv = &vv->next;
1141 data += 4;
1142 length -= 4;
1144 if (vallen < 4)
1145 fatal (_("unexpected version value length %ld"), (long) vallen);
1147 vallen -= 4;
1150 else
1151 fatal (_("unexpected version string"));
1153 vi->next = NULL;
1154 *pp = vi;
1155 pp = &vi->next;
1158 v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1159 v->fixed = fi;
1160 v->var = first;
1162 r = (rc_res_resource *) res_alloc (sizeof *r);
1163 r->type = RES_TYPE_VERSIONINFO;
1164 r->u.versioninfo = v;
1166 return r;
1169 /* Convert an arbitrary user defined resource from binary. */
1171 static rc_res_resource *
1172 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1173 rc_uint_type length)
1175 rc_rcdata_item *ri;
1176 rc_res_resource *r;
1178 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1180 ri->next = NULL;
1181 ri->type = RCDATA_BUFFER;
1182 ri->u.buffer.length = length;
1183 ri->u.buffer.data = data;
1185 r = (rc_res_resource *) res_alloc (sizeof *r);
1186 r->type = RES_TYPE_USERDATA;
1187 r->u.rcdata = ri;
1189 return r;
1192 static rc_res_resource *
1193 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1195 rc_toolbar *ri;
1196 rc_res_resource *r;
1197 rc_uint_type i;
1199 ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1200 ri->button_width = windres_get_32 (wrbfd, data, 4);
1201 ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1202 ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1203 ri->items = NULL;
1205 data += 12;
1206 length -= 12;
1207 for (i=0 ; i < ri->nitems; i++)
1209 rc_toolbar_item *it;
1210 it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1211 it->id.named = 0;
1212 it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1213 it->prev = it->next = NULL;
1214 data += 4;
1215 length -= 4;
1216 if(ri->items) {
1217 rc_toolbar_item *ii = ri->items;
1218 while (ii->next != NULL)
1219 ii = ii->next;
1220 it->prev = ii;
1221 ii->next = it;
1223 else
1224 ri->items = it;
1226 r = (rc_res_resource *) res_alloc (sizeof *r);
1227 r->type = RES_TYPE_TOOLBAR;
1228 r->u.toolbar = ri;
1229 return r;
1233 /* Local functions used to convert resources to binary format. */
1235 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1236 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1237 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1238 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1239 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1240 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1241 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1242 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1243 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1244 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1245 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1246 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1247 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1248 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1249 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1250 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1251 static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1252 const bfd_byte *);
1254 /* Convert a resource to binary. */
1256 rc_uint_type
1257 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1259 switch (res->type)
1261 case RES_TYPE_BITMAP:
1262 case RES_TYPE_FONT:
1263 case RES_TYPE_ICON:
1264 case RES_TYPE_MESSAGETABLE:
1265 return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1266 case RES_TYPE_ACCELERATOR:
1267 return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1268 case RES_TYPE_CURSOR:
1269 return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1270 case RES_TYPE_GROUP_CURSOR:
1271 return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1272 case RES_TYPE_DIALOG:
1273 return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1274 case RES_TYPE_FONTDIR:
1275 return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1276 case RES_TYPE_GROUP_ICON:
1277 return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1278 case RES_TYPE_MENU:
1279 return res_to_bin_menu (wrbfd, off, res->u.menu);
1280 case RES_TYPE_STRINGTABLE:
1281 return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1282 case RES_TYPE_VERSIONINFO:
1283 return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1284 case RES_TYPE_TOOLBAR:
1285 return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1286 case RES_TYPE_USERDATA:
1287 case RES_TYPE_RCDATA:
1288 default:
1289 return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1293 /* Convert a resource ID to binary. This always returns exactly one
1294 bindata structure. */
1296 static rc_uint_type
1297 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1299 if (! id.named)
1301 if (wrbfd)
1303 struct bin_res_id bri;
1305 windres_put_16 (wrbfd, bri.sig, 0xffff);
1306 windres_put_16 (wrbfd, bri.id, id.u.id);
1307 set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1309 off += BIN_RES_ID;
1311 else
1313 rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1314 if (wrbfd)
1316 bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1317 rc_uint_type i;
1318 for (i = 0; i < len; i++)
1319 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1320 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1321 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1323 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1325 return off;
1328 /* Convert a null terminated unicode string to binary. This always
1329 returns exactly one bindata structure. */
1331 static rc_uint_type
1332 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1334 rc_uint_type len = 0;
1336 if (str != NULL)
1337 len = unichar_len (str);
1339 if (wrbfd)
1341 bfd_byte *d;
1342 rc_uint_type i;
1343 d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1344 for (i = 0; i < len; i++)
1345 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[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 an accelerator resource to binary. */
1356 static rc_uint_type
1357 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1358 const rc_accelerator *accelerators)
1360 const rc_accelerator *a;
1362 for (a = accelerators; a != NULL; a = a->next)
1364 if (wrbfd)
1366 struct bin_accelerator ba;
1368 windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1369 windres_put_16 (wrbfd, ba.key, a->key);
1370 windres_put_16 (wrbfd, ba.id, a->id);
1371 windres_put_16 (wrbfd, ba.pad, 0);
1372 set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1374 off += BIN_ACCELERATOR_SIZE;
1376 return off;
1379 /* Convert a cursor resource to binary. */
1381 static rc_uint_type
1382 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1384 if (wrbfd)
1386 struct bin_cursor bc;
1388 windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1389 windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1390 set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1391 if (c->length)
1392 set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1394 off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1395 return off;
1398 /* Convert a group cursor resource to binary. */
1400 static rc_uint_type
1401 res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1402 const rc_group_cursor *group_cursors)
1404 int c = 0;
1405 const rc_group_cursor *gc;
1406 struct bin_group_cursor bgc;
1407 struct bin_group_cursor_item bgci;
1408 rc_uint_type start = off;
1410 off += BIN_GROUP_CURSOR_SIZE;
1412 for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1414 if (wrbfd)
1416 windres_put_16 (wrbfd, bgci.width, gc->width);
1417 windres_put_16 (wrbfd, bgci.height, gc->height);
1418 windres_put_16 (wrbfd, bgci.planes, gc->planes);
1419 windres_put_16 (wrbfd, bgci.bits, gc->bits);
1420 windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1421 windres_put_16 (wrbfd, bgci.index, gc->index);
1422 set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1425 off += BIN_GROUP_CURSOR_ITEM_SIZE;
1427 if (wrbfd)
1429 windres_put_16 (wrbfd, bgc.sig1, 0);
1430 windres_put_16 (wrbfd, bgc.sig2, 2);
1431 windres_put_16 (wrbfd, bgc.nitems, c);
1432 set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1434 return off;
1437 /* Convert a dialog resource to binary. */
1439 static rc_uint_type
1440 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1442 rc_uint_type off_delta;
1443 rc_uint_type start, marker;
1444 int dialogex;
1445 int c;
1446 rc_dialog_control *dc;
1447 struct bin_dialogex bdx;
1448 struct bin_dialog bd;
1450 off_delta = off;
1451 start = off;
1452 dialogex = extended_dialog (dialog);
1454 if (wrbfd)
1456 if (! dialogex)
1458 windres_put_32 (wrbfd, bd.style, dialog->style);
1459 windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1460 windres_put_16 (wrbfd, bd.x, dialog->x);
1461 windres_put_16 (wrbfd, bd.y, dialog->y);
1462 windres_put_16 (wrbfd, bd.width, dialog->width);
1463 windres_put_16 (wrbfd, bd.height, dialog->height);
1465 else
1467 windres_put_16 (wrbfd, bdx.sig1, 1);
1468 windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1469 windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1470 windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1471 windres_put_32 (wrbfd, bdx.style, dialog->style);
1472 windres_put_16 (wrbfd, bdx.x, dialog->x);
1473 windres_put_16 (wrbfd, bdx.y, dialog->y);
1474 windres_put_16 (wrbfd, bdx.width, dialog->width);
1475 windres_put_16 (wrbfd, bdx.height, dialog->height);
1479 off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1481 off = resid_to_bin (wrbfd, off, dialog->menu);
1482 off = resid_to_bin (wrbfd, off, dialog->class);
1483 off = unicode_to_bin (wrbfd, off, dialog->caption);
1485 if ((dialog->style & DS_SETFONT) != 0)
1487 if (wrbfd)
1489 if (! dialogex)
1491 struct bin_dialogfont bdf;
1492 windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1493 set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1495 else
1497 struct bin_dialogexfont bdxf;
1498 windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1499 windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1500 windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1501 windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1502 set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1505 off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1506 off = unicode_to_bin (wrbfd, off, dialog->font);
1508 for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1510 bfd_byte dc_rclen[2];
1512 off += (4 - ((off - off_delta) & 3)) & 3;
1513 if (wrbfd)
1515 if (! dialogex)
1517 struct bin_dialog_control bdc;
1519 windres_put_32 (wrbfd, bdc.style, dc->style);
1520 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1521 windres_put_16 (wrbfd, bdc.x, dc->x);
1522 windres_put_16 (wrbfd, bdc.y, dc->y);
1523 windres_put_16 (wrbfd, bdc.width, dc->width);
1524 windres_put_16 (wrbfd, bdc.height, dc->height);
1525 windres_put_16 (wrbfd, bdc.id, dc->id);
1526 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1528 else
1530 struct bin_dialogex_control bdc;
1532 windres_put_32 (wrbfd, bdc.help, dc->help);
1533 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1534 windres_put_32 (wrbfd, bdc.style, dc->style);
1535 windres_put_16 (wrbfd, bdc.x, dc->x);
1536 windres_put_16 (wrbfd, bdc.y, dc->y);
1537 windres_put_16 (wrbfd, bdc.width, dc->width);
1538 windres_put_16 (wrbfd, bdc.height, dc->height);
1539 windres_put_32 (wrbfd, bdc.id, dc->id);
1540 set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1543 off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1545 off = resid_to_bin (wrbfd, off, dc->class);
1546 off = resid_to_bin (wrbfd, off, dc->text);
1548 marker = off; /* Save two bytes for size of optional data. */
1549 off += 2;
1551 if (dc->data == NULL)
1553 if (wrbfd)
1554 windres_put_16 (wrbfd, dc_rclen, 0);
1556 else
1558 rc_uint_type saved_off = off;
1559 rc_uint_type old_off;
1560 off += (4 - ((off - off_delta) & 3)) & 3;
1562 old_off = off;
1563 off = res_to_bin_rcdata (wrbfd, off, dc->data);
1564 if ((off - old_off) == 0)
1565 old_off = off = saved_off;
1566 if (wrbfd)
1567 windres_put_16 (wrbfd, dc_rclen, off - old_off);
1569 if (wrbfd)
1570 set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1573 if (wrbfd)
1575 windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1576 if (! dialogex)
1577 set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1578 else
1579 set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1582 return off;
1585 /* Convert a fontdir resource to binary. */
1586 static rc_uint_type
1587 res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
1589 rc_uint_type start;
1590 int c;
1591 const rc_fontdir *fd;
1593 start = off;
1594 off += 2;
1596 for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1598 if (wrbfd)
1600 bfd_byte d[2];
1601 windres_put_16 (wrbfd, d, fd->index);
1602 set_windres_bfd_content (wrbfd, d, off, 2);
1603 if (fd->length)
1604 set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1606 off += (rc_uint_type) fd->length + 2;
1609 if (wrbfd)
1611 bfd_byte d[2];
1612 windres_put_16 (wrbfd, d, c);
1613 set_windres_bfd_content (wrbfd, d, start, 2);
1615 return off;
1618 /* Convert a group icon resource to binary. */
1620 static rc_uint_type
1621 res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1623 rc_uint_type start;
1624 struct bin_group_icon bgi;
1625 int c;
1626 const rc_group_icon *gi;
1628 start = off;
1629 off += BIN_GROUP_ICON_SIZE;
1631 for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1633 struct bin_group_icon_item bgii;
1635 if (wrbfd)
1637 windres_put_8 (wrbfd, bgii.width, gi->width);
1638 windres_put_8 (wrbfd, bgii.height, gi->height);
1639 windres_put_8 (wrbfd, bgii.colors, gi->colors);
1640 windres_put_8 (wrbfd, bgii.pad, 0);
1641 windres_put_16 (wrbfd, bgii.planes, gi->planes);
1642 windres_put_16 (wrbfd, bgii.bits, gi->bits);
1643 windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1644 windres_put_16 (wrbfd, bgii.index, gi->index);
1645 set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1647 off += BIN_GROUP_ICON_ITEM_SIZE;
1650 if (wrbfd)
1652 windres_put_16 (wrbfd, bgi.sig1, 0);
1653 windres_put_16 (wrbfd, bgi.sig2, 1);
1654 windres_put_16 (wrbfd, bgi.count, c);
1655 set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1657 return off;
1660 /* Convert a menu resource to binary. */
1662 static rc_uint_type
1663 res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1665 int menuex;
1667 menuex = extended_menu (menu);
1669 if (wrbfd)
1671 if (! menuex)
1673 struct bin_menu bm;
1674 windres_put_16 (wrbfd, bm.sig1, 0);
1675 windres_put_16 (wrbfd, bm.sig2, 0);
1676 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1678 else
1680 struct bin_menuex bm;
1681 windres_put_16 (wrbfd, bm.sig1, 1);
1682 windres_put_16 (wrbfd, bm.sig2, 4);
1683 windres_put_32 (wrbfd, bm.help, menu->help);
1684 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1687 off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1688 if (! menuex)
1690 off = res_to_bin_menuitems (wrbfd, off, menu->items);
1692 else
1694 off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1696 return off;
1699 /* Convert menu items to binary. */
1701 static rc_uint_type
1702 res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1704 const rc_menuitem *mi;
1706 for (mi = items; mi != NULL; mi = mi->next)
1708 struct bin_menuitem bmi;
1709 int flags;
1711 flags = mi->type;
1712 if (mi->next == NULL)
1713 flags |= MENUITEM_ENDMENU;
1714 if (mi->popup != NULL)
1715 flags |= MENUITEM_POPUP;
1717 if (wrbfd)
1719 windres_put_16 (wrbfd, bmi.flags, flags);
1720 if (mi->popup == NULL)
1721 windres_put_16 (wrbfd, bmi.id, mi->id);
1722 set_windres_bfd_content (wrbfd, &bmi, off,
1723 mi->popup == NULL ? BIN_MENUITEM_SIZE
1724 : BIN_MENUITEM_POPUP_SIZE);
1726 off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1728 off = unicode_to_bin (wrbfd, off, mi->text);
1730 if (mi->popup != NULL)
1732 off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1735 return off;
1738 /* Convert menuex items to binary. */
1740 static rc_uint_type
1741 res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1743 rc_uint_type off_delta = off;
1744 const rc_menuitem *mi;
1746 for (mi = items; mi != NULL; mi = mi->next)
1748 struct bin_menuitemex bmi;
1749 int flags;
1751 off += (4 - ((off - off_delta) & 3)) & 3;
1753 flags = 0;
1754 if (mi->next == NULL)
1755 flags |= 0x80;
1756 if (mi->popup != NULL)
1757 flags |= 1;
1759 if (wrbfd)
1761 windres_put_32 (wrbfd, bmi.type, mi->type);
1762 windres_put_32 (wrbfd, bmi.state, mi->state);
1763 windres_put_32 (wrbfd, bmi.id, mi->id);
1764 windres_put_16 (wrbfd, bmi.flags, flags);
1765 set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1767 off += BIN_MENUITEMEX_SIZE;
1769 off = unicode_to_bin (wrbfd, off, mi->text);
1771 if (mi->popup != NULL)
1773 bfd_byte help[4];
1775 off += (4 - ((off - off_delta) & 3)) & 3;
1777 if (wrbfd)
1779 windres_put_32 (wrbfd, help, mi->help);
1780 set_windres_bfd_content (wrbfd, help, off, 4);
1782 off += 4;
1783 off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1786 return off;
1789 /* Convert an rcdata resource to binary. This is also used to convert
1790 other information which happens to be stored in rc_rcdata_item lists
1791 to binary. */
1793 static rc_uint_type
1794 res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1796 const rc_rcdata_item *ri;
1798 for (ri = items; ri != NULL; ri = ri->next)
1800 rc_uint_type len;
1801 switch (ri->type)
1803 default:
1804 abort ();
1805 case RCDATA_WORD:
1806 len = 2;
1807 break;
1808 case RCDATA_DWORD:
1809 len = 4;
1810 break;
1811 case RCDATA_STRING:
1812 len = ri->u.string.length;
1813 break;
1814 case RCDATA_WSTRING:
1815 len = ri->u.wstring.length * sizeof (unichar);
1816 break;
1817 case RCDATA_BUFFER:
1818 len = ri->u.buffer.length;
1819 break;
1821 if (wrbfd)
1823 bfd_byte h[4];
1824 bfd_byte *hp = &h[0];
1825 switch (ri->type)
1827 case RCDATA_WORD:
1828 windres_put_16 (wrbfd, hp, ri->u.word);
1829 break;
1830 case RCDATA_DWORD:
1831 windres_put_32 (wrbfd, hp, ri->u.dword);
1832 break;
1833 case RCDATA_STRING:
1834 hp = (bfd_byte *) ri->u.string.s;
1835 break;
1836 case RCDATA_WSTRING:
1838 rc_uint_type i;
1840 hp = (bfd_byte *) reswr_alloc (len);
1841 for (i = 0; i < ri->u.wstring.length; i++)
1842 windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
1844 break;
1845 case RCDATA_BUFFER:
1846 hp = (bfd_byte *) ri->u.buffer.data;
1847 break;
1849 set_windres_bfd_content (wrbfd, hp, off, len);
1851 off += len;
1853 return off;
1856 /* Convert a stringtable resource to binary. */
1858 static rc_uint_type
1859 res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1860 const rc_stringtable *st)
1862 int i;
1864 for (i = 0; i < 16; i++)
1866 rc_uint_type slen, length;
1867 unichar *s;
1869 slen = (rc_uint_type) st->strings[i].length;
1870 s = st->strings[i].string;
1872 length = 2 + slen * 2;
1873 if (wrbfd)
1875 bfd_byte *hp;
1876 rc_uint_type j;
1878 hp = (bfd_byte *) reswr_alloc (length);
1879 windres_put_16 (wrbfd, hp, slen);
1881 for (j = 0; j < slen; j++)
1882 windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1883 set_windres_bfd_content (wrbfd, hp, off, length);
1885 off += length;
1887 return off;
1890 /* Convert an ASCII string to a unicode binary string. This always
1891 returns exactly one bindata structure. */
1893 static rc_uint_type
1894 string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1896 rc_uint_type len;
1898 len = (rc_uint_type) strlen (s);
1900 if (wrbfd)
1902 rc_uint_type i;
1903 bfd_byte *hp;
1905 hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1907 for (i = 0; i < len; i++)
1908 windres_put_16 (wrbfd, hp + i * 2, s[i]);
1909 windres_put_16 (wrbfd, hp + i * 2, 0);
1910 set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1912 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1913 return off;
1916 static rc_uint_type
1917 res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1919 if (wrbfd)
1921 struct bin_toolbar bt;
1922 windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1923 windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1924 windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1925 set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1926 if (tb->nitems > 0)
1928 rc_toolbar_item *it;
1929 bfd_byte *ids;
1930 rc_uint_type i = 0;
1932 ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1933 it=tb->items;
1934 while(it != NULL)
1936 windres_put_32 (wrbfd, ids + i, it->id.u.id);
1937 i += 4;
1938 it = it->next;
1940 set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1943 off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1945 return off;
1948 /* Convert a versioninfo resource to binary. */
1950 static rc_uint_type
1951 res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1952 const rc_versioninfo *versioninfo)
1954 rc_uint_type off_delta = off;
1955 rc_uint_type start;
1956 struct bin_versioninfo bvi;
1957 rc_ver_info *vi;
1959 start = off;
1960 off += BIN_VERSIONINFO_SIZE;
1961 off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1962 off += (4 - ((off - off_delta) & 3)) & 3;
1964 if (versioninfo->fixed != NULL)
1966 if (wrbfd)
1968 struct bin_fixed_versioninfo bfv;
1969 const rc_fixed_versioninfo *fi;
1971 fi = versioninfo->fixed;
1972 windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1973 windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1974 windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1975 windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
1976 windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
1977 windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
1978 windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
1979 windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
1980 windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
1981 windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
1982 windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
1983 windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
1984 windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
1985 set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
1987 off += BIN_FIXED_VERSIONINFO_SIZE;
1990 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
1992 struct bin_ver_info bv;
1993 rc_uint_type bv_off;
1995 off += (4 - ((off - off_delta) & 3)) & 3;
1997 bv_off = off;
1999 off += BIN_VER_INFO_SIZE;
2001 switch (vi->type)
2003 default:
2004 abort ();
2005 case VERINFO_STRING:
2007 struct bin_ver_info bvsd;
2008 rc_uint_type vs_off;
2009 const rc_ver_stringinfo *vs;
2011 off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2012 off += (4 - ((off - off_delta) & 3)) & 3;
2014 vs_off = off;
2016 off += BIN_VER_INFO_SIZE;
2018 off = unicode_to_bin (wrbfd, off, vi->u.string.language);
2020 for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2022 struct bin_ver_info bvss;
2023 rc_uint_type vss_off,str_off;
2025 off += (4 - ((off - off_delta) & 3)) & 3;
2027 vss_off = off;
2028 off += BIN_VER_INFO_SIZE;
2030 off = unicode_to_bin (wrbfd, off, vs->key);
2032 off += (4 - ((off - off_delta) & 3)) & 3;
2034 str_off = off;
2035 off = unicode_to_bin (wrbfd, off, vs->value);
2036 if (wrbfd)
2038 windres_put_16 (wrbfd, bvss.size, off - vss_off);
2039 windres_put_16 (wrbfd, bvss.sig1, (off - str_off) / 2);
2040 windres_put_16 (wrbfd, bvss.sig2, 1);
2041 set_windres_bfd_content (wrbfd, &bvss, vss_off,
2042 BIN_VER_INFO_SIZE);
2045 if (wrbfd)
2047 windres_put_16 (wrbfd, bvsd.size, off - vs_off);
2048 windres_put_16 (wrbfd, bvsd.sig1, 0);
2049 windres_put_16 (wrbfd, bvsd.sig2, 0);
2050 set_windres_bfd_content (wrbfd, &bvsd, vs_off,
2051 BIN_VER_INFO_SIZE);
2053 break;
2056 case VERINFO_VAR:
2058 rc_uint_type vvd_off, vvvd_off;
2059 struct bin_ver_info bvvd;
2060 const rc_ver_varinfo *vv;
2062 off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2064 off += (4 - ((off - off_delta) & 3)) & 3;
2066 vvd_off = off;
2067 off += BIN_VER_INFO_SIZE;
2069 off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2071 off += (4 - ((off - off_delta) & 3)) & 3;
2073 vvvd_off = off;
2075 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2077 if (wrbfd)
2079 bfd_byte vvsd[4];
2081 windres_put_16 (wrbfd, &vvsd[0], vv->language);
2082 windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2083 set_windres_bfd_content (wrbfd, vvsd, off, 4);
2085 off += 4;
2087 if (wrbfd)
2089 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2090 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2091 windres_put_16 (wrbfd, bvvd.sig2, 0);
2092 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2093 BIN_VER_INFO_SIZE);
2096 break;
2100 if (wrbfd)
2102 windres_put_16 (wrbfd, bv.size, off-bv_off);
2103 windres_put_16 (wrbfd, bv.sig1, 0);
2104 windres_put_16 (wrbfd, bv.sig2, 0);
2105 set_windres_bfd_content (wrbfd, &bv, bv_off,
2106 BIN_VER_INFO_SIZE);
2110 if (wrbfd)
2112 windres_put_16 (wrbfd, bvi.size, off - start);
2113 windres_put_16 (wrbfd, bvi.fixed_size,
2114 versioninfo->fixed == NULL ? 0
2115 : BIN_FIXED_VERSIONINFO_SIZE);
2116 windres_put_16 (wrbfd, bvi.sig2, 0);
2117 set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2119 return off;
2122 /* Convert a generic resource to binary. */
2124 static rc_uint_type
2125 res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2126 const bfd_byte *data)
2128 if (wrbfd && length != 0)
2129 set_windres_bfd_content (wrbfd, data, off, length);
2130 return off + (rc_uint_type) length;