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