xref: /netbsd-src/external/gpl3/binutils.old/dist/binutils/resbin.c (revision d909946ca08dceb44d7d0f22ec9488679695d976)
1 /* resbin.c -- manipulate the Windows binary resource format.
2    Copyright 1997, 1998, 1999, 2002, 2003, 2005, 2006, 2007, 2009, 2010, 2011
3    Free Software Foundation, Inc.
4    Written by Ian Lance Taylor, Cygnus Support.
5    Rewritten by Kai Tietz, Onevision.
6 
7    This file is part of GNU Binutils.
8 
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22    02110-1301, USA.  */
23 
24 
25 /* This file contains functions to convert between the binary resource
26    format and the internal structures that we want to use.  The same
27    binary resource format is used in both res and COFF files.  */
28 
29 #include "sysdep.h"
30 #include "bfd.h"
31 #include "bucomm.h"
32 #include "libiberty.h"
33 #include "windres.h"
34 
35 /* Local functions.  */
36 
37 static void toosmall (const char *);
38 
39 static unichar *get_unicode (windres_bfd *, const bfd_byte *, rc_uint_type, rc_uint_type *);
40 static int get_resid (windres_bfd *, rc_res_id *, const bfd_byte *, rc_uint_type);
41 static rc_res_resource *bin_to_res_generic (windres_bfd *, enum rc_res_type,
42 					    const bfd_byte *, rc_uint_type);
43 static rc_res_resource *bin_to_res_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
44 static rc_res_resource *bin_to_res_menu (windres_bfd *,const bfd_byte *, rc_uint_type);
45 static rc_menuitem *bin_to_res_menuitems (windres_bfd *, const bfd_byte *, rc_uint_type,
46 					  rc_uint_type *);
47 static rc_menuitem *bin_to_res_menuexitems (windres_bfd *, const bfd_byte *, rc_uint_type,
48 					    rc_uint_type *);
49 static rc_res_resource *bin_to_res_dialog (windres_bfd *, const bfd_byte *, rc_uint_type);
50 static rc_res_resource *bin_to_res_string (windres_bfd *,const bfd_byte *, rc_uint_type);
51 static rc_res_resource *bin_to_res_fontdir (windres_bfd *, const bfd_byte *, rc_uint_type);
52 static rc_res_resource *bin_to_res_accelerators (windres_bfd *, const bfd_byte *, rc_uint_type);
53 static rc_res_resource *bin_to_res_rcdata (windres_bfd *, const bfd_byte *, rc_uint_type, int);
54 static rc_res_resource *bin_to_res_group_cursor (windres_bfd *, const bfd_byte *, rc_uint_type);
55 static rc_res_resource *bin_to_res_group_icon (windres_bfd *, const bfd_byte *, rc_uint_type);
56 static rc_res_resource *bin_to_res_version (windres_bfd *, const bfd_byte *, rc_uint_type);
57 static rc_res_resource *bin_to_res_userdata (windres_bfd *, const bfd_byte *, rc_uint_type);
58 static rc_res_resource *bin_to_res_toolbar (windres_bfd *, const bfd_byte *, rc_uint_type);
59 static void get_version_header (windres_bfd *, const bfd_byte *, rc_uint_type, const char *,
60 				unichar **, rc_uint_type *, rc_uint_type *, rc_uint_type *,
61 				rc_uint_type *);
62 
63 /* Given a resource type ID, a pointer to data, a length, return a
64    rc_res_resource structure which represents that resource.  The caller
65    is responsible for initializing the res_info and coff_info fields
66    of the returned structure.  */
67 
68 rc_res_resource *
69 bin_to_res (windres_bfd *wrbfd, rc_res_id type, const bfd_byte *data,
70 	    rc_uint_type length)
71 {
72   if (type.named)
73     return bin_to_res_userdata (wrbfd, data, length);
74   else
75     {
76       switch (type.u.id)
77 	{
78 	default:
79 	  return bin_to_res_userdata (wrbfd, data, length);
80 	case RT_CURSOR:
81 	  return bin_to_res_cursor (wrbfd, data, length);
82 	case RT_BITMAP:
83 	  return bin_to_res_generic (wrbfd, RES_TYPE_BITMAP, data, length);
84 	case RT_ICON:
85 	  return bin_to_res_generic (wrbfd, RES_TYPE_ICON, data, length);
86 	case RT_MENU:
87 	  return bin_to_res_menu (wrbfd, data, length);
88 	case RT_DIALOG:
89 	  return bin_to_res_dialog (wrbfd, data, length);
90 	case RT_STRING:
91 	  return bin_to_res_string (wrbfd, data, length);
92 	case RT_FONTDIR:
93 	  return bin_to_res_fontdir (wrbfd, data, length);
94 	case RT_FONT:
95 	  return bin_to_res_generic (wrbfd, RES_TYPE_FONT, data, length);
96 	case RT_ACCELERATOR:
97 	  return bin_to_res_accelerators (wrbfd, data, length);
98 	case RT_RCDATA:
99 	  return bin_to_res_rcdata (wrbfd, data, length, RES_TYPE_RCDATA);
100 	case RT_MESSAGETABLE:
101 	  return bin_to_res_generic (wrbfd, RES_TYPE_MESSAGETABLE, data, length);
102 	case RT_GROUP_CURSOR:
103 	  return bin_to_res_group_cursor (wrbfd, data, length);
104 	case RT_GROUP_ICON:
105 	  return bin_to_res_group_icon (wrbfd, data, length);
106 	case RT_VERSION:
107 	  return bin_to_res_version (wrbfd, data, length);
108 	case RT_TOOLBAR:
109 	  return  bin_to_res_toolbar (wrbfd, data, length);
110 
111 	}
112     }
113 }
114 
115 /* Give an error if the binary data is too small.  */
116 
117 static void
118 toosmall (const char *msg)
119 {
120   fatal (_("%s: not enough binary data"), msg);
121 }
122 
123 /* Swap in a NULL terminated unicode string.  */
124 
125 static unichar *
126 get_unicode (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
127 	     rc_uint_type *retlen)
128 {
129   rc_uint_type c, i;
130   unichar *ret;
131 
132   c = 0;
133   while (1)
134     {
135       if (length < c * 2 + 2)
136 	toosmall (_("null terminated unicode string"));
137       if (windres_get_16 (wrbfd, data + c * 2, 2) == 0)
138 	break;
139       ++c;
140     }
141 
142   ret = (unichar *) res_alloc ((c + 1) * sizeof (unichar));
143 
144   for (i = 0; i < c; i++)
145     ret[i] = windres_get_16 (wrbfd, data + i * 2, 2);
146   ret[i] = 0;
147 
148   if (retlen != NULL)
149     *retlen = c;
150 
151   return ret;
152 }
153 
154 /* Get a resource identifier.  This returns the number of bytes used.  */
155 
156 static int
157 get_resid (windres_bfd *wrbfd, rc_res_id *id, const bfd_byte *data,
158 	   rc_uint_type length)
159 {
160   rc_uint_type first;
161 
162   if (length < 2)
163     toosmall (_("resource ID"));
164 
165   first = windres_get_16 (wrbfd, data, 2);
166   if (first == 0xffff)
167     {
168       if (length < 4)
169 	toosmall (_("resource ID"));
170       id->named = 0;
171       id->u.id = windres_get_16 (wrbfd, data + 2, 2);
172       return 4;
173     }
174   else
175     {
176       id->named = 1;
177       id->u.n.name = get_unicode (wrbfd, data, length, &id->u.n.length);
178       return id->u.n.length * 2 + 2;
179     }
180 }
181 
182 /* Convert a resource which just stores uninterpreted data from
183    binary.  */
184 
185 rc_res_resource *
186 bin_to_res_generic (windres_bfd *wrbfd ATTRIBUTE_UNUSED, enum rc_res_type type,
187 		    const bfd_byte *data, rc_uint_type length)
188 {
189   rc_res_resource *r;
190 
191   r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
192   r->type = type;
193   r->u.data.data = data;
194   r->u.data.length = length;
195 
196   return r;
197 }
198 
199 /* Convert a cursor resource from binary.  */
200 
201 rc_res_resource *
202 bin_to_res_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
203 {
204   rc_cursor *c;
205   rc_res_resource *r;
206 
207   if (length < 4)
208     toosmall (_("cursor"));
209 
210   c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
211   c->xhotspot = windres_get_16 (wrbfd, data, 2);
212   c->yhotspot = windres_get_16 (wrbfd, data + 2, 2);
213   c->length = length - 4;
214   c->data = data + 4;
215 
216   r = (rc_res_resource *) res_alloc (sizeof *r);
217   r->type = RES_TYPE_CURSOR;
218   r->u.cursor = c;
219 
220   return r;
221 }
222 
223 /* Convert a menu resource from binary.  */
224 
225 rc_res_resource *
226 bin_to_res_menu (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
227 {
228   rc_res_resource *r;
229   rc_menu *m;
230   rc_uint_type version, got;
231 
232   r = (rc_res_resource *) res_alloc (sizeof *r);
233   r->type = RES_TYPE_MENU;
234 
235   m = (rc_menu *) res_alloc (sizeof (rc_menu));
236   r->u.menu = m;
237 
238   if (length < 2)
239     toosmall (_("menu header"));
240 
241   version = windres_get_16 (wrbfd, data, 2);
242 
243   if (version == 0)
244     {
245       if (length < 4)
246 	toosmall (_("menu header"));
247       m->help = 0;
248       m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &got);
249     }
250   else if (version == 1)
251     {
252       rc_uint_type offset;
253 
254       if (length < 8)
255 	toosmall (_("menuex header"));
256       m->help = windres_get_32 (wrbfd, data + 4, 4);
257       offset = windres_get_16 (wrbfd, data + 2, 2);
258       if (offset + 4 >= length)
259 	toosmall (_("menuex offset"));
260       m->items = bin_to_res_menuexitems (wrbfd, data + 4 + offset,
261 					 length - (4 + offset), &got);
262     }
263   else
264     fatal (_("unsupported menu version %d"), (int) version);
265 
266   return r;
267 }
268 
269 /* Convert menu items from binary.  */
270 
271 static rc_menuitem *
272 bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
273 		      rc_uint_type *got)
274 {
275   rc_menuitem *first, **pp;
276 
277   first = NULL;
278   pp = &first;
279 
280   *got = 0;
281 
282   while (length > 0)
283     {
284       rc_uint_type flags, slen, itemlen;
285       rc_uint_type stroff;
286       rc_menuitem *mi;
287 
288       if (length < 4)
289 	toosmall (_("menuitem header"));
290 
291       mi = (rc_menuitem *) res_alloc (sizeof *mi);
292       mi->state = 0;
293       mi->help = 0;
294 
295       flags = windres_get_16 (wrbfd, data, 2);
296       mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);
297 
298       if ((flags & MENUITEM_POPUP) == 0)
299 	stroff = 4;
300       else
301 	stroff = 2;
302 
303       if (length < stroff + 2)
304 	toosmall (_("menuitem header"));
305 
306       if (windres_get_16 (wrbfd, data + stroff, 2) == 0)
307 	{
308 	  slen = 0;
309 	  mi->text = NULL;
310 	}
311       else
312 	mi->text = get_unicode (wrbfd, data + stroff, length - stroff, &slen);
313 
314       itemlen = stroff + slen * 2 + 2;
315 
316       if ((flags & MENUITEM_POPUP) == 0)
317 	{
318 	  mi->popup = NULL;
319 	  mi->id = windres_get_16 (wrbfd, data + 2, 2);
320 	}
321       else
322 	{
323 	  rc_uint_type subread;
324 
325 	  mi->id = 0;
326 	  mi->popup = bin_to_res_menuitems (wrbfd, data + itemlen, length - itemlen,
327 	  				    &subread);
328 	  itemlen += subread;
329 	}
330 
331       mi->next = NULL;
332       *pp = mi;
333       pp = &mi->next;
334 
335       data += itemlen;
336       length -= itemlen;
337       *got += itemlen;
338 
339       if ((flags & MENUITEM_ENDMENU) != 0)
340 	return first;
341     }
342 
343   return first;
344 }
345 
346 /* Convert menuex items from binary.  */
347 
348 static rc_menuitem *
349 bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
350 			rc_uint_type *got)
351 {
352   rc_menuitem *first, **pp;
353 
354   first = NULL;
355   pp = &first;
356 
357   *got = 0;
358 
359   while (length > 0)
360     {
361       rc_uint_type flags, slen;
362       rc_uint_type itemlen;
363       rc_menuitem *mi;
364 
365       if (length < 16)
366 	toosmall (_("menuitem header"));
367 
368       mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
369       mi->type = windres_get_32 (wrbfd, data, 4);
370       mi->state = windres_get_32 (wrbfd, data + 4, 4);
371       mi->id = windres_get_32 (wrbfd, data + 8, 4);
372 
373       flags = windres_get_16 (wrbfd, data + 12, 2);
374 
375       if (windres_get_16 (wrbfd, data + 14, 2) == 0)
376 	{
377 	  slen = 0;
378 	  mi->text = NULL;
379 	}
380       else
381 	mi->text = get_unicode (wrbfd, data + 14, length - 14, &slen);
382 
383       itemlen = 14 + slen * 2 + 2;
384       itemlen = (itemlen + 3) &~ 3;
385 
386       if ((flags & 1) == 0)
387 	{
388 	  mi->popup = NULL;
389 	  mi->help = 0;
390 	}
391       else
392 	{
393 	  rc_uint_type subread;
394 
395 	  if (length < itemlen + 4)
396 	    toosmall (_("menuitem"));
397 	  mi->help = windres_get_32 (wrbfd, data + itemlen, 4);
398 	  itemlen += 4;
399 
400 	  mi->popup = bin_to_res_menuexitems (wrbfd, data + itemlen,
401 					      length - itemlen, &subread);
402 	  itemlen += subread;
403 	}
404 
405       mi->next = NULL;
406       *pp = mi;
407       pp = &mi->next;
408 
409       data += itemlen;
410       length -= itemlen;
411       *got += itemlen;
412 
413       if ((flags & 0x80) != 0)
414 	return first;
415     }
416 
417   return first;
418 }
419 
420 /* Convert a dialog resource from binary.  */
421 
422 static rc_res_resource *
423 bin_to_res_dialog (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
424 {
425   rc_uint_type signature;
426   rc_dialog *d;
427   rc_uint_type c, sublen, i;
428   rc_uint_type off;
429   rc_dialog_control **pp;
430   rc_res_resource *r;
431 
432   if (length < 18)
433     toosmall (_("dialog header"));
434 
435   d = (rc_dialog *) res_alloc (sizeof (rc_dialog));
436 
437   signature = windres_get_16 (wrbfd, data + 2, 2);
438   if (signature != 0xffff)
439     {
440       d->ex = NULL;
441       d->style = windres_get_32 (wrbfd, data, 4);
442       d->exstyle = windres_get_32 (wrbfd, data + 4, 4);
443       off = 8;
444     }
445   else
446     {
447       int version;
448 
449       version = windres_get_16 (wrbfd, data, 2);
450       if (version != 1)
451 	fatal (_("unexpected DIALOGEX version %d"), version);
452 
453       d->ex = (rc_dialog_ex *) res_alloc (sizeof (rc_dialog_ex));
454       d->ex->help = windres_get_32 (wrbfd, data + 4, 4);
455       d->exstyle = windres_get_32 (wrbfd, data + 8, 4);
456       d->style = windres_get_32 (wrbfd, data + 12, 4);
457       off = 16;
458     }
459 
460   if (length < off + 10)
461     toosmall (_("dialog header"));
462 
463   c = windres_get_16 (wrbfd, data + off, 2);
464   d->x = windres_get_16 (wrbfd, data + off + 2, 2);
465   d->y = windres_get_16 (wrbfd, data + off + 4, 2);
466   d->width = windres_get_16 (wrbfd, data + off + 6, 2);
467   d->height = windres_get_16 (wrbfd, data + off + 8, 2);
468 
469   off += 10;
470 
471   sublen = get_resid (wrbfd, &d->menu, data + off, length - off);
472   off += sublen;
473 
474   sublen = get_resid (wrbfd, &d->class, data + off, length - off);
475   off += sublen;
476 
477   d->caption = get_unicode (wrbfd, data + off, length - off, &sublen);
478   off += sublen * 2 + 2;
479   if (sublen == 0)
480     d->caption = NULL;
481 
482   if ((d->style & DS_SETFONT) == 0)
483     {
484       d->pointsize = 0;
485       d->font = NULL;
486       if (d->ex != NULL)
487 	{
488 	  d->ex->weight = 0;
489 	  d->ex->italic = 0;
490 	  d->ex->charset = 1; /* Default charset.  */
491 	}
492     }
493   else
494     {
495       if (length < off + 2)
496 	toosmall (_("dialog font point size"));
497 
498       d->pointsize = windres_get_16 (wrbfd, data + off, 2);
499       off += 2;
500 
501       if (d->ex != NULL)
502 	{
503 	  if (length < off + 4)
504 	    toosmall (_("dialogex font information"));
505 	  d->ex->weight = windres_get_16 (wrbfd, data + off, 2);
506 	  d->ex->italic = windres_get_8 (wrbfd, data + off + 2, 1);
507 	  d->ex->charset = windres_get_8 (wrbfd, data + off + 3, 1);
508 	  off += 4;
509 	}
510 
511       d->font = get_unicode (wrbfd, data + off, length - off, &sublen);
512       off += sublen * 2 + 2;
513     }
514 
515   d->controls = NULL;
516   pp = &d->controls;
517 
518   for (i = 0; i < c; i++)
519     {
520       rc_dialog_control *dc;
521       int datalen;
522 
523       off = (off + 3) &~ 3;
524 
525       dc = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
526 
527       if (d->ex == NULL)
528 	{
529 	  if (length < off + 8)
530 	    toosmall (_("dialog control"));
531 
532 	  dc->style = windres_get_32 (wrbfd, data + off, 4);
533 	  dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
534 	  dc->help = 0;
535 	  off += 8;
536 	}
537       else
538 	{
539 	  if (length < off + 12)
540 	    toosmall (_("dialogex control"));
541 	  dc->help = windres_get_32 (wrbfd, data + off, 4);
542 	  dc->exstyle = windres_get_32 (wrbfd, data + off + 4, 4);
543 	  dc->style = windres_get_32 (wrbfd, data + off + 8, 4);
544 	  off += 12;
545 	}
546 
547       if (length < off + (d->ex != NULL ? 2 : 0) + 10)
548 	toosmall (_("dialog control"));
549 
550       dc->x = windres_get_16 (wrbfd, data + off, 2);
551       dc->y = windres_get_16 (wrbfd, data + off + 2, 2);
552       dc->width = windres_get_16 (wrbfd, data + off + 4, 2);
553       dc->height = windres_get_16 (wrbfd, data + off + 6, 2);
554 
555       if (d->ex != NULL)
556 	dc->id = windres_get_32 (wrbfd, data + off + 8, 4);
557       else
558 	dc->id = windres_get_16 (wrbfd, data + off + 8, 2);
559 
560       off += 10 + (d->ex != NULL ? 2 : 0);
561 
562       sublen = get_resid (wrbfd, &dc->class, data + off, length - off);
563       off += sublen;
564 
565       sublen = get_resid (wrbfd, &dc->text, data + off, length - off);
566       off += sublen;
567 
568       if (length < off + 2)
569 	toosmall (_("dialog control end"));
570 
571       datalen = windres_get_16 (wrbfd, data + off, 2);
572       off += 2;
573 
574       if (datalen == 0)
575 	dc->data = NULL;
576       else
577 	{
578 	  off = (off + 3) &~ 3;
579 
580 	  if (length < off + datalen)
581 	    toosmall (_("dialog control data"));
582 
583 	  dc->data = ((rc_rcdata_item *)
584 		      res_alloc (sizeof (rc_rcdata_item)));
585 	  dc->data->next = NULL;
586 	  dc->data->type = RCDATA_BUFFER;
587 	  dc->data->u.buffer.length = datalen;
588 	  dc->data->u.buffer.data = data + off;
589 
590 	  off += datalen;
591 	}
592 
593       dc->next = NULL;
594       *pp = dc;
595       pp = &dc->next;
596     }
597 
598   r = (rc_res_resource *) res_alloc (sizeof *r);
599   r->type = RES_TYPE_DIALOG;
600   r->u.dialog = d;
601 
602   return r;
603 }
604 
605 /* Convert a stringtable resource from binary.  */
606 
607 static rc_res_resource *
608 bin_to_res_string (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
609 {
610   rc_stringtable *st;
611   int i;
612   rc_res_resource *r;
613 
614   st = (rc_stringtable *) res_alloc (sizeof (rc_stringtable));
615 
616   for (i = 0; i < 16; i++)
617     {
618       unsigned int slen;
619 
620       if (length < 2)
621 	toosmall (_("stringtable string length"));
622       slen = windres_get_16 (wrbfd, data, 2);
623       st->strings[i].length = slen;
624 
625       if (slen > 0)
626 	{
627 	  unichar *s;
628 	  unsigned int j;
629 
630 	  if (length < 2 + 2 * slen)
631 	    toosmall (_("stringtable string"));
632 
633 	  s = (unichar *) res_alloc (slen * sizeof (unichar));
634 	  st->strings[i].string = s;
635 
636 	  for (j = 0; j < slen; j++)
637 	    s[j] = windres_get_16 (wrbfd, data + 2 + j * 2, 2);
638 	}
639 
640       data += 2 + 2 * slen;
641       length -= 2 + 2 * slen;
642     }
643 
644   r = (rc_res_resource *) res_alloc (sizeof *r);
645   r->type = RES_TYPE_STRINGTABLE;
646   r->u.stringtable = st;
647 
648   return r;
649 }
650 
651 /* Convert a fontdir resource from binary.  */
652 
653 static rc_res_resource *
654 bin_to_res_fontdir (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
655 {
656   rc_uint_type c, i;
657   rc_fontdir *first, **pp;
658   rc_res_resource *r;
659 
660   if (length < 2)
661     toosmall (_("fontdir header"));
662 
663   c = windres_get_16 (wrbfd, data, 2);
664 
665   first = NULL;
666   pp = &first;
667 
668   for (i = 0; i < c; i++)
669     {
670       const struct bin_fontdir_item *bfi;
671       rc_fontdir *fd;
672       unsigned int off;
673 
674       if (length < 56)
675 	toosmall (_("fontdir"));
676 
677       bfi = (const struct bin_fontdir_item *) data;
678       fd = (rc_fontdir *) res_alloc (sizeof *fd);
679       fd->index = windres_get_16 (wrbfd, bfi->index, 2);
680 
681       /* To work out the length of the fontdir data, we must get the
682          length of the device name and face name strings, even though
683          we don't store them in the rc_fontdir.  The
684          documentation says that these are NULL terminated char
685          strings, not Unicode strings.  */
686 
687       off = 56;
688 
689       while (off < length && data[off] != '\0')
690 	++off;
691       if (off >= length)
692 	toosmall (_("fontdir device name"));
693       ++off;
694 
695       while (off < length && data[off] != '\0')
696 	++off;
697       if (off >= length)
698 	toosmall (_("fontdir face name"));
699       ++off;
700 
701       fd->length = off;
702       fd->data = data;
703 
704       fd->next = NULL;
705       *pp = fd;
706       pp = &fd->next;
707 
708       /* The documentation does not indicate that any rounding is
709          required.  */
710 
711       data += off;
712       length -= off;
713     }
714 
715   r = (rc_res_resource *) res_alloc (sizeof *r);
716   r->type = RES_TYPE_FONTDIR;
717   r->u.fontdir = first;
718 
719   return r;
720 }
721 
722 /* Convert an accelerators resource from binary.  */
723 
724 static rc_res_resource *
725 bin_to_res_accelerators (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
726 {
727   rc_accelerator *first, **pp;
728   rc_res_resource *r;
729 
730   first = NULL;
731   pp = &first;
732 
733   while (1)
734     {
735       rc_accelerator *a;
736 
737       if (length < 8)
738 	toosmall (_("accelerator"));
739 
740       a = (rc_accelerator *) res_alloc (sizeof (rc_accelerator));
741 
742       a->flags = windres_get_16 (wrbfd, data, 2);
743       a->key = windres_get_16 (wrbfd, data + 2, 2);
744       a->id = windres_get_16 (wrbfd, data + 4, 2);
745 
746       a->next = NULL;
747       *pp = a;
748       pp = &a->next;
749 
750       if ((a->flags & ACC_LAST) != 0)
751 	break;
752 
753       data += 8;
754       length -= 8;
755     }
756 
757   r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
758   r->type = RES_TYPE_ACCELERATOR;
759   r->u.acc = first;
760 
761   return r;
762 }
763 
764 /* Convert an rcdata resource from binary.  */
765 
766 static rc_res_resource *
767 bin_to_res_rcdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
768 		   rc_uint_type length, int rctyp)
769 {
770   rc_rcdata_item *ri;
771   rc_res_resource *r;
772 
773   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
774 
775   ri->next = NULL;
776   ri->type = RCDATA_BUFFER;
777   ri->u.buffer.length = length;
778   ri->u.buffer.data = data;
779 
780   r = (rc_res_resource *) res_alloc (sizeof *r);
781   r->type = rctyp;
782   r->u.rcdata = ri;
783 
784   return r;
785 }
786 
787 /* Convert a group cursor resource from binary.  */
788 
789 static rc_res_resource *
790 bin_to_res_group_cursor (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
791 {
792   int type, c, i;
793   rc_group_cursor *first, **pp;
794   rc_res_resource *r;
795 
796   if (length < 6)
797     toosmall (_("group cursor header"));
798 
799   type = windres_get_16 (wrbfd, data + 2, 2);
800   if (type != 2)
801     fatal (_("unexpected group cursor type %d"), type);
802 
803   c = windres_get_16 (wrbfd, data + 4, 2);
804 
805   data += 6;
806   length -= 6;
807 
808   first = NULL;
809   pp = &first;
810 
811   for (i = 0; i < c; i++)
812     {
813       rc_group_cursor *gc;
814 
815       if (length < 14)
816 	toosmall (_("group cursor"));
817 
818       gc = (rc_group_cursor *) res_alloc (sizeof *gc);
819 
820       gc->width = windres_get_16 (wrbfd, data, 2);
821       gc->height = windres_get_16 (wrbfd, data + 2, 2);
822       gc->planes = windres_get_16 (wrbfd, data + 4, 2);
823       gc->bits = windres_get_16 (wrbfd, data + 6, 2);
824       gc->bytes = windres_get_32 (wrbfd, data + 8, 4);
825       gc->index = windres_get_16 (wrbfd, data + 12, 2);
826 
827       gc->next = NULL;
828       *pp = gc;
829       pp = &gc->next;
830 
831       data += 14;
832       length -= 14;
833     }
834 
835   r = (rc_res_resource *) res_alloc (sizeof (rc_res_resource));
836   r->type = RES_TYPE_GROUP_CURSOR;
837   r->u.group_cursor = first;
838 
839   return r;
840 }
841 
842 /* Convert a group icon resource from binary.  */
843 
844 static rc_res_resource *
845 bin_to_res_group_icon (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
846 {
847   int type, c, i;
848   rc_group_icon *first, **pp;
849   rc_res_resource *r;
850 
851   if (length < 6)
852     toosmall (_("group icon header"));
853 
854   type = windres_get_16 (wrbfd, data + 2, 2);
855   if (type != 1)
856     fatal (_("unexpected group icon type %d"), type);
857 
858   c = windres_get_16 (wrbfd, data + 4, 2);
859 
860   data += 6;
861   length -= 6;
862 
863   first = NULL;
864   pp = &first;
865 
866   for (i = 0; i < c; i++)
867     {
868       rc_group_icon *gi;
869 
870       if (length < 14)
871 	toosmall (_("group icon"));
872 
873       gi = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
874 
875       gi->width = windres_get_8 (wrbfd, data, 1);
876       gi->height = windres_get_8 (wrbfd, data + 1, 1);
877       gi->colors = windres_get_8 (wrbfd, data + 2, 1);
878       gi->planes = windres_get_16 (wrbfd, data + 4, 2);
879       gi->bits = windres_get_16 (wrbfd, data + 6, 2);
880       gi->bytes = windres_get_32 (wrbfd, data + 8, 4);
881       gi->index = windres_get_16 (wrbfd, data + 12, 2);
882 
883       gi->next = NULL;
884       *pp = gi;
885       pp = &gi->next;
886 
887       data += 14;
888       length -= 14;
889     }
890 
891   r = (rc_res_resource *) res_alloc (sizeof *r);
892   r->type = RES_TYPE_GROUP_ICON;
893   r->u.group_icon = first;
894 
895   return r;
896 }
897 
898 /* Extract data from a version header.  If KEY is not NULL, then the
899    key must be KEY; otherwise, the key is returned in *PKEY.  This
900    sets *LEN to the total length, *VALLEN to the value length, *TYPE
901    to the type, and *OFF to the offset to the children.  */
902 
903 static void
904 get_version_header (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
905 		    const char *key, unichar **pkey,
906 		    rc_uint_type *len, rc_uint_type *vallen, rc_uint_type *type,
907 		    rc_uint_type *off)
908 {
909   if (length < 8)
910     toosmall (key);
911 
912   *len = windres_get_16 (wrbfd, data, 2);
913   *vallen = windres_get_16 (wrbfd, data + 2, 2);
914   *type = windres_get_16 (wrbfd, data + 4, 2);
915 
916   *off = 6;
917 
918   length -= 6;
919   data += 6;
920 
921   if (key == NULL)
922     {
923       rc_uint_type sublen;
924 
925       *pkey = get_unicode (wrbfd, data, length, &sublen);
926       *off += (sublen + 1) * sizeof (unichar);
927     }
928   else
929     {
930       while (1)
931 	{
932 	  if (length < 2)
933 	    toosmall (key);
934 	  if (windres_get_16 (wrbfd, data, 2) != (bfd_byte) *key)
935 	    fatal (_("unexpected version string"));
936 
937 	  *off += 2;
938 	  length -= 2;
939 	  data += 2;
940 
941 	  if (*key == '\0')
942 	    break;
943 
944 	  ++key;
945 	}
946     }
947 
948   *off = (*off + 3) &~ 3;
949 }
950 
951 /* Convert a version resource from binary.  */
952 
953 static rc_res_resource *
954 bin_to_res_version (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
955 {
956   rc_uint_type verlen, vallen, type, off;
957   rc_fixed_versioninfo *fi;
958   rc_ver_info *first, **pp;
959   rc_versioninfo *v;
960   rc_res_resource *r;
961 
962   get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
963 		      (unichar **) NULL, &verlen, &vallen, &type, &off);
964 
965   if ((unsigned int) verlen != length)
966     fatal (_("version length %d does not match resource length %lu"),
967 	   (int) verlen, (unsigned long) length);
968 
969   if (type != 0)
970     fatal (_("unexpected version type %d"), (int) type);
971 
972   data += off;
973   length -= off;
974 
975   if (vallen == 0)
976     fi = NULL;
977   else
978     {
979       unsigned long signature, fiv;
980 
981       if (vallen != 52)
982 	fatal (_("unexpected fixed version information length %ld"), (long) vallen);
983 
984       if (length < 52)
985 	toosmall (_("fixed version info"));
986 
987       signature = windres_get_32 (wrbfd, data, 4);
988       if (signature != 0xfeef04bd)
989 	fatal (_("unexpected fixed version signature %lu"), signature);
990 
991       fiv = windres_get_32 (wrbfd, data + 4, 4);
992       if (fiv != 0 && fiv != 0x10000)
993 	fatal (_("unexpected fixed version info version %lu"), fiv);
994 
995       fi = (rc_fixed_versioninfo *) res_alloc (sizeof (rc_fixed_versioninfo));
996 
997       fi->file_version_ms = windres_get_32 (wrbfd, data + 8, 4);
998       fi->file_version_ls = windres_get_32 (wrbfd, data + 12, 4);
999       fi->product_version_ms = windres_get_32 (wrbfd, data + 16, 4);
1000       fi->product_version_ls = windres_get_32 (wrbfd, data + 20, 4);
1001       fi->file_flags_mask = windres_get_32 (wrbfd, data + 24, 4);
1002       fi->file_flags = windres_get_32 (wrbfd, data + 28, 4);
1003       fi->file_os = windres_get_32 (wrbfd, data + 32, 4);
1004       fi->file_type = windres_get_32 (wrbfd, data + 36, 4);
1005       fi->file_subtype = windres_get_32 (wrbfd, data + 40, 4);
1006       fi->file_date_ms = windres_get_32 (wrbfd, data + 44, 4);
1007       fi->file_date_ls = windres_get_32 (wrbfd, data + 48, 4);
1008 
1009       data += 52;
1010       length -= 52;
1011     }
1012 
1013   first = NULL;
1014   pp = &first;
1015 
1016   while (length > 0)
1017     {
1018       rc_ver_info *vi;
1019       int ch;
1020 
1021       if (length < 8)
1022 	toosmall (_("version var info"));
1023 
1024       vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1025 
1026       ch = windres_get_16 (wrbfd, data + 6, 2);
1027 
1028       if (ch == 'S')
1029 	{
1030 	  rc_ver_stringtable **ppvst;
1031 
1032 	  vi->type = VERINFO_STRING;
1033 
1034 	  get_version_header (wrbfd, data, length, "StringFileInfo",
1035 			      (unichar **) NULL, &verlen, &vallen, &type,
1036 			      &off);
1037 
1038 	  if (vallen != 0)
1039 	    fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1040 
1041 	  data += off;
1042 	  length -= off;
1043 
1044 	  /* It's convenient to round verlen to a 4 byte alignment,
1045              since we round the subvariables in the loop.  */
1046 
1047 	  verlen = (verlen + 3) &~ 3;
1048 
1049 	  vi->u.string.stringtables = NULL;
1050 	  ppvst = &vi->u.string.stringtables;
1051 
1052 	  while (verlen > 0)
1053 	    {
1054 	      rc_ver_stringtable *vst;
1055 	      rc_uint_type stverlen;
1056 	      rc_ver_stringinfo **ppvs;
1057 
1058 	      if (length < 8)
1059 		toosmall (_("version stringtable"));
1060 
1061 	      vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1062 
1063 	      get_version_header (wrbfd, data, length, (const char *) NULL,
1064 				  &vst->language, &stverlen, &vallen, &type, &off);
1065 
1066 	      if (vallen != 0)
1067 		fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1068 
1069 	      data += off;
1070 	      length -= off;
1071 	      verlen -= off;
1072 
1073 	  stverlen = (stverlen + 3) &~ 3;
1074 
1075 	  vst->strings = NULL;
1076 	  ppvs = &vst->strings;
1077 
1078 	  while (stverlen > 0)
1079 	    {
1080 	      rc_ver_stringinfo *vs;
1081 	      rc_uint_type sverlen, vslen, valoff;
1082 
1083 	      if (length < 8)
1084 		toosmall (_("version string"));
1085 
1086 	      vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1087 
1088 	      get_version_header (wrbfd, data, length, (const char *) NULL,
1089 				  &vs->key, &sverlen, &vallen, &type, &off);
1090 
1091 	      sverlen = (sverlen + 3) &~ 3;
1092 
1093 	      data += off;
1094 	      length -= off;
1095 
1096 	      vs->value = get_unicode (wrbfd, data, length, &vslen);
1097 	      valoff = vslen * 2 + 2;
1098 	      valoff = (valoff + 3) &~ 3;
1099 
1100 	      if (off + valoff != sverlen)
1101 		fatal (_("unexpected version string length %ld != %ld + %ld"),
1102 		       (long) sverlen, (long) off, (long) valoff);
1103 
1104 	      data += valoff;
1105 	      length -= valoff;
1106 
1107 	      if (stverlen < sverlen)
1108 		fatal (_("unexpected version string length %ld < %ld"),
1109 		       (long) verlen, (long) sverlen);
1110 	      stverlen -= sverlen;
1111 
1112 	      vs->next = NULL;
1113 	      *ppvs = vs;
1114 	      ppvs = &vs->next;
1115 	    }
1116 
1117 	  vst->next = NULL;
1118 	  *ppvst = vst;
1119 	  ppvst = &vst->next;
1120 	    }
1121 	}
1122       else if (ch == 'V')
1123 	{
1124 	  rc_ver_varinfo **ppvv;
1125 
1126 	  vi->type = VERINFO_VAR;
1127 
1128 	  get_version_header (wrbfd, data, length, "VarFileInfo",
1129 			      (unichar **) NULL, &verlen, &vallen, &type,
1130 			      &off);
1131 
1132 	  if (vallen != 0)
1133 	    fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1134 
1135 	  data += off;
1136 	  length -= off;
1137 
1138 	  get_version_header (wrbfd, data, length, (const char *) NULL,
1139 			      &vi->u.var.key, &verlen, &vallen, &type, &off);
1140 
1141 	  data += off;
1142 	  length -= off;
1143 
1144 	  vi->u.var.var = NULL;
1145 	  ppvv = &vi->u.var.var;
1146 
1147 	  while (vallen > 0)
1148 	    {
1149 	      rc_ver_varinfo *vv;
1150 
1151 	      if (length < 4)
1152 		toosmall (_("version varfileinfo"));
1153 
1154 	      vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1155 
1156 	      vv->language = windres_get_16 (wrbfd, data, 2);
1157 	      vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1158 
1159 	      vv->next = NULL;
1160 	      *ppvv = vv;
1161 	      ppvv = &vv->next;
1162 
1163 	      data += 4;
1164 	      length -= 4;
1165 
1166 	      if (vallen < 4)
1167 		fatal (_("unexpected version value length %ld"), (long) vallen);
1168 
1169 	      vallen -= 4;
1170 	    }
1171 	}
1172       else
1173 	fatal (_("unexpected version string"));
1174 
1175       vi->next = NULL;
1176       *pp = vi;
1177       pp = &vi->next;
1178     }
1179 
1180   v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1181   v->fixed = fi;
1182   v->var = first;
1183 
1184   r = (rc_res_resource *) res_alloc (sizeof *r);
1185   r->type = RES_TYPE_VERSIONINFO;
1186   r->u.versioninfo = v;
1187 
1188   return r;
1189 }
1190 
1191 /* Convert an arbitrary user defined resource from binary.  */
1192 
1193 static rc_res_resource *
1194 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1195 		     rc_uint_type length)
1196 {
1197   rc_rcdata_item *ri;
1198   rc_res_resource *r;
1199 
1200   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1201 
1202   ri->next = NULL;
1203   ri->type = RCDATA_BUFFER;
1204   ri->u.buffer.length = length;
1205   ri->u.buffer.data = data;
1206 
1207   r = (rc_res_resource *) res_alloc (sizeof *r);
1208   r->type = RES_TYPE_USERDATA;
1209   r->u.rcdata = ri;
1210 
1211   return r;
1212 }
1213 
1214 static rc_res_resource *
1215 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1216 {
1217   rc_toolbar *ri;
1218   rc_res_resource *r;
1219   rc_uint_type i;
1220 
1221   ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1222   ri->button_width = windres_get_32 (wrbfd, data, 4);
1223   ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1224   ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1225   ri->items = NULL;
1226 
1227   data += 12;
1228   length -= 12;
1229   for (i=0 ; i < ri->nitems; i++)
1230   {
1231     rc_toolbar_item *it;
1232     it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1233     it->id.named = 0;
1234     it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1235     it->prev = it->next = NULL;
1236     data += 4;
1237     length -= 4;
1238     if(ri->items) {
1239       rc_toolbar_item *ii = ri->items;
1240       while (ii->next != NULL)
1241 	ii = ii->next;
1242       it->prev = ii;
1243       ii->next = it;
1244     }
1245     else
1246       ri->items = it;
1247   }
1248   r = (rc_res_resource *) res_alloc (sizeof *r);
1249   r->type = RES_TYPE_TOOLBAR;
1250   r->u.toolbar = ri;
1251   return r;
1252 }
1253 
1254 
1255 /* Local functions used to convert resources to binary format.  */
1256 
1257 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1258 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1259 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1260 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1261 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1262 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1263 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1264 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1265 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1266 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1267 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1268 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1269 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1270 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1271 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1272 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1273 static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1274 					const bfd_byte *);
1275 
1276 /* Convert a resource to binary.  */
1277 
1278 rc_uint_type
1279 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1280 {
1281   switch (res->type)
1282     {
1283     case RES_TYPE_BITMAP:
1284     case RES_TYPE_FONT:
1285     case RES_TYPE_ICON:
1286     case RES_TYPE_MESSAGETABLE:
1287       return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1288     case RES_TYPE_ACCELERATOR:
1289       return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1290     case RES_TYPE_CURSOR:
1291       return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1292     case RES_TYPE_GROUP_CURSOR:
1293       return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1294     case RES_TYPE_DIALOG:
1295       return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1296     case RES_TYPE_FONTDIR:
1297       return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1298     case RES_TYPE_GROUP_ICON:
1299       return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1300     case RES_TYPE_MENU:
1301       return res_to_bin_menu (wrbfd, off, res->u.menu);
1302     case RES_TYPE_STRINGTABLE:
1303       return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1304     case RES_TYPE_VERSIONINFO:
1305       return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1306     case RES_TYPE_TOOLBAR:
1307       return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1308     case RES_TYPE_USERDATA:
1309     case RES_TYPE_RCDATA:
1310     default:
1311       return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1312     }
1313 }
1314 
1315 /* Convert a resource ID to binary.  This always returns exactly one
1316    bindata structure.  */
1317 
1318 static rc_uint_type
1319 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1320 {
1321   if (! id.named)
1322     {
1323       if (wrbfd)
1324 	{
1325 	  struct bin_res_id bri;
1326 
1327 	  windres_put_16 (wrbfd, bri.sig, 0xffff);
1328 	  windres_put_16 (wrbfd, bri.id, id.u.id);
1329 	  set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1330 	}
1331       off += BIN_RES_ID;
1332     }
1333   else
1334     {
1335       rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1336       if (wrbfd)
1337 	{
1338 	  bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1339 	  rc_uint_type i;
1340 	  for (i = 0; i < len; i++)
1341 	    windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1342 	  windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1343 	  set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1344     }
1345       off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1346     }
1347   return off;
1348 }
1349 
1350 /* Convert a null terminated unicode string to binary.  This always
1351    returns exactly one bindata structure.  */
1352 
1353 static rc_uint_type
1354 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1355 {
1356   rc_uint_type len = 0;
1357 
1358   if (str != NULL)
1359     len = unichar_len (str);
1360 
1361   if (wrbfd)
1362     {
1363       bfd_byte *d;
1364       rc_uint_type i;
1365       d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1366       for (i = 0; i < len; i++)
1367 	windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1368       windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1369       set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1370     }
1371   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1372 
1373   return off;
1374 }
1375 
1376 /* Convert an accelerator resource to binary.  */
1377 
1378 static rc_uint_type
1379 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1380 			const rc_accelerator *accelerators)
1381 {
1382   const rc_accelerator *a;
1383 
1384   for (a = accelerators; a != NULL; a = a->next)
1385     {
1386       if (wrbfd)
1387 	{
1388 	  struct bin_accelerator ba;
1389 
1390 	  windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1391 	  windres_put_16 (wrbfd, ba.key, a->key);
1392 	  windres_put_16 (wrbfd, ba.id, a->id);
1393 	  windres_put_16 (wrbfd, ba.pad, 0);
1394 	  set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1395     }
1396       off += BIN_ACCELERATOR_SIZE;
1397     }
1398   return off;
1399 }
1400 
1401 /* Convert a cursor resource to binary.  */
1402 
1403 static rc_uint_type
1404 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1405 {
1406   if (wrbfd)
1407     {
1408       struct bin_cursor bc;
1409 
1410       windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1411       windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1412       set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1413       if (c->length)
1414 	set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1415     }
1416   off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1417   return off;
1418 }
1419 
1420 /* Convert a group cursor resource to binary.  */
1421 
1422 static rc_uint_type
1423 res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1424 			 const rc_group_cursor *group_cursors)
1425 {
1426   int c = 0;
1427   const rc_group_cursor *gc;
1428   struct bin_group_cursor bgc;
1429   struct bin_group_cursor_item bgci;
1430   rc_uint_type start = off;
1431 
1432   off += BIN_GROUP_CURSOR_SIZE;
1433 
1434   for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1435     {
1436       if (wrbfd)
1437 	{
1438 	  windres_put_16 (wrbfd, bgci.width, gc->width);
1439 	  windres_put_16 (wrbfd, bgci.height, gc->height);
1440 	  windres_put_16 (wrbfd, bgci.planes, gc->planes);
1441 	  windres_put_16 (wrbfd, bgci.bits, gc->bits);
1442 	  windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1443 	  windres_put_16 (wrbfd, bgci.index, gc->index);
1444 	  set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1445     }
1446 
1447       off += BIN_GROUP_CURSOR_ITEM_SIZE;
1448     }
1449   if (wrbfd)
1450     {
1451       windres_put_16 (wrbfd, bgc.sig1, 0);
1452       windres_put_16 (wrbfd, bgc.sig2, 2);
1453       windres_put_16 (wrbfd, bgc.nitems, c);
1454       set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1455     }
1456   return off;
1457 }
1458 
1459 /* Convert a dialog resource to binary.  */
1460 
1461 static rc_uint_type
1462 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1463 {
1464   rc_uint_type off_delta;
1465   rc_uint_type start, marker;
1466   int dialogex;
1467   int c;
1468   rc_dialog_control *dc;
1469   struct bin_dialogex bdx;
1470   struct bin_dialog bd;
1471 
1472   off_delta = off;
1473   start = off;
1474   dialogex = extended_dialog (dialog);
1475 
1476   if (wrbfd)
1477     {
1478   if (! dialogex)
1479     {
1480 	  windres_put_32 (wrbfd, bd.style, dialog->style);
1481 	  windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1482 	  windres_put_16 (wrbfd, bd.x, dialog->x);
1483 	  windres_put_16 (wrbfd, bd.y, dialog->y);
1484 	  windres_put_16 (wrbfd, bd.width, dialog->width);
1485 	  windres_put_16 (wrbfd, bd.height, dialog->height);
1486     }
1487   else
1488     {
1489 	  windres_put_16 (wrbfd, bdx.sig1, 1);
1490 	  windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1491 	  windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1492 	  windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1493 	  windres_put_32 (wrbfd, bdx.style, dialog->style);
1494 	  windres_put_16 (wrbfd, bdx.x, dialog->x);
1495 	  windres_put_16 (wrbfd, bdx.y, dialog->y);
1496 	  windres_put_16 (wrbfd, bdx.width, dialog->width);
1497 	  windres_put_16 (wrbfd, bdx.height, dialog->height);
1498 	}
1499     }
1500 
1501   off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1502 
1503   off = resid_to_bin (wrbfd, off, dialog->menu);
1504   off = resid_to_bin (wrbfd, off, dialog->class);
1505   off = unicode_to_bin (wrbfd, off, dialog->caption);
1506 
1507   if ((dialog->style & DS_SETFONT) != 0)
1508     {
1509       if (wrbfd)
1510 	{
1511 	  if (! dialogex)
1512 	    {
1513 	      struct bin_dialogfont bdf;
1514 	      windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1515 	      set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1516 	    }
1517 	  else
1518 	    {
1519 	      struct bin_dialogexfont bdxf;
1520 	      windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1521 	      windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1522 	      windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1523 	      windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1524 	      set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1525 	    }
1526 	}
1527       off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1528       off = unicode_to_bin (wrbfd, off, dialog->font);
1529     }
1530   for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1531     {
1532       bfd_byte dc_rclen[2];
1533 
1534       off += (4 - ((off - off_delta) & 3)) & 3;
1535       if (wrbfd)
1536 	{
1537       if (! dialogex)
1538 	{
1539 	      struct bin_dialog_control bdc;
1540 
1541 	      windres_put_32 (wrbfd, bdc.style, dc->style);
1542 	      windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1543 	      windres_put_16 (wrbfd, bdc.x, dc->x);
1544 	      windres_put_16 (wrbfd, bdc.y, dc->y);
1545 	      windres_put_16 (wrbfd, bdc.width, dc->width);
1546 	      windres_put_16 (wrbfd, bdc.height, dc->height);
1547 	      windres_put_16 (wrbfd, bdc.id, dc->id);
1548 	      set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1549 	}
1550       else
1551 	{
1552 	      struct bin_dialogex_control bdc;
1553 
1554 	      windres_put_32 (wrbfd, bdc.help, dc->help);
1555 	      windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1556 	      windres_put_32 (wrbfd, bdc.style, dc->style);
1557 	      windres_put_16 (wrbfd, bdc.x, dc->x);
1558 	      windres_put_16 (wrbfd, bdc.y, dc->y);
1559 	      windres_put_16 (wrbfd, bdc.width, dc->width);
1560 	      windres_put_16 (wrbfd, bdc.height, dc->height);
1561 	      windres_put_32 (wrbfd, bdc.id, dc->id);
1562 	      set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1563 	    }
1564 	}
1565       off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1566 
1567       off = resid_to_bin (wrbfd, off, dc->class);
1568       off = resid_to_bin (wrbfd, off, dc->text);
1569 
1570       marker = off; /* Save two bytes for size of optional data.  */
1571       off += 2;
1572 
1573       if (dc->data == NULL)
1574         {
1575 	  if (wrbfd)
1576 	    windres_put_16 (wrbfd, dc_rclen, 0);
1577 	}
1578       else
1579 	{
1580 	  rc_uint_type saved_off = off;
1581 	  rc_uint_type old_off;
1582 	  off += (4 - ((off - off_delta) & 3)) & 3;
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