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