resrc.c revision 130561
1/* resrc.c -- read and write Windows rc files.
2   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3   Written by Ian Lance Taylor, Cygnus Support.
4
5   This file is part of GNU Binutils.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20   02111-1307, USA.  */
21
22/* This file contains functions that read and write Windows rc files.
23   These are text files that represent resources.  */
24
25#include "bfd.h"
26#include "bucomm.h"
27#include "libiberty.h"
28#include "safe-ctype.h"
29#include "windres.h"
30
31#include <assert.h>
32#include <errno.h>
33#include <sys/stat.h>
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37
38#ifdef HAVE_SYS_WAIT_H
39#include <sys/wait.h>
40#else /* ! HAVE_SYS_WAIT_H */
41#if ! defined (_WIN32) || defined (__CYGWIN__)
42#ifndef WIFEXITED
43#define WIFEXITED(w)	(((w)&0377) == 0)
44#endif
45#ifndef WIFSIGNALED
46#define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
47#endif
48#ifndef WTERMSIG
49#define WTERMSIG(w)	((w) & 0177)
50#endif
51#ifndef WEXITSTATUS
52#define WEXITSTATUS(w)	(((w) >> 8) & 0377)
53#endif
54#else /* defined (_WIN32) && ! defined (__CYGWIN__) */
55#ifndef WIFEXITED
56#define WIFEXITED(w)	(((w) & 0xff) == 0)
57#endif
58#ifndef WIFSIGNALED
59#define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
60#endif
61#ifndef WTERMSIG
62#define WTERMSIG(w)	((w) & 0x7f)
63#endif
64#ifndef WEXITSTATUS
65#define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
66#endif
67#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
68#endif /* ! HAVE_SYS_WAIT_H */
69
70#ifndef STDOUT_FILENO
71#define STDOUT_FILENO 1
72#endif
73
74#if defined (_WIN32) && ! defined (__CYGWIN__)
75#define popen _popen
76#define pclose _pclose
77#endif
78
79/* The default preprocessor.  */
80
81#define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
82
83/* We read the directory entries in a cursor or icon file into
84   instances of this structure.  */
85
86struct icondir
87{
88  /* Width of image.  */
89  unsigned char width;
90  /* Height of image.  */
91  unsigned char height;
92  /* Number of colors in image.  */
93  unsigned char colorcount;
94  union
95  {
96    struct
97    {
98      /* Color planes.  */
99      unsigned short planes;
100      /* Bits per pixel.  */
101      unsigned short bits;
102    } icon;
103    struct
104    {
105      /* X coordinate of hotspot.  */
106      unsigned short xhotspot;
107      /* Y coordinate of hotspot.  */
108      unsigned short yhotspot;
109    } cursor;
110  } u;
111  /* Bytes in image.  */
112  unsigned long bytes;
113  /* File offset of image.  */
114  unsigned long offset;
115};
116
117/* The name of the rc file we are reading.  */
118
119char *rc_filename;
120
121/* The line number in the rc file.  */
122
123int rc_lineno;
124
125/* The pipe we are reading from, so that we can close it if we exit.  */
126
127static FILE *cpp_pipe;
128
129/* The temporary file used if we're not using popen, so we can delete it
130   if we exit.  */
131
132static char *cpp_temp_file;
133
134/* Input stream is either a file or a pipe.  */
135
136static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
137
138/* As we read the rc file, we attach information to this structure.  */
139
140static struct res_directory *resources;
141
142/* The number of cursor resources we have written out.  */
143
144static int cursors;
145
146/* The number of font resources we have written out.  */
147
148static int fonts;
149
150/* Font directory information.  */
151
152struct fontdir *fontdirs;
153
154/* Resource info to use for fontdirs.  */
155
156struct res_res_info fontdirs_resinfo;
157
158/* The number of icon resources we have written out.  */
159
160static int icons;
161
162/* Local functions.  */
163
164static int run_cmd (char *, const char *);
165static FILE *open_input_stream (char *);
166static FILE *look_for_default
167  (char *, const char *, int, const char *, const char *);
168static void close_input_stream (void);
169static void unexpected_eof (const char *);
170static int get_word (FILE *, const char *);
171static unsigned long get_long (FILE *, const char *);
172static void get_data (FILE *, unsigned char *, unsigned long, const char *);
173static void define_fontdirs (void);
174
175/* Run `cmd' and redirect the output to `redir'.  */
176
177static int
178run_cmd (char *cmd, const char *redir)
179{
180  char *s;
181  int pid, wait_status, retcode;
182  int i;
183  const char **argv;
184  char *errmsg_fmt, *errmsg_arg;
185  char *temp_base = choose_temp_base ();
186  int in_quote;
187  char sep;
188  int redir_handle = -1;
189  int stdout_save = -1;
190
191  /* Count the args.  */
192  i = 0;
193
194  for (s = cmd; *s; s++)
195    if (*s == ' ')
196      i++;
197
198  i++;
199  argv = alloca (sizeof (char *) * (i + 3));
200  i = 0;
201  s = cmd;
202
203  while (1)
204    {
205      while (*s == ' ' && *s != 0)
206	s++;
207
208      if (*s == 0)
209	break;
210
211      in_quote = (*s == '\'' || *s == '"');
212      sep = (in_quote) ? *s++ : ' ';
213      argv[i++] = s;
214
215      while (*s != sep && *s != 0)
216	s++;
217
218      if (*s == 0)
219	break;
220
221      *s++ = 0;
222
223      if (in_quote)
224	s++;
225    }
226  argv[i++] = NULL;
227
228  /* Setup the redirection.  We can't use the usual fork/exec and redirect
229     since we may be running on non-POSIX Windows host.  */
230
231  fflush (stdout);
232  fflush (stderr);
233
234  /* Open temporary output file.  */
235  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
236  if (redir_handle == -1)
237    fatal (_("can't open temporary file `%s': %s"), redir,
238	   strerror (errno));
239
240  /* Duplicate the stdout file handle so it can be restored later.  */
241  stdout_save = dup (STDOUT_FILENO);
242  if (stdout_save == -1)
243    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
244
245  /* Redirect stdout to our output file.  */
246  dup2 (redir_handle, STDOUT_FILENO);
247
248  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
249		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
250
251  /* Restore stdout to its previous setting.  */
252  dup2 (stdout_save, STDOUT_FILENO);
253
254  /* Close response file.  */
255  close (redir_handle);
256
257  if (pid == -1)
258    {
259      fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
260      return 1;
261    }
262
263  retcode = 0;
264  pid = pwait (pid, &wait_status, 0);
265
266  if (pid == -1)
267    {
268      fatal (_("wait: %s"), strerror (errno));
269      retcode = 1;
270    }
271  else if (WIFSIGNALED (wait_status))
272    {
273      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
274      retcode = 1;
275    }
276  else if (WIFEXITED (wait_status))
277    {
278      if (WEXITSTATUS (wait_status) != 0)
279	{
280	  fatal (_("%s exited with status %d"), cmd,
281	         WEXITSTATUS (wait_status));
282	  retcode = 1;
283	}
284    }
285  else
286    retcode = 1;
287
288  return retcode;
289}
290
291static FILE *
292open_input_stream (char *cmd)
293{
294  if (istream_type == ISTREAM_FILE)
295    {
296      char *fileprefix;
297
298      fileprefix = choose_temp_base ();
299      cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
300      sprintf (cpp_temp_file, "%s.irc", fileprefix);
301      free (fileprefix);
302
303      if (run_cmd (cmd, cpp_temp_file))
304	fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
305
306      cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
307      if (cpp_pipe == NULL)
308	fatal (_("can't open temporary file `%s': %s"),
309	       cpp_temp_file, strerror (errno));
310
311      if (verbose)
312	fprintf (stderr,
313	         _("Using temporary file `%s' to read preprocessor output\n"),
314		 cpp_temp_file);
315    }
316  else
317    {
318      cpp_pipe = popen (cmd, FOPEN_RT);
319      if (cpp_pipe == NULL)
320	fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
321      if (verbose)
322	fprintf (stderr, _("Using popen to read preprocessor output\n"));
323    }
324
325  xatexit (close_input_stream);
326  return cpp_pipe;
327}
328
329/* look for the preprocessor program */
330
331static FILE *
332look_for_default (char *cmd, const char *prefix, int end_prefix,
333		  const char *preprocargs, const char *filename)
334{
335  char *space;
336  int found;
337  struct stat s;
338
339  strcpy (cmd, prefix);
340
341  sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
342  space = strchr (cmd + end_prefix, ' ');
343  if (space)
344    *space = 0;
345
346  if (
347#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
348      strchr (cmd, '\\') ||
349#endif
350      strchr (cmd, '/'))
351    {
352      found = (stat (cmd, &s) == 0
353#ifdef HAVE_EXECUTABLE_SUFFIX
354	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
355#endif
356	       );
357
358      if (! found)
359	{
360	  if (verbose)
361	    fprintf (stderr, _("Tried `%s'\n"), cmd);
362	  return NULL;
363	}
364    }
365
366  strcpy (cmd, prefix);
367
368  sprintf (cmd + end_prefix, "%s %s %s",
369	   DEFAULT_PREPROCESSOR, preprocargs, filename);
370
371  if (verbose)
372    fprintf (stderr, _("Using `%s'\n"), cmd);
373
374  cpp_pipe = open_input_stream (cmd);
375  return cpp_pipe;
376}
377
378/* Read an rc file.  */
379
380struct res_directory *
381read_rc_file (const char *filename, const char *preprocessor,
382	      const char *preprocargs, int language, int use_temp_file)
383{
384  char *cmd;
385
386  istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
387
388  if (preprocargs == NULL)
389    preprocargs = "";
390  if (filename == NULL)
391    filename = "-";
392
393  if (preprocessor)
394    {
395      cmd = xmalloc (strlen (preprocessor)
396		     + strlen (preprocargs)
397		     + strlen (filename)
398		     + 10);
399      sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
400
401      cpp_pipe = open_input_stream (cmd);
402    }
403  else
404    {
405      char *dash, *slash, *cp;
406
407      preprocessor = DEFAULT_PREPROCESSOR;
408
409      cmd = xmalloc (strlen (program_name)
410		     + strlen (preprocessor)
411		     + strlen (preprocargs)
412		     + strlen (filename)
413#ifdef HAVE_EXECUTABLE_SUFFIX
414		     + strlen (EXECUTABLE_SUFFIX)
415#endif
416		     + 10);
417
418
419      dash = slash = 0;
420      for (cp = program_name; *cp; cp++)
421	{
422	  if (*cp == '-')
423	    dash = cp;
424	  if (
425#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
426	      *cp == ':' || *cp == '\\' ||
427#endif
428	      *cp == '/')
429	    {
430	      slash = cp;
431	      dash = 0;
432	    }
433	}
434
435      cpp_pipe = 0;
436
437      if (dash)
438	{
439	  /* First, try looking for a prefixed gcc in the windres
440	     directory, with the same prefix as windres */
441
442	  cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1,
443				       preprocargs, filename);
444	}
445
446      if (slash && !cpp_pipe)
447	{
448	  /* Next, try looking for a gcc in the same directory as
449             that windres */
450
451	  cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1,
452				       preprocargs, filename);
453	}
454
455      if (!cpp_pipe)
456	{
457	  /* Sigh, try the default */
458
459	  cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
460	}
461
462    }
463
464  free (cmd);
465
466  rc_filename = xstrdup (filename);
467  rc_lineno = 1;
468  if (language != -1)
469    rcparse_set_language (language);
470  yyin = cpp_pipe;
471  yyparse ();
472  rcparse_discard_strings ();
473
474  close_input_stream ();
475
476  if (fontdirs != NULL)
477    define_fontdirs ();
478
479  free (rc_filename);
480  rc_filename = NULL;
481
482  return resources;
483}
484
485/* Close the input stream if it is open.  */
486
487static void
488close_input_stream (void)
489{
490  if (istream_type == ISTREAM_FILE)
491    {
492      if (cpp_pipe != NULL)
493	fclose (cpp_pipe);
494
495      if (cpp_temp_file != NULL)
496	{
497	  int errno_save = errno;
498
499	  unlink (cpp_temp_file);
500	  errno = errno_save;
501	  free (cpp_temp_file);
502	}
503    }
504  else
505    {
506      if (cpp_pipe != NULL)
507	pclose (cpp_pipe);
508    }
509
510  /* Since this is also run via xatexit, safeguard.  */
511  cpp_pipe = NULL;
512  cpp_temp_file = NULL;
513}
514
515/* Report an error while reading an rc file.  */
516
517void
518yyerror (const char *msg)
519{
520  fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
521}
522
523/* Issue a warning while reading an rc file.  */
524
525void
526rcparse_warning (const char *msg)
527{
528  fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
529}
530
531/* Die if we get an unexpected end of file.  */
532
533static void
534unexpected_eof (const char *msg)
535{
536  fatal (_("%s: unexpected EOF"), msg);
537}
538
539/* Read a 16 bit word from a file.  The data is assumed to be little
540   endian.  */
541
542static int
543get_word (FILE *e, const char *msg)
544{
545  int b1, b2;
546
547  b1 = getc (e);
548  b2 = getc (e);
549  if (feof (e))
550    unexpected_eof (msg);
551  return ((b2 & 0xff) << 8) | (b1 & 0xff);
552}
553
554/* Read a 32 bit word from a file.  The data is assumed to be little
555   endian.  */
556
557static unsigned long
558get_long (FILE *e, const char *msg)
559{
560  int b1, b2, b3, b4;
561
562  b1 = getc (e);
563  b2 = getc (e);
564  b3 = getc (e);
565  b4 = getc (e);
566  if (feof (e))
567    unexpected_eof (msg);
568  return (((((((b4 & 0xff) << 8)
569	      | (b3 & 0xff)) << 8)
570	    | (b2 & 0xff)) << 8)
571	  | (b1 & 0xff));
572}
573
574/* Read data from a file.  This is a wrapper to do error checking.  */
575
576static void
577get_data (FILE *e, unsigned char *p, unsigned long c, const char *msg)
578{
579  unsigned long got;
580
581  got = fread (p, 1, c, e);
582  if (got == c)
583    return;
584
585  fatal (_("%s: read of %lu returned %lu"), msg, c, got);
586}
587
588/* Define an accelerator resource.  */
589
590void
591define_accelerator (struct res_id id, const struct res_res_info *resinfo,
592		    struct accelerator *data)
593{
594  struct res_resource *r;
595
596  r = define_standard_resource (&resources, RT_ACCELERATOR, id,
597				resinfo->language, 0);
598  r->type = RES_TYPE_ACCELERATOR;
599  r->u.acc = data;
600  r->res_info = *resinfo;
601}
602
603/* Define a bitmap resource.  Bitmap data is stored in a file.  The
604   first 14 bytes of the file are a standard header, which is not
605   included in the resource data.  */
606
607#define BITMAP_SKIP (14)
608
609void
610define_bitmap (struct res_id id, const struct res_res_info *resinfo,
611	       const char *filename)
612{
613  FILE *e;
614  char *real_filename;
615  struct stat s;
616  unsigned char *data;
617  int i;
618  struct res_resource *r;
619
620  e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
621
622  if (stat (real_filename, &s) < 0)
623    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
624	   strerror (errno));
625
626  data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
627
628  for (i = 0; i < BITMAP_SKIP; i++)
629    getc (e);
630
631  get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
632
633  fclose (e);
634  free (real_filename);
635
636  r = define_standard_resource (&resources, RT_BITMAP, id,
637				resinfo->language, 0);
638
639  r->type = RES_TYPE_BITMAP;
640  r->u.data.length = s.st_size - BITMAP_SKIP;
641  r->u.data.data = data;
642  r->res_info = *resinfo;
643}
644
645/* Define a cursor resource.  A cursor file may contain a set of
646   bitmaps, each representing the same cursor at various different
647   resolutions.  They each get written out with a different ID.  The
648   real cursor resource is then a group resource which can be used to
649   select one of the actual cursors.  */
650
651void
652define_cursor (struct res_id id, const struct res_res_info *resinfo,
653	       const char *filename)
654{
655  FILE *e;
656  char *real_filename;
657  int type, count, i;
658  struct icondir *icondirs;
659  int first_cursor;
660  struct res_resource *r;
661  struct group_cursor *first, **pp;
662
663  e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
664
665  /* A cursor file is basically an icon file.  The start of the file
666     is a three word structure.  The first word is ignored.  The
667     second word is the type of data.  The third word is the number of
668     entries.  */
669
670  get_word (e, real_filename);
671  type = get_word (e, real_filename);
672  count = get_word (e, real_filename);
673  if (type != 2)
674    fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
675
676  /* Read in the icon directory entries.  */
677
678  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
679
680  for (i = 0; i < count; i++)
681    {
682      icondirs[i].width = getc (e);
683      icondirs[i].height = getc (e);
684      icondirs[i].colorcount = getc (e);
685      getc (e);
686      icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
687      icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
688      icondirs[i].bytes = get_long (e, real_filename);
689      icondirs[i].offset = get_long (e, real_filename);
690
691      if (feof (e))
692	unexpected_eof (real_filename);
693    }
694
695  /* Define each cursor as a unique resource.  */
696
697  first_cursor = cursors;
698
699  for (i = 0; i < count; i++)
700    {
701      unsigned char *data;
702      struct res_id name;
703      struct cursor *c;
704
705      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
706	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
707	       icondirs[i].offset, strerror (errno));
708
709      data = (unsigned char *) res_alloc (icondirs[i].bytes);
710
711      get_data (e, data, icondirs[i].bytes, real_filename);
712
713      c = (struct cursor *) res_alloc (sizeof *c);
714      c->xhotspot = icondirs[i].u.cursor.xhotspot;
715      c->yhotspot = icondirs[i].u.cursor.yhotspot;
716      c->length = icondirs[i].bytes;
717      c->data = data;
718
719      ++cursors;
720
721      name.named = 0;
722      name.u.id = cursors;
723
724      r = define_standard_resource (&resources, RT_CURSOR, name,
725				    resinfo->language, 0);
726      r->type = RES_TYPE_CURSOR;
727      r->u.cursor = c;
728      r->res_info = *resinfo;
729    }
730
731  fclose (e);
732  free (real_filename);
733
734  /* Define a cursor group resource.  */
735
736  first = NULL;
737  pp = &first;
738  for (i = 0; i < count; i++)
739    {
740      struct group_cursor *cg;
741
742      cg = (struct group_cursor *) res_alloc (sizeof *cg);
743      cg->next = NULL;
744      cg->width = icondirs[i].width;
745      cg->height = 2 * icondirs[i].height;
746
747      /* FIXME: What should these be set to?  */
748      cg->planes = 1;
749      cg->bits = 1;
750
751      cg->bytes = icondirs[i].bytes + 4;
752      cg->index = first_cursor + i + 1;
753
754      *pp = cg;
755      pp = &(*pp)->next;
756    }
757
758  free (icondirs);
759
760  r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
761				resinfo->language, 0);
762  r->type = RES_TYPE_GROUP_CURSOR;
763  r->u.group_cursor = first;
764  r->res_info = *resinfo;
765}
766
767/* Define a dialog resource.  */
768
769void
770define_dialog (struct res_id id, const struct res_res_info *resinfo,
771	       const struct dialog *dialog)
772{
773  struct dialog *copy;
774  struct res_resource *r;
775
776  copy = (struct dialog *) res_alloc (sizeof *copy);
777  *copy = *dialog;
778
779  r = define_standard_resource (&resources, RT_DIALOG, id,
780				resinfo->language, 0);
781  r->type = RES_TYPE_DIALOG;
782  r->u.dialog = copy;
783  r->res_info = *resinfo;
784}
785
786/* Define a dialog control.  This does not define a resource, but
787   merely allocates and fills in a structure.  */
788
789struct dialog_control *
790define_control (const struct res_id iid, unsigned long id, unsigned long x,
791		unsigned long y, unsigned long width, unsigned long height,
792		unsigned long class, unsigned long style,
793		unsigned long exstyle)
794{
795  struct dialog_control *n;
796
797  n = (struct dialog_control *) res_alloc (sizeof *n);
798  n->next = NULL;
799  n->id = id;
800  n->style = style;
801  n->exstyle = exstyle;
802  n->x = x;
803  n->y = y;
804  n->width = width;
805  n->height = height;
806  n->class.named = 0;
807  n->class.u.id = class;
808  n->text = iid;
809  n->data = NULL;
810  n->help = 0;
811
812  return n;
813}
814
815struct dialog_control *
816define_icon_control (struct res_id iid, unsigned long id, unsigned long x,
817		     unsigned long y, unsigned long style,
818		     unsigned long exstyle, unsigned long help,
819		     struct rcdata_item *data, struct dialog_ex *ex)
820{
821  struct dialog_control *n;
822  struct res_id tid;
823
824  if (style == 0)
825    style = SS_ICON | WS_CHILD | WS_VISIBLE;
826  res_string_to_id (&tid, "");
827  n = define_control (tid, id, x, y, 0, 0, CTL_STATIC, style, exstyle);
828  n->text = iid;
829  if (help && !ex)
830    rcparse_warning (_("help ID requires DIALOGEX"));
831  if (data && !ex)
832    rcparse_warning (_("control data requires DIALOGEX"));
833  n->help = help;
834  n->data = data;
835
836  return n;
837}
838
839/* Define a font resource.  */
840
841void
842define_font (struct res_id id, const struct res_res_info *resinfo,
843	     const char *filename)
844{
845  FILE *e;
846  char *real_filename;
847  struct stat s;
848  unsigned char *data;
849  struct res_resource *r;
850  long offset;
851  long fontdatalength;
852  unsigned char *fontdata;
853  struct fontdir *fd;
854  const char *device, *face;
855  struct fontdir **pp;
856
857  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
858
859  if (stat (real_filename, &s) < 0)
860    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
861	   strerror (errno));
862
863  data = (unsigned char *) res_alloc (s.st_size);
864
865  get_data (e, data, s.st_size, real_filename);
866
867  fclose (e);
868  free (real_filename);
869
870  r = define_standard_resource (&resources, RT_FONT, id,
871				resinfo->language, 0);
872
873  r->type = RES_TYPE_FONT;
874  r->u.data.length = s.st_size;
875  r->u.data.data = data;
876  r->res_info = *resinfo;
877
878  /* For each font resource, we must add an entry in the FONTDIR
879     resource.  The FONTDIR resource includes some strings in the font
880     file.  To find them, we have to do some magic on the data we have
881     read.  */
882
883  offset = ((((((data[47] << 8)
884		| data[46]) << 8)
885	      | data[45]) << 8)
886	    | data[44]);
887  if (offset > 0 && offset < s.st_size)
888    device = (char *) data + offset;
889  else
890    device = "";
891
892  offset = ((((((data[51] << 8)
893		| data[50]) << 8)
894	      | data[49]) << 8)
895	    | data[48]);
896  if (offset > 0 && offset < s.st_size)
897    face = (char *) data + offset;
898  else
899    face = "";
900
901  ++fonts;
902
903  fontdatalength = 58 + strlen (device) + strlen (face);
904  fontdata = (unsigned char *) res_alloc (fontdatalength);
905  memcpy (fontdata, data, 56);
906  strcpy ((char *) fontdata + 56, device);
907  strcpy ((char *) fontdata + 57 + strlen (device), face);
908
909  fd = (struct fontdir *) res_alloc (sizeof *fd);
910  fd->next = NULL;
911  fd->index = fonts;
912  fd->length = fontdatalength;
913  fd->data = fontdata;
914
915  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
916    ;
917  *pp = fd;
918
919  /* For the single fontdirs resource, we always use the resource
920     information of the last font.  I don't know what else to do.  */
921  fontdirs_resinfo = *resinfo;
922}
923
924/* Define the fontdirs resource.  This is called after the entire rc
925   file has been parsed, if any font resources were seen.  */
926
927static void
928define_fontdirs (void)
929{
930  struct res_resource *r;
931  struct res_id id;
932
933  id.named = 0;
934  id.u.id = 1;
935
936  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
937
938  r->type = RES_TYPE_FONTDIR;
939  r->u.fontdir = fontdirs;
940  r->res_info = fontdirs_resinfo;
941}
942
943/* Define an icon resource.  An icon file may contain a set of
944   bitmaps, each representing the same icon at various different
945   resolutions.  They each get written out with a different ID.  The
946   real icon resource is then a group resource which can be used to
947   select one of the actual icon bitmaps.  */
948
949void
950define_icon (struct res_id id, const struct res_res_info *resinfo,
951	     const char *filename)
952{
953  FILE *e;
954  char *real_filename;
955  int type, count, i;
956  struct icondir *icondirs;
957  int first_icon;
958  struct res_resource *r;
959  struct group_icon *first, **pp;
960
961  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
962
963  /* The start of an icon file is a three word structure.  The first
964     word is ignored.  The second word is the type of data.  The third
965     word is the number of entries.  */
966
967  get_word (e, real_filename);
968  type = get_word (e, real_filename);
969  count = get_word (e, real_filename);
970  if (type != 1)
971    fatal (_("icon file `%s' does not contain icon data"), real_filename);
972
973  /* Read in the icon directory entries.  */
974
975  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
976
977  for (i = 0; i < count; i++)
978    {
979      icondirs[i].width = getc (e);
980      icondirs[i].height = getc (e);
981      icondirs[i].colorcount = getc (e);
982      getc (e);
983      icondirs[i].u.icon.planes = get_word (e, real_filename);
984      icondirs[i].u.icon.bits = get_word (e, real_filename);
985      icondirs[i].bytes = get_long (e, real_filename);
986      icondirs[i].offset = get_long (e, real_filename);
987
988      if (feof (e))
989	unexpected_eof (real_filename);
990    }
991
992  /* Define each icon as a unique resource.  */
993
994  first_icon = icons;
995
996  for (i = 0; i < count; i++)
997    {
998      unsigned char *data;
999      struct res_id name;
1000
1001      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1002	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1003	       icondirs[i].offset, strerror (errno));
1004
1005      data = (unsigned char *) res_alloc (icondirs[i].bytes);
1006
1007      get_data (e, data, icondirs[i].bytes, real_filename);
1008
1009      ++icons;
1010
1011      name.named = 0;
1012      name.u.id = icons;
1013
1014      r = define_standard_resource (&resources, RT_ICON, name,
1015				    resinfo->language, 0);
1016      r->type = RES_TYPE_ICON;
1017      r->u.data.length = icondirs[i].bytes;
1018      r->u.data.data = data;
1019      r->res_info = *resinfo;
1020    }
1021
1022  fclose (e);
1023  free (real_filename);
1024
1025  /* Define an icon group resource.  */
1026
1027  first = NULL;
1028  pp = &first;
1029  for (i = 0; i < count; i++)
1030    {
1031      struct group_icon *cg;
1032
1033      /* For some reason, at least in some files the planes and bits
1034         are zero.  We instead set them from the color.  This is
1035         copied from rcl.  */
1036
1037      cg = (struct group_icon *) res_alloc (sizeof *cg);
1038      cg->next = NULL;
1039      cg->width = icondirs[i].width;
1040      cg->height = icondirs[i].height;
1041      cg->colors = icondirs[i].colorcount;
1042
1043      if (icondirs[i].u.icon.planes)
1044	cg->planes = icondirs[i].u.icon.planes;
1045      else
1046	cg->planes = 1;
1047
1048      if (icondirs[i].u.icon.bits)
1049	cg->bits = icondirs[i].u.icon.bits;
1050      else
1051	{
1052	  cg->bits = 0;
1053
1054	  while ((1L << cg->bits) < cg->colors)
1055	    ++cg->bits;
1056	}
1057
1058      cg->bytes = icondirs[i].bytes;
1059      cg->index = first_icon + i + 1;
1060
1061      *pp = cg;
1062      pp = &(*pp)->next;
1063    }
1064
1065  free (icondirs);
1066
1067  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1068				resinfo->language, 0);
1069  r->type = RES_TYPE_GROUP_ICON;
1070  r->u.group_icon = first;
1071  r->res_info = *resinfo;
1072}
1073
1074/* Define a menu resource.  */
1075
1076void
1077define_menu (struct res_id id, const struct res_res_info *resinfo,
1078	     struct menuitem *menuitems)
1079{
1080  struct menu *m;
1081  struct res_resource *r;
1082
1083  m = (struct menu *) res_alloc (sizeof *m);
1084  m->items = menuitems;
1085  m->help = 0;
1086
1087  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1088  r->type = RES_TYPE_MENU;
1089  r->u.menu = m;
1090  r->res_info = *resinfo;
1091}
1092
1093/* Define a menu item.  This does not define a resource, but merely
1094   allocates and fills in a structure.  */
1095
1096struct menuitem *
1097define_menuitem (const char *text, int menuid, unsigned long type,
1098		 unsigned long state, unsigned long help,
1099		 struct menuitem *menuitems)
1100{
1101  struct menuitem *mi;
1102
1103  mi = (struct menuitem *) res_alloc (sizeof *mi);
1104  mi->next = NULL;
1105  mi->type = type;
1106  mi->state = state;
1107  mi->id = menuid;
1108  if (text == NULL)
1109    mi->text = NULL;
1110  else
1111    unicode_from_ascii ((int *) NULL, &mi->text, text);
1112  mi->help = help;
1113  mi->popup = menuitems;
1114  return mi;
1115}
1116
1117/* Define a messagetable resource.  */
1118
1119void
1120define_messagetable (struct res_id id, const struct res_res_info *resinfo,
1121		     const char *filename)
1122{
1123  FILE *e;
1124  char *real_filename;
1125  struct stat s;
1126  unsigned char *data;
1127  struct res_resource *r;
1128
1129  e = open_file_search (filename, FOPEN_RB, "messagetable file",
1130			&real_filename);
1131
1132  if (stat (real_filename, &s) < 0)
1133    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1134	   strerror (errno));
1135
1136  data = (unsigned char *) res_alloc (s.st_size);
1137
1138  get_data (e, data, s.st_size, real_filename);
1139
1140  fclose (e);
1141  free (real_filename);
1142
1143  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1144				resinfo->language, 0);
1145
1146  r->type = RES_TYPE_MESSAGETABLE;
1147  r->u.data.length = s.st_size;
1148  r->u.data.data = data;
1149  r->res_info = *resinfo;
1150}
1151
1152/* Define an rcdata resource.  */
1153
1154void
1155define_rcdata (struct res_id id, const struct res_res_info *resinfo,
1156	       struct rcdata_item *data)
1157{
1158  struct res_resource *r;
1159
1160  r = define_standard_resource (&resources, RT_RCDATA, id,
1161				resinfo->language, 0);
1162  r->type = RES_TYPE_RCDATA;
1163  r->u.rcdata = data;
1164  r->res_info = *resinfo;
1165}
1166
1167/* Create an rcdata item holding a string.  */
1168
1169struct rcdata_item *
1170define_rcdata_string (const char *string, unsigned long len)
1171{
1172  struct rcdata_item *ri;
1173  char *s;
1174
1175  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1176  ri->next = NULL;
1177  ri->type = RCDATA_STRING;
1178  ri->u.string.length = len;
1179  s = (char *) res_alloc (len);
1180  memcpy (s, string, len);
1181  ri->u.string.s = s;
1182
1183  return ri;
1184}
1185
1186/* Create an rcdata item holding a number.  */
1187
1188struct rcdata_item *
1189define_rcdata_number (unsigned long val, int dword)
1190{
1191  struct rcdata_item *ri;
1192
1193  ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1194  ri->next = NULL;
1195  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1196  ri->u.word = val;
1197
1198  return ri;
1199}
1200
1201/* Define a stringtable resource.  This is called for each string
1202   which appears in a STRINGTABLE statement.  */
1203
1204void
1205define_stringtable (const struct res_res_info *resinfo,
1206		    unsigned long stringid, const char *string)
1207{
1208  struct res_id id;
1209  struct res_resource *r;
1210
1211  id.named = 0;
1212  id.u.id = (stringid >> 4) + 1;
1213  r = define_standard_resource (&resources, RT_STRING, id,
1214				resinfo->language, 1);
1215
1216  if (r->type == RES_TYPE_UNINITIALIZED)
1217    {
1218      int i;
1219
1220      r->type = RES_TYPE_STRINGTABLE;
1221      r->u.stringtable = ((struct stringtable *)
1222			  res_alloc (sizeof (struct stringtable)));
1223      for (i = 0; i < 16; i++)
1224	{
1225	  r->u.stringtable->strings[i].length = 0;
1226	  r->u.stringtable->strings[i].string = NULL;
1227	}
1228
1229      r->res_info = *resinfo;
1230    }
1231
1232  unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
1233		      &r->u.stringtable->strings[stringid & 0xf].string,
1234		      string);
1235}
1236
1237/* Define a user data resource where the data is in the rc file.  */
1238
1239void
1240define_user_data (struct res_id id, struct res_id type,
1241		  const struct res_res_info *resinfo,
1242		  struct rcdata_item *data)
1243{
1244  struct res_id ids[3];
1245  struct res_resource *r;
1246
1247  ids[0] = type;
1248  ids[1] = id;
1249  ids[2].named = 0;
1250  ids[2].u.id = resinfo->language;
1251
1252  r = define_resource (&resources, 3, ids, 0);
1253  r->type = RES_TYPE_USERDATA;
1254  r->u.userdata = data;
1255  r->res_info = *resinfo;
1256}
1257
1258/* Define a user data resource where the data is in a file.  */
1259
1260void
1261define_user_file (struct res_id id, struct res_id type,
1262		  const struct res_res_info *resinfo, const char *filename)
1263{
1264  FILE *e;
1265  char *real_filename;
1266  struct stat s;
1267  unsigned char *data;
1268  struct res_id ids[3];
1269  struct res_resource *r;
1270
1271  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
1272
1273  if (stat (real_filename, &s) < 0)
1274    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1275	   strerror (errno));
1276
1277  data = (unsigned char *) res_alloc (s.st_size);
1278
1279  get_data (e, data, s.st_size, real_filename);
1280
1281  fclose (e);
1282  free (real_filename);
1283
1284  ids[0] = type;
1285  ids[1] = id;
1286  ids[2].named = 0;
1287  ids[2].u.id = resinfo->language;
1288
1289  r = define_resource (&resources, 3, ids, 0);
1290  r->type = RES_TYPE_USERDATA;
1291  r->u.userdata = ((struct rcdata_item *)
1292		   res_alloc (sizeof (struct rcdata_item)));
1293  r->u.userdata->next = NULL;
1294  r->u.userdata->type = RCDATA_BUFFER;
1295  r->u.userdata->u.buffer.length = s.st_size;
1296  r->u.userdata->u.buffer.data = data;
1297  r->res_info = *resinfo;
1298}
1299
1300/* Define a versioninfo resource.  */
1301
1302void
1303define_versioninfo (struct res_id id, int language,
1304		    struct fixed_versioninfo *fixedverinfo,
1305		    struct ver_info *verinfo)
1306{
1307  struct res_resource *r;
1308
1309  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1310  r->type = RES_TYPE_VERSIONINFO;
1311  r->u.versioninfo = ((struct versioninfo *)
1312		      res_alloc (sizeof (struct versioninfo)));
1313  r->u.versioninfo->fixed = fixedverinfo;
1314  r->u.versioninfo->var = verinfo;
1315  r->res_info.language = language;
1316}
1317
1318/* Add string version info to a list of version information.  */
1319
1320struct ver_info *
1321append_ver_stringfileinfo (struct ver_info *verinfo, const char *language,
1322			   struct ver_stringinfo *strings)
1323{
1324  struct ver_info *vi, **pp;
1325
1326  vi = (struct ver_info *) res_alloc (sizeof *vi);
1327  vi->next = NULL;
1328  vi->type = VERINFO_STRING;
1329  unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
1330  vi->u.string.strings = strings;
1331
1332  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1333    ;
1334  *pp = vi;
1335
1336  return verinfo;
1337}
1338
1339/* Add variable version info to a list of version information.  */
1340
1341struct ver_info *
1342append_ver_varfileinfo (struct ver_info *verinfo, const char *key,
1343			struct ver_varinfo *var)
1344{
1345  struct ver_info *vi, **pp;
1346
1347  vi = (struct ver_info *) res_alloc (sizeof *vi);
1348  vi->next = NULL;
1349  vi->type = VERINFO_VAR;
1350  unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
1351  vi->u.var.var = var;
1352
1353  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1354    ;
1355  *pp = vi;
1356
1357  return verinfo;
1358}
1359
1360/* Append version string information to a list.  */
1361
1362struct ver_stringinfo *
1363append_verval (struct ver_stringinfo *strings, const char *key,
1364	       const char *value)
1365{
1366  struct ver_stringinfo *vs, **pp;
1367
1368  vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
1369  vs->next = NULL;
1370  unicode_from_ascii ((int *) NULL, &vs->key, key);
1371  unicode_from_ascii ((int *) NULL, &vs->value, value);
1372
1373  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1374    ;
1375  *pp = vs;
1376
1377  return strings;
1378}
1379
1380/* Append version variable information to a list.  */
1381
1382struct ver_varinfo *
1383append_vertrans (struct ver_varinfo *var, unsigned long language,
1384		 unsigned long charset)
1385{
1386  struct ver_varinfo *vv, **pp;
1387
1388  vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
1389  vv->next = NULL;
1390  vv->language = language;
1391  vv->charset = charset;
1392
1393  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1394    ;
1395  *pp = vv;
1396
1397  return var;
1398}
1399
1400/* Local functions used to write out an rc file.  */
1401
1402static void indent (FILE *, int);
1403static void write_rc_directory
1404  (FILE *, const struct res_directory *, const struct res_id *,
1405   const struct res_id *, int *, int);
1406static void write_rc_subdir
1407  (FILE *, const struct res_entry *, const struct res_id *,
1408   const struct res_id *, int *, int);
1409static void write_rc_resource
1410  (FILE *, const struct res_id *, const struct res_id *,
1411   const struct res_resource *, int *);
1412static void write_rc_accelerators (FILE *, const struct accelerator *);
1413static void write_rc_cursor (FILE *, const struct cursor *);
1414static void write_rc_group_cursor (FILE *, const struct group_cursor *);
1415static void write_rc_dialog (FILE *, const struct dialog *);
1416static void write_rc_dialog_control (FILE *, const struct dialog_control *);
1417static void write_rc_fontdir (FILE *, const struct fontdir *);
1418static void write_rc_group_icon (FILE *, const struct group_icon *);
1419static void write_rc_menu (FILE *, const struct menu *, int);
1420static void write_rc_menuitems (FILE *, const struct menuitem *, int, int);
1421static void write_rc_rcdata (FILE *, const struct rcdata_item *, int);
1422static void write_rc_stringtable
1423  (FILE *, const struct res_id *, const struct stringtable *);
1424static void write_rc_versioninfo (FILE *, const struct versioninfo *);
1425static void write_rc_filedata (FILE *, unsigned long, const unsigned char *);
1426
1427/* Indent a given number of spaces.  */
1428
1429static void
1430indent (FILE *e, int c)
1431{
1432  int i;
1433
1434  for (i = 0; i < c; i++)
1435    putc (' ', e);
1436}
1437
1438/* Dump the resources we have read in the format of an rc file.
1439
1440   Actually, we don't use the format of an rc file, because it's way
1441   too much of a pain--for example, we'd have to write icon resources
1442   into a file and refer to that file.  We just generate a readable
1443   format that kind of looks like an rc file, and is useful for
1444   understanding the contents of a resource file.  Someday we may want
1445   to generate an rc file which the rc compiler can read; if that day
1446   comes, this code will have to be fixed up.  */
1447
1448void
1449write_rc_file (const char *filename, const struct res_directory *resources)
1450{
1451  FILE *e;
1452  int language;
1453
1454  if (filename == NULL)
1455    e = stdout;
1456  else
1457    {
1458      e = fopen (filename, FOPEN_WT);
1459      if (e == NULL)
1460	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1461    }
1462
1463  language = -1;
1464  write_rc_directory (e, resources, (const struct res_id *) NULL,
1465		      (const struct res_id *) NULL, &language, 1);
1466}
1467
1468/* Write out a directory.  E is the file to write to.  RD is the
1469   directory.  TYPE is a pointer to the level 1 ID which serves as the
1470   resource type.  NAME is a pointer to the level 2 ID which serves as
1471   an individual resource name.  LANGUAGE is a pointer to the current
1472   language.  LEVEL is the level in the tree.  */
1473
1474static void
1475write_rc_directory (FILE *e, const struct res_directory *rd,
1476		    const struct res_id *type, const struct res_id *name,
1477		    int *language, int level)
1478{
1479  const struct res_entry *re;
1480
1481  /* Print out some COFF information that rc files can't represent.  */
1482
1483  if (rd->time != 0)
1484    fprintf (e, "// Time stamp: %lu\n", rd->time);
1485  if (rd->characteristics != 0)
1486    fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
1487  if (rd->major != 0 || rd->minor != 0)
1488    fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
1489
1490  for (re = rd->entries;  re != NULL; re = re->next)
1491    {
1492      switch (level)
1493	{
1494	case 1:
1495	  /* If we're at level 1, the key of this resource is the
1496             type.  This normally duplicates the information we have
1497             stored with the resource itself, but we need to remember
1498             the type if this is a user define resource type.  */
1499	  type = &re->id;
1500	  break;
1501
1502	case 2:
1503	  /* If we're at level 2, the key of this resource is the name
1504	     we are going to use in the rc printout.  */
1505	  name = &re->id;
1506	  break;
1507
1508	case 3:
1509	  /* If we're at level 3, then this key represents a language.
1510	     Use it to update the current language.  */
1511	  if (! re->id.named
1512	      && re->id.u.id != (unsigned long) (unsigned int) *language
1513	      && (re->id.u.id & 0xffff) == re->id.u.id)
1514	    {
1515	      fprintf (e, "LANGUAGE %lu, %lu\n",
1516		       re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
1517		       (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
1518	      *language = re->id.u.id;
1519	    }
1520	  break;
1521
1522	default:
1523	  break;
1524	}
1525
1526      if (re->subdir)
1527	write_rc_subdir (e, re, type, name, language, level);
1528      else
1529	{
1530	  if (level == 3)
1531	    {
1532	      /* This is the normal case: the three levels are
1533                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
1534                 2, and represents the name to use.  We probably just
1535                 set LANGUAGE, and it will probably match what the
1536                 resource itself records if anything.  */
1537	      write_rc_resource (e, type, name, re->u.res, language);
1538	    }
1539	  else
1540	    {
1541	      fprintf (e, "// Resource at unexpected level %d\n", level);
1542	      write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1543				 language);
1544	    }
1545	}
1546    }
1547}
1548
1549/* Write out a subdirectory entry.  E is the file to write to.  RE is
1550   the subdirectory entry.  TYPE and NAME are pointers to higher level
1551   IDs, or NULL.  LANGUAGE is a pointer to the current language.
1552   LEVEL is the level in the tree.  */
1553
1554static void
1555write_rc_subdir (FILE *e, const struct res_entry *re,
1556		 const struct res_id *type, const struct res_id *name,
1557		 int *language, int level)
1558{
1559  fprintf (e, "\n");
1560  switch (level)
1561    {
1562    case 1:
1563      fprintf (e, "// Type: ");
1564      if (re->id.named)
1565	res_id_print (e, re->id, 1);
1566      else
1567	{
1568	  const char *s;
1569
1570	  switch (re->id.u.id)
1571	    {
1572	    case RT_CURSOR: s = "cursor"; break;
1573	    case RT_BITMAP: s = "bitmap"; break;
1574	    case RT_ICON: s = "icon"; break;
1575	    case RT_MENU: s = "menu"; break;
1576	    case RT_DIALOG: s = "dialog"; break;
1577	    case RT_STRING: s = "stringtable"; break;
1578	    case RT_FONTDIR: s = "fontdir"; break;
1579	    case RT_FONT: s = "font"; break;
1580	    case RT_ACCELERATOR: s = "accelerators"; break;
1581	    case RT_RCDATA: s = "rcdata"; break;
1582	    case RT_MESSAGETABLE: s = "messagetable"; break;
1583	    case RT_GROUP_CURSOR: s = "group cursor"; break;
1584	    case RT_GROUP_ICON: s = "group icon"; break;
1585	    case RT_VERSION: s = "version"; break;
1586	    case RT_DLGINCLUDE: s = "dlginclude"; break;
1587	    case RT_PLUGPLAY: s = "plugplay"; break;
1588	    case RT_VXD: s = "vxd"; break;
1589	    case RT_ANICURSOR: s = "anicursor"; break;
1590	    case RT_ANIICON: s = "aniicon"; break;
1591	    default: s = NULL; break;
1592	    }
1593
1594	  if (s != NULL)
1595	    fprintf (e, "%s", s);
1596	  else
1597	    res_id_print (e, re->id, 1);
1598	}
1599      fprintf (e, "\n");
1600      break;
1601
1602    case 2:
1603      fprintf (e, "// Name: ");
1604      res_id_print (e, re->id, 1);
1605      fprintf (e, "\n");
1606      break;
1607
1608    case 3:
1609      fprintf (e, "// Language: ");
1610      res_id_print (e, re->id, 1);
1611      fprintf (e, "\n");
1612      break;
1613
1614    default:
1615      fprintf (e, "// Level %d: ", level);
1616      res_id_print (e, re->id, 1);
1617      fprintf (e, "\n");
1618    }
1619
1620  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1621}
1622
1623/* Write out a single resource.  E is the file to write to.  TYPE is a
1624   pointer to the type of the resource.  NAME is a pointer to the name
1625   of the resource; it will be NULL if there is a level mismatch.  RES
1626   is the resource data.  LANGUAGE is a pointer to the current
1627   language.  */
1628
1629static void
1630write_rc_resource (FILE *e, const struct res_id *type,
1631		   const struct res_id *name, const struct res_resource *res,
1632		   int *language)
1633{
1634  const char *s;
1635  int rt;
1636  int menuex = 0;
1637
1638  fprintf (e, "\n");
1639
1640  switch (res->type)
1641    {
1642    default:
1643      abort ();
1644
1645    case RES_TYPE_ACCELERATOR:
1646      s = "ACCELERATOR";
1647      rt = RT_ACCELERATOR;
1648      break;
1649
1650    case RES_TYPE_BITMAP:
1651      s = "BITMAP";
1652      rt = RT_BITMAP;
1653      break;
1654
1655    case RES_TYPE_CURSOR:
1656      s = "CURSOR";
1657      rt = RT_CURSOR;
1658      break;
1659
1660    case RES_TYPE_GROUP_CURSOR:
1661      s = "GROUP_CURSOR";
1662      rt = RT_GROUP_CURSOR;
1663      break;
1664
1665    case RES_TYPE_DIALOG:
1666      if (extended_dialog (res->u.dialog))
1667	s = "DIALOGEX";
1668      else
1669	s = "DIALOG";
1670      rt = RT_DIALOG;
1671      break;
1672
1673    case RES_TYPE_FONT:
1674      s = "FONT";
1675      rt = RT_FONT;
1676      break;
1677
1678    case RES_TYPE_FONTDIR:
1679      s = "FONTDIR";
1680      rt = RT_FONTDIR;
1681      break;
1682
1683    case RES_TYPE_ICON:
1684      s = "ICON";
1685      rt = RT_ICON;
1686      break;
1687
1688    case RES_TYPE_GROUP_ICON:
1689      s = "GROUP_ICON";
1690      rt = RT_GROUP_ICON;
1691      break;
1692
1693    case RES_TYPE_MENU:
1694      if (extended_menu (res->u.menu))
1695	{
1696	  s = "MENUEX";
1697	  menuex = 1;
1698	}
1699      else
1700	{
1701	  s = "MENU";
1702	  menuex = 0;
1703	}
1704      rt = RT_MENU;
1705      break;
1706
1707    case RES_TYPE_MESSAGETABLE:
1708      s = "MESSAGETABLE";
1709      rt = RT_MESSAGETABLE;
1710      break;
1711
1712    case RES_TYPE_RCDATA:
1713      s = "RCDATA";
1714      rt = RT_RCDATA;
1715      break;
1716
1717    case RES_TYPE_STRINGTABLE:
1718      s = "STRINGTABLE";
1719      rt = RT_STRING;
1720      break;
1721
1722    case RES_TYPE_USERDATA:
1723      s = NULL;
1724      rt = 0;
1725      break;
1726
1727    case RES_TYPE_VERSIONINFO:
1728      s = "VERSIONINFO";
1729      rt = RT_VERSION;
1730      break;
1731    }
1732
1733  if (rt != 0
1734      && type != NULL
1735      && (type->named || type->u.id != (unsigned long) rt))
1736    {
1737      fprintf (e, "// Unexpected resource type mismatch: ");
1738      res_id_print (e, *type, 1);
1739      fprintf (e, " != %d", rt);
1740    }
1741
1742  if (res->coff_info.codepage != 0)
1743    fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1744  if (res->coff_info.reserved != 0)
1745    fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1746
1747  if (name != NULL)
1748    res_id_print (e, *name, 0);
1749  else
1750    fprintf (e, "??Unknown-Name??");
1751
1752  fprintf (e, " ");
1753  if (s != NULL)
1754    fprintf (e, "%s", s);
1755  else if (type != NULL)
1756    res_id_print (e, *type, 0);
1757  else
1758    fprintf (e, "??Unknown-Type??");
1759
1760  if (res->res_info.memflags != 0)
1761    {
1762      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1763	fprintf (e, " MOVEABLE");
1764      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1765	fprintf (e, " PURE");
1766      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1767	fprintf (e, " PRELOAD");
1768      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1769	fprintf (e, " DISCARDABLE");
1770    }
1771
1772  if (res->type == RES_TYPE_DIALOG)
1773    {
1774      fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1775	       res->u.dialog->width, res->u.dialog->height);
1776      if (res->u.dialog->ex != NULL
1777	  && res->u.dialog->ex->help != 0)
1778	fprintf (e, ", %lu", res->u.dialog->ex->help);
1779    }
1780
1781  fprintf (e, "\n");
1782
1783  if ((res->res_info.language != 0 && res->res_info.language != *language)
1784      || res->res_info.characteristics != 0
1785      || res->res_info.version != 0)
1786    {
1787      int modifiers;
1788
1789      switch (res->type)
1790	{
1791	case RES_TYPE_ACCELERATOR:
1792	case RES_TYPE_DIALOG:
1793	case RES_TYPE_MENU:
1794	case RES_TYPE_RCDATA:
1795	case RES_TYPE_STRINGTABLE:
1796	  modifiers = 1;
1797	  break;
1798
1799	default:
1800	  modifiers = 0;
1801	  break;
1802	}
1803
1804      if (res->res_info.language != 0 && res->res_info.language != *language)
1805	fprintf (e, "%sLANGUAGE %d, %d\n",
1806		 modifiers ? "// " : "",
1807		 res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
1808		 (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
1809      if (res->res_info.characteristics != 0)
1810	fprintf (e, "%sCHARACTERISTICS %lu\n",
1811		 modifiers ? "// " : "",
1812		 res->res_info.characteristics);
1813      if (res->res_info.version != 0)
1814	fprintf (e, "%sVERSION %lu\n",
1815		 modifiers ? "// " : "",
1816		 res->res_info.version);
1817    }
1818
1819  switch (res->type)
1820    {
1821    default:
1822      abort ();
1823
1824    case RES_TYPE_ACCELERATOR:
1825      write_rc_accelerators (e, res->u.acc);
1826      break;
1827
1828    case RES_TYPE_CURSOR:
1829      write_rc_cursor (e, res->u.cursor);
1830      break;
1831
1832    case RES_TYPE_GROUP_CURSOR:
1833      write_rc_group_cursor (e, res->u.group_cursor);
1834      break;
1835
1836    case RES_TYPE_DIALOG:
1837      write_rc_dialog (e, res->u.dialog);
1838      break;
1839
1840    case RES_TYPE_FONTDIR:
1841      write_rc_fontdir (e, res->u.fontdir);
1842      break;
1843
1844    case RES_TYPE_GROUP_ICON:
1845      write_rc_group_icon (e, res->u.group_icon);
1846      break;
1847
1848    case RES_TYPE_MENU:
1849      write_rc_menu (e, res->u.menu, menuex);
1850      break;
1851
1852    case RES_TYPE_RCDATA:
1853      write_rc_rcdata (e, res->u.rcdata, 0);
1854      break;
1855
1856    case RES_TYPE_STRINGTABLE:
1857      write_rc_stringtable (e, name, res->u.stringtable);
1858      break;
1859
1860    case RES_TYPE_USERDATA:
1861      write_rc_rcdata (e, res->u.userdata, 0);
1862      break;
1863
1864    case RES_TYPE_VERSIONINFO:
1865      write_rc_versioninfo (e, res->u.versioninfo);
1866      break;
1867
1868    case RES_TYPE_BITMAP:
1869    case RES_TYPE_FONT:
1870    case RES_TYPE_ICON:
1871    case RES_TYPE_MESSAGETABLE:
1872      write_rc_filedata (e, res->u.data.length, res->u.data.data);
1873      break;
1874    }
1875}
1876
1877/* Write out accelerator information.  */
1878
1879static void
1880write_rc_accelerators (FILE *e, const struct accelerator *accelerators)
1881{
1882  const struct accelerator *acc;
1883
1884  fprintf (e, "BEGIN\n");
1885  for (acc = accelerators; acc != NULL; acc = acc->next)
1886    {
1887      int printable;
1888
1889      fprintf (e, "  ");
1890
1891      if ((acc->key & 0x7f) == acc->key
1892	  && ISPRINT (acc->key)
1893	  && (acc->flags & ACC_VIRTKEY) == 0)
1894	{
1895	  fprintf (e, "\"%c\"", acc->key);
1896	  printable = 1;
1897	}
1898      else
1899	{
1900	  fprintf (e, "%d", acc->key);
1901	  printable = 0;
1902	}
1903
1904      fprintf (e, ", %d", acc->id);
1905
1906      if (! printable)
1907	{
1908	  if ((acc->flags & ACC_VIRTKEY) != 0)
1909	    fprintf (e, ", VIRTKEY");
1910	  else
1911	    fprintf (e, ", ASCII");
1912	}
1913
1914      if ((acc->flags & ACC_SHIFT) != 0)
1915	fprintf (e, ", SHIFT");
1916      if ((acc->flags & ACC_CONTROL) != 0)
1917	fprintf (e, ", CONTROL");
1918      if ((acc->flags & ACC_ALT) != 0)
1919	fprintf (e, ", ALT");
1920
1921      fprintf (e, "\n");
1922    }
1923
1924  fprintf (e, "END\n");
1925}
1926
1927/* Write out cursor information.  This would normally be in a separate
1928   file, which the rc file would include.  */
1929
1930static void
1931write_rc_cursor (FILE *e, const struct cursor *cursor)
1932{
1933  fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
1934	   cursor->yhotspot);
1935  write_rc_filedata (e, cursor->length, cursor->data);
1936}
1937
1938/* Write out group cursor data.  This would normally be built from the
1939   cursor data.  */
1940
1941static void
1942write_rc_group_cursor (FILE *e, const struct group_cursor *group_cursor)
1943{
1944  const struct group_cursor *gc;
1945
1946  for (gc = group_cursor; gc != NULL; gc = gc->next)
1947    {
1948      fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
1949	     gc->width, gc->height, gc->planes, gc->bits);
1950      fprintf (e, "// data bytes: %lu; index: %d\n",
1951	       gc->bytes, gc->index);
1952    }
1953}
1954
1955/* Write dialog data.  */
1956
1957static void
1958write_rc_dialog (FILE *e, const struct dialog *dialog)
1959{
1960  const struct dialog_control *control;
1961
1962  fprintf (e, "STYLE 0x%lx\n", dialog->style);
1963
1964  if (dialog->exstyle != 0)
1965    fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
1966
1967  if ((dialog->class.named && dialog->class.u.n.length > 0)
1968      || dialog->class.u.id != 0)
1969    {
1970      fprintf (e, "CLASS ");
1971      res_id_print (e, dialog->class, 1);
1972      fprintf (e, "\n");
1973    }
1974
1975  if (dialog->caption != NULL)
1976    {
1977      fprintf (e, "CAPTION \"");
1978      unicode_print (e, dialog->caption, -1);
1979      fprintf (e, "\"\n");
1980    }
1981
1982  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
1983      || dialog->menu.u.id != 0)
1984    {
1985      fprintf (e, "MENU ");
1986      res_id_print (e, dialog->menu, 0);
1987      fprintf (e, "\n");
1988    }
1989
1990  if (dialog->font != NULL)
1991    {
1992      fprintf (e, "FONT %d, \"", dialog->pointsize);
1993      unicode_print (e, dialog->font, -1);
1994      fprintf (e, "\"");
1995      if (dialog->ex != NULL
1996	  && (dialog->ex->weight != 0
1997	      || dialog->ex->italic != 0
1998	      || dialog->ex->charset != 1))
1999	fprintf (e, ", %d, %d, %d",
2000		 dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
2001      fprintf (e, "\n");
2002    }
2003
2004  fprintf (e, "BEGIN\n");
2005
2006  for (control = dialog->controls; control != NULL; control = control->next)
2007    write_rc_dialog_control (e, control);
2008
2009  fprintf (e, "END\n");
2010}
2011
2012/* For each predefined control keyword, this table provides the class
2013   and the style.  */
2014
2015struct control_info
2016{
2017  const char *name;
2018  unsigned short class;
2019  unsigned long style;
2020};
2021
2022static const struct control_info control_info[] =
2023{
2024  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2025  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2026  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2027  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2028  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2029  { "CTEXT", CTL_STATIC, SS_CENTER },
2030  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2031  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2032  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2033  { "ICON", CTL_STATIC, SS_ICON },
2034  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2035  { "LTEXT", CTL_STATIC, SS_LEFT },
2036  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2037  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2038  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2039  { "RTEXT", CTL_STATIC, SS_RIGHT },
2040  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2041  { "STATE3", CTL_BUTTON, BS_3STATE },
2042  /* It's important that USERBUTTON come after all the other button
2043     types, so that it won't be matched too early.  */
2044  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2045  { NULL, 0, 0 }
2046};
2047
2048/* Write a dialog control.  */
2049
2050static void
2051write_rc_dialog_control (FILE *e, const struct dialog_control *control)
2052{
2053  const struct control_info *ci;
2054
2055  fprintf (e, "  ");
2056
2057  if (control->class.named)
2058    ci = NULL;
2059  else
2060    {
2061      for (ci = control_info; ci->name != NULL; ++ci)
2062	if (ci->class == control->class.u.id
2063	    && (ci->style == (unsigned long) -1
2064		|| ci->style == (control->style & 0xff)))
2065	  break;
2066    }
2067  if (ci == NULL)
2068    fprintf (e, "CONTROL");
2069  else if (ci->name != NULL)
2070    fprintf (e, "%s", ci->name);
2071  else
2072    fprintf (e, "CONTROL");
2073
2074  if (control->text.named || control->text.u.id != 0)
2075    {
2076      fprintf (e, " ");
2077      res_id_print (e, control->text, 1);
2078      fprintf (e, ",");
2079    }
2080
2081  fprintf (e, " %d, ", control->id);
2082
2083  if (ci == NULL)
2084    {
2085      if (control->class.named)
2086	fprintf (e, "\"");
2087      res_id_print (e, control->class, 0);
2088      if (control->class.named)
2089	fprintf (e, "\"");
2090      fprintf (e, ", 0x%lx, ", control->style);
2091    }
2092
2093  fprintf (e, "%d, %d", control->x, control->y);
2094
2095  if (control->style != SS_ICON
2096      || control->exstyle != 0
2097      || control->width != 0
2098      || control->height != 0
2099      || control->help != 0)
2100    {
2101      fprintf (e, ", %d, %d", control->width, control->height);
2102
2103      /* FIXME: We don't need to print the style if it is the default.
2104	 More importantly, in certain cases we actually need to turn
2105	 off parts of the forced style, by using NOT.  */
2106      fprintf (e, ", 0x%lx", control->style);
2107
2108      if (control->exstyle != 0 || control->help != 0)
2109	fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
2110    }
2111
2112  fprintf (e, "\n");
2113
2114  if (control->data != NULL)
2115    write_rc_rcdata (e, control->data, 2);
2116}
2117
2118/* Write out font directory data.  This would normally be built from
2119   the font data.  */
2120
2121static void
2122write_rc_fontdir (FILE *e, const struct fontdir *fontdir)
2123{
2124  const struct fontdir *fc;
2125
2126  for (fc = fontdir; fc != NULL; fc = fc->next)
2127    {
2128      fprintf (e, "// Font index: %d\n", fc->index);
2129      write_rc_filedata (e, fc->length, fc->data);
2130    }
2131}
2132
2133/* Write out group icon data.  This would normally be built from the
2134   icon data.  */
2135
2136static void
2137write_rc_group_icon (FILE *e, const struct group_icon *group_icon)
2138{
2139  const struct group_icon *gi;
2140
2141  for (gi = group_icon; gi != NULL; gi = gi->next)
2142    {
2143      fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
2144	       gi->width, gi->height, gi->colors, gi->planes, gi->bits);
2145      fprintf (e, "// data bytes: %lu; index: %d\n",
2146	       gi->bytes, gi->index);
2147    }
2148}
2149
2150/* Write out a menu resource.  */
2151
2152static void
2153write_rc_menu (FILE *e, const struct menu *menu, int menuex)
2154{
2155  if (menu->help != 0)
2156    fprintf (e, "// Help ID: %lu\n", menu->help);
2157  write_rc_menuitems (e, menu->items, menuex, 0);
2158}
2159
2160/* Write out menuitems.  */
2161
2162static void
2163write_rc_menuitems (FILE *e, const struct menuitem *menuitems, int menuex,
2164		    int ind)
2165{
2166  const struct menuitem *mi;
2167
2168  indent (e, ind);
2169  fprintf (e, "BEGIN\n");
2170
2171  for (mi = menuitems; mi != NULL; mi = mi->next)
2172    {
2173      indent (e, ind + 2);
2174
2175      if (mi->popup == NULL)
2176	fprintf (e, "MENUITEM");
2177      else
2178	fprintf (e, "POPUP");
2179
2180      if (! menuex
2181	  && mi->popup == NULL
2182	  && mi->text == NULL
2183	  && mi->type == 0
2184	  && mi->id == 0)
2185	{
2186	  fprintf (e, " SEPARATOR\n");
2187	  continue;
2188	}
2189
2190      if (mi->text == NULL)
2191	fprintf (e, " \"\"");
2192      else
2193	{
2194	  fprintf (e, " \"");
2195	  unicode_print (e, mi->text, -1);
2196	  fprintf (e, "\"");
2197	}
2198
2199      if (! menuex)
2200	{
2201	  if (mi->popup == NULL)
2202	    fprintf (e, ", %d", mi->id);
2203
2204	  if ((mi->type & MENUITEM_CHECKED) != 0)
2205	    fprintf (e, ", CHECKED");
2206	  if ((mi->type & MENUITEM_GRAYED) != 0)
2207	    fprintf (e, ", GRAYED");
2208	  if ((mi->type & MENUITEM_HELP) != 0)
2209	    fprintf (e, ", HELP");
2210	  if ((mi->type & MENUITEM_INACTIVE) != 0)
2211	    fprintf (e, ", INACTIVE");
2212	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2213	    fprintf (e, ", MENUBARBREAK");
2214	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
2215	    fprintf (e, ", MENUBREAK");
2216	}
2217      else
2218	{
2219	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2220	    {
2221	      fprintf (e, ", %d", mi->id);
2222	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2223		{
2224		  fprintf (e, ", %lu", mi->type);
2225		  if (mi->state != 0 || mi->help != 0)
2226		    {
2227		      fprintf (e, ", %lu", mi->state);
2228		      if (mi->help != 0)
2229			fprintf (e, ", %lu", mi->help);
2230		    }
2231		}
2232	    }
2233	}
2234
2235      fprintf (e, "\n");
2236
2237      if (mi->popup != NULL)
2238	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2239    }
2240
2241  indent (e, ind);
2242  fprintf (e, "END\n");
2243}
2244
2245/* Write out an rcdata resource.  This is also used for other types of
2246   resources that need to print arbitrary data.  */
2247
2248static void
2249write_rc_rcdata (FILE *e, const struct rcdata_item *rcdata, int ind)
2250{
2251  const struct rcdata_item *ri;
2252
2253  indent (e, ind);
2254  fprintf (e, "BEGIN\n");
2255
2256  for (ri = rcdata; ri != NULL; ri = ri->next)
2257    {
2258      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2259	continue;
2260
2261      indent (e, ind + 2);
2262
2263      switch (ri->type)
2264	{
2265	default:
2266	  abort ();
2267
2268	case RCDATA_WORD:
2269	  fprintf (e, "%d", ri->u.word);
2270	  break;
2271
2272	case RCDATA_DWORD:
2273	  fprintf (e, "%luL", ri->u.dword);
2274	  break;
2275
2276	case RCDATA_STRING:
2277	  {
2278	    const char *s;
2279	    unsigned long i;
2280
2281	    fprintf (e, "\"");
2282	    s = ri->u.string.s;
2283	    for (i = 0; i < ri->u.string.length; i++)
2284	      {
2285		if (ISPRINT (*s))
2286		  putc (*s, e);
2287		else
2288		  fprintf (e, "\\%03o", *s);
2289	      }
2290	    fprintf (e, "\"");
2291	    break;
2292	  }
2293
2294	case RCDATA_WSTRING:
2295	  fprintf (e, "L\"");
2296	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2297	  fprintf (e, "\"");
2298	  break;
2299
2300	case RCDATA_BUFFER:
2301	  {
2302	    unsigned long i;
2303	    int first;
2304
2305	    /* Assume little endian data.  */
2306
2307	    first = 1;
2308	    for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2309	      {
2310		unsigned long l;
2311		int j;
2312
2313		if (! first)
2314		  indent (e, ind + 2);
2315		l = ((((((ri->u.buffer.data[i + 3] << 8)
2316			 | ri->u.buffer.data[i + 2]) << 8)
2317		       | ri->u.buffer.data[i + 1]) << 8)
2318		     | ri->u.buffer.data[i]);
2319		fprintf (e, "%luL", l);
2320		if (i + 4 < ri->u.buffer.length || ri->next != NULL)
2321		  fprintf (e, ",");
2322		for (j = 0; j < 4; ++j)
2323		  if (! ISPRINT (ri->u.buffer.data[i + j])
2324		      && ri->u.buffer.data[i + j] != 0)
2325		    break;
2326		if (j >= 4)
2327		  {
2328		    fprintf (e, "\t// ");
2329		    for (j = 0; j < 4; ++j)
2330		      {
2331			if (! ISPRINT (ri->u.buffer.data[i + j]))
2332			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2333			else
2334			  {
2335			    if (ri->u.buffer.data[i + j] == '\\')
2336			      fprintf (e, "\\");
2337			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
2338			  }
2339		      }
2340		  }
2341		fprintf (e, "\n");
2342		first = 0;
2343	      }
2344
2345	    if (i + 1 < ri->u.buffer.length)
2346	      {
2347		int s;
2348		int j;
2349
2350		if (! first)
2351		  indent (e, ind + 2);
2352		s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2353		fprintf (e, "%d", s);
2354		if (i + 2 < ri->u.buffer.length || ri->next != NULL)
2355		  fprintf (e, ",");
2356		for (j = 0; j < 2; ++j)
2357		  if (! ISPRINT (ri->u.buffer.data[i + j])
2358		      && ri->u.buffer.data[i + j] != 0)
2359		    break;
2360		if (j >= 2)
2361		  {
2362		    fprintf (e, "\t// ");
2363		    for (j = 0; j < 2; ++j)
2364		      {
2365			if (! ISPRINT (ri->u.buffer.data[i + j]))
2366			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2367			else
2368			  {
2369			    if (ri->u.buffer.data[i + j] == '\\')
2370			      fprintf (e, "\\");
2371			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
2372			  }
2373		      }
2374		  }
2375		fprintf (e, "\n");
2376		i += 2;
2377		first = 0;
2378	      }
2379
2380	    if (i < ri->u.buffer.length)
2381	      {
2382		if (! first)
2383		  indent (e, ind + 2);
2384		if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2385		    && ISPRINT (ri->u.buffer.data[i]))
2386		  fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2387		else
2388		  fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
2389		if (ri->next != NULL)
2390		  fprintf (e, ",");
2391		fprintf (e, "\n");
2392		first = 0;
2393	      }
2394
2395	    break;
2396	  }
2397	}
2398
2399      if (ri->type != RCDATA_BUFFER)
2400	{
2401	  if (ri->next != NULL)
2402	    fprintf (e, ",");
2403	  fprintf (e, "\n");
2404	}
2405    }
2406
2407  indent (e, ind);
2408  fprintf (e, "END\n");
2409}
2410
2411/* Write out a stringtable resource.  */
2412
2413static void
2414write_rc_stringtable (FILE *e, const struct res_id *name,
2415		      const struct stringtable *stringtable)
2416{
2417  unsigned long offset;
2418  int i;
2419
2420  if (name != NULL && ! name->named)
2421    offset = (name->u.id - 1) << 4;
2422  else
2423    {
2424      fprintf (e, "// %s string table name\n",
2425	       name == NULL ? "Missing" : "Invalid");
2426      offset = 0;
2427    }
2428
2429  fprintf (e, "BEGIN\n");
2430
2431  for (i = 0; i < 16; i++)
2432    {
2433      if (stringtable->strings[i].length != 0)
2434	{
2435	  fprintf (e, "  %lu, \"", offset + i);
2436	  unicode_print (e, stringtable->strings[i].string,
2437			 stringtable->strings[i].length);
2438	  fprintf (e, "\"\n");
2439	}
2440    }
2441
2442  fprintf (e, "END\n");
2443}
2444
2445/* Write out a versioninfo resource.  */
2446
2447static void
2448write_rc_versioninfo (FILE *e, const struct versioninfo *versioninfo)
2449{
2450  const struct fixed_versioninfo *f;
2451  const struct ver_info *vi;
2452
2453  f = versioninfo->fixed;
2454  if (f->file_version_ms != 0 || f->file_version_ls != 0)
2455    fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2456	     (f->file_version_ms >> 16) & 0xffff,
2457	     f->file_version_ms & 0xffff,
2458	     (f->file_version_ls >> 16) & 0xffff,
2459	     f->file_version_ls & 0xffff);
2460  if (f->product_version_ms != 0 || f->product_version_ls != 0)
2461    fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2462	     (f->product_version_ms >> 16) & 0xffff,
2463	     f->product_version_ms & 0xffff,
2464	     (f->product_version_ls >> 16) & 0xffff,
2465	     f->product_version_ls & 0xffff);
2466  if (f->file_flags_mask != 0)
2467    fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2468  if (f->file_flags != 0)
2469    fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2470  if (f->file_os != 0)
2471    fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2472  if (f->file_type != 0)
2473    fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2474  if (f->file_subtype != 0)
2475    fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2476  if (f->file_date_ms != 0 || f->file_date_ls != 0)
2477    fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2478
2479  fprintf (e, "BEGIN\n");
2480
2481  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2482    {
2483      switch (vi->type)
2484	{
2485	case VERINFO_STRING:
2486	  {
2487	    const struct ver_stringinfo *vs;
2488
2489	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
2490	    fprintf (e, "  BEGIN\n");
2491	    fprintf (e, "    BLOCK \"");
2492	    unicode_print (e, vi->u.string.language, -1);
2493	    fprintf (e, "\"\n");
2494	    fprintf (e, "    BEGIN\n");
2495
2496	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2497	      {
2498		fprintf (e, "      VALUE \"");
2499		unicode_print (e, vs->key, -1);
2500		fprintf (e, "\", \"");
2501		unicode_print (e, vs->value, -1);
2502		fprintf (e, "\"\n");
2503	      }
2504
2505	    fprintf (e, "    END\n");
2506	    fprintf (e, "  END\n");
2507	    break;
2508	  }
2509
2510	case VERINFO_VAR:
2511	  {
2512	    const struct ver_varinfo *vv;
2513
2514	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
2515	    fprintf (e, "  BEGIN\n");
2516	    fprintf (e, "    VALUE \"");
2517	    unicode_print (e, vi->u.var.key, -1);
2518	    fprintf (e, "\"");
2519
2520	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2521	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2522		       vv->charset);
2523
2524	    fprintf (e, "\n  END\n");
2525
2526	    break;
2527	  }
2528	}
2529    }
2530
2531  fprintf (e, "END\n");
2532}
2533
2534/* Write out data which would normally be read from a file.  */
2535
2536static void
2537write_rc_filedata (FILE *e, unsigned long length, const unsigned char *data)
2538{
2539  unsigned long i;
2540
2541  for (i = 0; i + 15 < length; i += 16)
2542    {
2543      fprintf (e, "// %4lx: ", i);
2544      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2545	       data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2546	       data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2547      fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2548	       data[i +  8], data[i +  9], data[i + 10], data[i + 11],
2549	       data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2550    }
2551
2552  if (i < length)
2553    {
2554      fprintf (e, "// %4lx:", i);
2555      while (i < length)
2556	{
2557	  fprintf (e, " %02x", data[i]);
2558	  ++i;
2559	}
2560      fprintf (e, "\n");
2561    }
2562}
2563