resbin.c revision 1.10 1 /* resbin.c -- manipulate the Windows binary resource format.
2 Copyright (C) 1997-2025 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Cygnus Support.
4 Rewritten by Kai Tietz, Onevision.
5
6 This file is part of GNU Binutils.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21 02110-1301, USA. */
22
23
24 /* This file contains functions to convert between the binary resource
25 format and the internal structures that we want to use. The same
26 binary resource format is used in both res and COFF files. */
27
28 #include "sysdep.h"
29 #include "bfd.h"
30 #include "bucomm.h"
31 #include "libiberty.h"
32 #include "windres.h"
33
34 /* Local functions. */
35
36 static void toosmall (const char *);
37
38 static unichar *get_unicode (windres_bfd *, const bfd_byte *, rc_uint_type, rc_uint_type *);
39 static int get_resid (windres_bfd *, rc_res_id *, const bfd_byte *, rc_uint_type);
40 static rc_res_resource *bin_to_res_generic (windres_bfd *, enum rc_res_type,
41 const bfd_byte *, rc_uint_type);
42 static rc_res_resource *bin_to_res_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
43 static rc_res_resource *bin_to_res_menu (windres_bfd *,const bfd_byte *, rc_uint_type);
44 static rc_menuitem *bin_to_res_menuitems (windres_bfd *, const bfd_byte *, rc_uint_type,
45 rc_uint_type *);
46 static rc_menuitem *bin_to_res_menuexitems (windres_bfd *, const bfd_byte *, rc_uint_type,
47 rc_uint_type *);
48 static rc_res_resource *bin_to_res_dialog (windres_bfd *, const bfd_byte *, rc_uint_type);
49 static rc_res_resource *bin_to_res_string (windres_bfd *,const bfd_byte *, rc_uint_type);
50 static rc_res_resource *bin_to_res_fontdir (windres_bfd *, const bfd_byte *, rc_uint_type);
51 static rc_res_resource *bin_to_res_accelerators (windres_bfd *, const bfd_byte *, rc_uint_type);
52 static rc_res_resource *bin_to_res_rcdata (windres_bfd *, const bfd_byte *, rc_uint_type, int);
53 static rc_res_resource *bin_to_res_group_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
54 static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *, rc_uint_type);
55 static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
56 static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
57 static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
58 static bool get_version_header (windres_bfd *, const bfd_byte *, rc_uint_type, const char *,
59 unichar **, rc_uint_type *, rc_uint_type *, rc_uint_type *,
60 rc_uint_type *);
61
62 /* Given a resource type ID, a pointer to data, a length, return a
63 rc_res_resource structure which represents that resource. The caller
64 is responsible for initializing the res_info and coff_info fields
65 of the returned structure. */
66
67 rc_res_resource *
68 bin_to_res (windres_bfd *wrbfd, rc_res_id type, const bfd_byte *data,
69 rc_uint_type length)
70 {
71 if (type.named)
72 return bin_to_res_userdata (wrbfd, data, length);
73 else
74 {
75 switch (type.u.id)
76 {
77 default:
78 return bin_to_res_userdata (wrbfd, data, length);
79 case RT_CURSOR:
80 return bin_to_res_cursor (wrbfd, data, length);
81 case RT_BITMAP:
82 return bin_to_res_generic (wrbfd, RES_TYPE_BITMAP, data, length);
83 case RT_ICON:
84 return bin_to_res_generic (wrbfd, RES_TYPE_ICON, data, length);
85 case RT_MENU:
86 return bin_to_res_menu (wrbfd, data, length);
87 case RT_DIALOG:
88 return bin_to_res_dialog (wrbfd, data, length);
89 case RT_STRING:
90 return bin_to_res_string (wrbfd, data, length);
91 case RT_FONTDIR:
92 return bin_to_res_fontdir (wrbfd, data, length);
93 case RT_FONT:
94 return bin_to_res_generic (wrbfd, RES_TYPE_FONT, data, length);
95 case RT_ACCELERATOR:
96 return bin_to_res_accelerators (wrbfd, data, length);
97 case RT_RCDATA:
98 return bin_to_res_rcdata (wrbfd, data, length, RES_TYPE_RCDATA);
99 case RT_MESSAGETABLE:
100 return bin_to_res_generic (wrbfd, RES_TYPE_MESSAGETABLE, data, length);
101 case RT_GROUP_CURSOR:
102 return bin_to_res_group_cursor (wrbfd, data, length);
103 case RT_GROUP_ICON:
104 return bin_to_res_group_icon (wrbfd, data, length);
105 case RT_VERSION:
106 return bin_to_res_version (wrbfd, data, length);
107 case RT_TOOLBAR:
108 return bin_to_res_toolbar (wrbfd, data, length);
109
110 }
111 }
112 }
113
114 /* Give an error if the binary data is too small. */
115
116 static void
117 toosmall (const char *msg)
118 {
119 non_fatal (_("%s: not enough binary data"), msg);
120 }
121
122 /* Swap in a NULL terminated unicode string. */
123
124 static unichar *
125 get_unicode (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
126 rc_uint_type *retlen)
127 {
128 rc_uint_type c, i;
129 unichar *ret;
130
131 c = 0;
132 while (1)
133 {
134 if (length < c * 2 + 2)
135 {
136 toosmall (_("null terminated unicode string"));
137 return NULL;
138 }
139 if (windres_get_16 (wrbfd, data + c * 2) == 0)
140 break;
141 ++c;
142 }
143
144 ret = res_alloc ((c + 1) * sizeof (unichar));
145
146 for (i = 0; i < c; i++)
147 ret[i] = windres_get_16 (wrbfd, data + i * 2);
148 ret[i] = 0;
149
150 if (retlen != NULL)
151 *retlen = c;
152
153 return ret;
154 }
155
156 /* Get a resource identifier. This returns the number of bytes used. */
157
158 static int
159 get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
160 rc_uint_type length)
161 {
162 rc_uint_type first;
163
164 if (length < 2)
165 {
166 toosmall (_("resource ID"));
167 return -1;
168 }
169
170 first = windres_get_16 (wrbfd, data);
171 if (first == 0xffff)
172 {
173 if (length < 4)
174 {
175 toosmall (_("resource ID"));
176 return -1;
177 }
178 id->named = 0;
179 id->u.id = windres_get_16 (wrbfd, data + 2);
180 return 4;
181 }
182 else
183 {
184 id->named = 1;
185 id->u.n.name = get_unicode (wrbfd, data, length, &id->u.n.length);
186 if (id->u.n.name == NULL)
187 return -1;
188 return id->u.n.length * 2 + 2;
189 }
190 }
191
192 /* Convert a resource which just stores uninterpreted data from
193 binary. */
194
195 rc_res_resource *
196 bin_to_res_generic (windres_bfd *wrbfd ATTRIBUTE_UNUSED, enum rc_res_type type,
197 const bfd_byte *data, rc_uint_type length)
198 {
199 rc_res_resource *r;
200
201 r = res_alloc (sizeof (rc_res_resource));
202 r->type = type;
203 r->u.data.data = data;
204 r->u.data.length = length;
205
206 return r;
207 }
208
209 /* Convert a cursor resource from binary. */
210
211 rc_res_resource *
212 bin_to_res_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
213 {
214 rc_cursor *c;
215 rc_res_resource *r;
216
217 if (length < 4)
218 {
219 toosmall (_("cursor"));
220 return NULL;
221 }
222
223 c = res_alloc (sizeof (rc_cursor));
224 c->xhotspot = windres_get_16 (wrbfd, data);
225 c->yhotspot = windres_get_16 (wrbfd, data + 2);
226 c->length = length - 4;
227 c->data = data + 4;
228
229 r = res_alloc (sizeof *r);
230 r->type = RES_TYPE_CURSOR;
231 r->u.cursor = c;
232
233 return r;
234 }
235
236 /* Convert a menu resource from binary. */
237
238 rc_res_resource *
239 bin_to_res_menu (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
240 {
241 rc_res_resource *r;
242 rc_menu *m;
243 rc_uint_type version, got;
244
245 r = res_alloc (sizeof *r);
246 r->type = RES_TYPE_MENU;
247
248 m = res_alloc (sizeof (rc_menu));
249 r->u.menu = m;
250
251 if (length < 2)
252 {
253 toosmall (_("menu header"));
254 return NULL;
255 }
256
257 version = windres_get_16 (wrbfd, data);
258
259 if (version == 0)
260 {
261 if (length < 4)
262 {
263 toosmall (_("menu header"));
264 return NULL;
265 }
266 m->help = 0;
267 m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &got);
268 if (m->items == NULL)
269 return NULL;
270 }
271 else if (version == 1)
272 {
273 rc_uint_type offset;
274
275 if (length < 8)
276 {
277 toosmall (_("menuex header"));
278 return NULL;
279 }
280 m->help = windres_get_32 (wrbfd, data + 4);
281 offset = windres_get_16 (wrbfd, data + 2);
282 if (offset + 4 >= length)
283 {
284 toosmall (_("menuex offset"));
285 return NULL;
286 }
287 m->items = bin_to_res_menuexitems (wrbfd, data + 4 + offset,
288 length - (4 + offset), &got);
289 if (m->items == NULL)
290 return NULL;
291 }
292 else
293 {
294 non_fatal (_("unsupported menu version %d"), (int) version);
295 return NULL;
296 }
297
298 return r;
299 }
300
301 /* Convert menu items from binary. */
302
303 static rc_menuitem *
304 bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data,
305 rc_uint_type length, rc_uint_type *got)
306 {
307 rc_menuitem *first, **pp;
308
309 first = NULL;
310 pp = &first;
311
312 *got = 0;
313
314 while (length > 0)
315 {
316 rc_uint_type flags, slen, itemlen;
317 rc_uint_type stroff;
318 rc_menuitem *mi;
319
320 if (length < 4)
321 {
322 toosmall (_("menuitem header"));
323 return NULL;
324 }
325
326 mi = res_alloc (sizeof *mi);
327 mi->state = 0;
328 mi->help = 0;
329
330 flags = windres_get_16 (wrbfd, data);
331 mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);
332
333 if ((flags & MENUITEM_POPUP) == 0)
334 stroff = 4;
335 else
336 stroff = 2;
337
338 if (length < stroff + 2)
339 {
340 toosmall (_("menuitem header"));
341 return NULL;
342 }
343
344 if (windres_get_16 (wrbfd, data + stroff) == 0)
345 {
346 slen = 0;
347 mi->text = NULL;
348 }
349 else
350 {
351 mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
352 if (mi->text == NULL)
353 return NULL;
354 }
355
356 itemlen = stroff + slen * 2 + 2;
357
358 if ((flags & MENUITEM_POPUP) == 0)
359 {
360 mi->popup = NULL;
361 mi->id = windres_get_16 (wrbfd, data + 2);
362 }
363 else
364 {
365 rc_uint_type subread;
366
367 mi->id = 0;
368 mi->popup = bin_to_res_menuitems (wrbfd, data + itemlen,
369 length - itemlen, &subread);
370 if (mi->popup == NULL)
371 return NULL;
372 itemlen += subread;
373 }
374
375 mi->next = NULL;
376 *pp = mi;
377 pp = &mi->next;
378
379 data += itemlen;
380 length -= itemlen;
381 *got += itemlen;
382
383 if ((flags & MENUITEM_ENDMENU) != 0)
384 return first;
385 }
386
387 return first;
388 }
389
390 /* Convert menuex items from binary. */
391
392 static rc_menuitem *
393 bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data,
394 rc_uint_type length, rc_uint_type *got)
395 {
396 rc_menuitem *first, **pp;
397
398 first = NULL;
399 pp = &first;
400
401 *got = 0;
402
403 while (length > 0)
404 {
405 rc_uint_type flags, slen;
406 rc_uint_type itemlen;
407 rc_menuitem *mi;
408
409 if (length < 16)
410 {
411 toosmall (_("menuitem header"));
412 return NULL;
413 }
414
415 mi = res_alloc (sizeof (rc_menuitem));
416 mi->type = windres_get_32 (wrbfd, data);
417 mi->state = windres_get_32 (wrbfd, data + 4);
418 mi->id = windres_get_32 (wrbfd, data + 8);
419
420 flags = windres_get_16 (wrbfd, data + 12);
421
422 if (windres_get_16 (wrbfd, data + 14) == 0)
423 {
424 slen = 0;
425 mi->text = NULL;
426 }
427 else
428 {
429 mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
430 if (mi->text == NULL)
431 return NULL;
432 }
433
434 itemlen = 14 + slen * 2 + 2;
435 itemlen = (itemlen + 3) &~ 3;
436 /* Don't allow rounding up of itemlen to exceed length. This
437 is an anti-fuzzer measure to cope with unexpected offsets and
438 lengths. */
439 if (itemlen > length)
440 itemlen = length;
441
442 if ((flags & 1) == 0)
443 {
444 mi->popup = NULL;
445 mi->help = 0;
446 }
447 else
448 {
449 rc_uint_type subread;
450
451 if (length < itemlen + 4)
452 {
453 toosmall (_("menuitem"));
454 return NULL;
455 }
456 mi->help = windres_get_32 (wrbfd, data + itemlen);
457 itemlen += 4;
458
459 mi->popup = bin_to_res_menuexitems (wrbfd, data + itemlen,
460 length - itemlen, &subread);
461 if (mi->popup == NULL)
462 return NULL;
463 itemlen += subread;
464 }
465
466 mi->next = NULL;
467 *pp = mi;
468 pp = &mi->next;
469
470 data += itemlen;
471 length -= itemlen;
472 *got += itemlen;
473
474 if ((flags & 0x80) != 0)
475 return first;
476 }
477
478 return first;
479 }
480
481 /* Convert a dialog resource from binary. */
482
483 static rc_res_resource *
484 bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
485 {
486 rc_uint_type signature;
487 rc_dialog *d;
488 rc_uint_type c, sublen, i;
489 int ilen;
490 rc_uint_type off;
491 rc_dialog_control **pp;
492 rc_res_resource *r;
493
494 if (length < 18)
495 {
496 toosmall (_("dialog header"));
497 return NULL;
498 }
499
500 d = res_alloc (sizeof (rc_dialog));
501
502 signature = windres_get_16 (wrbfd, data + 2);
503 if (signature != 0xffff)
504 {
505 d->ex = NULL;
506 d->style = windres_get_32 (wrbfd, data);
507 d->exstyle = windres_get_32 (wrbfd, data + 4);
508 off = 8;
509 }
510 else
511 {
512 int version;
513
514 version = windres_get_16 (wrbfd, data);
515 if (version != 1)
516 {
517 non_fatal (_("unexpected DIALOGEX version %d"), version);
518 return NULL;
519 }
520
521 d->ex = res_alloc (sizeof (rc_dialog_ex));
522 d->ex->help = windres_get_32 (wrbfd, data + 4);
523 d->exstyle = windres_get_32 (wrbfd, data + 8);
524 d->style = windres_get_32 (wrbfd, data + 12);
525 off = 16;
526 }
527
528 if (length < off + 10)
529 {
530 toosmall (_("dialog header"));
531 return NULL;
532 }
533
534 c = windres_get_16 (wrbfd, data + off);
535 d->x = windres_get_16 (wrbfd, data + off + 2);
536 d->y = windres_get_16 (wrbfd, data + off + 4);
537 d->width = windres_get_16 (wrbfd, data + off + 6);
538 d->height = windres_get_16 (wrbfd, data + off + 8);
539
540 off += 10;
541
542 ilen = get_resid (wrbfd, &d->menu, data + off, length - off);
543 if (ilen == -1)
544 return NULL;
545 off += ilen;
546
547 ilen = get_resid (wrbfd, &d->class, data + off, length - off);
548 if (ilen == -1)
549 return NULL;
550 off += ilen;
551
552 d->caption = get_unicode (wrbfd, data + off, length - off, &sublen);
553 if (d->caption == NULL)
554 return NULL;
555 off += sublen * 2 + 2;
556 if (sublen == 0)
557 d->caption = NULL;
558
559 if ((d->style & DS_SETFONT) == 0)
560 {
561 d->pointsize = 0;
562 d->font = NULL;
563 if (d->ex != NULL)
564 {
565 d->ex->weight = 0;
566 d->ex->italic = 0;
567 d->ex->charset = 1; /* Default charset. */
568 }
569 }
570 else
571 {
572 if (length < off + 2)
573 {
574 toosmall (_("dialog font point size"));
575 return NULL;
576 }
577
578 d->pointsize = windres_get_16 (wrbfd, data + off);
579 off += 2;
580
581 if (d->ex != NULL)
582 {
583 if (length < off + 4)
584 {
585 toosmall (_("dialogex font information"));
586 return NULL;
587 }
588 d->ex->weight = windres_get_16 (wrbfd, data + off);
589 d->ex->italic = windres_get_8 (wrbfd, data + off + 2);
590 d->ex->charset = windres_get_8 (wrbfd, data + off + 3);
591 off += 4;
592 }
593
594 d->font = get_unicode (wrbfd, data + off, length - off, &sublen);
595 if (d->font == NULL)
596 return NULL;
597 off += sublen * 2 + 2;
598 }
599
600 d->controls = NULL;
601 pp = &d->controls;
602
603 for (i = 0; i < c; i++)
604 {
605 rc_dialog_control *dc;
606 int datalen;
607
608 off = (off + 3) &~ 3;
609
610 dc = res_alloc (sizeof (rc_dialog_control));
611
612 if (d->ex == NULL)
613 {
614 if (length < off + 8)
615 {
616 toosmall (_("dialog control"));
617 return NULL;
618 }
619
620 dc->style = windres_get_32 (wrbfd, data + off);
621 dc->exstyle = windres_get_32 (wrbfd, data + off + 4);
622 dc->help = 0;
623 off += 8;
624 }
625 else
626 {
627 if (length < off + 12)
628 {
629 toosmall (_("dialogex control"));
630 return NULL;
631 }
632 dc->help = windres_get_32 (wrbfd, data + off);
633 dc->exstyle = windres_get_32 (wrbfd, data + off + 4);
634 dc->style = windres_get_32 (wrbfd, data + off + 8);
635 off += 12;
636 }
637
638 if (length < off + (d->ex != NULL ? 2 : 0) + 10)
639 {
640 toosmall (_("dialog control"));
641 return NULL;
642 }
643
644 dc->x = windres_get_16 (wrbfd, data + off);
645 dc->y = windres_get_16 (wrbfd, data + off + 2);
646 dc->width = windres_get_16 (wrbfd, data + off + 4);
647 dc->height = windres_get_16 (wrbfd, data + off + 6);
648
649 if (d->ex != NULL)
650 dc->id = windres_get_32 (wrbfd, data + off + 8);
651 else
652 dc->id = windres_get_16 (wrbfd, data + off + 8);
653
654 off += 10 + (d->ex != NULL ? 2 : 0);
655
656 ilen = get_resid (wrbfd, &dc->class, data + off, length - off);
657 if (ilen == -1)
658 return NULL;
659 off += ilen;
660
661 ilen = get_resid (wrbfd, &dc->text, data + off, length - off);
662 if (ilen == -1)
663 return NULL;
664 off += ilen;
665
666 if (length < off + 2)
667 {
668 toosmall (_("dialog control end"));
669 return NULL;
670 }
671
672 datalen = windres_get_16 (wrbfd, data + off);
673 off += 2;
674
675 if (datalen == 0)
676 dc->data = NULL;
677 else
678 {
679 if (length < off + datalen)
680 {
681 toosmall (_("dialog control data"));
682 return NULL;
683 }
684
685 dc->data = res_alloc (sizeof (rc_rcdata_item));
686 dc->data->next = NULL;
687 dc->data->type = RCDATA_BUFFER;
688 dc->data->u.buffer.length = datalen;
689 dc->data->u.buffer.data = data + off;
690
691 off += datalen;
692 }
693
694 dc->next = NULL;
695 *pp = dc;
696 pp = &dc->next;
697 }
698
699 r = res_alloc (sizeof *r);
700 r->type = RES_TYPE_DIALOG;
701 r->u.dialog = d;
702
703 return r;
704 }
705
706 /* Convert a stringtable resource from binary. */
707
708 static rc_res_resource *
709 bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
710 {
711 rc_stringtable *st;
712 int i;
713 rc_res_resource *r;
714
715 st = res_alloc (sizeof (rc_stringtable));
716
717 for (i = 0; i < 16; i++)
718 {
719 unsigned int slen;
720
721 if (length < 2)
722 {
723 toosmall (_("stringtable string length"));
724 return NULL;
725 }
726 slen = windres_get_16 (wrbfd, data);
727 st->strings[i].length = slen;
728
729 if (slen > 0)
730 {
731 unichar *s;
732 unsigned int j;
733
734 if (length < 2 + 2 * slen)
735 {
736 toosmall (_("stringtable string"));
737 return NULL;
738 }
739
740 s = res_alloc (slen * sizeof (unichar));
741 st->strings[i].string = s;
742
743 for (j = 0; j < slen; j++)
744 s[j] = windres_get_16 (wrbfd, data + 2 + j * 2);
745 }
746
747 data += 2 + 2 * slen;
748 length -= 2 + 2 * slen;
749 }
750
751 r = res_alloc (sizeof *r);
752 r->type = RES_TYPE_STRINGTABLE;
753 r->u.stringtable = st;
754
755 return r;
756 }
757
758 /* Convert a fontdir resource from binary. */
759
760 static rc_res_resource *
761 bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data,
762 rc_uint_type length)
763 {
764 rc_uint_type c, i;
765 rc_fontdir *first, **pp;
766 rc_res_resource *r;
767
768 if (length < 2)
769 {
770 toosmall (_("fontdir header"));
771 return NULL;
772 }
773
774 c = windres_get_16 (wrbfd, data);
775
776 first = NULL;
777 pp = &first;
778
779 for (i = 0; i < c; i++)
780 {
781 const struct bin_fontdir_item *bfi;
782 rc_fontdir *fd;
783 unsigned int off;
784
785 if (length < 56)
786 {
787 toosmall (_("fontdir"));
788 return NULL;
789 }
790
791 bfi = (const struct bin_fontdir_item *) data;
792 fd = res_alloc (sizeof *fd);
793 fd->index = windres_get_16 (wrbfd, bfi->index);
794
795 /* To work out the length of the fontdir data, we must get the
796 length of the device name and face name strings, even though
797 we don't store them in the rc_fontdir. The
798 documentation says that these are NULL terminated char
799 strings, not Unicode strings. */
800
801 off = 56;
802
803 while (off < length && data[off] != '\0')
804 ++off;
805 if (off >= length)
806 {
807 toosmall (_("fontdir device name"));
808 return NULL;
809 }
810 ++off;
811
812 while (off < length && data[off] != '\0')
813 ++off;
814 if (off >= length)
815 {
816 toosmall (_("fontdir face name"));
817 return NULL;
818 }
819 ++off;
820
821 fd->length = off;
822 fd->data = data;
823
824 fd->next = NULL;
825 *pp = fd;
826 pp = &fd->next;
827
828 /* The documentation does not indicate that any rounding is
829 required. */
830
831 data += off;
832 length -= off;
833 }
834
835 r = res_alloc (sizeof *r);
836 r->type = RES_TYPE_FONTDIR;
837 r->u.fontdir = first;
838
839 return r;
840 }
841
842 /* Convert an accelerators resource from binary. */
843
844 static rc_res_resource *
845 bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data,
846 rc_uint_type length)
847 {
848 rc_accelerator *first, **pp;
849 rc_res_resource *r;
850
851 first = NULL;
852 pp = &first;
853
854 while (1)
855 {
856 rc_accelerator *a;
857
858 if (length < 8)
859 {
860 toosmall (_("accelerator"));
861 return NULL;
862 }
863
864 a = res_alloc (sizeof (rc_accelerator));
865
866 a->flags = windres_get_16 (wrbfd, data);
867 a->key = windres_get_16 (wrbfd, data + 2);
868 a->id = windres_get_16 (wrbfd, data + 4);
869
870 a->next = NULL;
871 *pp = a;
872 pp = &a->next;
873
874 if ((a->flags & ACC_LAST) != 0)
875 break;
876
877 data += 8;
878 length -= 8;
879 }
880
881 r = res_alloc (sizeof (rc_res_resource));
882 r->type = RES_TYPE_ACCELERATOR;
883 r->u.acc = first;
884
885 return r;
886 }
887
888 /* Convert an rcdata resource from binary. */
889
890 static rc_res_resource *
891 bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
892 rc_uint_type length, int rctyp)
893 {
894 rc_rcdata_item *ri;
895 rc_res_resource *r;
896
897 ri = res_alloc (sizeof (rc_rcdata_item));
898
899 ri->next = NULL;
900 ri->type = RCDATA_BUFFER;
901 ri->u.buffer.length = length;
902 ri->u.buffer.data = data;
903
904 r = res_alloc (sizeof *r);
905 r->type = rctyp;
906 r->u.rcdata = ri;
907
908 return r;
909 }
910
911 /* Convert a group cursor resource from binary. */
912
913 static rc_res_resource *
914 bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data,
915 rc_uint_type length)
916 {
917 int type, c, i;
918 rc_group_cursor *first, **pp;
919 rc_res_resource *r;
920
921 if (length < 6)
922 {
923 toosmall (_("group cursor header"));
924 return NULL;
925 }
926
927 type = windres_get_16 (wrbfd, data + 2);
928 if (type != 2)
929 {
930 non_fatal (_("unexpected group cursor type %d"), type);
931 return NULL;
932 }
933
934 c = windres_get_16 (wrbfd, data + 4);
935
936 data += 6;
937 length -= 6;
938
939 first = NULL;
940 pp = &first;
941
942 for (i = 0; i < c; i++)
943 {
944 rc_group_cursor *gc;
945
946 if (length < 14)
947 {
948 toosmall (_("group cursor"));
949 return NULL;
950 }
951
952 gc = res_alloc (sizeof *gc);
953
954 gc->width = windres_get_16 (wrbfd, data);
955 gc->height = windres_get_16 (wrbfd, data + 2);
956 gc->planes = windres_get_16 (wrbfd, data + 4);
957 gc->bits = windres_get_16 (wrbfd, data + 6);
958 gc->bytes = windres_get_32 (wrbfd, data + 8);
959 gc->index = windres_get_16 (wrbfd, data + 12);
960
961 gc->next = NULL;
962 *pp = gc;
963 pp = &gc->next;
964
965 data += 14;
966 length -= 14;
967 }
968
969 r = res_alloc (sizeof (rc_res_resource));
970 r->type = RES_TYPE_GROUP_CURSOR;
971 r->u.group_cursor = first;
972
973 return r;
974 }
975
976 /* Convert a group icon resource from binary. */
977
978 static rc_res_resource *
979 bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data,
980 rc_uint_type length)
981 {
982 int type, c, i;
983 rc_group_icon *first, **pp;
984 rc_res_resource *r;
985
986 if (length < 6)
987 {
988 toosmall (_("group icon header"));
989 return NULL;
990 }
991
992 type = windres_get_16 (wrbfd, data + 2);
993 if (type != 1)
994 {
995 non_fatal (_("unexpected group icon type %d"), type);
996 return NULL;
997 }
998
999 c = windres_get_16 (wrbfd, data + 4);
1000
1001 data += 6;
1002 length -= 6;
1003
1004 first = NULL;
1005 pp = &first;
1006
1007 for (i = 0; i < c; i++)
1008 {
1009 rc_group_icon *gi;
1010
1011 if (length < 14)
1012 {
1013 toosmall (_("group icon"));
1014 return NULL;
1015 }
1016
1017 gi = res_alloc (sizeof (rc_group_icon));
1018
1019 gi->width = windres_get_8 (wrbfd, data);
1020 gi->height = windres_get_8 (wrbfd, data + 1);
1021 gi->colors = windres_get_8 (wrbfd, data + 2);
1022 gi->planes = windres_get_16 (wrbfd, data + 4);
1023 gi->bits = windres_get_16 (wrbfd, data + 6);
1024 gi->bytes = windres_get_32 (wrbfd, data + 8);
1025 gi->index = windres_get_16 (wrbfd, data + 12);
1026
1027 gi->next = NULL;
1028 *pp = gi;
1029 pp = &gi->next;
1030
1031 data += 14;
1032 length -= 14;
1033 }
1034
1035 r = res_alloc (sizeof *r);
1036 r->type = RES_TYPE_GROUP_ICON;
1037 r->u.group_icon = first;
1038
1039 return r;
1040 }
1041
1042 /* Extract data from a version header. If KEY is not NULL, then the
1043 key must be KEY; otherwise, the key is returned in *PKEY. This
1044 sets *LEN to the total length, *VALLEN to the value length, *TYPE
1045 to the type, and *OFF to the offset to the children. */
1046
1047 static bool
1048 get_version_header (windres_bfd *wrbfd, const bfd_byte *data,
1049 rc_uint_type length, const char *key, unichar **pkey,
1050 rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
1051 rc_uint_type *off)
1052 {
1053 if (length < 8)
1054 {
1055 toosmall (key);
1056 return false;
1057 }
1058
1059 *len = (windres_get_16 (wrbfd, data) + 3) & ~3;
1060 *vallen = windres_get_16 (wrbfd, data + 2);
1061 *type = windres_get_16 (wrbfd, data + 4);
1062
1063 *off = 6;
1064
1065 length -= 6;
1066 data += 6;
1067
1068 if (key == NULL)
1069 {
1070 rc_uint_type sublen;
1071
1072 *pkey = get_unicode (wrbfd, data, length, &sublen);
1073 if (*pkey == NULL)
1074 return false;
1075 *off += (sublen + 1) * sizeof (unichar);
1076 }
1077 else
1078 {
1079 while (1)
1080 {
1081 if (length < 2)
1082 {
1083 toosmall (key);
1084 return false;
1085 }
1086 if (windres_get_16 (wrbfd, data) != (bfd_byte) *key)
1087 {
1088 non_fatal (_("unexpected version string"));
1089 return false;
1090 }
1091
1092 *off += 2;
1093 length -= 2;
1094 data += 2;
1095
1096 if (*key == '\0')
1097 break;
1098
1099 ++key;
1100 }
1101 }
1102
1103 *off = (*off + 3) &~ 3;
1104 return true;
1105 }
1106
1107 /* Convert a version resource from binary. */
1108
1109 static rc_res_resource *
1110 bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data,
1111 rc_uint_type length)
1112 {
1113 rc_uint_type verlen, vallen, type, off;
1114 rc_fixed_versioninfo *fi;
1115 rc_ver_info *first, **pp;
1116 rc_versioninfo *v;
1117 rc_res_resource *r;
1118
1119 if (!get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
1120 (unichar **) NULL, &verlen, &vallen, &type, &off))
1121 return NULL;
1122
1123 /* PR 17512: The verlen field does not include padding length. */
1124 if (verlen > length)
1125 {
1126 non_fatal (_("version length %lu greater than resource length %lu"),
1127 (unsigned long) verlen, (unsigned long) length);
1128 return NULL;
1129 }
1130
1131 if (type != 0)
1132 {
1133 non_fatal (_("unexpected version type %d"), (int) type);
1134 return NULL;
1135 }
1136
1137 /* PR 27686: Ignore any padding bytes after the end of the version
1138 structure. */
1139 length = verlen;
1140
1141 data += off;
1142 length -= off;
1143
1144 if (vallen == 0)
1145 fi = NULL;
1146 else
1147 {
1148 unsigned long signature, fiv;
1149
1150 if (vallen != 52)
1151 {
1152 non_fatal (_("unexpected fixed version information length %ld"),
1153 (long) vallen);
1154 return NULL;
1155 }
1156
1157 if (length < 52)
1158 {
1159 toosmall (_("fixed version info"));
1160 return NULL;
1161 }
1162
1163 signature = windres_get_32 (wrbfd, data);
1164 if (signature != 0xfeef04bd)
1165 {
1166 non_fatal (_("unexpected fixed version signature %lu"), signature);
1167 return NULL;
1168 }
1169
1170 fiv = windres_get_32 (wrbfd, data + 4);
1171 if (fiv != 0 && fiv != 0x10000)
1172 {
1173 non_fatal (_("unexpected fixed version info version %lu"), fiv);
1174 return NULL;
1175 }
1176
1177 fi = res_alloc (sizeof (rc_fixed_versioninfo));
1178
1179 fi->file_version_ms = windres_get_32 (wrbfd, data + 8);
1180 fi->file_version_ls = windres_get_32 (wrbfd, data + 12);
1181 fi->product_version_ms = windres_get_32 (wrbfd, data + 16);
1182 fi->product_version_ls = windres_get_32 (wrbfd, data + 20);
1183 fi->file_flags_mask = windres_get_32 (wrbfd, data + 24);
1184 fi->file_flags = windres_get_32 (wrbfd, data + 28);
1185 fi->file_os = windres_get_32 (wrbfd, data + 32);
1186 fi->file_type = windres_get_32 (wrbfd, data + 36);
1187 fi->file_subtype = windres_get_32 (wrbfd, data + 40);
1188 fi->file_date_ms = windres_get_32 (wrbfd, data + 44);
1189 fi->file_date_ls = windres_get_32 (wrbfd, data + 48);
1190
1191 data += 52;
1192 length -= 52;
1193 }
1194
1195 first = NULL;
1196 pp = &first;
1197
1198 while (length > 0)
1199 {
1200 rc_ver_info *vi;
1201 int ch;
1202
1203 if (length < 8)
1204 {
1205 toosmall (_("version var info"));
1206 return NULL;
1207 }
1208
1209 vi = res_alloc (sizeof (rc_ver_info));
1210
1211 ch = windres_get_16 (wrbfd, data + 6);
1212
1213 if (ch == 'S')
1214 {
1215 rc_ver_stringtable **ppvst;
1216
1217 vi->type = VERINFO_STRING;
1218
1219 if (!get_version_header (wrbfd, data, length, "StringFileInfo",
1220 (unichar **) NULL, &verlen, &vallen, &type,
1221 &off))
1222 return NULL;
1223
1224 if (vallen != 0)
1225 {
1226 non_fatal (_("unexpected stringfileinfo value length %ld"),
1227 (long) vallen);
1228 return NULL;
1229 }
1230
1231 data += off;
1232 length -= off;
1233
1234 verlen -= off;
1235
1236 vi->u.string.stringtables = NULL;
1237 ppvst = &vi->u.string.stringtables;
1238
1239 while (verlen > 0)
1240 {
1241 rc_ver_stringtable *vst;
1242 rc_uint_type stverlen;
1243 rc_ver_stringinfo **ppvs;
1244
1245 if (length < 8)
1246 {
1247 toosmall (_("version stringtable"));
1248 return NULL;
1249 }
1250
1251 vst = res_alloc (sizeof (rc_ver_stringtable));
1252
1253 if (!get_version_header (wrbfd, data, length, "version stringtable",
1254 &vst->language, &stverlen, &vallen,
1255 &type, &off))
1256 return NULL;
1257
1258 if (vallen != 0)
1259 {
1260 non_fatal (_("unexpected version stringtable value length %ld"),
1261 (long) vallen);
1262 return NULL;
1263 }
1264
1265 data += off;
1266 length -= off;
1267 verlen -= off;
1268
1269 stverlen -= off;
1270
1271 vst->strings = NULL;
1272 ppvs = &vst->strings;
1273
1274 while (stverlen > 0)
1275 {
1276 rc_ver_stringinfo *vs;
1277 rc_uint_type sverlen, vslen, valoff;
1278
1279 if (length < 8)
1280 {
1281 toosmall (_("version string"));
1282 return NULL;
1283 }
1284
1285 vs = res_alloc (sizeof (rc_ver_stringinfo));
1286
1287 if (!get_version_header (wrbfd, data, length, "version string",
1288 &vs->key, &sverlen, &vallen,
1289 &type, &off))
1290 return NULL;
1291
1292 data += off;
1293 length -= off;
1294
1295 vs->value = get_unicode (wrbfd, data, length, &vslen);
1296 if (vs->value == NULL)
1297 return NULL;
1298 valoff = vslen * 2 + 2;
1299 valoff = (valoff + 3) & ~3;
1300
1301 if (off + valoff != sverlen)
1302 {
1303 non_fatal (_("unexpected version string length %ld != %ld + %ld"),
1304 (long) sverlen, (long) off, (long) valoff);
1305 return NULL;
1306 }
1307
1308 data += valoff;
1309 length -= valoff;
1310
1311 if (stverlen < sverlen)
1312 {
1313 non_fatal (_("unexpected version string length %ld < %ld"),
1314 (long) verlen, (long) sverlen);
1315 return NULL;
1316 }
1317 stverlen -= sverlen;
1318 verlen -= sverlen;
1319
1320 vs->next = NULL;
1321 *ppvs = vs;
1322 ppvs = &vs->next;
1323 }
1324
1325 vst->next = NULL;
1326 *ppvst = vst;
1327 ppvst = &vst->next;
1328 }
1329 }
1330 else if (ch == 'V')
1331 {
1332 rc_ver_varinfo **ppvv;
1333
1334 vi->type = VERINFO_VAR;
1335
1336 if (!get_version_header (wrbfd, data, length, "VarFileInfo",
1337 (unichar **) NULL, &verlen, &vallen,
1338 &type, &off))
1339 return NULL;
1340
1341 if (vallen != 0)
1342 {
1343 non_fatal (_("unexpected varfileinfo value length %ld"),
1344 (long) vallen);
1345 return NULL;
1346 }
1347
1348 data += off;
1349 length -= off;
1350
1351 if (!get_version_header (wrbfd, data, length, "version varfileinfo",
1352 &vi->u.var.key, &verlen, &vallen,
1353 &type, &off))
1354 return NULL;
1355
1356 data += off;
1357 length -= off;
1358
1359 vi->u.var.var = NULL;
1360 ppvv = &vi->u.var.var;
1361
1362 while (vallen > 0)
1363 {
1364 rc_ver_varinfo *vv;
1365
1366 if (length < 4)
1367 {
1368 toosmall (_("version varfileinfo"));
1369 return NULL;
1370 }
1371
1372 vv = res_alloc (sizeof (rc_ver_varinfo));
1373
1374 vv->language = windres_get_16 (wrbfd, data);
1375 vv->charset = windres_get_16 (wrbfd, data + 2);
1376
1377 vv->next = NULL;
1378 *ppvv = vv;
1379 ppvv = &vv->next;
1380
1381 data += 4;
1382 length -= 4;
1383
1384 if (vallen < 4)
1385 {
1386 non_fatal (_("unexpected version value length %ld"),
1387 (long) vallen);
1388 return NULL;
1389 }
1390
1391 vallen -= 4;
1392 }
1393 }
1394 else if (ch == 0)
1395 {
1396 if (length == 8)
1397 /* Padding - skip. */
1398 break;
1399 non_fatal (_("nul bytes found in version string"));
1400 return NULL;
1401 }
1402 else
1403 {
1404 non_fatal (_("unexpected version string character: %x"), ch);
1405 return NULL;
1406 }
1407
1408 vi->next = NULL;
1409 *pp = vi;
1410 pp = &vi->next;
1411 }
1412
1413 v = res_alloc (sizeof (rc_versioninfo));
1414 v->fixed = fi;
1415 v->var = first;
1416
1417 r = res_alloc (sizeof *r);
1418 r->type = RES_TYPE_VERSIONINFO;
1419 r->u.versioninfo = v;
1420
1421 return r;
1422 }
1423
1424 /* Convert an arbitrary user defined resource from binary. */
1425
1426 static rc_res_resource *
1427 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1428 rc_uint_type length)
1429 {
1430 rc_rcdata_item *ri;
1431 rc_res_resource *r;
1432
1433 ri = res_alloc (sizeof (rc_rcdata_item));
1434
1435 ri->next = NULL;
1436 ri->type = RCDATA_BUFFER;
1437 ri->u.buffer.length = length;
1438 ri->u.buffer.data = data;
1439
1440 r = res_alloc (sizeof *r);
1441 r->type = RES_TYPE_USERDATA;
1442 r->u.rcdata = ri;
1443
1444 return r;
1445 }
1446
1447 static rc_res_resource *
1449 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data,
1450 rc_uint_type length)
1451 {
1452 rc_toolbar *ri;
1453 rc_res_resource *r;
1454 rc_uint_type i;
1455
1456 if (length < 12)
1457 {
1458 toosmall (_("toolbar"));
1459 return NULL;
1460 }
1461 ri = res_alloc (sizeof (rc_toolbar));
1462 ri->button_width = windres_get_32 (wrbfd, data);
1463 ri->button_height = windres_get_32 (wrbfd, data + 4);
1464 ri->nitems = windres_get_32 (wrbfd, data + 8);
1465 ri->items = NULL;
1466
1467 data += 12;
1468 length -= 12;
1469 for (i = 0; i < ri->nitems; i++)
1470 {
1471 rc_toolbar_item *it;
1472 it = res_alloc (sizeof (rc_toolbar_item));
1473 it->id.named = 0;
1474 if (length < 4)
1475 {
1476 toosmall (_("toolbar item"));
1477 return NULL;
1478 }
1479 it->id.u.id = (int) windres_get_32 (wrbfd, data);
1480 it->prev = it->next = NULL;
1481 data += 4;
1482 length -= 4;
1483 if(ri->items) {
1484 rc_toolbar_item *ii = ri->items;
1485 while (ii->next != NULL)
1486 ii = ii->next;
1487 it->prev = ii;
1488 ii->next = it;
1489 }
1490 else
1491 ri->items = it;
1492 }
1493 r = res_alloc (sizeof *r);
1494 r->type = RES_TYPE_TOOLBAR;
1495 r->u.toolbar = ri;
1496 return r;
1497 }
1498
1499
1500 /* Local functions used to convert resources to binary format. */
1501
1502 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1503 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1504 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1505 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1506 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1507 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1508 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1509 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1510 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1511 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1512 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1513 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1514 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1515 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1516 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1517 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1518 static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1519 const bfd_byte *);
1520
1521 /* Convert a resource to binary. */
1522
1523 rc_uint_type
1524 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1525 {
1526 switch (res->type)
1527 {
1528 case RES_TYPE_BITMAP:
1529 case RES_TYPE_FONT:
1530 case RES_TYPE_ICON:
1531 case RES_TYPE_MESSAGETABLE:
1532 return res_to_bin_generic (wrbfd, off, res->u.data.length,
1533 res->u.data.data);
1534 case RES_TYPE_ACCELERATOR:
1535 return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1536 case RES_TYPE_CURSOR:
1537 return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1538 case RES_TYPE_GROUP_CURSOR:
1539 return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1540 case RES_TYPE_DIALOG:
1541 return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1542 case RES_TYPE_FONTDIR:
1543 return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1544 case RES_TYPE_GROUP_ICON:
1545 return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1546 case RES_TYPE_MENU:
1547 return res_to_bin_menu (wrbfd, off, res->u.menu);
1548 case RES_TYPE_STRINGTABLE:
1549 return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1550 case RES_TYPE_VERSIONINFO:
1551 return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1552 case RES_TYPE_TOOLBAR:
1553 return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1554 case RES_TYPE_USERDATA:
1555 case RES_TYPE_RCDATA:
1556 default:
1557 return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1558 }
1559 }
1560
1561 /* Convert a resource ID to binary. This always returns exactly one
1562 bindata structure. */
1563
1564 static rc_uint_type
1565 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1566 {
1567 if (! id.named)
1568 {
1569 if (wrbfd)
1570 {
1571 struct bin_res_id bri;
1572
1573 windres_put_16 (wrbfd, bri.sig, 0xffff);
1574 windres_put_16 (wrbfd, bri.id, id.u.id);
1575 set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1576 }
1577 off += BIN_RES_ID;
1578 }
1579 else
1580 {
1581 rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1582 if (wrbfd)
1583 {
1584 bfd_byte *d = reswr_alloc ((len + 1) * sizeof (unichar));
1585 rc_uint_type i;
1586 for (i = 0; i < len; i++)
1587 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1588 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1589 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1590 }
1591 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1592 }
1593 return off;
1594 }
1595
1596 /* Convert a null terminated unicode string to binary. This always
1597 returns exactly one bindata structure. */
1598
1599 static rc_uint_type
1600 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1601 {
1602 rc_uint_type len = 0;
1603
1604 if (str != NULL)
1605 len = unichar_len (str);
1606
1607 if (wrbfd)
1608 {
1609 bfd_byte *d;
1610 rc_uint_type i;
1611 d = reswr_alloc ((len + 1) * sizeof (unichar));
1612 for (i = 0; i < len; i++)
1613 windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1614 windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1615 set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1616 }
1617 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1618
1619 return off;
1620 }
1621
1622 /* Convert an accelerator resource to binary. */
1623
1624 static rc_uint_type
1625 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1626 const rc_accelerator *accelerators)
1627 {
1628 const rc_accelerator *a;
1629
1630 for (a = accelerators; a != NULL; a = a->next)
1631 {
1632 if (wrbfd)
1633 {
1634 struct bin_accelerator ba;
1635
1636 windres_put_16 (wrbfd, ba.flags,
1637 a->flags | (a->next != NULL ? 0 : ACC_LAST));
1638 windres_put_16 (wrbfd, ba.key, a->key);
1639 windres_put_16 (wrbfd, ba.id, a->id);
1640 windres_put_16 (wrbfd, ba.pad, 0);
1641 set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1642 }
1643 off += BIN_ACCELERATOR_SIZE;
1644 }
1645 return off;
1646 }
1647
1648 /* Convert a cursor resource to binary. */
1649
1650 static rc_uint_type
1651 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1652 {
1653 if (wrbfd)
1654 {
1655 struct bin_cursor bc;
1656
1657 windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1658 windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1659 set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1660 if (c->length)
1661 set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE,
1662 c->length);
1663 }
1664 off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1665 return off;
1666 }
1667
1668 /* Convert a group cursor resource to binary. */
1669
1670 static rc_uint_type
1671 res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1672 const rc_group_cursor *group_cursors)
1673 {
1674 int c = 0;
1675 const rc_group_cursor *gc;
1676 struct bin_group_cursor bgc;
1677 struct bin_group_cursor_item bgci;
1678 rc_uint_type start = off;
1679
1680 off += BIN_GROUP_CURSOR_SIZE;
1681
1682 for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1683 {
1684 if (wrbfd)
1685 {
1686 windres_put_16 (wrbfd, bgci.width, gc->width);
1687 windres_put_16 (wrbfd, bgci.height, gc->height);
1688 windres_put_16 (wrbfd, bgci.planes, gc->planes);
1689 windres_put_16 (wrbfd, bgci.bits, gc->bits);
1690 windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1691 windres_put_16 (wrbfd, bgci.index, gc->index);
1692 set_windres_bfd_content (wrbfd, &bgci, off,
1693 BIN_GROUP_CURSOR_ITEM_SIZE);
1694 }
1695
1696 off += BIN_GROUP_CURSOR_ITEM_SIZE;
1697 }
1698 if (wrbfd)
1699 {
1700 windres_put_16 (wrbfd, bgc.sig1, 0);
1701 windres_put_16 (wrbfd, bgc.sig2, 2);
1702 windres_put_16 (wrbfd, bgc.nitems, c);
1703 set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1704 }
1705 return off;
1706 }
1707
1708 /* Convert a dialog resource to binary. */
1709
1710 static rc_uint_type
1711 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1712 {
1713 rc_uint_type off_delta;
1714 rc_uint_type start, marker;
1715 int dialogex;
1716 int c;
1717 rc_dialog_control *dc;
1718 struct bin_dialogex bdx;
1719 struct bin_dialog bd;
1720
1721 off_delta = off;
1722 start = off;
1723 dialogex = extended_dialog (dialog);
1724
1725 if (wrbfd)
1726 {
1727 if (! dialogex)
1728 {
1729 windres_put_32 (wrbfd, bd.style, dialog->style);
1730 windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1731 windres_put_16 (wrbfd, bd.x, dialog->x);
1732 windres_put_16 (wrbfd, bd.y, dialog->y);
1733 windres_put_16 (wrbfd, bd.width, dialog->width);
1734 windres_put_16 (wrbfd, bd.height, dialog->height);
1735 }
1736 else
1737 {
1738 windres_put_16 (wrbfd, bdx.sig1, 1);
1739 windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1740 windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1741 windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1742 windres_put_32 (wrbfd, bdx.style, dialog->style);
1743 windres_put_16 (wrbfd, bdx.x, dialog->x);
1744 windres_put_16 (wrbfd, bdx.y, dialog->y);
1745 windres_put_16 (wrbfd, bdx.width, dialog->width);
1746 windres_put_16 (wrbfd, bdx.height, dialog->height);
1747 }
1748 }
1749
1750 off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1751
1752 off = resid_to_bin (wrbfd, off, dialog->menu);
1753 off = resid_to_bin (wrbfd, off, dialog->class);
1754 off = unicode_to_bin (wrbfd, off, dialog->caption);
1755
1756 if ((dialog->style & DS_SETFONT) != 0)
1757 {
1758 if (wrbfd)
1759 {
1760 if (! dialogex)
1761 {
1762 struct bin_dialogfont bdf;
1763 windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1764 set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1765 }
1766 else
1767 {
1768 struct bin_dialogexfont bdxf;
1769 windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1770 windres_put_16 (wrbfd, bdxf.weight,
1771 dialog->ex == NULL ? 0 : dialog->ex->weight);
1772 windres_put_8 (wrbfd, bdxf.italic,
1773 dialog->ex == NULL ? 0 : dialog->ex->italic);
1774 windres_put_8 (wrbfd, bdxf.charset,
1775 dialog->ex == NULL ? 1 : dialog->ex->charset);
1776 set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1777 }
1778 }
1779 off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1780 off = unicode_to_bin (wrbfd, off, dialog->font);
1781 }
1782 for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1783 {
1784 bfd_byte dc_rclen[2];
1785
1786 off += (4 - ((off - off_delta) & 3)) & 3;
1787 if (wrbfd)
1788 {
1789 if (! dialogex)
1790 {
1791 struct bin_dialog_control bdc;
1792
1793 windres_put_32 (wrbfd, bdc.style, dc->style);
1794 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1795 windres_put_16 (wrbfd, bdc.x, dc->x);
1796 windres_put_16 (wrbfd, bdc.y, dc->y);
1797 windres_put_16 (wrbfd, bdc.width, dc->width);
1798 windres_put_16 (wrbfd, bdc.height, dc->height);
1799 windres_put_16 (wrbfd, bdc.id, dc->id);
1800 set_windres_bfd_content (wrbfd, &bdc, off,
1801 BIN_DIALOG_CONTROL_SIZE);
1802 }
1803 else
1804 {
1805 struct bin_dialogex_control bdc;
1806
1807 windres_put_32 (wrbfd, bdc.help, dc->help);
1808 windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1809 windres_put_32 (wrbfd, bdc.style, dc->style);
1810 windres_put_16 (wrbfd, bdc.x, dc->x);
1811 windres_put_16 (wrbfd, bdc.y, dc->y);
1812 windres_put_16 (wrbfd, bdc.width, dc->width);
1813 windres_put_16 (wrbfd, bdc.height, dc->height);
1814 windres_put_32 (wrbfd, bdc.id, dc->id);
1815 set_windres_bfd_content (wrbfd, &bdc, off,
1816 BIN_DIALOGEX_CONTROL_SIZE);
1817 }
1818 }
1819 off += dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE;
1820 off = resid_to_bin (wrbfd, off, dc->class);
1821 off = resid_to_bin (wrbfd, off, dc->text);
1822
1823 marker = off; /* Save two bytes for size of optional data. */
1824 off += 2;
1825
1826 if (dc->data == NULL)
1827 {
1828 if (wrbfd)
1829 windres_put_16 (wrbfd, dc_rclen, 0);
1830 }
1831 else
1832 {
1833 rc_uint_type saved_off = off;
1834 rc_uint_type old_off;
1835
1836 old_off = off;
1837 off = res_to_bin_rcdata (wrbfd, off, dc->data);
1838 if ((off - old_off) == 0)
1839 old_off = off = saved_off;
1840 if (wrbfd)
1841 windres_put_16 (wrbfd, dc_rclen, off - old_off);
1842 }
1843 if (wrbfd)
1844 set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1845 }
1846
1847 if (wrbfd)
1848 {
1849 windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1850 if (! dialogex)
1851 set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1852 else
1853 set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1854 }
1855
1856 return off;
1857 }
1858
1859 /* Convert a fontdir resource to binary. */
1860 static rc_uint_type
1861 res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off,
1862 const rc_fontdir *fontdirs)
1863 {
1864 rc_uint_type start;
1865 int c;
1866 const rc_fontdir *fd;
1867
1868 start = off;
1869 off += 2;
1870
1871 for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1872 {
1873 if (wrbfd)
1874 {
1875 bfd_byte d[2];
1876 windres_put_16 (wrbfd, d, fd->index);
1877 set_windres_bfd_content (wrbfd, d, off, 2);
1878 if (fd->length)
1879 set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1880 }
1881 off += (rc_uint_type) fd->length + 2;
1882 }
1883
1884 if (wrbfd)
1885 {
1886 bfd_byte d[2];
1887 windres_put_16 (wrbfd, d, c);
1888 set_windres_bfd_content (wrbfd, d, start, 2);
1889 }
1890 return off;
1891 }
1892
1893 /* Convert a group icon resource to binary. */
1894
1895 static rc_uint_type
1896 res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off,
1897 const rc_group_icon *group_icons)
1898 {
1899 rc_uint_type start;
1900 struct bin_group_icon bgi;
1901 int c;
1902 const rc_group_icon *gi;
1903
1904 start = off;
1905 off += BIN_GROUP_ICON_SIZE;
1906
1907 for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1908 {
1909 struct bin_group_icon_item bgii;
1910
1911 if (wrbfd)
1912 {
1913 windres_put_8 (wrbfd, bgii.width, gi->width);
1914 windres_put_8 (wrbfd, bgii.height, gi->height);
1915 windres_put_8 (wrbfd, bgii.colors, gi->colors);
1916 windres_put_8 (wrbfd, bgii.pad, 0);
1917 windres_put_16 (wrbfd, bgii.planes, gi->planes);
1918 windres_put_16 (wrbfd, bgii.bits, gi->bits);
1919 windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1920 windres_put_16 (wrbfd, bgii.index, gi->index);
1921 set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1922 }
1923 off += BIN_GROUP_ICON_ITEM_SIZE;
1924 }
1925
1926 if (wrbfd)
1927 {
1928 windres_put_16 (wrbfd, bgi.sig1, 0);
1929 windres_put_16 (wrbfd, bgi.sig2, 1);
1930 windres_put_16 (wrbfd, bgi.count, c);
1931 set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1932 }
1933 return off;
1934 }
1935
1936 /* Convert a menu resource to binary. */
1937
1938 static rc_uint_type
1939 res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1940 {
1941 int menuex;
1942
1943 menuex = extended_menu (menu);
1944
1945 if (wrbfd)
1946 {
1947 if (! menuex)
1948 {
1949 struct bin_menu bm;
1950 windres_put_16 (wrbfd, bm.sig1, 0);
1951 windres_put_16 (wrbfd, bm.sig2, 0);
1952 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1953 }
1954 else
1955 {
1956 struct bin_menuex bm;
1957 windres_put_16 (wrbfd, bm.sig1, 1);
1958 windres_put_16 (wrbfd, bm.sig2, 4);
1959 windres_put_32 (wrbfd, bm.help, menu->help);
1960 set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1961 }
1962 }
1963 off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1964 if (! menuex)
1965 {
1966 off = res_to_bin_menuitems (wrbfd, off, menu->items);
1967 }
1968 else
1969 {
1970 off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1971 }
1972 return off;
1973 }
1974
1975 /* Convert menu items to binary. */
1976
1977 static rc_uint_type
1978 res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off,
1979 const rc_menuitem *items)
1980 {
1981 const rc_menuitem *mi;
1982
1983 for (mi = items; mi != NULL; mi = mi->next)
1984 {
1985 struct bin_menuitem bmi;
1986 int flags;
1987
1988 flags = mi->type;
1989 if (mi->next == NULL)
1990 flags |= MENUITEM_ENDMENU;
1991 if (mi->popup != NULL)
1992 flags |= MENUITEM_POPUP;
1993
1994 if (wrbfd)
1995 {
1996 windres_put_16 (wrbfd, bmi.flags, flags);
1997 if (mi->popup == NULL)
1998 windres_put_16 (wrbfd, bmi.id, mi->id);
1999 set_windres_bfd_content (wrbfd, &bmi, off,
2000 (mi->popup == NULL
2001 ? BIN_MENUITEM_SIZE
2002 : BIN_MENUITEM_POPUP_SIZE));
2003 }
2004 off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
2005
2006 off = unicode_to_bin (wrbfd, off, mi->text);
2007
2008 if (mi->popup != NULL)
2009 {
2010 off = res_to_bin_menuitems (wrbfd, off, mi->popup);
2011 }
2012 }
2013 return off;
2014 }
2015
2016 /* Convert menuex items to binary. */
2017
2018 static rc_uint_type
2019 res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off,
2020 const rc_menuitem *items)
2021 {
2022 rc_uint_type off_delta = off;
2023 const rc_menuitem *mi;
2024
2025 for (mi = items; mi != NULL; mi = mi->next)
2026 {
2027 struct bin_menuitemex bmi;
2028 int flags;
2029
2030 off += (4 - ((off - off_delta) & 3)) & 3;
2031
2032 flags = 0;
2033 if (mi->next == NULL)
2034 flags |= 0x80;
2035 if (mi->popup != NULL)
2036 flags |= 1;
2037
2038 if (wrbfd)
2039 {
2040 windres_put_32 (wrbfd, bmi.type, mi->type);
2041 windres_put_32 (wrbfd, bmi.state, mi->state);
2042 windres_put_32 (wrbfd, bmi.id, mi->id);
2043 windres_put_16 (wrbfd, bmi.flags, flags);
2044 set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
2045 }
2046 off += BIN_MENUITEMEX_SIZE;
2047
2048 off = unicode_to_bin (wrbfd, off, mi->text);
2049
2050 if (mi->popup != NULL)
2051 {
2052 bfd_byte help[4];
2053
2054 off += (4 - ((off - off_delta) & 3)) & 3;
2055
2056 if (wrbfd)
2057 {
2058 windres_put_32 (wrbfd, help, mi->help);
2059 set_windres_bfd_content (wrbfd, help, off, 4);
2060 }
2061 off += 4;
2062 off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
2063 }
2064 }
2065 return off;
2066 }
2067
2068 /* Convert an rcdata resource to binary. This is also used to convert
2069 other information which happens to be stored in rc_rcdata_item lists
2070 to binary. */
2071
2072 static rc_uint_type
2073 res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off,
2074 const rc_rcdata_item *items)
2075 {
2076 const rc_rcdata_item *ri;
2077
2078 for (ri = items; ri != NULL; ri = ri->next)
2079 {
2080 rc_uint_type len;
2081 switch (ri->type)
2082 {
2083 default:
2084 abort ();
2085 case RCDATA_WORD:
2086 len = 2;
2087 break;
2088 case RCDATA_DWORD:
2089 len = 4;
2090 break;
2091 case RCDATA_STRING:
2092 len = ri->u.string.length;
2093 break;
2094 case RCDATA_WSTRING:
2095 len = ri->u.wstring.length * sizeof (unichar);
2096 break;
2097 case RCDATA_BUFFER:
2098 len = ri->u.buffer.length;
2099 break;
2100 }
2101 if (wrbfd)
2102 {
2103 bfd_byte h[4];
2104 bfd_byte *hp = &h[0];
2105 switch (ri->type)
2106 {
2107 case RCDATA_WORD:
2108 windres_put_16 (wrbfd, hp, ri->u.word);
2109 break;
2110 case RCDATA_DWORD:
2111 windres_put_32 (wrbfd, hp, ri->u.dword);
2112 break;
2113 case RCDATA_STRING:
2114 hp = (bfd_byte *) ri->u.string.s;
2115 break;
2116 case RCDATA_WSTRING:
2117 {
2118 rc_uint_type i;
2119
2120 hp = reswr_alloc (len);
2121 for (i = 0; i < ri->u.wstring.length; i++)
2122 windres_put_16 (wrbfd, hp + i * sizeof (unichar),
2123 ri->u.wstring.w[i]);
2124 }
2125 break;
2126 case RCDATA_BUFFER:
2127 hp = (bfd_byte *) ri->u.buffer.data;
2128 break;
2129 }
2130 set_windres_bfd_content (wrbfd, hp, off, len);
2131 }
2132 off += len;
2133 }
2134 return off;
2135 }
2136
2137 /* Convert a stringtable resource to binary. */
2138
2139 static rc_uint_type
2140 res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
2141 const rc_stringtable *st)
2142 {
2143 int i;
2144
2145 for (i = 0; i < 16; i++)
2146 {
2147 rc_uint_type slen, length;
2148 unichar *s;
2149
2150 slen = (rc_uint_type) st->strings[i].length;
2151 if (slen == 0xffffffff) slen = 0;
2152 s = st->strings[i].string;
2153
2154 length = 2 + slen * 2;
2155 if (wrbfd)
2156 {
2157 bfd_byte *hp;
2158 rc_uint_type j;
2159
2160 hp = reswr_alloc (length);
2161 windres_put_16 (wrbfd, hp, slen);
2162
2163 for (j = 0; j < slen; j++)
2164 windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
2165 set_windres_bfd_content (wrbfd, hp, off, length);
2166 }
2167 off += length;
2168 }
2169 return off;
2170 }
2171
2172 /* Convert an ASCII string to a unicode binary string. This always
2173 returns exactly one bindata structure. */
2174
2175 static rc_uint_type
2176 string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
2177 {
2178 rc_uint_type len;
2179
2180 len = (rc_uint_type) strlen (s);
2181
2182 if (wrbfd)
2183 {
2184 rc_uint_type i;
2185 bfd_byte *hp;
2186
2187 hp = reswr_alloc ((len + 1) * sizeof (unichar));
2188
2189 for (i = 0; i < len; i++)
2190 windres_put_16 (wrbfd, hp + i * 2, s[i]);
2191 windres_put_16 (wrbfd, hp + i * 2, 0);
2192 set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
2193 }
2194 off += (rc_uint_type) ((len + 1) * sizeof (unichar));
2195 return off;
2196 }
2197
2198 static rc_uint_type
2199 res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
2200 {
2201 if (wrbfd)
2202 {
2203 struct bin_toolbar bt;
2204 windres_put_32 (wrbfd, bt.button_width, tb->button_width);
2205 windres_put_32 (wrbfd, bt.button_height, tb->button_height);
2206 windres_put_32 (wrbfd, bt.nitems, tb->nitems);
2207 set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
2208 if (tb->nitems > 0)
2209 {
2210 rc_toolbar_item *it;
2211 bfd_byte *ids;
2212 rc_uint_type i = 0;
2213
2214 ids = reswr_alloc (tb->nitems * 4);
2215 it=tb->items;
2216 while(it != NULL)
2217 {
2218 windres_put_32 (wrbfd, ids + i, it->id.u.id);
2219 i += 4;
2220 it = it->next;
2221 }
2222 set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
2223 }
2224 }
2225 off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
2226
2227 return off;
2228 }
2229
2230 /* Convert a versioninfo resource to binary. */
2231
2232 static rc_uint_type
2233 res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
2234 const rc_versioninfo *versioninfo)
2235 {
2236 rc_uint_type off_delta = off;
2237 rc_uint_type start;
2238 struct bin_versioninfo bvi;
2239 rc_ver_info *vi;
2240
2241 start = off;
2242 off += BIN_VERSIONINFO_SIZE;
2243 off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
2244 off += (4 - ((off - off_delta) & 3)) & 3;
2245
2246 if (versioninfo->fixed != NULL)
2247 {
2248 if (wrbfd)
2249 {
2250 struct bin_fixed_versioninfo bfv;
2251 const rc_fixed_versioninfo *fi;
2252
2253 fi = versioninfo->fixed;
2254 windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
2255 windres_put_32 (wrbfd, bfv.sig2, 0x10000);
2256 windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
2257 windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
2258 windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
2259 windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
2260 windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
2261 windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
2262 windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
2263 windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
2264 windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
2265 windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
2266 windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
2267 set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
2268 }
2269 off += BIN_FIXED_VERSIONINFO_SIZE;
2270 }
2271
2272 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2273 {
2274 struct bin_ver_info bv;
2275 rc_uint_type bv_off;
2276
2277 off += (4 - ((off - off_delta) & 3)) & 3;
2278
2279 bv_off = off;
2280
2281 off += BIN_VER_INFO_SIZE;
2282
2283 switch (vi->type)
2284 {
2285 default:
2286 abort ();
2287 case VERINFO_STRING:
2288 {
2289 const rc_ver_stringtable *vst;
2290
2291 off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2292
2293 if (!vi->u.string.stringtables)
2294 off += (4 - ((off - off_delta) & 3)) & 3;
2295
2296 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
2297 {
2298 struct bin_ver_info bvst;
2299 rc_uint_type vst_off;
2300 const rc_ver_stringinfo *vs;
2301
2302 off += (4 - ((off - off_delta) & 3)) & 3;
2303
2304 vst_off = off;
2305 off += BIN_VER_INFO_SIZE;
2306
2307 off = unicode_to_bin (wrbfd, off, vst->language);
2308
2309 for (vs = vst->strings; vs != NULL; vs = vs->next)
2310 {
2311 struct bin_ver_info bvs;
2312 rc_uint_type vs_off, str_off;
2313
2314 off += (4 - ((off - off_delta) & 3)) & 3;
2315
2316 vs_off = off;
2317 off += BIN_VER_INFO_SIZE;
2318
2319 off = unicode_to_bin (wrbfd, off, vs->key);
2320
2321 off += (4 - ((off - off_delta) & 3)) & 3;
2322
2323 str_off = off;
2324 off = unicode_to_bin (wrbfd, off, vs->value);
2325
2326 if (wrbfd)
2327 {
2328 windres_put_16 (wrbfd, bvs.size, off - vs_off);
2329 windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
2330 windres_put_16 (wrbfd, bvs.sig2, 1);
2331 set_windres_bfd_content (wrbfd, &bvs, vs_off,
2332 BIN_VER_INFO_SIZE);
2333 }
2334 }
2335
2336 if (wrbfd)
2337 {
2338 windres_put_16 (wrbfd, bvst.size, off - vst_off);
2339 windres_put_16 (wrbfd, bvst.sig1, 0);
2340 windres_put_16 (wrbfd, bvst.sig2, 1);
2341 set_windres_bfd_content (wrbfd, &bvst, vst_off,
2342 BIN_VER_INFO_SIZE);
2343 }
2344 }
2345 break;
2346 }
2347
2348 case VERINFO_VAR:
2349 {
2350 rc_uint_type vvd_off, vvvd_off;
2351 struct bin_ver_info bvvd;
2352 const rc_ver_varinfo *vv;
2353
2354 off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2355
2356 off += (4 - ((off - off_delta) & 3)) & 3;
2357
2358 vvd_off = off;
2359 off += BIN_VER_INFO_SIZE;
2360
2361 off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2362
2363 off += (4 - ((off - off_delta) & 3)) & 3;
2364
2365 vvvd_off = off;
2366
2367 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2368 {
2369 if (wrbfd)
2370 {
2371 bfd_byte vvsd[4];
2372
2373 windres_put_16 (wrbfd, &vvsd[0], vv->language);
2374 windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2375 set_windres_bfd_content (wrbfd, vvsd, off, 4);
2376 }
2377 off += 4;
2378 }
2379 if (wrbfd)
2380 {
2381 windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2382 windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2383 windres_put_16 (wrbfd, bvvd.sig2, 0);
2384 set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2385 BIN_VER_INFO_SIZE);
2386 }
2387
2388 break;
2389 }
2390 }
2391
2392 if (wrbfd)
2393 {
2394 windres_put_16 (wrbfd, bv.size, off - bv_off);
2395 windres_put_16 (wrbfd, bv.sig1, 0);
2396 windres_put_16 (wrbfd, bv.sig2, 1);
2397 set_windres_bfd_content (wrbfd, &bv, bv_off,
2398 BIN_VER_INFO_SIZE);
2399 }
2400 }
2401
2402 if (wrbfd)
2403 {
2404 windres_put_16 (wrbfd, bvi.size, off - start);
2405 windres_put_16 (wrbfd, bvi.fixed_size,
2406 versioninfo->fixed == NULL ? 0
2407 : BIN_FIXED_VERSIONINFO_SIZE);
2408 windres_put_16 (wrbfd, bvi.sig2, 0);
2409 set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2410 }
2411 return off;
2412 }
2413
2414 /* Convert a generic resource to binary. */
2415
2416 static rc_uint_type
2417 res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2418 const bfd_byte *data)
2419 {
2420 if (wrbfd && length != 0)
2421 set_windres_bfd_content (wrbfd, data, off, length);
2422 return off + (rc_uint_type) length;
2423 }
2424