1 /* resbin.c -- manipulate the Windows binary resource format.
2    Copyright 1997, 1998, 1999, 2002, 2003, 2007
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, read;
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, &read);
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), &read);
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 *read)
274 {
275   rc_menuitem *first, **pp;
276 
277   first = NULL;
278   pp = &first;
279 
280   *read = 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       *read += 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 *read)
351 {
352   rc_menuitem *first, **pp;
353 
354   first = NULL;
355   pp = &first;
356 
357   *read = 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       *read += 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_stringinfo **ppvs;
1031 
1032 	  vi->type = VERINFO_STRING;
1033 
1034 	  get_version_header (wrbfd, data, length, "StringFileInfo",
1035 			      (unichar **) NULL, &verlen, &vallen, &type,
1036 			      &off);
1037 
1038 	  if (vallen != 0)
1039 	    fatal (_("unexpected stringfileinfo value length %ld"), (long) vallen);
1040 
1041 	  data += off;
1042 	  length -= off;
1043 
1044 	  get_version_header (wrbfd, data, length, (const char *) NULL,
1045 			      &vi->u.string.language, &verlen, &vallen,
1046 			      &type, &off);
1047 
1048 	  if (vallen != 0)
1049 	    fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
1050 
1051 	  data += off;
1052 	  length -= off;
1053 	  verlen -= off;
1054 
1055 	  vi->u.string.strings = NULL;
1056 	  ppvs = &vi->u.string.strings;
1057 
1058 	  /* It's convenient to round verlen to a 4 byte alignment,
1059              since we round the subvariables in the loop.  */
1060 	  verlen = (verlen + 3) &~ 3;
1061 
1062 	  while (verlen > 0)
1063 	    {
1064 	      rc_ver_stringinfo *vs;
1065 	      rc_uint_type subverlen, vslen, valoff;
1066 
1067 	      vs = (rc_ver_stringinfo *) res_alloc (sizeof *vs);
1068 
1069 	      get_version_header (wrbfd, data, length,
1070 				  (const char *) NULL, &vs->key, &subverlen,
1071 				  &vallen, &type, &off);
1072 
1073 	      subverlen = (subverlen + 3) &~ 3;
1074 
1075 	      data += off;
1076 	      length -= off;
1077 
1078 	      vs->value = get_unicode (wrbfd, data, length, &vslen);
1079 	      valoff = vslen * 2 + 2;
1080 	      valoff = (valoff + 3) &~ 3;
1081 
1082 	      if (off + valoff != subverlen)
1083 		fatal (_("unexpected version string length %ld != %ld + %ld"),
1084 		       (long) subverlen, (long) off, (long) valoff);
1085 
1086 	      vs->next = NULL;
1087 	      *ppvs = vs;
1088 	      ppvs = &vs->next;
1089 
1090 	      data += valoff;
1091 	      length -= valoff;
1092 
1093 	      if (verlen < subverlen)
1094 		fatal (_("unexpected version string length %ld < %ld"),
1095 		       (long) verlen, (long) subverlen);
1096 
1097 	      verlen -= subverlen;
1098 	    }
1099 	}
1100       else if (ch == 'V')
1101 	{
1102 	  rc_ver_varinfo **ppvv;
1103 
1104 	  vi->type = VERINFO_VAR;
1105 
1106 	  get_version_header (wrbfd, data, length, "VarFileInfo",
1107 			      (unichar **) NULL, &verlen, &vallen, &type,
1108 			      &off);
1109 
1110 	  if (vallen != 0)
1111 	    fatal (_("unexpected varfileinfo value length %ld"), (long) vallen);
1112 
1113 	  data += off;
1114 	  length -= off;
1115 
1116 	  get_version_header (wrbfd, data, length, (const char *) NULL,
1117 			      &vi->u.var.key, &verlen, &vallen, &type, &off);
1118 
1119 	  data += off;
1120 	  length -= off;
1121 
1122 	  vi->u.var.var = NULL;
1123 	  ppvv = &vi->u.var.var;
1124 
1125 	  while (vallen > 0)
1126 	    {
1127 	      rc_ver_varinfo *vv;
1128 
1129 	      if (length < 4)
1130 		toosmall (_("version varfileinfo"));
1131 
1132 	      vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1133 
1134 	      vv->language = windres_get_16 (wrbfd, data, 2);
1135 	      vv->charset = windres_get_16 (wrbfd, data + 2, 2);
1136 
1137 	      vv->next = NULL;
1138 	      *ppvv = vv;
1139 	      ppvv = &vv->next;
1140 
1141 	      data += 4;
1142 	      length -= 4;
1143 
1144 	      if (vallen < 4)
1145 		fatal (_("unexpected version value length %ld"), (long) vallen);
1146 
1147 	      vallen -= 4;
1148 	    }
1149 	}
1150       else
1151 	fatal (_("unexpected version string"));
1152 
1153       vi->next = NULL;
1154       *pp = vi;
1155       pp = &vi->next;
1156     }
1157 
1158   v = (rc_versioninfo *) res_alloc (sizeof (rc_versioninfo));
1159   v->fixed = fi;
1160   v->var = first;
1161 
1162   r = (rc_res_resource *) res_alloc (sizeof *r);
1163   r->type = RES_TYPE_VERSIONINFO;
1164   r->u.versioninfo = v;
1165 
1166   return r;
1167 }
1168 
1169 /* Convert an arbitrary user defined resource from binary.  */
1170 
1171 static rc_res_resource *
1172 bin_to_res_userdata (windres_bfd *wrbfd ATTRIBUTE_UNUSED, const bfd_byte *data,
1173 		     rc_uint_type length)
1174 {
1175   rc_rcdata_item *ri;
1176   rc_res_resource *r;
1177 
1178   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1179 
1180   ri->next = NULL;
1181   ri->type = RCDATA_BUFFER;
1182   ri->u.buffer.length = length;
1183   ri->u.buffer.data = data;
1184 
1185   r = (rc_res_resource *) res_alloc (sizeof *r);
1186   r->type = RES_TYPE_USERDATA;
1187   r->u.rcdata = ri;
1188 
1189   return r;
1190 }
1191 
1192 static rc_res_resource *
1193 bin_to_res_toolbar (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length)
1194 {
1195   rc_toolbar *ri;
1196   rc_res_resource *r;
1197   rc_uint_type i;
1198 
1199   ri = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1200   ri->button_width = windres_get_32 (wrbfd, data, 4);
1201   ri->button_height = windres_get_32 (wrbfd, data + 4, 4);
1202   ri->nitems = windres_get_32 (wrbfd, data + 8, 4);
1203   ri->items = NULL;
1204 
1205   data += 12;
1206   length -= 12;
1207   for (i=0 ; i < ri->nitems; i++)
1208   {
1209     rc_toolbar_item *it;
1210     it = (rc_toolbar_item *) res_alloc (sizeof (rc_toolbar_item));
1211     it->id.named = 0;
1212     it->id.u.id = (int) windres_get_32 (wrbfd, data, 4);
1213     it->prev = it->next = NULL;
1214     data += 4;
1215     length -= 4;
1216     if(ri->items) {
1217       rc_toolbar_item *ii = ri->items;
1218       while (ii->next != NULL)
1219 	ii = ii->next;
1220       it->prev = ii;
1221       ii->next = it;
1222     }
1223     else
1224       ri->items = it;
1225   }
1226   r = (rc_res_resource *) res_alloc (sizeof *r);
1227   r->type = RES_TYPE_TOOLBAR;
1228   r->u.toolbar = ri;
1229   return r;
1230 }
1231 
1232 
1233 /* Local functions used to convert resources to binary format.  */
1234 
1235 static rc_uint_type resid_to_bin (windres_bfd *, rc_uint_type, rc_res_id);
1236 static rc_uint_type unicode_to_bin (windres_bfd *, rc_uint_type, const unichar *);
1237 static rc_uint_type res_to_bin_accelerator (windres_bfd *, rc_uint_type, const rc_accelerator *);
1238 static rc_uint_type res_to_bin_cursor (windres_bfd *, rc_uint_type, const rc_cursor *);
1239 static rc_uint_type res_to_bin_group_cursor (windres_bfd *, rc_uint_type, const rc_group_cursor *);
1240 static rc_uint_type res_to_bin_dialog (windres_bfd *, rc_uint_type, const rc_dialog *);
1241 static rc_uint_type res_to_bin_fontdir (windres_bfd *, rc_uint_type, const rc_fontdir *);
1242 static rc_uint_type res_to_bin_group_icon (windres_bfd *, rc_uint_type, const rc_group_icon *);
1243 static rc_uint_type res_to_bin_menu (windres_bfd *, rc_uint_type, const rc_menu *);
1244 static rc_uint_type res_to_bin_menuitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1245 static rc_uint_type res_to_bin_menuexitems (windres_bfd *, rc_uint_type, const rc_menuitem *);
1246 static rc_uint_type res_to_bin_rcdata (windres_bfd *, rc_uint_type, const rc_rcdata_item *);
1247 static rc_uint_type res_to_bin_stringtable (windres_bfd *, rc_uint_type, const rc_stringtable *);
1248 static rc_uint_type string_to_unicode_bin (windres_bfd *, rc_uint_type, const char *);
1249 static rc_uint_type res_to_bin_toolbar (windres_bfd *, rc_uint_type, rc_toolbar *tb);
1250 static rc_uint_type res_to_bin_versioninfo (windres_bfd *, rc_uint_type, const rc_versioninfo *);
1251 static rc_uint_type res_to_bin_generic (windres_bfd *, rc_uint_type, rc_uint_type,
1252 					const bfd_byte *);
1253 
1254 /* Convert a resource to binary.  */
1255 
1256 rc_uint_type
1257 res_to_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res)
1258 {
1259   switch (res->type)
1260     {
1261     case RES_TYPE_BITMAP:
1262     case RES_TYPE_FONT:
1263     case RES_TYPE_ICON:
1264     case RES_TYPE_MESSAGETABLE:
1265       return res_to_bin_generic (wrbfd, off, res->u.data.length, res->u.data.data);
1266     case RES_TYPE_ACCELERATOR:
1267       return res_to_bin_accelerator (wrbfd, off, res->u.acc);
1268     case RES_TYPE_CURSOR:
1269       return res_to_bin_cursor (wrbfd, off, res->u.cursor);
1270     case RES_TYPE_GROUP_CURSOR:
1271       return res_to_bin_group_cursor (wrbfd, off, res->u.group_cursor);
1272     case RES_TYPE_DIALOG:
1273       return res_to_bin_dialog (wrbfd, off, res->u.dialog);
1274     case RES_TYPE_FONTDIR:
1275       return res_to_bin_fontdir (wrbfd, off, res->u.fontdir);
1276     case RES_TYPE_GROUP_ICON:
1277       return res_to_bin_group_icon (wrbfd, off, res->u.group_icon);
1278     case RES_TYPE_MENU:
1279       return res_to_bin_menu (wrbfd, off, res->u.menu);
1280     case RES_TYPE_STRINGTABLE:
1281       return res_to_bin_stringtable (wrbfd, off, res->u.stringtable);
1282     case RES_TYPE_VERSIONINFO:
1283       return res_to_bin_versioninfo (wrbfd, off, res->u.versioninfo);
1284     case RES_TYPE_TOOLBAR:
1285       return res_to_bin_toolbar (wrbfd, off, res->u.toolbar);
1286     case RES_TYPE_USERDATA:
1287     case RES_TYPE_RCDATA:
1288     default:
1289       return res_to_bin_rcdata (wrbfd, off, res->u.rcdata);
1290     }
1291 }
1292 
1293 /* Convert a resource ID to binary.  This always returns exactly one
1294    bindata structure.  */
1295 
1296 static rc_uint_type
1297 resid_to_bin (windres_bfd *wrbfd, rc_uint_type off, rc_res_id id)
1298 {
1299   if (! id.named)
1300     {
1301       if (wrbfd)
1302 	{
1303 	  struct bin_res_id bri;
1304 
1305 	  windres_put_16 (wrbfd, bri.sig, 0xffff);
1306 	  windres_put_16 (wrbfd, bri.id, id.u.id);
1307 	  set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
1308 	}
1309       off += BIN_RES_ID;
1310     }
1311   else
1312     {
1313       rc_uint_type len = (id.u.n.name ? unichar_len (id.u.n.name) : 0);
1314       if (wrbfd)
1315 	{
1316 	  bfd_byte *d = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1317 	  rc_uint_type i;
1318 	  for (i = 0; i < len; i++)
1319 	    windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id.u.n.name[i]);
1320 	  windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1321 	  set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1322     }
1323       off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1324     }
1325   return off;
1326 }
1327 
1328 /* Convert a null terminated unicode string to binary.  This always
1329    returns exactly one bindata structure.  */
1330 
1331 static rc_uint_type
1332 unicode_to_bin (windres_bfd *wrbfd, rc_uint_type off, const unichar *str)
1333 {
1334   rc_uint_type len = 0;
1335 
1336   if (str != NULL)
1337     len = unichar_len (str);
1338 
1339   if (wrbfd)
1340     {
1341       bfd_byte *d;
1342       rc_uint_type i;
1343       d = (bfd_byte *) reswr_alloc ( (len + 1) * sizeof (unichar));
1344       for (i = 0; i < len; i++)
1345 	windres_put_16 (wrbfd, d + (i * sizeof (unichar)), str[i]);
1346       windres_put_16 (wrbfd, d + (len * sizeof (unichar)), 0);
1347       set_windres_bfd_content (wrbfd, d, off, (len + 1) * sizeof (unichar));
1348     }
1349   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1350 
1351   return off;
1352 }
1353 
1354 /* Convert an accelerator resource to binary.  */
1355 
1356 static rc_uint_type
1357 res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
1358 			const rc_accelerator *accelerators)
1359 {
1360   bindata *first, **pp;
1361   const rc_accelerator *a;
1362 
1363   first = NULL;
1364   pp = &first;
1365 
1366   for (a = accelerators; a != NULL; a = a->next)
1367     {
1368       if (wrbfd)
1369 	{
1370 	  struct bin_accelerator ba;
1371 
1372 	  windres_put_16 (wrbfd, ba.flags, a->flags | (a->next != NULL ? 0 : ACC_LAST));
1373 	  windres_put_16 (wrbfd, ba.key, a->key);
1374 	  windres_put_16 (wrbfd, ba.id, a->id);
1375 	  windres_put_16 (wrbfd, ba.pad, 0);
1376 	  set_windres_bfd_content (wrbfd, &ba, off, BIN_ACCELERATOR_SIZE);
1377     }
1378       off += BIN_ACCELERATOR_SIZE;
1379     }
1380   return off;
1381 }
1382 
1383 /* Convert a cursor resource to binary.  */
1384 
1385 static rc_uint_type
1386 res_to_bin_cursor (windres_bfd *wrbfd, rc_uint_type off, const rc_cursor *c)
1387 {
1388   if (wrbfd)
1389     {
1390       struct bin_cursor bc;
1391 
1392       windres_put_16 (wrbfd, bc.xhotspot, c->xhotspot);
1393       windres_put_16 (wrbfd, bc.yhotspot, c->yhotspot);
1394       set_windres_bfd_content (wrbfd, &bc, off, BIN_CURSOR_SIZE);
1395       if (c->length)
1396 	set_windres_bfd_content (wrbfd, c->data, off + BIN_CURSOR_SIZE, c->length);
1397     }
1398   off = (off + BIN_CURSOR_SIZE + (rc_uint_type) c->length);
1399   return off;
1400 }
1401 
1402 /* Convert a group cursor resource to binary.  */
1403 
1404 static rc_uint_type
1405 res_to_bin_group_cursor (windres_bfd *wrbfd, rc_uint_type off,
1406 			 const rc_group_cursor *group_cursors)
1407 {
1408   int c = 0;
1409   const rc_group_cursor *gc;
1410   struct bin_group_cursor bgc;
1411   struct bin_group_cursor_item bgci;
1412   rc_uint_type start = off;
1413 
1414   off += BIN_GROUP_CURSOR_SIZE;
1415 
1416   for (c = 0, gc = group_cursors; gc != NULL; gc = gc->next, c++)
1417     {
1418       if (wrbfd)
1419 	{
1420 	  windres_put_16 (wrbfd, bgci.width, gc->width);
1421 	  windres_put_16 (wrbfd, bgci.height, gc->height);
1422 	  windres_put_16 (wrbfd, bgci.planes, gc->planes);
1423 	  windres_put_16 (wrbfd, bgci.bits, gc->bits);
1424 	  windres_put_32 (wrbfd, bgci.bytes, gc->bytes);
1425 	  windres_put_16 (wrbfd, bgci.index, gc->index);
1426 	  set_windres_bfd_content (wrbfd, &bgci, off, BIN_GROUP_CURSOR_ITEM_SIZE);
1427     }
1428 
1429       off += BIN_GROUP_CURSOR_ITEM_SIZE;
1430     }
1431   if (wrbfd)
1432     {
1433       windres_put_16 (wrbfd, bgc.sig1, 0);
1434       windres_put_16 (wrbfd, bgc.sig2, 2);
1435       windres_put_16 (wrbfd, bgc.nitems, c);
1436       set_windres_bfd_content (wrbfd, &bgc, start, BIN_GROUP_CURSOR_SIZE);
1437     }
1438   return off;
1439 }
1440 
1441 /* Convert a dialog resource to binary.  */
1442 
1443 static rc_uint_type
1444 res_to_bin_dialog (windres_bfd *wrbfd, rc_uint_type off, const rc_dialog *dialog)
1445 {
1446   rc_uint_type off_delta;
1447   rc_uint_type start, marker;
1448   int dialogex;
1449   int c;
1450   rc_dialog_control *dc;
1451   struct bin_dialogex bdx;
1452   struct bin_dialog bd;
1453 
1454   off_delta = off;
1455   start = off;
1456   dialogex = extended_dialog (dialog);
1457 
1458   if (wrbfd)
1459     {
1460   if (! dialogex)
1461     {
1462 	  windres_put_32 (wrbfd, bd.style, dialog->style);
1463 	  windres_put_32 (wrbfd, bd.exstyle, dialog->exstyle);
1464 	  windres_put_16 (wrbfd, bd.x, dialog->x);
1465 	  windres_put_16 (wrbfd, bd.y, dialog->y);
1466 	  windres_put_16 (wrbfd, bd.width, dialog->width);
1467 	  windres_put_16 (wrbfd, bd.height, dialog->height);
1468     }
1469   else
1470     {
1471 	  windres_put_16 (wrbfd, bdx.sig1, 1);
1472 	  windres_put_16 (wrbfd, bdx.sig2, 0xffff);
1473 	  windres_put_32 (wrbfd, bdx.help, (dialog->ex ? dialog->ex->help : 0));
1474 	  windres_put_32 (wrbfd, bdx.exstyle, dialog->exstyle);
1475 	  windres_put_32 (wrbfd, bdx.style, dialog->style);
1476 	  windres_put_16 (wrbfd, bdx.x, dialog->x);
1477 	  windres_put_16 (wrbfd, bdx.y, dialog->y);
1478 	  windres_put_16 (wrbfd, bdx.width, dialog->width);
1479 	  windres_put_16 (wrbfd, bdx.height, dialog->height);
1480 	}
1481     }
1482 
1483   off += (dialogex != 0 ? BIN_DIALOGEX_SIZE : BIN_DIALOG_SIZE);
1484 
1485   off = resid_to_bin (wrbfd, off, dialog->menu);
1486   off = resid_to_bin (wrbfd, off, dialog->class);
1487   off = unicode_to_bin (wrbfd, off, dialog->caption);
1488 
1489   if ((dialog->style & DS_SETFONT) != 0)
1490     {
1491       if (wrbfd)
1492 	{
1493 	  if (! dialogex)
1494 	    {
1495 	      struct bin_dialogfont bdf;
1496 	      windres_put_16 (wrbfd, bdf.pointsize, dialog->pointsize);
1497 	      set_windres_bfd_content (wrbfd, &bdf, off, BIN_DIALOGFONT_SIZE);
1498 	    }
1499 	  else
1500 	    {
1501 	      struct bin_dialogexfont bdxf;
1502 	      windres_put_16 (wrbfd, bdxf.pointsize, dialog->pointsize);
1503 	      windres_put_16 (wrbfd, bdxf.weight, (dialog->ex == NULL ? 0 : dialog->ex->weight));
1504 	      windres_put_8 (wrbfd, bdxf.italic, (dialog->ex == NULL ? 0 : dialog->ex->italic));
1505 	      windres_put_8 (wrbfd, bdxf.charset, (dialog->ex == NULL ? 1 : dialog->ex->charset));
1506 	      set_windres_bfd_content (wrbfd, &bdxf, off, BIN_DIALOGEXFONT_SIZE);
1507 	    }
1508 	}
1509       off += (dialogex ? BIN_DIALOGEXFONT_SIZE : BIN_DIALOGFONT_SIZE);
1510       off = unicode_to_bin (wrbfd, off, dialog->font);
1511     }
1512   for (c = 0, dc = dialog->controls; dc != NULL; dc = dc->next, c++)
1513     {
1514       bfd_byte dc_rclen[2];
1515 
1516       off += (4 - ((off - off_delta) & 3)) & 3;
1517       if (wrbfd)
1518 	{
1519       if (! dialogex)
1520 	{
1521 	      struct bin_dialog_control bdc;
1522 
1523 	      windres_put_32 (wrbfd, bdc.style, dc->style);
1524 	      windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1525 	      windres_put_16 (wrbfd, bdc.x, dc->x);
1526 	      windres_put_16 (wrbfd, bdc.y, dc->y);
1527 	      windres_put_16 (wrbfd, bdc.width, dc->width);
1528 	      windres_put_16 (wrbfd, bdc.height, dc->height);
1529 	      windres_put_16 (wrbfd, bdc.id, dc->id);
1530 	      set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOG_CONTROL_SIZE);
1531 	}
1532       else
1533 	{
1534 	      struct bin_dialogex_control bdc;
1535 
1536 	      windres_put_32 (wrbfd, bdc.help, dc->help);
1537 	      windres_put_32 (wrbfd, bdc.exstyle, dc->exstyle);
1538 	      windres_put_32 (wrbfd, bdc.style, dc->style);
1539 	      windres_put_16 (wrbfd, bdc.x, dc->x);
1540 	      windres_put_16 (wrbfd, bdc.y, dc->y);
1541 	      windres_put_16 (wrbfd, bdc.width, dc->width);
1542 	      windres_put_16 (wrbfd, bdc.height, dc->height);
1543 	      windres_put_32 (wrbfd, bdc.id, dc->id);
1544 	      set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
1545 	    }
1546 	}
1547       off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
1548 
1549       off = resid_to_bin (wrbfd, off, dc->class);
1550       off = resid_to_bin (wrbfd, off, dc->text);
1551 
1552       marker = off; /* Save two bytes for size of optional data.  */
1553       off += 2;
1554 
1555       if (dc->data == NULL)
1556         {
1557 	  if (wrbfd)
1558 	    windres_put_16 (wrbfd, dc_rclen, 0);
1559 	}
1560       else
1561 	{
1562 	  rc_uint_type saved_off = off;
1563 	  rc_uint_type old_off;
1564 	  off += (4 - ((off - off_delta) & 3)) & 3;
1565 
1566 	  old_off = off;
1567 	  off = res_to_bin_rcdata (wrbfd, off, dc->data);
1568 	  if ((off - old_off) == 0)
1569 	    old_off = off = saved_off;
1570 	  if (wrbfd)
1571 	    windres_put_16 (wrbfd, dc_rclen, off - old_off);
1572 	    }
1573       if (wrbfd)
1574 	set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
1575 	}
1576 
1577   if (wrbfd)
1578     {
1579       windres_put_16 (wrbfd, (dialogex != 0 ? bdx.off : bd.off), c);
1580       if (! dialogex)
1581 	set_windres_bfd_content (wrbfd, &bd, start, BIN_DIALOG_SIZE);
1582       else
1583 	set_windres_bfd_content (wrbfd, &bdx, start, BIN_DIALOGEX_SIZE);
1584     }
1585 
1586   return off;
1587 }
1588 
1589 /* Convert a fontdir resource to binary.  */
1590 static rc_uint_type
1591 res_to_bin_fontdir (windres_bfd *wrbfd, rc_uint_type off, const rc_fontdir *fontdirs)
1592 {
1593   rc_uint_type start;
1594   int c;
1595   const rc_fontdir *fd;
1596 
1597   start = off;
1598   off += 2;
1599 
1600   for (c = 0, fd = fontdirs; fd != NULL; fd = fd->next, c++)
1601     {
1602       if (wrbfd)
1603 	{
1604 	  bfd_byte d[2];
1605 	  windres_put_16 (wrbfd, d, fd->index);
1606 	  set_windres_bfd_content (wrbfd, d, off, 2);
1607 	  if (fd->length)
1608 	    set_windres_bfd_content (wrbfd, fd->data, off + 2, fd->length);
1609 	}
1610       off += (rc_uint_type) fd->length + 2;
1611     }
1612 
1613   if (wrbfd)
1614     {
1615       bfd_byte d[2];
1616       windres_put_16 (wrbfd, d, c);
1617       set_windres_bfd_content (wrbfd, d, start, 2);
1618     }
1619   return off;
1620 }
1621 
1622 /* Convert a group icon resource to binary.  */
1623 
1624 static rc_uint_type
1625 res_to_bin_group_icon (windres_bfd *wrbfd, rc_uint_type off, const rc_group_icon *group_icons)
1626 {
1627   rc_uint_type start;
1628   struct bin_group_icon bgi;
1629   int c;
1630   const rc_group_icon *gi;
1631 
1632   start = off;
1633   off += BIN_GROUP_ICON_SIZE;
1634 
1635   for (c = 0, gi = group_icons; gi != NULL; gi = gi->next, c++)
1636     {
1637       struct bin_group_icon_item bgii;
1638 
1639       if (wrbfd)
1640 	{
1641 	  windres_put_8 (wrbfd, bgii.width, gi->width);
1642 	  windres_put_8 (wrbfd, bgii.height, gi->height);
1643 	  windres_put_8 (wrbfd, bgii.colors, gi->colors);
1644 	  windres_put_8 (wrbfd, bgii.pad, 0);
1645 	  windres_put_16 (wrbfd, bgii.planes, gi->planes);
1646 	  windres_put_16 (wrbfd, bgii.bits, gi->bits);
1647 	  windres_put_32 (wrbfd, bgii.bytes, gi->bytes);
1648 	  windres_put_16 (wrbfd, bgii.index, gi->index);
1649 	  set_windres_bfd_content (wrbfd, &bgii, off, BIN_GROUP_ICON_ITEM_SIZE);
1650 	}
1651       off += BIN_GROUP_ICON_ITEM_SIZE;
1652     }
1653 
1654   if (wrbfd)
1655     {
1656       windres_put_16 (wrbfd, bgi.sig1, 0);
1657       windres_put_16 (wrbfd, bgi.sig2, 1);
1658       windres_put_16 (wrbfd, bgi.count, c);
1659       set_windres_bfd_content (wrbfd, &bgi, start, BIN_GROUP_ICON_SIZE);
1660     }
1661   return off;
1662 }
1663 
1664 /* Convert a menu resource to binary.  */
1665 
1666 static rc_uint_type
1667 res_to_bin_menu (windres_bfd *wrbfd, rc_uint_type off, const rc_menu *menu)
1668 {
1669   int menuex;
1670 
1671   menuex = extended_menu (menu);
1672 
1673   if (wrbfd)
1674     {
1675   if (! menuex)
1676     {
1677 	  struct bin_menu bm;
1678 	  windres_put_16 (wrbfd, bm.sig1, 0);
1679 	  windres_put_16 (wrbfd, bm.sig2, 0);
1680 	  set_windres_bfd_content (wrbfd, &bm, off, BIN_MENU_SIZE);
1681     }
1682   else
1683     {
1684 	  struct bin_menuex bm;
1685 	  windres_put_16 (wrbfd, bm.sig1, 1);
1686 	  windres_put_16 (wrbfd, bm.sig2, 4);
1687 	  windres_put_32 (wrbfd, bm.help, menu->help);
1688 	  set_windres_bfd_content (wrbfd, &bm, off, BIN_MENUEX_SIZE);
1689     }
1690     }
1691   off += (menuex != 0 ? BIN_MENUEX_SIZE : BIN_MENU_SIZE);
1692   if (! menuex)
1693     {
1694       off = res_to_bin_menuitems (wrbfd, off, menu->items);
1695     }
1696   else
1697     {
1698       off = res_to_bin_menuexitems (wrbfd, off, menu->items);
1699     }
1700   return off;
1701 }
1702 
1703 /* Convert menu items to binary.  */
1704 
1705 static rc_uint_type
1706 res_to_bin_menuitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1707 {
1708   const rc_menuitem *mi;
1709 
1710   for (mi = items; mi != NULL; mi = mi->next)
1711     {
1712       struct bin_menuitem bmi;
1713       int flags;
1714 
1715       flags = mi->type;
1716       if (mi->next == NULL)
1717 	flags |= MENUITEM_ENDMENU;
1718       if (mi->popup != NULL)
1719 	flags |= MENUITEM_POPUP;
1720 
1721       if (wrbfd)
1722 	{
1723 	  windres_put_16 (wrbfd, bmi.flags, flags);
1724       if (mi->popup == NULL)
1725 	    windres_put_16 (wrbfd, bmi.id, mi->id);
1726 	  set_windres_bfd_content (wrbfd, &bmi, off,
1727 				   mi->popup == NULL ? BIN_MENUITEM_SIZE
1728 				   		     : BIN_MENUITEM_POPUP_SIZE);
1729 	}
1730       off += (mi->popup == NULL ? BIN_MENUITEM_SIZE : BIN_MENUITEM_POPUP_SIZE);
1731 
1732       off = unicode_to_bin (wrbfd, off, mi->text);
1733 
1734       if (mi->popup != NULL)
1735 	{
1736 	  off = res_to_bin_menuitems (wrbfd, off, mi->popup);
1737 	}
1738     }
1739   return off;
1740 }
1741 
1742 /* Convert menuex items to binary.  */
1743 
1744 static rc_uint_type
1745 res_to_bin_menuexitems (windres_bfd *wrbfd, rc_uint_type off, const rc_menuitem *items)
1746 {
1747   rc_uint_type off_delta = off;
1748   const rc_menuitem *mi;
1749 
1750   for (mi = items; mi != NULL; mi = mi->next)
1751     {
1752       struct bin_menuitemex bmi;
1753       int flags;
1754 
1755       off += (4 - ((off - off_delta) & 3)) & 3;
1756 
1757       flags = 0;
1758       if (mi->next == NULL)
1759 	flags |= 0x80;
1760       if (mi->popup != NULL)
1761 	flags |= 1;
1762 
1763       if (wrbfd)
1764 	{
1765 	  windres_put_32 (wrbfd, bmi.type, mi->type);
1766 	  windres_put_32 (wrbfd, bmi.state, mi->state);
1767 	  windres_put_32 (wrbfd, bmi.id, mi->id);
1768 	  windres_put_16 (wrbfd, bmi.flags, flags);
1769 	  set_windres_bfd_content (wrbfd, &bmi, off, BIN_MENUITEMEX_SIZE);
1770 	}
1771       off += BIN_MENUITEMEX_SIZE;
1772 
1773       off = unicode_to_bin (wrbfd, off, mi->text);
1774 
1775       if (mi->popup != NULL)
1776 	{
1777 	  bfd_byte help[4];
1778 
1779 	  off += (4 - ((off - off_delta) & 3)) & 3;
1780 
1781 	  if (wrbfd)
1782 	    {
1783 	      windres_put_32 (wrbfd, help, mi->help);
1784 	      set_windres_bfd_content (wrbfd, help, off, 4);
1785 	    }
1786 	  off += 4;
1787 	  off = res_to_bin_menuexitems (wrbfd, off, mi->popup);
1788 	}
1789     }
1790   return off;
1791 }
1792 
1793 /* Convert an rcdata resource to binary.  This is also used to convert
1794    other information which happens to be stored in rc_rcdata_item lists
1795    to binary.  */
1796 
1797 static rc_uint_type
1798 res_to_bin_rcdata (windres_bfd *wrbfd, rc_uint_type off, const rc_rcdata_item *items)
1799 {
1800   const rc_rcdata_item *ri;
1801 
1802   for (ri = items; ri != NULL; ri = ri->next)
1803     {
1804       rc_uint_type len;
1805       switch (ri->type)
1806 	{
1807 	default:
1808 	  abort ();
1809 	case RCDATA_WORD:
1810 	  len = 2;
1811 	  break;
1812 	case RCDATA_DWORD:
1813 	  len = 4;
1814 	  break;
1815 	case RCDATA_STRING:
1816 	  len = ri->u.string.length;
1817 	  break;
1818 	case RCDATA_WSTRING:
1819 	  len = ri->u.wstring.length * sizeof (unichar);
1820 	  break;
1821 	case RCDATA_BUFFER:
1822 	  len = ri->u.buffer.length;
1823 	  break;
1824 	}
1825       if (wrbfd)
1826 	{
1827 	  bfd_byte h[4];
1828 	  bfd_byte *hp = &h[0];
1829 	  switch (ri->type)
1830 	    {
1831 	    case RCDATA_WORD:
1832 	      windres_put_16 (wrbfd, hp, ri->u.word);
1833 	      break;
1834 	    case RCDATA_DWORD:
1835 	      windres_put_32 (wrbfd, hp, ri->u.dword);
1836 	      break;
1837 	    case RCDATA_STRING:
1838 	      hp = (bfd_byte *) ri->u.string.s;
1839 	  break;
1840 	case RCDATA_WSTRING:
1841 	  {
1842 		rc_uint_type i;
1843 
1844 		hp = (bfd_byte *) reswr_alloc (len);
1845 	    for (i = 0; i < ri->u.wstring.length; i++)
1846 		  windres_put_16 (wrbfd, hp + i * sizeof (unichar), ri->u.wstring.w[i]);
1847 	  }
1848 	      break;
1849 	case RCDATA_BUFFER:
1850 	      hp = (bfd_byte *) ri->u.buffer.data;
1851 	  break;
1852 	}
1853 	  set_windres_bfd_content (wrbfd, hp, off, len);
1854     }
1855       off += len;
1856     }
1857   return off;
1858 }
1859 
1860 /* Convert a stringtable resource to binary.  */
1861 
1862 static rc_uint_type
1863 res_to_bin_stringtable (windres_bfd *wrbfd, rc_uint_type off,
1864 			const rc_stringtable *st)
1865 {
1866   int i;
1867 
1868   for (i = 0; i < 16; i++)
1869     {
1870       rc_uint_type slen, length;
1871       unichar *s;
1872 
1873       slen = (rc_uint_type) st->strings[i].length;
1874       s = st->strings[i].string;
1875 
1876       length = 2 + slen * 2;
1877       if (wrbfd)
1878 	{
1879 	  bfd_byte *hp;
1880 	  rc_uint_type j;
1881 
1882 	  hp = (bfd_byte *) reswr_alloc (length);
1883 	  windres_put_16 (wrbfd, hp, slen);
1884 
1885       for (j = 0; j < slen; j++)
1886 	    windres_put_16 (wrbfd, hp + 2 + j * 2, s[j]);
1887 	  set_windres_bfd_content (wrbfd, hp, off, length);
1888     }
1889       off += length;
1890     }
1891   return off;
1892 }
1893 
1894 /* Convert an ASCII string to a unicode binary string.  This always
1895    returns exactly one bindata structure.  */
1896 
1897 static rc_uint_type
1898 string_to_unicode_bin (windres_bfd *wrbfd, rc_uint_type off, const char *s)
1899 {
1900   rc_uint_type len;
1901 
1902   len = (rc_uint_type) strlen (s);
1903 
1904   if (wrbfd)
1905     {
1906       rc_uint_type i;
1907       bfd_byte *hp;
1908 
1909       hp = (bfd_byte *) reswr_alloc ((len + 1) * sizeof (unichar));
1910 
1911       for (i = 0; i < len; i++)
1912 	windres_put_16 (wrbfd, hp + i * 2, s[i]);
1913       windres_put_16 (wrbfd, hp + i * 2, 0);
1914       set_windres_bfd_content (wrbfd, hp, off, (len + 1) * sizeof (unichar));
1915     }
1916   off += (rc_uint_type) ((len + 1) * sizeof (unichar));
1917   return off;
1918 }
1919 
1920 static rc_uint_type
1921 res_to_bin_toolbar (windres_bfd *wrbfd, rc_uint_type off, rc_toolbar *tb)
1922 {
1923   if (wrbfd)
1924     {
1925       struct bin_toolbar bt;
1926       windres_put_32 (wrbfd, bt.button_width, tb->button_width);
1927       windres_put_32 (wrbfd, bt.button_height, tb->button_height);
1928       windres_put_32 (wrbfd, bt.nitems, tb->nitems);
1929       set_windres_bfd_content (wrbfd, &bt, off, BIN_TOOLBAR_SIZE);
1930       if (tb->nitems > 0)
1931 	{
1932 	  rc_toolbar_item *it;
1933 	  bfd_byte *ids;
1934 	  rc_uint_type i = 0;
1935 
1936 	  ids = (bfd_byte *) reswr_alloc (tb->nitems * 4);
1937 	  it=tb->items;
1938 	  while(it != NULL)
1939 	    {
1940 	      windres_put_32 (wrbfd, ids + i, it->id.u.id);
1941 	      i += 4;
1942 	      it = it->next;
1943 	    }
1944 	  set_windres_bfd_content (wrbfd, ids, off + BIN_TOOLBAR_SIZE, i);
1945  	}
1946     }
1947   off += BIN_TOOLBAR_SIZE + tb->nitems * 4;
1948 
1949   return off;
1950 }
1951 
1952 /* Convert a versioninfo resource to binary.  */
1953 
1954 static rc_uint_type
1955 res_to_bin_versioninfo (windres_bfd *wrbfd, rc_uint_type off,
1956 			const rc_versioninfo *versioninfo)
1957 {
1958   rc_uint_type off_delta = off;
1959   rc_uint_type start;
1960   struct bin_versioninfo bvi;
1961   rc_ver_info *vi;
1962 
1963   start = off;
1964   off += BIN_VERSIONINFO_SIZE;
1965   off = string_to_unicode_bin (wrbfd, off, "VS_VERSION_INFO");
1966   off += (4 - ((off - off_delta) & 3)) & 3;
1967 
1968   if (versioninfo->fixed != NULL)
1969     {
1970       if (wrbfd)
1971 	{
1972 	  struct bin_fixed_versioninfo bfv;
1973 	  const rc_fixed_versioninfo *fi;
1974 
1975       fi = versioninfo->fixed;
1976 	  windres_put_32 (wrbfd, bfv.sig1, 0xfeef04bd);
1977 	  windres_put_32 (wrbfd, bfv.sig2, 0x10000);
1978 	  windres_put_32 (wrbfd, bfv.file_version, fi->file_version_ms);
1979 	  windres_put_32 (wrbfd, bfv.file_version_ls, fi->file_version_ls);
1980 	  windres_put_32 (wrbfd, bfv.product_version_ms, fi->product_version_ms);
1981 	  windres_put_32 (wrbfd, bfv.product_version_ls, fi->product_version_ls);
1982 	  windres_put_32 (wrbfd, bfv.file_flags_mask, fi->file_flags_mask);
1983 	  windres_put_32 (wrbfd, bfv.file_flags, fi->file_flags);
1984 	  windres_put_32 (wrbfd, bfv.file_os, fi->file_os);
1985 	  windres_put_32 (wrbfd, bfv.file_type, fi->file_type);
1986 	  windres_put_32 (wrbfd, bfv.file_subtype, fi->file_subtype);
1987 	  windres_put_32 (wrbfd, bfv.file_date_ms, fi->file_date_ms);
1988 	  windres_put_32 (wrbfd, bfv.file_date_ls, fi->file_date_ls);
1989 	  set_windres_bfd_content (wrbfd, &bfv, off, BIN_FIXED_VERSIONINFO_SIZE);
1990 	}
1991       off += BIN_FIXED_VERSIONINFO_SIZE;
1992     }
1993 
1994   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
1995     {
1996       struct bin_ver_info bv;
1997       rc_uint_type bv_off;
1998 
1999       off += (4 - ((off - off_delta) & 3)) & 3;
2000 
2001       bv_off = off;
2002 
2003       off += BIN_VER_INFO_SIZE;
2004 
2005       switch (vi->type)
2006 	{
2007 	default:
2008 	  abort ();
2009 	case VERINFO_STRING:
2010 	  {
2011 	    struct bin_ver_info bvsd;
2012 	    rc_uint_type vs_off;
2013 	    const rc_ver_stringinfo *vs;
2014 
2015 	    off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
2016 	    off += (4 - ((off - off_delta) & 3)) & 3;
2017 
2018 	    vs_off = off;
2019 
2020 	    off += BIN_VER_INFO_SIZE;
2021 
2022 	    off = unicode_to_bin (wrbfd, off, vi->u.string.language);
2023 
2024 	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2025 	      {
2026 		struct bin_ver_info bvss;
2027 		rc_uint_type vss_off,str_off;
2028 
2029 		off += (4 - ((off - off_delta) & 3)) & 3;
2030 
2031 		vss_off = off;
2032 		off += BIN_VER_INFO_SIZE;
2033 
2034 		off = unicode_to_bin (wrbfd, off, vs->key);
2035 
2036 		off += (4 - ((off - off_delta) & 3)) & 3;
2037 
2038 		str_off = off;
2039 		off = unicode_to_bin (wrbfd, off, vs->value);
2040 		if (wrbfd)
2041 		  {
2042 		    windres_put_16 (wrbfd, bvss.size, off - vss_off);
2043 		    windres_put_16 (wrbfd, bvss.sig1, (off - str_off) / 2);
2044 		    windres_put_16 (wrbfd, bvss.sig2, 1);
2045 		    set_windres_bfd_content (wrbfd, &bvss, vss_off,
2046 		    			     BIN_VER_INFO_SIZE);
2047 		  }
2048 	      }
2049 	    if (wrbfd)
2050 	      {
2051 		windres_put_16 (wrbfd, bvsd.size, off - vs_off);
2052 		windres_put_16 (wrbfd, bvsd.sig1, 0);
2053 		windres_put_16 (wrbfd, bvsd.sig2, 0);
2054 		set_windres_bfd_content (wrbfd, &bvsd, vs_off,
2055 					 BIN_VER_INFO_SIZE);
2056 	      }
2057 	    break;
2058 	  }
2059 
2060 	case VERINFO_VAR:
2061 	  {
2062 	    rc_uint_type vvd_off, vvvd_off;
2063 	    struct bin_ver_info bvvd;
2064 	    const rc_ver_varinfo *vv;
2065 
2066 	    off = string_to_unicode_bin (wrbfd, off, "VarFileInfo");
2067 
2068 	    off += (4 - ((off - off_delta) & 3)) & 3;
2069 
2070 	    vvd_off = off;
2071 	    off += BIN_VER_INFO_SIZE;
2072 
2073 	    off = unicode_to_bin (wrbfd, off, vi->u.var.key);
2074 
2075 	    off += (4 - ((off - off_delta) & 3)) & 3;
2076 
2077 	    vvvd_off = off;
2078 
2079 	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2080 	      {
2081 		if (wrbfd)
2082 		  {
2083 		    bfd_byte vvsd[4];
2084 
2085 		    windres_put_16 (wrbfd, &vvsd[0], vv->language);
2086 		    windres_put_16 (wrbfd, &vvsd[2], vv->charset);
2087 		    set_windres_bfd_content (wrbfd, vvsd, off, 4);
2088 		  }
2089 		off += 4;
2090 	      }
2091 	    if (wrbfd)
2092 	    {
2093 		windres_put_16 (wrbfd, bvvd.size, off - vvd_off);
2094 		windres_put_16 (wrbfd, bvvd.sig1, off - vvvd_off);
2095 		windres_put_16 (wrbfd, bvvd.sig2, 0);
2096 		set_windres_bfd_content (wrbfd, &bvvd, vvd_off,
2097 					 BIN_VER_INFO_SIZE);
2098 	    }
2099 
2100 	    break;
2101 	  }
2102 	}
2103 
2104       if (wrbfd)
2105 	{
2106 	  windres_put_16 (wrbfd, bv.size, off-bv_off);
2107 	  windres_put_16 (wrbfd, bv.sig1, 0);
2108 	  windres_put_16 (wrbfd, bv.sig2, 0);
2109 	  set_windres_bfd_content (wrbfd, &bv, bv_off,
2110 	  			   BIN_VER_INFO_SIZE);
2111 	}
2112     }
2113 
2114   if (wrbfd)
2115     {
2116       windres_put_16 (wrbfd, bvi.size, off - start);
2117       windres_put_16 (wrbfd, bvi.fixed_size,
2118 		      versioninfo->fixed == NULL ? 0
2119 		      				 : BIN_FIXED_VERSIONINFO_SIZE);
2120       windres_put_16 (wrbfd, bvi.sig2, 0);
2121       set_windres_bfd_content (wrbfd, &bvi, start, BIN_VER_INFO_SIZE);
2122     }
2123   return off;
2124 }
2125 
2126 /* Convert a generic resource to binary.  */
2127 
2128 static rc_uint_type
2129 res_to_bin_generic (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type length,
2130 		    const bfd_byte *data)
2131 {
2132   if (wrbfd && length != 0)
2133     set_windres_bfd_content (wrbfd, data, off, length);
2134   return off + (rc_uint_type) length;
2135 }
2136