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