1/* resbin.c -- manipulate the Windows binary resource format.
2   Copyright (C) 1997-2020 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	  if (length < off + datalen)
578	    toosmall (_("dialog control data"));
579
580	  dc->data = ((rc_rcdata_item *)
581		      res_alloc (sizeof (rc_rcdata_item)));
582	  dc->data->next = NULL;
583	  dc->data->type = RCDATA_BUFFER;
584	  dc->data->u.buffer.length = datalen;
585	  dc->data->u.buffer.data = data + off;
586
587	  off += datalen;
588	}
589
590      dc->next = NULL;
591      *pp = dc;
592      pp = &dc->next;
593    }
594
595  r = (rc_res_resource *) res_alloc (sizeof *r);
596  r->type = RES_TYPE_DIALOG;
597  r->u.dialog = d;
598
599  return r;
600}
601
602/* Convert a stringtable resource from binary.  */
603
604static rc_res_resource *
605bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
606{
607  rc_stringtable *st;
608  int i;
609  rc_res_resource *r;
610
611  st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
612
613  for (i = 0; i < 16; i++)
614    {
615      unsigned int slen;
616
617      if (length < 2)
618	toosmall (_("stringtable string length"));
619      slen = windres_get_16 (wrbfd, data, 2);
620      st->strings[i].length = slen;
621
622      if (slen > 0)
623	{
624	  unichar *s;
625	  unsigned int j;
626
627	  if (length < 2 + 2 * slen)
628	    toosmall (_("stringtable string"));
629
630	  s = (unichar *) res_alloc (slen * sizeof (unichar));
631	  st->strings[i].string = s;
632
633	  for (j = 0; j < slen; j++)
634	    s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
635	}
636
637      data += 2 + 2 * slen;
638      length -= 2 + 2 * slen;
639    }
640
641  r = (rc_res_resource *) res_alloc (sizeof *r);
642  r->type = RES_TYPE_STRINGTABLE;
643  r->u.stringtable = st;
644
645  return r;
646}
647
648/* Convert a fontdir resource from binary.  */
649
650static rc_res_resource *
651bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
652{
653  rc_uint_type c, i;
654  rc_fontdir *first, **pp;
655  rc_res_resource *r;
656
657  if (length < 2)
658    toosmall (_("fontdir header"));
659
660  c = windres_get_16 (wrbfd, data, 2);
661
662  first = NULL;
663  pp = &first;
664
665  for (i = 0; i < c; i++)
666    {
667      const struct bin_fontdir_item *bfi;
668      rc_fontdir *fd;
669      unsigned int off;
670
671      if (length < 56)
672	toosmall (_("fontdir"));
673
674      bfi = (const struct bin_fontdir_item *) data;
675      fd = (rc_fontdir *) res_alloc (sizeof *fd);
676      fd->index = windres_get_16 (wrbfd, bfi->index, 2);
677
678      /* To work out the length of the fontdir data, we must get the
679         length of the device name and face name strings, even though
680         we don't store them in the rc_fontdir.  The
681         documentation says that these are NULL terminated char
682         strings, not Unicode strings.  */
683
684      off = 56;
685
686      while (off < length && data[off] != '\0')
687	++off;
688      if (off >= length)
689	toosmall (_("fontdir device name"));
690      ++off;
691
692      while (off < length && data[off] != '\0')
693	++off;
694      if (off >= length)
695	toosmall (_("fontdir face name"));
696      ++off;
697
698      fd->length = off;
699      fd->data = data;
700
701      fd->next = NULL;
702      *pp = fd;
703      pp = &fd->next;
704
705      /* The documentation does not indicate that any rounding is
706         required.  */
707
708      data += off;
709      length -= off;
710    }
711
712  r = (rc_res_resource *) res_alloc (sizeof *r);
713  r->type = RES_TYPE_FONTDIR;
714  r->u.fontdir = first;
715
716  return r;
717}
718
719/* Convert an accelerators resource from binary.  */
720
721static rc_res_resource *
722bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
723{
724  rc_accelerator *first, **pp;
725  rc_res_resource *r;
726
727  first = NULL;
728  pp = &first;
729
730  while (1)
731    {
732      rc_accelerator *a;
733
734      if (length < 8)
735	toosmall (_("accelerator"));
736
737      a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
738
739      a->flags = windres_get_16 (wrbfd, data, 2);
740      a->key = windres_get_16 (wrbfd, data + 2, 2);
741      a->id = windres_get_16 (wrbfd, data + 4, 2);
742
743      a->next = NULL;
744      *pp = a;
745      pp = &a->next;
746
747      if ((a->flags & ACC_LAST) != 0)
748	break;
749
750      data += 8;
751      length -= 8;
752    }
753
754  r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
755  r->type = RES_TYPE_ACCELERATOR;
756  r->u.acc = first;
757
758  return r;
759}
760
761/* Convert an rcdata resource from binary.  */
762
763static rc_res_resource *
764bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
765		   rc_uint_type length, int rctyp)
766{
767  rc_rcdata_item *ri;
768  rc_res_resource *r;
769
770  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
771
772  ri->next = NULL;
773  ri->type = RCDATA_BUFFER;
774  ri->u.buffer.length = length;
775  ri->u.buffer.data = data;
776
777  r = (rc_res_resource *) res_alloc (sizeof *r);
778  r->type = rctyp;
779  r->u.rcdata = ri;
780
781  return r;
782}
783
784/* Convert a group cursor resource from binary.  */
785
786static rc_res_resource *
787bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
788{
789  int type, c, i;
790  rc_group_cursor *first, **pp;
791  rc_res_resource *r;
792
793  if (length < 6)
794    toosmall (_("group cursor header"));
795
796  type = windres_get_16 (wrbfd, data + 2, 2);
797  if (type != 2)
798    fatal (_("unexpected group cursor type %d"), type);
799
800  c = windres_get_16 (wrbfd, data + 4, 2);
801
802  data += 6;
803  length -= 6;
804
805  first = NULL;
806  pp = &first;
807
808  for (i = 0; i < c; i++)
809    {
810      rc_group_cursor *gc;
811
812      if (length < 14)
813	toosmall (_("group cursor"));
814
815      gc = (rc_group_cursor *) res_alloc (sizeof *gc);
816
817      gc->width = windres_get_16 (wrbfd, data, 2);
818      gc->height = windres_get_16 (wrbfd, data + 2, 2);
819      gc->planes = windres_get_16 (wrbfd, data + 4, 2);
820      gc->bits = windres_get_16 (wrbfd, data + 6, 2);
821      gc->bytes = windres_get_32 (wrbfd, data + 8, 4);
822      gc->index = windres_get_16 (wrbfd, data + 12, 2);
823
824      gc->next = NULL;
825      *pp = gc;
826      pp = &gc->next;
827
828      data += 14;
829      length -= 14;
830    }
831
832  r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
833  r->type = RES_TYPE_GROUP_CURSOR;
834  r->u.group_cursor = first;
835
836  return r;
837}
838
839/* Convert a group icon resource from binary.  */
840
841static rc_res_resource *
842bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
843{
844  int type, c, i;
845  rc_group_icon *first, **pp;
846  rc_res_resource *r;
847
848  if (length < 6)
849    toosmall (_("group icon header"));
850
851  type = windres_get_16 (wrbfd, data + 2, 2);
852  if (type != 1)
853    fatal (_("unexpected group icon type %d"), type);
854
855  c = windres_get_16 (wrbfd, data + 4, 2);
856
857  data += 6;
858  length -= 6;
859
860  first = NULL;
861  pp = &first;
862
863  for (i = 0; i < c; i++)
864    {
865      rc_group_icon *gi;
866
867      if (length < 14)
868	toosmall (_("group icon"));
869
870      gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
871
872      gi->width = windres_get_8 (wrbfd, data, 1);
873      gi->height = windres_get_8 (wrbfd, data + 1, 1);
874      gi->colors = windres_get_8 (wrbfd, data + 2, 1);
875      gi->planes = windres_get_16 (wrbfd, data + 4, 2);
876      gi->bits = windres_get_16 (wrbfd, data + 6, 2);
877      gi->bytes = windres_get_32 (wrbfd, data + 8, 4);
878      gi->index = windres_get_16 (wrbfd, data + 12, 2);
879
880      gi->next = NULL;
881      *pp = gi;
882      pp = &gi->next;
883
884      data += 14;
885      length -= 14;
886    }
887
888  r = (rc_res_resource *) res_alloc (sizeof *r);
889  r->type = RES_TYPE_GROUP_ICON;
890  r->u.group_icon = first;
891
892  return r;
893}
894
895/* Extract data from a version header.  If KEY is not NULL, then the
896   key must be KEY; otherwise, the key is returned in *PKEY.  This
897   sets *LEN to the total length, *VALLEN to the value length, *TYPE
898   to the type, and *OFF to the offset to the children.  */
899
900static void
901get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
902		    const char *key, unichar **pkey,
903		    rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
904		    rc_uint_type *off)
905{
906  if (length < 8)
907    toosmall (key);
908
909  *len = (windres_get_16 (wrbfd, data, 2) + 3) & ~3;
910  *vallen = windres_get_16 (wrbfd, data + 2, 2);
911  *type = windres_get_16 (wrbfd, data + 4, 2);
912
913  *off = 6;
914
915  length -= 6;
916  data += 6;
917
918  if (key == NULL)
919    {
920      rc_uint_type sublen;
921
922      *pkey = get_unicode (wrbfd, data, length, &sublen);
923      *off += (sublen + 1) * sizeof (unichar);
924    }
925  else
926    {
927      while (1)
928	{
929	  if (length < 2)
930	    toosmall (key);
931	  if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
932	    fatal (_("unexpected version string"));
933
934	  *off += 2;
935	  length -= 2;
936	  data += 2;
937
938	  if (*key == '\0')
939	    break;
940
941	  ++key;
942	}
943    }
944
945  *off = (*off + 3) &~ 3;
946}
947
948/* Convert a version resource from binary.  */
949
950static rc_res_resource *
951bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
952{
953  rc_uint_type verlen, vallen, type, off;
954  rc_fixed_versioninfo *fi;
955  rc_ver_info *first, **pp;
956  rc_versioninfo *v;
957  rc_res_resource *r;
958
959  get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
960		      (unichar **) NULL, &verlen, &vallen, &type, &off);
961
962  /* PR 17512: The verlen field does not include padding length.  */
963  if (verlen > length)
964    fatal (_("version length %lu greater than resource length %lu"),
965	   (unsigned long) verlen, (unsigned long) length);
966
967  if (type != 0)
968    fatal (_("unexpected version type %d"), (int) type);
969
970  data += off;
971  length -= off;
972
973  if (vallen == 0)
974    fi = NULL;
975  else
976    {
977      unsigned long signature, fiv;
978
979      if (vallen != 52)
980	fatal (_("unexpected fixed version information length %ld"), (long) vallen);
981
982      if (length < 52)
983	toosmall (_("fixed version info"));
984
985      signature = windres_get_32 (wrbfd, data, 4);
986      if (signature != 0xfeef04bd)
987	fatal (_("unexpected fixed version signature %lu"), signature);
988
989      fiv = windres_get_32 (wrbfd, data + 4, 4);
990      if (fiv != 0 && fiv != 0x10000)
991	fatal (_("unexpected fixed version info version %lu"), fiv);
992
993      fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
994
995      fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
996      fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
997      fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
998      fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
999      fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1000      fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1001      fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1002      fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1003      fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1004      fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1005      fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
1006
1007      data += 52;
1008      length -= 52;
1009    }
1010
1011  first = NULL;
1012  pp = &first;
1013
1014  while (length > 0)
1015    {
1016      rc_ver_info *vi;
1017      int ch;
1018
1019      if (length < 8)
1020	toosmall (_("version var info"));
1021
1022      vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1023
1024      ch = windres_get_16 (wrbfd, data + 6, 2);
1025
1026      if (ch == 'S')
1027	{
1028	  rc_ver_stringtable **ppvst;
1029
1030	  vi->type = VERINFO_STRING;
1031
1032	  get_version_header (wrbfd, data, length, "StringFileInfo",
1033			      (unichar **) NULL, &verlen, &vallen, &type,
1034			      &off);
1035
1036	  if (vallen != 0)
1037	    fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1038
1039	  data += off;
1040	  length -= off;
1041
1042	  verlen -= off;
1043
1044	  vi->u.string.stringtables = NULL;
1045	  ppvst = &vi->u.string.stringtables;
1046
1047	  while (verlen > 0)
1048	    {
1049	      rc_ver_stringtable *vst;
1050	      rc_uint_type stverlen;
1051	      rc_ver_stringinfo **ppvs;
1052
1053	      if (length < 8)
1054		toosmall (_("version stringtable"));
1055
1056	      vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1057
1058	      get_version_header (wrbfd, data, length, (const char *) NULL,
1059				  &vst->language, &stverlen, &vallen, &type, &off);
1060
1061	      if (vallen != 0)
1062		fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1063
1064	      data += off;
1065	      length -= off;
1066	      verlen -= off;
1067
1068	  stverlen -= off;
1069
1070	  vst->strings = NULL;
1071	  ppvs = &vst->strings;
1072
1073	  while (stverlen > 0)
1074	    {
1075	      rc_ver_stringinfo *vs;
1076	      rc_uint_type sverlen, vslen, valoff;
1077
1078	      if (length < 8)
1079		toosmall (_("version string"));
1080
1081	      vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1082
1083	      get_version_header (wrbfd, data, length, (const char *) NULL,
1084				  &vs->key, &sverlen, &vallen, &type, &off);
1085
1086	      data += off;
1087	      length -= off;
1088
1089	      vs->value = get_unicode (wrbfd, data, length, &vslen);
1090	      valoff = vslen * 2 + 2;
1091	      valoff = (valoff + 3) & ~3;
1092
1093	      if (off + valoff != sverlen)
1094		fatal (_("unexpected version string length %ld != %ld + %ld"),
1095		       (long) sverlen, (long) off, (long) valoff);
1096
1097	      data += valoff;
1098	      length -= valoff;
1099
1100	      if (stverlen < sverlen)
1101		fatal (_("unexpected version string length %ld < %ld"),
1102		       (long) verlen, (long) sverlen);
1103	      stverlen -= sverlen;
1104	      verlen -= sverlen;
1105
1106	      vs->next = NULL;
1107	      *ppvs = vs;
1108	      ppvs = &vs->next;
1109	    }
1110
1111	  vst->next = NULL;
1112	  *ppvst = vst;
1113	  ppvst = &vst->next;
1114	    }
1115	}
1116      else if (ch == 'V')
1117	{
1118	  rc_ver_varinfo **ppvv;
1119
1120	  vi->type = VERINFO_VAR;
1121
1122	  get_version_header (wrbfd, data, length, "VarFileInfo",
1123			      (unichar **) NULL, &verlen, &vallen, &type,
1124			      &off);
1125
1126	  if (vallen != 0)
1127	    fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1128
1129	  data += off;
1130	  length -= off;
1131
1132	  get_version_header (wrbfd, data, length, (const char *) NULL,
1133			      &vi->u.var.key, &verlen, &vallen, &type, &off);
1134
1135	  data += off;
1136	  length -= off;
1137
1138	  vi->u.var.var = NULL;
1139	  ppvv = &vi->u.var.var;
1140
1141	  while (vallen > 0)
1142	    {
1143	      rc_ver_varinfo *vv;
1144
1145	      if (length < 4)
1146		toosmall (_("version varfileinfo"));
1147
1148	      vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1149
1150	      vv->language = windres_get_16 (wrbfd, data, 2);
1151	      vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1152
1153	      vv->next = NULL;
1154	      *ppvv = vv;
1155	      ppvv = &vv->next;
1156
1157	      data += 4;
1158	      length -= 4;
1159
1160	      if (vallen < 4)
1161		fatal (_("unexpected version value length %ld"), (long) vallen);
1162
1163	      vallen -= 4;
1164	    }
1165	}
1166      else if (ch == 0)
1167	{
1168	  if (length == 8)
1169	    /* Padding - skip.  */
1170	    break;
1171	  fatal (_("nul bytes found in version string"));
1172	}
1173      else
1174	fatal (_("unexpected version string character: %x"), ch);
1175
1176      vi->next = NULL;
1177      *pp = vi;
1178      pp = &vi->next;
1179    }
1180
1181  v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1182  v->fixed = fi;
1183  v->var = first;
1184
1185  r = (rc_res_resource *) res_alloc (sizeof *r);
1186  r->type = RES_TYPE_VERSIONINFO;
1187  r->u.versioninfo = v;
1188
1189  return r;
1190}
1191
1192/* Convert an arbitrary user defined resource from binary.  */
1193
1194static rc_res_resource *
1195bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1196		     rc_uint_type length)
1197{
1198  rc_rcdata_item *ri;
1199  rc_res_resource *r;
1200
1201  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1202
1203  ri->next = NULL;
1204  ri->type = RCDATA_BUFFER;
1205  ri->u.buffer.length = length;
1206  ri->u.buffer.data = data;
1207
1208  r = (rc_res_resource *) res_alloc (sizeof *r);
1209  r->type = RES_TYPE_USERDATA;
1210  r->u.rcdata = ri;
1211
1212  return r;
1213}
1214
1215static rc_res_resource *
1216bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1217{
1218  rc_toolbar *ri;
1219  rc_res_resource *r;
1220  rc_uint_type i;
1221
1222  ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1223  ri->button_width = windres_get_32 (wrbfd, data, 4);
1224  ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1225  ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1226  ri->items = NULL;
1227
1228  data += 12;
1229  length -= 12;
1230  for (i=0 ; i < ri->nitems; i++)
1231  {
1232    rc_toolbar_item *it;
1233    it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1234    it->id.named = 0;
1235    it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1236    it->prev = it->next = NULL;
1237    data += 4;
1238    length -= 4;
1239    if(ri->items) {
1240      rc_toolbar_item *ii = ri->items;
1241      while (ii->next != NULL)
1242	ii = ii->next;
1243      it->prev = ii;
1244      ii->next = it;
1245    }
1246    else
1247      ri->items = it;
1248  }
1249  r = (rc_res_resource *) res_alloc (sizeof *r);
1250  r->type = RES_TYPE_TOOLBAR;
1251  r->u.toolbar = ri;
1252  return r;
1253}
1254
1255
1256/* Local functions used to convert resources to binary format.  */
1257
1258static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1259static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1260static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1261static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1262static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1263static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1264static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1265static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1266static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1267static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1268static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1269static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1270static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1271static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1272static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1273static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1274static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1275					const bfd_byte *);
1276
1277/* Convert a resource to binary.  */
1278
1279rc_uint_type
1280res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1281{
1282  switch (res->type)
1283    {
1284    case RES_TYPE_BITMAP:
1285    case RES_TYPE_FONT:
1286    case RES_TYPE_ICON:
1287    case RES_TYPE_MESSAGETABLE:
1288      return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1289    case RES_TYPE_ACCELERATOR:
1290      return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1291    case RES_TYPE_CURSOR:
1292      return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1293    case RES_TYPE_GROUP_CURSOR:
1294      return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1295    case RES_TYPE_DIALOG:
1296      return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1297    case RES_TYPE_FONTDIR:
1298      return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1299    case RES_TYPE_GROUP_ICON:
1300      return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1301    case RES_TYPE_MENU:
1302      return res_to_bin_menu (wrbfd, off, res->u.menu);
1303    case RES_TYPE_STRINGTABLE:
1304      return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1305    case RES_TYPE_VERSIONINFO:
1306      return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1307    case RES_TYPE_TOOLBAR:
1308      return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1309    case RES_TYPE_USERDATA:
1310    case RES_TYPE_RCDATA:
1311    default:
1312      return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1313    }
1314}
1315
1316/* Convert a resource ID to binary.  This always returns exactly one
1317   bindata structure.  */
1318
1319static rc_uint_type
1320resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1321{
1322  if (! id.named)
1323    {
1324      if (wrbfd)
1325	{
1326	  struct bin_res_id bri;
1327
1328	  windres_put_16 (wrbfd, bri.sig, 0xffff);
1329	  windres_put_16 (wrbfd, bri.id, id.u.id);
1330	  set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1331	}
1332      off += BIN_RES_ID;
1333    }
1334  else
1335    {
1336      rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1337      if (wrbfd)
1338	{
1339	  bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1340	  rc_uint_type i;
1341	  for (i = 0; i < len; i++)
1342	    windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1343	  windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1344	  set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1345    }
1346      off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1347    }
1348  return off;
1349}
1350
1351/* Convert a null terminated unicode string to binary.  This always
1352   returns exactly one bindata structure.  */
1353
1354static rc_uint_type
1355unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1356{
1357  rc_uint_type len = 0;
1358
1359  if (str != NULL)
1360    len = unichar_len (str);
1361
1362  if (wrbfd)
1363    {
1364      bfd_byte *d;
1365      rc_uint_type i;
1366      d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1367      for (i = 0; i < len; i++)
1368	windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1369      windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1370      set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1371    }
1372  off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1373
1374  return off;
1375}
1376
1377/* Convert an accelerator resource to binary.  */
1378
1379static rc_uint_type
1380res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1381			const rc_accelerator *accelerators)
1382{
1383  const rc_accelerator *a;
1384
1385  for (a = accelerators; a != NULL; a = a->next)
1386    {
1387      if (wrbfd)
1388	{
1389	  struct bin_accelerator ba;
1390
1391	  windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1392	  windres_put_16 (wrbfd, ba.key, a->key);
1393	  windres_put_16 (wrbfd, ba.id, a->id);
1394	  windres_put_16 (wrbfd, ba.pad, 0);
1395	  set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1396    }
1397      off += BIN_ACCELERATOR_SIZE;
1398    }
1399  return off;
1400}
1401
1402/* Convert a cursor resource to binary.  */
1403
1404static rc_uint_type
1405res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1406{
1407  if (wrbfd)
1408    {
1409      struct bin_cursor bc;
1410
1411      windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1412      windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1413      set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1414      if (c->length)
1415	set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1416    }
1417  off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1418  return off;
1419}
1420
1421/* Convert a group cursor resource to binary.  */
1422
1423static rc_uint_type
1424res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1425			 const rc_group_cursor *group_cursors)
1426{
1427  int c = 0;
1428  const rc_group_cursor *gc;
1429  struct bin_group_cursor bgc;
1430  struct bin_group_cursor_item bgci;
1431  rc_uint_type start = off;
1432
1433  off += BIN_GROUP_CURSOR_SIZE;
1434
1435  for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1436    {
1437      if (wrbfd)
1438	{
1439	  windres_put_16 (wrbfd, bgci.width, gc->width);
1440	  windres_put_16 (wrbfd, bgci.height, gc->height);
1441	  windres_put_16 (wrbfd, bgci.planes, gc->planes);
1442	  windres_put_16 (wrbfd, bgci.bits, gc->bits);
1443	  windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1444	  windres_put_16 (wrbfd, bgci.index, gc->index);
1445	  set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1446    }
1447
1448      off += BIN_GROUP_CURSOR_ITEM_SIZE;
1449    }
1450  if (wrbfd)
1451    {
1452      windres_put_16 (wrbfd, bgc.sig1, 0);
1453      windres_put_16 (wrbfd, bgc.sig2, 2);
1454      windres_put_16 (wrbfd, bgc.nitems, c);
1455      set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1456    }
1457  return off;
1458}
1459
1460/* Convert a dialog resource to binary.  */
1461
1462static rc_uint_type
1463res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1464{
1465  rc_uint_type off_delta;
1466  rc_uint_type start, marker;
1467  int dialogex;
1468  int c;
1469  rc_dialog_control *dc;
1470  struct bin_dialogex bdx;
1471  struct bin_dialog bd;
1472
1473  off_delta = off;
1474  start = off;
1475  dialogex = extended_dialog (dialog);
1476
1477  if (wrbfd)
1478    {
1479  if (! dialogex)
1480    {
1481	  windres_put_32 (wrbfd, bd.style, dialog->style);
1482	  windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1483	  windres_put_16 (wrbfd, bd.x, dialog->x);
1484	  windres_put_16 (wrbfd, bd.y, dialog->y);
1485	  windres_put_16 (wrbfd, bd.width, dialog->width);
1486	  windres_put_16 (wrbfd, bd.height, dialog->height);
1487    }
1488  else
1489    {
1490	  windres_put_16 (wrbfd, bdx.sig1, 1);
1491	  windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1492	  windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1493	  windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1494	  windres_put_32 (wrbfd, bdx.style, dialog->style);
1495	  windres_put_16 (wrbfd, bdx.x, dialog->x);
1496	  windres_put_16 (wrbfd, bdx.y, dialog->y);
1497	  windres_put_16 (wrbfd, bdx.width, dialog->width);
1498	  windres_put_16 (wrbfd, bdx.height, dialog->height);
1499	}
1500    }
1501
1502  off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1503
1504  off = resid_to_bin (wrbfd, off, dialog->menu);
1505  off = resid_to_bin (wrbfd, off, dialog->class);
1506  off = unicode_to_bin (wrbfd, off, dialog->caption);
1507
1508  if ((dialog->style & DS_SETFONT) != 0)
1509    {
1510      if (wrbfd)
1511	{
1512	  if (! dialogex)
1513	    {
1514	      struct bin_dialogfont bdf;
1515	      windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1516	      set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1517	    }
1518	  else
1519	    {
1520	      struct bin_dialogexfont bdxf;
1521	      windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1522	      windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1523	      windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1524	      windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1525	      set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1526	    }
1527	}
1528      off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1529      off = unicode_to_bin (wrbfd, off, dialog->font);
1530    }
1531  for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1532    {
1533      bfd_byte dc_rclen[2];
1534
1535      off += (4 - ((off - off_delta) & 3)) & 3;
1536      if (wrbfd)
1537	{
1538      if (! dialogex)
1539	{
1540	      struct bin_dialog_control bdc;
1541
1542	      windres_put_32 (wrbfd, bdc.style, dc->style);
1543	      windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1544	      windres_put_16 (wrbfd, bdc.x, dc->x);
1545	      windres_put_16 (wrbfd, bdc.y, dc->y);
1546	      windres_put_16 (wrbfd, bdc.width, dc->width);
1547	      windres_put_16 (wrbfd, bdc.height, dc->height);
1548	      windres_put_16 (wrbfd, bdc.id, dc->id);
1549	      set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1550	}
1551      else
1552	{
1553	      struct bin_dialogex_control bdc;
1554
1555	      windres_put_32 (wrbfd, bdc.help, dc->help);
1556	      windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1557	      windres_put_32 (wrbfd, bdc.style, dc->style);
1558	      windres_put_16 (wrbfd, bdc.x, dc->x);
1559	      windres_put_16 (wrbfd, bdc.y, dc->y);
1560	      windres_put_16 (wrbfd, bdc.width, dc->width);
1561	      windres_put_16 (wrbfd, bdc.height, dc->height);
1562	      windres_put_32 (wrbfd, bdc.id, dc->id);
1563	      set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1564	    }
1565	}
1566      off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1567
1568      off = resid_to_bin (wrbfd, off, dc->class);
1569      off = resid_to_bin (wrbfd, off, dc->text);
1570
1571      marker = off; /* Save two bytes for size of optional data.  */
1572      off += 2;
1573
1574      if (dc->data == NULL)
1575        {
1576	  if (wrbfd)
1577	    windres_put_16 (wrbfd, dc_rclen, 0);
1578	}
1579      else
1580	{
1581	  rc_uint_type saved_off = off;
1582	  rc_uint_type old_off;
1583
1584	  old_off = off;
1585	  off = res_to_bin_rcdata (wrbfd, off, dc->data);
1586	  if ((off - old_off) == 0)
1587	    old_off = off = saved_off;
1588	  if (wrbfd)
1589	    windres_put_16 (wrbfd, dc_rclen, off - old_off);
1590	}
1591      if (wrbfd)
1592	set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1593    }
1594
1595  if (wrbfd)
1596    {
1597      windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1598      if (! dialogex)
1599	set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1600      else
1601	set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1602    }
1603
1604  return off;
1605}
1606
1607/* Convert a fontdir resource to binary.  */
1608static rc_uint_type
1609res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
1610{
1611  rc_uint_type start;
1612  int c;
1613  const rc_fontdir *fd;
1614
1615  start = off;
1616  off += 2;
1617
1618  for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1619    {
1620      if (wrbfd)
1621	{
1622	  bfd_byte d[2];
1623	  windres_put_16 (wrbfd, d, fd->index);
1624	  set_windres_bfd_content (wrbfd, d, off, 2);
1625	  if (fd->length)
1626	    set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1627	}
1628      off += (rc_uint_type) fd->length + 2;
1629    }
1630
1631  if (wrbfd)
1632    {
1633      bfd_byte d[2];
1634      windres_put_16 (wrbfd, d, c);
1635      set_windres_bfd_content (wrbfd, d, start, 2);
1636    }
1637  return off;
1638}
1639
1640/* Convert a group icon resource to binary.  */
1641
1642static rc_uint_type
1643res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1644{
1645  rc_uint_type start;
1646  struct bin_group_icon bgi;
1647  int c;
1648  const rc_group_icon *gi;
1649
1650  start = off;
1651  off += BIN_GROUP_ICON_SIZE;
1652
1653  for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1654    {
1655      struct bin_group_icon_item bgii;
1656
1657      if (wrbfd)
1658	{
1659	  windres_put_8 (wrbfd, bgii.width, gi->width);
1660	  windres_put_8 (wrbfd, bgii.height, gi->height);
1661	  windres_put_8 (wrbfd, bgii.colors, gi->colors);
1662	  windres_put_8 (wrbfd, bgii.pad, 0);
1663	  windres_put_16 (wrbfd, bgii.planes, gi->planes);
1664	  windres_put_16 (wrbfd, bgii.bits, gi->bits);
1665	  windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1666	  windres_put_16 (wrbfd, bgii.index, gi->index);
1667	  set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1668	}
1669      off += BIN_GROUP_ICON_ITEM_SIZE;
1670    }
1671
1672  if (wrbfd)
1673    {
1674      windres_put_16 (wrbfd, bgi.sig1, 0);
1675      windres_put_16 (wrbfd, bgi.sig2, 1);
1676      windres_put_16 (wrbfd, bgi.count, c);
1677      set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1678    }
1679  return off;
1680}
1681
1682/* Convert a menu resource to binary.  */
1683
1684static rc_uint_type
1685res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1686{
1687  int menuex;
1688
1689  menuex = extended_menu (menu);
1690
1691  if (wrbfd)
1692    {
1693  if (! menuex)
1694    {
1695	  struct bin_menu bm;
1696	  windres_put_16 (wrbfd, bm.sig1, 0);
1697	  windres_put_16 (wrbfd, bm.sig2, 0);
1698	  set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1699    }
1700  else
1701    {
1702	  struct bin_menuex bm;
1703	  windres_put_16 (wrbfd, bm.sig1, 1);
1704	  windres_put_16 (wrbfd, bm.sig2, 4);
1705	  windres_put_32 (wrbfd, bm.help, menu->help);
1706	  set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1707    }
1708    }
1709  off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1710  if (! menuex)
1711    {
1712      off = res_to_bin_menuitems (wrbfd, off, menu->items);
1713    }
1714  else
1715    {
1716      off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1717    }
1718  return off;
1719}
1720
1721/* Convert menu items to binary.  */
1722
1723static rc_uint_type
1724res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1725{
1726  const rc_menuitem *mi;
1727
1728  for (mi = items; mi != NULL; mi = mi->next)
1729    {
1730      struct bin_menuitem bmi;
1731      int flags;
1732
1733      flags = mi->type;
1734      if (mi->next == NULL)
1735	flags |= MENUITEM_ENDMENU;
1736      if (mi->popup != NULL)
1737	flags |= MENUITEM_POPUP;
1738
1739      if (wrbfd)
1740	{
1741	  windres_put_16 (wrbfd, bmi.flags, flags);
1742      if (mi->popup == NULL)
1743	    windres_put_16 (wrbfd, bmi.id, mi->id);
1744	  set_windres_bfd_content (wrbfd, &bmi, off,
1745				   mi->popup == NULL ? BIN_MENUITEM_SIZE
1746				   		     : BIN_MENUITEM_POPUP_SIZE);
1747	}
1748      off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1749
1750      off = unicode_to_bin (wrbfd, off, mi->text);
1751
1752      if (mi->popup != NULL)
1753	{
1754	  off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1755	}
1756    }
1757  return off;
1758}
1759
1760/* Convert menuex items to binary.  */
1761
1762static rc_uint_type
1763res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1764{
1765  rc_uint_type off_delta = off;
1766  const rc_menuitem *mi;
1767
1768  for (mi = items; mi != NULL; mi = mi->next)
1769    {
1770      struct bin_menuitemex bmi;
1771      int flags;
1772
1773      off += (4 - ((off - off_delta) & 3)) & 3;
1774
1775      flags = 0;
1776      if (mi->next == NULL)
1777	flags |= 0x80;
1778      if (mi->popup != NULL)
1779	flags |= 1;
1780
1781      if (wrbfd)
1782	{
1783	  windres_put_32 (wrbfd, bmi.type, mi->type);
1784	  windres_put_32 (wrbfd, bmi.state, mi->state);
1785	  windres_put_32 (wrbfd, bmi.id, mi->id);
1786	  windres_put_16 (wrbfd, bmi.flags, flags);
1787	  set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1788	}
1789      off += BIN_MENUITEMEX_SIZE;
1790
1791      off = unicode_to_bin (wrbfd, off, mi->text);
1792
1793      if (mi->popup != NULL)
1794	{
1795	  bfd_byte help[4];
1796
1797	  off += (4 - ((off - off_delta) & 3)) & 3;
1798
1799	  if (wrbfd)
1800	    {
1801	      windres_put_32 (wrbfd, help, mi->help);
1802	      set_windres_bfd_content (wrbfd, help, off, 4);
1803	    }
1804	  off += 4;
1805	  off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1806	}
1807    }
1808  return off;
1809}
1810
1811/* Convert an rcdata resource to binary.  This is also used to convert
1812   other information which happens to be stored in rc_rcdata_item lists
1813   to binary.  */
1814
1815static rc_uint_type
1816res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1817{
1818  const rc_rcdata_item *ri;
1819
1820  for (ri = items; ri != NULL; ri = ri->next)
1821    {
1822      rc_uint_type len;
1823      switch (ri->type)
1824	{
1825	default:
1826	  abort ();
1827	case RCDATA_WORD:
1828	  len = 2;
1829	  break;
1830	case RCDATA_DWORD:
1831	  len = 4;
1832	  break;
1833	case RCDATA_STRING:
1834	  len = ri->u.string.length;
1835	  break;
1836	case RCDATA_WSTRING:
1837	  len = ri->u.wstring.length * sizeof (unichar);
1838	  break;
1839	case RCDATA_BUFFER:
1840	  len = ri->u.buffer.length;
1841	  break;
1842	}
1843      if (wrbfd)
1844	{
1845	  bfd_byte h[4];
1846	  bfd_byte *hp = &h[0];
1847	  switch (ri->type)
1848	    {
1849	    case RCDATA_WORD:
1850	      windres_put_16 (wrbfd, hp, ri->u.word);
1851	      break;
1852	    case RCDATA_DWORD:
1853	      windres_put_32 (wrbfd, hp, ri->u.dword);
1854	      break;
1855	    case RCDATA_STRING:
1856	      hp = (bfd_byte *) ri->u.string.s;
1857	  break;
1858	case RCDATA_WSTRING:
1859	  {
1860		rc_uint_type i;
1861
1862		hp = (bfd_byte *) reswr_alloc (len);
1863	    for (i = 0; i < ri->u.wstring.length; i++)
1864		  windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
1865	  }
1866	      break;
1867	case RCDATA_BUFFER:
1868	      hp = (bfd_byte *) ri->u.buffer.data;
1869	  break;
1870	}
1871	  set_windres_bfd_content (wrbfd, hp, off, len);
1872    }
1873      off += len;
1874    }
1875  return off;
1876}
1877
1878/* Convert a stringtable resource to binary.  */
1879
1880static rc_uint_type
1881res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1882			const rc_stringtable *st)
1883{
1884  int i;
1885
1886  for (i = 0; i < 16; i++)
1887    {
1888      rc_uint_type slen, length;
1889      unichar *s;
1890
1891      slen = (rc_uint_type) st->strings[i].length;
1892      if (slen == 0xffffffff) slen = 0;
1893      s = st->strings[i].string;
1894
1895      length = 2 + slen * 2;
1896      if (wrbfd)
1897	{
1898	  bfd_byte *hp;
1899	  rc_uint_type j;
1900
1901	  hp = (bfd_byte *) reswr_alloc (length);
1902	  windres_put_16 (wrbfd, hp, slen);
1903
1904      for (j = 0; j < slen; j++)
1905	    windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1906	  set_windres_bfd_content (wrbfd, hp, off, length);
1907    }
1908      off += length;
1909    }
1910  return off;
1911}
1912
1913/* Convert an ASCII string to a unicode binary string.  This always
1914   returns exactly one bindata structure.  */
1915
1916static rc_uint_type
1917string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1918{
1919  rc_uint_type len;
1920
1921  len = (rc_uint_type) strlen (s);
1922
1923  if (wrbfd)
1924    {
1925      rc_uint_type i;
1926      bfd_byte *hp;
1927
1928      hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1929
1930      for (i = 0; i < len; i++)
1931	windres_put_16 (wrbfd, hp + i * 2, s[i]);
1932      windres_put_16 (wrbfd, hp + i * 2, 0);
1933      set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1934    }
1935  off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1936  return off;
1937}
1938
1939static rc_uint_type
1940res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1941{
1942  if (wrbfd)
1943    {
1944      struct bin_toolbar bt;
1945      windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1946      windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1947      windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1948      set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1949      if (tb->nitems > 0)
1950	{
1951	  rc_toolbar_item *it;
1952	  bfd_byte *ids;
1953	  rc_uint_type i = 0;
1954
1955	  ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1956	  it=tb->items;
1957	  while(it != NULL)
1958	    {
1959	      windres_put_32 (wrbfd, ids + i, it->id.u.id);
1960	      i += 4;
1961	      it = it->next;
1962	    }
1963	  set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1964 	}
1965    }
1966  off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1967
1968  return off;
1969}
1970
1971/* Convert a versioninfo resource to binary.  */
1972
1973static rc_uint_type
1974res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1975			const rc_versioninfo *versioninfo)
1976{
1977  rc_uint_type off_delta = off;
1978  rc_uint_type start;
1979  struct bin_versioninfo bvi;
1980  rc_ver_info *vi;
1981
1982  start = off;
1983  off += BIN_VERSIONINFO_SIZE;
1984  off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1985  off += (4 - ((off - off_delta) & 3)) & 3;
1986
1987  if (versioninfo->fixed != NULL)
1988    {
1989      if (wrbfd)
1990	{
1991	  struct bin_fixed_versioninfo bfv;
1992	  const rc_fixed_versioninfo *fi;
1993
1994      fi = versioninfo->fixed;
1995	  windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1996	  windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1997	  windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1998	  windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
1999	  windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
2000	  windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
2001	  windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
2002	  windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
2003	  windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
2004	  windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
2005	  windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
2006	  windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
2007	  windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
2008	  set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
2009	}
2010      off += BIN_FIXED_VERSIONINFO_SIZE;
2011    }
2012
2013  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2014    {
2015      struct bin_ver_info bv;
2016      rc_uint_type bv_off;
2017
2018      off += (4 - ((off - off_delta) & 3)) & 3;
2019
2020      bv_off = off;
2021
2022      off += BIN_VER_INFO_SIZE;
2023
2024      switch (vi->type)
2025	{
2026	default:
2027	  abort ();
2028	case VERINFO_STRING:
2029	  {
2030	    const rc_ver_stringtable *vst;
2031
2032	    off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2033
2034	    if (!vi->u.string.stringtables)
2035	      off += (4 - ((off - off_delta) & 3)) & 3;
2036
2037	    for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
2038	      {
2039		struct bin_ver_info bvst;
2040		rc_uint_type vst_off;
2041		const rc_ver_stringinfo *vs;
2042
2043		off += (4 - ((off - off_delta) & 3)) & 3;
2044
2045		vst_off = off;
2046		off += BIN_VER_INFO_SIZE;
2047
2048		off = unicode_to_bin (wrbfd, off, vst->language);
2049
2050		for (vs = vst->strings; vs != NULL; vs = vs->next)
2051		  {
2052		    struct bin_ver_info bvs;
2053		    rc_uint_type vs_off, str_off;
2054
2055		    off += (4 - ((off - off_delta) & 3)) & 3;
2056
2057		    vs_off = off;
2058		    off += BIN_VER_INFO_SIZE;
2059
2060		    off = unicode_to_bin (wrbfd, off, vs->key);
2061
2062		    off += (4 - ((off - off_delta) & 3)) & 3;
2063
2064		    str_off = off;
2065		    off = unicode_to_bin (wrbfd, off, vs->value);
2066
2067		    if (wrbfd)
2068		      {
2069			windres_put_16 (wrbfd, bvs.size, off - vs_off);
2070			windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
2071			windres_put_16 (wrbfd, bvs.sig2, 1);
2072			set_windres_bfd_content (wrbfd, &bvs, vs_off,
2073						 BIN_VER_INFO_SIZE);
2074		      }
2075		  }
2076
2077		if (wrbfd)
2078		  {
2079		    windres_put_16 (wrbfd, bvst.size, off - vst_off);
2080		    windres_put_16 (wrbfd, bvst.sig1, 0);
2081		    windres_put_16 (wrbfd, bvst.sig2, 1);
2082		    set_windres_bfd_content (wrbfd, &bvst, vst_off,
2083					     BIN_VER_INFO_SIZE);
2084		  }
2085	      }
2086	    break;
2087	  }
2088
2089	case VERINFO_VAR:
2090	  {
2091	    rc_uint_type vvd_off, vvvd_off;
2092	    struct bin_ver_info bvvd;
2093	    const rc_ver_varinfo *vv;
2094
2095	    off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2096
2097	    off += (4 - ((off - off_delta) & 3)) & 3;
2098
2099	    vvd_off = off;
2100	    off += BIN_VER_INFO_SIZE;
2101
2102	    off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2103
2104	    off += (4 - ((off - off_delta) & 3)) & 3;
2105
2106	    vvvd_off = off;
2107
2108	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2109	      {
2110		if (wrbfd)
2111		  {
2112		    bfd_byte vvsd[4];
2113
2114		    windres_put_16 (wrbfd, &vvsd[0], vv->language);
2115		    windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2116		    set_windres_bfd_content (wrbfd, vvsd, off, 4);
2117		  }
2118		off += 4;
2119	      }
2120	    if (wrbfd)
2121	    {
2122		windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2123		windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2124		windres_put_16 (wrbfd, bvvd.sig2, 0);
2125		set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2126					 BIN_VER_INFO_SIZE);
2127	    }
2128
2129	    break;
2130	  }
2131	}
2132
2133      if (wrbfd)
2134	{
2135	  windres_put_16 (wrbfd, bv.size, off - bv_off);
2136	  windres_put_16 (wrbfd, bv.sig1, 0);
2137	  windres_put_16 (wrbfd, bv.sig2, 1);
2138	  set_windres_bfd_content (wrbfd, &bv, bv_off,
2139	  			   BIN_VER_INFO_SIZE);
2140	}
2141    }
2142
2143  if (wrbfd)
2144    {
2145      windres_put_16 (wrbfd, bvi.size, off - start);
2146      windres_put_16 (wrbfd, bvi.fixed_size,
2147		      versioninfo->fixed == NULL ? 0
2148		      				 : BIN_FIXED_VERSIONINFO_SIZE);
2149      windres_put_16 (wrbfd, bvi.sig2, 0);
2150      set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2151    }
2152  return off;
2153}
2154
2155/* Convert a generic resource to binary.  */
2156
2157static rc_uint_type
2158res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2159		    const bfd_byte *data)
2160{
2161  if (wrbfd && length != 0)
2162    set_windres_bfd_content (wrbfd, data, off, length);
2163  return off + (rc_uint_type) length;
2164}
2165