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