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