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