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