xref: /netbsd-src/external/gpl3/binutils.old/dist/binutils/resbin.c (revision 181254a7b1bdde6873432bffef2d2decc4b5c22f)
1 /* resbin.c -- manipulate the Windows binary resource format.
2    Copyright (C) 1997-2018 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 
36 static void toosmall (const char *);
37 
38 static unichar *get_unicode (windres_bfd *, const bfd_byte *, rc_uint_type, rc_uint_type *);
39 static int get_resid (windres_bfd *, rc_res_id *, const bfd_byte *, rc_uint_type);
40 static rc_res_resource *bin_to_res_generic (windres_bfd *, enum rc_res_type,
41 					    const bfd_byte *, rc_uint_type);
42 static rc_res_resource *bin_to_res_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
43 static rc_res_resource *bin_to_res_menu (windres_bfd *,const bfd_byte *, rc_uint_type);
44 static rc_menuitem *bin_to_res_menuitems (windres_bfd *, const bfd_byte *, rc_uint_type,
45 					  rc_uint_type *);
46 static rc_menuitem *bin_to_res_menuexitems (windres_bfd *, const bfd_byte *, rc_uint_type,
47 					    rc_uint_type *);
48 static rc_res_resource *bin_to_res_dialog (windres_bfd *, const bfd_byte *, rc_uint_type);
49 static rc_res_resource *bin_to_res_string (windres_bfd *,const bfd_byte *, rc_uint_type);
50 static rc_res_resource *bin_to_res_fontdir (windres_bfd *, const bfd_byte *, rc_uint_type);
51 static rc_res_resource *bin_to_res_accelerators (windres_bfd *, const bfd_byte *, rc_uint_type);
52 static rc_res_resource *bin_to_res_rcdata (windres_bfd *, const bfd_byte *, rc_uint_type, int);
53 static rc_res_resource *bin_to_res_group_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
54 static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *, rc_uint_type);
55 static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
56 static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
57 static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
58 static 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 
67 rc_res_resource *
68 bin_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 
116 static void
117 toosmall (const char *msg)
118 {
119   fatal (_("%s: not enough binary data"), msg);
120 }
121 
122 /* Swap in a NULL terminated unicode string.  */
123 
124 static unichar *
125 get_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 
155 static int
156 get_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 
184 rc_res_resource *
185 bin_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 
200 rc_res_resource *
201 bin_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 
224 rc_res_resource *
225 bin_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 
270 static rc_menuitem *
271 bin_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 
347 static rc_menuitem *
348 bin_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 
421 static rc_res_resource *
422 bin_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 
604 static rc_res_resource *
605 bin_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 
650 static rc_res_resource *
651 bin_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 
721 static rc_res_resource *
722 bin_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 
763 static rc_res_resource *
764 bin_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 
786 static rc_res_resource *
787 bin_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 
841 static rc_res_resource *
842 bin_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 
900 static void
901 get_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 
950 static rc_res_resource *
951 bin_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 
1194 static rc_res_resource *
1195 bin_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 
1215 static rc_res_resource *
1216 bin_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 
1258 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1259 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1260 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1261 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1262 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1263 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1264 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1265 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1266 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1267 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1268 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1269 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1270 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1271 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1272 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1273 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1274 static 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 
1279 rc_uint_type
1280 res_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 
1319 static rc_uint_type
1320 resid_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 
1354 static rc_uint_type
1355 unicode_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 
1379 static rc_uint_type
1380 res_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 
1404 static rc_uint_type
1405 res_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 
1423 static rc_uint_type
1424 res_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 
1462 static rc_uint_type
1463 res_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.  */
1608 static rc_uint_type
1609 res_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 
1642 static rc_uint_type
1643 res_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 
1684 static rc_uint_type
1685 res_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 
1723 static rc_uint_type
1724 res_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 
1762 static rc_uint_type
1763 res_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 
1815 static rc_uint_type
1816 res_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 
1880 static rc_uint_type
1881 res_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 
1916 static rc_uint_type
1917 string_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 
1939 static rc_uint_type
1940 res_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 
1973 static rc_uint_type
1974 res_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 
2157 static rc_uint_type
2158 res_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