1997-06-23 05:35:35 +08:00
|
|
|
|
/* resrc.c -- read and write Windows rc files.
|
|
|
|
|
Copyright 1997 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 function that read and write Windows rc files.
|
|
|
|
|
These are text files that represent resources. */
|
|
|
|
|
|
|
|
|
|
#include "bfd.h"
|
|
|
|
|
#include "bucomm.h"
|
|
|
|
|
#include "libiberty.h"
|
|
|
|
|
#include "windres.h"
|
|
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
|
|
/* The default preprocessor. */
|
|
|
|
|
|
|
|
|
|
#define DEFAULT_PREPROCESSOR "gcc -E -xc-header -DRC_INVOKED"
|
|
|
|
|
|
|
|
|
|
/* We read the directory entries in a cursor or icon file into
|
|
|
|
|
instances of this structure. */
|
|
|
|
|
|
|
|
|
|
struct icondir
|
|
|
|
|
{
|
|
|
|
|
/* Width of image. */
|
|
|
|
|
unsigned char width;
|
|
|
|
|
/* Height of image. */
|
|
|
|
|
unsigned char height;
|
|
|
|
|
/* Number of colors in image. */
|
|
|
|
|
unsigned char colorcount;
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
/* Color planes. */
|
|
|
|
|
unsigned short planes;
|
|
|
|
|
/* Bits per pixel. */
|
|
|
|
|
unsigned short bits;
|
|
|
|
|
} icon;
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
/* X coordinate of hotspot. */
|
|
|
|
|
unsigned short xhotspot;
|
|
|
|
|
/* Y coordinate of hotspot. */
|
|
|
|
|
unsigned short yhotspot;
|
|
|
|
|
} cursor;
|
|
|
|
|
} u;
|
|
|
|
|
/* Bytes in image. */
|
|
|
|
|
unsigned long bytes;
|
|
|
|
|
/* File offset of image. */
|
|
|
|
|
unsigned long offset;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* The name of the rc file we are reading. */
|
|
|
|
|
|
|
|
|
|
char *rc_filename;
|
|
|
|
|
|
|
|
|
|
/* The line number in the rc file. */
|
|
|
|
|
|
|
|
|
|
int rc_lineno;
|
|
|
|
|
|
|
|
|
|
/* The pipe we are reading from, so that we can close it if we exit. */
|
|
|
|
|
|
|
|
|
|
static FILE *cpp_pipe;
|
|
|
|
|
|
|
|
|
|
/* As we read the rc file, we attach information to this structure. */
|
|
|
|
|
|
|
|
|
|
static struct res_directory *resources;
|
|
|
|
|
|
|
|
|
|
/* The number of cursor resources we have written out. */
|
|
|
|
|
|
|
|
|
|
static int cursors;
|
|
|
|
|
|
|
|
|
|
/* The number of font resources we have written out. */
|
|
|
|
|
|
|
|
|
|
static int fonts;
|
|
|
|
|
|
|
|
|
|
/* Font directory information. */
|
|
|
|
|
|
|
|
|
|
struct fontdir *fontdirs;
|
|
|
|
|
|
|
|
|
|
/* Resource info to use for fontdirs. */
|
|
|
|
|
|
|
|
|
|
struct res_res_info fontdirs_resinfo;
|
|
|
|
|
|
|
|
|
|
/* The number of icon resources we have written out. */
|
|
|
|
|
|
|
|
|
|
static int icons;
|
|
|
|
|
|
|
|
|
|
/* Local functions. */
|
|
|
|
|
|
|
|
|
|
static void close_pipe PARAMS ((void));
|
|
|
|
|
static void unexpected_eof PARAMS ((const char *));
|
|
|
|
|
static int get_word PARAMS ((FILE *, const char *));
|
|
|
|
|
static unsigned long get_long PARAMS ((FILE *, const char *));
|
|
|
|
|
static void get_data
|
|
|
|
|
PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
|
|
|
|
|
static void define_fontdirs PARAMS ((void));
|
|
|
|
|
|
|
|
|
|
/* Read an rc file. */
|
|
|
|
|
|
|
|
|
|
struct res_directory *
|
|
|
|
|
read_rc_file (filename, preprocessor, preprocargs, language)
|
|
|
|
|
const char *filename;
|
|
|
|
|
const char *preprocessor;
|
|
|
|
|
const char *preprocargs;
|
|
|
|
|
int language;
|
|
|
|
|
{
|
|
|
|
|
char *cmd;
|
|
|
|
|
|
|
|
|
|
if (preprocessor == NULL)
|
|
|
|
|
preprocessor = DEFAULT_PREPROCESSOR;
|
|
|
|
|
|
|
|
|
|
if (preprocargs == NULL)
|
|
|
|
|
preprocargs = "";
|
|
|
|
|
if (filename == NULL)
|
|
|
|
|
filename = "-";
|
|
|
|
|
|
|
|
|
|
cmd = xmalloc (strlen (preprocessor)
|
|
|
|
|
+ strlen (preprocargs)
|
|
|
|
|
+ strlen (filename)
|
|
|
|
|
+ 10);
|
|
|
|
|
sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
|
|
|
|
|
|
|
|
|
|
cpp_pipe = popen (cmd, FOPEN_RT);
|
|
|
|
|
if (cpp_pipe == NULL)
|
|
|
|
|
fatal ("can't popen `%s': %s", cmd, strerror (errno));
|
|
|
|
|
|
|
|
|
|
xatexit (close_pipe);
|
|
|
|
|
|
|
|
|
|
rc_filename = xstrdup (filename);
|
|
|
|
|
rc_lineno = 1;
|
|
|
|
|
if (language != -1)
|
|
|
|
|
rcparse_set_language (language);
|
|
|
|
|
yyin = cpp_pipe;
|
|
|
|
|
yyparse ();
|
|
|
|
|
|
|
|
|
|
if (pclose (cpp_pipe) != 0)
|
|
|
|
|
fprintf (stderr, "%s: warning: preprocessor failed\n", program_name);
|
|
|
|
|
cpp_pipe = NULL;
|
|
|
|
|
|
|
|
|
|
if (fontdirs != NULL)
|
|
|
|
|
define_fontdirs ();
|
|
|
|
|
|
|
|
|
|
free (rc_filename);
|
|
|
|
|
rc_filename = NULL;
|
|
|
|
|
|
|
|
|
|
return resources;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Close the pipe if it is open. This is called via xatexit. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
close_pipe ()
|
|
|
|
|
{
|
|
|
|
|
if (cpp_pipe != NULL)
|
|
|
|
|
pclose (cpp_pipe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Report an error while reading an rc file. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
yyerror (msg)
|
|
|
|
|
const char *msg;
|
|
|
|
|
{
|
|
|
|
|
fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Issue a warning while reading an rc file. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
rcparse_warning (msg)
|
|
|
|
|
const char *msg;
|
|
|
|
|
{
|
|
|
|
|
fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Die if we get an unexpected end of file. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
unexpected_eof (msg)
|
|
|
|
|
const char *msg;
|
|
|
|
|
{
|
|
|
|
|
fatal ("%s: unexpected EOF", msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read a 16 bit word from a file. The data is assumed to be little
|
|
|
|
|
endian. */
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
get_word (e, msg)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const char *msg;
|
|
|
|
|
{
|
|
|
|
|
int b1, b2;
|
|
|
|
|
|
|
|
|
|
b1 = getc (e);
|
|
|
|
|
b2 = getc (e);
|
|
|
|
|
if (feof (e))
|
|
|
|
|
unexpected_eof (msg);
|
|
|
|
|
return ((b2 & 0xff) << 8) | (b1 & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read a 32 bit word from a file. The data is assumed to be little
|
|
|
|
|
endian. */
|
|
|
|
|
|
|
|
|
|
static unsigned long
|
|
|
|
|
get_long (e, msg)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const char *msg;
|
|
|
|
|
{
|
|
|
|
|
int b1, b2, b3, b4;
|
|
|
|
|
|
|
|
|
|
b1 = getc (e);
|
|
|
|
|
b2 = getc (e);
|
|
|
|
|
b3 = getc (e);
|
|
|
|
|
b4 = getc (e);
|
|
|
|
|
if (feof (e))
|
|
|
|
|
unexpected_eof (msg);
|
|
|
|
|
return (((((((b4 & 0xff) << 8)
|
|
|
|
|
| (b3 & 0xff)) << 8)
|
|
|
|
|
| (b2 & 0xff)) << 8)
|
|
|
|
|
| (b1 & 0xff));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read data from a file. This is a wrapper to do error checking. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_data (e, p, c, msg)
|
|
|
|
|
FILE *e;
|
|
|
|
|
unsigned char *p;
|
|
|
|
|
unsigned long c;
|
|
|
|
|
const char *msg;
|
|
|
|
|
{
|
|
|
|
|
unsigned long got;
|
|
|
|
|
|
|
|
|
|
got = fread (p, 1, c, e);
|
|
|
|
|
if (got == c)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
fatal ("%s: read of %lu returned %lu", msg, c, got);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define an accelerator resource. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_accelerator (id, resinfo, data)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
struct accelerator *data;
|
|
|
|
|
{
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_ACCELERATORS, id,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
r->type = RES_TYPE_ACCELERATOR;
|
|
|
|
|
r->u.acc = data;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a bitmap resource. Bitmap data is stored in a file. The
|
|
|
|
|
first 14 bytes of the file are a standard header, which is not
|
|
|
|
|
included in the resource data. */
|
|
|
|
|
|
|
|
|
|
#define BITMAP_SKIP (14)
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_bitmap (id, resinfo, filename)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
const char *filename;
|
|
|
|
|
{
|
|
|
|
|
FILE *e;
|
|
|
|
|
char *real_filename;
|
|
|
|
|
struct stat s;
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
int i;
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
|
|
|
|
|
|
|
|
|
|
if (stat (real_filename, &s) < 0)
|
|
|
|
|
fatal ("stat failed on bitmap file `%s': %s", real_filename,
|
|
|
|
|
strerror (errno));
|
|
|
|
|
|
|
|
|
|
data = (unsigned char *) xmalloc (s.st_size - BITMAP_SKIP);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < BITMAP_SKIP; i++)
|
|
|
|
|
getc (e);
|
|
|
|
|
|
|
|
|
|
get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
|
|
|
|
|
|
|
|
|
|
fclose (e);
|
|
|
|
|
free (real_filename);
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_BITMAP, id,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
|
|
|
|
|
r->type = RES_TYPE_BITMAP;
|
|
|
|
|
r->u.data.length = s.st_size - BITMAP_SKIP;
|
|
|
|
|
r->u.data.data = data;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a cursor resource. A cursor file may contain a set of
|
|
|
|
|
bitmaps, each representing the same cursor at various different
|
|
|
|
|
resolutions. They each get written out with a different ID. The
|
|
|
|
|
real cursor resource is then a group resource which can be used to
|
|
|
|
|
select one of the actual cursors. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_cursor (id, resinfo, filename)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
const char *filename;
|
|
|
|
|
{
|
|
|
|
|
FILE *e;
|
|
|
|
|
char *real_filename;
|
|
|
|
|
int type, count, i;
|
|
|
|
|
struct icondir *icondirs;
|
|
|
|
|
int first_cursor;
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
struct group_cursor *first, **pp;
|
|
|
|
|
|
|
|
|
|
e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
|
|
|
|
|
|
|
|
|
|
/* A cursor file is basically an icon file. The start of the file
|
|
|
|
|
is a three word structure. The first word is ignored. The
|
|
|
|
|
second word is the type of data. The third word is the number of
|
|
|
|
|
entries. */
|
|
|
|
|
|
|
|
|
|
get_word (e, real_filename);
|
|
|
|
|
type = get_word (e, real_filename);
|
|
|
|
|
count = get_word (e, real_filename);
|
|
|
|
|
if (type != 2)
|
|
|
|
|
fatal ("cursor file `%s' does not contain cursor data", real_filename);
|
|
|
|
|
|
|
|
|
|
/* Read in the icon directory entries. */
|
|
|
|
|
|
|
|
|
|
icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
icondirs[i].width = getc (e);
|
|
|
|
|
icondirs[i].height = getc (e);
|
|
|
|
|
icondirs[i].colorcount = getc (e);
|
|
|
|
|
getc (e);
|
|
|
|
|
icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
|
|
|
|
|
icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
|
|
|
|
|
icondirs[i].bytes = get_long (e, real_filename);
|
|
|
|
|
icondirs[i].offset = get_long (e, real_filename);
|
|
|
|
|
|
|
|
|
|
if (feof (e))
|
|
|
|
|
unexpected_eof (real_filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define each cursor as a unique resource. */
|
|
|
|
|
|
|
|
|
|
first_cursor = cursors;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
struct res_id name;
|
|
|
|
|
struct cursor *c;
|
|
|
|
|
|
|
|
|
|
if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
|
|
|
|
|
fatal ("%s: fseek to %lu failed: %s", real_filename,
|
|
|
|
|
icondirs[i].offset, strerror (errno));
|
|
|
|
|
|
|
|
|
|
data = (unsigned char *) xmalloc (icondirs[i].bytes);
|
|
|
|
|
|
|
|
|
|
get_data (e, data, icondirs[i].bytes, real_filename);
|
|
|
|
|
|
|
|
|
|
c = (struct cursor *) xmalloc (sizeof *c);
|
|
|
|
|
c->xhotspot = icondirs[i].u.cursor.xhotspot;
|
|
|
|
|
c->yhotspot = icondirs[i].u.cursor.yhotspot;
|
|
|
|
|
c->length = icondirs[i].bytes;
|
|
|
|
|
c->data = data;
|
|
|
|
|
|
|
|
|
|
++cursors;
|
|
|
|
|
|
|
|
|
|
name.named = 0;
|
|
|
|
|
name.u.id = cursors;
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_CURSOR, name,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
r->type = RES_TYPE_CURSOR;
|
|
|
|
|
r->u.cursor = c;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose (e);
|
|
|
|
|
free (real_filename);
|
|
|
|
|
|
|
|
|
|
/* Define a cursor group resource. */
|
|
|
|
|
|
|
|
|
|
first = NULL;
|
|
|
|
|
pp = &first;
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
struct group_cursor *cg;
|
|
|
|
|
|
|
|
|
|
/* These manipulations of icondirs into cg are copied from rcl. */
|
|
|
|
|
|
|
|
|
|
cg = (struct group_cursor *) xmalloc (sizeof *cg);
|
|
|
|
|
cg->next = NULL;
|
|
|
|
|
cg->width = icondirs[i].width;
|
|
|
|
|
cg->height = 2 * icondirs[i].height;
|
|
|
|
|
cg->planes = 1;
|
|
|
|
|
cg->bits = 4;
|
|
|
|
|
cg->bytes = icondirs[i].bytes + 8;
|
|
|
|
|
cg->index = first_cursor + i + 1;
|
|
|
|
|
|
|
|
|
|
*pp = cg;
|
|
|
|
|
pp = &(*pp)->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
r->type = RES_TYPE_GROUP_CURSOR;
|
|
|
|
|
r->u.group_cursor = first;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a dialog resource. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_dialog (id, resinfo, dialog)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
const struct dialog *dialog;
|
|
|
|
|
{
|
|
|
|
|
struct dialog *copy;
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
copy = (struct dialog *) xmalloc (sizeof *copy);
|
|
|
|
|
*copy = *dialog;
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_DIALOG, id,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
r->type = RES_TYPE_DIALOG;
|
|
|
|
|
r->u.dialog = copy;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a dialog control. This does not define a resource, but
|
|
|
|
|
merely allocates and fills in a structure. */
|
|
|
|
|
|
|
|
|
|
struct dialog_control *
|
|
|
|
|
define_control (text, id, x, y, width, height, class, style, exstyle)
|
|
|
|
|
char *text;
|
|
|
|
|
unsigned long id;
|
|
|
|
|
unsigned long x;
|
|
|
|
|
unsigned long y;
|
|
|
|
|
unsigned long width;
|
|
|
|
|
unsigned long height;
|
|
|
|
|
unsigned long class;
|
|
|
|
|
unsigned long style;
|
|
|
|
|
unsigned long exstyle;
|
|
|
|
|
{
|
|
|
|
|
struct dialog_control *n;
|
|
|
|
|
|
|
|
|
|
n = (struct dialog_control *) xmalloc (sizeof *n);
|
|
|
|
|
n->next = NULL;
|
|
|
|
|
n->id = id;
|
|
|
|
|
n->style = style;
|
|
|
|
|
n->exstyle = exstyle;
|
|
|
|
|
n->x = x;
|
|
|
|
|
n->y = y;
|
|
|
|
|
n->width = width;
|
|
|
|
|
n->height = height;
|
|
|
|
|
n->class.named = 0;
|
|
|
|
|
n->class.u.id = class;
|
|
|
|
|
if (text != NULL)
|
|
|
|
|
res_string_to_id (&n->text, text);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
n->text.named = 0;
|
|
|
|
|
n->text.u.id = 0;
|
|
|
|
|
}
|
|
|
|
|
free (text);
|
|
|
|
|
n->data = NULL;
|
|
|
|
|
n->help = 0;
|
|
|
|
|
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a font resource. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_font (id, resinfo, filename)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
const char *filename;
|
|
|
|
|
{
|
|
|
|
|
FILE *e;
|
|
|
|
|
char *real_filename;
|
|
|
|
|
struct stat s;
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
struct fontdir *fd;
|
|
|
|
|
long offset;
|
|
|
|
|
const char *device, *face;
|
|
|
|
|
struct fontdir **pp;
|
|
|
|
|
|
|
|
|
|
e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
|
|
|
|
|
|
|
|
|
|
if (stat (real_filename, &s) < 0)
|
|
|
|
|
fatal ("stat failed on bitmap file `%s': %s", real_filename,
|
|
|
|
|
strerror (errno));
|
|
|
|
|
|
|
|
|
|
data = (unsigned char *) xmalloc (s.st_size);
|
|
|
|
|
|
|
|
|
|
get_data (e, data, s.st_size, real_filename);
|
|
|
|
|
|
|
|
|
|
fclose (e);
|
|
|
|
|
free (real_filename);
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_FONT, id,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
|
|
|
|
|
r->type = RES_TYPE_FONT;
|
|
|
|
|
r->u.data.length = s.st_size;
|
|
|
|
|
r->u.data.data = data;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
|
|
|
|
|
/* For each font resource, we must add an entry in the FONTDIR
|
|
|
|
|
resource. The FONTDIR resource includes some strings in the font
|
|
|
|
|
file. To find them, we have to do some magic on the data we have
|
|
|
|
|
read. */
|
|
|
|
|
|
|
|
|
|
offset = ((((((data[47] << 8)
|
|
|
|
|
| data[46]) << 8)
|
|
|
|
|
| data[45]) << 8)
|
|
|
|
|
| data[44]);
|
|
|
|
|
if (offset > 0 && offset < s.st_size)
|
|
|
|
|
device = (char *) data + offset;
|
|
|
|
|
else
|
|
|
|
|
device = "";
|
|
|
|
|
|
|
|
|
|
offset = ((((((data[51] << 8)
|
|
|
|
|
| data[50]) << 8)
|
|
|
|
|
| data[49]) << 8)
|
|
|
|
|
| data[48]);
|
|
|
|
|
if (offset > 0 && offset < s.st_size)
|
|
|
|
|
face = (char *) data + offset;
|
|
|
|
|
else
|
|
|
|
|
face = "";
|
|
|
|
|
|
|
|
|
|
++fonts;
|
|
|
|
|
|
|
|
|
|
fd = (struct fontdir *) xmalloc (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);
|
|
|
|
|
|
|
|
|
|
for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
|
|
|
|
|
;
|
|
|
|
|
*pp = fd;
|
|
|
|
|
|
|
|
|
|
/* For the single fontdirs resource, we always use the resource
|
|
|
|
|
information of the last font. I don't know what else to do. */
|
|
|
|
|
fontdirs_resinfo = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define the fontdirs resource. This is called after the entire rc
|
|
|
|
|
file has been parsed, if any font resources were seen. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
define_fontdirs ()
|
|
|
|
|
{
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
struct res_id id;
|
|
|
|
|
|
|
|
|
|
id.named = 0;
|
|
|
|
|
id.u.id = 1;
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
|
|
|
|
|
|
|
|
|
|
r->type = RES_TYPE_FONTDIR;
|
|
|
|
|
r->u.fontdir = fontdirs;
|
|
|
|
|
r->res_info = fontdirs_resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define an icon resource. An icon file may contain a set of
|
|
|
|
|
bitmaps, each representing the same icon at various different
|
|
|
|
|
resolutions. They each get written out with a different ID. The
|
|
|
|
|
real icon resource is then a group resource which can be used to
|
|
|
|
|
select one of the actual icon bitmaps. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_icon (id, resinfo, filename)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
const char *filename;
|
|
|
|
|
{
|
|
|
|
|
FILE *e;
|
|
|
|
|
char *real_filename;
|
|
|
|
|
int type, count, i;
|
|
|
|
|
struct icondir *icondirs;
|
|
|
|
|
int first_icon;
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
struct group_icon *first, **pp;
|
|
|
|
|
|
|
|
|
|
e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
|
|
|
|
|
|
|
|
|
|
/* The start of an icon file is a three word structure. The first
|
|
|
|
|
word is ignored. The second word is the type of data. The third
|
|
|
|
|
word is the number of entries. */
|
|
|
|
|
|
|
|
|
|
get_word (e, real_filename);
|
|
|
|
|
type = get_word (e, real_filename);
|
|
|
|
|
count = get_word (e, real_filename);
|
|
|
|
|
if (type != 1)
|
|
|
|
|
fatal ("icon file `%s' does not contain icon data", real_filename);
|
|
|
|
|
|
|
|
|
|
/* Read in the icon directory entries. */
|
|
|
|
|
|
|
|
|
|
icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
icondirs[i].width = getc (e);
|
|
|
|
|
icondirs[i].height = getc (e);
|
|
|
|
|
icondirs[i].colorcount = getc (e);
|
|
|
|
|
getc (e);
|
|
|
|
|
icondirs[i].u.icon.planes = get_word (e, real_filename);
|
|
|
|
|
icondirs[i].u.icon.bits = get_word (e, real_filename);
|
|
|
|
|
icondirs[i].bytes = get_long (e, real_filename);
|
|
|
|
|
icondirs[i].offset = get_long (e, real_filename);
|
|
|
|
|
|
|
|
|
|
if (feof (e))
|
|
|
|
|
unexpected_eof (real_filename);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define each icon as a unique resource. */
|
|
|
|
|
|
|
|
|
|
first_icon = icons;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
struct res_id name;
|
|
|
|
|
|
|
|
|
|
if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
|
|
|
|
|
fatal ("%s: fseek to %lu failed: %s", real_filename,
|
|
|
|
|
icondirs[i].offset, strerror (errno));
|
|
|
|
|
|
|
|
|
|
data = (unsigned char *) xmalloc (icondirs[i].bytes);
|
|
|
|
|
|
|
|
|
|
get_data (e, data, icondirs[i].bytes, real_filename);
|
|
|
|
|
|
|
|
|
|
++icons;
|
|
|
|
|
|
|
|
|
|
name.named = 0;
|
|
|
|
|
name.u.id = icons;
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_ICON, name,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
r->type = RES_TYPE_ICON;
|
|
|
|
|
r->u.data.length = icondirs[i].bytes;
|
|
|
|
|
r->u.data.data = data;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose (e);
|
|
|
|
|
free (real_filename);
|
|
|
|
|
|
|
|
|
|
/* Define an icon group resource. */
|
|
|
|
|
|
|
|
|
|
first = NULL;
|
|
|
|
|
pp = &first;
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
struct group_icon *cg;
|
|
|
|
|
|
|
|
|
|
/* FIXME: rcl sets planes and bits based on colors, rather than
|
|
|
|
|
just copying the values from the file. */
|
|
|
|
|
|
|
|
|
|
cg = (struct group_icon *) xmalloc (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->bytes = icondirs[i].bytes;
|
|
|
|
|
cg->index = first_icon + i + 1;
|
|
|
|
|
|
|
|
|
|
*pp = cg;
|
|
|
|
|
pp = &(*pp)->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_GROUP_ICON, id,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
r->type = RES_TYPE_GROUP_ICON;
|
|
|
|
|
r->u.group_icon = first;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a menu resource. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_menu (id, resinfo, menuitems)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
struct menuitem *menuitems;
|
|
|
|
|
{
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
|
|
|
|
|
r->type = RES_TYPE_MENU;
|
|
|
|
|
r->u.menu = menuitems;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a menu item. This does not define a resource, but merely
|
|
|
|
|
allocates and fills in a structure. */
|
|
|
|
|
|
|
|
|
|
struct menuitem *
|
|
|
|
|
define_menuitem (text, menuid, type, state, help, menuitems)
|
|
|
|
|
char *text;
|
|
|
|
|
int menuid;
|
|
|
|
|
unsigned long type;
|
|
|
|
|
unsigned long state;
|
|
|
|
|
unsigned long help;
|
|
|
|
|
struct menuitem *menuitems;
|
|
|
|
|
{
|
|
|
|
|
struct menuitem *mi;
|
|
|
|
|
|
|
|
|
|
mi = (struct menuitem *) xmalloc (sizeof *mi);
|
|
|
|
|
mi->next = NULL;
|
|
|
|
|
mi->type = type;
|
|
|
|
|
mi->state = state;
|
|
|
|
|
mi->id = menuid;
|
|
|
|
|
mi->text = text;
|
|
|
|
|
mi->help = help;
|
|
|
|
|
mi->popup = menuitems;
|
|
|
|
|
return mi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a messagetable resource. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_messagetable (id, resinfo, filename)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
const char *filename;
|
|
|
|
|
{
|
|
|
|
|
FILE *e;
|
|
|
|
|
char *real_filename;
|
|
|
|
|
struct stat s;
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
e = open_file_search (filename, FOPEN_RB, "messagetable file",
|
|
|
|
|
&real_filename);
|
|
|
|
|
|
|
|
|
|
if (stat (real_filename, &s) < 0)
|
|
|
|
|
fatal ("stat failed on bitmap file `%s': %s", real_filename,
|
|
|
|
|
strerror (errno));
|
|
|
|
|
|
|
|
|
|
data = (unsigned char *) xmalloc (s.st_size);
|
|
|
|
|
|
|
|
|
|
get_data (e, data, s.st_size, real_filename);
|
|
|
|
|
|
|
|
|
|
fclose (e);
|
|
|
|
|
free (real_filename);
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
|
|
|
|
|
r->type = RES_TYPE_MESSAGETABLE;
|
|
|
|
|
r->u.data.length = s.st_size;
|
|
|
|
|
r->u.data.data = data;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define an rcdata resource. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_rcdata (id, resinfo, data)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
struct rcdata_data *data;
|
|
|
|
|
{
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_RCDATA, id,
|
|
|
|
|
resinfo->language, 0);
|
|
|
|
|
r->type = RES_TYPE_RCDATA;
|
|
|
|
|
r->u.rcdata = data;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add an rcdata_item to an rcdata resource. */
|
|
|
|
|
|
|
|
|
|
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 *ri;
|
|
|
|
|
|
|
|
|
|
ri = (struct rcdata_item *) xmalloc (sizeof *ri);
|
|
|
|
|
ri->next = NULL;
|
|
|
|
|
ri->type = RCDATA_STRING;
|
|
|
|
|
ri->u.string = string;
|
|
|
|
|
|
|
|
|
|
return append_rcdata_item (data, ri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add a number to an rcdata resource. */
|
|
|
|
|
|
|
|
|
|
struct rcdata_data *
|
|
|
|
|
append_rcdata_number (data, val, dword)
|
|
|
|
|
struct rcdata_data *data;
|
|
|
|
|
unsigned long val;
|
|
|
|
|
int dword;
|
|
|
|
|
{
|
|
|
|
|
struct rcdata_item *ri;
|
|
|
|
|
|
|
|
|
|
ri = (struct rcdata_item *) xmalloc (sizeof *ri);
|
|
|
|
|
ri->next = NULL;
|
|
|
|
|
ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
|
|
|
|
|
ri->u.word = val;
|
|
|
|
|
|
|
|
|
|
return append_rcdata_item (data, ri);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a stringtable resource. This is called for each string
|
|
|
|
|
which appears in a STRINGTABLE statement. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_stringtable (resinfo, stringid, string)
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
unsigned long stringid;
|
|
|
|
|
char *string;
|
|
|
|
|
{
|
|
|
|
|
struct res_id id;
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
id.named = 0;
|
|
|
|
|
id.u.id = stringid >> 4;
|
|
|
|
|
r = define_standard_resource (&resources, RT_STRING, id,
|
|
|
|
|
resinfo->language, 1);
|
|
|
|
|
|
|
|
|
|
if (r->type == RES_TYPE_UNINITIALIZED)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
r->type = RES_TYPE_STRINGTABLE;
|
|
|
|
|
r->u.stringtable = ((struct stringtable *)
|
|
|
|
|
xmalloc (sizeof (struct stringtable)));
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
|
{
|
|
|
|
|
r->u.stringtable->strings[i].length = 0;
|
|
|
|
|
r->u.stringtable->strings[i].string = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
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 res_id ids[3];
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
ids[0] = type;
|
|
|
|
|
ids[1] = id;
|
|
|
|
|
ids[2].named = 0;
|
|
|
|
|
ids[2].u.id = resinfo->language;
|
|
|
|
|
|
|
|
|
|
r = define_resource (&resources, 3, ids, 0);
|
|
|
|
|
r->type = RES_TYPE_USERDATA;
|
|
|
|
|
r->u.userdata = data;
|
|
|
|
|
r->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a user data resource where the data is in a file. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_user_file (id, type, resinfo, filename)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
struct res_id type;
|
|
|
|
|
const struct res_res_info *resinfo;
|
|
|
|
|
const char *filename;
|
|
|
|
|
{
|
|
|
|
|
FILE *e;
|
|
|
|
|
char *real_filename;
|
|
|
|
|
struct stat s;
|
|
|
|
|
unsigned char *data;
|
|
|
|
|
struct res_id ids[3];
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
|
|
|
|
|
|
|
|
|
|
if (stat (real_filename, &s) < 0)
|
|
|
|
|
fatal ("stat failed on bitmap file `%s': %s", real_filename,
|
|
|
|
|
strerror (errno));
|
|
|
|
|
|
|
|
|
|
data = (unsigned char *) xmalloc (s.st_size);
|
|
|
|
|
|
|
|
|
|
get_data (e, data, s.st_size, real_filename);
|
|
|
|
|
|
|
|
|
|
fclose (e);
|
|
|
|
|
free (real_filename);
|
|
|
|
|
|
|
|
|
|
ids[0] = type;
|
|
|
|
|
ids[1] = id;
|
|
|
|
|
ids[2].named = 0;
|
|
|
|
|
ids[2].u.id = resinfo->language;
|
|
|
|
|
|
|
|
|
|
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->res_info = *resinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Define a versioninfo resource. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
define_versioninfo (id, language, fixedverinfo, verinfo)
|
|
|
|
|
struct res_id id;
|
|
|
|
|
int language;
|
|
|
|
|
struct fixed_versioninfo *fixedverinfo;
|
|
|
|
|
struct ver_info *verinfo;
|
|
|
|
|
{
|
|
|
|
|
struct res_resource *r;
|
|
|
|
|
|
|
|
|
|
r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
|
|
|
|
|
r->type = RES_TYPE_VERSIONINFO;
|
|
|
|
|
r->u.versioninfo = ((struct versioninfo *)
|
|
|
|
|
xmalloc (sizeof (struct versioninfo)));
|
|
|
|
|
r->u.versioninfo->fixed = fixedverinfo;
|
|
|
|
|
r->u.versioninfo->var = verinfo;
|
|
|
|
|
r->res_info.language = language;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add string version info to a list of version information. */
|
|
|
|
|
|
|
|
|
|
struct ver_info *
|
|
|
|
|
append_ver_stringfileinfo (verinfo, language, strings)
|
|
|
|
|
struct ver_info *verinfo;
|
|
|
|
|
char *language;
|
|
|
|
|
struct ver_stringinfo *strings;
|
|
|
|
|
{
|
|
|
|
|
struct ver_info *vi, **pp;
|
|
|
|
|
|
|
|
|
|
vi = (struct ver_info *) xmalloc (sizeof *vi);
|
|
|
|
|
vi->next = NULL;
|
|
|
|
|
vi->type = VERINFO_STRING;
|
|
|
|
|
unicode_from_ascii ((unsigned short *) NULL, &vi->u.string.language,
|
|
|
|
|
language);
|
|
|
|
|
free (language);
|
|
|
|
|
vi->u.string.strings = strings;
|
|
|
|
|
|
|
|
|
|
for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
|
|
|
|
|
;
|
|
|
|
|
*pp = vi;
|
|
|
|
|
|
|
|
|
|
return verinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add variable version info to a list of version information. */
|
|
|
|
|
|
|
|
|
|
struct ver_info *
|
|
|
|
|
append_ver_varfileinfo (verinfo, key, var)
|
|
|
|
|
struct ver_info *verinfo;
|
|
|
|
|
char *key;
|
|
|
|
|
struct ver_varinfo *var;
|
|
|
|
|
{
|
|
|
|
|
struct ver_info *vi, **pp;
|
|
|
|
|
|
|
|
|
|
vi = (struct ver_info *) xmalloc (sizeof *vi);
|
|
|
|
|
vi->next = NULL;
|
|
|
|
|
vi->type = VERINFO_VAR;
|
|
|
|
|
unicode_from_ascii ((unsigned short *) NULL, &vi->u.var.key, key);
|
|
|
|
|
free (key);
|
|
|
|
|
vi->u.var.var = var;
|
|
|
|
|
|
|
|
|
|
for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
|
|
|
|
|
;
|
|
|
|
|
*pp = vi;
|
|
|
|
|
|
|
|
|
|
return verinfo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Append version string information to a list. */
|
|
|
|
|
|
|
|
|
|
struct ver_stringinfo *
|
|
|
|
|
append_verval (strings, key, value)
|
|
|
|
|
struct ver_stringinfo *strings;
|
|
|
|
|
char *key;
|
|
|
|
|
char *value;
|
|
|
|
|
{
|
|
|
|
|
struct ver_stringinfo *vs, **pp;
|
|
|
|
|
|
|
|
|
|
vs = (struct ver_stringinfo *) xmalloc (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);
|
|
|
|
|
|
|
|
|
|
for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
|
|
|
|
|
;
|
|
|
|
|
*pp = vs;
|
|
|
|
|
|
|
|
|
|
return strings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Append version variable information to a list. */
|
|
|
|
|
|
|
|
|
|
struct ver_varinfo *
|
|
|
|
|
append_vertrans (var, language, charset)
|
|
|
|
|
struct ver_varinfo *var;
|
|
|
|
|
unsigned long language;
|
|
|
|
|
unsigned long charset;
|
|
|
|
|
{
|
|
|
|
|
struct ver_varinfo *vv, **pp;
|
|
|
|
|
|
|
|
|
|
vv = (struct ver_varinfo *) xmalloc (sizeof *vv);
|
|
|
|
|
vv->next = NULL;
|
|
|
|
|
vv->language = language;
|
|
|
|
|
vv->charset = charset;
|
|
|
|
|
|
|
|
|
|
for (pp = &var; *pp != NULL; pp = &(*pp)->next)
|
|
|
|
|
;
|
|
|
|
|
*pp = vv;
|
|
|
|
|
|
|
|
|
|
return var;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Local functions used to write out an rc file. */
|
|
|
|
|
|
|
|
|
|
static void indent PARAMS ((FILE *, int));
|
|
|
|
|
static void write_rc_directory
|
|
|
|
|
PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
|
|
|
|
|
const struct res_id *, int *, int));
|
|
|
|
|
static void write_rc_subdir
|
|
|
|
|
PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
|
|
|
|
|
const struct res_id *, int *, int));
|
|
|
|
|
static void write_rc_resource
|
|
|
|
|
PARAMS ((FILE *, const struct res_id *, const struct res_id *,
|
|
|
|
|
const struct res_resource *, int *));
|
|
|
|
|
static void write_rc_accelerators
|
|
|
|
|
PARAMS ((FILE *, const struct accelerator *));
|
|
|
|
|
static void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
|
|
|
|
|
static void write_rc_group_cursor
|
|
|
|
|
PARAMS ((FILE *, const struct group_cursor *));
|
|
|
|
|
static void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
|
|
|
|
|
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_stringtable
|
|
|
|
|
PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
|
|
|
|
|
static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
|
|
|
|
|
static void write_rc_filedata
|
|
|
|
|
PARAMS ((FILE *, unsigned long, const unsigned char *));
|
|
|
|
|
|
|
|
|
|
/* Indent a given number of spaces. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
indent (e, c)
|
|
|
|
|
FILE *e;
|
|
|
|
|
int c;
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
|
putc (' ', e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dump the resources we have read in the format of an rc file.
|
|
|
|
|
|
|
|
|
|
Actually, we don't use the format of an rc file, because it's way
|
|
|
|
|
too much of a pain--for example, we'd have to write icon resources
|
|
|
|
|
into a file and refer to that file. We just generate a readable
|
|
|
|
|
format that kind of looks like an rc file, and is useful for
|
|
|
|
|
understanding the contents of a resource file. Someday we may want
|
|
|
|
|
to generate an rc file which the rc compiler can read; if that day
|
|
|
|
|
comes, this code will have to be fixed up. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
write_rc_file (filename, resources)
|
|
|
|
|
const char *filename;
|
|
|
|
|
const struct res_directory *resources;
|
|
|
|
|
{
|
|
|
|
|
FILE *e;
|
|
|
|
|
int language;
|
|
|
|
|
|
|
|
|
|
if (filename == NULL)
|
|
|
|
|
e = stdout;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
e = fopen (filename, FOPEN_WT);
|
|
|
|
|
if (e == NULL)
|
|
|
|
|
fatal ("can't open `%s' for output: %s", filename, strerror (errno));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
language = -1;
|
|
|
|
|
write_rc_directory (e, resources, (const struct res_id *) NULL,
|
|
|
|
|
(const struct res_id *) NULL, &language, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out a directory. E is the file to write to. RD is the
|
|
|
|
|
directory. TYPE is a pointer to the level 1 ID which serves as the
|
|
|
|
|
resource type. NAME is a pointer to the level 2 ID which serves as
|
|
|
|
|
an individual resource name. LANGUAGE is a pointer to the current
|
|
|
|
|
language. LEVEL is the level in the tree. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_directory (e, rd, type, name, language, level)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct res_directory *rd;
|
|
|
|
|
const struct res_id *type;
|
|
|
|
|
const struct res_id *name;
|
|
|
|
|
int *language;
|
|
|
|
|
int level;
|
|
|
|
|
{
|
|
|
|
|
const struct res_entry *re;
|
|
|
|
|
|
|
|
|
|
/* Print out some COFF information that rc files can't represent. */
|
|
|
|
|
|
|
|
|
|
if (rd->time != 0)
|
|
|
|
|
fprintf (e, "// Time stamp: %lu\n", rd->time);
|
|
|
|
|
if (rd->characteristics != 0)
|
|
|
|
|
fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
|
|
|
|
|
if (rd->major != 0 || rd->minor != 0)
|
|
|
|
|
fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
|
|
|
|
|
|
|
|
|
|
for (re = rd->entries; re != NULL; re = re->next)
|
|
|
|
|
{
|
|
|
|
|
switch (level)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
/* If we're at level 1, the key of this resource is the
|
|
|
|
|
type. This normally duplicates the information we have
|
|
|
|
|
stored with the resource itself, but we need to remember
|
|
|
|
|
the type if this is a user define resource type. */
|
|
|
|
|
type = &re->id;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
/* If we're at level 2, the key of this resource is the name
|
|
|
|
|
we are going to use in the rc printout. */
|
|
|
|
|
name = &re->id;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
/* If we're at level 3, then this key represents a language.
|
|
|
|
|
Use it to update the current language. */
|
|
|
|
|
if (! re->id.named
|
|
|
|
|
&& re->id.u.id != *language
|
|
|
|
|
&& (re->id.u.id & 0xffff) == re->id.u.id)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "LANGUAGE %lu, %lu\n",
|
|
|
|
|
re->id.u.id & 0xff, (re->id.u.id >> 8) & 0xff);
|
|
|
|
|
*language = re->id.u.id;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (re->subdir)
|
|
|
|
|
write_rc_subdir (e, re, type, name, language, level);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (level == 3)
|
|
|
|
|
{
|
|
|
|
|
/* This is the normal case: the three levels are
|
|
|
|
|
TYPE/NAME/LANGUAGE. NAME will have been set at level
|
|
|
|
|
2, and represents the name to use. We probably just
|
|
|
|
|
set LANGUAGE, and it will probably match what the
|
|
|
|
|
resource itself records if anything. */
|
|
|
|
|
write_rc_resource (e, type, name, re->u.res, language);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// Resource at unexpected level %d\n", level);
|
|
|
|
|
write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
|
|
|
|
|
language);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out a subdirectory entry. E is the file to write to. RE is
|
|
|
|
|
the subdirectory entry. TYPE and NAME are pointers to higher level
|
|
|
|
|
IDs, or NULL. LANGUAGE is a pointer to the current language.
|
|
|
|
|
LEVEL is the level in the tree. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_subdir (e, re, type, name, language, level)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct res_entry *re;
|
|
|
|
|
const struct res_id *type;
|
|
|
|
|
const struct res_id *name;
|
|
|
|
|
int *language;
|
|
|
|
|
int level;
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
switch (level)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
|
|
|
|
fprintf (e, "// Type: ");
|
|
|
|
|
if (re->id.named)
|
|
|
|
|
res_id_print (e, re->id, 1);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
|
|
switch (re->id.u.id)
|
|
|
|
|
{
|
|
|
|
|
case RT_CURSOR: s = "cursor"; break;
|
|
|
|
|
case RT_BITMAP: s = "bitmap"; break;
|
|
|
|
|
case RT_ICON: s = "icon"; break;
|
|
|
|
|
case RT_MENU: s = "menu"; break;
|
|
|
|
|
case RT_DIALOG: s = "dialog"; break;
|
|
|
|
|
case RT_STRING: s = "stringtable"; break;
|
|
|
|
|
case RT_FONTDIR: s = "fontdir"; break;
|
|
|
|
|
case RT_FONT: s = "font"; break;
|
|
|
|
|
case RT_ACCELERATORS: s = "accelerators"; break;
|
|
|
|
|
case RT_RCDATA: s = "rcdata"; break;
|
|
|
|
|
case RT_MESSAGETABLE: s = "messagetable"; break;
|
|
|
|
|
case RT_GROUP_CURSOR: s = "group cursor"; break;
|
|
|
|
|
case RT_GROUP_ICON: s = "group icon"; break;
|
|
|
|
|
case RT_VERSION: s = "version"; break;
|
|
|
|
|
case RT_DLGINCLUDE: s = "dlginclude"; break;
|
|
|
|
|
case RT_PLUGPLAY: s = "plugplay"; break;
|
|
|
|
|
case RT_VXD: s = "vxd"; break;
|
|
|
|
|
case RT_ANICURSOR: s = "anicursor"; break;
|
|
|
|
|
case RT_ANIICON: s = "aniicon"; break;
|
|
|
|
|
default: s = NULL; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (s != NULL)
|
|
|
|
|
fprintf (e, "%s", s);
|
|
|
|
|
else
|
|
|
|
|
res_id_print (e, re->id, 1);
|
|
|
|
|
}
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
fprintf (e, "// Name: ");
|
|
|
|
|
res_id_print (e, re->id, 1);
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
|
fprintf (e, "// Language: ");
|
|
|
|
|
res_id_print (e, re->id, 1);
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf (e, "// Level %d: ", level);
|
|
|
|
|
res_id_print (e, re->id, 1);
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_rc_directory (e, re->u.dir, type, name, language, level + 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out a single resource. E is the file to write to. TYPE is a
|
|
|
|
|
pointer to the type of the resource. NAME is a pointer to the name
|
|
|
|
|
of the resource; it will be NULL if there is a level mismatch. RES
|
|
|
|
|
is the resource data. LANGUAGE is a pointer to the current
|
|
|
|
|
language. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_resource (e, type, name, res, language)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct res_id *type;
|
|
|
|
|
const struct res_id *name;
|
|
|
|
|
const struct res_resource *res;
|
|
|
|
|
int *language;
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
int rt;
|
|
|
|
|
int menuex = 0;
|
|
|
|
|
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
|
|
|
|
|
switch (res->type)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_ACCELERATOR:
|
|
|
|
|
s = "ACCELERATOR";
|
|
|
|
|
rt = RT_ACCELERATORS;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_BITMAP:
|
|
|
|
|
s = "BITMAP";
|
|
|
|
|
rt = RT_BITMAP;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_CURSOR:
|
|
|
|
|
s = "CURSOR";
|
|
|
|
|
rt = RT_CURSOR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_GROUP_CURSOR:
|
|
|
|
|
s = "GROUP_CURSOR";
|
|
|
|
|
rt = RT_GROUP_CURSOR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_DIALOG:
|
|
|
|
|
if (extended_dialog (res->u.dialog))
|
|
|
|
|
s = "DIALOGEX";
|
|
|
|
|
else
|
|
|
|
|
s = "DIALOG";
|
|
|
|
|
rt = RT_DIALOG;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_FONT:
|
|
|
|
|
s = "FONT";
|
|
|
|
|
rt = RT_FONT;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_FONTDIR:
|
|
|
|
|
s = "FONTDIR";
|
|
|
|
|
rt = RT_FONTDIR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_ICON:
|
|
|
|
|
s = "ICON";
|
|
|
|
|
rt = RT_ICON;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_GROUP_ICON:
|
|
|
|
|
s = "GROUP_ICON";
|
|
|
|
|
rt = RT_GROUP_ICON;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_MENU:
|
|
|
|
|
if (extended_menu (res->u.menu))
|
|
|
|
|
{
|
|
|
|
|
s = "MENUEX";
|
|
|
|
|
menuex = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
s = "MENU";
|
|
|
|
|
menuex = 0;
|
|
|
|
|
}
|
|
|
|
|
rt = RT_MENU;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_MESSAGETABLE:
|
|
|
|
|
s = "MESSAGETABLE";
|
|
|
|
|
rt = RT_MESSAGETABLE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_RCDATA:
|
|
|
|
|
s = "RCDATA";
|
|
|
|
|
rt = RT_RCDATA;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_STRINGTABLE:
|
|
|
|
|
s = "STRINGTABLE";
|
|
|
|
|
rt = RT_STRING;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_USERDATA:
|
|
|
|
|
s = NULL;
|
|
|
|
|
rt = 0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_VERSIONINFO:
|
|
|
|
|
s = "VERSIONINFO";
|
|
|
|
|
rt = RT_VERSION;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rt != 0
|
|
|
|
|
&& type != NULL
|
|
|
|
|
&& (type->named || type->u.id != rt))
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// Unexpected resource type mismatch: ");
|
|
|
|
|
res_id_print (e, *type, 1);
|
|
|
|
|
fprintf (e, " != %d", rt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res->coff_info.codepage != 0)
|
|
|
|
|
fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
|
|
|
|
|
if (res->coff_info.reserved != 0)
|
|
|
|
|
fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
|
|
|
|
|
|
|
|
|
|
if (name != NULL)
|
|
|
|
|
res_id_print (e, *name, 0);
|
|
|
|
|
else
|
|
|
|
|
fprintf (e, "??Unknown-Name??");
|
|
|
|
|
|
|
|
|
|
fprintf (e, " ");
|
|
|
|
|
if (s != NULL)
|
|
|
|
|
fprintf (e, "%s", s);
|
|
|
|
|
else if (type != NULL)
|
|
|
|
|
res_id_print (e, *type, 0);
|
|
|
|
|
else
|
|
|
|
|
fprintf (e, "??Unknown-Type??");
|
|
|
|
|
|
|
|
|
|
if (res->res_info.memflags != 0)
|
|
|
|
|
{
|
|
|
|
|
if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
|
|
|
|
|
fprintf (e, " MOVEABLE");
|
|
|
|
|
if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
|
|
|
|
|
fprintf (e, " PURE");
|
|
|
|
|
if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
|
|
|
|
|
fprintf (e, " PRELOAD");
|
|
|
|
|
if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
|
|
|
|
|
fprintf (e, " DISCARDABLE");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res->type == RES_TYPE_DIALOG)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
|
|
|
|
|
res->u.dialog->width, res->u.dialog->height);
|
|
|
|
|
if (res->u.dialog->ex != NULL
|
|
|
|
|
&& res->u.dialog->ex->help != 0)
|
|
|
|
|
fprintf (e, ", %lu", res->u.dialog->ex->help);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
|
|
|
|
|
if ((res->res_info.language != 0 && res->res_info.language != *language)
|
|
|
|
|
|| res->res_info.characteristics != 0
|
|
|
|
|
|| res->res_info.version != 0)
|
|
|
|
|
{
|
|
|
|
|
int modifiers;
|
|
|
|
|
|
|
|
|
|
switch (res->type)
|
|
|
|
|
{
|
|
|
|
|
case RES_TYPE_ACCELERATOR:
|
|
|
|
|
case RES_TYPE_DIALOG:
|
|
|
|
|
case RES_TYPE_MENU:
|
|
|
|
|
case RES_TYPE_RCDATA:
|
|
|
|
|
case RES_TYPE_STRINGTABLE:
|
|
|
|
|
modifiers = 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
modifiers = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (res->res_info.language != 0 && res->res_info.language != *language)
|
|
|
|
|
fprintf (e, "%sLANGUAGE %d, %d\n",
|
|
|
|
|
modifiers ? "// " : "",
|
|
|
|
|
res->res_info.language & 0xff,
|
|
|
|
|
(res->res_info.language >> 8) & 0xff);
|
|
|
|
|
if (res->res_info.characteristics != 0)
|
|
|
|
|
fprintf (e, "%sCHARACTERISTICS %lu\n",
|
|
|
|
|
modifiers ? "// " : "",
|
|
|
|
|
res->res_info.characteristics);
|
|
|
|
|
if (res->res_info.version != 0)
|
|
|
|
|
fprintf (e, "%sVERSION %lu\n",
|
|
|
|
|
modifiers ? "// " : "",
|
|
|
|
|
res->res_info.version);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (res->type)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_ACCELERATOR:
|
|
|
|
|
write_rc_accelerators (e, res->u.acc);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_CURSOR:
|
|
|
|
|
write_rc_cursor (e, res->u.cursor);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_GROUP_CURSOR:
|
|
|
|
|
write_rc_group_cursor (e, res->u.group_cursor);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_DIALOG:
|
|
|
|
|
write_rc_dialog (e, res->u.dialog);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_FONTDIR:
|
|
|
|
|
write_rc_fontdir (e, res->u.fontdir);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_GROUP_ICON:
|
|
|
|
|
write_rc_group_icon (e, res->u.group_icon);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_MENU:
|
|
|
|
|
write_rc_menu (e, res->u.menu, menuex, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_RCDATA:
|
|
|
|
|
write_rc_rcdata (e, res->u.rcdata, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_STRINGTABLE:
|
|
|
|
|
write_rc_stringtable (e, name, res->u.stringtable);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_USERDATA:
|
|
|
|
|
write_rc_rcdata (e, res->u.userdata, 0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_VERSIONINFO:
|
|
|
|
|
write_rc_versioninfo (e, res->u.versioninfo);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RES_TYPE_BITMAP:
|
|
|
|
|
case RES_TYPE_FONT:
|
|
|
|
|
case RES_TYPE_ICON:
|
|
|
|
|
case RES_TYPE_MESSAGETABLE:
|
|
|
|
|
write_rc_filedata (e, res->u.data.length, res->u.data.data);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out accelerator information. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_accelerators (e, accelerators)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct accelerator *accelerators;
|
|
|
|
|
{
|
|
|
|
|
const struct accelerator *acc;
|
|
|
|
|
|
|
|
|
|
fprintf (e, "BEGIN\n");
|
|
|
|
|
for (acc = accelerators; acc != NULL; acc = acc->next)
|
|
|
|
|
{
|
|
|
|
|
int printable;
|
|
|
|
|
|
|
|
|
|
fprintf (e, " ");
|
|
|
|
|
|
|
|
|
|
if ((acc->key & 0x7f) == acc->key
|
|
|
|
|
&& isprint ((unsigned char) acc->key)
|
|
|
|
|
&& (acc->flags & ACC_VIRTKEY) == 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "\"%c\"", acc->key);
|
|
|
|
|
printable = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "%d", acc->key);
|
|
|
|
|
printable = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, ", %d", acc->id);
|
|
|
|
|
|
|
|
|
|
if (! printable)
|
|
|
|
|
{
|
|
|
|
|
if ((acc->flags & ACC_VIRTKEY) != 0)
|
|
|
|
|
fprintf (e, ", VIRTKEY");
|
|
|
|
|
else
|
|
|
|
|
fprintf (e, ", ASCII");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((acc->flags & ACC_SHIFT) != 0)
|
|
|
|
|
fprintf (e, ", SHIFT");
|
|
|
|
|
if ((acc->flags & ACC_CONTROL) != 0)
|
|
|
|
|
fprintf (e, ", CONTROL");
|
|
|
|
|
if ((acc->flags & ACC_ALT) != 0)
|
|
|
|
|
fprintf (e, ", ALT");
|
|
|
|
|
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "END\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out cursor information. This would normally be in a separate
|
|
|
|
|
file, which the rc file would include. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_cursor (e, cursor)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct cursor *cursor;
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
|
|
|
|
|
cursor->yhotspot);
|
|
|
|
|
write_rc_filedata (e, cursor->length, cursor->data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out group cursor data. This would normally be built from the
|
|
|
|
|
cursor data. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_group_cursor (e, group_cursor)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct group_cursor *group_cursor;
|
|
|
|
|
{
|
|
|
|
|
const struct group_cursor *gc;
|
|
|
|
|
|
|
|
|
|
for (gc = group_cursor; gc != NULL; gc = gc->next)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
|
|
|
|
|
gc->width, gc->height, gc->planes, gc->bits);
|
|
|
|
|
fprintf (e, "// data bytes: %lu; index: %d\n",
|
|
|
|
|
gc->bytes, gc->index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write dialog data. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_dialog (e, dialog)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct dialog *dialog;
|
|
|
|
|
{
|
|
|
|
|
const struct dialog_control *control;
|
|
|
|
|
|
|
|
|
|
if (dialog->style != 0)
|
|
|
|
|
fprintf (e, "STYLE 0x%lx\n", dialog->style);
|
|
|
|
|
if (dialog->exstyle != 0)
|
|
|
|
|
fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
|
|
|
|
|
if (dialog->class.named || dialog->class.u.id != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "CLASS ");
|
|
|
|
|
res_id_print (e, dialog->class, 0);
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
}
|
|
|
|
|
if (dialog->caption != NULL)
|
|
|
|
|
fprintf (e, "CAPTION \"%s\"\n", dialog->caption);
|
|
|
|
|
if (dialog->menu.named || dialog->menu.u.id != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "MENU ");
|
|
|
|
|
res_id_print (e, dialog->menu, 0);
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
}
|
|
|
|
|
if (dialog->font != NULL)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "FONT %d, \"%s\"", dialog->pointsize, dialog->font);
|
|
|
|
|
if (dialog->ex != NULL
|
|
|
|
|
&& (dialog->ex->weight != 0 || dialog->ex->italic != 0))
|
|
|
|
|
fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "BEGIN\n");
|
|
|
|
|
|
|
|
|
|
for (control = dialog->controls; control != NULL; control = control->next)
|
|
|
|
|
write_rc_dialog_control (e, control);
|
|
|
|
|
|
|
|
|
|
fprintf (e, "END\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* For each predefined control keyword, this table provides the class
|
|
|
|
|
and the style. */
|
|
|
|
|
|
|
|
|
|
struct control_info
|
|
|
|
|
{
|
|
|
|
|
const char *name;
|
|
|
|
|
unsigned short class;
|
|
|
|
|
unsigned long style;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct control_info control_info[] =
|
|
|
|
|
{
|
|
|
|
|
{ "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
|
|
|
|
|
{ "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
|
|
|
|
|
{ "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
|
|
|
|
|
{ "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
|
|
|
|
|
{ "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
|
|
|
|
|
{ "CTEXT", CTL_STATIC, SS_CENTER },
|
|
|
|
|
{ "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
|
|
|
|
|
{ "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
|
|
|
|
|
{ "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
|
|
|
|
|
{ "ICON", CTL_STATIC, SS_ICON },
|
|
|
|
|
{ "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
|
|
|
|
|
{ "LTEXT", CTL_STATIC, SS_LEFT },
|
|
|
|
|
{ "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
|
|
|
|
|
{ "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
|
|
|
|
|
{ "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
|
|
|
|
|
{ "RTEXT", CTL_STATIC, SS_RIGHT },
|
|
|
|
|
{ "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
|
|
|
|
|
{ "STATE3", CTL_BUTTON, BS_3STATE },
|
|
|
|
|
/* It's important that USERBUTTON come after all the other button
|
|
|
|
|
types, so that it won't be matched too early. */
|
|
|
|
|
{ "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
|
|
|
|
|
{ NULL, 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Write a dialog control. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_dialog_control (e, control)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct dialog_control *control;
|
|
|
|
|
{
|
|
|
|
|
const struct control_info *ci;
|
|
|
|
|
|
|
|
|
|
fprintf (e, " ");
|
|
|
|
|
|
|
|
|
|
if (control->class.named)
|
|
|
|
|
ci = NULL;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for (ci = control_info; ci->name != NULL; ++ci)
|
|
|
|
|
if (ci->class == control->class.u.id
|
|
|
|
|
&& (ci->style == (unsigned long) -1
|
|
|
|
|
|| ci->style == (control->style & 0xff)))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ci->name != NULL)
|
|
|
|
|
fprintf (e, "%s", ci->name);
|
|
|
|
|
else
|
|
|
|
|
fprintf (e, "CONTROL");
|
|
|
|
|
|
|
|
|
|
if (control->text.named || control->text.u.id != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, " ");
|
|
|
|
|
res_id_print (e, control->text, 1);
|
|
|
|
|
fprintf (e, ",");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, " %d, ", control->id);
|
|
|
|
|
|
|
|
|
|
if (ci->name == NULL)
|
|
|
|
|
{
|
|
|
|
|
res_id_print (e, control->class, 0);
|
|
|
|
|
fprintf (e, ", 0x%lx, ", control->style);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "%d, %d", control->x, control->y);
|
|
|
|
|
|
|
|
|
|
if (control->style != SS_ICON
|
|
|
|
|
|| control->exstyle != 0
|
|
|
|
|
|| control->width != 0
|
|
|
|
|
|| control->height != 0
|
|
|
|
|
|| control->help != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, ", %d, %d", control->width, control->height);
|
|
|
|
|
|
|
|
|
|
/* FIXME: We don't need to print the style if it is the default.
|
|
|
|
|
More importantly, in certain cases we actually need to turn
|
|
|
|
|
off parts of the forced style, by using NOT. */
|
|
|
|
|
fprintf (e, ", 0x%lx", control->style);
|
|
|
|
|
|
|
|
|
|
if (control->exstyle != 0 || control->help != 0)
|
|
|
|
|
fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
|
|
|
|
|
if (control->data != NULL)
|
|
|
|
|
write_rc_rcdata (e, control->data, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out font directory data. This would normally be built from
|
|
|
|
|
the font data. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_fontdir (e, fontdir)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct fontdir *fontdir;
|
|
|
|
|
{
|
|
|
|
|
const struct fontdir *fc;
|
|
|
|
|
|
|
|
|
|
for (fc = fontdir; fc != NULL; fc = fc->next)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// Font index: %d\n", fc->index);
|
|
|
|
|
write_rc_filedata (e, fc->length, fc->data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out group icon data. This would normally be built from the
|
|
|
|
|
icon data. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_group_icon (e, group_icon)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct group_icon *group_icon;
|
|
|
|
|
{
|
|
|
|
|
const struct group_icon *gi;
|
|
|
|
|
|
|
|
|
|
for (gi = group_icon; gi != NULL; gi = gi->next)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
|
|
|
|
|
gi->width, gi->height, gi->colors, gi->planes, gi->bits);
|
|
|
|
|
fprintf (e, "// data bytes: %lu; index: %d\n",
|
|
|
|
|
gi->bytes, gi->index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out a menu resource. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_menu (e, menuitems, menuex, ind)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct menuitem *menuitems;
|
|
|
|
|
int menuex;
|
|
|
|
|
int ind;
|
|
|
|
|
{
|
|
|
|
|
const struct menuitem *mi;
|
|
|
|
|
|
|
|
|
|
indent (e, ind);
|
|
|
|
|
fprintf (e, "BEGIN\n");
|
|
|
|
|
|
|
|
|
|
for (mi = menuitems; mi != NULL; mi = mi->next)
|
|
|
|
|
{
|
|
|
|
|
indent (e, ind + 2);
|
|
|
|
|
|
|
|
|
|
if (mi->popup == NULL)
|
|
|
|
|
fprintf (e, "MENUITEM");
|
|
|
|
|
else
|
|
|
|
|
fprintf (e, "POPUP");
|
|
|
|
|
|
|
|
|
|
if (! menuex
|
|
|
|
|
&& mi->popup == NULL
|
|
|
|
|
&& mi->text == NULL
|
|
|
|
|
&& mi->type == 0
|
|
|
|
|
&& mi->id == 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, " SEPARATOR\n");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mi->text == NULL)
|
|
|
|
|
fprintf (e, " \"\"");
|
|
|
|
|
else
|
|
|
|
|
fprintf (e, " \"%s\"", mi->text);
|
|
|
|
|
|
|
|
|
|
if (! menuex)
|
|
|
|
|
{
|
|
|
|
|
if (mi->popup == NULL)
|
|
|
|
|
fprintf (e, ", %d", mi->id);
|
|
|
|
|
|
|
|
|
|
if ((mi->type & MENUITEM_CHECKED) != 0)
|
|
|
|
|
fprintf (e, ", CHECKED");
|
|
|
|
|
if ((mi->type & MENUITEM_GRAYED) != 0)
|
|
|
|
|
fprintf (e, ", GRAYED");
|
|
|
|
|
if ((mi->type & MENUITEM_HELP) != 0)
|
|
|
|
|
fprintf (e, ", HELP");
|
|
|
|
|
if ((mi->type & MENUITEM_INACTIVE) != 0)
|
|
|
|
|
fprintf (e, ", INACTIVE");
|
|
|
|
|
if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
|
|
|
|
|
fprintf (e, ", MENUBARBREAK");
|
|
|
|
|
if ((mi->type & MENUITEM_MENUBREAK) != 0)
|
|
|
|
|
fprintf (e, ", MENUBREAK");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, ", %d", mi->id);
|
|
|
|
|
if (mi->type != 0 || mi->state != 0 || mi->help != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, ", %lu", mi->type);
|
|
|
|
|
if (mi->state != 0 || mi->help != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, ", %lu", mi->state);
|
|
|
|
|
if (mi->help != 0)
|
|
|
|
|
fprintf (e, ", %lu", mi->help);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
|
|
|
|
|
if (mi->popup != NULL)
|
|
|
|
|
write_rc_menu (e, mi->popup, menuex, ind + 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
indent (e, ind);
|
|
|
|
|
fprintf (e, "END\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out an rcdata resource. This is also used for other types of
|
|
|
|
|
resources that need to print arbitrary data. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_rcdata (e, rcdata, ind)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct rcdata_data *rcdata;
|
|
|
|
|
int ind;
|
|
|
|
|
{
|
|
|
|
|
const struct rcdata_item *ri;
|
|
|
|
|
|
|
|
|
|
indent (e, ind);
|
|
|
|
|
fprintf (e, "BEGIN\n");
|
|
|
|
|
|
|
|
|
|
for (ri = rcdata->first; ri != NULL; ri = ri->next)
|
|
|
|
|
{
|
|
|
|
|
if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
indent (e, ind + 2);
|
|
|
|
|
|
|
|
|
|
switch (ri->type)
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
abort ();
|
|
|
|
|
|
|
|
|
|
case RCDATA_WORD:
|
|
|
|
|
fprintf (e, "%d", ri->u.word);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RCDATA_DWORD:
|
|
|
|
|
fprintf (e, "%luL", ri->u.dword);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RCDATA_STRING:
|
|
|
|
|
fprintf (e, "\"%s\"", ri->u.string);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RCDATA_WSTRING:
|
|
|
|
|
fprintf (e, "L\"");
|
|
|
|
|
unicode_print (e, ri->u.wstring, -1);
|
|
|
|
|
fprintf (e, "\"");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RCDATA_BUFFER:
|
|
|
|
|
{
|
|
|
|
|
unsigned long i;
|
|
|
|
|
int first;
|
|
|
|
|
|
|
|
|
|
/* Assume little endian data. */
|
|
|
|
|
|
|
|
|
|
first = 1;
|
|
|
|
|
for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
|
|
|
|
|
{
|
|
|
|
|
unsigned long l;
|
|
|
|
|
|
|
|
|
|
l = ((((((ri->u.buffer.data[i + 3] << 8)
|
|
|
|
|
| ri->u.buffer.data[i + 2]) << 8)
|
|
|
|
|
| ri->u.buffer.data[i + 1]) << 8)
|
|
|
|
|
| ri->u.buffer.data[i]);
|
|
|
|
|
if (first)
|
|
|
|
|
first = 0;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, ",\n");
|
1997-06-23 08:08:54 +08:00
|
|
|
|
indent (e, ind + 2);
|
1997-06-23 05:35:35 +08:00
|
|
|
|
}
|
|
|
|
|
fprintf (e, "%luL", l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i + 1 < ri->u.buffer.length)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
i = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
|
|
|
|
|
if (first)
|
|
|
|
|
first = 0;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, ",\n");
|
1997-06-23 08:08:54 +08:00
|
|
|
|
indent (e, ind + 2);
|
1997-06-23 05:35:35 +08:00
|
|
|
|
}
|
|
|
|
|
fprintf (e, "%d", i);
|
|
|
|
|
i += 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i < ri->u.buffer.length)
|
|
|
|
|
{
|
|
|
|
|
if (first)
|
|
|
|
|
first = 0;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, ",\n");
|
1997-06-23 08:08:54 +08:00
|
|
|
|
indent (e, ind + 2);
|
1997-06-23 05:35:35 +08:00
|
|
|
|
}
|
|
|
|
|
if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
|
|
|
|
|
&& isprint (ri->u.buffer.data[i]))
|
|
|
|
|
fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
|
|
|
|
|
else
|
|
|
|
|
fprintf (e, "\"\%03o\"", ri->u.buffer.data[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ri->next != NULL)
|
|
|
|
|
fprintf (e, ",");
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
indent (e, ind);
|
|
|
|
|
fprintf (e, "END\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out a stringtable resource. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_stringtable (e, name, stringtable)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct res_id *name;
|
|
|
|
|
const struct stringtable *stringtable;
|
|
|
|
|
{
|
|
|
|
|
unsigned long offset;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (name != NULL && ! name->named)
|
|
|
|
|
offset = name->u.id << 4;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// %s string table name\n",
|
|
|
|
|
name == NULL ? "Missing" : "Invalid");
|
|
|
|
|
offset = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "BEGIN\n");
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < 16; i++)
|
|
|
|
|
{
|
|
|
|
|
if (stringtable->strings[i].length != 0)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, " %lu, \"", offset + i);
|
|
|
|
|
unicode_print (e, stringtable->strings[i].string,
|
|
|
|
|
stringtable->strings[i].length);
|
|
|
|
|
fprintf (e, "\"\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "END\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out a versioninfo resource. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_versioninfo (e, versioninfo)
|
|
|
|
|
FILE *e;
|
|
|
|
|
const struct versioninfo *versioninfo;
|
|
|
|
|
{
|
|
|
|
|
const struct fixed_versioninfo *f;
|
|
|
|
|
const struct ver_info *vi;
|
|
|
|
|
|
|
|
|
|
f = versioninfo->fixed;
|
|
|
|
|
if (f->file_version_ms != 0 || f->file_version_ls != 0)
|
|
|
|
|
fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
|
|
|
|
|
(f->file_version_ms >> 16) & 0xffff,
|
|
|
|
|
f->file_version_ms & 0xffff,
|
|
|
|
|
(f->file_version_ls >> 16) & 0xffff,
|
|
|
|
|
f->file_version_ls & 0xffff);
|
|
|
|
|
if (f->product_version_ms != 0 || f->product_version_ls != 0)
|
|
|
|
|
fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
|
|
|
|
|
(f->product_version_ms >> 16) & 0xffff,
|
|
|
|
|
f->product_version_ms & 0xffff,
|
|
|
|
|
(f->product_version_ls >> 16) & 0xffff,
|
|
|
|
|
f->product_version_ls & 0xffff);
|
|
|
|
|
if (f->file_flags_mask != 0)
|
|
|
|
|
fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
|
|
|
|
|
if (f->file_flags != 0)
|
|
|
|
|
fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
|
|
|
|
|
if (f->file_os != 0)
|
|
|
|
|
fprintf (e, " FILEOS 0x%lx\n", f->file_os);
|
|
|
|
|
if (f->file_type != 0)
|
|
|
|
|
fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
|
|
|
|
|
if (f->file_subtype != 0)
|
|
|
|
|
fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
|
|
|
|
|
if (f->file_date_ms != 0 || f->file_date_ls != 0)
|
|
|
|
|
fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
|
|
|
|
|
|
|
|
|
|
fprintf (e, "BEGIN\n");
|
|
|
|
|
|
|
|
|
|
for (vi = versioninfo->var; vi != NULL; vi = vi->next)
|
|
|
|
|
{
|
|
|
|
|
switch (vi->type)
|
|
|
|
|
{
|
|
|
|
|
case VERINFO_STRING:
|
|
|
|
|
{
|
|
|
|
|
const struct ver_stringinfo *vs;
|
|
|
|
|
|
|
|
|
|
fprintf (e, " BLOCK \"StringFileInfo\"\n");
|
|
|
|
|
fprintf (e, " BEGIN\n");
|
|
|
|
|
fprintf (e, " BLOCK \"");
|
|
|
|
|
unicode_print (e, vi->u.string.language, -1);
|
|
|
|
|
fprintf (e, "\"\n");
|
|
|
|
|
fprintf (e, " BEGIN\n");
|
|
|
|
|
|
|
|
|
|
for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, " VALUE \"");
|
|
|
|
|
unicode_print (e, vs->key, -1);
|
|
|
|
|
fprintf (e, "\", \"");
|
|
|
|
|
unicode_print (e, vs->value, -1);
|
|
|
|
|
fprintf (e, "\"\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, " END\n");
|
|
|
|
|
fprintf (e, " END\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case VERINFO_VAR:
|
|
|
|
|
{
|
|
|
|
|
const struct ver_varinfo *vv;
|
|
|
|
|
|
|
|
|
|
fprintf (e, " BLOCK \"VarFileInfo\"\n");
|
|
|
|
|
fprintf (e, " BEGIN\n");
|
|
|
|
|
fprintf (e, " VALUE \"");
|
|
|
|
|
unicode_print (e, vi->u.var.key, -1);
|
|
|
|
|
fprintf (e, "\"");
|
|
|
|
|
|
|
|
|
|
for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
|
|
|
|
|
fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
|
|
|
|
|
vv->charset);
|
|
|
|
|
|
|
|
|
|
fprintf (e, "\n END\n");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf (e, "END\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out data which would normally be read from a file. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
write_rc_filedata (e, length, data)
|
|
|
|
|
FILE *e;
|
|
|
|
|
unsigned long length;
|
|
|
|
|
const unsigned char *data;
|
|
|
|
|
{
|
|
|
|
|
unsigned long i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i + 15 < length; i += 16)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// %4lx: ", i);
|
|
|
|
|
fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
|
|
|
|
|
data[i + 0], data[i + 1], data[i + 2], data[i + 3],
|
|
|
|
|
data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
|
|
|
|
|
fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
|
|
|
|
data[i + 8], data[i + 9], data[i + 10], data[i + 11],
|
|
|
|
|
data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (i < length)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, "// %4lx:", i);
|
|
|
|
|
while (i < length)
|
|
|
|
|
{
|
|
|
|
|
fprintf (e, " %02x", data[i]);
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
fprintf (e, "\n");
|
|
|
|
|
}
|
|
|
|
|
}
|