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