160484Sobrien/* resres.c: read_res_file and write_res_file implementation for windres. 2218822Sdim Copyright 1998, 1999, 2001, 2002, 2007 3218822Sdim Free Software Foundation, Inc. 460484Sobrien Written by Anders Norlander <anorland@hem2.passagen.se>. 5218822Sdim Rewritten by Kai Tietz, Onevision. 660484Sobrien 760484Sobrien This file is part of GNU Binutils. 860484Sobrien 960484Sobrien This program is free software; you can redistribute it and/or modify 1060484Sobrien it under the terms of the GNU General Public License as published by 1160484Sobrien the Free Software Foundation; either version 2 of the License, or 1260484Sobrien (at your option) any later version. 1360484Sobrien 1460484Sobrien This program is distributed in the hope that it will be useful, 1560484Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 1660484Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1760484Sobrien GNU General Public License for more details. 1860484Sobrien 1960484Sobrien You should have received a copy of the GNU General Public License 2060484Sobrien along with this program; if not, write to the Free Software 21218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 22218822Sdim 02110-1301, USA. */ 2360484Sobrien 2460484Sobrien/* FIXME: This file does not work correctly in a cross configuration. 2560484Sobrien It assumes that it can use fread and fwrite to read and write 2660484Sobrien integers. It does no swapping. */ 2760484Sobrien 28218822Sdim#include "sysdep.h" 2960484Sobrien#include "bfd.h" 3060484Sobrien#include "bucomm.h" 3160484Sobrien#include "libiberty.h" 3260484Sobrien#include "windres.h" 3360484Sobrien 3460484Sobrien#include <assert.h> 3560484Sobrien#include <time.h> 3660484Sobrien 37218822Sdimstatic rc_uint_type write_res_directory (windres_bfd *, rc_uint_type, 38218822Sdim const rc_res_directory *, const rc_res_id *, 39218822Sdim const rc_res_id *, rc_uint_type *, int); 40218822Sdimstatic rc_uint_type write_res_resource (windres_bfd *, rc_uint_type,const rc_res_id *, 41218822Sdim const rc_res_id *, const rc_res_resource *, 42218822Sdim rc_uint_type *); 43218822Sdimstatic rc_uint_type write_res_bin (windres_bfd *, rc_uint_type, const rc_res_resource *, 44218822Sdim const rc_res_id *, const rc_res_id *, 45218822Sdim const rc_res_res_info *); 4660484Sobrien 47218822Sdimstatic rc_uint_type write_res_id (windres_bfd *, rc_uint_type, const rc_res_id *); 48218822Sdimstatic rc_uint_type write_res_info (windres_bfd *, rc_uint_type, const rc_res_res_info *); 49218822Sdimstatic rc_uint_type write_res_data_hdr (windres_bfd *, rc_uint_type, res_hdr *); 5060484Sobrien 51218822Sdimstatic rc_uint_type write_res_header (windres_bfd *, rc_uint_type, rc_uint_type, 52218822Sdim const rc_res_id *, const rc_res_id *, 53218822Sdim const rc_res_res_info *); 5460484Sobrien 55218822Sdimstatic int read_resource_entry (windres_bfd *, rc_uint_type *, rc_uint_type); 56218822Sdimstatic void read_res_data (windres_bfd *, rc_uint_type *, rc_uint_type, void *, 57218822Sdim rc_uint_type); 58218822Sdimstatic void read_res_data_hdr (windres_bfd *, rc_uint_type *, rc_uint_type, res_hdr *); 59218822Sdimstatic void read_res_id (windres_bfd *, rc_uint_type *, rc_uint_type, rc_res_id *); 60218822Sdimstatic unichar *read_unistring (windres_bfd *, rc_uint_type *, rc_uint_type, rc_uint_type *); 61218822Sdimstatic void skip_null_resource (windres_bfd *, rc_uint_type *, rc_uint_type); 62218822Sdimstatic int probe_binary (windres_bfd *wrbfd, rc_uint_type); 6360484Sobrien 64218822Sdimstatic unsigned long get_id_size (const rc_res_id *); 6560484Sobrien 66218822Sdimstatic void res_add_resource (rc_res_resource *, const rc_res_id *, 67218822Sdim const rc_res_id *, rc_uint_type, int); 6860484Sobrien 69218822Sdimstatic void res_append_resource (rc_res_directory **, rc_res_resource *, 70218822Sdim int, const rc_res_id *, int); 7160484Sobrien 72218822Sdimstatic rc_res_directory *resources = NULL; 7360484Sobrien 7460484Sobrienstatic const char *filename; 7560484Sobrien 7660484Sobrienextern char *program_name; 7760484Sobrien 7860484Sobrien/* Read resource file */ 79218822Sdimrc_res_directory * 80218822Sdimread_res_file (const char *fn) 8160484Sobrien{ 82218822Sdim rc_uint_type off, flen; 83218822Sdim windres_bfd wrbfd; 84218822Sdim bfd *abfd; 85218822Sdim asection *sec; 8660484Sobrien filename = fn; 8760484Sobrien 88218822Sdim flen = (rc_uint_type) get_file_size (filename); 89218822Sdim if (! flen) 90218822Sdim fatal ("can't open '%s' for input.", filename); 91218822Sdim abfd = windres_open_as_binary (filename, 1); 92218822Sdim sec = bfd_get_section_by_name (abfd, ".data"); 93218822Sdim if (sec == NULL) 94218822Sdim bfd_fatal ("bfd_get_section_by_name"); 95218822Sdim set_windres_bfd (&wrbfd, abfd, sec, 96218822Sdim (target_is_bigendian ? WR_KIND_BFD_BIN_B 97218822Sdim : WR_KIND_BFD_BIN_L)); 98218822Sdim off = 0; 9960484Sobrien 100218822Sdim if (! probe_binary (&wrbfd, flen)) 101218822Sdim set_windres_bfd_endianess (&wrbfd, ! target_is_bigendian); 102218822Sdim 103218822Sdim skip_null_resource (&wrbfd, &off, flen); 104218822Sdim 105218822Sdim while (read_resource_entry (&wrbfd, &off, flen)) 10660484Sobrien ; 10760484Sobrien 108218822Sdim bfd_close (abfd); 10960484Sobrien 11060484Sobrien return resources; 11160484Sobrien} 11260484Sobrien 11360484Sobrien/* Write resource file */ 11460484Sobrienvoid 115218822Sdimwrite_res_file (const char *fn,const rc_res_directory *resdir) 11660484Sobrien{ 117218822Sdim asection *sec; 118218822Sdim rc_uint_type language; 119218822Sdim bfd *abfd; 120218822Sdim windres_bfd wrbfd; 121218822Sdim unsigned long sec_length = 0,sec_length_wrote; 122218822Sdim static const bfd_byte sign[] = 12360484Sobrien {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 12460484Sobrien 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 12560484Sobrien 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 12660484Sobrien 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 12760484Sobrien 12860484Sobrien filename = fn; 12960484Sobrien 130218822Sdim abfd = windres_open_as_binary (filename, 0); 131218822Sdim sec = bfd_make_section (abfd, ".data"); 132218822Sdim if (sec == NULL) 133218822Sdim bfd_fatal ("bfd_make_section"); 134218822Sdim if (! bfd_set_section_flags (abfd, sec, 135218822Sdim (SEC_HAS_CONTENTS | SEC_ALLOC 136218822Sdim | SEC_LOAD | SEC_DATA))) 137218822Sdim bfd_fatal ("bfd_set_section_flags"); 138218822Sdim /* Requiring this is probably a bug in BFD. */ 139218822Sdim sec->output_section = sec; 14060484Sobrien 141218822Sdim set_windres_bfd (&wrbfd, abfd, sec, 142218822Sdim (target_is_bigendian ? WR_KIND_BFD_BIN_B 143218822Sdim : WR_KIND_BFD_BIN_L)); 14460484Sobrien 14560484Sobrien language = -1; 146218822Sdim sec_length = write_res_directory ((windres_bfd *) NULL, 0x20UL, resdir, 147218822Sdim (const rc_res_id *) NULL, 148218822Sdim (const rc_res_id *) NULL, &language, 1); 149218822Sdim if (! bfd_set_section_size (abfd, sec, (sec_length + 3) & ~3)) 150218822Sdim bfd_fatal ("bfd_set_section_size"); 151218822Sdim if ((sec_length & 3) != 0) 152218822Sdim set_windres_bfd_content (&wrbfd, sign, sec_length, 4-(sec_length & 3)); 153218822Sdim set_windres_bfd_content (&wrbfd, sign, 0, sizeof (sign)); 154218822Sdim language = -1; 155218822Sdim sec_length_wrote = write_res_directory (&wrbfd, 0x20UL, resdir, 156218822Sdim (const rc_res_id *) NULL, 157218822Sdim (const rc_res_id *) NULL, 158218822Sdim &language, 1); 159218822Sdim if (sec_length != sec_length_wrote) 160218822Sdim fatal ("res write failed with different sizes (%lu/%lu).", (long) sec_length, 161218822Sdim (long) sec_length_wrote); 16260484Sobrien 163218822Sdim bfd_close (abfd); 164218822Sdim return; 16560484Sobrien} 16660484Sobrien 16760484Sobrien/* Read a resource entry, returns 0 when all resources are read */ 16860484Sobrienstatic int 169218822Sdimread_resource_entry (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax) 17060484Sobrien{ 171218822Sdim rc_res_id type; 172218822Sdim rc_res_id name; 173218822Sdim rc_res_res_info resinfo; 174218822Sdim res_hdr reshdr; 17560484Sobrien void *buff; 17660484Sobrien 177218822Sdim rc_res_resource *r; 178218822Sdim struct bin_res_info l; 17960484Sobrien 180218822Sdim off[0] = (off[0] + 3) & ~3; 18160484Sobrien 18260484Sobrien /* Read header */ 183218822Sdim if ((off[0] + 8) > omax) 18460484Sobrien return 0; 185218822Sdim read_res_data_hdr (wrbfd, off, omax, &reshdr); 18660484Sobrien 18760484Sobrien /* read resource type */ 188218822Sdim read_res_id (wrbfd, off, omax, &type); 18960484Sobrien /* read resource id */ 190218822Sdim read_res_id (wrbfd, off, omax, &name); 19160484Sobrien 192218822Sdim off[0] = (off[0] + 3) & ~3; 19360484Sobrien 19460484Sobrien /* Read additional resource header */ 195218822Sdim read_res_data (wrbfd, off, omax, &l, BIN_RES_INFO_SIZE); 196218822Sdim resinfo.version = windres_get_32 (wrbfd, l.version, 4); 197218822Sdim resinfo.memflags = windres_get_16 (wrbfd, l.memflags, 2); 198218822Sdim resinfo.language = windres_get_16 (wrbfd, l.language, 2); 199218822Sdim /* resinfo.version2 = windres_get_32 (wrbfd, l.version2, 4); */ 200218822Sdim resinfo.characteristics = windres_get_32 (wrbfd, l.characteristics, 4); 20160484Sobrien 202218822Sdim off[0] = (off[0] + 3) & ~3; 20360484Sobrien 20460484Sobrien /* Allocate buffer for data */ 20560484Sobrien buff = res_alloc (reshdr.data_size); 20660484Sobrien /* Read data */ 207218822Sdim read_res_data (wrbfd, off, omax, buff, reshdr.data_size); 20860484Sobrien /* Convert binary data to resource */ 209218822Sdim r = bin_to_res (wrbfd, type, buff, reshdr.data_size); 21060484Sobrien r->res_info = resinfo; 21160484Sobrien /* Add resource to resource directory */ 21260484Sobrien res_add_resource (r, &type, &name, resinfo.language, 0); 21360484Sobrien 21460484Sobrien return 1; 21560484Sobrien} 21660484Sobrien 21760484Sobrien/* write resource directory to binary resource file */ 218218822Sdimstatic rc_uint_type 219218822Sdimwrite_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_directory *rd, 220218822Sdim const rc_res_id *type, const rc_res_id *name, rc_uint_type *language, 221218822Sdim int level) 22260484Sobrien{ 223218822Sdim const rc_res_entry *re; 22460484Sobrien 22560484Sobrien for (re = rd->entries; re != NULL; re = re->next) 22660484Sobrien { 22760484Sobrien switch (level) 22860484Sobrien { 22960484Sobrien case 1: 23060484Sobrien /* If we're at level 1, the key of this resource is the 23160484Sobrien type. This normally duplicates the information we have 23260484Sobrien stored with the resource itself, but we need to remember 23360484Sobrien the type if this is a user define resource type. */ 23460484Sobrien type = &re->id; 23560484Sobrien break; 23660484Sobrien 23760484Sobrien case 2: 23860484Sobrien /* If we're at level 2, the key of this resource is the name 239104834Sobrien we are going to use in the rc printout. */ 24060484Sobrien name = &re->id; 24160484Sobrien break; 24260484Sobrien 24360484Sobrien case 3: 24460484Sobrien /* If we're at level 3, then this key represents a language. 24560484Sobrien Use it to update the current language. */ 246218822Sdim if (! re->id.named 24760484Sobrien && re->id.u.id != (unsigned long) *language 24860484Sobrien && (re->id.u.id & 0xffff) == re->id.u.id) 24960484Sobrien { 25060484Sobrien *language = re->id.u.id; 25160484Sobrien } 25260484Sobrien break; 25360484Sobrien 25460484Sobrien default: 25560484Sobrien break; 25660484Sobrien } 25760484Sobrien 25860484Sobrien if (re->subdir) 259218822Sdim off = write_res_directory (wrbfd, off, re->u.dir, type, name, language, 260218822Sdim level + 1); 26160484Sobrien else 26260484Sobrien { 26360484Sobrien if (level == 3) 26460484Sobrien { 26560484Sobrien /* This is the normal case: the three levels are 26660484Sobrien TYPE/NAME/LANGUAGE. NAME will have been set at level 26760484Sobrien 2, and represents the name to use. We probably just 26860484Sobrien set LANGUAGE, and it will probably match what the 26960484Sobrien resource itself records if anything. */ 270218822Sdim off = write_res_resource (wrbfd, off, type, name, re->u.res, 271218822Sdim language); 27260484Sobrien } 27360484Sobrien else 27460484Sobrien { 27560484Sobrien fprintf (stderr, "// Resource at unexpected level %d\n", level); 276218822Sdim off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL, 277218822Sdim re->u.res, language); 27860484Sobrien } 27960484Sobrien } 28060484Sobrien } 28160484Sobrien 282218822Sdim return off; 28360484Sobrien} 28460484Sobrien 285218822Sdimstatic rc_uint_type 286218822Sdimwrite_res_resource (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *type, 287218822Sdim const rc_res_id *name, const rc_res_resource *res, 288218822Sdim rc_uint_type *language ATTRIBUTE_UNUSED) 28960484Sobrien{ 29060484Sobrien int rt; 29160484Sobrien 29260484Sobrien switch (res->type) 29360484Sobrien { 29460484Sobrien default: 29560484Sobrien abort (); 29660484Sobrien 29760484Sobrien case RES_TYPE_ACCELERATOR: 29860484Sobrien rt = RT_ACCELERATOR; 29960484Sobrien break; 30060484Sobrien 30160484Sobrien case RES_TYPE_BITMAP: 30260484Sobrien rt = RT_BITMAP; 30360484Sobrien break; 30460484Sobrien 30560484Sobrien case RES_TYPE_CURSOR: 30660484Sobrien rt = RT_CURSOR; 30760484Sobrien break; 30860484Sobrien 30960484Sobrien case RES_TYPE_GROUP_CURSOR: 31060484Sobrien rt = RT_GROUP_CURSOR; 31160484Sobrien break; 31260484Sobrien 31360484Sobrien case RES_TYPE_DIALOG: 31460484Sobrien rt = RT_DIALOG; 31560484Sobrien break; 31660484Sobrien 31760484Sobrien case RES_TYPE_FONT: 31860484Sobrien rt = RT_FONT; 31960484Sobrien break; 32060484Sobrien 32160484Sobrien case RES_TYPE_FONTDIR: 32260484Sobrien rt = RT_FONTDIR; 32360484Sobrien break; 32460484Sobrien 32560484Sobrien case RES_TYPE_ICON: 32660484Sobrien rt = RT_ICON; 32760484Sobrien break; 32860484Sobrien 32960484Sobrien case RES_TYPE_GROUP_ICON: 33060484Sobrien rt = RT_GROUP_ICON; 33160484Sobrien break; 33260484Sobrien 33360484Sobrien case RES_TYPE_MENU: 33460484Sobrien rt = RT_MENU; 33560484Sobrien break; 33660484Sobrien 33760484Sobrien case RES_TYPE_MESSAGETABLE: 33860484Sobrien rt = RT_MESSAGETABLE; 33960484Sobrien break; 34060484Sobrien 34160484Sobrien case RES_TYPE_RCDATA: 34260484Sobrien rt = RT_RCDATA; 34360484Sobrien break; 34460484Sobrien 34560484Sobrien case RES_TYPE_STRINGTABLE: 34660484Sobrien rt = RT_STRING; 34760484Sobrien break; 34860484Sobrien 34960484Sobrien case RES_TYPE_USERDATA: 35060484Sobrien rt = 0; 35160484Sobrien break; 35260484Sobrien 35360484Sobrien case RES_TYPE_VERSIONINFO: 35460484Sobrien rt = RT_VERSION; 35560484Sobrien break; 356218822Sdim 357218822Sdim case RES_TYPE_TOOLBAR: 358218822Sdim rt = RT_TOOLBAR; 359218822Sdim break; 36060484Sobrien } 36160484Sobrien 36260484Sobrien if (rt != 0 36360484Sobrien && type != NULL 36460484Sobrien && (type->named || type->u.id != (unsigned long) rt)) 36560484Sobrien { 36660484Sobrien fprintf (stderr, "// Unexpected resource type mismatch: "); 36760484Sobrien res_id_print (stderr, *type, 1); 36860484Sobrien fprintf (stderr, " != %d", rt); 36960484Sobrien abort (); 37060484Sobrien } 37160484Sobrien 372218822Sdim return write_res_bin (wrbfd, off, res, type, name, &res->res_info); 37360484Sobrien} 37460484Sobrien 37560484Sobrien/* Write a resource in binary resource format */ 376218822Sdimstatic rc_uint_type 377218822Sdimwrite_res_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res, 378218822Sdim const rc_res_id *type, const rc_res_id *name, 379218822Sdim const rc_res_res_info *resinfo) 38060484Sobrien{ 381218822Sdim rc_uint_type noff; 382218822Sdim rc_uint_type datasize = 0; 38360484Sobrien 384218822Sdim noff = res_to_bin ((windres_bfd *) NULL, off, res); 385218822Sdim datasize = noff - off; 38660484Sobrien 387218822Sdim off = write_res_header (wrbfd, off, datasize, type, name, resinfo); 388218822Sdim return res_to_bin (wrbfd, off, res); 38960484Sobrien} 39060484Sobrien 39160484Sobrien/* Get number of bytes needed to store an id in binary format */ 39260484Sobrienstatic unsigned long 39360484Sobrienget_id_size (id) 394218822Sdim const rc_res_id *id; 39560484Sobrien{ 39660484Sobrien if (id->named) 39760484Sobrien return sizeof (unichar) * (id->u.n.length + 1); 39860484Sobrien else 39960484Sobrien return sizeof (unichar) * 2; 40060484Sobrien} 40160484Sobrien 40260484Sobrien/* Write a resource header */ 403218822Sdimstatic rc_uint_type 404218822Sdimwrite_res_header (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type datasize, 405218822Sdim const rc_res_id *type, const rc_res_id *name, 406218822Sdim const rc_res_res_info *resinfo) 40760484Sobrien{ 408218822Sdim res_hdr reshdr; 40960484Sobrien reshdr.data_size = datasize; 41060484Sobrien reshdr.header_size = 24 + get_id_size (type) + get_id_size (name); 41160484Sobrien 41289857Sobrien reshdr.header_size = (reshdr.header_size + 3) & ~3; 41389857Sobrien 414218822Sdim off = (off + 3) & ~3; 41560484Sobrien 416218822Sdim off = write_res_data_hdr (wrbfd, off, &reshdr); 417218822Sdim off = write_res_id (wrbfd, off, type); 418218822Sdim off = write_res_id (wrbfd, off, name); 41960484Sobrien 420218822Sdim off = (off + 3) & ~3; 421218822Sdim 422218822Sdim off = write_res_info (wrbfd, off, resinfo); 423218822Sdim off = (off + 3) & ~3; 424218822Sdim return off; 42560484Sobrien} 42660484Sobrien 427218822Sdimstatic rc_uint_type 428218822Sdimwrite_res_data_hdr (windres_bfd *wrbfd, rc_uint_type off, res_hdr *hdr) 429218822Sdim{ 430218822Sdim if (wrbfd) 431218822Sdim { 432218822Sdim struct bin_res_hdr brh; 433218822Sdim windres_put_32 (wrbfd, brh.data_size, hdr->data_size); 434218822Sdim windres_put_32 (wrbfd, brh.header_size, hdr->header_size); 435218822Sdim set_windres_bfd_content (wrbfd, &brh, off, BIN_RES_HDR_SIZE); 436218822Sdim } 437218822Sdim return off + BIN_RES_HDR_SIZE; 438218822Sdim} 43960484Sobrien 44060484Sobrienstatic void 441218822Sdimread_res_data_hdr (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, 442218822Sdim res_hdr *reshdr) 44360484Sobrien{ 444218822Sdim struct bin_res_hdr brh; 445218822Sdim 446218822Sdim if ((off[0] + BIN_RES_HDR_SIZE) > omax) 447218822Sdim fatal ("%s: unexpected end of file %ld/%ld", filename,(long) off[0], (long) omax); 448218822Sdim 449218822Sdim get_windres_bfd_content (wrbfd, &brh, off[0], BIN_RES_HDR_SIZE); 450218822Sdim reshdr->data_size = windres_get_32 (wrbfd, brh.data_size, 4); 451218822Sdim reshdr->header_size = windres_get_32 (wrbfd, brh.header_size, 4); 452218822Sdim off[0] += BIN_RES_HDR_SIZE; 45360484Sobrien} 45460484Sobrien 45560484Sobrien/* Read data from file, abort on failure */ 45660484Sobrienstatic void 457218822Sdimread_res_data (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, void *data, 458218822Sdim rc_uint_type size) 45960484Sobrien{ 460218822Sdim if ((off[0] + size) > omax) 461218822Sdim fatal ("%s: unexpected end of file %ld/%ld %ld", filename,(long) off[0], 462218822Sdim (long) omax, (long) size); 463218822Sdim get_windres_bfd_content (wrbfd, data, off[0], size); 464218822Sdim off[0] += size; 46560484Sobrien} 46660484Sobrien 46760484Sobrien/* Write a resource id */ 468218822Sdimstatic rc_uint_type 469218822Sdimwrite_res_id (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *id) 47060484Sobrien{ 47160484Sobrien if (id->named) 47260484Sobrien { 473218822Sdim rc_uint_type len = (((bfd_signed_vma) id->u.n.length < 0 ? 0 : id->u.n.length) + 1); 474218822Sdim if (wrbfd) 475218822Sdim { 476218822Sdim rc_uint_type i; 477218822Sdim bfd_byte *d = (bfd_byte *) xmalloc (len * sizeof (unichar)); 478218822Sdim for (i = 0; i < (len - 1); i++) 479218822Sdim windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id->u.n.name[i]); 480218822Sdim windres_put_16 (wrbfd, d + (i * sizeof (unichar)), 0); 481218822Sdim set_windres_bfd_content (wrbfd, d, off, (len * sizeof (unichar))); 482218822Sdim } 483218822Sdim off += (len * sizeof (unichar)); 48460484Sobrien } 48560484Sobrien else 48660484Sobrien { 487218822Sdim if (wrbfd) 488218822Sdim { 489218822Sdim struct bin_res_id bid; 490218822Sdim windres_put_16 (wrbfd, bid.sig, 0xffff); 491218822Sdim windres_put_16 (wrbfd, bid.id, id->u.id); 492218822Sdim set_windres_bfd_content (wrbfd, &bid, off, BIN_RES_ID); 493218822Sdim } 494218822Sdim off += BIN_RES_ID; 49560484Sobrien } 496218822Sdim return off; 49760484Sobrien} 49860484Sobrien 49960484Sobrien/* Write resource info */ 500218822Sdimstatic rc_uint_type 501218822Sdimwrite_res_info (windres_bfd *wrbfd, rc_uint_type off, const rc_res_res_info *info) 50260484Sobrien{ 503218822Sdim if (wrbfd) 504218822Sdim { 505218822Sdim struct bin_res_info l; 506218822Sdim 507218822Sdim windres_put_32 (wrbfd, l.version, info->version); 508218822Sdim windres_put_16 (wrbfd, l.memflags, info->memflags); 509218822Sdim windres_put_16 (wrbfd, l.language, info->language); 510218822Sdim windres_put_32 (wrbfd, l.version2, info->version); 511218822Sdim windres_put_32 (wrbfd, l.characteristics, info->characteristics); 512218822Sdim set_windres_bfd_content (wrbfd, &l, off, BIN_RES_INFO_SIZE); 513218822Sdim } 514218822Sdim return off + BIN_RES_INFO_SIZE; 51560484Sobrien} 51660484Sobrien 51760484Sobrien/* read a resource identifier */ 518218822Sdimstatic void 519218822Sdimread_res_id (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, rc_res_id *id) 52060484Sobrien{ 521218822Sdim struct bin_res_id bid; 52260484Sobrien unsigned short ord; 52360484Sobrien unichar *id_s = NULL; 524218822Sdim rc_uint_type len; 52560484Sobrien 526218822Sdim read_res_data (wrbfd, off, omax, &bid, BIN_RES_ID - 2); 527218822Sdim ord = (unsigned short) windres_get_16 (wrbfd, bid.sig, 2); 52860484Sobrien if (ord == 0xFFFF) /* an ordinal id */ 52960484Sobrien { 530218822Sdim read_res_data (wrbfd, off, omax, bid.id, BIN_RES_ID - 2); 53160484Sobrien id->named = 0; 532218822Sdim id->u.id = windres_get_16 (wrbfd, bid.id, 2); 53360484Sobrien } 53460484Sobrien else 53560484Sobrien /* named id */ 53660484Sobrien { 537218822Sdim off[0] -= 2; 538218822Sdim id_s = read_unistring (wrbfd, off, omax, &len); 53960484Sobrien id->named = 1; 54060484Sobrien id->u.n.length = len; 54160484Sobrien id->u.n.name = id_s; 54260484Sobrien } 54360484Sobrien} 54460484Sobrien 54560484Sobrien/* Read a null terminated UNICODE string */ 54660484Sobrienstatic unichar * 547218822Sdimread_unistring (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, 548218822Sdim rc_uint_type *len) 54960484Sobrien{ 55060484Sobrien unichar *s; 551218822Sdim bfd_byte d[2]; 55260484Sobrien unichar c; 55360484Sobrien unichar *p; 554218822Sdim rc_uint_type l; 555218822Sdim rc_uint_type soff = off[0]; 55660484Sobrien 557218822Sdim do 558218822Sdim { 559218822Sdim read_res_data (wrbfd, &soff, omax, d, sizeof (unichar)); 560218822Sdim c = windres_get_16 (wrbfd, d, 2); 561218822Sdim } 562218822Sdim while (c != 0); 563218822Sdim l = ((soff - off[0]) / sizeof (unichar)); 56460484Sobrien 565218822Sdim /* there are hardly any names longer than 256 characters, but anyway. */ 566218822Sdim p = s = (unichar *) xmalloc (sizeof (unichar) * l); 56760484Sobrien do 56860484Sobrien { 569218822Sdim read_res_data (wrbfd, off, omax, d, sizeof (unichar)); 570218822Sdim c = windres_get_16 (wrbfd, d, 2); 57160484Sobrien *p++ = c; 57260484Sobrien } 57360484Sobrien while (c != 0); 574218822Sdim *len = l - 1; 57560484Sobrien return s; 57660484Sobrien} 57760484Sobrien 578218822Sdimstatic int 579218822Sdimprobe_binary (windres_bfd *wrbfd, rc_uint_type omax) 58060484Sobrien{ 581218822Sdim rc_uint_type off; 582218822Sdim res_hdr reshdr; 583218822Sdim 584218822Sdim off = 0; 585218822Sdim read_res_data_hdr (wrbfd, &off, omax, &reshdr); 586218822Sdim if (reshdr.data_size != 0) 587218822Sdim return 1; 588218822Sdim if ((reshdr.header_size != 0x20 && ! target_is_bigendian) 589218822Sdim || (reshdr.header_size != 0x20000000 && target_is_bigendian)) 590218822Sdim return 1; 591218822Sdim 592218822Sdim /* Subtract size of HeaderSize. DataSize has to be zero. */ 593218822Sdim off += 0x20 - BIN_RES_HDR_SIZE; 594218822Sdim if ((off + BIN_RES_HDR_SIZE) >= omax) 595218822Sdim return 1; 596218822Sdim read_res_data_hdr (wrbfd, &off, omax, &reshdr); 597218822Sdim /* off is advanced by BIN_RES_HDR_SIZE in read_res_data_hdr() 598218822Sdim which is part of reshdr.header_size. We shouldn't take it 599218822Sdim into account twice. */ 600218822Sdim if ((off - BIN_RES_HDR_SIZE + reshdr.data_size + reshdr.header_size) > omax) 601218822Sdim return 0; 602218822Sdim return 1; 60360484Sobrien} 60460484Sobrien 60560484Sobrien/* Check if file is a win32 binary resource file, if so 60660484Sobrien skip past the null resource. Returns 0 if successful, -1 on 60760484Sobrien error. 60860484Sobrien */ 60960484Sobrienstatic void 610218822Sdimskip_null_resource (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax) 61160484Sobrien{ 612218822Sdim res_hdr reshdr; 613218822Sdim read_res_data_hdr (wrbfd, off, omax, &reshdr); 614218822Sdim if (reshdr.data_size != 0) 61560484Sobrien goto skip_err; 616218822Sdim if ((reshdr.header_size != 0x20 && ! target_is_bigendian) 617218822Sdim || (reshdr.header_size != 0x20000000 && target_is_bigendian)) 618218822Sdim goto skip_err; 61960484Sobrien 620218822Sdim /* Subtract size of HeaderSize. DataSize has to be zero. */ 621218822Sdim off[0] += 0x20 - BIN_RES_HDR_SIZE; 622218822Sdim if (off[0] >= omax) 62360484Sobrien goto skip_err; 62460484Sobrien 62560484Sobrien return; 62660484Sobrien 62760484Sobrienskip_err: 62860484Sobrien fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name, 62960484Sobrien filename); 63060484Sobrien xexit (1); 63160484Sobrien} 63260484Sobrien 63360484Sobrien/* Add a resource to resource directory */ 634218822Sdimstatic void 635218822Sdimres_add_resource (rc_res_resource *r, const rc_res_id *type, const rc_res_id *id, 636218822Sdim rc_uint_type language, int dupok) 63760484Sobrien{ 638218822Sdim rc_res_id a[3]; 63960484Sobrien 64060484Sobrien a[0] = *type; 64160484Sobrien a[1] = *id; 64260484Sobrien a[2].named = 0; 64360484Sobrien a[2].u.id = language; 64460484Sobrien res_append_resource (&resources, r, 3, a, dupok); 64560484Sobrien} 64660484Sobrien 64760484Sobrien/* Append a resource to resource directory. 64860484Sobrien This is just copied from define_resource 64960484Sobrien and modified to add an existing resource. 65060484Sobrien */ 651218822Sdimstatic void 652218822Sdimres_append_resource (rc_res_directory **resources, rc_res_resource *resource, 653218822Sdim int cids, const rc_res_id *ids, int dupok) 65460484Sobrien{ 655218822Sdim rc_res_entry *re = NULL; 65660484Sobrien int i; 65760484Sobrien 65860484Sobrien assert (cids > 0); 65960484Sobrien for (i = 0; i < cids; i++) 66060484Sobrien { 661218822Sdim rc_res_entry **pp; 66260484Sobrien 66360484Sobrien if (*resources == NULL) 66460484Sobrien { 66560484Sobrien static unsigned long timeval; 66660484Sobrien 66760484Sobrien /* Use the same timestamp for every resource created in a 66860484Sobrien single run. */ 66960484Sobrien if (timeval == 0) 67060484Sobrien timeval = time (NULL); 67160484Sobrien 672218822Sdim *resources = ((rc_res_directory *) 673218822Sdim res_alloc (sizeof (rc_res_directory))); 67460484Sobrien (*resources)->characteristics = 0; 67560484Sobrien (*resources)->time = timeval; 67660484Sobrien (*resources)->major = 0; 67760484Sobrien (*resources)->minor = 0; 67860484Sobrien (*resources)->entries = NULL; 67960484Sobrien } 68060484Sobrien 68160484Sobrien for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next) 68260484Sobrien if (res_id_cmp ((*pp)->id, ids[i]) == 0) 68360484Sobrien break; 68460484Sobrien 68560484Sobrien if (*pp != NULL) 68660484Sobrien re = *pp; 68760484Sobrien else 68860484Sobrien { 689218822Sdim re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry)); 69060484Sobrien re->next = NULL; 69160484Sobrien re->id = ids[i]; 69260484Sobrien if ((i + 1) < cids) 69360484Sobrien { 69460484Sobrien re->subdir = 1; 69560484Sobrien re->u.dir = NULL; 69660484Sobrien } 69760484Sobrien else 69860484Sobrien { 69960484Sobrien re->subdir = 0; 70060484Sobrien re->u.res = NULL; 70160484Sobrien } 70260484Sobrien 70360484Sobrien *pp = re; 70460484Sobrien } 70560484Sobrien 70660484Sobrien if ((i + 1) < cids) 70760484Sobrien { 708218822Sdim if (! re->subdir) 70960484Sobrien { 71060484Sobrien fprintf (stderr, "%s: ", program_name); 71160484Sobrien res_ids_print (stderr, i, ids); 71260484Sobrien fprintf (stderr, ": expected to be a directory\n"); 71360484Sobrien xexit (1); 71460484Sobrien } 71560484Sobrien 71660484Sobrien resources = &re->u.dir; 71760484Sobrien } 71860484Sobrien } 71960484Sobrien 72060484Sobrien if (re->subdir) 72160484Sobrien { 72260484Sobrien fprintf (stderr, "%s: ", program_name); 72360484Sobrien res_ids_print (stderr, cids, ids); 72460484Sobrien fprintf (stderr, ": expected to be a leaf\n"); 72560484Sobrien xexit (1); 72660484Sobrien } 72760484Sobrien 72860484Sobrien if (re->u.res != NULL) 72960484Sobrien { 73060484Sobrien if (dupok) 73160484Sobrien return; 73260484Sobrien 73360484Sobrien fprintf (stderr, "%s: warning: ", program_name); 73460484Sobrien res_ids_print (stderr, cids, ids); 73560484Sobrien fprintf (stderr, ": duplicate value\n"); 73660484Sobrien } 73760484Sobrien 73860484Sobrien re->u.res = resource; 73960484Sobrien} 740