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