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