/* resrc.c -- read and write Windows rc files.
- Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 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,
#include "windres.h"
#include <assert.h>
-#include <errno.h>
-#include <sys/stat.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
i++;
i++;
- argv = alloca (sizeof (char *) * (i + 3));
+ argv = xmalloc (sizeof (char *) * (i + 3));
i = 0;
s = cmd;
pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
&errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
+ free (argv);
/* Restore stdout to its previous setting. */
dup2 (stdout_save, STDOUT_FILENO);
if (pid == -1)
{
- fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
+ fatal ("%s %s: %s", errmsg_fmt, errmsg_arg, strerror (errno));
return 1;
}
if (run_cmd (cmd, cpp_temp_file))
fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
- cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
+ cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);
if (cpp_pipe == NULL)
fatal (_("can't open temporary file `%s': %s"),
cpp_temp_file, strerror (errno));
return cpp_pipe;
}
-/* look for the preprocessor program */
+/* Determine if FILENAME contains special characters that
+ can cause problems unless the entire filename is quoted. */
+
+static int
+filename_need_quotes (const char *filename)
+{
+ if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
+ return 0;
+
+ while (*filename != 0)
+ {
+ switch (*filename)
+ {
+ case '&':
+ case ' ':
+ case '<':
+ case '>':
+ case '|':
+ case '%':
+ return 1;
+ }
+ ++filename;
+ }
+ return 0;
+}
+
+/* Look for the preprocessor program. */
static FILE *
look_for_default (char *cmd, const char *prefix, int end_prefix,
char *space;
int found;
struct stat s;
+ const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
strcpy (cmd, prefix);
strcpy (cmd, prefix);
- sprintf (cmd + end_prefix, "%s %s %s",
- DEFAULT_PREPROCESSOR, preprocargs, filename);
+ sprintf (cmd + end_prefix, "%s %s %s%s%s",
+ DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
if (verbose)
fprintf (stderr, _("Using `%s'\n"), cmd);
const char *preprocargs, int language, int use_temp_file)
{
char *cmd;
+ const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
+
+ if (filename == NULL)
+ filename = "-";
+ /* Setup the default resource import path taken from input file. */
+ else if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL)
+ {
+ char *edit, *dir;
+
+ if (filename[0] == '/'
+ || filename[0] == '\\'
+ || filename[1] == ':')
+ /* Absolute path. */
+ edit = dir = xstrdup (filename);
+ else
+ {
+ /* Relative path. */
+ edit = dir = xmalloc (strlen (filename) + 3);
+ sprintf (dir, "./%s", filename);
+ }
+
+ /* Walk dir backwards stopping at the first directory separator. */
+ edit += strlen (dir);
+ while (edit > dir && (edit[-1] != '\\' && edit[-1] != '/'))
+ {
+ --edit;
+ edit[0] = 0;
+ }
+
+ /* Cut off trailing slash. */
+ --edit;
+ edit[0] = 0;
+
+ /* Convert all back slashes to forward slashes. */
+ while ((edit = strchr (dir, '\\')) != NULL)
+ *edit = '/';
+
+ windres_add_include_dir (dir);
+ }
istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
if (preprocargs == NULL)
preprocargs = "";
- if (filename == NULL)
- filename = "-";
if (preprocessor)
{
cmd = xmalloc (strlen (preprocessor)
+ strlen (preprocargs)
+ strlen (filename)
+ + strlen (fnquotes) * 2
+ 10);
- sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
+ sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
+ fnquotes, filename, fnquotes);
cpp_pipe = open_input_stream (cmd);
}
+ strlen (preprocessor)
+ strlen (preprocargs)
+ strlen (filename)
+ + strlen (fnquotes) * 2
#ifdef HAVE_EXECUTABLE_SUFFIX
+ strlen (EXECUTABLE_SUFFIX)
#endif
else
{
if (cpp_pipe != NULL)
- pclose (cpp_pipe);
+ {
+ int err;
+ err = pclose (cpp_pipe);
+ /* We are reading from a pipe, therefore we don't
+ know if cpp failed or succeeded until pclose. */
+ if (err != 0 || errno == ECHILD)
+ {
+ /* Since this is also run via xatexit, safeguard. */
+ cpp_pipe = NULL;
+ cpp_temp_file = NULL;
+ fatal (_("preprocessing failed."));
+ }
+ }
}
/* Since this is also run via xatexit, safeguard. */
void
rcparse_warning (const char *msg)
{
- fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
+ fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
}
/* Die if we get an unexpected end of file. */
if (got == c)
return;
- fatal (_("%s: read of %lu returned %lu"), msg, (long) c, (long) got);
+ fatal (_("%s: read of %lu returned %lu"),
+ msg, (unsigned long) c, (unsigned long) got);
}
\f
/* Define an accelerator resource. */
void
define_stringtable (const rc_res_res_info *resinfo,
- rc_uint_type stringid, const unichar *string)
+ rc_uint_type stringid, const unichar *string, int len)
{
+ unichar *h;
rc_res_id id;
rc_res_resource *r;
r->res_info = *resinfo;
}
-
- r->u.stringtable->strings[stringid & 0xf].length = unichar_len (string);
- r->u.stringtable->strings[stringid & 0xf].string = unichar_dup (string);
+ h = (unichar *) res_alloc ((len + 1) * sizeof (unichar));
+ if (len)
+ memcpy (h, string, len * sizeof (unichar));
+ h[len] = 0;
+ r->u.stringtable->strings[stringid & 0xf].length = (rc_uint_type) len;
+ r->u.stringtable->strings[stringid & 0xf].string = h;
}
void
/* Add string version info to a list of version information. */
rc_ver_info *
-append_ver_stringfileinfo (rc_ver_info *verinfo, const char *language,
- rc_ver_stringinfo *strings)
+append_ver_stringfileinfo (rc_ver_info *verinfo,
+ rc_ver_stringtable *stringtables)
{
rc_ver_info *vi, **pp;
vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
vi->next = NULL;
vi->type = VERINFO_STRING;
- unicode_from_ascii ((rc_uint_type *) NULL, &vi->u.string.language, language);
- vi->u.string.strings = strings;
+ vi->u.string.stringtables = stringtables;
for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
;
return verinfo;
}
+rc_ver_stringtable *
+append_ver_stringtable (rc_ver_stringtable *stringtable,
+ const char *language,
+ rc_ver_stringinfo *strings)
+{
+ rc_ver_stringtable *vst, **pp;
+
+ vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
+ vst->next = NULL;
+ unicode_from_ascii ((rc_uint_type *) NULL, &vst->language, language);
+ vst->strings = strings;
+
+ for (pp = &stringtable; *pp != NULL; pp = &(*pp)->next)
+ ;
+ *pp = vst;
+
+ return stringtable;
+}
+
/* Add variable version info to a list of version information. */
rc_ver_info *
without the need to store it somewhere externally. */
void
-write_rc_file (const char *filename, const rc_res_directory *resources)
+write_rc_file (const char *filename, const rc_res_directory *res_dir)
{
FILE *e;
rc_uint_type language;
}
language = (rc_uint_type) ((bfd_signed_vma) -1);
- write_rc_directory (e, resources, (const rc_res_id *) NULL,
+ write_rc_directory (e, res_dir, (const rc_res_id *) NULL,
(const rc_res_id *) NULL, &language, 1);
}
default:
res_id_print (e, *type, 0);
break;
-
+
PRINT_RT_NAME(RT_MANIFEST);
PRINT_RT_NAME(RT_ANICURSOR);
PRINT_RT_NAME(RT_ANIICON);
ci = NULL;
}
- if (control->text.named || control->text.u.id != 0)
+ /* For EDITTEXT, COMBOBOX, LISTBOX, and SCROLLBAR don't dump text. */
+ if ((control->text.named || control->text.u.id != 0)
+ && (!ci
+ || (ci->class != CTL_EDIT
+ && ci->class != CTL_COMBOBOX
+ && ci->class != CTL_LISTBOX
+ && ci->class != CTL_SCROLLBAR)))
{
fprintf (e, " ");
res_id_print (e, control->text, 1);
indent (e, 2);
if (it->id.u.id == 0)
fprintf (e, "SEPARATOR\n");
- else
+ else
fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
it = it->next;
}
int has_nl;
rc_uint_type c;
rc_uint_type i;
-
+
if (length <= 1)
return 0;
{
int has_error = 0;
const struct bin_messagetable *mt;
+
fprintf (e, "BEGIN\n");
write_rc_datablock (e, length, data, 0, 0, 0);
if (length < BIN_MESSAGETABLE_SIZE)
has_error = 1;
else
- do {
- rc_uint_type m, i;
- mt = (const struct bin_messagetable *) data;
- m = windres_get_32 (&wrtarget, mt->cblocks, length);
- if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
- {
- has_error = 1;
- break;
- }
- for (i = 0; i < m; i++)
- {
- rc_uint_type low, high, offset;
- const struct bin_messagetable_item *mti;
+ do
+ {
+ rc_uint_type m, i;
+
+ mt = (const struct bin_messagetable *) data;
+ m = windres_get_32 (&wrtarget, mt->cblocks, length);
+
+ if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
+ {
+ has_error = 1;
+ break;
+ }
+ for (i = 0; i < m; i++)
+ {
+ rc_uint_type low, high, offset;
+ const struct bin_messagetable_item *mti;
+
+ low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
+ high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
+ offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
+
+ while (low <= high)
+ {
+ rc_uint_type elen, flags;
+ if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
+ {
+ has_error = 1;
+ break;
+ }
+ mti = (const struct bin_messagetable_item *) &data[offset];
+ elen = windres_get_16 (&wrtarget, mti->length, 2);
+ flags = windres_get_16 (&wrtarget, mti->flags, 2);
+ if ((offset + elen) > length)
+ {
+ has_error = 1;
+ break;
+ }
+ wr_printcomment (e, "MessageId = 0x%x", low);
+ wr_printcomment (e, "");
+
+ if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
+ {
+ /* PR 17512: file: 5c3232dc. */
+ if (elen > BIN_MESSAGETABLE_ITEM_SIZE * 2)
+ unicode_print (e, (const unichar *) mti->data,
+ (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
+ }
+ else
+ {
+ if (elen > BIN_MESSAGETABLE_ITEM_SIZE)
+ ascii_print (e, (const char *) mti->data,
+ (elen - BIN_MESSAGETABLE_ITEM_SIZE));
+ }
+
+ wr_printcomment (e,"");
+ ++low;
+ offset += elen;
+ }
+ }
+ }
+ while (0);
- low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
- high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
- offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
- while (low <= high)
- {
- rc_uint_type elen, flags;
- if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
- {
- has_error = 1;
- break;
- }
- mti = (const struct bin_messagetable_item *) &data[offset];
- elen = windres_get_16 (&wrtarget, mti->length, 2);
- flags = windres_get_16 (&wrtarget, mti->flags, 2);
- if ((offset + elen) > length)
- {
- has_error = 1;
- break;
- }
- wr_printcomment (e, "MessageId = 0x%x", low);
- wr_printcomment (e, "");
- if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
- unicode_print (e, (const unichar *) mti->data,
- (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
- else
- ascii_print (e, (const char *) mti->data,
- (elen - BIN_MESSAGETABLE_ITEM_SIZE));
- wr_printcomment (e,"");
- ++low;
- offset += elen;
- }
- }
- } while (0);
if (has_error)
wr_printcomment (e, "Illegal data");
wr_print_flush (e);
fprintf (e, "BEGIN\n");
if (show_comment == -1)
- {
+ {
if (test_rc_datablock_text(length, data))
{
rc_uint_type i, c;
;
if (i < length && data[i] == '\n')
++i, ++c;
- ascii_print (e, (const char *) &data[i - c], c);
+ ascii_print(e, (const char *) &data[i - c], c);
fprintf (e, "\"");
if (i < length)
fprintf (e, "\n");
}
-
+
if (i == 0)
{
indent (e, 2);
u = (const unichar *) &data[i];
indent (e, 2);
fprintf (e, "L\"");
-
+
for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
;
if (i < length && u[c] == '\n')
{
rc_uint_type k;
rc_uint_type comment_start;
-
+
comment_start = i;
-
+
if (! first)
indent (e, 2);
{
if (k == 0)
plen = fprintf (e, "0x%lxL",
- (long) windres_get_32 (&wrtarget, data + i, length - i));
+ (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
else
plen = fprintf (e, " 0x%lxL",
- (long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
+ (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
if (has_next || (i + 4) < length)
{
if (plen>0 && plen < 11)
{
if (stringtable->strings[i].length != 0)
{
- fprintf (e, " %lu, ", (long) offset + i);
+ fprintf (e, " %lu, ", (unsigned long) offset + i);
unicode_print_quoted (e, stringtable->strings[i].string,
stringtable->strings[i].length);
fprintf (e, "\n");
{
case VERINFO_STRING:
{
+ const rc_ver_stringtable *vst;
const rc_ver_stringinfo *vs;
fprintf (e, " BLOCK \"StringFileInfo\"\n");
fprintf (e, " BEGIN\n");
- fprintf (e, " BLOCK ");
- unicode_print_quoted (e, vi->u.string.language, -1);
- fprintf (e, "\n");
- fprintf (e, " BEGIN\n");
- for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
+ for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
{
- fprintf (e, " VALUE ");
- unicode_print_quoted (e, vs->key, -1);
- fprintf (e, ", ");
- unicode_print_quoted (e, vs->value, -1);
+ fprintf (e, " BLOCK ");
+ unicode_print_quoted (e, vst->language, -1);
+
fprintf (e, "\n");
- }
+ fprintf (e, " BEGIN\n");
- fprintf (e, " END\n");
+ for (vs = vst->strings; vs != NULL; vs = vs->next)
+ {
+ fprintf (e, " VALUE ");
+ unicode_print_quoted (e, vs->key, -1);
+ fprintf (e, ", ");
+ unicode_print_quoted (e, vs->value, -1);
+ fprintf (e, "\n");
+ }
+
+ fprintf (e, " END\n");
+ }
fprintf (e, " END\n");
break;
}