* resbin.c: New file.

* rclex.l, rcparse.y, rescoff.c, resrc.c, windres.c, windres.h:
	Numerous fixes and improvements.
	* Makefile.in: Rebuild dependencies.
 	(CFILES): Add resbin.c.
	(WINDRES_OBJS): Add resbin.o.
This commit is contained in:
Ian Lance Taylor 1997-06-26 00:59:44 +00:00
parent 9fd0d551fc
commit 662cc41eaf
9 changed files with 3354 additions and 246 deletions

View File

@ -84,6 +84,7 @@ ranlib.1
ranlib.sh
rclex.l
rcparse.y
resbin.c
rescoff.c
resrc.c
rdcoff.c

View File

@ -1,3 +1,12 @@
Wed Jun 25 20:57:06 1997 Ian Lance Taylor <ian@cygnus.com>
* resbin.c: New file.
* rclex.l, rcparse.y, rescoff.c, resrc.c, windres.c, windres.h:
Numerous fixes and improvements.
* Makefile.in: Rebuild dependencies.
(CFILES): Add resbin.c.
(WINDRES_OBJS): Add resbin.o.
Sun Jun 22 17:29:41 1997 Ian Lance Taylor <ian@cygnus.com>
First stab at Windows resource compiler:

View File

@ -138,7 +138,7 @@ CFILES = addr2line.c ar.c arsup.c bucomm.c coffdump.c coffgrok.c debug.c \
maybe-strip.c nlmconv.c nm.c not-ranlib.c not-strip.c \
objcopy.c objdump.c prdbg.c rdcoff.c rddbg.c size.c srconv.c \
stabs.c strings.c sysdump.c version.c wrstabs.c \
windres.c resrc.c rescoff.c
windres.c resrc.c rescoff.c resbin.c
GENERATED_CFILES = \
underscore.c arparse.c arlex.c sysroff.c sysinfo.c syslex.c \
@ -409,7 +409,7 @@ nlmconv.o: nlmconv.c $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h
$(NLMCONV_PROG): nlmconv.o nlmheader.o $(ADDL_DEPS)
$(HLDENV) $(CC) $(HLDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ nlmconv.o nlmheader.o $(ADDL_LIBS) $(EXTRALIBS)
WINDRES_OBJS = windres.o resrc.o rescoff.o rcparse.o rclex.o
WINDRES_OBJS = windres.o resrc.o rescoff.o resbin.o rcparse.o rclex.o
$(WINDRES_PROG): $(WINDRES_OBJS) $(ADDL_DEPS)
$(HLDENV) $(CC) $(HLDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(WINDRES_OBJS) $(ADDL_LIBS) $(EXTRALIBS)
@ -762,7 +762,7 @@ wrstabs.o: wrstabs.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
$(INCDIR)/aout/stab.def
windres.o: windres.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
$(INCDIR)/getopt.h bucomm.h config.h $(INCDIR)/fopen-same.h \
$(INCDIR)/libiberty.h windres.h
$(INCDIR)/libiberty.h $(INCDIR)/obstack.h windres.h
resrc.o: resrc.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
windres.h
@ -770,6 +770,9 @@ rescoff.o: rescoff.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
windres.h $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h \
$(INCDIR)/bfdlink.h
resbin.o: resbin.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \
windres.h
underscore.o: underscore.c
arparse.o: arparse.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \
bucomm.h config.h $(INCDIR)/fopen-same.h arsup.h

View File

@ -32,8 +32,26 @@
#include <ctype.h>
#include <assert.h>
/* Whether we are in rcdata mode, in which we returns the lengths of
strings. */
static int rcdata_mode;
/* List of allocated strings. */
struct alloc_string
{
struct alloc_string *next;
char *s;
};
static struct alloc_string *strings;
/* Local functions. */
static void cpp_line PARAMS ((const char *));
static char *handle_quotes PARAMS ((const char *));
static char *handle_quotes PARAMS ((const char *, unsigned long *));
static char *get_string PARAMS ((int));
%}
@ -133,9 +151,12 @@ static char *handle_quotes PARAMS ((const char *));
return BLOCKVARFILEINFO;
else
{
yylval.s = (char *) xmalloc (send - s + 1);
strncpy (yylval.s, s, send - s);
yylval.s[send - s] = '\0';
char *r;
r = get_string (send - s + 1);
strncpy (r, s, send - s);
r[send - s] = '\0';
yylval.s = r;
return BLOCK;
}
}
@ -157,12 +178,29 @@ static char *handle_quotes PARAMS ((const char *));
}
("\""[^\"\n]*"\""[ \t]*)+ {
yylval.s = handle_quotes (yytext);
return QUOTEDSTRING;
char *s;
unsigned long length;
s = handle_quotes (yytext, &length);
if (! rcdata_mode)
{
yylval.s = s;
return QUOTEDSTRING;
}
else
{
yylval.ss.length = length;
yylval.ss.s = s;
return SIZEDSTRING;
}
}
[A-Za-z][^ \t\r\n]* {
yylval.s = xstrdup (yytext);
char *s;
s = get_string (strlen (yytext) + 1);
strcpy (s, yytext);
yylval.s = s;
return STRING;
}
@ -224,14 +262,15 @@ cpp_line (s)
merged separated by whitespace are merged, as in C. */
static char *
handle_quotes (input)
handle_quotes (input, len)
const char *input;
unsigned long *len;
{
char *ret, *s;
const char *t;
int ch;
ret = (char *) xmalloc (strlen (input) + 1);
ret = get_string (strlen (input) + 1);
s = ret;
t = input;
@ -316,5 +355,62 @@ handle_quotes (input)
*s = '\0';
*len = s - ret;
return ret;
}
/* Allocate a string of a given length. */
static char *
get_string (len)
int len;
{
struct alloc_string *as;
as = (struct alloc_string *) xmalloc (sizeof *as);
as->s = xmalloc (len);
as->next = strings;
strings = as->next;
return as->s;
}
/* Discard all the strings we have allocated. The parser calls this
when it no longer needs them. */
void
rcparse_discard_strings ()
{
struct alloc_string *as;
as = strings;
while (as != NULL)
{
struct alloc_string *n;
free (as->s);
n = as->next;
free (as);
as = n;
}
strings = NULL;
}
/* Enter rcdata mode. */
void
rcparse_rcdata ()
{
rcdata_mode = 1;
}
/* Go back to normal mode from rcdata mode. */
void
rcparse_normal ()
{
rcdata_mode = 0;
}

View File

@ -27,9 +27,11 @@
#include "libiberty.h"
#include "windres.h"
/* The current language. The default is U.S. English. */
#include <ctype.h>
static unsigned short language = 0x409;
/* The current language. */
static unsigned short language;
/* The resource information during a sub statement. */
@ -60,7 +62,12 @@ static unsigned long class;
struct accelerator *pacc;
struct dialog_control *dialog_control;
struct menuitem *menuitem;
struct rcdata_data *rcdata;
struct
{
struct rcdata_item *first;
struct rcdata_item *last;
} rcdata;
struct rcdata_item *rcdata_item;
struct stringtable_data *stringtable;
struct fixed_versioninfo *fixver;
struct ver_info *verinfo;
@ -81,7 +88,12 @@ static unsigned long class;
} i;
unsigned long il;
unsigned short is;
char *s;
const char *s;
struct
{
unsigned long length;
const char *s;
} ss;
};
%token BEG END
@ -109,12 +121,14 @@ static unsigned long class;
%token NOT
%token <s> QUOTEDSTRING STRING
%token <i> NUMBER
%token <ss> SIZEDSTRING
%type <pacc> acc_entries
%type <acc> acc_entry acc_event
%type <dialog_control> control control_params
%type <menuitem> menuitems menuitem menuexitems menuexitem
%type <rcdata> optrcdata_data rcdata_data opt_control_data
%type <rcdata> optrcdata_data optrcdata_data_int rcdata_data
%type <rcdata_item> opt_control_data
%type <fixver> fixedverinfo
%type <verinfo> verblocks
%type <verstring> vervals
@ -139,20 +153,27 @@ static unsigned long class;
input:
/* empty */
| input accelerator
| input bitmap
| input cursor
| input dialog
| input font
| input icon
| input language
| input menu
| input menuex
| input messagetable
| input rcdata
| input stringtable
| input user
| input versioninfo
| input newcmd accelerator
| input newcmd bitmap
| input newcmd cursor
| input newcmd dialog
| input newcmd font
| input newcmd icon
| input newcmd language
| input newcmd menu
| input newcmd menuex
| input newcmd messagetable
| input newcmd rcdata
| input newcmd stringtable
| input newcmd user
| input newcmd versioninfo
;
newcmd:
/* empty */
{
rcparse_discard_strings ();
}
;
/* Accelerator resources. */
@ -173,7 +194,7 @@ acc_entries:
{
struct accelerator *a;
a = (struct accelerator *) xmalloc (sizeof *a);
a = (struct accelerator *) res_alloc (sizeof *a);
*a = $2;
if ($1 == NULL)
$$ = a;
@ -206,7 +227,7 @@ acc_entry:
acc_event:
QUOTEDSTRING
{
char *s = $1;
const char *s = $1;
$$.id = 0;
if (*s != '^')
@ -219,7 +240,6 @@ acc_event:
$$.key = *s;
if (s[1] != '\0')
rcparse_warning ("accelerator should only be one character");
free (s);
}
| posnumexpr
{
@ -274,7 +294,6 @@ bitmap:
id BITMAP memflags_move file_name
{
define_bitmap ($1, &$3, $4);
free ($4);
}
;
@ -284,7 +303,6 @@ cursor:
id CURSOR memflags_move_discard file_name
{
define_cursor ($1, &$3, $4);
free ($4);
}
;
@ -322,7 +340,7 @@ dialog:
dialog.exstyle = $4;
dialog.font = NULL;
dialog.ex = ((struct dialog_ex *)
xmalloc (sizeof (struct dialog_ex)));
res_alloc (sizeof (struct dialog_ex)));
memset (dialog.ex, 0, sizeof (struct dialog_ex));
dialog.controls = NULL;
sub_res_info = $3;
@ -343,7 +361,7 @@ dialog:
dialog.exstyle = $4;
dialog.font = NULL;
dialog.ex = ((struct dialog_ex *)
xmalloc (sizeof (struct dialog_ex)));
res_alloc (sizeof (struct dialog_ex)));
memset (dialog.ex, 0, sizeof (struct dialog_ex));
dialog.ex->help = $9;
dialog.controls = NULL;
@ -370,7 +388,7 @@ styles:
/* empty */
| styles CAPTION QUOTEDSTRING
{
dialog.caption = $3;
unicode_from_ascii ((int *) NULL, &dialog.caption, $3);
}
| styles CLASS id
{
@ -389,12 +407,12 @@ styles:
| styles FONT numexpr ',' QUOTEDSTRING
{
dialog.pointsize = $3;
dialog.font = $5;
unicode_from_ascii ((int *) NULL, &dialog.font, $5);
}
| styles FONT numexpr ',' QUOTEDSTRING cnumexpr cnumexpr
{
dialog.pointsize = $3;
dialog.font = $5;
unicode_from_ascii ((int *) NULL, &dialog.font, $5);
if (dialog.ex == NULL)
rcparse_warning ("extended FONT requires DIALOGEX");
else
@ -766,7 +784,7 @@ opt_control_data:
}
| BEG optrcdata_data END
{
$$ = $2;
$$ = $2.first;
}
;
@ -796,7 +814,6 @@ font:
id FONT memflags_move_discard file_name
{
define_font ($1, &$3, $4);
free ($4);
}
;
@ -806,7 +823,6 @@ icon:
id ICON memflags_move_discard file_name
{
define_icon ($1, &$3, $4);
free ($4);
}
;
@ -975,7 +991,6 @@ messagetable:
id MESSAGETABLE memflags_move file_name
{
define_messagetable ($1, &$3, $4);
free ($4);
}
;
@ -984,14 +999,29 @@ messagetable:
rcdata:
id RCDATA suboptions BEG optrcdata_data END
{
define_rcdata ($1, &$3, $5);
define_rcdata ($1, &$3, $5.first);
}
;
/* We use a different lexing algorithm, because rcdata strings may
contain embedded null bytes, and we need to know the length to use. */
optrcdata_data:
{
rcparse_rcdata ();
}
optrcdata_data_int
{
rcparse_normal ();
$$ = $2;
}
;
optrcdata_data_int:
/* empty */
{
$$ = NULL;
$$.first = NULL;
$$.last = NULL;
}
| rcdata_data
{
@ -1000,21 +1030,39 @@ optrcdata_data:
;
rcdata_data:
QUOTEDSTRING
SIZEDSTRING
{
$$ = append_rcdata_string (NULL, $1);
struct rcdata_item *ri;
ri = define_rcdata_string ($1.s, $1.length);
$$.first = ri;
$$.last = ri;
}
| sizednumexpr
{
$$ = append_rcdata_number (NULL, $1.val, $1.dword);
struct rcdata_item *ri;
ri = define_rcdata_number ($1.val, $1.dword);
$$.first = ri;
$$.last = ri;
}
| rcdata_data ',' QUOTEDSTRING
| rcdata_data ',' SIZEDSTRING
{
$$ = append_rcdata_string ($1, $3);
struct rcdata_item *ri;
ri = define_rcdata_string ($3.s, $3.length);
$$.first = $1.first;
$1.last->next = ri;
$$.last = ri;
}
| rcdata_data ',' sizednumexpr
{
$$ = append_rcdata_number ($1, $3.val, $3.dword);
struct rcdata_item *ri;
ri = define_rcdata_number ($3.val, $3.dword);
$$.first = $1.first;
$1.last->next = ri;
$$.last = ri;
}
;
@ -1042,14 +1090,13 @@ string_data:
file_name case to keep the parser happy. */
user:
id id suboptions BEG rcdata_data END
id id suboptions BEG optrcdata_data END
{
define_user_data ($1, $2, &$3, $5);
define_user_data ($1, $2, &$3, $5.first);
}
| id id suboptions file_name
{
define_user_file ($1, $2, &$3, $4);
free ($4);
}
;
@ -1066,7 +1113,7 @@ fixedverinfo:
/* empty */
{
$$ = ((struct fixed_versioninfo *)
xmalloc (sizeof (struct fixed_versioninfo)));
res_alloc (sizeof (struct fixed_versioninfo)));
memset ($$, 0, sizeof (struct fixed_versioninfo));
}
| fixedverinfo FILEVERSION numexpr cnumexpr cnumexpr cnumexpr
@ -1161,8 +1208,15 @@ id:
}
| STRING
{
res_string_to_id (&$$, $1);
free ($1);
char *copy, *s;
/* It seems that resource ID's are forced to upper case. */
copy = xstrdup ($1);
for (s = copy; *s != '\0'; s++)
if (islower (*s))
*s = toupper (*s);
res_string_to_id (&$$, copy);
free (copy);
}
;

2368
binutils/resbin.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* resrc.c -- read and write Windows rc files.
/* rescoff.c -- read and write resources in Windows COFF files.
Copyright 1997 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
@ -27,6 +27,8 @@
#include "libiberty.h"
#include "windres.h"
#include <assert.h>
/* In order to use the address of a resource data entry, we need to
get the image base of the file. Right now we extract it from
internal BFD information. FIXME. */
@ -95,16 +97,18 @@ struct extern_res_data
/* Macros to swap in values. */
#define get_16(fi, s) ((fi)->big_endian ? bfd_getb16 (s) : bfd_getl16 (s))
#define get_32(fi, s) ((fi)->big_endian ? bfd_getb32 (s) : bfd_getl32 (s))
#define getfi_16(fi, s) ((fi)->big_endian ? bfd_getb16 (s) : bfd_getl16 (s))
#define getfi_32(fi, s) ((fi)->big_endian ? bfd_getb32 (s) : bfd_getl32 (s))
/* Local functions. */
static void overrun PARAMS ((const struct coff_file_info *, const char *));
static struct res_directory *read_coff_res_dir
PARAMS ((const bfd_byte *, const struct coff_file_info *));
PARAMS ((const bfd_byte *, const struct coff_file_info *,
const struct res_id *, int));
static struct res_resource *read_coff_data_entry
PARAMS ((const bfd_byte *, const struct coff_file_info *));
PARAMS ((const bfd_byte *, const struct coff_file_info *,
const struct res_id *));
/* Read the resources in a COFF file. */
@ -141,7 +145,7 @@ read_coff_rsrc (filename, target)
}
size = bfd_section_size (abfd, sec);
data = (bfd_byte *) xmalloc (size);
data = (bfd_byte *) res_alloc (size);
if (! bfd_get_section_contents (abfd, sec, data, 0, size))
bfd_fatal ("can't read resource section");
@ -160,7 +164,7 @@ read_coff_rsrc (filename, target)
it. If we ever want to free up the resource information we read,
this will have to be cleaned up. */
return read_coff_res_dir (data, &finfo);
return read_coff_res_dir (data, &finfo, (const struct res_id *) NULL, 0);
}
/* Give an error if we are out of bounds. */
@ -176,9 +180,11 @@ overrun (finfo, msg)
/* Read a resource directory. */
static struct res_directory *
read_coff_res_dir (data, finfo)
read_coff_res_dir (data, finfo, type, level)
const bfd_byte *data;
const struct coff_file_info *finfo;
const struct res_id *type;
int level;
{
const struct extern_res_directory *erd;
struct res_directory *rd;
@ -191,15 +197,15 @@ read_coff_res_dir (data, finfo)
erd = (const struct extern_res_directory *) data;
rd = (struct res_directory *) xmalloc (sizeof *rd);
rd->characteristics = get_32 (finfo, erd->characteristics);
rd->time = get_32 (finfo, erd->time);
rd->major = get_16 (finfo, erd->major);
rd->minor = get_16 (finfo, erd->minor);
rd = (struct res_directory *) res_alloc (sizeof *rd);
rd->characteristics = getfi_32 (finfo, erd->characteristics);
rd->time = getfi_32 (finfo, erd->time);
rd->major = getfi_16 (finfo, erd->major);
rd->minor = getfi_16 (finfo, erd->minor);
rd->entries = NULL;
name_count = get_16 (finfo, erd->name_count);
id_count = get_16 (finfo, erd->id_count);
name_count = getfi_16 (finfo, erd->name_count);
id_count = getfi_16 (finfo, erd->id_count);
pp = &rd->entries;
@ -217,8 +223,8 @@ read_coff_res_dir (data, finfo)
if ((const bfd_byte *) ere >= finfo->data_end)
overrun (finfo, "named directory entry");
name = get_32 (finfo, ere->name);
rva = get_32 (finfo, ere->rva);
name = getfi_32 (finfo, ere->name);
rva = getfi_32 (finfo, ere->rva);
/* For some reason the high bit in NAME is set. */
name &=~ 0x80000000;
@ -228,15 +234,17 @@ read_coff_res_dir (data, finfo)
ers = finfo->data + name;
re = (struct res_entry *) xmalloc (sizeof *re);
re = (struct res_entry *) res_alloc (sizeof *re);
re->next = NULL;
re->id.named = 1;
length = get_16 (finfo, ers);
length = getfi_16 (finfo, ers);
re->id.u.n.length = length;
re->id.u.n.name = ((unsigned short *)
xmalloc (length * sizeof (unsigned short)));
re->id.u.n.name = (unichar *) res_alloc (length * sizeof (unichar));
for (j = 0; j < length; j++)
re->id.u.n.name[j] = get_16 (finfo, ers + j * 2 + 2);
re->id.u.n.name[j] = getfi_16 (finfo, ers + j * 2 + 2);
if (level == 0)
type = &re->id;
if ((rva & 0x80000000) != 0)
{
@ -244,14 +252,15 @@ read_coff_res_dir (data, finfo)
if (rva >= finfo->data_end - finfo->data)
overrun (finfo, "named subdirectory");
re->subdir = 1;
re->u.dir = read_coff_res_dir (finfo->data + rva, finfo);
re->u.dir = read_coff_res_dir (finfo->data + rva, finfo, type,
level + 1);
}
else
{
if (rva >= finfo->data_end - finfo->data)
overrun (finfo, "named resource");
re->subdir = 0;
re->u.res = read_coff_data_entry (finfo->data + rva, finfo);
re->u.res = read_coff_data_entry (finfo->data + rva, finfo, type);
}
*pp = re;
@ -266,28 +275,32 @@ read_coff_res_dir (data, finfo)
if ((const bfd_byte *) ere >= finfo->data_end)
overrun (finfo, "ID directory entry");
name = get_32 (finfo, ere->name);
rva = get_32 (finfo, ere->rva);
name = getfi_32 (finfo, ere->name);
rva = getfi_32 (finfo, ere->rva);
re = (struct res_entry *) xmalloc (sizeof *re);
re = (struct res_entry *) res_alloc (sizeof *re);
re->next = NULL;
re->id.named = 0;
re->id.u.id = name;
if (level == 0)
type = &re->id;
if ((rva & 0x80000000) != 0)
{
rva &=~ 0x80000000;
if (rva >= finfo->data_end - finfo->data)
overrun (finfo, "ID subdirectory");
re->subdir = 1;
re->u.dir = read_coff_res_dir (finfo->data + rva, finfo);
re->u.dir = read_coff_res_dir (finfo->data + rva, finfo, type,
level + 1);
}
else
{
if (rva >= finfo->data_end - finfo->data)
overrun (finfo, "ID resource");
re->subdir = 0;
re->u.res = read_coff_data_entry (finfo->data + rva, finfo);
re->u.res = read_coff_data_entry (finfo->data + rva, finfo, type);
}
*pp = re;
@ -300,43 +313,459 @@ read_coff_res_dir (data, finfo)
/* Read a resource data entry. */
static struct res_resource *
read_coff_data_entry (data, finfo)
read_coff_data_entry (data, finfo, type)
const bfd_byte *data;
const struct coff_file_info *finfo;
const struct res_id *type;
{
const struct extern_res_data *erd;
struct res_resource *r;
unsigned long size, rva;
const bfd_byte *resdata;
if (type == NULL)
fatal ("resource type unknown");
if (finfo->data_end - data < sizeof (struct extern_res_data))
overrun (finfo, "data entry");
erd = (const struct extern_res_data *) data;
r = (struct res_resource *) xmalloc (sizeof *r);
memset (&r->res_info, 0, sizeof (struct res_res_info));
r->coff_info.codepage = get_32 (finfo, erd->codepage);
r->coff_info.reserved = get_32 (finfo, erd->reserved);
size = get_32 (finfo, erd->size);
rva = get_32 (finfo, erd->rva);
size = getfi_32 (finfo, erd->size);
rva = getfi_32 (finfo, erd->rva);
if (rva < finfo->secaddr
|| rva - finfo->secaddr >= finfo->data_end - finfo->data)
overrun (finfo, "resource data");
resdata = finfo->data + (rva - finfo->secaddr);
r->type = RES_TYPE_USERDATA;
r->u.userdata = ((struct rcdata_data *)
xmalloc (sizeof (struct rcdata_data)));
r->u.userdata->first = ((struct rcdata_item *)
xmalloc (sizeof (struct rcdata_item)));
r->u.userdata->last = r->u.userdata->first;
r->u.userdata->first->next = NULL;
r->u.userdata->first->type = RCDATA_BUFFER;
r->u.userdata->first->u.buffer.length = size;
r->u.userdata->first->u.buffer.data = (unsigned char *) resdata;
if (size > finfo->data_end - resdata)
overrun (finfo, "resource data size");
r = bin_to_res (*type, resdata, size, finfo->big_endian);
memset (&r->res_info, 0, sizeof (struct res_res_info));
r->coff_info.codepage = getfi_32 (finfo, erd->codepage);
r->coff_info.reserved = getfi_32 (finfo, erd->reserved);
return r;
}
/* This structure is used to build a list of bindata structures. */
struct bindata_build
{
/* The data. */
struct bindata *d;
/* The last structure we have added to the list. */
struct bindata *last;
/* The size of the list as a whole. */
unsigned long length;
};
/* This structure keeps track of information as we build the directory
tree. */
struct coff_write_info
{
/* These fields are based on the BFD. */
/* The BFD itself. */
bfd *abfd;
/* Non-zero if the file is big endian. */
int big_endian;
/* Pointer to section symbol used to build RVA relocs. */
asymbol **sympp;
/* These fields are computed initially, and then not changed. */
/* Length of directory tables and entries. */
unsigned long dirsize;
/* Length of directory entry strings. */
unsigned long dirstrsize;
/* Length of resource data entries. */
unsigned long dataentsize;
/* These fields are updated as we add data. */
/* Directory tables and entries. */
struct bindata_build dirs;
/* Directory entry strings. */
struct bindata_build dirstrs;
/* Resource data entries. */
struct bindata_build dataents;
/* Actual resource data. */
struct bindata_build resources;
/* Relocations. */
arelent **relocs;
/* Number of relocations. */
unsigned int reloc_count;
};
/* Macros to swap out values. */
#define putcwi_16(cwi, v, s) \
((cwi->big_endian) ? bfd_putb16 ((v), (s)) : bfd_putl16 ((v), (s)))
#define putcwi_32(cwi, v, s) \
((cwi->big_endian) ? bfd_putb32 ((v), (s)) : bfd_putl32 ((v), (s)))
static void coff_bin_sizes
PARAMS ((const struct res_directory *, struct coff_write_info *));
static unsigned char *coff_alloc PARAMS ((struct bindata_build *, size_t));
static void coff_to_bin
PARAMS ((const struct res_directory *, struct coff_write_info *));
static void coff_res_to_bin
PARAMS ((const struct res_resource *, struct coff_write_info *));
/* Write resources to a COFF file. RESOURCES should already be
sorted.
Right now we always create a new file. Someday we should also
offer the ability to merge resources into an existing file. This
would require doing the basic work of objcopy, just modifying or
adding the .rsrc section. */
void
write_coff_file (filename, target, resources)
const char *filename;
const char *target;
const struct res_directory *resources;
{
bfd *abfd;
asection *sec;
struct coff_write_info cwi;
struct bindata *d;
unsigned long length, offset;
abfd = bfd_openw (filename, target);
if (abfd == NULL)
bfd_fatal (filename);
if (! bfd_set_format (abfd, bfd_object))
bfd_fatal ("bfd_set_format");
/* FIXME: This is obviously i386 specific. */
if (! bfd_set_arch_mach (abfd, bfd_arch_i386, 0))
bfd_fatal ("bfd_set_arch_mach");
if (! bfd_set_file_flags (abfd, HAS_SYMS | HAS_RELOC))
bfd_fatal ("bfd_set_file_flags");
sec = bfd_make_section (abfd, ".rsrc");
if (sec == NULL)
bfd_fatal ("bfd_make_section");
if (! bfd_set_section_flags (abfd, sec,
(SEC_HAS_CONTENTS | SEC_ALLOC
| SEC_LOAD | SEC_DATA)))
bfd_fatal ("bfd_set_section_flags");
if (! bfd_set_symtab (abfd, sec->symbol_ptr_ptr, 1))
bfd_fatal ("bfd_set_symtab");
/* Requiring this is probably a bug in BFD. */
sec->output_section = sec;
/* The order of data in the .rsrc section is
resource directory tables and entries
resource directory strings
resource data entries
actual resource data
We build these different types of data in different lists. */
cwi.abfd = abfd;
cwi.big_endian = bfd_big_endian (abfd);
cwi.sympp = sec->symbol_ptr_ptr;
cwi.dirsize = 0;
cwi.dirstrsize = 0;
cwi.dataentsize = 0;
cwi.dirs.d = NULL;
cwi.dirs.last = NULL;
cwi.dirs.length = 0;
cwi.dirstrs.d = NULL;
cwi.dirstrs.last = NULL;
cwi.dirstrs.length = 0;
cwi.dataents.d = NULL;
cwi.dataents.last = NULL;
cwi.dataents.length = 0;
cwi.resources.d = NULL;
cwi.resources.last = NULL;
cwi.resources.length = 0;
cwi.relocs = NULL;
cwi.reloc_count = 0;
/* Work out the sizes of the resource directory entries, so that we
know the various offsets we will need. */
coff_bin_sizes (resources, &cwi);
/* Force the directory strings to be 32 bit aligned. Every other
structure is 32 bit aligned anyhow. */
cwi.dirstrsize = (cwi.dirstrsize + 3) &~ 3;
/* Actually convert the resources to binary. */
coff_to_bin (resources, &cwi);
/* Add another 2 bytes to the directory strings if needed for
alignment. */
if ((cwi.dirstrs.length & 3) != 0)
{
unsigned char *ex;
ex = coff_alloc (&cwi.dirstrs, 2);
ex[0] = 0;
ex[1] = 0;
}
/* Make sure that the data we built came out to the same size as we
calculated initially. */
assert (cwi.dirs.length == cwi.dirsize);
assert (cwi.dirstrs.length == cwi.dirstrsize);
assert (cwi.dataents.length == cwi.dataentsize);
length = (cwi.dirsize
+ cwi.dirstrsize
+ cwi.dataentsize
+ cwi.resources.length);
if (! bfd_set_section_size (abfd, sec, length))
bfd_fatal ("bfd_set_section_size");
bfd_set_reloc (abfd, sec, cwi.relocs, cwi.reloc_count);
/* We allocated the relocs array using malloc. */
free (cwi.relocs);
offset = 0;
for (d = cwi.dirs.d; d != NULL; d = d->next)
{
if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
bfd_fatal ("bfd_set_section_contents");
offset += d->length;
}
for (d = cwi.dirstrs.d; d != NULL; d = d->next)
{
if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
bfd_fatal ("bfd_set_section_contents");
offset += d->length;
}
for (d = cwi.dataents.d; d != NULL; d = d->next)
{
if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
bfd_fatal ("bfd_set_section_contents");
offset += d->length;
}
for (d = cwi.resources.d; d != NULL; d = d->next)
{
if (! bfd_set_section_contents (abfd, sec, d->data, offset, d->length))
bfd_fatal ("bfd_set_section_contents");
offset += d->length;
}
assert (offset == length);
if (! bfd_close (abfd))
bfd_fatal ("bfd_close");
}
/* Work out the sizes of the various fixed size resource directory
entries. This updates fields in CWI. */
static void
coff_bin_sizes (resdir, cwi)
const struct res_directory *resdir;
struct coff_write_info *cwi;
{
const struct res_entry *re;
cwi->dirsize += sizeof (struct extern_res_directory);
for (re = resdir->entries; re != NULL; re = re->next)
{
cwi->dirsize += sizeof (struct extern_res_entry);
if (re->id.named)
cwi->dirstrsize += re->id.u.n.length * 2 + 2;
if (re->subdir)
coff_bin_sizes (re->u.dir, cwi);
else
cwi->dataentsize += sizeof (struct extern_res_data);
}
}
/* Allocate data for a particular list. */
static unsigned char *
coff_alloc (bb, size)
struct bindata_build *bb;
size_t size;
{
struct bindata *d;
d = (struct bindata *) reswr_alloc (sizeof *d);
d->next = NULL;
d->data = (unsigned char *) reswr_alloc (size);
d->length = size;
if (bb->d == NULL)
bb->d = d;
else
bb->last->next = d;
bb->last = d;
bb->length += size;
return d->data;
}
/* Convert the resource directory RESDIR to binary. */
static void
coff_to_bin (resdir, cwi)
const struct res_directory *resdir;
struct coff_write_info *cwi;
{
struct extern_res_directory *erd;
int ci, cn;
const struct res_entry *e;
struct extern_res_entry *ere;
/* Write out the directory table. */
erd = ((struct extern_res_directory *)
coff_alloc (&cwi->dirs, sizeof (*erd)));
putcwi_32 (cwi, resdir->characteristics, erd->characteristics);
putcwi_32 (cwi, resdir->time, erd->time);
putcwi_16 (cwi, resdir->major, erd->major);
putcwi_16 (cwi, resdir->minor, erd->minor);
ci = 0;
cn = 0;
for (e = resdir->entries; e != NULL; e = e->next)
{
if (e->id.named)
++cn;
else
++ci;
}
putcwi_16 (cwi, cn, erd->name_count);
putcwi_16 (cwi, ci, erd->id_count);
/* Write out the data entries. Note that we allocate space for all
the entries before writing them out. That permits a recursive
call to work correctly when writing out subdirectories. */
ere = ((struct extern_res_entry *)
coff_alloc (&cwi->dirs, (ci + cn) * sizeof (*ere)));
for (e = resdir->entries; e != NULL; e = e->next, ere++)
{
if (! e->id.named)
putcwi_32 (cwi, e->id.u.id, ere->name);
else
{
unsigned char *str;
int i;
/* For some reason existing files seem to have the high bit
set on the address of the name, although that is not
documented. */
putcwi_32 (cwi,
0x80000000 | (cwi->dirsize + cwi->dirstrs.length),
ere->name);
str = coff_alloc (&cwi->dirstrs, e->id.u.n.length * 2 + 2);
putcwi_16 (cwi, e->id.u.n.length, str);
for (i = 0; i < e->id.u.n.length; i++)
putcwi_16 (cwi, e->id.u.n.name[i], str + i * 2 + 2);
}
if (e->subdir)
{
putcwi_32 (cwi, 0x80000000 | cwi->dirs.length, ere->rva);
coff_to_bin (e->u.dir, cwi);
}
else
{
putcwi_32 (cwi,
cwi->dirsize + cwi->dirstrsize + cwi->dataents.length,
ere->rva);
coff_res_to_bin (e->u.res, cwi);
}
}
}
/* Convert the resource RES to binary. */
static void
coff_res_to_bin (res, cwi)
const struct res_resource *res;
struct coff_write_info *cwi;
{
arelent *r;
struct extern_res_data *erd;
struct bindata *d;
unsigned long length;
/* For some reason, although every other address is a section
offset, the address of the resource data itself is an RVA. That
means that we need to generate a relocation for it. We allocate
the relocs array using malloc so that we can use realloc. FIXME:
This relocation handling is correct for the i386, but probably
not for any other target. */
r = (arelent *) reswr_alloc (sizeof (arelent));
r->sym_ptr_ptr = cwi->sympp;
r->address = cwi->dirsize + cwi->dirstrsize + cwi->dataents.length;
r->addend = 0;
r->howto = bfd_reloc_type_lookup (cwi->abfd, BFD_RELOC_RVA);
if (r->howto == NULL)
bfd_fatal ("can't get BFD_RELOC_RVA relocation type");
cwi->relocs = xrealloc (cwi->relocs,
(cwi->reloc_count + 2) * sizeof (arelent *));
cwi->relocs[cwi->reloc_count] = r;
cwi->relocs[cwi->reloc_count + 1] = NULL;
++cwi->reloc_count;
erd = (struct extern_res_data *) coff_alloc (&cwi->dataents, sizeof (*erd));
putcwi_32 (cwi,
(cwi->dirsize
+ cwi->dirstrsize
+ cwi->dataentsize
+ cwi->resources.length),
erd->rva);
putcwi_32 (cwi, res->coff_info.codepage, erd->codepage);
putcwi_32 (cwi, res->coff_info.reserved, erd->reserved);
d = res_to_bin (res, cwi->big_endian);
if (cwi->resources.d == NULL)
cwi->resources.d = d;
else
cwi->resources.last->next = d;
length = 0;
for (; d->next != NULL; d = d->next)
length += d->length;
length += d->length;
cwi->resources.last = d;
cwi->resources.length += length;
putcwi_32 (cwi, length, erd->size);
/* Force the next resource to have 32 bit alignment. */
if ((length & 3) != 0)
{
int add;
unsigned char *ex;
add = 4 - (length & 3);
ex = coff_alloc (&cwi->resources, add);
memset (ex, 0, add);
}
}

View File

@ -143,6 +143,7 @@ read_rc_file (filename, preprocessor, preprocargs, language)
cpp_pipe = popen (cmd, FOPEN_RT);
if (cpp_pipe == NULL)
fatal ("can't popen `%s': %s", cmd, strerror (errno));
free (cmd);
xatexit (close_pipe);
@ -301,7 +302,7 @@ define_bitmap (id, resinfo, filename)
fatal ("stat failed on bitmap file `%s': %s", real_filename,
strerror (errno));
data = (unsigned char *) xmalloc (s.st_size - BITMAP_SKIP);
data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
for (i = 0; i < BITMAP_SKIP; i++)
getc (e);
@ -386,11 +387,11 @@ define_cursor (id, resinfo, filename)
fatal ("%s: fseek to %lu failed: %s", real_filename,
icondirs[i].offset, strerror (errno));
data = (unsigned char *) xmalloc (icondirs[i].bytes);
data = (unsigned char *) res_alloc (icondirs[i].bytes);
get_data (e, data, icondirs[i].bytes, real_filename);
c = (struct cursor *) xmalloc (sizeof *c);
c = (struct cursor *) res_alloc (sizeof *c);
c->xhotspot = icondirs[i].u.cursor.xhotspot;
c->yhotspot = icondirs[i].u.cursor.yhotspot;
c->length = icondirs[i].bytes;
@ -419,21 +420,24 @@ define_cursor (id, resinfo, filename)
{
struct group_cursor *cg;
/* These manipulations of icondirs into cg are copied from rcl. */
cg = (struct group_cursor *) xmalloc (sizeof *cg);
cg = (struct group_cursor *) res_alloc (sizeof *cg);
cg->next = NULL;
cg->width = icondirs[i].width;
cg->height = 2 * icondirs[i].height;
/* FIXME: What should these be set to? */
cg->planes = 1;
cg->bits = 4;
cg->bytes = icondirs[i].bytes + 8;
cg->bits = 1;
cg->bytes = icondirs[i].bytes + 4;
cg->index = first_cursor + i + 1;
*pp = cg;
pp = &(*pp)->next;
}
free (icondirs);
r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
resinfo->language, 0);
r->type = RES_TYPE_GROUP_CURSOR;
@ -452,7 +456,7 @@ define_dialog (id, resinfo, dialog)
struct dialog *copy;
struct res_resource *r;
copy = (struct dialog *) xmalloc (sizeof *copy);
copy = (struct dialog *) res_alloc (sizeof *copy);
*copy = *dialog;
r = define_standard_resource (&resources, RT_DIALOG, id,
@ -467,7 +471,7 @@ define_dialog (id, resinfo, dialog)
struct dialog_control *
define_control (text, id, x, y, width, height, class, style, exstyle)
char *text;
const char *text;
unsigned long id;
unsigned long x;
unsigned long y;
@ -479,7 +483,7 @@ define_control (text, id, x, y, width, height, class, style, exstyle)
{
struct dialog_control *n;
n = (struct dialog_control *) xmalloc (sizeof *n);
n = (struct dialog_control *) res_alloc (sizeof *n);
n->next = NULL;
n->id = id;
n->style = style;
@ -497,7 +501,6 @@ define_control (text, id, x, y, width, height, class, style, exstyle)
n->text.named = 0;
n->text.u.id = 0;
}
free (text);
n->data = NULL;
n->help = 0;
@ -517,8 +520,10 @@ define_font (id, resinfo, filename)
struct stat s;
unsigned char *data;
struct res_resource *r;
struct fontdir *fd;
long offset;
long fontdatalength;
unsigned char *fontdata;
struct fontdir *fd;
const char *device, *face;
struct fontdir **pp;
@ -528,7 +533,7 @@ define_font (id, resinfo, filename)
fatal ("stat failed on bitmap file `%s': %s", real_filename,
strerror (errno));
data = (unsigned char *) xmalloc (s.st_size);
data = (unsigned char *) res_alloc (s.st_size);
get_data (e, data, s.st_size, real_filename);
@ -568,15 +573,17 @@ define_font (id, resinfo, filename)
++fonts;
fd = (struct fontdir *) xmalloc (sizeof *fd);
fontdatalength = 58 + strlen (device) + strlen (face);
fontdata = (unsigned char *) res_alloc (fontdatalength);
memcpy (fontdata, data, 56);
strcpy ((char *) fontdata + 56, device);
strcpy ((char *) fontdata + 57 + strlen (device), face);
fd = (struct fontdir *) res_alloc (sizeof *fd);
fd->next = NULL;
fd->index = fonts;
fd->length = 58 + strlen (device) + strlen (face);
fd->data = (unsigned char *) xmalloc (fd->length);
memcpy (fd->data, data, 56);
strcpy ((char *) fd->data + 56, device);
strcpy ((char *) fd->data + 57 + strlen (device), face);
fd->length = fontdatalength;
fd->data = fontdata;
for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
;
@ -670,7 +677,7 @@ define_icon (id, resinfo, filename)
fatal ("%s: fseek to %lu failed: %s", real_filename,
icondirs[i].offset, strerror (errno));
data = (unsigned char *) xmalloc (icondirs[i].bytes);
data = (unsigned char *) res_alloc (icondirs[i].bytes);
get_data (e, data, icondirs[i].bytes, real_filename);
@ -698,16 +705,21 @@ define_icon (id, resinfo, filename)
{
struct group_icon *cg;
/* FIXME: rcl sets planes and bits based on colors, rather than
just copying the values from the file. */
/* For some reason, at least in some files the planes and bits
are zero. We instead set them from the color. This is
copied from rcl. */
cg = (struct group_icon *) xmalloc (sizeof *cg);
cg = (struct group_icon *) res_alloc (sizeof *cg);
cg->next = NULL;
cg->width = icondirs[i].width;
cg->height = icondirs[i].height;
cg->colors = icondirs[i].colorcount;
cg->planes = icondirs[i].u.icon.planes;
cg->bits = icondirs[i].u.icon.bits;
cg->planes = 1;
cg->bits = 0;
while ((1 << cg->bits) < cg->colors)
++cg->bits;
cg->bytes = icondirs[i].bytes;
cg->index = first_icon + i + 1;
@ -715,6 +727,8 @@ define_icon (id, resinfo, filename)
pp = &(*pp)->next;
}
free (icondirs);
r = define_standard_resource (&resources, RT_GROUP_ICON, id,
resinfo->language, 0);
r->type = RES_TYPE_GROUP_ICON;
@ -730,11 +744,16 @@ define_menu (id, resinfo, menuitems)
const struct res_res_info *resinfo;
struct menuitem *menuitems;
{
struct menu *m;
struct res_resource *r;
m = (struct menu *) res_alloc (sizeof *m);
m->items = menuitems;
m->help = 0;
r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
r->type = RES_TYPE_MENU;
r->u.menu = menuitems;
r->u.menu = m;
r->res_info = *resinfo;
}
@ -743,7 +762,7 @@ define_menu (id, resinfo, menuitems)
struct menuitem *
define_menuitem (text, menuid, type, state, help, menuitems)
char *text;
const char *text;
int menuid;
unsigned long type;
unsigned long state;
@ -752,12 +771,15 @@ define_menuitem (text, menuid, type, state, help, menuitems)
{
struct menuitem *mi;
mi = (struct menuitem *) xmalloc (sizeof *mi);
mi = (struct menuitem *) res_alloc (sizeof *mi);
mi->next = NULL;
mi->type = type;
mi->state = state;
mi->id = menuid;
mi->text = text;
if (text == NULL)
mi->text = NULL;
else
unicode_from_ascii ((int *) NULL, &mi->text, text);
mi->help = help;
mi->popup = menuitems;
return mi;
@ -784,7 +806,7 @@ define_messagetable (id, resinfo, filename)
fatal ("stat failed on bitmap file `%s': %s", real_filename,
strerror (errno));
data = (unsigned char *) xmalloc (s.st_size);
data = (unsigned char *) res_alloc (s.st_size);
get_data (e, data, s.st_size, real_filename);
@ -806,7 +828,7 @@ void
define_rcdata (id, resinfo, data)
struct res_id id;
const struct res_res_info *resinfo;
struct rcdata_data *data;
struct rcdata_item *data;
{
struct res_resource *r;
@ -817,61 +839,42 @@ define_rcdata (id, resinfo, data)
r->res_info = *resinfo;
}
/* Add an rcdata_item to an rcdata resource. */
/* Create an rcdata item holding a string. */
struct rcdata_data *
append_rcdata_item (data, item)
struct rcdata_data *data;
struct rcdata_item *item;
{
if (data == NULL)
{
data = (struct rcdata_data *) xmalloc (sizeof *data);
data->first = item;
data->last = item;
}
else
{
data->last->next = item;
data->last = item;
}
return data;
}
/* Add a string to an rcdata resource. */
struct rcdata_data *
append_rcdata_string (data, string)
struct rcdata_data *data;
char *string;
struct rcdata_item *
define_rcdata_string (string, len)
const char *string;
unsigned long len;
{
struct rcdata_item *ri;
char *s;
ri = (struct rcdata_item *) xmalloc (sizeof *ri);
ri = (struct rcdata_item *) res_alloc (sizeof *ri);
ri->next = NULL;
ri->type = RCDATA_STRING;
ri->u.string = string;
ri->u.string.length = len;
s = (char *) res_alloc (len);
memcpy (s, string, len);
ri->u.string.s = s;
return append_rcdata_item (data, ri);
return ri;
}
/* Add a number to an rcdata resource. */
/* Create an rcdata item holding a number. */
struct rcdata_data *
append_rcdata_number (data, val, dword)
struct rcdata_data *data;
struct rcdata_item *
define_rcdata_number (val, dword)
unsigned long val;
int dword;
{
struct rcdata_item *ri;
ri = (struct rcdata_item *) xmalloc (sizeof *ri);
ri = (struct rcdata_item *) res_alloc (sizeof *ri);
ri->next = NULL;
ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
ri->u.word = val;
return append_rcdata_item (data, ri);
return ri;
}
/* Define a stringtable resource. This is called for each string
@ -881,7 +884,7 @@ void
define_stringtable (resinfo, stringid, string)
const struct res_res_info *resinfo;
unsigned long stringid;
char *string;
const char *string;
{
struct res_id id;
struct res_resource *r;
@ -897,7 +900,7 @@ define_stringtable (resinfo, stringid, string)
r->type = RES_TYPE_STRINGTABLE;
r->u.stringtable = ((struct stringtable *)
xmalloc (sizeof (struct stringtable)));
res_alloc (sizeof (struct stringtable)));
for (i = 0; i < 16; i++)
{
r->u.stringtable->strings[i].length = 0;
@ -910,7 +913,6 @@ define_stringtable (resinfo, stringid, string)
unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
&r->u.stringtable->strings[stringid & 0xf].string,
string);
free (string);
}
/* Define a user data resource where the data is in the rc file. */
@ -920,7 +922,7 @@ define_user_data (id, type, resinfo, data)
struct res_id id;
struct res_id type;
const struct res_res_info *resinfo;
struct rcdata_data *data;
struct rcdata_item *data;
{
struct res_id ids[3];
struct res_resource *r;
@ -958,7 +960,7 @@ define_user_file (id, type, resinfo, filename)
fatal ("stat failed on bitmap file `%s': %s", real_filename,
strerror (errno));
data = (unsigned char *) xmalloc (s.st_size);
data = (unsigned char *) res_alloc (s.st_size);
get_data (e, data, s.st_size, real_filename);
@ -972,15 +974,12 @@ define_user_file (id, type, resinfo, filename)
r = define_resource (&resources, 3, ids, 0);
r->type = RES_TYPE_USERDATA;
r->u.userdata = ((struct rcdata_data *)
xmalloc (sizeof (struct rcdata_data)));
r->u.userdata->first = ((struct rcdata_item *)
xmalloc (sizeof (struct rcdata_item)));
r->u.userdata->last = r->u.userdata->first;
r->u.userdata->first->next = NULL;
r->u.userdata->first->type = RCDATA_BUFFER;
r->u.userdata->first->u.buffer.length = s.st_size;
r->u.userdata->first->u.buffer.data = data;
r->u.userdata = ((struct rcdata_item *)
res_alloc (sizeof (struct rcdata_item)));
r->u.userdata->next = NULL;
r->u.userdata->type = RCDATA_BUFFER;
r->u.userdata->u.buffer.length = s.st_size;
r->u.userdata->u.buffer.data = data;
r->res_info = *resinfo;
}
@ -998,7 +997,7 @@ define_versioninfo (id, language, fixedverinfo, verinfo)
r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
r->type = RES_TYPE_VERSIONINFO;
r->u.versioninfo = ((struct versioninfo *)
xmalloc (sizeof (struct versioninfo)));
res_alloc (sizeof (struct versioninfo)));
r->u.versioninfo->fixed = fixedverinfo;
r->u.versioninfo->var = verinfo;
r->res_info.language = language;
@ -1009,17 +1008,15 @@ define_versioninfo (id, language, fixedverinfo, verinfo)
struct ver_info *
append_ver_stringfileinfo (verinfo, language, strings)
struct ver_info *verinfo;
char *language;
const char *language;
struct ver_stringinfo *strings;
{
struct ver_info *vi, **pp;
vi = (struct ver_info *) xmalloc (sizeof *vi);
vi = (struct ver_info *) res_alloc (sizeof *vi);
vi->next = NULL;
vi->type = VERINFO_STRING;
unicode_from_ascii ((unsigned short *) NULL, &vi->u.string.language,
language);
free (language);
unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
vi->u.string.strings = strings;
for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
@ -1034,16 +1031,15 @@ append_ver_stringfileinfo (verinfo, language, strings)
struct ver_info *
append_ver_varfileinfo (verinfo, key, var)
struct ver_info *verinfo;
char *key;
const char *key;
struct ver_varinfo *var;
{
struct ver_info *vi, **pp;
vi = (struct ver_info *) xmalloc (sizeof *vi);
vi = (struct ver_info *) res_alloc (sizeof *vi);
vi->next = NULL;
vi->type = VERINFO_VAR;
unicode_from_ascii ((unsigned short *) NULL, &vi->u.var.key, key);
free (key);
unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
vi->u.var.var = var;
for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
@ -1058,17 +1054,15 @@ append_ver_varfileinfo (verinfo, key, var)
struct ver_stringinfo *
append_verval (strings, key, value)
struct ver_stringinfo *strings;
char *key;
char *value;
const char *key;
const char *value;
{
struct ver_stringinfo *vs, **pp;
vs = (struct ver_stringinfo *) xmalloc (sizeof *vs);
vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
vs->next = NULL;
unicode_from_ascii ((unsigned short *) NULL, &vs->key, key);
free (key);
unicode_from_ascii ((unsigned short *) NULL, &vs->value, value);
free (value);
unicode_from_ascii ((int *) NULL, &vs->key, key);
unicode_from_ascii ((int *) NULL, &vs->value, value);
for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
;
@ -1087,7 +1081,7 @@ append_vertrans (var, language, charset)
{
struct ver_varinfo *vv, **pp;
vv = (struct ver_varinfo *) xmalloc (sizeof *vv);
vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
vv->next = NULL;
vv->language = language;
vv->charset = charset;
@ -1121,8 +1115,10 @@ static void write_rc_dialog_control
PARAMS ((FILE *, const struct dialog_control *));
static void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
static void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
static void write_rc_menu PARAMS ((FILE *, const struct menuitem *, int, int));
static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_data *, int));
static void write_rc_menu PARAMS ((FILE *, const struct menu *, int));
static void write_rc_menuitems
PARAMS ((FILE *, const struct menuitem *, int, int));
static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_item *, int));
static void write_rc_stringtable
PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
@ -1565,7 +1561,7 @@ write_rc_resource (e, type, name, res, language)
break;
case RES_TYPE_MENU:
write_rc_menu (e, res->u.menu, menuex, 0);
write_rc_menu (e, res->u.menu, menuex);
break;
case RES_TYPE_RCDATA:
@ -1697,7 +1693,11 @@ write_rc_dialog (e, dialog)
fprintf (e, "\n");
}
if (dialog->caption != NULL)
fprintf (e, "CAPTION \"%s\"\n", dialog->caption);
{
fprintf (e, "CAPTION \"");
unicode_print (e, dialog->caption, -1);
fprintf (e, "\"\n");
}
if (dialog->menu.named || dialog->menu.u.id != 0)
{
fprintf (e, "MENU ");
@ -1706,7 +1706,9 @@ write_rc_dialog (e, dialog)
}
if (dialog->font != NULL)
{
fprintf (e, "FONT %d, \"%s\"", dialog->pointsize, dialog->font);
fprintf (e, "FONT %d, \"", dialog->pointsize);
unicode_print (e, dialog->font, -1);
fprintf (e, "\"");
if (dialog->ex != NULL
&& (dialog->ex->weight != 0 || dialog->ex->italic != 0))
fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
@ -1863,7 +1865,20 @@ write_rc_group_icon (e, group_icon)
/* Write out a menu resource. */
static void
write_rc_menu (e, menuitems, menuex, ind)
write_rc_menu (e, menu, menuex)
FILE *e;
const struct menu *menu;
int menuex;
{
if (menu->help != 0)
fprintf (e, "// Help ID: %lu\n", menu->help);
write_rc_menuitems (e, menu->items, menuex, 0);
}
/* Write out menuitems. */
static void
write_rc_menuitems (e, menuitems, menuex, ind)
FILE *e;
const struct menuitem *menuitems;
int menuex;
@ -1896,7 +1911,11 @@ write_rc_menu (e, menuitems, menuex, ind)
if (mi->text == NULL)
fprintf (e, " \"\"");
else
fprintf (e, " \"%s\"", mi->text);
{
fprintf (e, " \"");
unicode_print (e, mi->text, -1);
fprintf (e, "\"");
}
if (! menuex)
{
@ -1937,7 +1956,7 @@ write_rc_menu (e, menuitems, menuex, ind)
fprintf (e, "\n");
if (mi->popup != NULL)
write_rc_menu (e, mi->popup, menuex, ind + 2);
write_rc_menuitems (e, mi->popup, menuex, ind + 2);
}
indent (e, ind);
@ -1950,7 +1969,7 @@ write_rc_menu (e, menuitems, menuex, ind)
static void
write_rc_rcdata (e, rcdata, ind)
FILE *e;
const struct rcdata_data *rcdata;
const struct rcdata_item *rcdata;
int ind;
{
const struct rcdata_item *ri;
@ -1958,7 +1977,7 @@ write_rc_rcdata (e, rcdata, ind)
indent (e, ind);
fprintf (e, "BEGIN\n");
for (ri = rcdata->first; ri != NULL; ri = ri->next)
for (ri = rcdata; ri != NULL; ri = ri->next)
{
if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
continue;
@ -1979,12 +1998,26 @@ write_rc_rcdata (e, rcdata, ind)
break;
case RCDATA_STRING:
fprintf (e, "\"%s\"", ri->u.string);
break;
{
const char *s;
unsigned long i;
fprintf (e, "\"");
s = ri->u.string.s;
for (i = 0; i < ri->u.string.length; i++)
{
if (isprint (*s))
putc (*s, e);
else
fprintf (e, "\\%03o", *s);
}
fprintf (e, "\"");
break;
}
case RCDATA_WSTRING:
fprintf (e, "L\"");
unicode_print (e, ri->u.wstring, -1);
unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
fprintf (e, "\"");
break;

View File

@ -39,6 +39,7 @@
#include "getopt.h"
#include "bucomm.h"
#include "libiberty.h"
#include "obstack.h"
#include "windres.h"
#include <assert.h>
@ -127,9 +128,62 @@ static const struct option long_options[] =
/* Static functions. */
static void res_init PARAMS ((void));
static int extended_menuitems PARAMS ((const struct menuitem *));
static enum res_format format_from_name PARAMS ((const char *));
static enum res_format format_from_filename PARAMS ((const char *, int));
static void usage PARAMS ((FILE *, int));
static int cmp_res_entry PARAMS ((const PTR, const PTR));
static struct res_directory *sort_resources PARAMS ((struct res_directory *));
/* When we are building a resource tree, we allocate everything onto
an obstack, so that we can free it all at once if we want. */
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
/* The resource building obstack. */
static struct obstack res_obstack;
/* Initialize the resource building obstack. */
static void
res_init ()
{
obstack_init (&res_obstack);
}
/* Allocate space on the resource building obstack. */
PTR
res_alloc (bytes)
size_t bytes;
{
return (PTR) obstack_alloc (&res_obstack, bytes);
}
/* We also use an obstack to save memory used while writing out a set
of resources. */
static struct obstack reswr_obstack;
/* Initialize the resource writing obstack. */
static void
reswr_init ()
{
obstack_init (&reswr_obstack);
}
/* Allocate space on the resource writing obstack. */
PTR
reswr_alloc (bytes)
size_t bytes;
{
return (PTR) obstack_alloc (&reswr_obstack, bytes);
}
/* Open a file using the include directory search list. */
@ -183,8 +237,8 @@ open_file_search (filename, mode, errmsg, real_filename)
void
unicode_from_ascii (length, unicode, ascii)
unsigned short *length;
unsigned short **unicode;
int *length;
unichar **unicode;
const char *ascii;
{
int len;
@ -194,13 +248,9 @@ unicode_from_ascii (length, unicode, ascii)
len = strlen (ascii);
if (length != NULL)
{
if (len > 0xffff)
fatal ("string too long (%d chars > 0xffff)", len);
*length = len;
}
*length = len;
*unicode = (unsigned short *) xmalloc ((len + 1) * sizeof (unsigned short));
*unicode = ((unichar *) res_alloc ((len + 1) * sizeof (unichar)));
for (s = ascii, w = *unicode; *s != '\0'; s++, w++)
*w = *s & 0xff;
@ -214,12 +264,12 @@ unicode_from_ascii (length, unicode, ascii)
void
unicode_print (e, unicode, length)
FILE *e;
const unsigned short *unicode;
const unichar *unicode;
int length;
{
while (1)
{
unsigned short ch;
unichar ch;
if (length == 0)
return;
@ -228,7 +278,7 @@ unicode_print (e, unicode, length)
ch = *unicode;
if (ch == 0)
if (ch == 0 && length < 0)
return;
++unicode;
@ -264,7 +314,7 @@ res_id_cmp (a, b)
}
else
{
unsigned short *as, *ase, *bs, *bse;
unichar *as, *ase, *bs, *bse;
if (! b.named)
return -1;
@ -368,7 +418,8 @@ define_resource (resources, cids, ids, dupok)
if (*resources == NULL)
{
*resources = (struct res_directory *) xmalloc (sizeof **resources);
*resources = ((struct res_directory *)
res_alloc (sizeof **resources));
(*resources)->characteristics = 0;
(*resources)->time = 0;
(*resources)->major = 0;
@ -384,7 +435,7 @@ define_resource (resources, cids, ids, dupok)
re = *pp;
else
{
re = (struct res_entry *) xmalloc (sizeof *re);
re = (struct res_entry *) res_alloc (sizeof *re);
re->next = NULL;
re->id = ids[i];
if ((i + 1) < cids)
@ -433,7 +484,8 @@ define_resource (resources, cids, ids, dupok)
fprintf (stderr, ": duplicate value\n");
}
re->u.res = (struct res_resource *) xmalloc (sizeof (struct res_resource));
re->u.res = ((struct res_resource *)
res_alloc (sizeof (struct res_resource)));
re->u.res->type = RES_TYPE_UNINITIALIZED;
memset (&re->u.res->res_info, 0, sizeof (struct res_res_info));
@ -462,6 +514,62 @@ define_standard_resource (resources, type, name, language, dupok)
a[2].u.id = language;
return define_resource (resources, 3, a, dupok);
}
/* Comparison routine for resource sorting. */
static int
cmp_res_entry (p1, p2)
const PTR p1;
const PTR p2;
{
const struct res_entry **re1, **re2;
re1 = (const struct res_entry **) p1;
re2 = (const struct res_entry **) p2;
return res_id_cmp ((*re1)->id, (*re2)->id);
}
/* Sort the resources. */
static struct res_directory *
sort_resources (resdir)
struct res_directory *resdir;
{
int c, i;
struct res_entry *re;
struct res_entry **a;
if (resdir->entries == NULL)
return resdir;
c = 0;
for (re = resdir->entries; re != NULL; re = re->next)
++c;
/* This is a recursive routine, so using xmalloc is probably better
than alloca. */
a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *));
for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
a[i] = re;
qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
resdir->entries = a[0];
for (i = 0; i < c - 1; i++)
a[i]->next = a[i + 1];
a[i]->next = NULL;
free (a);
/* Now sort the subdirectories. */
for (re = resdir->entries; re != NULL; re = re->next)
if (re->subdir)
re->u.dir = sort_resources (re->u.dir);
return resdir;
}
/* Return whether the dialog resource DIALOG is a DIALOG or a
DIALOGEX. */
@ -485,7 +593,14 @@ extended_dialog (dialog)
/* Return whether MENUITEMS are a MENU or a MENUEX. */
int
extended_menu (menuitems)
extended_menu (menu)
const struct menu *menu;
{
return extended_menuitems (menu->items);
}
static int
extended_menuitems (menuitems)
const struct menuitem *menuitems;
{
const struct menuitem *mi;
@ -507,7 +622,7 @@ extended_menu (menuitems)
return 1;
if (mi->popup != NULL)
{
if (extended_menu (mi->popup))
if (extended_menuitems (mi->popup))
return 1;
}
}
@ -685,6 +800,8 @@ main (argc, argv)
bfd_init ();
set_default_bfd_target ();
res_init ();
input_filename = NULL;
output_filename = NULL;
input_format = RES_FORMAT_UNKNOWN;
@ -843,8 +960,15 @@ main (argc, argv)
break;
}
/* Sort the resources. This is required for COFF, convenient for
rc, and unimportant for res. */
resources = sort_resources (resources);
/* Write the output file. */
reswr_init ();
switch (output_format)
{
default:
@ -879,12 +1003,3 @@ write_res_file (filename, resources)
{
fatal ("write_res_file unimplemented");
}
void
write_coff_file (filename, target, resources)
const char *filename;
const char *target;
const struct res_directory *resources;
{
fatal ("write_coff_file unimplemented");
}