/* resbin.c -- manipulate the Windows binary resource format.
- Copyright 1997, 1998, 1999, 2002, 2003, 2007
- Free Software Foundation, Inc.
+ Copyright (C) 1997-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
Rewritten by Kai Tietz, Onevision.
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
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, 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. */
{
rc_res_resource *r;
rc_menu *m;
- rc_uint_type version, read;
+ rc_uint_type version, got;
r = (rc_res_resource *) res_alloc (sizeof *r);
r->type = RES_TYPE_MENU;
if (length < 4)
toosmall (_("menu header"));
m->help = 0;
- m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &read);
+ m->items = bin_to_res_menuitems (wrbfd, data + 4, length - 4, &got);
}
else if (version == 1)
{
if (offset + 4 >= length)
toosmall (_("menuex offset"));
m->items = bin_to_res_menuexitems (wrbfd, data + 4 + offset,
- length - (4 + offset), &read);
+ length - (4 + offset), &got);
}
else
fatal (_("unsupported menu version %d"), (int) version);
static rc_menuitem *
bin_to_res_menuitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
- rc_uint_type *read)
+ rc_uint_type *got)
{
rc_menuitem *first, **pp;
first = NULL;
pp = &first;
- *read = 0;
+ *got = 0;
while (length > 0)
{
data += itemlen;
length -= itemlen;
- *read += itemlen;
+ *got += itemlen;
if ((flags & MENUITEM_ENDMENU) != 0)
return first;
static rc_menuitem *
bin_to_res_menuexitems (windres_bfd *wrbfd, const bfd_byte *data, rc_uint_type length,
- rc_uint_type *read)
+ rc_uint_type *got)
{
rc_menuitem *first, **pp;
first = NULL;
pp = &first;
- *read = 0;
+ *got = 0;
while (length > 0)
{
data += itemlen;
length -= itemlen;
- *read += itemlen;
+ *got += itemlen;
if ((flags & 0x80) != 0)
return first;
dc->data = NULL;
else
{
- off = (off + 3) &~ 3;
-
if (length < off + datalen)
toosmall (_("dialog control data"));
if (length < 8)
toosmall (key);
- *len = windres_get_16 (wrbfd, data, 2);
+ *len = (windres_get_16 (wrbfd, data, 2) + 3) & ~3;
*vallen = windres_get_16 (wrbfd, data + 2, 2);
*type = windres_get_16 (wrbfd, data + 4, 2);
get_version_header (wrbfd, data, length, "VS_VERSION_INFO",
(unichar **) NULL, &verlen, &vallen, &type, &off);
- if ((unsigned int) verlen != length)
- fatal (_("version length %d does not match resource length %lu"),
- (int) verlen, (unsigned long) length);
+ /* PR 17512: The verlen field does not include padding length. */
+ if (verlen > length)
+ fatal (_("version length %lu greater than resource length %lu"),
+ (unsigned long) verlen, (unsigned long) length);
if (type != 0)
fatal (_("unexpected version type %d"), (int) type);
if (ch == 'S')
{
- rc_ver_stringinfo **ppvs;
+ rc_ver_stringtable **ppvst;
vi->type = VERINFO_STRING;
data += off;
length -= off;
- get_version_header (wrbfd, data, length, (const char *) NULL,
- &vi->u.string.language, &verlen, &vallen,
- &type, &off);
+ verlen -= off;
- if (vallen != 0)
- fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
+ vi->u.string.stringtables = NULL;
+ ppvst = &vi->u.string.stringtables;
- data += off;
- length -= off;
- verlen -= off;
+ while (verlen > 0)
+ {
+ rc_ver_stringtable *vst;
+ rc_uint_type stverlen;
+ rc_ver_stringinfo **ppvs;
- vi->u.string.strings = NULL;
- ppvs = &vi->u.string.strings;
+ if (length < 8)
+ toosmall (_("version stringtable"));
- /* It's convenient to round verlen to a 4 byte alignment,
- since we round the subvariables in the loop. */
- verlen = (verlen + 3) &~ 3;
+ vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
- while (verlen > 0)
+ get_version_header (wrbfd, data, length, (const char *) NULL,
+ &vst->language, &stverlen, &vallen, &type, &off);
+
+ if (vallen != 0)
+ fatal (_("unexpected version stringtable value length %ld"), (long) vallen);
+
+ data += off;
+ length -= off;
+ verlen -= off;
+
+ stverlen -= off;
+
+ vst->strings = NULL;
+ ppvs = &vst->strings;
+
+ while (stverlen > 0)
{
rc_ver_stringinfo *vs;
- rc_uint_type subverlen, vslen, valoff;
+ rc_uint_type sverlen, vslen, valoff;
- vs = (rc_ver_stringinfo *) res_alloc (sizeof *vs);
+ if (length < 8)
+ toosmall (_("version string"));
- get_version_header (wrbfd, data, length,
- (const char *) NULL, &vs->key, &subverlen,
- &vallen, &type, &off);
+ vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
- subverlen = (subverlen + 3) &~ 3;
+ get_version_header (wrbfd, data, length, (const char *) NULL,
+ &vs->key, &sverlen, &vallen, &type, &off);
data += off;
length -= off;
vs->value = get_unicode (wrbfd, data, length, &vslen);
valoff = vslen * 2 + 2;
- valoff = (valoff + 3) &~ 3;
+ valoff = (valoff + 3) & ~3;
- if (off + valoff != subverlen)
+ if (off + valoff != sverlen)
fatal (_("unexpected version string length %ld != %ld + %ld"),
- (long) subverlen, (long) off, (long) valoff);
-
- vs->next = NULL;
- *ppvs = vs;
- ppvs = &vs->next;
+ (long) sverlen, (long) off, (long) valoff);
data += valoff;
length -= valoff;
- if (verlen < subverlen)
+ if (stverlen < sverlen)
fatal (_("unexpected version string length %ld < %ld"),
- (long) verlen, (long) subverlen);
+ (long) verlen, (long) sverlen);
+ stverlen -= sverlen;
+ verlen -= sverlen;
- verlen -= subverlen;
+ vs->next = NULL;
+ *ppvs = vs;
+ ppvs = &vs->next;
+ }
+
+ vst->next = NULL;
+ *ppvst = vst;
+ ppvst = &vst->next;
}
}
else if (ch == 'V')
vallen -= 4;
}
}
+ else if (ch == 0)
+ {
+ if (length == 8)
+ /* Padding - skip. */
+ break;
+ fatal (_("nul bytes found in version string"));
+ }
else
- fatal (_("unexpected version string"));
+ fatal (_("unexpected version string character: %x"), ch);
vi->next = NULL;
*pp = vi;
if (wrbfd)
{
struct bin_res_id bri;
-
+
windres_put_16 (wrbfd, bri.sig, 0xffff);
windres_put_16 (wrbfd, bri.id, id.u.id);
set_windres_bfd_content (wrbfd, &bri, off, BIN_RES_ID);
res_to_bin_accelerator (windres_bfd *wrbfd, rc_uint_type off,
const rc_accelerator *accelerators)
{
- bindata *first, **pp;
const rc_accelerator *a;
- first = NULL;
- pp = &first;
-
for (a = accelerators; a != NULL; a = a->next)
{
if (wrbfd)
windres_put_32 (wrbfd, bdc.id, dc->id);
set_windres_bfd_content (wrbfd, &bdc, off, BIN_DIALOGEX_CONTROL_SIZE);
}
- }
+ }
off += (dialogex != 0 ? BIN_DIALOGEX_CONTROL_SIZE : BIN_DIALOG_CONTROL_SIZE);
off = resid_to_bin (wrbfd, off, dc->class);
{
rc_uint_type saved_off = off;
rc_uint_type old_off;
- off += (4 - ((off - off_delta) & 3)) & 3;
old_off = off;
off = res_to_bin_rcdata (wrbfd, off, dc->data);
old_off = off = saved_off;
if (wrbfd)
windres_put_16 (wrbfd, dc_rclen, off - old_off);
- }
+ }
if (wrbfd)
set_windres_bfd_content (wrbfd, dc_rclen, marker, 2);
- }
+ }
if (wrbfd)
{
unichar *s;
slen = (rc_uint_type) st->strings[i].length;
+ if (slen == 0xffffffff) slen = 0;
s = st->strings[i].string;
length = 2 + slen * 2;
abort ();
case VERINFO_STRING:
{
- struct bin_ver_info bvsd;
- rc_uint_type vs_off;
- const rc_ver_stringinfo *vs;
+ const rc_ver_stringtable *vst;
off = string_to_unicode_bin (wrbfd, off, "StringFileInfo");
- off += (4 - ((off - off_delta) & 3)) & 3;
-
- vs_off = off;
-
- off += BIN_VER_INFO_SIZE;
- off = unicode_to_bin (wrbfd, off, vi->u.string.language);
+ if (!vi->u.string.stringtables)
+ off += (4 - ((off - off_delta) & 3)) & 3;
- for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
+ for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
{
- struct bin_ver_info bvss;
- rc_uint_type vss_off,str_off;
+ struct bin_ver_info bvst;
+ rc_uint_type vst_off;
+ const rc_ver_stringinfo *vs;
off += (4 - ((off - off_delta) & 3)) & 3;
- vss_off = off;
+ vst_off = off;
off += BIN_VER_INFO_SIZE;
- off = unicode_to_bin (wrbfd, off, vs->key);
+ off = unicode_to_bin (wrbfd, off, vst->language);
- off += (4 - ((off - off_delta) & 3)) & 3;
+ for (vs = vst->strings; vs != NULL; vs = vs->next)
+ {
+ struct bin_ver_info bvs;
+ rc_uint_type vs_off, str_off;
+
+ off += (4 - ((off - off_delta) & 3)) & 3;
+
+ vs_off = off;
+ off += BIN_VER_INFO_SIZE;
+
+ off = unicode_to_bin (wrbfd, off, vs->key);
+
+ off += (4 - ((off - off_delta) & 3)) & 3;
+
+ str_off = off;
+ off = unicode_to_bin (wrbfd, off, vs->value);
+
+ if (wrbfd)
+ {
+ windres_put_16 (wrbfd, bvs.size, off - vs_off);
+ windres_put_16 (wrbfd, bvs.sig1, (off - str_off) / 2);
+ windres_put_16 (wrbfd, bvs.sig2, 1);
+ set_windres_bfd_content (wrbfd, &bvs, vs_off,
+ BIN_VER_INFO_SIZE);
+ }
+ }
- str_off = off;
- off = unicode_to_bin (wrbfd, off, vs->value);
if (wrbfd)
{
- windres_put_16 (wrbfd, bvss.size, off - vss_off);
- windres_put_16 (wrbfd, bvss.sig1, (off - str_off) / 2);
- windres_put_16 (wrbfd, bvss.sig2, 1);
- set_windres_bfd_content (wrbfd, &bvss, vss_off,
- BIN_VER_INFO_SIZE);
+ windres_put_16 (wrbfd, bvst.size, off - vst_off);
+ windres_put_16 (wrbfd, bvst.sig1, 0);
+ windres_put_16 (wrbfd, bvst.sig2, 1);
+ set_windres_bfd_content (wrbfd, &bvst, vst_off,
+ BIN_VER_INFO_SIZE);
}
}
- if (wrbfd)
- {
- windres_put_16 (wrbfd, bvsd.size, off - vs_off);
- windres_put_16 (wrbfd, bvsd.sig1, 0);
- windres_put_16 (wrbfd, bvsd.sig2, 0);
- set_windres_bfd_content (wrbfd, &bvsd, vs_off,
- BIN_VER_INFO_SIZE);
- }
break;
}
if (wrbfd)
{
- windres_put_16 (wrbfd, bv.size, off-bv_off);
+ windres_put_16 (wrbfd, bv.size, off - bv_off);
windres_put_16 (wrbfd, bv.sig1, 0);
- windres_put_16 (wrbfd, bv.sig2, 0);
+ windres_put_16 (wrbfd, bv.sig2, 1);
set_windres_bfd_content (wrbfd, &bv, bv_off,
BIN_VER_INFO_SIZE);
}