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