(root)/
binutils-2.41/
binutils/
resres.c
       1  /* resres.c: read_res_file and write_res_file implementation for windres.
       2     Copyright (C) 1998-2023 Free Software Foundation, Inc.
       3     Written by Anders Norlander <anorland@hem2.passagen.se>.
       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  /* FIXME: This file does not work correctly in a cross configuration.
      24     It assumes that it can use fread and fwrite to read and write
      25     integers.  It does no swapping.  */
      26  
      27  #include "sysdep.h"
      28  #include "bfd.h"
      29  #include "bucomm.h"
      30  #include "libiberty.h"
      31  #include "windres.h"
      32  
      33  #include <assert.h>
      34  
      35  static rc_uint_type write_res_directory (windres_bfd *, rc_uint_type,
      36  				    	 const rc_res_directory *, const rc_res_id *,
      37  				    	 const rc_res_id *, rc_uint_type *, int);
      38  static rc_uint_type write_res_resource (windres_bfd *, rc_uint_type,const rc_res_id *,
      39  				   	const rc_res_id *, const rc_res_resource *,
      40  				   	rc_uint_type *);
      41  static rc_uint_type write_res_bin (windres_bfd *, rc_uint_type, const rc_res_resource *,
      42  				   const rc_res_id *, const rc_res_id *,
      43  				   const rc_res_res_info *);
      44  
      45  static rc_uint_type write_res_id (windres_bfd *, rc_uint_type, const rc_res_id *);
      46  static rc_uint_type write_res_info (windres_bfd *, rc_uint_type, const rc_res_res_info *);
      47  static rc_uint_type write_res_data_hdr (windres_bfd *, rc_uint_type, res_hdr *);
      48  
      49  static rc_uint_type write_res_header (windres_bfd *, rc_uint_type, rc_uint_type,
      50  				      const rc_res_id *, const rc_res_id *,
      51  				      const rc_res_res_info *);
      52  
      53  static int read_resource_entry (windres_bfd *, rc_uint_type *, rc_uint_type);
      54  static void read_res_data (windres_bfd *, rc_uint_type *, rc_uint_type, void *,
      55  			   rc_uint_type);
      56  static void read_res_data_hdr (windres_bfd *, rc_uint_type *, rc_uint_type, res_hdr *);
      57  static void read_res_id (windres_bfd *, rc_uint_type *, rc_uint_type, rc_res_id *);
      58  static unichar *read_unistring (windres_bfd *, rc_uint_type *, rc_uint_type, rc_uint_type *);
      59  static void skip_null_resource (windres_bfd *, rc_uint_type *, rc_uint_type);
      60  static int probe_binary (windres_bfd *wrbfd, rc_uint_type);
      61  
      62  static unsigned long get_id_size (const rc_res_id *);
      63  
      64  static void res_add_resource (rc_res_resource *, const rc_res_id *,
      65  			      const rc_res_id *, rc_uint_type, int);
      66  
      67  static void res_append_resource (rc_res_directory **, rc_res_resource *,
      68  				 int, const rc_res_id *, int);
      69  
      70  static rc_res_directory *resources = NULL;
      71  
      72  static const char *filename;
      73  
      74  extern char *program_name;
      75  
      76  /* Read resource file */
      77  rc_res_directory *
      78  read_res_file (const char *fn)
      79  {
      80    rc_uint_type off, flen;
      81    windres_bfd wrbfd;
      82    bfd *abfd;
      83    asection *sec;
      84    filename = fn;
      85  
      86    flen = (rc_uint_type) get_file_size (filename);
      87    if (! flen)
      88      fatal ("can't open '%s' for input.", filename);
      89    abfd = windres_open_as_binary (filename, 1);
      90    sec = bfd_get_section_by_name (abfd, ".data");
      91    if (sec == NULL)
      92      bfd_fatal ("bfd_get_section_by_name");
      93    set_windres_bfd (&wrbfd, abfd, sec,
      94  		   (target_is_bigendian ? WR_KIND_BFD_BIN_B
      95  					: WR_KIND_BFD_BIN_L));
      96    off = 0;
      97  
      98    if (! probe_binary (&wrbfd, flen))
      99      set_windres_bfd_endianness (&wrbfd, ! target_is_bigendian);
     100  
     101    skip_null_resource (&wrbfd, &off, flen);
     102  
     103    while (read_resource_entry (&wrbfd, &off, flen))
     104      ;
     105  
     106    bfd_close (abfd);
     107  
     108    return resources;
     109  }
     110  
     111  /* Write resource file */
     112  void
     113  write_res_file (const char *fn,const rc_res_directory *resdir)
     114  {
     115    asection *sec;
     116    rc_uint_type language;
     117    bfd *abfd;
     118    windres_bfd wrbfd;
     119    unsigned long sec_length = 0,sec_length_wrote;
     120    static const bfd_byte sign[] =
     121    {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
     122     0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
     123     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     124     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
     125  
     126    filename = fn;
     127  
     128    abfd = windres_open_as_binary (filename, 0);
     129    sec = bfd_make_section_with_flags (abfd, ".data",
     130  				     (SEC_HAS_CONTENTS | SEC_ALLOC
     131  				      | SEC_LOAD | SEC_DATA));
     132    if (sec == NULL)
     133      bfd_fatal ("bfd_make_section");
     134    /* Requiring this is probably a bug in BFD.  */
     135    sec->output_section = sec;
     136  
     137    set_windres_bfd (&wrbfd, abfd, sec,
     138  		   (target_is_bigendian ? WR_KIND_BFD_BIN_B
     139  					: WR_KIND_BFD_BIN_L));
     140  
     141    language = -1;
     142    sec_length = write_res_directory ((windres_bfd *) NULL, 0x20UL, resdir,
     143  				    (const rc_res_id *) NULL,
     144  				    (const rc_res_id *) NULL, &language, 1);
     145    if (!bfd_set_section_size (sec, (sec_length + 3) & ~3))
     146      bfd_fatal ("bfd_set_section_size");
     147    if ((sec_length & 3) != 0)
     148      set_windres_bfd_content (&wrbfd, sign, sec_length, 4-(sec_length & 3));
     149    set_windres_bfd_content (&wrbfd, sign, 0, sizeof (sign));
     150    language = -1;
     151    sec_length_wrote = write_res_directory (&wrbfd, 0x20UL, resdir,
     152  					  (const rc_res_id *) NULL,
     153  					  (const rc_res_id *) NULL,
     154  					  &language, 1);
     155    if (sec_length != sec_length_wrote)
     156      fatal ("res write failed with different sizes (%lu/%lu).",
     157  	   (unsigned long) sec_length, (unsigned long) sec_length_wrote);
     158  
     159    bfd_close (abfd);
     160    return;
     161  }
     162  
     163  /* Read a resource entry, returns 0 when all resources are read */
     164  static int
     165  read_resource_entry (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
     166  {
     167    rc_res_id type;
     168    rc_res_id name;
     169    rc_res_res_info resinfo;
     170    res_hdr reshdr;
     171    void *buff;
     172  
     173    rc_res_resource *r;
     174    struct bin_res_info l;
     175  
     176    off[0] = (off[0] + 3) & ~3;
     177  
     178    /* Read header */
     179    if ((off[0] + 8) > omax)
     180      return 0;
     181    read_res_data_hdr (wrbfd, off, omax, &reshdr);
     182  
     183    /* read resource type */
     184    read_res_id (wrbfd, off, omax, &type);
     185    /* read resource id */
     186    read_res_id (wrbfd, off, omax, &name);
     187  
     188    off[0] = (off[0] + 3) & ~3;
     189  
     190    /* Read additional resource header */
     191    read_res_data (wrbfd, off, omax, &l, BIN_RES_INFO_SIZE);
     192    resinfo.version = windres_get_32 (wrbfd, l.version, 4);
     193    resinfo.memflags = windres_get_16 (wrbfd, l.memflags, 2);
     194    resinfo.language = windres_get_16 (wrbfd, l.language, 2);
     195    /* resinfo.version2 = windres_get_32 (wrbfd, l.version2, 4); */
     196    resinfo.characteristics = windres_get_32 (wrbfd, l.characteristics, 4);
     197  
     198    off[0] = (off[0] + 3) & ~3;
     199  
     200    /* Allocate buffer for data */
     201    buff = res_alloc (reshdr.data_size);
     202    /* Read data */
     203    read_res_data (wrbfd, off, omax, buff, reshdr.data_size);
     204    /* Convert binary data to resource */
     205    r = bin_to_res (wrbfd, type, buff, reshdr.data_size);
     206    r->res_info = resinfo;
     207    /* Add resource to resource directory */
     208    res_add_resource (r, &type, &name, resinfo.language, 0);
     209  
     210    return 1;
     211  }
     212  
     213  /* write resource directory to binary resource file */
     214  static rc_uint_type
     215  write_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_directory *rd,
     216  		     const rc_res_id *type, const rc_res_id *name, rc_uint_type *language,
     217  		     int level)
     218  {
     219    const rc_res_entry *re;
     220  
     221    for (re = rd->entries; re != NULL; re = re->next)
     222      {
     223        switch (level)
     224  	{
     225  	case 1:
     226  	  /* If we're at level 1, the key of this resource is the
     227  	     type.  This normally duplicates the information we have
     228  	     stored with the resource itself, but we need to remember
     229  	     the type if this is a user define resource type.  */
     230  	  type = &re->id;
     231  	  break;
     232  
     233  	case 2:
     234  	  /* If we're at level 2, the key of this resource is the name
     235  	     we are going to use in the rc printout.  */
     236  	  name = &re->id;
     237  	  break;
     238  
     239  	case 3:
     240  	  /* If we're at level 3, then this key represents a language.
     241  	     Use it to update the current language.  */
     242  	  if (! re->id.named
     243  	      && re->id.u.id != (unsigned long) *language
     244  	      && (re->id.u.id & 0xffff) == re->id.u.id)
     245  	    {
     246  	      *language = re->id.u.id;
     247  	    }
     248  	  break;
     249  
     250  	default:
     251  	  break;
     252  	}
     253  
     254        if (re->subdir)
     255  	off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
     256  				   level + 1);
     257        else
     258  	{
     259  	  if (level == 3)
     260  	    {
     261  	      /* This is the normal case: the three levels are
     262  	         TYPE/NAME/LANGUAGE.  NAME will have been set at level
     263  	         2, and represents the name to use.  We probably just
     264  	         set LANGUAGE, and it will probably match what the
     265  	         resource itself records if anything.  */
     266  	      off = write_res_resource (wrbfd, off, type, name, re->u.res,
     267  	      				language);
     268  	    }
     269  	  else
     270  	    {
     271  	      fprintf (stderr, "// Resource at unexpected level %d\n", level);
     272  	      off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL,
     273  	      				re->u.res, language);
     274  	    }
     275  	}
     276      }
     277  
     278    return off;
     279  }
     280  
     281  static rc_uint_type
     282  write_res_resource (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *type,
     283  		    const rc_res_id *name, const rc_res_resource *res,
     284  		    rc_uint_type *language ATTRIBUTE_UNUSED)
     285  {
     286    int rt;
     287  
     288    switch (res->type)
     289      {
     290      default:
     291        abort ();
     292  
     293      case RES_TYPE_ACCELERATOR:
     294        rt = RT_ACCELERATOR;
     295        break;
     296  
     297      case RES_TYPE_BITMAP:
     298        rt = RT_BITMAP;
     299        break;
     300  
     301      case RES_TYPE_CURSOR:
     302        rt = RT_CURSOR;
     303        break;
     304  
     305      case RES_TYPE_GROUP_CURSOR:
     306        rt = RT_GROUP_CURSOR;
     307        break;
     308  
     309      case RES_TYPE_DIALOG:
     310        rt = RT_DIALOG;
     311        break;
     312  
     313      case RES_TYPE_FONT:
     314        rt = RT_FONT;
     315        break;
     316  
     317      case RES_TYPE_FONTDIR:
     318        rt = RT_FONTDIR;
     319        break;
     320  
     321      case RES_TYPE_ICON:
     322        rt = RT_ICON;
     323        break;
     324  
     325      case RES_TYPE_GROUP_ICON:
     326        rt = RT_GROUP_ICON;
     327        break;
     328  
     329      case RES_TYPE_MENU:
     330        rt = RT_MENU;
     331        break;
     332  
     333      case RES_TYPE_MESSAGETABLE:
     334        rt = RT_MESSAGETABLE;
     335        break;
     336  
     337      case RES_TYPE_RCDATA:
     338        rt = RT_RCDATA;
     339        break;
     340  
     341      case RES_TYPE_STRINGTABLE:
     342        rt = RT_STRING;
     343        break;
     344  
     345      case RES_TYPE_USERDATA:
     346        rt = 0;
     347        break;
     348  
     349      case RES_TYPE_VERSIONINFO:
     350        rt = RT_VERSION;
     351        break;
     352  
     353      case RES_TYPE_TOOLBAR:
     354        rt = RT_TOOLBAR;
     355        break;
     356      }
     357  
     358    if (rt != 0
     359        && type != NULL
     360        && (type->named || type->u.id != (unsigned long) rt))
     361      {
     362        fprintf (stderr, "// Unexpected resource type mismatch: ");
     363        res_id_print (stderr, *type, 1);
     364        fprintf (stderr, " != %d", rt);
     365        abort ();
     366      }
     367  
     368    return write_res_bin (wrbfd, off, res, type, name, &res->res_info);
     369  }
     370  
     371  /* Write a resource in binary resource format */
     372  static rc_uint_type
     373  write_res_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res,
     374  	       const rc_res_id *type, const rc_res_id *name,
     375  	       const rc_res_res_info *resinfo)
     376  {
     377    rc_uint_type noff;
     378    rc_uint_type datasize = 0;
     379  
     380    noff = res_to_bin ((windres_bfd *) NULL, off, res);
     381    datasize = noff - off;
     382  
     383    off = write_res_header (wrbfd, off, datasize, type, name, resinfo);
     384    return res_to_bin (wrbfd, off, res);
     385  }
     386  
     387  /* Get number of bytes needed to store an id in binary format */
     388  static unsigned long
     389  get_id_size (const rc_res_id *id)
     390  {
     391    if (id->named)
     392      return sizeof (unichar) * (id->u.n.length + 1);
     393    else
     394      return sizeof (unichar) * 2;
     395  }
     396  
     397  /* Write a resource header */
     398  static rc_uint_type
     399  write_res_header (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type datasize,
     400  		  const rc_res_id *type, const rc_res_id *name,
     401  		  const rc_res_res_info *resinfo)
     402  {
     403    res_hdr reshdr;
     404    reshdr.data_size = datasize;
     405    reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
     406  
     407    reshdr.header_size = (reshdr.header_size + 3) & ~3;
     408  
     409    off = (off + 3) & ~3;
     410  
     411    off = write_res_data_hdr (wrbfd, off, &reshdr);
     412    off = write_res_id (wrbfd, off, type);
     413    off = write_res_id (wrbfd, off, name);
     414  
     415    off = (off + 3) & ~3;
     416  
     417    off = write_res_info (wrbfd, off, resinfo);
     418    off = (off + 3) & ~3;
     419    return off;
     420  }
     421  
     422  static rc_uint_type
     423  write_res_data_hdr (windres_bfd *wrbfd, rc_uint_type off, res_hdr *hdr)
     424  {
     425    if (wrbfd)
     426      {
     427        struct bin_res_hdr brh;
     428        windres_put_32 (wrbfd, brh.data_size, hdr->data_size);
     429        windres_put_32 (wrbfd, brh.header_size, hdr->header_size);
     430        set_windres_bfd_content (wrbfd, &brh, off, BIN_RES_HDR_SIZE);
     431      }
     432    return off + BIN_RES_HDR_SIZE;
     433  }
     434  
     435  static void
     436  read_res_data_hdr (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
     437  		   res_hdr *reshdr)
     438  {
     439    struct bin_res_hdr brh;
     440  
     441    if ((off[0] + BIN_RES_HDR_SIZE) > omax)
     442      fatal ("%s: unexpected end of file %ld/%ld", filename,(long) off[0], (long) omax);
     443  
     444    get_windres_bfd_content (wrbfd, &brh, off[0], BIN_RES_HDR_SIZE);
     445    reshdr->data_size = windres_get_32 (wrbfd, brh.data_size, 4);
     446    reshdr->header_size = windres_get_32 (wrbfd, brh.header_size, 4);
     447    off[0] += BIN_RES_HDR_SIZE;
     448  }
     449  
     450  /* Read data from file, abort on failure */
     451  static void
     452  read_res_data (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, void *data,
     453  	       rc_uint_type size)
     454  {
     455    if ((off[0] + size) > omax)
     456      fatal ("%s: unexpected end of file %ld/%ld %ld", filename,(long) off[0],
     457      	   (long) omax, (long) size);
     458    get_windres_bfd_content (wrbfd, data, off[0], size);
     459    off[0] += size;
     460  }
     461  
     462  /* Write a resource id */
     463  static rc_uint_type
     464  write_res_id (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *id)
     465  {
     466    if (id->named)
     467      {
     468        rc_uint_type len = (((bfd_signed_vma) id->u.n.length < 0 ? 0 : id->u.n.length) + 1);
     469        if (wrbfd)
     470  	{
     471  	  rc_uint_type i;
     472  	  bfd_byte *d = (bfd_byte *) xmalloc (len * sizeof (unichar));
     473  	  for (i = 0; i < (len - 1); i++)
     474  	    windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id->u.n.name[i]);
     475  	  windres_put_16 (wrbfd, d + (i * sizeof (unichar)), 0);
     476  	  set_windres_bfd_content (wrbfd, d, off, (len * sizeof (unichar)));
     477  	}
     478        off += (len * sizeof (unichar));
     479      }
     480    else
     481      {
     482        if (wrbfd)
     483  	{
     484  	  struct bin_res_id bid;
     485  	  windres_put_16 (wrbfd, bid.sig, 0xffff);
     486  	  windres_put_16 (wrbfd, bid.id, id->u.id);
     487  	  set_windres_bfd_content (wrbfd, &bid, off, BIN_RES_ID);
     488  	}
     489        off += BIN_RES_ID;
     490      }
     491    return off;
     492  }
     493  
     494  /* Write resource info */
     495  static rc_uint_type
     496  write_res_info (windres_bfd *wrbfd, rc_uint_type off, const rc_res_res_info *info)
     497  {
     498    if (wrbfd)
     499      {
     500        struct bin_res_info l;
     501  
     502        windres_put_32 (wrbfd, l.version, info->version);
     503        windres_put_16 (wrbfd, l.memflags, info->memflags);
     504        windres_put_16 (wrbfd, l.language, info->language);
     505        windres_put_32 (wrbfd, l.version2, info->version);
     506        windres_put_32 (wrbfd, l.characteristics, info->characteristics);
     507        set_windres_bfd_content (wrbfd, &l, off, BIN_RES_INFO_SIZE);
     508      }
     509    return off + BIN_RES_INFO_SIZE;
     510  }
     511  
     512  /* read a resource identifier */
     513  static void
     514  read_res_id (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, rc_res_id *id)
     515  {
     516    struct bin_res_id bid;
     517    unsigned short ord;
     518    unichar *id_s = NULL;
     519    rc_uint_type len;
     520  
     521    read_res_data (wrbfd, off, omax, &bid, BIN_RES_ID - 2);
     522    ord = (unsigned short) windres_get_16 (wrbfd, bid.sig, 2);
     523    if (ord == 0xFFFF)		/* an ordinal id */
     524      {
     525        read_res_data (wrbfd, off, omax, bid.id, BIN_RES_ID - 2);
     526        id->named = 0;
     527        id->u.id = windres_get_16 (wrbfd, bid.id, 2);
     528      }
     529    else
     530      /* named id */
     531      {
     532        off[0] -= 2;
     533        id_s = read_unistring (wrbfd, off, omax, &len);
     534        id->named = 1;
     535        id->u.n.length = len;
     536        id->u.n.name = id_s;
     537      }
     538  }
     539  
     540  /* Read a null terminated UNICODE string */
     541  static unichar *
     542  read_unistring (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
     543  		rc_uint_type *len)
     544  {
     545    unichar *s;
     546    bfd_byte d[2];
     547    unichar c;
     548    unichar *p;
     549    rc_uint_type l;
     550    rc_uint_type soff = off[0];
     551  
     552    do
     553      {
     554        read_res_data (wrbfd, &soff, omax, d, sizeof (unichar));
     555        c = windres_get_16 (wrbfd, d, 2);
     556      }
     557    while (c != 0);
     558    l = ((soff - off[0]) / sizeof (unichar));
     559  
     560    /* there are hardly any names longer than 256 characters, but anyway. */
     561    p = s = (unichar *) xmalloc (sizeof (unichar) * l);
     562    do
     563      {
     564        read_res_data (wrbfd, off, omax, d, sizeof (unichar));
     565        c = windres_get_16 (wrbfd, d, 2);
     566        *p++ = c;
     567      }
     568    while (c != 0);
     569    *len = l - 1;
     570    return s;
     571  }
     572  
     573  static int
     574  probe_binary (windres_bfd *wrbfd, rc_uint_type omax)
     575  {
     576    rc_uint_type off;
     577    res_hdr reshdr;
     578  
     579    off = 0;
     580    read_res_data_hdr (wrbfd, &off, omax, &reshdr);
     581    if (reshdr.data_size != 0)
     582      return 1;
     583    if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
     584        || (reshdr.header_size != 0x20000000 && target_is_bigendian))
     585      return 1;
     586  
     587    /* Subtract size of HeaderSize. DataSize has to be zero. */
     588    off += 0x20 - BIN_RES_HDR_SIZE;
     589    if ((off + BIN_RES_HDR_SIZE) >= omax)
     590      return 1;
     591    read_res_data_hdr (wrbfd, &off, omax, &reshdr);
     592    /* off is advanced by BIN_RES_HDR_SIZE in read_res_data_hdr()
     593       which is part of reshdr.header_size. We shouldn't take it
     594       into account twice.  */
     595    if ((off - BIN_RES_HDR_SIZE + reshdr.data_size + reshdr.header_size) > omax)
     596      return 0;
     597    return 1;
     598  }
     599  
     600  /* Check if file is a win32 binary resource file, if so
     601     skip past the null resource. Returns 0 if successful, -1 on
     602     error.
     603   */
     604  static void
     605  skip_null_resource (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
     606  {
     607    res_hdr reshdr;
     608    read_res_data_hdr (wrbfd, off, omax, &reshdr);
     609    if (reshdr.data_size != 0)
     610      goto skip_err;
     611    if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
     612      || (reshdr.header_size != 0x20000000 && target_is_bigendian))
     613      goto skip_err;
     614  
     615    /* Subtract size of HeaderSize. DataSize has to be zero. */
     616    off[0] += 0x20 - BIN_RES_HDR_SIZE;
     617    if (off[0] >= omax)
     618      goto skip_err;
     619  
     620    return;
     621  
     622   skip_err:
     623    fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
     624  	   filename);
     625    xexit (1);
     626  }
     627  
     628  /* Add a resource to resource directory */
     629  static void
     630  res_add_resource (rc_res_resource *r, const rc_res_id *type, const rc_res_id *id,
     631  		  rc_uint_type language, int dupok)
     632  {
     633    rc_res_id a[3];
     634  
     635    a[0] = *type;
     636    a[1] = *id;
     637    a[2].named = 0;
     638    a[2].u.id = language;
     639    res_append_resource (&resources, r, 3, a, dupok);
     640  }
     641  
     642  /* Append a resource to resource directory.
     643     This is just copied from define_resource
     644     and modified to add an existing resource.
     645   */
     646  static void
     647  res_append_resource (rc_res_directory **res_dirs, rc_res_resource *resource,
     648  		     int cids, const rc_res_id *ids, int dupok)
     649  {
     650    rc_res_entry *re = NULL;
     651    int i;
     652  
     653    assert (cids > 0);
     654    for (i = 0; i < cids; i++)
     655      {
     656        rc_res_entry **pp;
     657  
     658        if (*res_dirs == NULL)
     659  	{
     660  	  *res_dirs = ((rc_res_directory *)
     661  			res_alloc (sizeof (rc_res_directory)));
     662  
     663  	  (*res_dirs)->characteristics = 0;
     664  	  /* Using a real timestamp only serves to create non-deterministic
     665  	     results.  Use zero instead.  */
     666  	  (*res_dirs)->time = 0;
     667  	  (*res_dirs)->major = 0;
     668  	  (*res_dirs)->minor = 0;
     669  	  (*res_dirs)->entries = NULL;
     670  	}
     671  
     672        for (pp = &(*res_dirs)->entries; *pp != NULL; pp = &(*pp)->next)
     673  	if (res_id_cmp ((*pp)->id, ids[i]) == 0)
     674  	  break;
     675  
     676        if (*pp != NULL)
     677  	re = *pp;
     678        else
     679  	{
     680  	  re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
     681  	  re->next = NULL;
     682  	  re->id = ids[i];
     683  	  if ((i + 1) < cids)
     684  	    {
     685  	      re->subdir = 1;
     686  	      re->u.dir = NULL;
     687  	    }
     688  	  else
     689  	    {
     690  	      re->subdir = 0;
     691  	      re->u.res = NULL;
     692  	    }
     693  
     694  	  *pp = re;
     695  	}
     696  
     697        if ((i + 1) < cids)
     698  	{
     699  	  if (! re->subdir)
     700  	    {
     701  	      fprintf (stderr, "%s: ", program_name);
     702  	      res_ids_print (stderr, i, ids);
     703  	      fprintf (stderr, ": expected to be a directory\n");
     704  	      xexit (1);
     705  	    }
     706  
     707  	  res_dirs = &re->u.dir;
     708  	}
     709      }
     710  
     711    if (re->subdir)
     712      {
     713        fprintf (stderr, "%s: ", program_name);
     714        res_ids_print (stderr, cids, ids);
     715        fprintf (stderr, ": expected to be a leaf\n");
     716        xexit (1);
     717      }
     718  
     719    if (re->u.res != NULL)
     720      {
     721        if (dupok)
     722  	return;
     723  
     724        fprintf (stderr, "%s: warning: ", program_name);
     725        res_ids_print (stderr, cids, ids);
     726        fprintf (stderr, ": duplicate value\n");
     727      }
     728  
     729    re->u.res = resource;
     730  }