175fd0b74Schristos /* resres.c: read_res_file and write_res_file implementation for windres.
2*e992f068Schristos Copyright (C) 1998-2022 Free Software Foundation, Inc.
375fd0b74Schristos Written by Anders Norlander <anorland@hem2.passagen.se>.
475fd0b74Schristos Rewritten by Kai Tietz, Onevision.
575fd0b74Schristos
675fd0b74Schristos This file is part of GNU Binutils.
775fd0b74Schristos
875fd0b74Schristos This program is free software; you can redistribute it and/or modify
975fd0b74Schristos it under the terms of the GNU General Public License as published by
1075fd0b74Schristos the Free Software Foundation; either version 3 of the License, or
1175fd0b74Schristos (at your option) any later version.
1275fd0b74Schristos
1375fd0b74Schristos This program is distributed in the hope that it will be useful,
1475fd0b74Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
1575fd0b74Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1675fd0b74Schristos GNU General Public License for more details.
1775fd0b74Schristos
1875fd0b74Schristos You should have received a copy of the GNU General Public License
1975fd0b74Schristos along with this program; if not, write to the Free Software
2075fd0b74Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
2175fd0b74Schristos 02110-1301, USA. */
2275fd0b74Schristos
2375fd0b74Schristos /* FIXME: This file does not work correctly in a cross configuration.
2475fd0b74Schristos It assumes that it can use fread and fwrite to read and write
2575fd0b74Schristos integers. It does no swapping. */
2675fd0b74Schristos
2775fd0b74Schristos #include "sysdep.h"
2875fd0b74Schristos #include "bfd.h"
2975fd0b74Schristos #include "bucomm.h"
3075fd0b74Schristos #include "libiberty.h"
3175fd0b74Schristos #include "windres.h"
3275fd0b74Schristos
3375fd0b74Schristos #include <assert.h>
3475fd0b74Schristos
3575fd0b74Schristos static rc_uint_type write_res_directory (windres_bfd *, rc_uint_type,
3675fd0b74Schristos const rc_res_directory *, const rc_res_id *,
3775fd0b74Schristos const rc_res_id *, rc_uint_type *, int);
3875fd0b74Schristos static rc_uint_type write_res_resource (windres_bfd *, rc_uint_type,const rc_res_id *,
3975fd0b74Schristos const rc_res_id *, const rc_res_resource *,
4075fd0b74Schristos rc_uint_type *);
4175fd0b74Schristos static rc_uint_type write_res_bin (windres_bfd *, rc_uint_type, const rc_res_resource *,
4275fd0b74Schristos const rc_res_id *, const rc_res_id *,
4375fd0b74Schristos const rc_res_res_info *);
4475fd0b74Schristos
4575fd0b74Schristos static rc_uint_type write_res_id (windres_bfd *, rc_uint_type, const rc_res_id *);
4675fd0b74Schristos static rc_uint_type write_res_info (windres_bfd *, rc_uint_type, const rc_res_res_info *);
4775fd0b74Schristos static rc_uint_type write_res_data_hdr (windres_bfd *, rc_uint_type, res_hdr *);
4875fd0b74Schristos
4975fd0b74Schristos static rc_uint_type write_res_header (windres_bfd *, rc_uint_type, rc_uint_type,
5075fd0b74Schristos const rc_res_id *, const rc_res_id *,
5175fd0b74Schristos const rc_res_res_info *);
5275fd0b74Schristos
5375fd0b74Schristos static int read_resource_entry (windres_bfd *, rc_uint_type *, rc_uint_type);
5475fd0b74Schristos static void read_res_data (windres_bfd *, rc_uint_type *, rc_uint_type, void *,
5575fd0b74Schristos rc_uint_type);
5675fd0b74Schristos static void read_res_data_hdr (windres_bfd *, rc_uint_type *, rc_uint_type, res_hdr *);
5775fd0b74Schristos static void read_res_id (windres_bfd *, rc_uint_type *, rc_uint_type, rc_res_id *);
5875fd0b74Schristos static unichar *read_unistring (windres_bfd *, rc_uint_type *, rc_uint_type, rc_uint_type *);
5975fd0b74Schristos static void skip_null_resource (windres_bfd *, rc_uint_type *, rc_uint_type);
6075fd0b74Schristos static int probe_binary (windres_bfd *wrbfd, rc_uint_type);
6175fd0b74Schristos
6275fd0b74Schristos static unsigned long get_id_size (const rc_res_id *);
6375fd0b74Schristos
6475fd0b74Schristos static void res_add_resource (rc_res_resource *, const rc_res_id *,
6575fd0b74Schristos const rc_res_id *, rc_uint_type, int);
6675fd0b74Schristos
6775fd0b74Schristos static void res_append_resource (rc_res_directory **, rc_res_resource *,
6875fd0b74Schristos int, const rc_res_id *, int);
6975fd0b74Schristos
7075fd0b74Schristos static rc_res_directory *resources = NULL;
7175fd0b74Schristos
7275fd0b74Schristos static const char *filename;
7375fd0b74Schristos
7475fd0b74Schristos extern char *program_name;
7575fd0b74Schristos
7675fd0b74Schristos /* Read resource file */
7775fd0b74Schristos rc_res_directory *
read_res_file(const char * fn)7875fd0b74Schristos read_res_file (const char *fn)
7975fd0b74Schristos {
8075fd0b74Schristos rc_uint_type off, flen;
8175fd0b74Schristos windres_bfd wrbfd;
8275fd0b74Schristos bfd *abfd;
8375fd0b74Schristos asection *sec;
8475fd0b74Schristos filename = fn;
8575fd0b74Schristos
8675fd0b74Schristos flen = (rc_uint_type) get_file_size (filename);
8775fd0b74Schristos if (! flen)
8875fd0b74Schristos fatal ("can't open '%s' for input.", filename);
8975fd0b74Schristos abfd = windres_open_as_binary (filename, 1);
9075fd0b74Schristos sec = bfd_get_section_by_name (abfd, ".data");
9175fd0b74Schristos if (sec == NULL)
9275fd0b74Schristos bfd_fatal ("bfd_get_section_by_name");
9375fd0b74Schristos set_windres_bfd (&wrbfd, abfd, sec,
9475fd0b74Schristos (target_is_bigendian ? WR_KIND_BFD_BIN_B
9575fd0b74Schristos : WR_KIND_BFD_BIN_L));
9675fd0b74Schristos off = 0;
9775fd0b74Schristos
9875fd0b74Schristos if (! probe_binary (&wrbfd, flen))
9975fd0b74Schristos set_windres_bfd_endianness (&wrbfd, ! target_is_bigendian);
10075fd0b74Schristos
10175fd0b74Schristos skip_null_resource (&wrbfd, &off, flen);
10275fd0b74Schristos
10375fd0b74Schristos while (read_resource_entry (&wrbfd, &off, flen))
10475fd0b74Schristos ;
10575fd0b74Schristos
10675fd0b74Schristos bfd_close (abfd);
10775fd0b74Schristos
10875fd0b74Schristos return resources;
10975fd0b74Schristos }
11075fd0b74Schristos
11175fd0b74Schristos /* Write resource file */
11275fd0b74Schristos void
write_res_file(const char * fn,const rc_res_directory * resdir)11375fd0b74Schristos write_res_file (const char *fn,const rc_res_directory *resdir)
11475fd0b74Schristos {
11575fd0b74Schristos asection *sec;
11675fd0b74Schristos rc_uint_type language;
11775fd0b74Schristos bfd *abfd;
11875fd0b74Schristos windres_bfd wrbfd;
11975fd0b74Schristos unsigned long sec_length = 0,sec_length_wrote;
12075fd0b74Schristos static const bfd_byte sign[] =
12175fd0b74Schristos {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
12275fd0b74Schristos 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
12375fd0b74Schristos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
12475fd0b74Schristos 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
12575fd0b74Schristos
12675fd0b74Schristos filename = fn;
12775fd0b74Schristos
12875fd0b74Schristos abfd = windres_open_as_binary (filename, 0);
12975fd0b74Schristos sec = bfd_make_section_with_flags (abfd, ".data",
13075fd0b74Schristos (SEC_HAS_CONTENTS | SEC_ALLOC
13175fd0b74Schristos | SEC_LOAD | SEC_DATA));
13275fd0b74Schristos if (sec == NULL)
13375fd0b74Schristos bfd_fatal ("bfd_make_section");
13475fd0b74Schristos /* Requiring this is probably a bug in BFD. */
13575fd0b74Schristos sec->output_section = sec;
13675fd0b74Schristos
13775fd0b74Schristos set_windres_bfd (&wrbfd, abfd, sec,
13875fd0b74Schristos (target_is_bigendian ? WR_KIND_BFD_BIN_B
13975fd0b74Schristos : WR_KIND_BFD_BIN_L));
14075fd0b74Schristos
14175fd0b74Schristos language = -1;
14275fd0b74Schristos sec_length = write_res_directory ((windres_bfd *) NULL, 0x20UL, resdir,
14375fd0b74Schristos (const rc_res_id *) NULL,
14475fd0b74Schristos (const rc_res_id *) NULL, &language, 1);
145012573ebSchristos if (!bfd_set_section_size (sec, (sec_length + 3) & ~3))
14675fd0b74Schristos bfd_fatal ("bfd_set_section_size");
14775fd0b74Schristos if ((sec_length & 3) != 0)
14875fd0b74Schristos set_windres_bfd_content (&wrbfd, sign, sec_length, 4-(sec_length & 3));
14975fd0b74Schristos set_windres_bfd_content (&wrbfd, sign, 0, sizeof (sign));
15075fd0b74Schristos language = -1;
15175fd0b74Schristos sec_length_wrote = write_res_directory (&wrbfd, 0x20UL, resdir,
15275fd0b74Schristos (const rc_res_id *) NULL,
15375fd0b74Schristos (const rc_res_id *) NULL,
15475fd0b74Schristos &language, 1);
15575fd0b74Schristos if (sec_length != sec_length_wrote)
15675fd0b74Schristos fatal ("res write failed with different sizes (%lu/%lu).",
15775fd0b74Schristos (unsigned long) sec_length, (unsigned long) sec_length_wrote);
15875fd0b74Schristos
15975fd0b74Schristos bfd_close (abfd);
16075fd0b74Schristos return;
16175fd0b74Schristos }
16275fd0b74Schristos
16375fd0b74Schristos /* Read a resource entry, returns 0 when all resources are read */
16475fd0b74Schristos static int
read_resource_entry(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax)16575fd0b74Schristos read_resource_entry (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
16675fd0b74Schristos {
16775fd0b74Schristos rc_res_id type;
16875fd0b74Schristos rc_res_id name;
16975fd0b74Schristos rc_res_res_info resinfo;
17075fd0b74Schristos res_hdr reshdr;
17175fd0b74Schristos void *buff;
17275fd0b74Schristos
17375fd0b74Schristos rc_res_resource *r;
17475fd0b74Schristos struct bin_res_info l;
17575fd0b74Schristos
17675fd0b74Schristos off[0] = (off[0] + 3) & ~3;
17775fd0b74Schristos
17875fd0b74Schristos /* Read header */
17975fd0b74Schristos if ((off[0] + 8) > omax)
18075fd0b74Schristos return 0;
18175fd0b74Schristos read_res_data_hdr (wrbfd, off, omax, &reshdr);
18275fd0b74Schristos
18375fd0b74Schristos /* read resource type */
18475fd0b74Schristos read_res_id (wrbfd, off, omax, &type);
18575fd0b74Schristos /* read resource id */
18675fd0b74Schristos read_res_id (wrbfd, off, omax, &name);
18775fd0b74Schristos
18875fd0b74Schristos off[0] = (off[0] + 3) & ~3;
18975fd0b74Schristos
19075fd0b74Schristos /* Read additional resource header */
19175fd0b74Schristos read_res_data (wrbfd, off, omax, &l, BIN_RES_INFO_SIZE);
19275fd0b74Schristos resinfo.version = windres_get_32 (wrbfd, l.version, 4);
19375fd0b74Schristos resinfo.memflags = windres_get_16 (wrbfd, l.memflags, 2);
19475fd0b74Schristos resinfo.language = windres_get_16 (wrbfd, l.language, 2);
19575fd0b74Schristos /* resinfo.version2 = windres_get_32 (wrbfd, l.version2, 4); */
19675fd0b74Schristos resinfo.characteristics = windres_get_32 (wrbfd, l.characteristics, 4);
19775fd0b74Schristos
19875fd0b74Schristos off[0] = (off[0] + 3) & ~3;
19975fd0b74Schristos
20075fd0b74Schristos /* Allocate buffer for data */
20175fd0b74Schristos buff = res_alloc (reshdr.data_size);
20275fd0b74Schristos /* Read data */
20375fd0b74Schristos read_res_data (wrbfd, off, omax, buff, reshdr.data_size);
20475fd0b74Schristos /* Convert binary data to resource */
20575fd0b74Schristos r = bin_to_res (wrbfd, type, buff, reshdr.data_size);
20675fd0b74Schristos r->res_info = resinfo;
20775fd0b74Schristos /* Add resource to resource directory */
20875fd0b74Schristos res_add_resource (r, &type, &name, resinfo.language, 0);
20975fd0b74Schristos
21075fd0b74Schristos return 1;
21175fd0b74Schristos }
21275fd0b74Schristos
21375fd0b74Schristos /* write resource directory to binary resource file */
21475fd0b74Schristos static rc_uint_type
write_res_directory(windres_bfd * wrbfd,rc_uint_type off,const rc_res_directory * rd,const rc_res_id * type,const rc_res_id * name,rc_uint_type * language,int level)21575fd0b74Schristos write_res_directory (windres_bfd *wrbfd, rc_uint_type off, const rc_res_directory *rd,
21675fd0b74Schristos const rc_res_id *type, const rc_res_id *name, rc_uint_type *language,
21775fd0b74Schristos int level)
21875fd0b74Schristos {
21975fd0b74Schristos const rc_res_entry *re;
22075fd0b74Schristos
22175fd0b74Schristos for (re = rd->entries; re != NULL; re = re->next)
22275fd0b74Schristos {
22375fd0b74Schristos switch (level)
22475fd0b74Schristos {
22575fd0b74Schristos case 1:
22675fd0b74Schristos /* If we're at level 1, the key of this resource is the
22775fd0b74Schristos type. This normally duplicates the information we have
22875fd0b74Schristos stored with the resource itself, but we need to remember
22975fd0b74Schristos the type if this is a user define resource type. */
23075fd0b74Schristos type = &re->id;
23175fd0b74Schristos break;
23275fd0b74Schristos
23375fd0b74Schristos case 2:
23475fd0b74Schristos /* If we're at level 2, the key of this resource is the name
23575fd0b74Schristos we are going to use in the rc printout. */
23675fd0b74Schristos name = &re->id;
23775fd0b74Schristos break;
23875fd0b74Schristos
23975fd0b74Schristos case 3:
24075fd0b74Schristos /* If we're at level 3, then this key represents a language.
24175fd0b74Schristos Use it to update the current language. */
24275fd0b74Schristos if (! re->id.named
24375fd0b74Schristos && re->id.u.id != (unsigned long) *language
24475fd0b74Schristos && (re->id.u.id & 0xffff) == re->id.u.id)
24575fd0b74Schristos {
24675fd0b74Schristos *language = re->id.u.id;
24775fd0b74Schristos }
24875fd0b74Schristos break;
24975fd0b74Schristos
25075fd0b74Schristos default:
25175fd0b74Schristos break;
25275fd0b74Schristos }
25375fd0b74Schristos
25475fd0b74Schristos if (re->subdir)
25575fd0b74Schristos off = write_res_directory (wrbfd, off, re->u.dir, type, name, language,
25675fd0b74Schristos level + 1);
25775fd0b74Schristos else
25875fd0b74Schristos {
25975fd0b74Schristos if (level == 3)
26075fd0b74Schristos {
26175fd0b74Schristos /* This is the normal case: the three levels are
26275fd0b74Schristos TYPE/NAME/LANGUAGE. NAME will have been set at level
26375fd0b74Schristos 2, and represents the name to use. We probably just
26475fd0b74Schristos set LANGUAGE, and it will probably match what the
26575fd0b74Schristos resource itself records if anything. */
26675fd0b74Schristos off = write_res_resource (wrbfd, off, type, name, re->u.res,
26775fd0b74Schristos language);
26875fd0b74Schristos }
26975fd0b74Schristos else
27075fd0b74Schristos {
27175fd0b74Schristos fprintf (stderr, "// Resource at unexpected level %d\n", level);
27275fd0b74Schristos off = write_res_resource (wrbfd, off, type, (rc_res_id *) NULL,
27375fd0b74Schristos re->u.res, language);
27475fd0b74Schristos }
27575fd0b74Schristos }
27675fd0b74Schristos }
27775fd0b74Schristos
27875fd0b74Schristos return off;
27975fd0b74Schristos }
28075fd0b74Schristos
28175fd0b74Schristos static rc_uint_type
write_res_resource(windres_bfd * wrbfd,rc_uint_type off,const rc_res_id * type,const rc_res_id * name,const rc_res_resource * res,rc_uint_type * language ATTRIBUTE_UNUSED)28275fd0b74Schristos write_res_resource (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *type,
28375fd0b74Schristos const rc_res_id *name, const rc_res_resource *res,
28475fd0b74Schristos rc_uint_type *language ATTRIBUTE_UNUSED)
28575fd0b74Schristos {
28675fd0b74Schristos int rt;
28775fd0b74Schristos
28875fd0b74Schristos switch (res->type)
28975fd0b74Schristos {
29075fd0b74Schristos default:
29175fd0b74Schristos abort ();
29275fd0b74Schristos
29375fd0b74Schristos case RES_TYPE_ACCELERATOR:
29475fd0b74Schristos rt = RT_ACCELERATOR;
29575fd0b74Schristos break;
29675fd0b74Schristos
29775fd0b74Schristos case RES_TYPE_BITMAP:
29875fd0b74Schristos rt = RT_BITMAP;
29975fd0b74Schristos break;
30075fd0b74Schristos
30175fd0b74Schristos case RES_TYPE_CURSOR:
30275fd0b74Schristos rt = RT_CURSOR;
30375fd0b74Schristos break;
30475fd0b74Schristos
30575fd0b74Schristos case RES_TYPE_GROUP_CURSOR:
30675fd0b74Schristos rt = RT_GROUP_CURSOR;
30775fd0b74Schristos break;
30875fd0b74Schristos
30975fd0b74Schristos case RES_TYPE_DIALOG:
31075fd0b74Schristos rt = RT_DIALOG;
31175fd0b74Schristos break;
31275fd0b74Schristos
31375fd0b74Schristos case RES_TYPE_FONT:
31475fd0b74Schristos rt = RT_FONT;
31575fd0b74Schristos break;
31675fd0b74Schristos
31775fd0b74Schristos case RES_TYPE_FONTDIR:
31875fd0b74Schristos rt = RT_FONTDIR;
31975fd0b74Schristos break;
32075fd0b74Schristos
32175fd0b74Schristos case RES_TYPE_ICON:
32275fd0b74Schristos rt = RT_ICON;
32375fd0b74Schristos break;
32475fd0b74Schristos
32575fd0b74Schristos case RES_TYPE_GROUP_ICON:
32675fd0b74Schristos rt = RT_GROUP_ICON;
32775fd0b74Schristos break;
32875fd0b74Schristos
32975fd0b74Schristos case RES_TYPE_MENU:
33075fd0b74Schristos rt = RT_MENU;
33175fd0b74Schristos break;
33275fd0b74Schristos
33375fd0b74Schristos case RES_TYPE_MESSAGETABLE:
33475fd0b74Schristos rt = RT_MESSAGETABLE;
33575fd0b74Schristos break;
33675fd0b74Schristos
33775fd0b74Schristos case RES_TYPE_RCDATA:
33875fd0b74Schristos rt = RT_RCDATA;
33975fd0b74Schristos break;
34075fd0b74Schristos
34175fd0b74Schristos case RES_TYPE_STRINGTABLE:
34275fd0b74Schristos rt = RT_STRING;
34375fd0b74Schristos break;
34475fd0b74Schristos
34575fd0b74Schristos case RES_TYPE_USERDATA:
34675fd0b74Schristos rt = 0;
34775fd0b74Schristos break;
34875fd0b74Schristos
34975fd0b74Schristos case RES_TYPE_VERSIONINFO:
35075fd0b74Schristos rt = RT_VERSION;
35175fd0b74Schristos break;
35275fd0b74Schristos
35375fd0b74Schristos case RES_TYPE_TOOLBAR:
35475fd0b74Schristos rt = RT_TOOLBAR;
35575fd0b74Schristos break;
35675fd0b74Schristos }
35775fd0b74Schristos
35875fd0b74Schristos if (rt != 0
35975fd0b74Schristos && type != NULL
36075fd0b74Schristos && (type->named || type->u.id != (unsigned long) rt))
36175fd0b74Schristos {
36275fd0b74Schristos fprintf (stderr, "// Unexpected resource type mismatch: ");
36375fd0b74Schristos res_id_print (stderr, *type, 1);
36475fd0b74Schristos fprintf (stderr, " != %d", rt);
36575fd0b74Schristos abort ();
36675fd0b74Schristos }
36775fd0b74Schristos
36875fd0b74Schristos return write_res_bin (wrbfd, off, res, type, name, &res->res_info);
36975fd0b74Schristos }
37075fd0b74Schristos
37175fd0b74Schristos /* Write a resource in binary resource format */
37275fd0b74Schristos static rc_uint_type
write_res_bin(windres_bfd * wrbfd,rc_uint_type off,const rc_res_resource * res,const rc_res_id * type,const rc_res_id * name,const rc_res_res_info * resinfo)37375fd0b74Schristos write_res_bin (windres_bfd *wrbfd, rc_uint_type off, const rc_res_resource *res,
37475fd0b74Schristos const rc_res_id *type, const rc_res_id *name,
37575fd0b74Schristos const rc_res_res_info *resinfo)
37675fd0b74Schristos {
37775fd0b74Schristos rc_uint_type noff;
37875fd0b74Schristos rc_uint_type datasize = 0;
37975fd0b74Schristos
38075fd0b74Schristos noff = res_to_bin ((windres_bfd *) NULL, off, res);
38175fd0b74Schristos datasize = noff - off;
38275fd0b74Schristos
38375fd0b74Schristos off = write_res_header (wrbfd, off, datasize, type, name, resinfo);
38475fd0b74Schristos return res_to_bin (wrbfd, off, res);
38575fd0b74Schristos }
38675fd0b74Schristos
38775fd0b74Schristos /* Get number of bytes needed to store an id in binary format */
38875fd0b74Schristos static unsigned long
get_id_size(const rc_res_id * id)38975fd0b74Schristos get_id_size (const rc_res_id *id)
39075fd0b74Schristos {
39175fd0b74Schristos if (id->named)
39275fd0b74Schristos return sizeof (unichar) * (id->u.n.length + 1);
39375fd0b74Schristos else
39475fd0b74Schristos return sizeof (unichar) * 2;
39575fd0b74Schristos }
39675fd0b74Schristos
39775fd0b74Schristos /* Write a resource header */
39875fd0b74Schristos static rc_uint_type
write_res_header(windres_bfd * wrbfd,rc_uint_type off,rc_uint_type datasize,const rc_res_id * type,const rc_res_id * name,const rc_res_res_info * resinfo)39975fd0b74Schristos write_res_header (windres_bfd *wrbfd, rc_uint_type off, rc_uint_type datasize,
40075fd0b74Schristos const rc_res_id *type, const rc_res_id *name,
40175fd0b74Schristos const rc_res_res_info *resinfo)
40275fd0b74Schristos {
40375fd0b74Schristos res_hdr reshdr;
40475fd0b74Schristos reshdr.data_size = datasize;
40575fd0b74Schristos reshdr.header_size = 24 + get_id_size (type) + get_id_size (name);
40675fd0b74Schristos
40775fd0b74Schristos reshdr.header_size = (reshdr.header_size + 3) & ~3;
40875fd0b74Schristos
40975fd0b74Schristos off = (off + 3) & ~3;
41075fd0b74Schristos
41175fd0b74Schristos off = write_res_data_hdr (wrbfd, off, &reshdr);
41275fd0b74Schristos off = write_res_id (wrbfd, off, type);
41375fd0b74Schristos off = write_res_id (wrbfd, off, name);
41475fd0b74Schristos
41575fd0b74Schristos off = (off + 3) & ~3;
41675fd0b74Schristos
41775fd0b74Schristos off = write_res_info (wrbfd, off, resinfo);
41875fd0b74Schristos off = (off + 3) & ~3;
41975fd0b74Schristos return off;
42075fd0b74Schristos }
42175fd0b74Schristos
42275fd0b74Schristos static rc_uint_type
write_res_data_hdr(windres_bfd * wrbfd,rc_uint_type off,res_hdr * hdr)42375fd0b74Schristos write_res_data_hdr (windres_bfd *wrbfd, rc_uint_type off, res_hdr *hdr)
42475fd0b74Schristos {
42575fd0b74Schristos if (wrbfd)
42675fd0b74Schristos {
42775fd0b74Schristos struct bin_res_hdr brh;
42875fd0b74Schristos windres_put_32 (wrbfd, brh.data_size, hdr->data_size);
42975fd0b74Schristos windres_put_32 (wrbfd, brh.header_size, hdr->header_size);
43075fd0b74Schristos set_windres_bfd_content (wrbfd, &brh, off, BIN_RES_HDR_SIZE);
43175fd0b74Schristos }
43275fd0b74Schristos return off + BIN_RES_HDR_SIZE;
43375fd0b74Schristos }
43475fd0b74Schristos
43575fd0b74Schristos static void
read_res_data_hdr(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax,res_hdr * reshdr)43675fd0b74Schristos read_res_data_hdr (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
43775fd0b74Schristos res_hdr *reshdr)
43875fd0b74Schristos {
43975fd0b74Schristos struct bin_res_hdr brh;
44075fd0b74Schristos
44175fd0b74Schristos if ((off[0] + BIN_RES_HDR_SIZE) > omax)
44275fd0b74Schristos fatal ("%s: unexpected end of file %ld/%ld", filename,(long) off[0], (long) omax);
44375fd0b74Schristos
44475fd0b74Schristos get_windres_bfd_content (wrbfd, &brh, off[0], BIN_RES_HDR_SIZE);
44575fd0b74Schristos reshdr->data_size = windres_get_32 (wrbfd, brh.data_size, 4);
44675fd0b74Schristos reshdr->header_size = windres_get_32 (wrbfd, brh.header_size, 4);
44775fd0b74Schristos off[0] += BIN_RES_HDR_SIZE;
44875fd0b74Schristos }
44975fd0b74Schristos
45075fd0b74Schristos /* Read data from file, abort on failure */
45175fd0b74Schristos static void
read_res_data(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax,void * data,rc_uint_type size)45275fd0b74Schristos read_res_data (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, void *data,
45375fd0b74Schristos rc_uint_type size)
45475fd0b74Schristos {
45575fd0b74Schristos if ((off[0] + size) > omax)
45675fd0b74Schristos fatal ("%s: unexpected end of file %ld/%ld %ld", filename,(long) off[0],
45775fd0b74Schristos (long) omax, (long) size);
45875fd0b74Schristos get_windres_bfd_content (wrbfd, data, off[0], size);
45975fd0b74Schristos off[0] += size;
46075fd0b74Schristos }
46175fd0b74Schristos
46275fd0b74Schristos /* Write a resource id */
46375fd0b74Schristos static rc_uint_type
write_res_id(windres_bfd * wrbfd,rc_uint_type off,const rc_res_id * id)46475fd0b74Schristos write_res_id (windres_bfd *wrbfd, rc_uint_type off, const rc_res_id *id)
46575fd0b74Schristos {
46675fd0b74Schristos if (id->named)
46775fd0b74Schristos {
46875fd0b74Schristos rc_uint_type len = (((bfd_signed_vma) id->u.n.length < 0 ? 0 : id->u.n.length) + 1);
46975fd0b74Schristos if (wrbfd)
47075fd0b74Schristos {
47175fd0b74Schristos rc_uint_type i;
47275fd0b74Schristos bfd_byte *d = (bfd_byte *) xmalloc (len * sizeof (unichar));
47375fd0b74Schristos for (i = 0; i < (len - 1); i++)
47475fd0b74Schristos windres_put_16 (wrbfd, d + (i * sizeof (unichar)), id->u.n.name[i]);
47575fd0b74Schristos windres_put_16 (wrbfd, d + (i * sizeof (unichar)), 0);
47675fd0b74Schristos set_windres_bfd_content (wrbfd, d, off, (len * sizeof (unichar)));
47775fd0b74Schristos }
47875fd0b74Schristos off += (len * sizeof (unichar));
47975fd0b74Schristos }
48075fd0b74Schristos else
48175fd0b74Schristos {
48275fd0b74Schristos if (wrbfd)
48375fd0b74Schristos {
48475fd0b74Schristos struct bin_res_id bid;
48575fd0b74Schristos windres_put_16 (wrbfd, bid.sig, 0xffff);
48675fd0b74Schristos windres_put_16 (wrbfd, bid.id, id->u.id);
48775fd0b74Schristos set_windres_bfd_content (wrbfd, &bid, off, BIN_RES_ID);
48875fd0b74Schristos }
48975fd0b74Schristos off += BIN_RES_ID;
49075fd0b74Schristos }
49175fd0b74Schristos return off;
49275fd0b74Schristos }
49375fd0b74Schristos
49475fd0b74Schristos /* Write resource info */
49575fd0b74Schristos static rc_uint_type
write_res_info(windres_bfd * wrbfd,rc_uint_type off,const rc_res_res_info * info)49675fd0b74Schristos write_res_info (windres_bfd *wrbfd, rc_uint_type off, const rc_res_res_info *info)
49775fd0b74Schristos {
49875fd0b74Schristos if (wrbfd)
49975fd0b74Schristos {
50075fd0b74Schristos struct bin_res_info l;
50175fd0b74Schristos
50275fd0b74Schristos windres_put_32 (wrbfd, l.version, info->version);
50375fd0b74Schristos windres_put_16 (wrbfd, l.memflags, info->memflags);
50475fd0b74Schristos windres_put_16 (wrbfd, l.language, info->language);
50575fd0b74Schristos windres_put_32 (wrbfd, l.version2, info->version);
50675fd0b74Schristos windres_put_32 (wrbfd, l.characteristics, info->characteristics);
50775fd0b74Schristos set_windres_bfd_content (wrbfd, &l, off, BIN_RES_INFO_SIZE);
50875fd0b74Schristos }
50975fd0b74Schristos return off + BIN_RES_INFO_SIZE;
51075fd0b74Schristos }
51175fd0b74Schristos
51275fd0b74Schristos /* read a resource identifier */
51375fd0b74Schristos static void
read_res_id(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax,rc_res_id * id)51475fd0b74Schristos read_res_id (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax, rc_res_id *id)
51575fd0b74Schristos {
51675fd0b74Schristos struct bin_res_id bid;
51775fd0b74Schristos unsigned short ord;
51875fd0b74Schristos unichar *id_s = NULL;
51975fd0b74Schristos rc_uint_type len;
52075fd0b74Schristos
52175fd0b74Schristos read_res_data (wrbfd, off, omax, &bid, BIN_RES_ID - 2);
52275fd0b74Schristos ord = (unsigned short) windres_get_16 (wrbfd, bid.sig, 2);
52375fd0b74Schristos if (ord == 0xFFFF) /* an ordinal id */
52475fd0b74Schristos {
52575fd0b74Schristos read_res_data (wrbfd, off, omax, bid.id, BIN_RES_ID - 2);
52675fd0b74Schristos id->named = 0;
52775fd0b74Schristos id->u.id = windres_get_16 (wrbfd, bid.id, 2);
52875fd0b74Schristos }
52975fd0b74Schristos else
53075fd0b74Schristos /* named id */
53175fd0b74Schristos {
53275fd0b74Schristos off[0] -= 2;
53375fd0b74Schristos id_s = read_unistring (wrbfd, off, omax, &len);
53475fd0b74Schristos id->named = 1;
53575fd0b74Schristos id->u.n.length = len;
53675fd0b74Schristos id->u.n.name = id_s;
53775fd0b74Schristos }
53875fd0b74Schristos }
53975fd0b74Schristos
54075fd0b74Schristos /* Read a null terminated UNICODE string */
54175fd0b74Schristos static unichar *
read_unistring(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax,rc_uint_type * len)54275fd0b74Schristos read_unistring (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax,
54375fd0b74Schristos rc_uint_type *len)
54475fd0b74Schristos {
54575fd0b74Schristos unichar *s;
54675fd0b74Schristos bfd_byte d[2];
54775fd0b74Schristos unichar c;
54875fd0b74Schristos unichar *p;
54975fd0b74Schristos rc_uint_type l;
55075fd0b74Schristos rc_uint_type soff = off[0];
55175fd0b74Schristos
55275fd0b74Schristos do
55375fd0b74Schristos {
55475fd0b74Schristos read_res_data (wrbfd, &soff, omax, d, sizeof (unichar));
55575fd0b74Schristos c = windres_get_16 (wrbfd, d, 2);
55675fd0b74Schristos }
55775fd0b74Schristos while (c != 0);
55875fd0b74Schristos l = ((soff - off[0]) / sizeof (unichar));
55975fd0b74Schristos
56075fd0b74Schristos /* there are hardly any names longer than 256 characters, but anyway. */
56175fd0b74Schristos p = s = (unichar *) xmalloc (sizeof (unichar) * l);
56275fd0b74Schristos do
56375fd0b74Schristos {
56475fd0b74Schristos read_res_data (wrbfd, off, omax, d, sizeof (unichar));
56575fd0b74Schristos c = windres_get_16 (wrbfd, d, 2);
56675fd0b74Schristos *p++ = c;
56775fd0b74Schristos }
56875fd0b74Schristos while (c != 0);
56975fd0b74Schristos *len = l - 1;
57075fd0b74Schristos return s;
57175fd0b74Schristos }
57275fd0b74Schristos
57375fd0b74Schristos static int
probe_binary(windres_bfd * wrbfd,rc_uint_type omax)57475fd0b74Schristos probe_binary (windres_bfd *wrbfd, rc_uint_type omax)
57575fd0b74Schristos {
57675fd0b74Schristos rc_uint_type off;
57775fd0b74Schristos res_hdr reshdr;
57875fd0b74Schristos
57975fd0b74Schristos off = 0;
58075fd0b74Schristos read_res_data_hdr (wrbfd, &off, omax, &reshdr);
58175fd0b74Schristos if (reshdr.data_size != 0)
58275fd0b74Schristos return 1;
58375fd0b74Schristos if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
58475fd0b74Schristos || (reshdr.header_size != 0x20000000 && target_is_bigendian))
58575fd0b74Schristos return 1;
58675fd0b74Schristos
58775fd0b74Schristos /* Subtract size of HeaderSize. DataSize has to be zero. */
58875fd0b74Schristos off += 0x20 - BIN_RES_HDR_SIZE;
58975fd0b74Schristos if ((off + BIN_RES_HDR_SIZE) >= omax)
59075fd0b74Schristos return 1;
59175fd0b74Schristos read_res_data_hdr (wrbfd, &off, omax, &reshdr);
59275fd0b74Schristos /* off is advanced by BIN_RES_HDR_SIZE in read_res_data_hdr()
59375fd0b74Schristos which is part of reshdr.header_size. We shouldn't take it
59475fd0b74Schristos into account twice. */
59575fd0b74Schristos if ((off - BIN_RES_HDR_SIZE + reshdr.data_size + reshdr.header_size) > omax)
59675fd0b74Schristos return 0;
59775fd0b74Schristos return 1;
59875fd0b74Schristos }
59975fd0b74Schristos
60075fd0b74Schristos /* Check if file is a win32 binary resource file, if so
60175fd0b74Schristos skip past the null resource. Returns 0 if successful, -1 on
60275fd0b74Schristos error.
60375fd0b74Schristos */
60475fd0b74Schristos static void
skip_null_resource(windres_bfd * wrbfd,rc_uint_type * off,rc_uint_type omax)60575fd0b74Schristos skip_null_resource (windres_bfd *wrbfd, rc_uint_type *off, rc_uint_type omax)
60675fd0b74Schristos {
60775fd0b74Schristos res_hdr reshdr;
60875fd0b74Schristos read_res_data_hdr (wrbfd, off, omax, &reshdr);
60975fd0b74Schristos if (reshdr.data_size != 0)
61075fd0b74Schristos goto skip_err;
61175fd0b74Schristos if ((reshdr.header_size != 0x20 && ! target_is_bigendian)
61275fd0b74Schristos || (reshdr.header_size != 0x20000000 && target_is_bigendian))
61375fd0b74Schristos goto skip_err;
61475fd0b74Schristos
61575fd0b74Schristos /* Subtract size of HeaderSize. DataSize has to be zero. */
61675fd0b74Schristos off[0] += 0x20 - BIN_RES_HDR_SIZE;
61775fd0b74Schristos if (off[0] >= omax)
61875fd0b74Schristos goto skip_err;
61975fd0b74Schristos
62075fd0b74Schristos return;
62175fd0b74Schristos
62275fd0b74Schristos skip_err:
62375fd0b74Schristos fprintf (stderr, "%s: %s: Not a valid WIN32 resource file\n", program_name,
62475fd0b74Schristos filename);
62575fd0b74Schristos xexit (1);
62675fd0b74Schristos }
62775fd0b74Schristos
62875fd0b74Schristos /* Add a resource to resource directory */
62975fd0b74Schristos static void
res_add_resource(rc_res_resource * r,const rc_res_id * type,const rc_res_id * id,rc_uint_type language,int dupok)63075fd0b74Schristos res_add_resource (rc_res_resource *r, const rc_res_id *type, const rc_res_id *id,
63175fd0b74Schristos rc_uint_type language, int dupok)
63275fd0b74Schristos {
63375fd0b74Schristos rc_res_id a[3];
63475fd0b74Schristos
63575fd0b74Schristos a[0] = *type;
63675fd0b74Schristos a[1] = *id;
63775fd0b74Schristos a[2].named = 0;
63875fd0b74Schristos a[2].u.id = language;
63975fd0b74Schristos res_append_resource (&resources, r, 3, a, dupok);
64075fd0b74Schristos }
64175fd0b74Schristos
64275fd0b74Schristos /* Append a resource to resource directory.
64375fd0b74Schristos This is just copied from define_resource
64475fd0b74Schristos and modified to add an existing resource.
64575fd0b74Schristos */
64675fd0b74Schristos static void
res_append_resource(rc_res_directory ** res_dirs,rc_res_resource * resource,int cids,const rc_res_id * ids,int dupok)64775fd0b74Schristos res_append_resource (rc_res_directory **res_dirs, rc_res_resource *resource,
64875fd0b74Schristos int cids, const rc_res_id *ids, int dupok)
64975fd0b74Schristos {
65075fd0b74Schristos rc_res_entry *re = NULL;
65175fd0b74Schristos int i;
65275fd0b74Schristos
65375fd0b74Schristos assert (cids > 0);
65475fd0b74Schristos for (i = 0; i < cids; i++)
65575fd0b74Schristos {
65675fd0b74Schristos rc_res_entry **pp;
65775fd0b74Schristos
65875fd0b74Schristos if (*res_dirs == NULL)
65975fd0b74Schristos {
66075fd0b74Schristos *res_dirs = ((rc_res_directory *)
66175fd0b74Schristos res_alloc (sizeof (rc_res_directory)));
66275fd0b74Schristos
66375fd0b74Schristos (*res_dirs)->characteristics = 0;
66475fd0b74Schristos /* Using a real timestamp only serves to create non-deterministic
66575fd0b74Schristos results. Use zero instead. */
66675fd0b74Schristos (*res_dirs)->time = 0;
66775fd0b74Schristos (*res_dirs)->major = 0;
66875fd0b74Schristos (*res_dirs)->minor = 0;
66975fd0b74Schristos (*res_dirs)->entries = NULL;
67075fd0b74Schristos }
67175fd0b74Schristos
67275fd0b74Schristos for (pp = &(*res_dirs)->entries; *pp != NULL; pp = &(*pp)->next)
67375fd0b74Schristos if (res_id_cmp ((*pp)->id, ids[i]) == 0)
67475fd0b74Schristos break;
67575fd0b74Schristos
67675fd0b74Schristos if (*pp != NULL)
67775fd0b74Schristos re = *pp;
67875fd0b74Schristos else
67975fd0b74Schristos {
68075fd0b74Schristos re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
68175fd0b74Schristos re->next = NULL;
68275fd0b74Schristos re->id = ids[i];
68375fd0b74Schristos if ((i + 1) < cids)
68475fd0b74Schristos {
68575fd0b74Schristos re->subdir = 1;
68675fd0b74Schristos re->u.dir = NULL;
68775fd0b74Schristos }
68875fd0b74Schristos else
68975fd0b74Schristos {
69075fd0b74Schristos re->subdir = 0;
69175fd0b74Schristos re->u.res = NULL;
69275fd0b74Schristos }
69375fd0b74Schristos
69475fd0b74Schristos *pp = re;
69575fd0b74Schristos }
69675fd0b74Schristos
69775fd0b74Schristos if ((i + 1) < cids)
69875fd0b74Schristos {
69975fd0b74Schristos if (! re->subdir)
70075fd0b74Schristos {
70175fd0b74Schristos fprintf (stderr, "%s: ", program_name);
70275fd0b74Schristos res_ids_print (stderr, i, ids);
70375fd0b74Schristos fprintf (stderr, ": expected to be a directory\n");
70475fd0b74Schristos xexit (1);
70575fd0b74Schristos }
70675fd0b74Schristos
70775fd0b74Schristos res_dirs = &re->u.dir;
70875fd0b74Schristos }
70975fd0b74Schristos }
71075fd0b74Schristos
71175fd0b74Schristos if (re->subdir)
71275fd0b74Schristos {
71375fd0b74Schristos fprintf (stderr, "%s: ", program_name);
71475fd0b74Schristos res_ids_print (stderr, cids, ids);
71575fd0b74Schristos fprintf (stderr, ": expected to be a leaf\n");
71675fd0b74Schristos xexit (1);
71775fd0b74Schristos }
71875fd0b74Schristos
71975fd0b74Schristos if (re->u.res != NULL)
72075fd0b74Schristos {
72175fd0b74Schristos if (dupok)
72275fd0b74Schristos return;
72375fd0b74Schristos
72475fd0b74Schristos fprintf (stderr, "%s: warning: ", program_name);
72575fd0b74Schristos res_ids_print (stderr, cids, ids);
72675fd0b74Schristos fprintf (stderr, ": duplicate value\n");
72775fd0b74Schristos }
72875fd0b74Schristos
72975fd0b74Schristos re->u.res = resource;
73075fd0b74Schristos }
731