2388 lines
55 KiB
C
2388 lines
55 KiB
C
|
/* resbin.c -- manipulate the Windows binary resource format.
|
|||
|
Copyright 1997, 1998 Free Software Foundation, Inc.
|
|||
|
Written by Ian Lance Taylor, Cygnus Support.
|
|||
|
|
|||
|
This file is part of GNU Binutils.
|
|||
|
|
|||
|
This program is free software; you can redistribute it and/or modify
|
|||
|
it under the terms of the GNU General Public License as published by
|
|||
|
the Free Software Foundation; either version 2 of the License, or
|
|||
|
(at your option) any later version.
|
|||
|
|
|||
|
This program is distributed in the hope that it will be useful,
|
|||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|||
|
GNU General Public License for more details.
|
|||
|
|
|||
|
You should have received a copy of the GNU General Public License
|
|||
|
along with this program; if not, write to the Free Software
|
|||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|||
|
02111-1307, USA. */
|
|||
|
|
|||
|
/* This file contains functions to convert between the binary resource
|
|||
|
format and the internal structures that we want to use. The same
|
|||
|
binary resource format is used in both res and COFF files. */
|
|||
|
|
|||
|
#include "bfd.h"
|
|||
|
#include "bucomm.h"
|
|||
|
#include "libiberty.h"
|
|||
|
#include "windres.h"
|
|||
|
|
|||
|
/* Macros to swap in values. */
|
|||
|
|
|||
|
#define get_16(be, s) ((be) ? bfd_getb16 (s) : bfd_getl16 (s))
|
|||
|
#define get_32(be, s) ((be) ? bfd_getb32 (s) : bfd_getl32 (s))
|
|||
|
|
|||
|
/* Local functions. */
|
|||
|
|
|||
|
static void toosmall PARAMS ((const char *));
|
|||
|
static unichar *get_unicode
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int, int *));
|
|||
|
static int get_resid
|
|||
|
PARAMS ((struct res_id *, const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_generic
|
|||
|
PARAMS ((enum res_type, const unsigned char *, unsigned long));
|
|||
|
static struct res_resource *bin_to_res_cursor
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_menu
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct menuitem *bin_to_res_menuitems
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int, int *));
|
|||
|
static struct menuitem *bin_to_res_menuexitems
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int, int *));
|
|||
|
static struct res_resource *bin_to_res_dialog
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_string
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_fontdir
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_accelerators
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_rcdata
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_group_cursor
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_group_icon
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_version
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
static struct res_resource *bin_to_res_userdata
|
|||
|
PARAMS ((const unsigned char *, unsigned long, int));
|
|||
|
|
|||
|
/* Given a resource type ID, a pointer to data, a length, return a
|
|||
|
res_resource structure which represents that resource. The caller
|
|||
|
is responsible for initializing the res_info and coff_info fields
|
|||
|
of the returned structure. */
|
|||
|
|
|||
|
struct res_resource *
|
|||
|
bin_to_res (type, data, length, big_endian)
|
|||
|
struct res_id type;
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
if (type.named)
|
|||
|
return bin_to_res_userdata (data, length, big_endian);
|
|||
|
else
|
|||
|
{
|
|||
|
switch (type.u.id)
|
|||
|
{
|
|||
|
default:
|
|||
|
return bin_to_res_userdata (data, length, big_endian);
|
|||
|
case RT_CURSOR:
|
|||
|
return bin_to_res_cursor (data, length, big_endian);
|
|||
|
case RT_BITMAP:
|
|||
|
return bin_to_res_generic (RES_TYPE_BITMAP, data, length);
|
|||
|
case RT_ICON:
|
|||
|
return bin_to_res_generic (RES_TYPE_ICON, data, length);
|
|||
|
case RT_MENU:
|
|||
|
return bin_to_res_menu (data, length, big_endian);
|
|||
|
case RT_DIALOG:
|
|||
|
return bin_to_res_dialog (data, length, big_endian);
|
|||
|
case RT_STRING:
|
|||
|
return bin_to_res_string (data, length, big_endian);
|
|||
|
case RT_FONTDIR:
|
|||
|
return bin_to_res_fontdir (data, length, big_endian);
|
|||
|
case RT_FONT:
|
|||
|
return bin_to_res_generic (RES_TYPE_FONT, data, length);
|
|||
|
case RT_ACCELERATOR:
|
|||
|
return bin_to_res_accelerators (data, length, big_endian);
|
|||
|
case RT_RCDATA:
|
|||
|
return bin_to_res_rcdata (data, length, big_endian);
|
|||
|
case RT_MESSAGETABLE:
|
|||
|
return bin_to_res_generic (RES_TYPE_MESSAGETABLE, data, length);
|
|||
|
case RT_GROUP_CURSOR:
|
|||
|
return bin_to_res_group_cursor (data, length, big_endian);
|
|||
|
case RT_GROUP_ICON:
|
|||
|
return bin_to_res_group_icon (data, length, big_endian);
|
|||
|
case RT_VERSION:
|
|||
|
return bin_to_res_version (data, length, big_endian);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Give an error if the binary data is too small. */
|
|||
|
|
|||
|
static void
|
|||
|
toosmall (msg)
|
|||
|
const char *msg;
|
|||
|
{
|
|||
|
fatal (_("%s: not enough binary data"), msg);
|
|||
|
}
|
|||
|
|
|||
|
/* Swap in a NULL terminated unicode string. */
|
|||
|
|
|||
|
static unichar *
|
|||
|
get_unicode (data, length, big_endian, retlen)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
int *retlen;
|
|||
|
{
|
|||
|
int c, i;
|
|||
|
unichar *ret;
|
|||
|
|
|||
|
c = 0;
|
|||
|
while (1)
|
|||
|
{
|
|||
|
if (length < (unsigned long) c * 2 + 2)
|
|||
|
toosmall (_("null terminated unicode string"));
|
|||
|
if (get_16 (big_endian, data + c * 2) == 0)
|
|||
|
break;
|
|||
|
++c;
|
|||
|
}
|
|||
|
|
|||
|
ret = (unichar *) res_alloc ((c + 1) * sizeof (unichar));
|
|||
|
|
|||
|
for (i = 0; i < c; i++)
|
|||
|
ret[i] = get_16 (big_endian, data + i * 2);
|
|||
|
ret[i] = 0;
|
|||
|
|
|||
|
if (retlen != NULL)
|
|||
|
*retlen = c;
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
/* Get a resource identifier. This returns the number of bytes used. */
|
|||
|
|
|||
|
static int
|
|||
|
get_resid (id, data, length, big_endian)
|
|||
|
struct res_id *id;
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int first;
|
|||
|
|
|||
|
if (length < 2)
|
|||
|
toosmall (_("resource ID"));
|
|||
|
|
|||
|
first = get_16 (big_endian, data);
|
|||
|
if (first == 0xffff)
|
|||
|
{
|
|||
|
if (length < 4)
|
|||
|
toosmall (_("resource ID"));
|
|||
|
id->named = 0;
|
|||
|
id->u.id = get_16 (big_endian, data + 2);
|
|||
|
return 4;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
id->named = 1;
|
|||
|
id->u.n.name = get_unicode (data, length, big_endian, &id->u.n.length);
|
|||
|
return id->u.n.length * 2 + 2;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a resource which just stores uninterpreted data from
|
|||
|
binary. */
|
|||
|
|
|||
|
struct res_resource *
|
|||
|
bin_to_res_generic (type, data, length)
|
|||
|
enum res_type type;
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
{
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = type;
|
|||
|
r->u.data.data = data;
|
|||
|
r->u.data.length = length;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a cursor resource from binary. */
|
|||
|
|
|||
|
struct res_resource *
|
|||
|
bin_to_res_cursor (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct cursor *c;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
if (length < 4)
|
|||
|
toosmall (_("cursor"));
|
|||
|
|
|||
|
c = (struct cursor *) res_alloc (sizeof *c);
|
|||
|
c->xhotspot = get_16 (big_endian, data);
|
|||
|
c->yhotspot = get_16 (big_endian, data + 2);
|
|||
|
c->length = length - 4;
|
|||
|
c->data = data + 4;
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_CURSOR;
|
|||
|
r->u.cursor = c;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a menu resource from binary. */
|
|||
|
|
|||
|
struct res_resource *
|
|||
|
bin_to_res_menu (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct res_resource *r;
|
|||
|
struct menu *m;
|
|||
|
int version, read;
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_MENU;
|
|||
|
|
|||
|
m = (struct menu *) res_alloc (sizeof *m);
|
|||
|
r->u.menu = m;
|
|||
|
|
|||
|
if (length < 2)
|
|||
|
toosmall (_("menu header"));
|
|||
|
|
|||
|
version = get_16 (big_endian, data);
|
|||
|
|
|||
|
if (version == 0)
|
|||
|
{
|
|||
|
if (length < 4)
|
|||
|
toosmall (_("menu header"));
|
|||
|
m->help = 0;
|
|||
|
m->items = bin_to_res_menuitems (data + 4, length - 4, big_endian,
|
|||
|
&read);
|
|||
|
}
|
|||
|
else if (version == 1)
|
|||
|
{
|
|||
|
unsigned int offset;
|
|||
|
|
|||
|
if (length < 8)
|
|||
|
toosmall (_("menuex header"));
|
|||
|
m->help = get_32 (big_endian, data + 4);
|
|||
|
offset = get_16 (big_endian, data + 2);
|
|||
|
if (offset + 4 >= length)
|
|||
|
toosmall (_("menuex offset"));
|
|||
|
m->items = bin_to_res_menuexitems (data + 4 + offset,
|
|||
|
length - (4 + offset),
|
|||
|
big_endian,
|
|||
|
&read);
|
|||
|
}
|
|||
|
else
|
|||
|
fatal (_("unsupported menu version %d"), version);
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert menu items from binary. */
|
|||
|
|
|||
|
static struct menuitem *
|
|||
|
bin_to_res_menuitems (data, length, big_endian, read)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
int *read;
|
|||
|
{
|
|||
|
struct menuitem *first, **pp;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
*read = 0;
|
|||
|
|
|||
|
while (length > 0)
|
|||
|
{
|
|||
|
int flags, slen, itemlen;
|
|||
|
unsigned int stroff;
|
|||
|
struct menuitem *mi;
|
|||
|
|
|||
|
if (length < 4)
|
|||
|
toosmall (_("menuitem header"));
|
|||
|
|
|||
|
mi = (struct menuitem *) res_alloc (sizeof *mi);
|
|||
|
mi->state = 0;
|
|||
|
mi->help = 0;
|
|||
|
|
|||
|
flags = get_16 (big_endian, data);
|
|||
|
mi->type = flags &~ (MENUITEM_POPUP | MENUITEM_ENDMENU);
|
|||
|
|
|||
|
if ((flags & MENUITEM_POPUP) == 0)
|
|||
|
stroff = 4;
|
|||
|
else
|
|||
|
stroff = 2;
|
|||
|
|
|||
|
if (length < stroff + 2)
|
|||
|
toosmall (_("menuitem header"));
|
|||
|
|
|||
|
if (get_16 (big_endian, data + stroff) == 0)
|
|||
|
{
|
|||
|
slen = 0;
|
|||
|
mi->text = NULL;
|
|||
|
}
|
|||
|
else
|
|||
|
mi->text = get_unicode (data + stroff, length - stroff, big_endian,
|
|||
|
&slen);
|
|||
|
|
|||
|
itemlen = stroff + slen * 2 + 2;
|
|||
|
|
|||
|
if ((flags & MENUITEM_POPUP) == 0)
|
|||
|
{
|
|||
|
mi->popup = NULL;
|
|||
|
mi->id = get_16 (big_endian, data + 2);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
int subread;
|
|||
|
|
|||
|
mi->id = 0;
|
|||
|
mi->popup = bin_to_res_menuitems (data + itemlen, length - itemlen,
|
|||
|
big_endian, &subread);
|
|||
|
itemlen += subread;
|
|||
|
}
|
|||
|
|
|||
|
mi->next = NULL;
|
|||
|
*pp = mi;
|
|||
|
pp = &mi->next;
|
|||
|
|
|||
|
data += itemlen;
|
|||
|
length -= itemlen;
|
|||
|
*read += itemlen;
|
|||
|
|
|||
|
if ((flags & MENUITEM_ENDMENU) != 0)
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert menuex items from binary. */
|
|||
|
|
|||
|
static struct menuitem *
|
|||
|
bin_to_res_menuexitems (data, length, big_endian, read)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
int *read;
|
|||
|
{
|
|||
|
struct menuitem *first, **pp;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
*read = 0;
|
|||
|
|
|||
|
while (length > 0)
|
|||
|
{
|
|||
|
int flags, slen;
|
|||
|
unsigned int itemlen;
|
|||
|
struct menuitem *mi;
|
|||
|
|
|||
|
if (length < 14)
|
|||
|
toosmall (_("menuitem header"));
|
|||
|
|
|||
|
mi = (struct menuitem *) res_alloc (sizeof *mi);
|
|||
|
mi->type = get_32 (big_endian, data);
|
|||
|
mi->state = get_32 (big_endian, data + 4);
|
|||
|
mi->id = get_16 (big_endian, data + 8);
|
|||
|
|
|||
|
flags = get_16 (big_endian, data + 10);
|
|||
|
|
|||
|
if (get_16 (big_endian, data + 12) == 0)
|
|||
|
{
|
|||
|
slen = 0;
|
|||
|
mi->text = NULL;
|
|||
|
}
|
|||
|
else
|
|||
|
mi->text = get_unicode (data + 12, length - 12, big_endian, &slen);
|
|||
|
|
|||
|
itemlen = 12 + slen * 2 + 2;
|
|||
|
itemlen = (itemlen + 3) &~ 3;
|
|||
|
|
|||
|
if ((flags & 1) == 0)
|
|||
|
{
|
|||
|
mi->popup = NULL;
|
|||
|
mi->help = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
int subread;
|
|||
|
|
|||
|
if (length < itemlen + 4)
|
|||
|
toosmall (_("menuitem"));
|
|||
|
mi->help = get_32 (big_endian, data + itemlen);
|
|||
|
itemlen += 4;
|
|||
|
|
|||
|
mi->popup = bin_to_res_menuexitems (data + itemlen,
|
|||
|
length - itemlen,
|
|||
|
big_endian, &subread);
|
|||
|
itemlen += subread;
|
|||
|
}
|
|||
|
|
|||
|
mi->next = NULL;
|
|||
|
*pp = mi;
|
|||
|
pp = &mi->next;
|
|||
|
|
|||
|
data += itemlen;
|
|||
|
length -= itemlen;
|
|||
|
*read += itemlen;
|
|||
|
|
|||
|
if ((flags & 0x80) != 0)
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a dialog resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_dialog (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int version;
|
|||
|
struct dialog *d;
|
|||
|
int c, sublen, i;
|
|||
|
unsigned int off;
|
|||
|
struct dialog_control **pp;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
if (length < 18)
|
|||
|
toosmall (_("dialog header"));
|
|||
|
|
|||
|
d = (struct dialog *) res_alloc (sizeof *d);
|
|||
|
|
|||
|
version = get_16 (big_endian, data);
|
|||
|
if (version != 1)
|
|||
|
{
|
|||
|
d->ex = NULL;
|
|||
|
d->style = get_32 (big_endian, data);
|
|||
|
d->exstyle = get_32 (big_endian, data + 4);
|
|||
|
off = 8;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
int signature;
|
|||
|
|
|||
|
signature = get_16 (big_endian, data + 2);
|
|||
|
if (signature != 0xffff)
|
|||
|
fatal (_("unexpected dialog signature %d"), signature);
|
|||
|
|
|||
|
d->ex = (struct dialog_ex *) res_alloc (sizeof (struct dialog_ex));
|
|||
|
d->ex->help = get_32 (big_endian, data + 4);
|
|||
|
d->exstyle = get_32 (big_endian, data + 8);
|
|||
|
d->style = get_32 (big_endian, data + 12);
|
|||
|
off = 16;
|
|||
|
}
|
|||
|
|
|||
|
if (length < off + 10)
|
|||
|
toosmall (_("dialog header"));
|
|||
|
|
|||
|
c = get_16 (big_endian, data + off);
|
|||
|
d->x = get_16 (big_endian, data + off + 2);
|
|||
|
d->y = get_16 (big_endian, data + off + 4);
|
|||
|
d->width = get_16 (big_endian, data + off + 6);
|
|||
|
d->height = get_16 (big_endian, data + off + 8);
|
|||
|
|
|||
|
off += 10;
|
|||
|
|
|||
|
sublen = get_resid (&d->menu, data + off, length - off, big_endian);
|
|||
|
off += sublen;
|
|||
|
|
|||
|
sublen = get_resid (&d->class, data + off, length - off, big_endian);
|
|||
|
off += sublen;
|
|||
|
|
|||
|
d->caption = get_unicode (data + off, length - off, big_endian, &sublen);
|
|||
|
off += sublen * 2 + 2;
|
|||
|
|
|||
|
if ((d->style & DS_SETFONT) == 0)
|
|||
|
{
|
|||
|
d->pointsize = 0;
|
|||
|
d->font = NULL;
|
|||
|
if (d->ex != NULL)
|
|||
|
{
|
|||
|
d->ex->weight = 0;
|
|||
|
d->ex->italic = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (length < off + 2)
|
|||
|
toosmall (_("dialog font point size"));
|
|||
|
|
|||
|
d->pointsize = get_16 (big_endian, data + off);
|
|||
|
off += 2;
|
|||
|
|
|||
|
if (d->ex != NULL)
|
|||
|
{
|
|||
|
if (length < off + 4)
|
|||
|
toosmall (_("dialogex font information"));
|
|||
|
d->ex->weight = get_16 (big_endian, data + off);
|
|||
|
d->ex->italic = get_16 (big_endian, data + off + 2);
|
|||
|
off += 4;
|
|||
|
}
|
|||
|
|
|||
|
d->font = get_unicode (data + off, length - off, big_endian, &sublen);
|
|||
|
off += sublen * 2 + 2;
|
|||
|
}
|
|||
|
|
|||
|
d->controls = NULL;
|
|||
|
pp = &d->controls;
|
|||
|
|
|||
|
for (i = 0; i < c; i++)
|
|||
|
{
|
|||
|
struct dialog_control *dc;
|
|||
|
int datalen;
|
|||
|
|
|||
|
off = (off + 3) &~ 3;
|
|||
|
|
|||
|
dc = (struct dialog_control *) res_alloc (sizeof *dc);
|
|||
|
|
|||
|
if (d->ex == NULL)
|
|||
|
{
|
|||
|
if (length < off + 8)
|
|||
|
toosmall (_("dialog control"));
|
|||
|
|
|||
|
dc->style = get_32 (big_endian, data + off);
|
|||
|
dc->exstyle = get_32 (big_endian, data + off + 4);
|
|||
|
dc->help = 0;
|
|||
|
off += 8;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (length < off + 12)
|
|||
|
toosmall (_("dialogex control"));
|
|||
|
dc->help = get_32 (big_endian, data + off);
|
|||
|
dc->exstyle = get_32 (big_endian, data + off + 4);
|
|||
|
dc->style = get_32 (big_endian, data + off + 8);
|
|||
|
off += 12;
|
|||
|
}
|
|||
|
|
|||
|
if (length < off + 10)
|
|||
|
toosmall (_("dialog control"));
|
|||
|
|
|||
|
dc->x = get_16 (big_endian, data + off);
|
|||
|
dc->y = get_16 (big_endian, data + off + 2);
|
|||
|
dc->width = get_16 (big_endian, data + off + 4);
|
|||
|
dc->height = get_16 (big_endian, data + off + 6);
|
|||
|
|
|||
|
if (d->ex != NULL)
|
|||
|
dc->id = get_32 (big_endian, data + off + 8);
|
|||
|
else
|
|||
|
dc->id = get_16 (big_endian, data + off + 8);
|
|||
|
|
|||
|
off += 10 + (d->ex != NULL ? 2 : 0);
|
|||
|
|
|||
|
sublen = get_resid (&dc->class, data + off, length - off, big_endian);
|
|||
|
off += sublen;
|
|||
|
|
|||
|
sublen = get_resid (&dc->text, data + off, length - off, big_endian);
|
|||
|
off += sublen;
|
|||
|
|
|||
|
if (length < off + 2)
|
|||
|
toosmall (_("dialog control end"));
|
|||
|
|
|||
|
datalen = get_16 (big_endian, data + off);
|
|||
|
off += 2;
|
|||
|
|
|||
|
if (datalen == 0)
|
|||
|
dc->data = NULL;
|
|||
|
else
|
|||
|
{
|
|||
|
off = (off + 3) &~ 3;
|
|||
|
|
|||
|
if (length < off + datalen)
|
|||
|
toosmall (_("dialog control data"));
|
|||
|
|
|||
|
dc->data = ((struct rcdata_item *)
|
|||
|
res_alloc (sizeof (struct rcdata_item)));
|
|||
|
dc->data->next = NULL;
|
|||
|
dc->data->type = RCDATA_BUFFER;
|
|||
|
dc->data->u.buffer.length = datalen;
|
|||
|
dc->data->u.buffer.data = data + off;
|
|||
|
|
|||
|
off += datalen;
|
|||
|
}
|
|||
|
|
|||
|
dc->next = NULL;
|
|||
|
*pp = dc;
|
|||
|
pp = &dc->next;
|
|||
|
}
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_DIALOG;
|
|||
|
r->u.dialog = d;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a stringtable resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_string (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct stringtable *st;
|
|||
|
int i;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
st = (struct stringtable *) res_alloc (sizeof *st);
|
|||
|
|
|||
|
for (i = 0; i < 16; i++)
|
|||
|
{
|
|||
|
unsigned int slen;
|
|||
|
|
|||
|
if (length < 2)
|
|||
|
toosmall (_("stringtable string length"));
|
|||
|
slen = get_16 (big_endian, data);
|
|||
|
st->strings[i].length = slen;
|
|||
|
|
|||
|
if (slen > 0)
|
|||
|
{
|
|||
|
unichar *s;
|
|||
|
unsigned int j;
|
|||
|
|
|||
|
if (length < 2 + 2 * slen)
|
|||
|
toosmall (_("stringtable string"));
|
|||
|
|
|||
|
s = (unichar *) res_alloc (slen * sizeof (unichar));
|
|||
|
st->strings[i].string = s;
|
|||
|
|
|||
|
for (j = 0; j < slen; j++)
|
|||
|
s[j] = get_16 (big_endian, data + 2 + j * 2);
|
|||
|
}
|
|||
|
|
|||
|
data += 2 + 2 * slen;
|
|||
|
length -= 2 + 2 * slen;
|
|||
|
}
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_STRINGTABLE;
|
|||
|
r->u.stringtable = st;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a fontdir resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_fontdir (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int c, i;
|
|||
|
struct fontdir *first, **pp;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
if (length < 2)
|
|||
|
toosmall (_("fontdir header"));
|
|||
|
|
|||
|
c = get_16 (big_endian, data);
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
for (i = 0; i < c; i++)
|
|||
|
{
|
|||
|
struct fontdir *fd;
|
|||
|
unsigned int off;
|
|||
|
|
|||
|
if (length < 56)
|
|||
|
toosmall (_("fontdir"));
|
|||
|
|
|||
|
fd = (struct fontdir *) res_alloc (sizeof *fd);
|
|||
|
fd->index = get_16 (big_endian, data);
|
|||
|
|
|||
|
/* To work out the length of the fontdir data, we must get the
|
|||
|
length of the device name and face name strings, even though
|
|||
|
we don't store them in the fontdir structure. The
|
|||
|
documentation says that these are NULL terminated char
|
|||
|
strings, not Unicode strings. */
|
|||
|
|
|||
|
off = 56;
|
|||
|
|
|||
|
while (off < length && data[off] != '\0')
|
|||
|
++off;
|
|||
|
if (off >= length)
|
|||
|
toosmall (_("fontdir device name"));
|
|||
|
++off;
|
|||
|
|
|||
|
while (off < length && data[off] != '\0')
|
|||
|
++off;
|
|||
|
if (off >= length)
|
|||
|
toosmall (_("fontdir face name"));
|
|||
|
++off;
|
|||
|
|
|||
|
fd->length = off;
|
|||
|
fd->data = data;
|
|||
|
|
|||
|
fd->next = NULL;
|
|||
|
*pp = fd;
|
|||
|
pp = &fd->next;
|
|||
|
|
|||
|
/* The documentation does not indicate that any rounding is
|
|||
|
required. */
|
|||
|
|
|||
|
data += off;
|
|||
|
length -= off;
|
|||
|
}
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_FONTDIR;
|
|||
|
r->u.fontdir = first;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert an accelerators resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_accelerators (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct accelerator *first, **pp;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
while (1)
|
|||
|
{
|
|||
|
struct accelerator *a;
|
|||
|
|
|||
|
if (length < 8)
|
|||
|
toosmall (_("accelerator"));
|
|||
|
|
|||
|
a = (struct accelerator *) res_alloc (sizeof *a);
|
|||
|
|
|||
|
a->flags = get_16 (big_endian, data);
|
|||
|
a->key = get_16 (big_endian, data + 2);
|
|||
|
a->id = get_16 (big_endian, data + 4);
|
|||
|
|
|||
|
a->next = NULL;
|
|||
|
*pp = a;
|
|||
|
pp = &a->next;
|
|||
|
|
|||
|
if ((a->flags & ACC_LAST) != 0)
|
|||
|
break;
|
|||
|
|
|||
|
data += 8;
|
|||
|
length -= 8;
|
|||
|
}
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_ACCELERATOR;
|
|||
|
r->u.acc = first;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert an rcdata resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_rcdata (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct rcdata_item *ri;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
ri = (struct rcdata_item *) res_alloc (sizeof *ri);
|
|||
|
|
|||
|
ri->next = NULL;
|
|||
|
ri->type = RCDATA_BUFFER;
|
|||
|
ri->u.buffer.length = length;
|
|||
|
ri->u.buffer.data = data;
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_RCDATA;
|
|||
|
r->u.rcdata = ri;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a group cursor resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_group_cursor (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int type, c, i;
|
|||
|
struct group_cursor *first, **pp;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
if (length < 6)
|
|||
|
toosmall (_("group cursor header"));
|
|||
|
|
|||
|
type = get_16 (big_endian, data + 2);
|
|||
|
if (type != 2)
|
|||
|
fatal (_("unexpected group cursor type %d"), type);
|
|||
|
|
|||
|
c = get_16 (big_endian, data + 4);
|
|||
|
|
|||
|
data += 6;
|
|||
|
length -= 6;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
for (i = 0; i < c; i++)
|
|||
|
{
|
|||
|
struct group_cursor *gc;
|
|||
|
|
|||
|
if (length < 14)
|
|||
|
toosmall (_("group cursor"));
|
|||
|
|
|||
|
gc = (struct group_cursor *) res_alloc (sizeof *gc);
|
|||
|
|
|||
|
gc->width = get_16 (big_endian, data);
|
|||
|
gc->height = get_16 (big_endian, data + 2);
|
|||
|
gc->planes = get_16 (big_endian, data + 4);
|
|||
|
gc->bits = get_16 (big_endian, data + 6);
|
|||
|
gc->bytes = get_32 (big_endian, data + 8);
|
|||
|
gc->index = get_16 (big_endian, data + 12);
|
|||
|
|
|||
|
gc->next = NULL;
|
|||
|
*pp = gc;
|
|||
|
pp = &gc->next;
|
|||
|
|
|||
|
data += 14;
|
|||
|
length -= 14;
|
|||
|
}
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_GROUP_CURSOR;
|
|||
|
r->u.group_cursor = first;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a group icon resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_group_icon (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int type, c, i;
|
|||
|
struct group_icon *first, **pp;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
if (length < 6)
|
|||
|
toosmall (_("group icon header"));
|
|||
|
|
|||
|
type = get_16 (big_endian, data + 2);
|
|||
|
if (type != 1)
|
|||
|
fatal (_("unexpected group icon type %d"), type);
|
|||
|
|
|||
|
c = get_16 (big_endian, data + 4);
|
|||
|
|
|||
|
data += 6;
|
|||
|
length -= 6;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
for (i = 0; i < c; i++)
|
|||
|
{
|
|||
|
struct group_icon *gi;
|
|||
|
|
|||
|
if (length < 14)
|
|||
|
toosmall (_("group icon"));
|
|||
|
|
|||
|
gi = (struct group_icon *) res_alloc (sizeof *gi);
|
|||
|
|
|||
|
gi->width = data[0];
|
|||
|
gi->height = data[1];
|
|||
|
gi->colors = data[2];
|
|||
|
gi->planes = get_16 (big_endian, data + 4);
|
|||
|
gi->bits = get_16 (big_endian, data + 6);
|
|||
|
gi->bytes = get_32 (big_endian, data + 8);
|
|||
|
gi->index = get_16 (big_endian, data + 12);
|
|||
|
|
|||
|
gi->next = NULL;
|
|||
|
*pp = gi;
|
|||
|
pp = &gi->next;
|
|||
|
|
|||
|
data += 14;
|
|||
|
length -= 14;
|
|||
|
}
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_GROUP_ICON;
|
|||
|
r->u.group_icon = first;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Extract data from a version header. If KEY is not NULL, then the
|
|||
|
key must be KEY; otherwise, the key is returned in *PKEY. This
|
|||
|
sets *LEN to the total length, *VALLEN to the value length, *TYPE
|
|||
|
to the type, and *OFF to the offset to the children. */
|
|||
|
|
|||
|
static void
|
|||
|
get_version_header (data, length, big_endian, key, pkey, len, vallen, type,
|
|||
|
off)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
const char *key;
|
|||
|
unichar **pkey;
|
|||
|
int *len;
|
|||
|
int *vallen;
|
|||
|
int *type;
|
|||
|
int *off;
|
|||
|
{
|
|||
|
if (length < 8)
|
|||
|
toosmall (key);
|
|||
|
|
|||
|
*len = get_16 (big_endian, data);
|
|||
|
*vallen = get_16 (big_endian, data + 2);
|
|||
|
*type = get_16 (big_endian, data + 4);
|
|||
|
|
|||
|
*off = 6;
|
|||
|
|
|||
|
length -= 6;
|
|||
|
data += 6;
|
|||
|
|
|||
|
if (key == NULL)
|
|||
|
{
|
|||
|
int sublen;
|
|||
|
|
|||
|
*pkey = get_unicode (data, length, big_endian, &sublen);
|
|||
|
*off += sublen * 2 + 2;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
while (1)
|
|||
|
{
|
|||
|
if (length < 2)
|
|||
|
toosmall (key);
|
|||
|
if (get_16 (big_endian, data) != (unsigned char) *key)
|
|||
|
fatal (_("unexpected version string"));
|
|||
|
|
|||
|
*off += 2;
|
|||
|
length -= 2;
|
|||
|
data += 2;
|
|||
|
|
|||
|
if (*key == '\0')
|
|||
|
break;
|
|||
|
|
|||
|
++key;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*off = (*off + 3) &~ 3;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a version resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_version (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int verlen, vallen, type, off;
|
|||
|
struct fixed_versioninfo *fi;
|
|||
|
struct ver_info *first, **pp;
|
|||
|
struct versioninfo *v;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
get_version_header (data, length, big_endian, "VS_VERSION_INFO",
|
|||
|
(unichar *) NULL, &verlen, &vallen, &type, &off);
|
|||
|
|
|||
|
if ((unsigned int) verlen != length)
|
|||
|
fatal (_("version length %d does not match resource length %lu"),
|
|||
|
verlen, length);
|
|||
|
|
|||
|
if (type != 0)
|
|||
|
fatal (_("unexpected version type %d"), type);
|
|||
|
|
|||
|
data += off;
|
|||
|
length -= off;
|
|||
|
|
|||
|
if (vallen == 0)
|
|||
|
fi = NULL;
|
|||
|
else
|
|||
|
{
|
|||
|
unsigned long signature, fiv;
|
|||
|
|
|||
|
if (vallen != 52)
|
|||
|
fatal (_("unexpected fixed version information length %d"), vallen);
|
|||
|
|
|||
|
if (length < 52)
|
|||
|
toosmall (_("fixed version info"));
|
|||
|
|
|||
|
signature = get_32 (big_endian, data);
|
|||
|
if (signature != 0xfeef04bd)
|
|||
|
fatal (_("unexpected fixed version signature %lu"), signature);
|
|||
|
|
|||
|
fiv = get_32 (big_endian, data + 4);
|
|||
|
if (fiv != 0 && fiv != 0x10000)
|
|||
|
fatal (_("unexpected fixed version info version %lu"), fiv);
|
|||
|
|
|||
|
fi = (struct fixed_versioninfo *) res_alloc (sizeof *fi);
|
|||
|
|
|||
|
fi->file_version_ms = get_32 (big_endian, data + 8);
|
|||
|
fi->file_version_ls = get_32 (big_endian, data + 12);
|
|||
|
fi->product_version_ms = get_32 (big_endian, data + 16);
|
|||
|
fi->product_version_ls = get_32 (big_endian, data + 20);
|
|||
|
fi->file_flags_mask = get_32 (big_endian, data + 24);
|
|||
|
fi->file_flags = get_32 (big_endian, data + 28);
|
|||
|
fi->file_os = get_32 (big_endian, data + 32);
|
|||
|
fi->file_type = get_32 (big_endian, data + 36);
|
|||
|
fi->file_subtype = get_32 (big_endian, data + 40);
|
|||
|
fi->file_date_ms = get_32 (big_endian, data + 44);
|
|||
|
fi->file_date_ls = get_32 (big_endian, data + 48);
|
|||
|
|
|||
|
data += 52;
|
|||
|
length -= 52;
|
|||
|
}
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
while (length > 0)
|
|||
|
{
|
|||
|
struct ver_info *vi;
|
|||
|
int ch;
|
|||
|
|
|||
|
if (length < 8)
|
|||
|
toosmall (_("version var info"));
|
|||
|
|
|||
|
vi = (struct ver_info *) res_alloc (sizeof *vi);
|
|||
|
|
|||
|
ch = get_16 (big_endian, data + 6);
|
|||
|
|
|||
|
if (ch == 'S')
|
|||
|
{
|
|||
|
struct ver_stringinfo **ppvs;
|
|||
|
|
|||
|
vi->type = VERINFO_STRING;
|
|||
|
|
|||
|
get_version_header (data, length, big_endian, "StringFileInfo",
|
|||
|
(unichar *) NULL, &verlen, &vallen, &type,
|
|||
|
&off);
|
|||
|
|
|||
|
if (vallen != 0)
|
|||
|
fatal (_("unexpected stringfileinfo value length %d"), vallen);
|
|||
|
|
|||
|
data += off;
|
|||
|
length -= off;
|
|||
|
|
|||
|
get_version_header (data, length, big_endian, (const char *) NULL,
|
|||
|
&vi->u.string.language, &verlen, &vallen,
|
|||
|
&type, &off);
|
|||
|
|
|||
|
if (vallen != 0)
|
|||
|
fatal (_("unexpected version stringtable value length %d"), vallen);
|
|||
|
|
|||
|
data += off;
|
|||
|
length -= off;
|
|||
|
verlen -= off;
|
|||
|
|
|||
|
vi->u.string.strings = NULL;
|
|||
|
ppvs = &vi->u.string.strings;
|
|||
|
|
|||
|
/* It's convenient to round verlen to a 4 byte alignment,
|
|||
|
since we round the subvariables in the loop. */
|
|||
|
verlen = (verlen + 3) &~ 3;
|
|||
|
|
|||
|
while (verlen > 0)
|
|||
|
{
|
|||
|
struct ver_stringinfo *vs;
|
|||
|
int subverlen, vslen, valoff;
|
|||
|
|
|||
|
vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
|
|||
|
|
|||
|
get_version_header (data, length, big_endian,
|
|||
|
(const char *) NULL, &vs->key, &subverlen,
|
|||
|
&vallen, &type, &off);
|
|||
|
|
|||
|
subverlen = (subverlen + 3) &~ 3;
|
|||
|
|
|||
|
data += off;
|
|||
|
length -= off;
|
|||
|
|
|||
|
vs->value = get_unicode (data, length, big_endian, &vslen);
|
|||
|
valoff = vslen * 2 + 2;
|
|||
|
valoff = (valoff + 3) &~ 3;
|
|||
|
|
|||
|
if (off + valoff != subverlen)
|
|||
|
fatal (_("unexpected version string length %d != %d + %d"),
|
|||
|
subverlen, off, valoff);
|
|||
|
|
|||
|
vs->next = NULL;
|
|||
|
*ppvs = vs;
|
|||
|
ppvs = &vs->next;
|
|||
|
|
|||
|
data += valoff;
|
|||
|
length -= valoff;
|
|||
|
|
|||
|
if (verlen < subverlen)
|
|||
|
fatal (_("unexpected version string length %d < %d"),
|
|||
|
verlen, subverlen);
|
|||
|
|
|||
|
verlen -= subverlen;
|
|||
|
}
|
|||
|
}
|
|||
|
else if (ch == 'V')
|
|||
|
{
|
|||
|
struct ver_varinfo **ppvv;
|
|||
|
|
|||
|
vi->type = VERINFO_VAR;
|
|||
|
|
|||
|
get_version_header (data, length, big_endian, "VarFileInfo",
|
|||
|
(unichar *) NULL, &verlen, &vallen, &type,
|
|||
|
&off);
|
|||
|
|
|||
|
if (vallen != 0)
|
|||
|
fatal (_("unexpected varfileinfo value length %d"), vallen);
|
|||
|
|
|||
|
data += off;
|
|||
|
length -= off;
|
|||
|
|
|||
|
get_version_header (data, length, big_endian, (const char *) NULL,
|
|||
|
&vi->u.var.key, &verlen, &vallen, &type, &off);
|
|||
|
|
|||
|
data += off;
|
|||
|
length -= off;
|
|||
|
|
|||
|
vi->u.var.var = NULL;
|
|||
|
ppvv = &vi->u.var.var;
|
|||
|
|
|||
|
while (vallen > 0)
|
|||
|
{
|
|||
|
struct ver_varinfo *vv;
|
|||
|
|
|||
|
if (length < 4)
|
|||
|
toosmall (_("version varfileinfo"));
|
|||
|
|
|||
|
vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
|
|||
|
|
|||
|
vv->language = get_16 (big_endian, data);
|
|||
|
vv->charset = get_16 (big_endian, data + 2);
|
|||
|
|
|||
|
vv->next = NULL;
|
|||
|
*ppvv = vv;
|
|||
|
ppvv = &vv->next;
|
|||
|
|
|||
|
data += 4;
|
|||
|
length -= 4;
|
|||
|
|
|||
|
if (vallen < 4)
|
|||
|
fatal (_("unexpected version value length %d"), vallen);
|
|||
|
|
|||
|
vallen -= 4;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
fatal (_("unexpected version string"));
|
|||
|
|
|||
|
vi->next = NULL;
|
|||
|
*pp = vi;
|
|||
|
pp = &vi->next;
|
|||
|
}
|
|||
|
|
|||
|
v = (struct versioninfo *) res_alloc (sizeof *v);
|
|||
|
v->fixed = fi;
|
|||
|
v->var = first;
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_VERSIONINFO;
|
|||
|
r->u.versioninfo = v;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert an arbitrary user defined resource from binary. */
|
|||
|
|
|||
|
static struct res_resource *
|
|||
|
bin_to_res_userdata (data, length, big_endian)
|
|||
|
const unsigned char *data;
|
|||
|
unsigned long length;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct rcdata_item *ri;
|
|||
|
struct res_resource *r;
|
|||
|
|
|||
|
ri = (struct rcdata_item *) res_alloc (sizeof *ri);
|
|||
|
|
|||
|
ri->next = NULL;
|
|||
|
ri->type = RCDATA_BUFFER;
|
|||
|
ri->u.buffer.length = length;
|
|||
|
ri->u.buffer.data = data;
|
|||
|
|
|||
|
r = (struct res_resource *) res_alloc (sizeof *r);
|
|||
|
r->type = RES_TYPE_USERDATA;
|
|||
|
r->u.rcdata = ri;
|
|||
|
|
|||
|
return r;
|
|||
|
}
|
|||
|
|
|||
|
/* Macros to swap out values. */
|
|||
|
|
|||
|
#define put_16(be, v, s) ((be) ? bfd_putb16 ((v), (s)) : bfd_putl16 ((v), (s)))
|
|||
|
#define put_32(be, v, s) ((be) ? bfd_putb32 ((v), (s)) : bfd_putl32 ((v), (s)))
|
|||
|
|
|||
|
/* Local functions used to convert resources to binary format. */
|
|||
|
|
|||
|
static void dword_align_bin PARAMS ((struct bindata ***, unsigned long *));
|
|||
|
static struct bindata *resid_to_bin PARAMS ((struct res_id, int));
|
|||
|
static struct bindata *unicode_to_bin PARAMS ((const unichar *, int));
|
|||
|
static struct bindata *res_to_bin_accelerator
|
|||
|
PARAMS ((const struct accelerator *, int));
|
|||
|
static struct bindata *res_to_bin_cursor
|
|||
|
PARAMS ((const struct cursor *, int));
|
|||
|
static struct bindata *res_to_bin_group_cursor
|
|||
|
PARAMS ((const struct group_cursor *, int));
|
|||
|
static struct bindata *res_to_bin_dialog
|
|||
|
PARAMS ((const struct dialog *, int));
|
|||
|
static struct bindata *res_to_bin_fontdir
|
|||
|
PARAMS ((const struct fontdir *, int));
|
|||
|
static struct bindata *res_to_bin_group_icon
|
|||
|
PARAMS ((const struct group_icon *, int));
|
|||
|
static struct bindata *res_to_bin_menu
|
|||
|
PARAMS ((const struct menu *, int));
|
|||
|
static struct bindata *res_to_bin_menuitems
|
|||
|
PARAMS ((const struct menuitem *, int));
|
|||
|
static struct bindata *res_to_bin_menuexitems
|
|||
|
PARAMS ((const struct menuitem *, int));
|
|||
|
static struct bindata *res_to_bin_rcdata
|
|||
|
PARAMS ((const struct rcdata_item *, int));
|
|||
|
static struct bindata *res_to_bin_stringtable
|
|||
|
PARAMS ((const struct stringtable *, int));
|
|||
|
static struct bindata *string_to_unicode_bin PARAMS ((const char *, int));
|
|||
|
static struct bindata *res_to_bin_versioninfo
|
|||
|
PARAMS ((const struct versioninfo *, int));
|
|||
|
static struct bindata *res_to_bin_generic
|
|||
|
PARAMS ((unsigned long, const unsigned char *));
|
|||
|
|
|||
|
/* Convert a resource to binary. */
|
|||
|
|
|||
|
struct bindata *
|
|||
|
res_to_bin (res, big_endian)
|
|||
|
const struct res_resource *res;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
switch (res->type)
|
|||
|
{
|
|||
|
default:
|
|||
|
abort ();
|
|||
|
case RES_TYPE_BITMAP:
|
|||
|
case RES_TYPE_FONT:
|
|||
|
case RES_TYPE_ICON:
|
|||
|
case RES_TYPE_MESSAGETABLE:
|
|||
|
return res_to_bin_generic (res->u.data.length, res->u.data.data);
|
|||
|
case RES_TYPE_ACCELERATOR:
|
|||
|
return res_to_bin_accelerator (res->u.acc, big_endian);
|
|||
|
case RES_TYPE_CURSOR:
|
|||
|
return res_to_bin_cursor (res->u.cursor, big_endian);
|
|||
|
case RES_TYPE_GROUP_CURSOR:
|
|||
|
return res_to_bin_group_cursor (res->u.group_cursor, big_endian);
|
|||
|
case RES_TYPE_DIALOG:
|
|||
|
return res_to_bin_dialog (res->u.dialog, big_endian);
|
|||
|
case RES_TYPE_FONTDIR:
|
|||
|
return res_to_bin_fontdir (res->u.fontdir, big_endian);
|
|||
|
case RES_TYPE_GROUP_ICON:
|
|||
|
return res_to_bin_group_icon (res->u.group_icon, big_endian);
|
|||
|
case RES_TYPE_MENU:
|
|||
|
return res_to_bin_menu (res->u.menu, big_endian);
|
|||
|
case RES_TYPE_RCDATA:
|
|||
|
return res_to_bin_rcdata (res->u.rcdata, big_endian);
|
|||
|
case RES_TYPE_STRINGTABLE:
|
|||
|
return res_to_bin_stringtable (res->u.stringtable, big_endian);
|
|||
|
case RES_TYPE_USERDATA:
|
|||
|
return res_to_bin_rcdata (res->u.rcdata, big_endian);
|
|||
|
case RES_TYPE_VERSIONINFO:
|
|||
|
return res_to_bin_versioninfo (res->u.versioninfo, big_endian);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Align to a 32 bit boundary. PPP points to the of a list of bindata
|
|||
|
structures. LENGTH points to the length of the structures. If
|
|||
|
necessary, this adds a new bindata to bring length up to a 32 bit
|
|||
|
boundary. It updates *PPP and *LENGTH. */
|
|||
|
|
|||
|
static void
|
|||
|
dword_align_bin (ppp, length)
|
|||
|
struct bindata ***ppp;
|
|||
|
unsigned long *length;
|
|||
|
{
|
|||
|
int add;
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
if ((*length & 3) == 0)
|
|||
|
return;
|
|||
|
|
|||
|
add = 4 - (*length & 3);
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = add;
|
|||
|
d->data = (unsigned char *) reswr_alloc (add);
|
|||
|
memset (d->data, 0, add);
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
**ppp = d;
|
|||
|
*ppp = &(**ppp)->next;
|
|||
|
|
|||
|
*length += add;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a resource ID to binary. This always returns exactly one
|
|||
|
bindata structure. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
resid_to_bin (id, big_endian)
|
|||
|
struct res_id id;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
|
|||
|
if (! id.named)
|
|||
|
{
|
|||
|
d->length = 4;
|
|||
|
d->data = (unsigned char *) reswr_alloc (4);
|
|||
|
put_16 (big_endian, 0xffff, d->data);
|
|||
|
put_16 (big_endian, id.u.id, d->data + 2);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
d->length = id.u.n.length * 2 + 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
for (i = 0; i < id.u.n.length; i++)
|
|||
|
put_16 (big_endian, id.u.n.name[i], d->data + i * 2);
|
|||
|
put_16 (big_endian, 0, d->data + i * 2);
|
|||
|
}
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a null terminated unicode string to binary. This always
|
|||
|
returns exactly one bindata structure. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
unicode_to_bin (str, big_endian)
|
|||
|
const unichar *str;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int len;
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
len = 0;
|
|||
|
if (str != NULL)
|
|||
|
{
|
|||
|
const unichar *s;
|
|||
|
|
|||
|
for (s = str; *s != 0; s++)
|
|||
|
++len;
|
|||
|
}
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = len * 2 + 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
|
|||
|
if (str == NULL)
|
|||
|
put_16 (big_endian, 0, d->data);
|
|||
|
else
|
|||
|
{
|
|||
|
const unichar *s;
|
|||
|
int i;
|
|||
|
|
|||
|
for (s = str, i = 0; *s != 0; s++, i++)
|
|||
|
put_16 (big_endian, *s, d->data + i * 2);
|
|||
|
put_16 (big_endian, 0, d->data + i * 2);
|
|||
|
}
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert an accelerator resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_accelerator (accelerators, big_endian)
|
|||
|
const struct accelerator *accelerators;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
const struct accelerator *a;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
for (a = accelerators; a != NULL; a = a->next)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 8;
|
|||
|
d->data = (unsigned char *) reswr_alloc (8);
|
|||
|
|
|||
|
put_16 (big_endian,
|
|||
|
a->flags | (a->next != NULL ? 0 : ACC_LAST),
|
|||
|
d->data);
|
|||
|
put_16 (big_endian, a->key, d->data + 2);
|
|||
|
put_16 (big_endian, a->id, d->data + 4);
|
|||
|
put_16 (big_endian, 0, d->data + 8);
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
}
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a cursor resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_cursor (c, big_endian)
|
|||
|
const struct cursor *c;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 4;
|
|||
|
d->data = (unsigned char *) reswr_alloc (4);
|
|||
|
|
|||
|
put_16 (big_endian, c->xhotspot, d->data);
|
|||
|
put_16 (big_endian, c->yhotspot, d->data + 2);
|
|||
|
|
|||
|
d->next = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->next->length = c->length;
|
|||
|
d->next->data = (unsigned char *) c->data;
|
|||
|
d->next->next = NULL;
|
|||
|
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a group cursor resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_group_cursor (group_cursors, big_endian)
|
|||
|
const struct group_cursor *group_cursors;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
int c;
|
|||
|
const struct group_cursor *gc;
|
|||
|
|
|||
|
first = (struct bindata *) reswr_alloc (sizeof *first);
|
|||
|
first->length = 6;
|
|||
|
first->data = (unsigned char *) reswr_alloc (6);
|
|||
|
|
|||
|
put_16 (big_endian, 0, first->data);
|
|||
|
put_16 (big_endian, 2, first->data + 2);
|
|||
|
|
|||
|
first->next = NULL;
|
|||
|
pp = &first->next;
|
|||
|
|
|||
|
c = 0;
|
|||
|
for (gc = group_cursors; gc != NULL; gc = gc->next)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
++c;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 14;
|
|||
|
d->data = (unsigned char *) reswr_alloc (14);
|
|||
|
|
|||
|
put_16 (big_endian, gc->width, d->data);
|
|||
|
put_16 (big_endian, gc->height, d->data + 2);
|
|||
|
put_16 (big_endian, gc->planes, d->data + 4);
|
|||
|
put_16 (big_endian, gc->bits, d->data + 6);
|
|||
|
put_32 (big_endian, gc->bytes, d->data + 8);
|
|||
|
put_16 (big_endian, gc->index, d->data + 12);
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, c, first->data + 4);
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a dialog resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_dialog (dialog, big_endian)
|
|||
|
const struct dialog *dialog;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int dialogex;
|
|||
|
struct bindata *first, **pp;
|
|||
|
unsigned long length;
|
|||
|
int off, c;
|
|||
|
struct dialog_control *dc;
|
|||
|
|
|||
|
dialogex = extended_dialog (dialog);
|
|||
|
|
|||
|
first = (struct bindata *) reswr_alloc (sizeof *first);
|
|||
|
first->length = dialogex ? 26 : 18;
|
|||
|
first->data = (unsigned char *) reswr_alloc (first->length);
|
|||
|
|
|||
|
length = first->length;
|
|||
|
|
|||
|
if (! dialogex)
|
|||
|
{
|
|||
|
put_32 (big_endian, dialog->style, first->data);
|
|||
|
put_32 (big_endian, dialog->exstyle, first->data + 4);
|
|||
|
off = 8;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
put_16 (big_endian, 1, first->data);
|
|||
|
put_16 (big_endian, 0xffff, first->data + 2);
|
|||
|
|
|||
|
if (dialog->ex == NULL)
|
|||
|
put_32 (big_endian, 0, first->data + 4);
|
|||
|
else
|
|||
|
put_32 (big_endian, dialog->ex->help, first->data + 4);
|
|||
|
put_32 (big_endian, dialog->exstyle, first->data + 8);
|
|||
|
put_32 (big_endian, dialog->style, first->data + 12);
|
|||
|
off = 16;
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, dialog->x, first->data + off + 2);
|
|||
|
put_16 (big_endian, dialog->y, first->data + off + 4);
|
|||
|
put_16 (big_endian, dialog->width, first->data + off + 6);
|
|||
|
put_16 (big_endian, dialog->height, first->data + off + 8);
|
|||
|
|
|||
|
pp = &first->next;
|
|||
|
|
|||
|
*pp = resid_to_bin (dialog->menu, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
*pp = resid_to_bin (dialog->class, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
*pp = unicode_to_bin (dialog->caption, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
if ((dialog->style & DS_SETFONT) != 0)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = dialogex ? 6 : 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
|
|||
|
length += d->length;
|
|||
|
|
|||
|
put_16 (big_endian, dialog->pointsize, d->data);
|
|||
|
|
|||
|
if (dialogex)
|
|||
|
{
|
|||
|
if (dialog->ex == NULL)
|
|||
|
{
|
|||
|
put_16 (big_endian, 0, d->data + 2);
|
|||
|
put_16 (big_endian, 0, d->data + 4);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
put_16 (big_endian, dialog->ex->weight, d->data + 2);
|
|||
|
put_16 (big_endian, dialog->ex->italic, d->data + 4);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
|
|||
|
*pp = unicode_to_bin (dialog->font, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
}
|
|||
|
|
|||
|
c = 0;
|
|||
|
for (dc = dialog->controls; dc != NULL; dc = dc->next)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
int dcoff;
|
|||
|
|
|||
|
++c;
|
|||
|
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = dialogex ? 24 : 18;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
|
|||
|
length += d->length;
|
|||
|
|
|||
|
if (! dialogex)
|
|||
|
{
|
|||
|
put_32 (big_endian, dc->style, d->data);
|
|||
|
put_32 (big_endian, dc->exstyle, d->data + 4);
|
|||
|
dcoff = 8;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
put_32 (big_endian, dc->help, d->data);
|
|||
|
put_32 (big_endian, dc->exstyle, d->data + 4);
|
|||
|
put_32 (big_endian, dc->style, d->data + 8);
|
|||
|
dcoff = 12;
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, dc->x, d->data + dcoff);
|
|||
|
put_16 (big_endian, dc->y, d->data + dcoff + 2);
|
|||
|
put_16 (big_endian, dc->width, d->data + dcoff + 4);
|
|||
|
put_16 (big_endian, dc->height, d->data + dcoff + 6);
|
|||
|
|
|||
|
if (dialogex)
|
|||
|
put_32 (big_endian, dc->id, d->data + dcoff + 8);
|
|||
|
else
|
|||
|
put_16 (big_endian, dc->id, d->data + dcoff + 8);
|
|||
|
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
|
|||
|
*pp = resid_to_bin (dc->class, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
*pp = resid_to_bin (dc->text, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (2);
|
|||
|
|
|||
|
length += 2;
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
|
|||
|
if (dc->data == NULL)
|
|||
|
put_16 (big_endian, 0, d->data);
|
|||
|
else
|
|||
|
{
|
|||
|
unsigned long sublen;
|
|||
|
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
|
|||
|
*pp = res_to_bin_rcdata (dc->data, big_endian);
|
|||
|
sublen = 0;
|
|||
|
while (*pp != NULL)
|
|||
|
{
|
|||
|
sublen += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, sublen, d->data);
|
|||
|
|
|||
|
length += sublen;
|
|||
|
}
|
|||
|
}
|
|||
|
put_16 (big_endian, c, first->data + off);
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a fontdir resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_fontdir (fontdirs, big_endian)
|
|||
|
const struct fontdir *fontdirs;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
int c;
|
|||
|
const struct fontdir *fd;
|
|||
|
|
|||
|
first = (struct bindata *) reswr_alloc (sizeof *first);
|
|||
|
first->length = 2;
|
|||
|
first->data = (unsigned char *) reswr_alloc (2);
|
|||
|
|
|||
|
first->next = NULL;
|
|||
|
pp = &first->next;
|
|||
|
|
|||
|
c = 0;
|
|||
|
for (fd = fontdirs; fd != NULL; fd = fd->next)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
++c;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (2);
|
|||
|
|
|||
|
put_16 (big_endian, fd->index, d->data);
|
|||
|
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = fd->length;
|
|||
|
d->data = (unsigned char *) fd->data;
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, c, first->data);
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a group icon resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_group_icon (group_icons, big_endian)
|
|||
|
const struct group_icon *group_icons;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
int c;
|
|||
|
const struct group_icon *gi;
|
|||
|
|
|||
|
first = (struct bindata *) reswr_alloc (sizeof *first);
|
|||
|
first->length = 6;
|
|||
|
first->data = (unsigned char *) reswr_alloc (6);
|
|||
|
|
|||
|
put_16 (big_endian, 0, first->data);
|
|||
|
put_16 (big_endian, 1, first->data + 2);
|
|||
|
|
|||
|
first->next = NULL;
|
|||
|
pp = &first->next;
|
|||
|
|
|||
|
c = 0;
|
|||
|
for (gi = group_icons; gi != NULL; gi = gi->next)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
++c;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 14;
|
|||
|
d->data = (unsigned char *) reswr_alloc (14);
|
|||
|
|
|||
|
d->data[0] = gi->width;
|
|||
|
d->data[1] = gi->height;
|
|||
|
d->data[2] = gi->colors;
|
|||
|
d->data[3] = 0;
|
|||
|
put_16 (big_endian, gi->planes, d->data + 4);
|
|||
|
put_16 (big_endian, gi->bits, d->data + 6);
|
|||
|
put_32 (big_endian, gi->bytes, d->data + 8);
|
|||
|
put_16 (big_endian, gi->index, d->data + 12);
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, c, first->data + 4);
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a menu resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_menu (menu, big_endian)
|
|||
|
const struct menu *menu;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
int menuex;
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
menuex = extended_menu (menu);
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = menuex ? 8 : 4;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
|
|||
|
if (! menuex)
|
|||
|
{
|
|||
|
put_16 (big_endian, 0, d->data);
|
|||
|
put_16 (big_endian, 0, d->data + 2);
|
|||
|
|
|||
|
d->next = res_to_bin_menuitems (menu->items, big_endian);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
put_16 (big_endian, 1, d->data);
|
|||
|
put_16 (big_endian, 4, d->data + 2);
|
|||
|
put_32 (big_endian, menu->help, d->data + 4);
|
|||
|
|
|||
|
d->next = res_to_bin_menuexitems (menu->items, big_endian);
|
|||
|
}
|
|||
|
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert menu items to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_menuitems (items, big_endian)
|
|||
|
const struct menuitem *items;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
const struct menuitem *mi;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
for (mi = items; mi != NULL; mi = mi->next)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
int flags;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = mi->popup == NULL ? 4 : 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
|
|||
|
flags = mi->type;
|
|||
|
if (mi->next == NULL)
|
|||
|
flags |= MENUITEM_ENDMENU;
|
|||
|
if (mi->popup != NULL)
|
|||
|
flags |= MENUITEM_POPUP;
|
|||
|
|
|||
|
put_16 (big_endian, flags, d->data);
|
|||
|
|
|||
|
if (mi->popup == NULL)
|
|||
|
put_16 (big_endian, mi->id, d->data + 2);
|
|||
|
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
|
|||
|
*pp = unicode_to_bin (mi->text, big_endian);
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
if (mi->popup != NULL)
|
|||
|
{
|
|||
|
*pp = res_to_bin_menuitems (mi->popup, big_endian);
|
|||
|
while (*pp != NULL)
|
|||
|
pp = &(*pp)->next;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert menuex items to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_menuexitems (items, big_endian)
|
|||
|
const struct menuitem *items;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
unsigned long length;
|
|||
|
const struct menuitem *mi;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
length = 0;
|
|||
|
|
|||
|
for (mi = items; mi != NULL; mi = mi->next)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
int flags;
|
|||
|
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 12;
|
|||
|
d->data = (unsigned char *) reswr_alloc (12);
|
|||
|
|
|||
|
length += 12;
|
|||
|
|
|||
|
put_32 (big_endian, mi->type, d->data);
|
|||
|
put_32 (big_endian, mi->state, d->data + 4);
|
|||
|
put_16 (big_endian, mi->id, d->data + 8);
|
|||
|
|
|||
|
flags = 0;
|
|||
|
if (mi->next == NULL)
|
|||
|
flags |= 0x80;
|
|||
|
if (mi->popup != NULL)
|
|||
|
flags |= 1;
|
|||
|
put_16 (big_endian, flags, d->data + 10);
|
|||
|
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
|
|||
|
*pp = unicode_to_bin (mi->text, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
if (mi->popup != NULL)
|
|||
|
{
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 4;
|
|||
|
d->data = (unsigned char *) reswr_alloc (4);
|
|||
|
|
|||
|
put_32 (big_endian, mi->help, d->data);
|
|||
|
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
|
|||
|
*pp = res_to_bin_menuexitems (mi->popup, big_endian);
|
|||
|
while (*pp != NULL)
|
|||
|
{
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert an rcdata resource to binary. This is also used to convert
|
|||
|
other information which happens to be stored in rcdata_item lists
|
|||
|
to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_rcdata (items, big_endian)
|
|||
|
const struct rcdata_item *items;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
const struct rcdata_item *ri;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
for (ri = items; ri != NULL; ri = ri->next)
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
|
|||
|
switch (ri->type)
|
|||
|
{
|
|||
|
default:
|
|||
|
abort ();
|
|||
|
|
|||
|
case RCDATA_WORD:
|
|||
|
d->length = 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (2);
|
|||
|
put_16 (big_endian, ri->u.word, d->data);
|
|||
|
break;
|
|||
|
|
|||
|
case RCDATA_DWORD:
|
|||
|
d->length = 4;
|
|||
|
d->data = (unsigned char *) reswr_alloc (4);
|
|||
|
put_32 (big_endian, ri->u.dword, d->data);
|
|||
|
break;
|
|||
|
|
|||
|
case RCDATA_STRING:
|
|||
|
d->length = ri->u.string.length;
|
|||
|
d->data = (unsigned char *) ri->u.string.s;
|
|||
|
break;
|
|||
|
|
|||
|
case RCDATA_WSTRING:
|
|||
|
{
|
|||
|
unsigned long i;
|
|||
|
|
|||
|
d->length = ri->u.wstring.length * 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
for (i = 0; i < ri->u.wstring.length; i++)
|
|||
|
put_16 (big_endian, ri->u.wstring.w[i], d->data + i * 2);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case RCDATA_BUFFER:
|
|||
|
d->length = ri->u.buffer.length;
|
|||
|
d->data = (unsigned char *) ri->u.buffer.data;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
}
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a stringtable resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_stringtable (st, big_endian)
|
|||
|
const struct stringtable *st;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
int i;
|
|||
|
|
|||
|
first = NULL;
|
|||
|
pp = &first;
|
|||
|
|
|||
|
for (i = 0; i < 16; i++)
|
|||
|
{
|
|||
|
int slen, j;
|
|||
|
struct bindata *d;
|
|||
|
unichar *s;
|
|||
|
|
|||
|
slen = st->strings[i].length;
|
|||
|
s = st->strings[i].string;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 2 + slen * 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
|
|||
|
put_16 (big_endian, slen, d->data);
|
|||
|
|
|||
|
for (j = 0; j < slen; j++)
|
|||
|
put_16 (big_endian, s[j], d->data + 2 + j * 2);
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
}
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert an ASCII string to a unicode binary string. This always
|
|||
|
returns exactly one bindata structure. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
string_to_unicode_bin (s, big_endian)
|
|||
|
const char *s;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
size_t len, i;
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
len = strlen (s);
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = len * 2 + 2;
|
|||
|
d->data = (unsigned char *) reswr_alloc (d->length);
|
|||
|
|
|||
|
for (i = 0; i < len; i++)
|
|||
|
put_16 (big_endian, s[i], d->data + i * 2);
|
|||
|
put_16 (big_endian, 0, d->data + i * 2);
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
|
|||
|
return d;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a versioninfo resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_versioninfo (versioninfo, big_endian)
|
|||
|
const struct versioninfo *versioninfo;
|
|||
|
int big_endian;
|
|||
|
{
|
|||
|
struct bindata *first, **pp;
|
|||
|
unsigned long length;
|
|||
|
struct ver_info *vi;
|
|||
|
|
|||
|
first = (struct bindata *) reswr_alloc (sizeof *first);
|
|||
|
first->length = 6;
|
|||
|
first->data = (unsigned char *) reswr_alloc (6);
|
|||
|
|
|||
|
length = 6;
|
|||
|
|
|||
|
if (versioninfo->fixed == NULL)
|
|||
|
put_16 (big_endian, 0, first->data + 2);
|
|||
|
else
|
|||
|
put_16 (big_endian, 52, first->data + 2);
|
|||
|
|
|||
|
put_16 (big_endian, 0, first->data + 4);
|
|||
|
|
|||
|
pp = &first->next;
|
|||
|
|
|||
|
*pp = string_to_unicode_bin ("VS_VERSION_INFO", big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
|
|||
|
if (versioninfo->fixed != NULL)
|
|||
|
{
|
|||
|
const struct fixed_versioninfo *fi;
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = 52;
|
|||
|
d->data = (unsigned char *) reswr_alloc (52);
|
|||
|
|
|||
|
length += 52;
|
|||
|
|
|||
|
fi = versioninfo->fixed;
|
|||
|
|
|||
|
put_32 (big_endian, 0xfeef04bd, d->data);
|
|||
|
put_32 (big_endian, 0x10000, d->data + 4);
|
|||
|
put_32 (big_endian, fi->file_version_ms, d->data + 8);
|
|||
|
put_32 (big_endian, fi->file_version_ls, d->data + 12);
|
|||
|
put_32 (big_endian, fi->product_version_ms, d->data + 16);
|
|||
|
put_32 (big_endian, fi->product_version_ls, d->data + 20);
|
|||
|
put_32 (big_endian, fi->file_flags_mask, d->data + 24);
|
|||
|
put_32 (big_endian, fi->file_flags, d->data + 28);
|
|||
|
put_32 (big_endian, fi->file_os, d->data + 32);
|
|||
|
put_32 (big_endian, fi->file_type, d->data + 36);
|
|||
|
put_32 (big_endian, fi->file_subtype, d->data + 40);
|
|||
|
put_32 (big_endian, fi->file_date_ms, d->data + 44);
|
|||
|
put_32 (big_endian, fi->file_date_ls, d->data + 48);
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
*pp = d;
|
|||
|
pp = &d->next;
|
|||
|
}
|
|||
|
|
|||
|
for (vi = versioninfo->var; vi != NULL; vi = vi->next)
|
|||
|
{
|
|||
|
struct bindata *vid;
|
|||
|
unsigned long vilen;
|
|||
|
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
|
|||
|
vid = (struct bindata *) reswr_alloc (sizeof *vid);
|
|||
|
vid->length = 6;
|
|||
|
vid->data = (unsigned char *) reswr_alloc (6);
|
|||
|
|
|||
|
length += 6;
|
|||
|
vilen = 6;
|
|||
|
|
|||
|
put_16 (big_endian, 0, vid->data + 2);
|
|||
|
put_16 (big_endian, 0, vid->data + 4);
|
|||
|
|
|||
|
*pp = vid;
|
|||
|
pp = &vid->next;
|
|||
|
|
|||
|
switch (vi->type)
|
|||
|
{
|
|||
|
default:
|
|||
|
abort ();
|
|||
|
|
|||
|
case VERINFO_STRING:
|
|||
|
{
|
|||
|
unsigned long hold, vslen;
|
|||
|
struct bindata *vsd;
|
|||
|
const struct ver_stringinfo *vs;
|
|||
|
|
|||
|
*pp = string_to_unicode_bin ("StringFileInfo", big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
vilen += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
hold = length;
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
vilen += length - hold;
|
|||
|
|
|||
|
vsd = (struct bindata *) reswr_alloc (sizeof *vsd);
|
|||
|
vsd->length = 6;
|
|||
|
vsd->data = (unsigned char *) reswr_alloc (6);
|
|||
|
|
|||
|
length += 6;
|
|||
|
vilen += 6;
|
|||
|
vslen = 6;
|
|||
|
|
|||
|
put_16 (big_endian, 0, vsd->data + 2);
|
|||
|
put_16 (big_endian, 0, vsd->data + 4);
|
|||
|
|
|||
|
*pp = vsd;
|
|||
|
pp = &vsd->next;
|
|||
|
|
|||
|
*pp = unicode_to_bin (vi->u.string.language, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
vilen += (*pp)->length;
|
|||
|
vslen += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
|
|||
|
{
|
|||
|
struct bindata *vssd;
|
|||
|
unsigned long vsslen;
|
|||
|
|
|||
|
hold = length;
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
vilen += length - hold;
|
|||
|
vslen += length - hold;
|
|||
|
|
|||
|
vssd = (struct bindata *) reswr_alloc (sizeof *vssd);
|
|||
|
vssd->length = 6;
|
|||
|
vssd->data = (unsigned char *) reswr_alloc (6);
|
|||
|
|
|||
|
length += 6;
|
|||
|
vilen += 6;
|
|||
|
vslen += 6;
|
|||
|
vsslen = 6;
|
|||
|
|
|||
|
put_16 (big_endian, 1, vssd->data + 4);
|
|||
|
|
|||
|
*pp = vssd;
|
|||
|
pp = &vssd->next;
|
|||
|
|
|||
|
*pp = unicode_to_bin (vs->key, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
vilen += (*pp)->length;
|
|||
|
vslen += (*pp)->length;
|
|||
|
vsslen += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
hold = length;
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
vilen += length - hold;
|
|||
|
vslen += length - hold;
|
|||
|
vsslen += length - hold;
|
|||
|
|
|||
|
*pp = unicode_to_bin (vs->value, big_endian);
|
|||
|
put_16 (big_endian, (*pp)->length / 2, vssd->data + 2);
|
|||
|
length += (*pp)->length;
|
|||
|
vilen += (*pp)->length;
|
|||
|
vslen += (*pp)->length;
|
|||
|
vsslen += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
put_16 (big_endian, vsslen, vssd->data);
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, vslen, vsd->data);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
case VERINFO_VAR:
|
|||
|
{
|
|||
|
unsigned long hold, vvlen, vvvlen;
|
|||
|
struct bindata *vvd;
|
|||
|
const struct ver_varinfo *vv;
|
|||
|
|
|||
|
*pp = string_to_unicode_bin ("VarFileInfo", big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
vilen += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
hold = length;
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
vilen += length - hold;
|
|||
|
|
|||
|
vvd = (struct bindata *) reswr_alloc (sizeof *vvd);
|
|||
|
vvd->length = 6;
|
|||
|
vvd->data = (unsigned char *) reswr_alloc (6);
|
|||
|
|
|||
|
length += 6;
|
|||
|
vilen += 6;
|
|||
|
vvlen = 6;
|
|||
|
|
|||
|
put_16 (big_endian, 0, vvd->data + 4);
|
|||
|
|
|||
|
*pp = vvd;
|
|||
|
pp = &vvd->next;
|
|||
|
|
|||
|
*pp = unicode_to_bin (vi->u.var.key, big_endian);
|
|||
|
length += (*pp)->length;
|
|||
|
vilen += (*pp)->length;
|
|||
|
vvlen += (*pp)->length;
|
|||
|
pp = &(*pp)->next;
|
|||
|
|
|||
|
hold = length;
|
|||
|
dword_align_bin (&pp, &length);
|
|||
|
vilen += length - hold;
|
|||
|
vvlen += length - hold;
|
|||
|
|
|||
|
vvvlen = 0;
|
|||
|
|
|||
|
for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
|
|||
|
{
|
|||
|
struct bindata *vvsd;
|
|||
|
|
|||
|
vvsd = (struct bindata *) reswr_alloc (sizeof *vvsd);
|
|||
|
vvsd->length = 4;
|
|||
|
vvsd->data = (unsigned char *) reswr_alloc (4);
|
|||
|
|
|||
|
length += 4;
|
|||
|
vilen += 4;
|
|||
|
vvlen += 4;
|
|||
|
vvvlen += 4;
|
|||
|
|
|||
|
put_16 (big_endian, vv->language, vvsd->data);
|
|||
|
put_16 (big_endian, vv->charset, vvsd->data + 2);
|
|||
|
|
|||
|
vvsd->next = NULL;
|
|||
|
*pp = vvsd;
|
|||
|
pp = &vvsd->next;
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, vvlen, vvd->data);
|
|||
|
put_16 (big_endian, vvvlen, vvd->data + 2);
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, vilen, vid->data);
|
|||
|
}
|
|||
|
|
|||
|
put_16 (big_endian, length, first->data);
|
|||
|
|
|||
|
return first;
|
|||
|
}
|
|||
|
|
|||
|
/* Convert a generic resource to binary. */
|
|||
|
|
|||
|
static struct bindata *
|
|||
|
res_to_bin_generic (length, data)
|
|||
|
unsigned long length;
|
|||
|
const unsigned char *data;
|
|||
|
{
|
|||
|
struct bindata *d;
|
|||
|
|
|||
|
d = (struct bindata *) reswr_alloc (sizeof *d);
|
|||
|
d->length = length;
|
|||
|
d->data = (unsigned char *) data;
|
|||
|
|
|||
|
d->next = NULL;
|
|||
|
|
|||
|
return d;
|
|||
|
}
|