resrc.c revision 38889
138889Sjdp/* resrc.c -- read and write Windows rc files.
238889Sjdp   Copyright 1997, 1998 Free Software Foundation, Inc.
338889Sjdp   Written by Ian Lance Taylor, Cygnus Support.
438889Sjdp
538889Sjdp   This file is part of GNU Binutils.
638889Sjdp
738889Sjdp   This program is free software; you can redistribute it and/or modify
838889Sjdp   it under the terms of the GNU General Public License as published by
938889Sjdp   the Free Software Foundation; either version 2 of the License, or
1038889Sjdp   (at your option) any later version.
1138889Sjdp
1238889Sjdp   This program is distributed in the hope that it will be useful,
1338889Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1438889Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1538889Sjdp   GNU General Public License for more details.
1638889Sjdp
1738889Sjdp   You should have received a copy of the GNU General Public License
1838889Sjdp   along with this program; if not, write to the Free Software
1938889Sjdp   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
2038889Sjdp   02111-1307, USA.  */
2138889Sjdp
2238889Sjdp/* This file contains functions that read and write Windows rc files.
2338889Sjdp   These are text files that represent resources.  */
2438889Sjdp
2538889Sjdp#include "bfd.h"
2638889Sjdp#include "bucomm.h"
2738889Sjdp#include "libiberty.h"
2838889Sjdp#include "windres.h"
2938889Sjdp
3038889Sjdp#include <assert.h>
3138889Sjdp#include <ctype.h>
3238889Sjdp#include <sys/stat.h>
3338889Sjdp
3438889Sjdp#if defined (_WIN32) && ! defined (__CYGWIN32__)
3538889Sjdp#define popen _popen
3638889Sjdp#define pclose _pclose
3738889Sjdp#endif
3838889Sjdp
3938889Sjdp/* The default preprocessor.  */
4038889Sjdp
4138889Sjdp#define DEFAULT_PREPROCESSOR "gcc -E -xc-header -DRC_INVOKED"
4238889Sjdp
4338889Sjdp/* We read the directory entries in a cursor or icon file into
4438889Sjdp   instances of this structure.  */
4538889Sjdp
4638889Sjdpstruct icondir
4738889Sjdp{
4838889Sjdp  /* Width of image.  */
4938889Sjdp  unsigned char width;
5038889Sjdp  /* Height of image.  */
5138889Sjdp  unsigned char height;
5238889Sjdp  /* Number of colors in image.  */
5338889Sjdp  unsigned char colorcount;
5438889Sjdp  union
5538889Sjdp  {
5638889Sjdp    struct
5738889Sjdp    {
5838889Sjdp      /* Color planes.  */
5938889Sjdp      unsigned short planes;
6038889Sjdp      /* Bits per pixel.  */
6138889Sjdp      unsigned short bits;
6238889Sjdp    } icon;
6338889Sjdp    struct
6438889Sjdp    {
6538889Sjdp      /* X coordinate of hotspot.  */
6638889Sjdp      unsigned short xhotspot;
6738889Sjdp      /* Y coordinate of hotspot.  */
6838889Sjdp      unsigned short yhotspot;
6938889Sjdp    } cursor;
7038889Sjdp  } u;
7138889Sjdp  /* Bytes in image.  */
7238889Sjdp  unsigned long bytes;
7338889Sjdp  /* File offset of image.  */
7438889Sjdp  unsigned long offset;
7538889Sjdp};
7638889Sjdp
7738889Sjdp/* The name of the rc file we are reading.  */
7838889Sjdp
7938889Sjdpchar *rc_filename;
8038889Sjdp
8138889Sjdp/* The line number in the rc file.  */
8238889Sjdp
8338889Sjdpint rc_lineno;
8438889Sjdp
8538889Sjdp/* The pipe we are reading from, so that we can close it if we exit.  */
8638889Sjdp
8738889Sjdpstatic FILE *cpp_pipe;
8838889Sjdp
8938889Sjdp/* As we read the rc file, we attach information to this structure.  */
9038889Sjdp
9138889Sjdpstatic struct res_directory *resources;
9238889Sjdp
9338889Sjdp/* The number of cursor resources we have written out.  */
9438889Sjdp
9538889Sjdpstatic int cursors;
9638889Sjdp
9738889Sjdp/* The number of font resources we have written out.  */
9838889Sjdp
9938889Sjdpstatic int fonts;
10038889Sjdp
10138889Sjdp/* Font directory information.  */
10238889Sjdp
10338889Sjdpstruct fontdir *fontdirs;
10438889Sjdp
10538889Sjdp/* Resource info to use for fontdirs.  */
10638889Sjdp
10738889Sjdpstruct res_res_info fontdirs_resinfo;
10838889Sjdp
10938889Sjdp/* The number of icon resources we have written out.  */
11038889Sjdp
11138889Sjdpstatic int icons;
11238889Sjdp
11338889Sjdp/* Local functions.  */
11438889Sjdp
11538889Sjdpstatic void close_pipe PARAMS ((void));
11638889Sjdpstatic void unexpected_eof PARAMS ((const char *));
11738889Sjdpstatic int get_word PARAMS ((FILE *, const char *));
11838889Sjdpstatic unsigned long get_long PARAMS ((FILE *, const char *));
11938889Sjdpstatic void get_data
12038889Sjdp  PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
12138889Sjdpstatic void define_fontdirs PARAMS ((void));
12238889Sjdp
12338889Sjdp/* Read an rc file.  */
12438889Sjdp
12538889Sjdpstruct res_directory *
12638889Sjdpread_rc_file (filename, preprocessor, preprocargs, language)
12738889Sjdp     const char *filename;
12838889Sjdp     const char *preprocessor;
12938889Sjdp     const char *preprocargs;
13038889Sjdp     int language;
13138889Sjdp{
13238889Sjdp  char *cmd;
13338889Sjdp
13438889Sjdp  if (preprocessor == NULL)
13538889Sjdp    preprocessor = DEFAULT_PREPROCESSOR;
13638889Sjdp
13738889Sjdp  if (preprocargs == NULL)
13838889Sjdp    preprocargs = "";
13938889Sjdp  if (filename == NULL)
14038889Sjdp    filename = "-";
14138889Sjdp
14238889Sjdp  cmd = xmalloc (strlen (preprocessor)
14338889Sjdp		 + strlen (preprocargs)
14438889Sjdp		 + strlen (filename)
14538889Sjdp		 + 10);
14638889Sjdp  sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
14738889Sjdp
14838889Sjdp  cpp_pipe = popen (cmd, FOPEN_RT);
14938889Sjdp  if (cpp_pipe == NULL)
15038889Sjdp    fatal ("can't popen `%s': %s", cmd, strerror (errno));
15138889Sjdp  free (cmd);
15238889Sjdp
15338889Sjdp  xatexit (close_pipe);
15438889Sjdp
15538889Sjdp  rc_filename = xstrdup (filename);
15638889Sjdp  rc_lineno = 1;
15738889Sjdp  if (language != -1)
15838889Sjdp    rcparse_set_language (language);
15938889Sjdp  yyin = cpp_pipe;
16038889Sjdp  yyparse ();
16138889Sjdp
16238889Sjdp  if (pclose (cpp_pipe) != 0)
16338889Sjdp    fprintf (stderr, "%s: warning: preprocessor failed\n", program_name);
16438889Sjdp  cpp_pipe = NULL;
16538889Sjdp
16638889Sjdp  if (fontdirs != NULL)
16738889Sjdp    define_fontdirs ();
16838889Sjdp
16938889Sjdp  free (rc_filename);
17038889Sjdp  rc_filename = NULL;
17138889Sjdp
17238889Sjdp  return resources;
17338889Sjdp}
17438889Sjdp
17538889Sjdp/* Close the pipe if it is open.  This is called via xatexit.  */
17638889Sjdp
17738889Sjdpvoid
17838889Sjdpclose_pipe ()
17938889Sjdp{
18038889Sjdp  if (cpp_pipe != NULL)
18138889Sjdp    pclose (cpp_pipe);
18238889Sjdp}
18338889Sjdp
18438889Sjdp/* Report an error while reading an rc file.  */
18538889Sjdp
18638889Sjdpvoid
18738889Sjdpyyerror (msg)
18838889Sjdp     const char *msg;
18938889Sjdp{
19038889Sjdp  fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
19138889Sjdp}
19238889Sjdp
19338889Sjdp/* Issue a warning while reading an rc file.  */
19438889Sjdp
19538889Sjdpvoid
19638889Sjdprcparse_warning (msg)
19738889Sjdp     const char *msg;
19838889Sjdp{
19938889Sjdp  fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
20038889Sjdp}
20138889Sjdp
20238889Sjdp/* Die if we get an unexpected end of file.  */
20338889Sjdp
20438889Sjdpstatic void
20538889Sjdpunexpected_eof (msg)
20638889Sjdp     const char *msg;
20738889Sjdp{
20838889Sjdp  fatal ("%s: unexpected EOF", msg);
20938889Sjdp}
21038889Sjdp
21138889Sjdp/* Read a 16 bit word from a file.  The data is assumed to be little
21238889Sjdp   endian.  */
21338889Sjdp
21438889Sjdpstatic int
21538889Sjdpget_word (e, msg)
21638889Sjdp     FILE *e;
21738889Sjdp     const char *msg;
21838889Sjdp{
21938889Sjdp  int b1, b2;
22038889Sjdp
22138889Sjdp  b1 = getc (e);
22238889Sjdp  b2 = getc (e);
22338889Sjdp  if (feof (e))
22438889Sjdp    unexpected_eof (msg);
22538889Sjdp  return ((b2 & 0xff) << 8) | (b1 & 0xff);
22638889Sjdp}
22738889Sjdp
22838889Sjdp/* Read a 32 bit word from a file.  The data is assumed to be little
22938889Sjdp   endian.  */
23038889Sjdp
23138889Sjdpstatic unsigned long
23238889Sjdpget_long (e, msg)
23338889Sjdp     FILE *e;
23438889Sjdp     const char *msg;
23538889Sjdp{
23638889Sjdp  int b1, b2, b3, b4;
23738889Sjdp
23838889Sjdp  b1 = getc (e);
23938889Sjdp  b2 = getc (e);
24038889Sjdp  b3 = getc (e);
24138889Sjdp  b4 = getc (e);
24238889Sjdp  if (feof (e))
24338889Sjdp    unexpected_eof (msg);
24438889Sjdp  return (((((((b4 & 0xff) << 8)
24538889Sjdp	      | (b3 & 0xff)) << 8)
24638889Sjdp	    | (b2 & 0xff)) << 8)
24738889Sjdp	  | (b1 & 0xff));
24838889Sjdp}
24938889Sjdp
25038889Sjdp/* Read data from a file.  This is a wrapper to do error checking.  */
25138889Sjdp
25238889Sjdpstatic void
25338889Sjdpget_data (e, p, c, msg)
25438889Sjdp     FILE *e;
25538889Sjdp     unsigned char *p;
25638889Sjdp     unsigned long c;
25738889Sjdp     const char *msg;
25838889Sjdp{
25938889Sjdp  unsigned long got;
26038889Sjdp
26138889Sjdp  got = fread (p, 1, c, e);
26238889Sjdp  if (got == c)
26338889Sjdp    return;
26438889Sjdp
26538889Sjdp  fatal ("%s: read of %lu returned %lu", msg, c, got);
26638889Sjdp}
26738889Sjdp
26838889Sjdp/* Define an accelerator resource.  */
26938889Sjdp
27038889Sjdpvoid
27138889Sjdpdefine_accelerator (id, resinfo, data)
27238889Sjdp     struct res_id id;
27338889Sjdp     const struct res_res_info *resinfo;
27438889Sjdp     struct accelerator *data;
27538889Sjdp{
27638889Sjdp  struct res_resource *r;
27738889Sjdp
27838889Sjdp  r = define_standard_resource (&resources, RT_ACCELERATORS, id,
27938889Sjdp				resinfo->language, 0);
28038889Sjdp  r->type = RES_TYPE_ACCELERATOR;
28138889Sjdp  r->u.acc = data;
28238889Sjdp  r->res_info = *resinfo;
28338889Sjdp}
28438889Sjdp
28538889Sjdp/* Define a bitmap resource.  Bitmap data is stored in a file.  The
28638889Sjdp   first 14 bytes of the file are a standard header, which is not
28738889Sjdp   included in the resource data.  */
28838889Sjdp
28938889Sjdp#define BITMAP_SKIP (14)
29038889Sjdp
29138889Sjdpvoid
29238889Sjdpdefine_bitmap (id, resinfo, filename)
29338889Sjdp     struct res_id id;
29438889Sjdp     const struct res_res_info *resinfo;
29538889Sjdp     const char *filename;
29638889Sjdp{
29738889Sjdp  FILE *e;
29838889Sjdp  char *real_filename;
29938889Sjdp  struct stat s;
30038889Sjdp  unsigned char *data;
30138889Sjdp  int i;
30238889Sjdp  struct res_resource *r;
30338889Sjdp
30438889Sjdp  e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
30538889Sjdp
30638889Sjdp  if (stat (real_filename, &s) < 0)
30738889Sjdp    fatal ("stat failed on bitmap file `%s': %s", real_filename,
30838889Sjdp	   strerror (errno));
30938889Sjdp
31038889Sjdp  data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
31138889Sjdp
31238889Sjdp  for (i = 0; i < BITMAP_SKIP; i++)
31338889Sjdp    getc (e);
31438889Sjdp
31538889Sjdp  get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
31638889Sjdp
31738889Sjdp  fclose (e);
31838889Sjdp  free (real_filename);
31938889Sjdp
32038889Sjdp  r = define_standard_resource (&resources, RT_BITMAP, id,
32138889Sjdp				resinfo->language, 0);
32238889Sjdp
32338889Sjdp  r->type = RES_TYPE_BITMAP;
32438889Sjdp  r->u.data.length = s.st_size - BITMAP_SKIP;
32538889Sjdp  r->u.data.data = data;
32638889Sjdp  r->res_info = *resinfo;
32738889Sjdp}
32838889Sjdp
32938889Sjdp/* Define a cursor resource.  A cursor file may contain a set of
33038889Sjdp   bitmaps, each representing the same cursor at various different
33138889Sjdp   resolutions.  They each get written out with a different ID.  The
33238889Sjdp   real cursor resource is then a group resource which can be used to
33338889Sjdp   select one of the actual cursors.  */
33438889Sjdp
33538889Sjdpvoid
33638889Sjdpdefine_cursor (id, resinfo, filename)
33738889Sjdp     struct res_id id;
33838889Sjdp     const struct res_res_info *resinfo;
33938889Sjdp     const char *filename;
34038889Sjdp{
34138889Sjdp  FILE *e;
34238889Sjdp  char *real_filename;
34338889Sjdp  int type, count, i;
34438889Sjdp  struct icondir *icondirs;
34538889Sjdp  int first_cursor;
34638889Sjdp  struct res_resource *r;
34738889Sjdp  struct group_cursor *first, **pp;
34838889Sjdp
34938889Sjdp  e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
35038889Sjdp
35138889Sjdp  /* A cursor file is basically an icon file.  The start of the file
35238889Sjdp     is a three word structure.  The first word is ignored.  The
35338889Sjdp     second word is the type of data.  The third word is the number of
35438889Sjdp     entries.  */
35538889Sjdp
35638889Sjdp  get_word (e, real_filename);
35738889Sjdp  type = get_word (e, real_filename);
35838889Sjdp  count = get_word (e, real_filename);
35938889Sjdp  if (type != 2)
36038889Sjdp    fatal ("cursor file `%s' does not contain cursor data", real_filename);
36138889Sjdp
36238889Sjdp  /* Read in the icon directory entries.  */
36338889Sjdp
36438889Sjdp  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
36538889Sjdp
36638889Sjdp  for (i = 0; i < count; i++)
36738889Sjdp    {
36838889Sjdp      icondirs[i].width = getc (e);
36938889Sjdp      icondirs[i].height = getc (e);
37038889Sjdp      icondirs[i].colorcount = getc (e);
37138889Sjdp      getc (e);
37238889Sjdp      icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
37338889Sjdp      icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
37438889Sjdp      icondirs[i].bytes = get_long (e, real_filename);
37538889Sjdp      icondirs[i].offset = get_long (e, real_filename);
37638889Sjdp
37738889Sjdp      if (feof (e))
37838889Sjdp	unexpected_eof (real_filename);
37938889Sjdp    }
38038889Sjdp
38138889Sjdp  /* Define each cursor as a unique resource.  */
38238889Sjdp
38338889Sjdp  first_cursor = cursors;
38438889Sjdp
38538889Sjdp  for (i = 0; i < count; i++)
38638889Sjdp    {
38738889Sjdp      unsigned char *data;
38838889Sjdp      struct res_id name;
38938889Sjdp      struct cursor *c;
39038889Sjdp
39138889Sjdp      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
39238889Sjdp	fatal ("%s: fseek to %lu failed: %s", real_filename,
39338889Sjdp	       icondirs[i].offset, strerror (errno));
39438889Sjdp
39538889Sjdp      data = (unsigned char *) res_alloc (icondirs[i].bytes);
39638889Sjdp
39738889Sjdp      get_data (e, data, icondirs[i].bytes, real_filename);
39838889Sjdp
39938889Sjdp      c = (struct cursor *) res_alloc (sizeof *c);
40038889Sjdp      c->xhotspot = icondirs[i].u.cursor.xhotspot;
40138889Sjdp      c->yhotspot = icondirs[i].u.cursor.yhotspot;
40238889Sjdp      c->length = icondirs[i].bytes;
40338889Sjdp      c->data = data;
40438889Sjdp
40538889Sjdp      ++cursors;
40638889Sjdp
40738889Sjdp      name.named = 0;
40838889Sjdp      name.u.id = cursors;
40938889Sjdp
41038889Sjdp      r = define_standard_resource (&resources, RT_CURSOR, name,
41138889Sjdp				    resinfo->language, 0);
41238889Sjdp      r->type = RES_TYPE_CURSOR;
41338889Sjdp      r->u.cursor = c;
41438889Sjdp      r->res_info = *resinfo;
41538889Sjdp    }
41638889Sjdp
41738889Sjdp  fclose (e);
41838889Sjdp  free (real_filename);
41938889Sjdp
42038889Sjdp  /* Define a cursor group resource.  */
42138889Sjdp
42238889Sjdp  first = NULL;
42338889Sjdp  pp = &first;
42438889Sjdp  for (i = 0; i < count; i++)
42538889Sjdp    {
42638889Sjdp      struct group_cursor *cg;
42738889Sjdp
42838889Sjdp      cg = (struct group_cursor *) res_alloc (sizeof *cg);
42938889Sjdp      cg->next = NULL;
43038889Sjdp      cg->width = icondirs[i].width;
43138889Sjdp      cg->height = 2 * icondirs[i].height;
43238889Sjdp
43338889Sjdp      /* FIXME: What should these be set to?  */
43438889Sjdp      cg->planes = 1;
43538889Sjdp      cg->bits = 1;
43638889Sjdp
43738889Sjdp      cg->bytes = icondirs[i].bytes + 4;
43838889Sjdp      cg->index = first_cursor + i + 1;
43938889Sjdp
44038889Sjdp      *pp = cg;
44138889Sjdp      pp = &(*pp)->next;
44238889Sjdp    }
44338889Sjdp
44438889Sjdp  free (icondirs);
44538889Sjdp
44638889Sjdp  r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
44738889Sjdp				resinfo->language, 0);
44838889Sjdp  r->type = RES_TYPE_GROUP_CURSOR;
44938889Sjdp  r->u.group_cursor = first;
45038889Sjdp  r->res_info = *resinfo;
45138889Sjdp}
45238889Sjdp
45338889Sjdp/* Define a dialog resource.  */
45438889Sjdp
45538889Sjdpvoid
45638889Sjdpdefine_dialog (id, resinfo, dialog)
45738889Sjdp     struct res_id id;
45838889Sjdp     const struct res_res_info *resinfo;
45938889Sjdp     const struct dialog *dialog;
46038889Sjdp{
46138889Sjdp  struct dialog *copy;
46238889Sjdp  struct res_resource *r;
46338889Sjdp
46438889Sjdp  copy = (struct dialog *) res_alloc (sizeof *copy);
46538889Sjdp  *copy = *dialog;
46638889Sjdp
46738889Sjdp  r = define_standard_resource (&resources, RT_DIALOG, id,
46838889Sjdp				resinfo->language, 0);
46938889Sjdp  r->type = RES_TYPE_DIALOG;
47038889Sjdp  r->u.dialog = copy;
47138889Sjdp  r->res_info = *resinfo;
47238889Sjdp}
47338889Sjdp
47438889Sjdp/* Define a dialog control.  This does not define a resource, but
47538889Sjdp   merely allocates and fills in a structure.  */
47638889Sjdp
47738889Sjdpstruct dialog_control *
47838889Sjdpdefine_control (text, id, x, y, width, height, class, style, exstyle)
47938889Sjdp     const char *text;
48038889Sjdp     unsigned long id;
48138889Sjdp     unsigned long x;
48238889Sjdp     unsigned long y;
48338889Sjdp     unsigned long width;
48438889Sjdp     unsigned long height;
48538889Sjdp     unsigned long class;
48638889Sjdp     unsigned long style;
48738889Sjdp     unsigned long exstyle;
48838889Sjdp{
48938889Sjdp  struct dialog_control *n;
49038889Sjdp
49138889Sjdp  n = (struct dialog_control *) res_alloc (sizeof *n);
49238889Sjdp  n->next = NULL;
49338889Sjdp  n->id = id;
49438889Sjdp  n->style = style;
49538889Sjdp  n->exstyle = exstyle;
49638889Sjdp  n->x = x;
49738889Sjdp  n->y = y;
49838889Sjdp  n->width = width;
49938889Sjdp  n->height = height;
50038889Sjdp  n->class.named = 0;
50138889Sjdp  n->class.u.id = class;
50238889Sjdp  if (text != NULL)
50338889Sjdp    res_string_to_id (&n->text, text);
50438889Sjdp  else
50538889Sjdp    {
50638889Sjdp      n->text.named = 0;
50738889Sjdp      n->text.u.id = 0;
50838889Sjdp    }
50938889Sjdp  n->data = NULL;
51038889Sjdp  n->help = 0;
51138889Sjdp
51238889Sjdp  return n;
51338889Sjdp}
51438889Sjdp
51538889Sjdp/* Define a font resource.  */
51638889Sjdp
51738889Sjdpvoid
51838889Sjdpdefine_font (id, resinfo, filename)
51938889Sjdp     struct res_id id;
52038889Sjdp     const struct res_res_info *resinfo;
52138889Sjdp     const char *filename;
52238889Sjdp{
52338889Sjdp  FILE *e;
52438889Sjdp  char *real_filename;
52538889Sjdp  struct stat s;
52638889Sjdp  unsigned char *data;
52738889Sjdp  struct res_resource *r;
52838889Sjdp  long offset;
52938889Sjdp  long fontdatalength;
53038889Sjdp  unsigned char *fontdata;
53138889Sjdp  struct fontdir *fd;
53238889Sjdp  const char *device, *face;
53338889Sjdp  struct fontdir **pp;
53438889Sjdp
53538889Sjdp  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
53638889Sjdp
53738889Sjdp  if (stat (real_filename, &s) < 0)
53838889Sjdp    fatal ("stat failed on bitmap file `%s': %s", real_filename,
53938889Sjdp	   strerror (errno));
54038889Sjdp
54138889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
54238889Sjdp
54338889Sjdp  get_data (e, data, s.st_size, real_filename);
54438889Sjdp
54538889Sjdp  fclose (e);
54638889Sjdp  free (real_filename);
54738889Sjdp
54838889Sjdp  r = define_standard_resource (&resources, RT_FONT, id,
54938889Sjdp				resinfo->language, 0);
55038889Sjdp
55138889Sjdp  r->type = RES_TYPE_FONT;
55238889Sjdp  r->u.data.length = s.st_size;
55338889Sjdp  r->u.data.data = data;
55438889Sjdp  r->res_info = *resinfo;
55538889Sjdp
55638889Sjdp  /* For each font resource, we must add an entry in the FONTDIR
55738889Sjdp     resource.  The FONTDIR resource includes some strings in the font
55838889Sjdp     file.  To find them, we have to do some magic on the data we have
55938889Sjdp     read.  */
56038889Sjdp
56138889Sjdp  offset = ((((((data[47] << 8)
56238889Sjdp		| data[46]) << 8)
56338889Sjdp	      | data[45]) << 8)
56438889Sjdp	    | data[44]);
56538889Sjdp  if (offset > 0 && offset < s.st_size)
56638889Sjdp    device = (char *) data + offset;
56738889Sjdp  else
56838889Sjdp    device = "";
56938889Sjdp
57038889Sjdp  offset = ((((((data[51] << 8)
57138889Sjdp		| data[50]) << 8)
57238889Sjdp	      | data[49]) << 8)
57338889Sjdp	    | data[48]);
57438889Sjdp  if (offset > 0 && offset < s.st_size)
57538889Sjdp    face = (char *) data + offset;
57638889Sjdp  else
57738889Sjdp    face = "";
57838889Sjdp
57938889Sjdp  ++fonts;
58038889Sjdp
58138889Sjdp  fontdatalength = 58 + strlen (device) + strlen (face);
58238889Sjdp  fontdata = (unsigned char *) res_alloc (fontdatalength);
58338889Sjdp  memcpy (fontdata, data, 56);
58438889Sjdp  strcpy ((char *) fontdata + 56, device);
58538889Sjdp  strcpy ((char *) fontdata + 57 + strlen (device), face);
58638889Sjdp
58738889Sjdp  fd = (struct fontdir *) res_alloc (sizeof *fd);
58838889Sjdp  fd->next = NULL;
58938889Sjdp  fd->index = fonts;
59038889Sjdp  fd->length = fontdatalength;
59138889Sjdp  fd->data = fontdata;
59238889Sjdp
59338889Sjdp  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
59438889Sjdp    ;
59538889Sjdp  *pp = fd;
59638889Sjdp
59738889Sjdp  /* For the single fontdirs resource, we always use the resource
59838889Sjdp     information of the last font.  I don't know what else to do.  */
59938889Sjdp  fontdirs_resinfo = *resinfo;
60038889Sjdp}
60138889Sjdp
60238889Sjdp/* Define the fontdirs resource.  This is called after the entire rc
60338889Sjdp   file has been parsed, if any font resources were seen.  */
60438889Sjdp
60538889Sjdpstatic void
60638889Sjdpdefine_fontdirs ()
60738889Sjdp{
60838889Sjdp  struct res_resource *r;
60938889Sjdp  struct res_id id;
61038889Sjdp
61138889Sjdp  id.named = 0;
61238889Sjdp  id.u.id = 1;
61338889Sjdp
61438889Sjdp  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
61538889Sjdp
61638889Sjdp  r->type = RES_TYPE_FONTDIR;
61738889Sjdp  r->u.fontdir = fontdirs;
61838889Sjdp  r->res_info = fontdirs_resinfo;
61938889Sjdp}
62038889Sjdp
62138889Sjdp/* Define an icon resource.  An icon file may contain a set of
62238889Sjdp   bitmaps, each representing the same icon at various different
62338889Sjdp   resolutions.  They each get written out with a different ID.  The
62438889Sjdp   real icon resource is then a group resource which can be used to
62538889Sjdp   select one of the actual icon bitmaps.  */
62638889Sjdp
62738889Sjdpvoid
62838889Sjdpdefine_icon (id, resinfo, filename)
62938889Sjdp     struct res_id id;
63038889Sjdp     const struct res_res_info *resinfo;
63138889Sjdp     const char *filename;
63238889Sjdp{
63338889Sjdp  FILE *e;
63438889Sjdp  char *real_filename;
63538889Sjdp  int type, count, i;
63638889Sjdp  struct icondir *icondirs;
63738889Sjdp  int first_icon;
63838889Sjdp  struct res_resource *r;
63938889Sjdp  struct group_icon *first, **pp;
64038889Sjdp
64138889Sjdp  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
64238889Sjdp
64338889Sjdp  /* The start of an icon file is a three word structure.  The first
64438889Sjdp     word is ignored.  The second word is the type of data.  The third
64538889Sjdp     word is the number of entries.  */
64638889Sjdp
64738889Sjdp  get_word (e, real_filename);
64838889Sjdp  type = get_word (e, real_filename);
64938889Sjdp  count = get_word (e, real_filename);
65038889Sjdp  if (type != 1)
65138889Sjdp    fatal ("icon file `%s' does not contain icon data", real_filename);
65238889Sjdp
65338889Sjdp  /* Read in the icon directory entries.  */
65438889Sjdp
65538889Sjdp  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
65638889Sjdp
65738889Sjdp  for (i = 0; i < count; i++)
65838889Sjdp    {
65938889Sjdp      icondirs[i].width = getc (e);
66038889Sjdp      icondirs[i].height = getc (e);
66138889Sjdp      icondirs[i].colorcount = getc (e);
66238889Sjdp      getc (e);
66338889Sjdp      icondirs[i].u.icon.planes = get_word (e, real_filename);
66438889Sjdp      icondirs[i].u.icon.bits = get_word (e, real_filename);
66538889Sjdp      icondirs[i].bytes = get_long (e, real_filename);
66638889Sjdp      icondirs[i].offset = get_long (e, real_filename);
66738889Sjdp
66838889Sjdp      if (feof (e))
66938889Sjdp	unexpected_eof (real_filename);
67038889Sjdp    }
67138889Sjdp
67238889Sjdp  /* Define each icon as a unique resource.  */
67338889Sjdp
67438889Sjdp  first_icon = icons;
67538889Sjdp
67638889Sjdp  for (i = 0; i < count; i++)
67738889Sjdp    {
67838889Sjdp      unsigned char *data;
67938889Sjdp      struct res_id name;
68038889Sjdp
68138889Sjdp      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
68238889Sjdp	fatal ("%s: fseek to %lu failed: %s", real_filename,
68338889Sjdp	       icondirs[i].offset, strerror (errno));
68438889Sjdp
68538889Sjdp      data = (unsigned char *) res_alloc (icondirs[i].bytes);
68638889Sjdp
68738889Sjdp      get_data (e, data, icondirs[i].bytes, real_filename);
68838889Sjdp
68938889Sjdp      ++icons;
69038889Sjdp
69138889Sjdp      name.named = 0;
69238889Sjdp      name.u.id = icons;
69338889Sjdp
69438889Sjdp      r = define_standard_resource (&resources, RT_ICON, name,
69538889Sjdp				    resinfo->language, 0);
69638889Sjdp      r->type = RES_TYPE_ICON;
69738889Sjdp      r->u.data.length = icondirs[i].bytes;
69838889Sjdp      r->u.data.data = data;
69938889Sjdp      r->res_info = *resinfo;
70038889Sjdp    }
70138889Sjdp
70238889Sjdp  fclose (e);
70338889Sjdp  free (real_filename);
70438889Sjdp
70538889Sjdp  /* Define an icon group resource.  */
70638889Sjdp
70738889Sjdp  first = NULL;
70838889Sjdp  pp = &first;
70938889Sjdp  for (i = 0; i < count; i++)
71038889Sjdp    {
71138889Sjdp      struct group_icon *cg;
71238889Sjdp
71338889Sjdp      /* For some reason, at least in some files the planes and bits
71438889Sjdp         are zero.  We instead set them from the color.  This is
71538889Sjdp         copied from rcl.  */
71638889Sjdp
71738889Sjdp      cg = (struct group_icon *) res_alloc (sizeof *cg);
71838889Sjdp      cg->next = NULL;
71938889Sjdp      cg->width = icondirs[i].width;
72038889Sjdp      cg->height = icondirs[i].height;
72138889Sjdp      cg->colors = icondirs[i].colorcount;
72238889Sjdp
72338889Sjdp      cg->planes = 1;
72438889Sjdp      cg->bits = 0;
72538889Sjdp      while ((1 << cg->bits) < cg->colors)
72638889Sjdp	++cg->bits;
72738889Sjdp
72838889Sjdp      cg->bytes = icondirs[i].bytes;
72938889Sjdp      cg->index = first_icon + i + 1;
73038889Sjdp
73138889Sjdp      *pp = cg;
73238889Sjdp      pp = &(*pp)->next;
73338889Sjdp    }
73438889Sjdp
73538889Sjdp  free (icondirs);
73638889Sjdp
73738889Sjdp  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
73838889Sjdp				resinfo->language, 0);
73938889Sjdp  r->type = RES_TYPE_GROUP_ICON;
74038889Sjdp  r->u.group_icon = first;
74138889Sjdp  r->res_info = *resinfo;
74238889Sjdp}
74338889Sjdp
74438889Sjdp/* Define a menu resource.  */
74538889Sjdp
74638889Sjdpvoid
74738889Sjdpdefine_menu (id, resinfo, menuitems)
74838889Sjdp     struct res_id id;
74938889Sjdp     const struct res_res_info *resinfo;
75038889Sjdp     struct menuitem *menuitems;
75138889Sjdp{
75238889Sjdp  struct menu *m;
75338889Sjdp  struct res_resource *r;
75438889Sjdp
75538889Sjdp  m = (struct menu *) res_alloc (sizeof *m);
75638889Sjdp  m->items = menuitems;
75738889Sjdp  m->help = 0;
75838889Sjdp
75938889Sjdp  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
76038889Sjdp  r->type = RES_TYPE_MENU;
76138889Sjdp  r->u.menu = m;
76238889Sjdp  r->res_info = *resinfo;
76338889Sjdp}
76438889Sjdp
76538889Sjdp/* Define a menu item.  This does not define a resource, but merely
76638889Sjdp   allocates and fills in a structure.  */
76738889Sjdp
76838889Sjdpstruct menuitem *
76938889Sjdpdefine_menuitem (text, menuid, type, state, help, menuitems)
77038889Sjdp     const char *text;
77138889Sjdp     int menuid;
77238889Sjdp     unsigned long type;
77338889Sjdp     unsigned long state;
77438889Sjdp     unsigned long help;
77538889Sjdp     struct menuitem *menuitems;
77638889Sjdp{
77738889Sjdp  struct menuitem *mi;
77838889Sjdp
77938889Sjdp  mi = (struct menuitem *) res_alloc (sizeof *mi);
78038889Sjdp  mi->next = NULL;
78138889Sjdp  mi->type = type;
78238889Sjdp  mi->state = state;
78338889Sjdp  mi->id = menuid;
78438889Sjdp  if (text == NULL)
78538889Sjdp    mi->text = NULL;
78638889Sjdp  else
78738889Sjdp    unicode_from_ascii ((int *) NULL, &mi->text, text);
78838889Sjdp  mi->help = help;
78938889Sjdp  mi->popup = menuitems;
79038889Sjdp  return mi;
79138889Sjdp}
79238889Sjdp
79338889Sjdp/* Define a messagetable resource.  */
79438889Sjdp
79538889Sjdpvoid
79638889Sjdpdefine_messagetable (id, resinfo, filename)
79738889Sjdp     struct res_id id;
79838889Sjdp     const struct res_res_info *resinfo;
79938889Sjdp     const char *filename;
80038889Sjdp{
80138889Sjdp  FILE *e;
80238889Sjdp  char *real_filename;
80338889Sjdp  struct stat s;
80438889Sjdp  unsigned char *data;
80538889Sjdp  struct res_resource *r;
80638889Sjdp
80738889Sjdp  e = open_file_search (filename, FOPEN_RB, "messagetable file",
80838889Sjdp			&real_filename);
80938889Sjdp
81038889Sjdp  if (stat (real_filename, &s) < 0)
81138889Sjdp    fatal ("stat failed on bitmap file `%s': %s", real_filename,
81238889Sjdp	   strerror (errno));
81338889Sjdp
81438889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
81538889Sjdp
81638889Sjdp  get_data (e, data, s.st_size, real_filename);
81738889Sjdp
81838889Sjdp  fclose (e);
81938889Sjdp  free (real_filename);
82038889Sjdp
82138889Sjdp  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
82238889Sjdp				resinfo->language, 0);
82338889Sjdp
82438889Sjdp  r->type = RES_TYPE_MESSAGETABLE;
82538889Sjdp  r->u.data.length = s.st_size;
82638889Sjdp  r->u.data.data = data;
82738889Sjdp  r->res_info = *resinfo;
82838889Sjdp}
82938889Sjdp
83038889Sjdp/* Define an rcdata resource.  */
83138889Sjdp
83238889Sjdpvoid
83338889Sjdpdefine_rcdata (id, resinfo, data)
83438889Sjdp     struct res_id id;
83538889Sjdp     const struct res_res_info *resinfo;
83638889Sjdp     struct rcdata_item *data;
83738889Sjdp{
83838889Sjdp  struct res_resource *r;
83938889Sjdp
84038889Sjdp  r = define_standard_resource (&resources, RT_RCDATA, id,
84138889Sjdp				resinfo->language, 0);
84238889Sjdp  r->type = RES_TYPE_RCDATA;
84338889Sjdp  r->u.rcdata = data;
84438889Sjdp  r->res_info = *resinfo;
84538889Sjdp}
84638889Sjdp
84738889Sjdp/* Create an rcdata item holding a string.  */
84838889Sjdp
84938889Sjdpstruct rcdata_item *
85038889Sjdpdefine_rcdata_string (string, len)
85138889Sjdp     const char *string;
85238889Sjdp     unsigned long len;
85338889Sjdp{
85438889Sjdp  struct rcdata_item *ri;
85538889Sjdp  char *s;
85638889Sjdp
85738889Sjdp  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
85838889Sjdp  ri->next = NULL;
85938889Sjdp  ri->type = RCDATA_STRING;
86038889Sjdp  ri->u.string.length = len;
86138889Sjdp  s = (char *) res_alloc (len);
86238889Sjdp  memcpy (s, string, len);
86338889Sjdp  ri->u.string.s = s;
86438889Sjdp
86538889Sjdp  return ri;
86638889Sjdp}
86738889Sjdp
86838889Sjdp/* Create an rcdata item holding a number.  */
86938889Sjdp
87038889Sjdpstruct rcdata_item *
87138889Sjdpdefine_rcdata_number (val, dword)
87238889Sjdp     unsigned long val;
87338889Sjdp     int dword;
87438889Sjdp{
87538889Sjdp  struct rcdata_item *ri;
87638889Sjdp
87738889Sjdp  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
87838889Sjdp  ri->next = NULL;
87938889Sjdp  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
88038889Sjdp  ri->u.word = val;
88138889Sjdp
88238889Sjdp  return ri;
88338889Sjdp}
88438889Sjdp
88538889Sjdp/* Define a stringtable resource.  This is called for each string
88638889Sjdp   which appears in a STRINGTABLE statement.  */
88738889Sjdp
88838889Sjdpvoid
88938889Sjdpdefine_stringtable (resinfo, stringid, string)
89038889Sjdp     const struct res_res_info *resinfo;
89138889Sjdp     unsigned long stringid;
89238889Sjdp     const char *string;
89338889Sjdp{
89438889Sjdp  struct res_id id;
89538889Sjdp  struct res_resource *r;
89638889Sjdp
89738889Sjdp  id.named = 0;
89838889Sjdp  id.u.id = (stringid >> 4) + 1;
89938889Sjdp  r = define_standard_resource (&resources, RT_STRING, id,
90038889Sjdp				resinfo->language, 1);
90138889Sjdp
90238889Sjdp  if (r->type == RES_TYPE_UNINITIALIZED)
90338889Sjdp    {
90438889Sjdp      int i;
90538889Sjdp
90638889Sjdp      r->type = RES_TYPE_STRINGTABLE;
90738889Sjdp      r->u.stringtable = ((struct stringtable *)
90838889Sjdp			  res_alloc (sizeof (struct stringtable)));
90938889Sjdp      for (i = 0; i < 16; i++)
91038889Sjdp	{
91138889Sjdp	  r->u.stringtable->strings[i].length = 0;
91238889Sjdp	  r->u.stringtable->strings[i].string = NULL;
91338889Sjdp	}
91438889Sjdp
91538889Sjdp      r->res_info = *resinfo;
91638889Sjdp    }
91738889Sjdp
91838889Sjdp  unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
91938889Sjdp		      &r->u.stringtable->strings[stringid & 0xf].string,
92038889Sjdp		      string);
92138889Sjdp}
92238889Sjdp
92338889Sjdp/* Define a user data resource where the data is in the rc file.  */
92438889Sjdp
92538889Sjdpvoid
92638889Sjdpdefine_user_data (id, type, resinfo, data)
92738889Sjdp     struct res_id id;
92838889Sjdp     struct res_id type;
92938889Sjdp     const struct res_res_info *resinfo;
93038889Sjdp     struct rcdata_item *data;
93138889Sjdp{
93238889Sjdp  struct res_id ids[3];
93338889Sjdp  struct res_resource *r;
93438889Sjdp
93538889Sjdp  ids[0] = type;
93638889Sjdp  ids[1] = id;
93738889Sjdp  ids[2].named = 0;
93838889Sjdp  ids[2].u.id = resinfo->language;
93938889Sjdp
94038889Sjdp  r = define_resource (&resources, 3, ids, 0);
94138889Sjdp  r->type = RES_TYPE_USERDATA;
94238889Sjdp  r->u.userdata = data;
94338889Sjdp  r->res_info = *resinfo;
94438889Sjdp}
94538889Sjdp
94638889Sjdp/* Define a user data resource where the data is in a file.  */
94738889Sjdp
94838889Sjdpvoid
94938889Sjdpdefine_user_file (id, type, resinfo, filename)
95038889Sjdp     struct res_id id;
95138889Sjdp     struct res_id type;
95238889Sjdp     const struct res_res_info *resinfo;
95338889Sjdp     const char *filename;
95438889Sjdp{
95538889Sjdp  FILE *e;
95638889Sjdp  char *real_filename;
95738889Sjdp  struct stat s;
95838889Sjdp  unsigned char *data;
95938889Sjdp  struct res_id ids[3];
96038889Sjdp  struct res_resource *r;
96138889Sjdp
96238889Sjdp  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
96338889Sjdp
96438889Sjdp  if (stat (real_filename, &s) < 0)
96538889Sjdp    fatal ("stat failed on bitmap file `%s': %s", real_filename,
96638889Sjdp	   strerror (errno));
96738889Sjdp
96838889Sjdp  data = (unsigned char *) res_alloc (s.st_size);
96938889Sjdp
97038889Sjdp  get_data (e, data, s.st_size, real_filename);
97138889Sjdp
97238889Sjdp  fclose (e);
97338889Sjdp  free (real_filename);
97438889Sjdp
97538889Sjdp  ids[0] = type;
97638889Sjdp  ids[1] = id;
97738889Sjdp  ids[2].named = 0;
97838889Sjdp  ids[2].u.id = resinfo->language;
97938889Sjdp
98038889Sjdp  r = define_resource (&resources, 3, ids, 0);
98138889Sjdp  r->type = RES_TYPE_USERDATA;
98238889Sjdp  r->u.userdata = ((struct rcdata_item *)
98338889Sjdp		   res_alloc (sizeof (struct rcdata_item)));
98438889Sjdp  r->u.userdata->next = NULL;
98538889Sjdp  r->u.userdata->type = RCDATA_BUFFER;
98638889Sjdp  r->u.userdata->u.buffer.length = s.st_size;
98738889Sjdp  r->u.userdata->u.buffer.data = data;
98838889Sjdp  r->res_info = *resinfo;
98938889Sjdp}
99038889Sjdp
99138889Sjdp/* Define a versioninfo resource.  */
99238889Sjdp
99338889Sjdpvoid
99438889Sjdpdefine_versioninfo (id, language, fixedverinfo, verinfo)
99538889Sjdp     struct res_id id;
99638889Sjdp     int language;
99738889Sjdp     struct fixed_versioninfo *fixedverinfo;
99838889Sjdp     struct ver_info *verinfo;
99938889Sjdp{
100038889Sjdp  struct res_resource *r;
100138889Sjdp
100238889Sjdp  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
100338889Sjdp  r->type = RES_TYPE_VERSIONINFO;
100438889Sjdp  r->u.versioninfo = ((struct versioninfo *)
100538889Sjdp		      res_alloc (sizeof (struct versioninfo)));
100638889Sjdp  r->u.versioninfo->fixed = fixedverinfo;
100738889Sjdp  r->u.versioninfo->var = verinfo;
100838889Sjdp  r->res_info.language = language;
100938889Sjdp}
101038889Sjdp
101138889Sjdp/* Add string version info to a list of version information.  */
101238889Sjdp
101338889Sjdpstruct ver_info *
101438889Sjdpappend_ver_stringfileinfo (verinfo, language, strings)
101538889Sjdp     struct ver_info *verinfo;
101638889Sjdp     const char *language;
101738889Sjdp     struct ver_stringinfo *strings;
101838889Sjdp{
101938889Sjdp  struct ver_info *vi, **pp;
102038889Sjdp
102138889Sjdp  vi = (struct ver_info *) res_alloc (sizeof *vi);
102238889Sjdp  vi->next = NULL;
102338889Sjdp  vi->type = VERINFO_STRING;
102438889Sjdp  unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
102538889Sjdp  vi->u.string.strings = strings;
102638889Sjdp
102738889Sjdp  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
102838889Sjdp    ;
102938889Sjdp  *pp = vi;
103038889Sjdp
103138889Sjdp  return verinfo;
103238889Sjdp}
103338889Sjdp
103438889Sjdp/* Add variable version info to a list of version information.  */
103538889Sjdp
103638889Sjdpstruct ver_info *
103738889Sjdpappend_ver_varfileinfo (verinfo, key, var)
103838889Sjdp     struct ver_info *verinfo;
103938889Sjdp     const char *key;
104038889Sjdp     struct ver_varinfo *var;
104138889Sjdp{
104238889Sjdp  struct ver_info *vi, **pp;
104338889Sjdp
104438889Sjdp  vi = (struct ver_info *) res_alloc (sizeof *vi);
104538889Sjdp  vi->next = NULL;
104638889Sjdp  vi->type = VERINFO_VAR;
104738889Sjdp  unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
104838889Sjdp  vi->u.var.var = var;
104938889Sjdp
105038889Sjdp  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
105138889Sjdp    ;
105238889Sjdp  *pp = vi;
105338889Sjdp
105438889Sjdp  return verinfo;
105538889Sjdp}
105638889Sjdp
105738889Sjdp/* Append version string information to a list.  */
105838889Sjdp
105938889Sjdpstruct ver_stringinfo *
106038889Sjdpappend_verval (strings, key, value)
106138889Sjdp     struct ver_stringinfo *strings;
106238889Sjdp     const char *key;
106338889Sjdp     const char *value;
106438889Sjdp{
106538889Sjdp  struct ver_stringinfo *vs, **pp;
106638889Sjdp
106738889Sjdp  vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
106838889Sjdp  vs->next = NULL;
106938889Sjdp  unicode_from_ascii ((int *) NULL, &vs->key, key);
107038889Sjdp  unicode_from_ascii ((int *) NULL, &vs->value, value);
107138889Sjdp
107238889Sjdp  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
107338889Sjdp    ;
107438889Sjdp  *pp = vs;
107538889Sjdp
107638889Sjdp  return strings;
107738889Sjdp}
107838889Sjdp
107938889Sjdp/* Append version variable information to a list.  */
108038889Sjdp
108138889Sjdpstruct ver_varinfo *
108238889Sjdpappend_vertrans (var, language, charset)
108338889Sjdp     struct ver_varinfo *var;
108438889Sjdp     unsigned long language;
108538889Sjdp     unsigned long charset;
108638889Sjdp{
108738889Sjdp  struct ver_varinfo *vv, **pp;
108838889Sjdp
108938889Sjdp  vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
109038889Sjdp  vv->next = NULL;
109138889Sjdp  vv->language = language;
109238889Sjdp  vv->charset = charset;
109338889Sjdp
109438889Sjdp  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
109538889Sjdp    ;
109638889Sjdp  *pp = vv;
109738889Sjdp
109838889Sjdp  return var;
109938889Sjdp}
110038889Sjdp
110138889Sjdp/* Local functions used to write out an rc file.  */
110238889Sjdp
110338889Sjdpstatic void indent PARAMS ((FILE *, int));
110438889Sjdpstatic void write_rc_directory
110538889Sjdp  PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
110638889Sjdp	   const struct res_id *, int *, int));
110738889Sjdpstatic void write_rc_subdir
110838889Sjdp  PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
110938889Sjdp	   const struct res_id *, int *, int));
111038889Sjdpstatic void write_rc_resource
111138889Sjdp  PARAMS ((FILE *, const struct res_id *, const struct res_id *,
111238889Sjdp	   const struct res_resource *, int *));
111338889Sjdpstatic void write_rc_accelerators
111438889Sjdp  PARAMS ((FILE *, const struct accelerator *));
111538889Sjdpstatic void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
111638889Sjdpstatic void write_rc_group_cursor
111738889Sjdp  PARAMS ((FILE *, const struct group_cursor *));
111838889Sjdpstatic void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
111938889Sjdpstatic void write_rc_dialog_control
112038889Sjdp  PARAMS ((FILE *, const struct dialog_control *));
112138889Sjdpstatic void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
112238889Sjdpstatic void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
112338889Sjdpstatic void write_rc_menu PARAMS ((FILE *, const struct menu *, int));
112438889Sjdpstatic void write_rc_menuitems
112538889Sjdp  PARAMS ((FILE *, const struct menuitem *, int, int));
112638889Sjdpstatic void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_item *, int));
112738889Sjdpstatic void write_rc_stringtable
112838889Sjdp  PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
112938889Sjdpstatic void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
113038889Sjdpstatic void write_rc_filedata
113138889Sjdp  PARAMS ((FILE *, unsigned long, const unsigned char *));
113238889Sjdp
113338889Sjdp/* Indent a given number of spaces.  */
113438889Sjdp
113538889Sjdpstatic void
113638889Sjdpindent (e, c)
113738889Sjdp     FILE *e;
113838889Sjdp     int c;
113938889Sjdp{
114038889Sjdp  int i;
114138889Sjdp
114238889Sjdp  for (i = 0; i < c; i++)
114338889Sjdp    putc (' ', e);
114438889Sjdp}
114538889Sjdp
114638889Sjdp/* Dump the resources we have read in the format of an rc file.
114738889Sjdp
114838889Sjdp   Actually, we don't use the format of an rc file, because it's way
114938889Sjdp   too much of a pain--for example, we'd have to write icon resources
115038889Sjdp   into a file and refer to that file.  We just generate a readable
115138889Sjdp   format that kind of looks like an rc file, and is useful for
115238889Sjdp   understanding the contents of a resource file.  Someday we may want
115338889Sjdp   to generate an rc file which the rc compiler can read; if that day
115438889Sjdp   comes, this code will have to be fixed up.  */
115538889Sjdp
115638889Sjdpvoid
115738889Sjdpwrite_rc_file (filename, resources)
115838889Sjdp     const char *filename;
115938889Sjdp     const struct res_directory *resources;
116038889Sjdp{
116138889Sjdp  FILE *e;
116238889Sjdp  int language;
116338889Sjdp
116438889Sjdp  if (filename == NULL)
116538889Sjdp    e = stdout;
116638889Sjdp  else
116738889Sjdp    {
116838889Sjdp      e = fopen (filename, FOPEN_WT);
116938889Sjdp      if (e == NULL)
117038889Sjdp	fatal ("can't open `%s' for output: %s", filename, strerror (errno));
117138889Sjdp    }
117238889Sjdp
117338889Sjdp  language = -1;
117438889Sjdp  write_rc_directory (e, resources, (const struct res_id *) NULL,
117538889Sjdp		      (const struct res_id *) NULL, &language, 1);
117638889Sjdp}
117738889Sjdp
117838889Sjdp/* Write out a directory.  E is the file to write to.  RD is the
117938889Sjdp   directory.  TYPE is a pointer to the level 1 ID which serves as the
118038889Sjdp   resource type.  NAME is a pointer to the level 2 ID which serves as
118138889Sjdp   an individual resource name.  LANGUAGE is a pointer to the current
118238889Sjdp   language.  LEVEL is the level in the tree.  */
118338889Sjdp
118438889Sjdpstatic void
118538889Sjdpwrite_rc_directory (e, rd, type, name, language, level)
118638889Sjdp     FILE *e;
118738889Sjdp     const struct res_directory *rd;
118838889Sjdp     const struct res_id *type;
118938889Sjdp     const struct res_id *name;
119038889Sjdp     int *language;
119138889Sjdp     int level;
119238889Sjdp{
119338889Sjdp  const struct res_entry *re;
119438889Sjdp
119538889Sjdp  /* Print out some COFF information that rc files can't represent.  */
119638889Sjdp
119738889Sjdp  if (rd->time != 0)
119838889Sjdp    fprintf (e, "// Time stamp: %lu\n", rd->time);
119938889Sjdp  if (rd->characteristics != 0)
120038889Sjdp    fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
120138889Sjdp  if (rd->major != 0 || rd->minor != 0)
120238889Sjdp    fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
120338889Sjdp
120438889Sjdp  for (re = rd->entries;  re != NULL; re = re->next)
120538889Sjdp    {
120638889Sjdp      switch (level)
120738889Sjdp	{
120838889Sjdp	case 1:
120938889Sjdp	  /* If we're at level 1, the key of this resource is the
121038889Sjdp             type.  This normally duplicates the information we have
121138889Sjdp             stored with the resource itself, but we need to remember
121238889Sjdp             the type if this is a user define resource type.  */
121338889Sjdp	  type = &re->id;
121438889Sjdp	  break;
121538889Sjdp
121638889Sjdp	case 2:
121738889Sjdp	  /* If we're at level 2, the key of this resource is the name
121838889Sjdp	     we are going to use in the rc printout. */
121938889Sjdp	  name = &re->id;
122038889Sjdp	  break;
122138889Sjdp
122238889Sjdp	case 3:
122338889Sjdp	  /* If we're at level 3, then this key represents a language.
122438889Sjdp	     Use it to update the current language.  */
122538889Sjdp	  if (! re->id.named
122638889Sjdp	      && re->id.u.id != *language
122738889Sjdp	      && (re->id.u.id & 0xffff) == re->id.u.id)
122838889Sjdp	    {
122938889Sjdp	      fprintf (e, "LANGUAGE %lu, %lu\n",
123038889Sjdp		       re->id.u.id & 0xff, (re->id.u.id >> 8) & 0xff);
123138889Sjdp	      *language = re->id.u.id;
123238889Sjdp	    }
123338889Sjdp	  break;
123438889Sjdp
123538889Sjdp	default:
123638889Sjdp	  break;
123738889Sjdp	}
123838889Sjdp
123938889Sjdp      if (re->subdir)
124038889Sjdp	write_rc_subdir (e, re, type, name, language, level);
124138889Sjdp      else
124238889Sjdp	{
124338889Sjdp	  if (level == 3)
124438889Sjdp	    {
124538889Sjdp	      /* This is the normal case: the three levels are
124638889Sjdp                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
124738889Sjdp                 2, and represents the name to use.  We probably just
124838889Sjdp                 set LANGUAGE, and it will probably match what the
124938889Sjdp                 resource itself records if anything.  */
125038889Sjdp	      write_rc_resource (e, type, name, re->u.res, language);
125138889Sjdp	    }
125238889Sjdp	  else
125338889Sjdp	    {
125438889Sjdp	      fprintf (e, "// Resource at unexpected level %d\n", level);
125538889Sjdp	      write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
125638889Sjdp				 language);
125738889Sjdp	    }
125838889Sjdp	}
125938889Sjdp    }
126038889Sjdp}
126138889Sjdp
126238889Sjdp/* Write out a subdirectory entry.  E is the file to write to.  RE is
126338889Sjdp   the subdirectory entry.  TYPE and NAME are pointers to higher level
126438889Sjdp   IDs, or NULL.  LANGUAGE is a pointer to the current language.
126538889Sjdp   LEVEL is the level in the tree.  */
126638889Sjdp
126738889Sjdpstatic void
126838889Sjdpwrite_rc_subdir (e, re, type, name, language, level)
126938889Sjdp     FILE *e;
127038889Sjdp     const struct res_entry *re;
127138889Sjdp     const struct res_id *type;
127238889Sjdp     const struct res_id *name;
127338889Sjdp     int *language;
127438889Sjdp     int level;
127538889Sjdp{
127638889Sjdp  fprintf (e, "\n");
127738889Sjdp  switch (level)
127838889Sjdp    {
127938889Sjdp    case 1:
128038889Sjdp      fprintf (e, "// Type: ");
128138889Sjdp      if (re->id.named)
128238889Sjdp	res_id_print (e, re->id, 1);
128338889Sjdp      else
128438889Sjdp	{
128538889Sjdp	  const char *s;
128638889Sjdp
128738889Sjdp	  switch (re->id.u.id)
128838889Sjdp	    {
128938889Sjdp	    case RT_CURSOR: s = "cursor"; break;
129038889Sjdp	    case RT_BITMAP: s = "bitmap"; break;
129138889Sjdp	    case RT_ICON: s = "icon"; break;
129238889Sjdp	    case RT_MENU: s = "menu"; break;
129338889Sjdp	    case RT_DIALOG: s = "dialog"; break;
129438889Sjdp	    case RT_STRING: s = "stringtable"; break;
129538889Sjdp	    case RT_FONTDIR: s = "fontdir"; break;
129638889Sjdp	    case RT_FONT: s = "font"; break;
129738889Sjdp	    case RT_ACCELERATORS: s = "accelerators"; break;
129838889Sjdp	    case RT_RCDATA: s = "rcdata"; break;
129938889Sjdp	    case RT_MESSAGETABLE: s = "messagetable"; break;
130038889Sjdp	    case RT_GROUP_CURSOR: s = "group cursor"; break;
130138889Sjdp	    case RT_GROUP_ICON: s = "group icon"; break;
130238889Sjdp	    case RT_VERSION: s = "version"; break;
130338889Sjdp	    case RT_DLGINCLUDE: s = "dlginclude"; break;
130438889Sjdp	    case RT_PLUGPLAY: s = "plugplay"; break;
130538889Sjdp	    case RT_VXD: s = "vxd"; break;
130638889Sjdp	    case RT_ANICURSOR: s = "anicursor"; break;
130738889Sjdp	    case RT_ANIICON: s = "aniicon"; break;
130838889Sjdp	    default: s = NULL; break;
130938889Sjdp	    }
131038889Sjdp
131138889Sjdp	  if (s != NULL)
131238889Sjdp	    fprintf (e, "%s", s);
131338889Sjdp	  else
131438889Sjdp	    res_id_print (e, re->id, 1);
131538889Sjdp	}
131638889Sjdp      fprintf (e, "\n");
131738889Sjdp      break;
131838889Sjdp
131938889Sjdp    case 2:
132038889Sjdp      fprintf (e, "// Name: ");
132138889Sjdp      res_id_print (e, re->id, 1);
132238889Sjdp      fprintf (e, "\n");
132338889Sjdp      break;
132438889Sjdp
132538889Sjdp    case 3:
132638889Sjdp      fprintf (e, "// Language: ");
132738889Sjdp      res_id_print (e, re->id, 1);
132838889Sjdp      fprintf (e, "\n");
132938889Sjdp      break;
133038889Sjdp
133138889Sjdp    default:
133238889Sjdp      fprintf (e, "// Level %d: ", level);
133338889Sjdp      res_id_print (e, re->id, 1);
133438889Sjdp      fprintf (e, "\n");
133538889Sjdp    }
133638889Sjdp
133738889Sjdp  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
133838889Sjdp}
133938889Sjdp
134038889Sjdp/* Write out a single resource.  E is the file to write to.  TYPE is a
134138889Sjdp   pointer to the type of the resource.  NAME is a pointer to the name
134238889Sjdp   of the resource; it will be NULL if there is a level mismatch.  RES
134338889Sjdp   is the resource data.  LANGUAGE is a pointer to the current
134438889Sjdp   language.  */
134538889Sjdp
134638889Sjdpstatic void
134738889Sjdpwrite_rc_resource (e, type, name, res, language)
134838889Sjdp     FILE *e;
134938889Sjdp     const struct res_id *type;
135038889Sjdp     const struct res_id *name;
135138889Sjdp     const struct res_resource *res;
135238889Sjdp     int *language;
135338889Sjdp{
135438889Sjdp  const char *s;
135538889Sjdp  int rt;
135638889Sjdp  int menuex = 0;
135738889Sjdp
135838889Sjdp  fprintf (e, "\n");
135938889Sjdp
136038889Sjdp  switch (res->type)
136138889Sjdp    {
136238889Sjdp    default:
136338889Sjdp      abort ();
136438889Sjdp
136538889Sjdp    case RES_TYPE_ACCELERATOR:
136638889Sjdp      s = "ACCELERATOR";
136738889Sjdp      rt = RT_ACCELERATORS;
136838889Sjdp      break;
136938889Sjdp
137038889Sjdp    case RES_TYPE_BITMAP:
137138889Sjdp      s = "BITMAP";
137238889Sjdp      rt = RT_BITMAP;
137338889Sjdp      break;
137438889Sjdp
137538889Sjdp    case RES_TYPE_CURSOR:
137638889Sjdp      s = "CURSOR";
137738889Sjdp      rt = RT_CURSOR;
137838889Sjdp      break;
137938889Sjdp
138038889Sjdp    case RES_TYPE_GROUP_CURSOR:
138138889Sjdp      s = "GROUP_CURSOR";
138238889Sjdp      rt = RT_GROUP_CURSOR;
138338889Sjdp      break;
138438889Sjdp
138538889Sjdp    case RES_TYPE_DIALOG:
138638889Sjdp      if (extended_dialog (res->u.dialog))
138738889Sjdp	s = "DIALOGEX";
138838889Sjdp      else
138938889Sjdp	s = "DIALOG";
139038889Sjdp      rt = RT_DIALOG;
139138889Sjdp      break;
139238889Sjdp
139338889Sjdp    case RES_TYPE_FONT:
139438889Sjdp      s = "FONT";
139538889Sjdp      rt = RT_FONT;
139638889Sjdp      break;
139738889Sjdp
139838889Sjdp    case RES_TYPE_FONTDIR:
139938889Sjdp      s = "FONTDIR";
140038889Sjdp      rt = RT_FONTDIR;
140138889Sjdp      break;
140238889Sjdp
140338889Sjdp    case RES_TYPE_ICON:
140438889Sjdp      s = "ICON";
140538889Sjdp      rt = RT_ICON;
140638889Sjdp      break;
140738889Sjdp
140838889Sjdp    case RES_TYPE_GROUP_ICON:
140938889Sjdp      s = "GROUP_ICON";
141038889Sjdp      rt = RT_GROUP_ICON;
141138889Sjdp      break;
141238889Sjdp
141338889Sjdp    case RES_TYPE_MENU:
141438889Sjdp      if (extended_menu (res->u.menu))
141538889Sjdp	{
141638889Sjdp	  s = "MENUEX";
141738889Sjdp	  menuex = 1;
141838889Sjdp	}
141938889Sjdp      else
142038889Sjdp	{
142138889Sjdp	  s = "MENU";
142238889Sjdp	  menuex = 0;
142338889Sjdp	}
142438889Sjdp      rt = RT_MENU;
142538889Sjdp      break;
142638889Sjdp
142738889Sjdp    case RES_TYPE_MESSAGETABLE:
142838889Sjdp      s = "MESSAGETABLE";
142938889Sjdp      rt = RT_MESSAGETABLE;
143038889Sjdp      break;
143138889Sjdp
143238889Sjdp    case RES_TYPE_RCDATA:
143338889Sjdp      s = "RCDATA";
143438889Sjdp      rt = RT_RCDATA;
143538889Sjdp      break;
143638889Sjdp
143738889Sjdp    case RES_TYPE_STRINGTABLE:
143838889Sjdp      s = "STRINGTABLE";
143938889Sjdp      rt = RT_STRING;
144038889Sjdp      break;
144138889Sjdp
144238889Sjdp    case RES_TYPE_USERDATA:
144338889Sjdp      s = NULL;
144438889Sjdp      rt = 0;
144538889Sjdp      break;
144638889Sjdp
144738889Sjdp    case RES_TYPE_VERSIONINFO:
144838889Sjdp      s = "VERSIONINFO";
144938889Sjdp      rt = RT_VERSION;
145038889Sjdp      break;
145138889Sjdp    }
145238889Sjdp
145338889Sjdp  if (rt != 0
145438889Sjdp      && type != NULL
145538889Sjdp      && (type->named || type->u.id != rt))
145638889Sjdp    {
145738889Sjdp      fprintf (e, "// Unexpected resource type mismatch: ");
145838889Sjdp      res_id_print (e, *type, 1);
145938889Sjdp      fprintf (e, " != %d", rt);
146038889Sjdp    }
146138889Sjdp
146238889Sjdp  if (res->coff_info.codepage != 0)
146338889Sjdp    fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
146438889Sjdp  if (res->coff_info.reserved != 0)
146538889Sjdp    fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
146638889Sjdp
146738889Sjdp  if (name != NULL)
146838889Sjdp    res_id_print (e, *name, 0);
146938889Sjdp  else
147038889Sjdp    fprintf (e, "??Unknown-Name??");
147138889Sjdp
147238889Sjdp  fprintf (e, " ");
147338889Sjdp  if (s != NULL)
147438889Sjdp    fprintf (e, "%s", s);
147538889Sjdp  else if (type != NULL)
147638889Sjdp    res_id_print (e, *type, 0);
147738889Sjdp  else
147838889Sjdp    fprintf (e, "??Unknown-Type??");
147938889Sjdp
148038889Sjdp  if (res->res_info.memflags != 0)
148138889Sjdp    {
148238889Sjdp      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
148338889Sjdp	fprintf (e, " MOVEABLE");
148438889Sjdp      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
148538889Sjdp	fprintf (e, " PURE");
148638889Sjdp      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
148738889Sjdp	fprintf (e, " PRELOAD");
148838889Sjdp      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
148938889Sjdp	fprintf (e, " DISCARDABLE");
149038889Sjdp    }
149138889Sjdp
149238889Sjdp  if (res->type == RES_TYPE_DIALOG)
149338889Sjdp    {
149438889Sjdp      fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
149538889Sjdp	       res->u.dialog->width, res->u.dialog->height);
149638889Sjdp      if (res->u.dialog->ex != NULL
149738889Sjdp	  && res->u.dialog->ex->help != 0)
149838889Sjdp	fprintf (e, ", %lu", res->u.dialog->ex->help);
149938889Sjdp    }
150038889Sjdp
150138889Sjdp  fprintf (e, "\n");
150238889Sjdp
150338889Sjdp  if ((res->res_info.language != 0 && res->res_info.language != *language)
150438889Sjdp      || res->res_info.characteristics != 0
150538889Sjdp      || res->res_info.version != 0)
150638889Sjdp    {
150738889Sjdp      int modifiers;
150838889Sjdp
150938889Sjdp      switch (res->type)
151038889Sjdp	{
151138889Sjdp	case RES_TYPE_ACCELERATOR:
151238889Sjdp	case RES_TYPE_DIALOG:
151338889Sjdp	case RES_TYPE_MENU:
151438889Sjdp	case RES_TYPE_RCDATA:
151538889Sjdp	case RES_TYPE_STRINGTABLE:
151638889Sjdp	  modifiers = 1;
151738889Sjdp	  break;
151838889Sjdp
151938889Sjdp	default:
152038889Sjdp	  modifiers = 0;
152138889Sjdp	  break;
152238889Sjdp	}
152338889Sjdp
152438889Sjdp      if (res->res_info.language != 0 && res->res_info.language != *language)
152538889Sjdp	fprintf (e, "%sLANGUAGE %d, %d\n",
152638889Sjdp		 modifiers ? "// " : "",
152738889Sjdp		 res->res_info.language & 0xff,
152838889Sjdp		 (res->res_info.language >> 8) & 0xff);
152938889Sjdp      if (res->res_info.characteristics != 0)
153038889Sjdp	fprintf (e, "%sCHARACTERISTICS %lu\n",
153138889Sjdp		 modifiers ? "// " : "",
153238889Sjdp		 res->res_info.characteristics);
153338889Sjdp      if (res->res_info.version != 0)
153438889Sjdp	fprintf (e, "%sVERSION %lu\n",
153538889Sjdp		 modifiers ? "// " : "",
153638889Sjdp		 res->res_info.version);
153738889Sjdp    }
153838889Sjdp
153938889Sjdp  switch (res->type)
154038889Sjdp    {
154138889Sjdp    default:
154238889Sjdp      abort ();
154338889Sjdp
154438889Sjdp    case RES_TYPE_ACCELERATOR:
154538889Sjdp      write_rc_accelerators (e, res->u.acc);
154638889Sjdp      break;
154738889Sjdp
154838889Sjdp    case RES_TYPE_CURSOR:
154938889Sjdp      write_rc_cursor (e, res->u.cursor);
155038889Sjdp      break;
155138889Sjdp
155238889Sjdp    case RES_TYPE_GROUP_CURSOR:
155338889Sjdp      write_rc_group_cursor (e, res->u.group_cursor);
155438889Sjdp      break;
155538889Sjdp
155638889Sjdp    case RES_TYPE_DIALOG:
155738889Sjdp      write_rc_dialog (e, res->u.dialog);
155838889Sjdp      break;
155938889Sjdp
156038889Sjdp    case RES_TYPE_FONTDIR:
156138889Sjdp      write_rc_fontdir (e, res->u.fontdir);
156238889Sjdp      break;
156338889Sjdp
156438889Sjdp    case RES_TYPE_GROUP_ICON:
156538889Sjdp      write_rc_group_icon (e, res->u.group_icon);
156638889Sjdp      break;
156738889Sjdp
156838889Sjdp    case RES_TYPE_MENU:
156938889Sjdp      write_rc_menu (e, res->u.menu, menuex);
157038889Sjdp      break;
157138889Sjdp
157238889Sjdp    case RES_TYPE_RCDATA:
157338889Sjdp      write_rc_rcdata (e, res->u.rcdata, 0);
157438889Sjdp      break;
157538889Sjdp
157638889Sjdp    case RES_TYPE_STRINGTABLE:
157738889Sjdp      write_rc_stringtable (e, name, res->u.stringtable);
157838889Sjdp      break;
157938889Sjdp
158038889Sjdp    case RES_TYPE_USERDATA:
158138889Sjdp      write_rc_rcdata (e, res->u.userdata, 0);
158238889Sjdp      break;
158338889Sjdp
158438889Sjdp    case RES_TYPE_VERSIONINFO:
158538889Sjdp      write_rc_versioninfo (e, res->u.versioninfo);
158638889Sjdp      break;
158738889Sjdp
158838889Sjdp    case RES_TYPE_BITMAP:
158938889Sjdp    case RES_TYPE_FONT:
159038889Sjdp    case RES_TYPE_ICON:
159138889Sjdp    case RES_TYPE_MESSAGETABLE:
159238889Sjdp      write_rc_filedata (e, res->u.data.length, res->u.data.data);
159338889Sjdp      break;
159438889Sjdp    }
159538889Sjdp}
159638889Sjdp
159738889Sjdp/* Write out accelerator information.  */
159838889Sjdp
159938889Sjdpstatic void
160038889Sjdpwrite_rc_accelerators (e, accelerators)
160138889Sjdp     FILE *e;
160238889Sjdp     const struct accelerator *accelerators;
160338889Sjdp{
160438889Sjdp  const struct accelerator *acc;
160538889Sjdp
160638889Sjdp  fprintf (e, "BEGIN\n");
160738889Sjdp  for (acc = accelerators; acc != NULL; acc = acc->next)
160838889Sjdp    {
160938889Sjdp      int printable;
161038889Sjdp
161138889Sjdp      fprintf (e, "  ");
161238889Sjdp
161338889Sjdp      if ((acc->key & 0x7f) == acc->key
161438889Sjdp	  && isprint ((unsigned char) acc->key)
161538889Sjdp	  && (acc->flags & ACC_VIRTKEY) == 0)
161638889Sjdp	{
161738889Sjdp	  fprintf (e, "\"%c\"", acc->key);
161838889Sjdp	  printable = 1;
161938889Sjdp	}
162038889Sjdp      else
162138889Sjdp	{
162238889Sjdp	  fprintf (e, "%d", acc->key);
162338889Sjdp	  printable = 0;
162438889Sjdp	}
162538889Sjdp
162638889Sjdp      fprintf (e, ", %d", acc->id);
162738889Sjdp
162838889Sjdp      if (! printable)
162938889Sjdp	{
163038889Sjdp	  if ((acc->flags & ACC_VIRTKEY) != 0)
163138889Sjdp	    fprintf (e, ", VIRTKEY");
163238889Sjdp	  else
163338889Sjdp	    fprintf (e, ", ASCII");
163438889Sjdp	}
163538889Sjdp
163638889Sjdp      if ((acc->flags & ACC_SHIFT) != 0)
163738889Sjdp	fprintf (e, ", SHIFT");
163838889Sjdp      if ((acc->flags & ACC_CONTROL) != 0)
163938889Sjdp	fprintf (e, ", CONTROL");
164038889Sjdp      if ((acc->flags & ACC_ALT) != 0)
164138889Sjdp	fprintf (e, ", ALT");
164238889Sjdp
164338889Sjdp      fprintf (e, "\n");
164438889Sjdp    }
164538889Sjdp
164638889Sjdp  fprintf (e, "END\n");
164738889Sjdp}
164838889Sjdp
164938889Sjdp/* Write out cursor information.  This would normally be in a separate
165038889Sjdp   file, which the rc file would include.  */
165138889Sjdp
165238889Sjdpstatic void
165338889Sjdpwrite_rc_cursor (e, cursor)
165438889Sjdp     FILE *e;
165538889Sjdp     const struct cursor *cursor;
165638889Sjdp{
165738889Sjdp  fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
165838889Sjdp	   cursor->yhotspot);
165938889Sjdp  write_rc_filedata (e, cursor->length, cursor->data);
166038889Sjdp}
166138889Sjdp
166238889Sjdp/* Write out group cursor data.  This would normally be built from the
166338889Sjdp   cursor data.  */
166438889Sjdp
166538889Sjdpstatic void
166638889Sjdpwrite_rc_group_cursor (e, group_cursor)
166738889Sjdp     FILE *e;
166838889Sjdp     const struct group_cursor *group_cursor;
166938889Sjdp{
167038889Sjdp  const struct group_cursor *gc;
167138889Sjdp
167238889Sjdp  for (gc = group_cursor; gc != NULL; gc = gc->next)
167338889Sjdp    {
167438889Sjdp      fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
167538889Sjdp	     gc->width, gc->height, gc->planes, gc->bits);
167638889Sjdp      fprintf (e, "// data bytes: %lu; index: %d\n",
167738889Sjdp	       gc->bytes, gc->index);
167838889Sjdp    }
167938889Sjdp}
168038889Sjdp
168138889Sjdp/* Write dialog data.  */
168238889Sjdp
168338889Sjdpstatic void
168438889Sjdpwrite_rc_dialog (e, dialog)
168538889Sjdp     FILE *e;
168638889Sjdp     const struct dialog *dialog;
168738889Sjdp{
168838889Sjdp  const struct dialog_control *control;
168938889Sjdp
169038889Sjdp  if (dialog->style != 0)
169138889Sjdp    fprintf (e, "STYLE 0x%lx\n", dialog->style);
169238889Sjdp  if (dialog->exstyle != 0)
169338889Sjdp    fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
169438889Sjdp  if ((dialog->class.named && dialog->class.u.n.length > 0)
169538889Sjdp      || dialog->class.u.id != 0)
169638889Sjdp    {
169738889Sjdp      fprintf (e, "CLASS ");
169838889Sjdp      res_id_print (e, dialog->class, 0);
169938889Sjdp      fprintf (e, "\n");
170038889Sjdp    }
170138889Sjdp  if (dialog->caption != NULL)
170238889Sjdp    {
170338889Sjdp      fprintf (e, "CAPTION \"");
170438889Sjdp      unicode_print (e, dialog->caption, -1);
170538889Sjdp      fprintf (e, "\"\n");
170638889Sjdp    }
170738889Sjdp  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
170838889Sjdp      || dialog->menu.u.id != 0)
170938889Sjdp    {
171038889Sjdp      fprintf (e, "MENU ");
171138889Sjdp      res_id_print (e, dialog->menu, 0);
171238889Sjdp      fprintf (e, "\n");
171338889Sjdp    }
171438889Sjdp  if (dialog->font != NULL)
171538889Sjdp    {
171638889Sjdp      fprintf (e, "FONT %d, \"", dialog->pointsize);
171738889Sjdp      unicode_print (e, dialog->font, -1);
171838889Sjdp      fprintf (e, "\"");
171938889Sjdp      if (dialog->ex != NULL
172038889Sjdp	  && (dialog->ex->weight != 0 || dialog->ex->italic != 0))
172138889Sjdp	fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
172238889Sjdp      fprintf (e, "\n");
172338889Sjdp    }
172438889Sjdp
172538889Sjdp  fprintf (e, "BEGIN\n");
172638889Sjdp
172738889Sjdp  for (control = dialog->controls; control != NULL; control = control->next)
172838889Sjdp    write_rc_dialog_control (e, control);
172938889Sjdp
173038889Sjdp  fprintf (e, "END\n");
173138889Sjdp}
173238889Sjdp
173338889Sjdp/* For each predefined control keyword, this table provides the class
173438889Sjdp   and the style.  */
173538889Sjdp
173638889Sjdpstruct control_info
173738889Sjdp{
173838889Sjdp  const char *name;
173938889Sjdp  unsigned short class;
174038889Sjdp  unsigned long style;
174138889Sjdp};
174238889Sjdp
174338889Sjdpstatic const struct control_info control_info[] =
174438889Sjdp{
174538889Sjdp  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
174638889Sjdp  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
174738889Sjdp  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
174838889Sjdp  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
174938889Sjdp  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
175038889Sjdp  { "CTEXT", CTL_STATIC, SS_CENTER },
175138889Sjdp  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
175238889Sjdp  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
175338889Sjdp  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
175438889Sjdp  { "ICON", CTL_STATIC, SS_ICON },
175538889Sjdp  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
175638889Sjdp  { "LTEXT", CTL_STATIC, SS_LEFT },
175738889Sjdp  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
175838889Sjdp  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
175938889Sjdp  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
176038889Sjdp  { "RTEXT", CTL_STATIC, SS_RIGHT },
176138889Sjdp  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
176238889Sjdp  { "STATE3", CTL_BUTTON, BS_3STATE },
176338889Sjdp  /* It's important that USERBUTTON come after all the other button
176438889Sjdp     types, so that it won't be matched too early.  */
176538889Sjdp  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
176638889Sjdp  { NULL, 0, 0 }
176738889Sjdp};
176838889Sjdp
176938889Sjdp/* Write a dialog control.  */
177038889Sjdp
177138889Sjdpstatic void
177238889Sjdpwrite_rc_dialog_control (e, control)
177338889Sjdp     FILE *e;
177438889Sjdp     const struct dialog_control *control;
177538889Sjdp{
177638889Sjdp  const struct control_info *ci;
177738889Sjdp
177838889Sjdp  fprintf (e, "  ");
177938889Sjdp
178038889Sjdp  if (control->class.named)
178138889Sjdp    ci = NULL;
178238889Sjdp  else
178338889Sjdp    {
178438889Sjdp      for (ci = control_info; ci->name != NULL; ++ci)
178538889Sjdp	if (ci->class == control->class.u.id
178638889Sjdp	    && (ci->style == (unsigned long) -1
178738889Sjdp		|| ci->style == (control->style & 0xff)))
178838889Sjdp	  break;
178938889Sjdp    }
179038889Sjdp
179138889Sjdp  if (ci->name != NULL)
179238889Sjdp    fprintf (e, "%s", ci->name);
179338889Sjdp  else
179438889Sjdp    fprintf (e, "CONTROL");
179538889Sjdp
179638889Sjdp  if (control->text.named || control->text.u.id != 0)
179738889Sjdp    {
179838889Sjdp      fprintf (e, " ");
179938889Sjdp      res_id_print (e, control->text, 1);
180038889Sjdp      fprintf (e, ",");
180138889Sjdp    }
180238889Sjdp
180338889Sjdp  fprintf (e, " %d, ", control->id);
180438889Sjdp
180538889Sjdp  if (ci->name == NULL)
180638889Sjdp    {
180738889Sjdp      res_id_print (e, control->class, 0);
180838889Sjdp      fprintf (e, ", 0x%lx, ", control->style);
180938889Sjdp    }
181038889Sjdp
181138889Sjdp  fprintf (e, "%d, %d", control->x, control->y);
181238889Sjdp
181338889Sjdp  if (control->style != SS_ICON
181438889Sjdp      || control->exstyle != 0
181538889Sjdp      || control->width != 0
181638889Sjdp      || control->height != 0
181738889Sjdp      || control->help != 0)
181838889Sjdp    {
181938889Sjdp      fprintf (e, ", %d, %d", control->width, control->height);
182038889Sjdp
182138889Sjdp      /* FIXME: We don't need to print the style if it is the default.
182238889Sjdp	 More importantly, in certain cases we actually need to turn
182338889Sjdp	 off parts of the forced style, by using NOT.  */
182438889Sjdp      fprintf (e, ", 0x%lx", control->style);
182538889Sjdp
182638889Sjdp      if (control->exstyle != 0 || control->help != 0)
182738889Sjdp	fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
182838889Sjdp    }
182938889Sjdp
183038889Sjdp  fprintf (e, "\n");
183138889Sjdp
183238889Sjdp  if (control->data != NULL)
183338889Sjdp    write_rc_rcdata (e, control->data, 2);
183438889Sjdp}
183538889Sjdp
183638889Sjdp/* Write out font directory data.  This would normally be built from
183738889Sjdp   the font data.  */
183838889Sjdp
183938889Sjdpstatic void
184038889Sjdpwrite_rc_fontdir (e, fontdir)
184138889Sjdp     FILE *e;
184238889Sjdp     const struct fontdir *fontdir;
184338889Sjdp{
184438889Sjdp  const struct fontdir *fc;
184538889Sjdp
184638889Sjdp  for (fc = fontdir; fc != NULL; fc = fc->next)
184738889Sjdp    {
184838889Sjdp      fprintf (e, "// Font index: %d\n", fc->index);
184938889Sjdp      write_rc_filedata (e, fc->length, fc->data);
185038889Sjdp    }
185138889Sjdp}
185238889Sjdp
185338889Sjdp/* Write out group icon data.  This would normally be built from the
185438889Sjdp   icon data.  */
185538889Sjdp
185638889Sjdpstatic void
185738889Sjdpwrite_rc_group_icon (e, group_icon)
185838889Sjdp     FILE *e;
185938889Sjdp     const struct group_icon *group_icon;
186038889Sjdp{
186138889Sjdp  const struct group_icon *gi;
186238889Sjdp
186338889Sjdp  for (gi = group_icon; gi != NULL; gi = gi->next)
186438889Sjdp    {
186538889Sjdp      fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
186638889Sjdp	       gi->width, gi->height, gi->colors, gi->planes, gi->bits);
186738889Sjdp      fprintf (e, "// data bytes: %lu; index: %d\n",
186838889Sjdp	       gi->bytes, gi->index);
186938889Sjdp    }
187038889Sjdp}
187138889Sjdp
187238889Sjdp/* Write out a menu resource.  */
187338889Sjdp
187438889Sjdpstatic void
187538889Sjdpwrite_rc_menu (e, menu, menuex)
187638889Sjdp     FILE *e;
187738889Sjdp     const struct menu *menu;
187838889Sjdp     int menuex;
187938889Sjdp{
188038889Sjdp  if (menu->help != 0)
188138889Sjdp    fprintf (e, "// Help ID: %lu\n", menu->help);
188238889Sjdp  write_rc_menuitems (e, menu->items, menuex, 0);
188338889Sjdp}
188438889Sjdp
188538889Sjdp/* Write out menuitems.  */
188638889Sjdp
188738889Sjdpstatic void
188838889Sjdpwrite_rc_menuitems (e, menuitems, menuex, ind)
188938889Sjdp     FILE *e;
189038889Sjdp     const struct menuitem *menuitems;
189138889Sjdp     int menuex;
189238889Sjdp     int ind;
189338889Sjdp{
189438889Sjdp  const struct menuitem *mi;
189538889Sjdp
189638889Sjdp  indent (e, ind);
189738889Sjdp  fprintf (e, "BEGIN\n");
189838889Sjdp
189938889Sjdp  for (mi = menuitems; mi != NULL; mi = mi->next)
190038889Sjdp    {
190138889Sjdp      indent (e, ind + 2);
190238889Sjdp
190338889Sjdp      if (mi->popup == NULL)
190438889Sjdp	fprintf (e, "MENUITEM");
190538889Sjdp      else
190638889Sjdp	fprintf (e, "POPUP");
190738889Sjdp
190838889Sjdp      if (! menuex
190938889Sjdp	  && mi->popup == NULL
191038889Sjdp	  && mi->text == NULL
191138889Sjdp	  && mi->type == 0
191238889Sjdp	  && mi->id == 0)
191338889Sjdp	{
191438889Sjdp	  fprintf (e, " SEPARATOR\n");
191538889Sjdp	  continue;
191638889Sjdp	}
191738889Sjdp
191838889Sjdp      if (mi->text == NULL)
191938889Sjdp	fprintf (e, " \"\"");
192038889Sjdp      else
192138889Sjdp	{
192238889Sjdp	  fprintf (e, " \"");
192338889Sjdp	  unicode_print (e, mi->text, -1);
192438889Sjdp	  fprintf (e, "\"");
192538889Sjdp	}
192638889Sjdp
192738889Sjdp      if (! menuex)
192838889Sjdp	{
192938889Sjdp	  if (mi->popup == NULL)
193038889Sjdp	    fprintf (e, ", %d", mi->id);
193138889Sjdp
193238889Sjdp	  if ((mi->type & MENUITEM_CHECKED) != 0)
193338889Sjdp	    fprintf (e, ", CHECKED");
193438889Sjdp	  if ((mi->type & MENUITEM_GRAYED) != 0)
193538889Sjdp	    fprintf (e, ", GRAYED");
193638889Sjdp	  if ((mi->type & MENUITEM_HELP) != 0)
193738889Sjdp	    fprintf (e, ", HELP");
193838889Sjdp	  if ((mi->type & MENUITEM_INACTIVE) != 0)
193938889Sjdp	    fprintf (e, ", INACTIVE");
194038889Sjdp	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
194138889Sjdp	    fprintf (e, ", MENUBARBREAK");
194238889Sjdp	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
194338889Sjdp	    fprintf (e, ", MENUBREAK");
194438889Sjdp	}
194538889Sjdp      else
194638889Sjdp	{
194738889Sjdp	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
194838889Sjdp	    {
194938889Sjdp	      fprintf (e, ", %d", mi->id);
195038889Sjdp	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
195138889Sjdp		{
195238889Sjdp		  fprintf (e, ", %lu", mi->type);
195338889Sjdp		  if (mi->state != 0 || mi->help != 0)
195438889Sjdp		    {
195538889Sjdp		      fprintf (e, ", %lu", mi->state);
195638889Sjdp		      if (mi->help != 0)
195738889Sjdp			fprintf (e, ", %lu", mi->help);
195838889Sjdp		    }
195938889Sjdp		}
196038889Sjdp	    }
196138889Sjdp	}
196238889Sjdp
196338889Sjdp      fprintf (e, "\n");
196438889Sjdp
196538889Sjdp      if (mi->popup != NULL)
196638889Sjdp	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
196738889Sjdp    }
196838889Sjdp
196938889Sjdp  indent (e, ind);
197038889Sjdp  fprintf (e, "END\n");
197138889Sjdp}
197238889Sjdp
197338889Sjdp/* Write out an rcdata resource.  This is also used for other types of
197438889Sjdp   resources that need to print arbitrary data.  */
197538889Sjdp
197638889Sjdpstatic void
197738889Sjdpwrite_rc_rcdata (e, rcdata, ind)
197838889Sjdp     FILE *e;
197938889Sjdp     const struct rcdata_item *rcdata;
198038889Sjdp     int ind;
198138889Sjdp{
198238889Sjdp  const struct rcdata_item *ri;
198338889Sjdp
198438889Sjdp  indent (e, ind);
198538889Sjdp  fprintf (e, "BEGIN\n");
198638889Sjdp
198738889Sjdp  for (ri = rcdata; ri != NULL; ri = ri->next)
198838889Sjdp    {
198938889Sjdp      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
199038889Sjdp	continue;
199138889Sjdp
199238889Sjdp      indent (e, ind + 2);
199338889Sjdp
199438889Sjdp      switch (ri->type)
199538889Sjdp	{
199638889Sjdp	default:
199738889Sjdp	  abort ();
199838889Sjdp
199938889Sjdp	case RCDATA_WORD:
200038889Sjdp	  fprintf (e, "%d", ri->u.word);
200138889Sjdp	  break;
200238889Sjdp
200338889Sjdp	case RCDATA_DWORD:
200438889Sjdp	  fprintf (e, "%luL", ri->u.dword);
200538889Sjdp	  break;
200638889Sjdp
200738889Sjdp	case RCDATA_STRING:
200838889Sjdp	  {
200938889Sjdp	    const char *s;
201038889Sjdp	    unsigned long i;
201138889Sjdp
201238889Sjdp	    fprintf (e, "\"");
201338889Sjdp	    s = ri->u.string.s;
201438889Sjdp	    for (i = 0; i < ri->u.string.length; i++)
201538889Sjdp	      {
201638889Sjdp		if (isprint (*s))
201738889Sjdp		  putc (*s, e);
201838889Sjdp		else
201938889Sjdp		  fprintf (e, "\\%03o", *s);
202038889Sjdp	      }
202138889Sjdp	    fprintf (e, "\"");
202238889Sjdp	    break;
202338889Sjdp	  }
202438889Sjdp
202538889Sjdp	case RCDATA_WSTRING:
202638889Sjdp	  fprintf (e, "L\"");
202738889Sjdp	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
202838889Sjdp	  fprintf (e, "\"");
202938889Sjdp	  break;
203038889Sjdp
203138889Sjdp	case RCDATA_BUFFER:
203238889Sjdp	  {
203338889Sjdp	    unsigned long i;
203438889Sjdp	    int first;
203538889Sjdp
203638889Sjdp	    /* Assume little endian data.  */
203738889Sjdp
203838889Sjdp	    first = 1;
203938889Sjdp	    for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
204038889Sjdp	      {
204138889Sjdp		unsigned long l;
204238889Sjdp
204338889Sjdp		l = ((((((ri->u.buffer.data[i + 3] << 8)
204438889Sjdp			 | ri->u.buffer.data[i + 2]) << 8)
204538889Sjdp		       | ri->u.buffer.data[i + 1]) << 8)
204638889Sjdp		     | ri->u.buffer.data[i]);
204738889Sjdp		if (first)
204838889Sjdp		  first = 0;
204938889Sjdp		else
205038889Sjdp		  {
205138889Sjdp		    fprintf (e, ",\n");
205238889Sjdp		    indent (e, ind + 2);
205338889Sjdp		  }
205438889Sjdp		fprintf (e, "%luL", l);
205538889Sjdp	      }
205638889Sjdp
205738889Sjdp	    if (i + 1 < ri->u.buffer.length)
205838889Sjdp	      {
205938889Sjdp		int i;
206038889Sjdp
206138889Sjdp		i = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
206238889Sjdp		if (first)
206338889Sjdp		  first = 0;
206438889Sjdp		else
206538889Sjdp		  {
206638889Sjdp		    fprintf (e, ",\n");
206738889Sjdp		    indent (e, ind + 2);
206838889Sjdp		  }
206938889Sjdp		fprintf (e, "%d", i);
207038889Sjdp		i += 2;
207138889Sjdp	      }
207238889Sjdp
207338889Sjdp	    if (i < ri->u.buffer.length)
207438889Sjdp	      {
207538889Sjdp		if (first)
207638889Sjdp		  first = 0;
207738889Sjdp		else
207838889Sjdp		  {
207938889Sjdp		    fprintf (e, ",\n");
208038889Sjdp		    indent (e, ind + 2);
208138889Sjdp		  }
208238889Sjdp		if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
208338889Sjdp		    && isprint (ri->u.buffer.data[i]))
208438889Sjdp		  fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
208538889Sjdp		else
208638889Sjdp		  fprintf (e, "\"\%03o\"", ri->u.buffer.data[i]);
208738889Sjdp	      }
208838889Sjdp
208938889Sjdp	    break;
209038889Sjdp	  }
209138889Sjdp	}
209238889Sjdp
209338889Sjdp      if (ri->next != NULL)
209438889Sjdp	fprintf (e, ",");
209538889Sjdp      fprintf (e, "\n");
209638889Sjdp    }
209738889Sjdp
209838889Sjdp  indent (e, ind);
209938889Sjdp  fprintf (e, "END\n");
210038889Sjdp}
210138889Sjdp
210238889Sjdp/* Write out a stringtable resource.  */
210338889Sjdp
210438889Sjdpstatic void
210538889Sjdpwrite_rc_stringtable (e, name, stringtable)
210638889Sjdp     FILE *e;
210738889Sjdp     const struct res_id *name;
210838889Sjdp     const struct stringtable *stringtable;
210938889Sjdp{
211038889Sjdp  unsigned long offset;
211138889Sjdp  int i;
211238889Sjdp
211338889Sjdp  if (name != NULL && ! name->named)
211438889Sjdp    offset = (name->u.id - 1) << 4;
211538889Sjdp  else
211638889Sjdp    {
211738889Sjdp      fprintf (e, "// %s string table name\n",
211838889Sjdp	       name == NULL ? "Missing" : "Invalid");
211938889Sjdp      offset = 0;
212038889Sjdp    }
212138889Sjdp
212238889Sjdp  fprintf (e, "BEGIN\n");
212338889Sjdp
212438889Sjdp  for (i = 0; i < 16; i++)
212538889Sjdp    {
212638889Sjdp      if (stringtable->strings[i].length != 0)
212738889Sjdp	{
212838889Sjdp	  fprintf (e, "  %lu, \"", offset + i);
212938889Sjdp	  unicode_print (e, stringtable->strings[i].string,
213038889Sjdp			 stringtable->strings[i].length);
213138889Sjdp	  fprintf (e, "\"\n");
213238889Sjdp	}
213338889Sjdp    }
213438889Sjdp
213538889Sjdp  fprintf (e, "END\n");
213638889Sjdp}
213738889Sjdp
213838889Sjdp/* Write out a versioninfo resource.  */
213938889Sjdp
214038889Sjdpstatic void
214138889Sjdpwrite_rc_versioninfo (e, versioninfo)
214238889Sjdp     FILE *e;
214338889Sjdp     const struct versioninfo *versioninfo;
214438889Sjdp{
214538889Sjdp  const struct fixed_versioninfo *f;
214638889Sjdp  const struct ver_info *vi;
214738889Sjdp
214838889Sjdp  f = versioninfo->fixed;
214938889Sjdp  if (f->file_version_ms != 0 || f->file_version_ls != 0)
215038889Sjdp    fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
215138889Sjdp	     (f->file_version_ms >> 16) & 0xffff,
215238889Sjdp	     f->file_version_ms & 0xffff,
215338889Sjdp	     (f->file_version_ls >> 16) & 0xffff,
215438889Sjdp	     f->file_version_ls & 0xffff);
215538889Sjdp  if (f->product_version_ms != 0 || f->product_version_ls != 0)
215638889Sjdp    fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
215738889Sjdp	     (f->product_version_ms >> 16) & 0xffff,
215838889Sjdp	     f->product_version_ms & 0xffff,
215938889Sjdp	     (f->product_version_ls >> 16) & 0xffff,
216038889Sjdp	     f->product_version_ls & 0xffff);
216138889Sjdp  if (f->file_flags_mask != 0)
216238889Sjdp    fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
216338889Sjdp  if (f->file_flags != 0)
216438889Sjdp    fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
216538889Sjdp  if (f->file_os != 0)
216638889Sjdp    fprintf (e, " FILEOS 0x%lx\n", f->file_os);
216738889Sjdp  if (f->file_type != 0)
216838889Sjdp    fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
216938889Sjdp  if (f->file_subtype != 0)
217038889Sjdp    fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
217138889Sjdp  if (f->file_date_ms != 0 || f->file_date_ls != 0)
217238889Sjdp    fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
217338889Sjdp
217438889Sjdp  fprintf (e, "BEGIN\n");
217538889Sjdp
217638889Sjdp  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
217738889Sjdp    {
217838889Sjdp      switch (vi->type)
217938889Sjdp	{
218038889Sjdp	case VERINFO_STRING:
218138889Sjdp	  {
218238889Sjdp	    const struct ver_stringinfo *vs;
218338889Sjdp
218438889Sjdp	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
218538889Sjdp	    fprintf (e, "  BEGIN\n");
218638889Sjdp	    fprintf (e, "    BLOCK \"");
218738889Sjdp	    unicode_print (e, vi->u.string.language, -1);
218838889Sjdp	    fprintf (e, "\"\n");
218938889Sjdp	    fprintf (e, "    BEGIN\n");
219038889Sjdp
219138889Sjdp	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
219238889Sjdp	      {
219338889Sjdp		fprintf (e, "      VALUE \"");
219438889Sjdp		unicode_print (e, vs->key, -1);
219538889Sjdp		fprintf (e, "\", \"");
219638889Sjdp		unicode_print (e, vs->value, -1);
219738889Sjdp		fprintf (e, "\"\n");
219838889Sjdp	      }
219938889Sjdp
220038889Sjdp	    fprintf (e, "    END\n");
220138889Sjdp	    fprintf (e, "  END\n");
220238889Sjdp	    break;
220338889Sjdp	  }
220438889Sjdp
220538889Sjdp	case VERINFO_VAR:
220638889Sjdp	  {
220738889Sjdp	    const struct ver_varinfo *vv;
220838889Sjdp
220938889Sjdp	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
221038889Sjdp	    fprintf (e, "  BEGIN\n");
221138889Sjdp	    fprintf (e, "    VALUE \"");
221238889Sjdp	    unicode_print (e, vi->u.var.key, -1);
221338889Sjdp	    fprintf (e, "\"");
221438889Sjdp
221538889Sjdp	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
221638889Sjdp	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
221738889Sjdp		       vv->charset);
221838889Sjdp
221938889Sjdp	    fprintf (e, "\n  END\n");
222038889Sjdp
222138889Sjdp	    break;
222238889Sjdp	  }
222338889Sjdp	}
222438889Sjdp    }
222538889Sjdp
222638889Sjdp  fprintf (e, "END\n");
222738889Sjdp}
222838889Sjdp
222938889Sjdp/* Write out data which would normally be read from a file.  */
223038889Sjdp
223138889Sjdpstatic void
223238889Sjdpwrite_rc_filedata (e, length, data)
223338889Sjdp     FILE *e;
223438889Sjdp     unsigned long length;
223538889Sjdp     const unsigned char *data;
223638889Sjdp{
223738889Sjdp  unsigned long i;
223838889Sjdp
223938889Sjdp  for (i = 0; i + 15 < length; i += 16)
224038889Sjdp    {
224138889Sjdp      fprintf (e, "// %4lx: ", i);
224238889Sjdp      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
224338889Sjdp	       data[i + 0], data[i + 1], data[i + 2], data[i + 3],
224438889Sjdp	       data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
224538889Sjdp      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
224638889Sjdp	       data[i +  8], data[i +  9], data[i + 10], data[i + 11],
224738889Sjdp	       data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
224838889Sjdp    }
224938889Sjdp
225038889Sjdp  if (i < length)
225138889Sjdp    {
225238889Sjdp      fprintf (e, "// %4lx:", i);
225338889Sjdp      while (i < length)
225438889Sjdp	{
225538889Sjdp	  fprintf (e, " %02x", data[i]);
225638889Sjdp	  ++i;
225738889Sjdp	}
225838889Sjdp      fprintf (e, "\n");
225938889Sjdp    }
226038889Sjdp}
2261