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 
87 struct 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 
120 char *rc_filename;
121 
122 /* The line number in the rc file.  */
123 
124 int rc_lineno;
125 
126 /* The pipe we are reading from, so that we can close it if we exit.  */
127 
128 static 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 
133 static char *cpp_temp_file;
134 
135 /* Input stream is either a file or a pipe.  */
136 
137 static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
138 
139 /* As we read the rc file, we attach information to this structure.  */
140 
141 static struct res_directory *resources;
142 
143 /* The number of cursor resources we have written out.  */
144 
145 static int cursors;
146 
147 /* The number of font resources we have written out.  */
148 
149 static int fonts;
150 
151 /* Font directory information.  */
152 
153 struct fontdir *fontdirs;
154 
155 /* Resource info to use for fontdirs.  */
156 
157 struct res_res_info fontdirs_resinfo;
158 
159 /* The number of icon resources we have written out.  */
160 
161 static int icons;
162 
163 /* Local functions.  */
164 
165 static int run_cmd (char *, const char *);
166 static FILE *open_input_stream (char *);
167 static FILE *look_for_default
168   (char *, const char *, int, const char *, const char *);
169 static void close_input_stream (void);
170 static void unexpected_eof (const char *);
171 static int get_word (FILE *, const char *);
172 static unsigned long get_long (FILE *, const char *);
173 static void get_data (FILE *, unsigned char *, unsigned long, const char *);
174 static void define_fontdirs (void);
175 
176 /* Run `cmd' and redirect the output to `redir'.  */
177 
178 static int
179 run_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 #if defined(__MSDOS__) && !defined(__GO32__)
187   char *temp_base = choose_temp_base ();
188 #else
189   char *temp_base = NULL;
190 #endif
191   int in_quote;
192   char sep;
193   int redir_handle = -1;
194   int stdout_save = -1;
195 
196   /* Count the args.  */
197   i = 0;
198 
199   for (s = cmd; *s; s++)
200     if (*s == ' ')
201       i++;
202 
203   i++;
204   argv = alloca (sizeof (char *) * (i + 3));
205   i = 0;
206   s = cmd;
207 
208   while (1)
209     {
210       while (*s == ' ' && *s != 0)
211 	s++;
212 
213       if (*s == 0)
214 	break;
215 
216       in_quote = (*s == '\'' || *s == '"');
217       sep = (in_quote) ? *s++ : ' ';
218       argv[i++] = s;
219 
220       while (*s != sep && *s != 0)
221 	s++;
222 
223       if (*s == 0)
224 	break;
225 
226       *s++ = 0;
227 
228       if (in_quote)
229 	s++;
230     }
231   argv[i++] = NULL;
232 
233   /* Setup the redirection.  We can't use the usual fork/exec and redirect
234      since we may be running on non-POSIX Windows host.  */
235 
236   fflush (stdout);
237   fflush (stderr);
238 
239   /* Open temporary output file.  */
240   redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
241   if (redir_handle == -1)
242     fatal (_("can't open temporary file `%s': %s"), redir,
243 	   strerror (errno));
244 
245   /* Duplicate the stdout file handle so it can be restored later.  */
246   stdout_save = dup (STDOUT_FILENO);
247   if (stdout_save == -1)
248     fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
249 
250   /* Redirect stdout to our output file.  */
251   dup2 (redir_handle, STDOUT_FILENO);
252 
253   pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
254 		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
255 
256   /* Restore stdout to its previous setting.  */
257   dup2 (stdout_save, STDOUT_FILENO);
258 
259   /* Close response file.  */
260   close (redir_handle);
261 
262   if (pid == -1)
263     {
264       fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
265       return 1;
266     }
267 
268   retcode = 0;
269   pid = pwait (pid, &wait_status, 0);
270 
271   if (pid == -1)
272     {
273       fatal (_("wait: %s"), strerror (errno));
274       retcode = 1;
275     }
276   else if (WIFSIGNALED (wait_status))
277     {
278       fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
279       retcode = 1;
280     }
281   else if (WIFEXITED (wait_status))
282     {
283       if (WEXITSTATUS (wait_status) != 0)
284 	{
285 	  fatal (_("%s exited with status %d"), cmd,
286 	         WEXITSTATUS (wait_status));
287 	  retcode = 1;
288 	}
289     }
290   else
291     retcode = 1;
292 
293   return retcode;
294 }
295 
296 static FILE *
297 open_input_stream (char *cmd)
298 {
299   if (istream_type == ISTREAM_FILE)
300     {
301       cpp_temp_file = make_temp_file (".irc");
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 
331 static FILE *
332 look_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 
380 struct res_directory *
381 read_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 
487 static void
488 close_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 
517 void
518 yyerror (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 
525 void
526 rcparse_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 
533 static void
534 unexpected_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 
542 static int
543 get_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 
557 static unsigned long
558 get_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 
576 static void
577 get_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 
590 void
591 define_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 
609 void
610 define_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 
651 void
652 define_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 
769 void
770 define_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 
789 struct dialog_control *
790 define_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 
815 struct dialog_control *
816 define_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 
841 void
842 define_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 font 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 
927 static void
928 define_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 
949 void
950 define_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 
1076 void
1077 define_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 
1096 struct menuitem *
1097 define_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 
1119 void
1120 define_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 
1154 void
1155 define_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 
1169 struct rcdata_item *
1170 define_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 
1188 struct rcdata_item *
1189 define_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 
1204 void
1205 define_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 
1239 void
1240 define_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 void
1259 define_rcdata_file (struct res_id id, const struct res_res_info *resinfo,
1260 		    const char *filename)
1261 {
1262   struct rcdata_item *ri;
1263   FILE *e;
1264   char *real_filename;
1265   struct stat s;
1266   unsigned char *data;
1267 
1268   e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1269 
1270 
1271   if (stat (real_filename, &s) < 0)
1272     fatal (_("stat failed on file `%s': %s"), real_filename,
1273 	   strerror (errno));
1274 
1275   data = (unsigned char *) res_alloc (s.st_size);
1276 
1277   get_data (e, data, s.st_size, real_filename);
1278 
1279   fclose (e);
1280   free (real_filename);
1281 
1282   ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1283   ri->next = NULL;
1284   ri->type = RCDATA_BUFFER;
1285   ri->u.buffer.length = s.st_size;
1286   ri->u.buffer.data = data;
1287 
1288   define_rcdata (id, resinfo, ri);
1289 }
1290 
1291 /* Define a user data resource where the data is in a file.  */
1292 
1293 void
1294 define_user_file (struct res_id id, struct res_id type,
1295 		  const struct res_res_info *resinfo, const char *filename)
1296 {
1297   FILE *e;
1298   char *real_filename;
1299   struct stat s;
1300   unsigned char *data;
1301   struct res_id ids[3];
1302   struct res_resource *r;
1303 
1304   e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1305 
1306   if (stat (real_filename, &s) < 0)
1307     fatal (_("stat failed on file `%s': %s"), real_filename,
1308 	   strerror (errno));
1309 
1310   data = (unsigned char *) res_alloc (s.st_size);
1311 
1312   get_data (e, data, s.st_size, real_filename);
1313 
1314   fclose (e);
1315   free (real_filename);
1316 
1317   ids[0] = type;
1318   ids[1] = id;
1319   ids[2].named = 0;
1320   ids[2].u.id = resinfo->language;
1321 
1322   r = define_resource (&resources, 3, ids, 0);
1323   r->type = RES_TYPE_USERDATA;
1324   r->u.userdata = ((struct rcdata_item *)
1325 		   res_alloc (sizeof (struct rcdata_item)));
1326   r->u.userdata->next = NULL;
1327   r->u.userdata->type = RCDATA_BUFFER;
1328   r->u.userdata->u.buffer.length = s.st_size;
1329   r->u.userdata->u.buffer.data = data;
1330   r->res_info = *resinfo;
1331 }
1332 
1333 /* Define a versioninfo resource.  */
1334 
1335 void
1336 define_versioninfo (struct res_id id, int language,
1337 		    struct fixed_versioninfo *fixedverinfo,
1338 		    struct ver_info *verinfo)
1339 {
1340   struct res_resource *r;
1341 
1342   r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1343   r->type = RES_TYPE_VERSIONINFO;
1344   r->u.versioninfo = ((struct versioninfo *)
1345 		      res_alloc (sizeof (struct versioninfo)));
1346   r->u.versioninfo->fixed = fixedverinfo;
1347   r->u.versioninfo->var = verinfo;
1348   r->res_info.language = language;
1349 }
1350 
1351 /* Add string version info to a list of version information.  */
1352 
1353 struct ver_info *
1354 append_ver_stringfileinfo (struct ver_info *verinfo, const char *language,
1355 			   struct ver_stringinfo *strings)
1356 {
1357   struct ver_info *vi, **pp;
1358 
1359   vi = (struct ver_info *) res_alloc (sizeof *vi);
1360   vi->next = NULL;
1361   vi->type = VERINFO_STRING;
1362   unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
1363   vi->u.string.strings = strings;
1364 
1365   for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1366     ;
1367   *pp = vi;
1368 
1369   return verinfo;
1370 }
1371 
1372 /* Add variable version info to a list of version information.  */
1373 
1374 struct ver_info *
1375 append_ver_varfileinfo (struct ver_info *verinfo, const char *key,
1376 			struct ver_varinfo *var)
1377 {
1378   struct ver_info *vi, **pp;
1379 
1380   vi = (struct ver_info *) res_alloc (sizeof *vi);
1381   vi->next = NULL;
1382   vi->type = VERINFO_VAR;
1383   unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
1384   vi->u.var.var = var;
1385 
1386   for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1387     ;
1388   *pp = vi;
1389 
1390   return verinfo;
1391 }
1392 
1393 /* Append version string information to a list.  */
1394 
1395 struct ver_stringinfo *
1396 append_verval (struct ver_stringinfo *strings, const char *key,
1397 	       const char *value)
1398 {
1399   struct ver_stringinfo *vs, **pp;
1400 
1401   vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
1402   vs->next = NULL;
1403   unicode_from_ascii ((int *) NULL, &vs->key, key);
1404   unicode_from_ascii ((int *) NULL, &vs->value, value);
1405 
1406   for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1407     ;
1408   *pp = vs;
1409 
1410   return strings;
1411 }
1412 
1413 /* Append version variable information to a list.  */
1414 
1415 struct ver_varinfo *
1416 append_vertrans (struct ver_varinfo *var, unsigned long language,
1417 		 unsigned long charset)
1418 {
1419   struct ver_varinfo *vv, **pp;
1420 
1421   vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
1422   vv->next = NULL;
1423   vv->language = language;
1424   vv->charset = charset;
1425 
1426   for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1427     ;
1428   *pp = vv;
1429 
1430   return var;
1431 }
1432 
1433 /* Local functions used to write out an rc file.  */
1434 
1435 static void indent (FILE *, int);
1436 static void write_rc_directory
1437   (FILE *, const struct res_directory *, const struct res_id *,
1438    const struct res_id *, int *, int);
1439 static void write_rc_subdir
1440   (FILE *, const struct res_entry *, const struct res_id *,
1441    const struct res_id *, int *, int);
1442 static void write_rc_resource
1443   (FILE *, const struct res_id *, const struct res_id *,
1444    const struct res_resource *, int *);
1445 static void write_rc_accelerators (FILE *, const struct accelerator *);
1446 static void write_rc_cursor (FILE *, const struct cursor *);
1447 static void write_rc_group_cursor (FILE *, const struct group_cursor *);
1448 static void write_rc_dialog (FILE *, const struct dialog *);
1449 static void write_rc_dialog_control (FILE *, const struct dialog_control *);
1450 static void write_rc_fontdir (FILE *, const struct fontdir *);
1451 static void write_rc_group_icon (FILE *, const struct group_icon *);
1452 static void write_rc_menu (FILE *, const struct menu *, int);
1453 static void write_rc_menuitems (FILE *, const struct menuitem *, int, int);
1454 static void write_rc_rcdata (FILE *, const struct rcdata_item *, int);
1455 static void write_rc_stringtable
1456   (FILE *, const struct res_id *, const struct stringtable *);
1457 static void write_rc_versioninfo (FILE *, const struct versioninfo *);
1458 static void write_rc_filedata (FILE *, unsigned long, const unsigned char *);
1459 
1460 /* Indent a given number of spaces.  */
1461 
1462 static void
1463 indent (FILE *e, int c)
1464 {
1465   int i;
1466 
1467   for (i = 0; i < c; i++)
1468     putc (' ', e);
1469 }
1470 
1471 /* Dump the resources we have read in the format of an rc file.
1472 
1473    Actually, we don't use the format of an rc file, because it's way
1474    too much of a pain--for example, we'd have to write icon resources
1475    into a file and refer to that file.  We just generate a readable
1476    format that kind of looks like an rc file, and is useful for
1477    understanding the contents of a resource file.  Someday we may want
1478    to generate an rc file which the rc compiler can read; if that day
1479    comes, this code will have to be fixed up.  */
1480 
1481 void
1482 write_rc_file (const char *filename, const struct res_directory *resources)
1483 {
1484   FILE *e;
1485   int language;
1486 
1487   if (filename == NULL)
1488     e = stdout;
1489   else
1490     {
1491       e = fopen (filename, FOPEN_WT);
1492       if (e == NULL)
1493 	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1494     }
1495 
1496   language = -1;
1497   write_rc_directory (e, resources, (const struct res_id *) NULL,
1498 		      (const struct res_id *) NULL, &language, 1);
1499 }
1500 
1501 /* Write out a directory.  E is the file to write to.  RD is the
1502    directory.  TYPE is a pointer to the level 1 ID which serves as the
1503    resource type.  NAME is a pointer to the level 2 ID which serves as
1504    an individual resource name.  LANGUAGE is a pointer to the current
1505    language.  LEVEL is the level in the tree.  */
1506 
1507 static void
1508 write_rc_directory (FILE *e, const struct res_directory *rd,
1509 		    const struct res_id *type, const struct res_id *name,
1510 		    int *language, int level)
1511 {
1512   const struct res_entry *re;
1513 
1514   /* Print out some COFF information that rc files can't represent.  */
1515 
1516   if (rd->time != 0)
1517     fprintf (e, "// Time stamp: %lu\n", rd->time);
1518   if (rd->characteristics != 0)
1519     fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
1520   if (rd->major != 0 || rd->minor != 0)
1521     fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
1522 
1523   for (re = rd->entries;  re != NULL; re = re->next)
1524     {
1525       switch (level)
1526 	{
1527 	case 1:
1528 	  /* If we're at level 1, the key of this resource is the
1529              type.  This normally duplicates the information we have
1530              stored with the resource itself, but we need to remember
1531              the type if this is a user define resource type.  */
1532 	  type = &re->id;
1533 	  break;
1534 
1535 	case 2:
1536 	  /* If we're at level 2, the key of this resource is the name
1537 	     we are going to use in the rc printout.  */
1538 	  name = &re->id;
1539 	  break;
1540 
1541 	case 3:
1542 	  /* If we're at level 3, then this key represents a language.
1543 	     Use it to update the current language.  */
1544 	  if (! re->id.named
1545 	      && re->id.u.id != (unsigned long) (unsigned int) *language
1546 	      && (re->id.u.id & 0xffff) == re->id.u.id)
1547 	    {
1548 	      fprintf (e, "LANGUAGE %lu, %lu\n",
1549 		       re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
1550 		       (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
1551 	      *language = re->id.u.id;
1552 	    }
1553 	  break;
1554 
1555 	default:
1556 	  break;
1557 	}
1558 
1559       if (re->subdir)
1560 	write_rc_subdir (e, re, type, name, language, level);
1561       else
1562 	{
1563 	  if (level == 3)
1564 	    {
1565 	      /* This is the normal case: the three levels are
1566                  TYPE/NAME/LANGUAGE.  NAME will have been set at level
1567                  2, and represents the name to use.  We probably just
1568                  set LANGUAGE, and it will probably match what the
1569                  resource itself records if anything.  */
1570 	      write_rc_resource (e, type, name, re->u.res, language);
1571 	    }
1572 	  else
1573 	    {
1574 	      fprintf (e, "// Resource at unexpected level %d\n", level);
1575 	      write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1576 				 language);
1577 	    }
1578 	}
1579     }
1580 }
1581 
1582 /* Write out a subdirectory entry.  E is the file to write to.  RE is
1583    the subdirectory entry.  TYPE and NAME are pointers to higher level
1584    IDs, or NULL.  LANGUAGE is a pointer to the current language.
1585    LEVEL is the level in the tree.  */
1586 
1587 static void
1588 write_rc_subdir (FILE *e, const struct res_entry *re,
1589 		 const struct res_id *type, const struct res_id *name,
1590 		 int *language, int level)
1591 {
1592   fprintf (e, "\n");
1593   switch (level)
1594     {
1595     case 1:
1596       fprintf (e, "// Type: ");
1597       if (re->id.named)
1598 	res_id_print (e, re->id, 1);
1599       else
1600 	{
1601 	  const char *s;
1602 
1603 	  switch (re->id.u.id)
1604 	    {
1605 	    case RT_CURSOR: s = "cursor"; break;
1606 	    case RT_BITMAP: s = "bitmap"; break;
1607 	    case RT_ICON: s = "icon"; break;
1608 	    case RT_MENU: s = "menu"; break;
1609 	    case RT_DIALOG: s = "dialog"; break;
1610 	    case RT_STRING: s = "stringtable"; break;
1611 	    case RT_FONTDIR: s = "fontdir"; break;
1612 	    case RT_FONT: s = "font"; break;
1613 	    case RT_ACCELERATOR: s = "accelerators"; break;
1614 	    case RT_RCDATA: s = "rcdata"; break;
1615 	    case RT_MESSAGETABLE: s = "messagetable"; break;
1616 	    case RT_GROUP_CURSOR: s = "group cursor"; break;
1617 	    case RT_GROUP_ICON: s = "group icon"; break;
1618 	    case RT_VERSION: s = "version"; break;
1619 	    case RT_DLGINCLUDE: s = "dlginclude"; break;
1620 	    case RT_PLUGPLAY: s = "plugplay"; break;
1621 	    case RT_VXD: s = "vxd"; break;
1622 	    case RT_ANICURSOR: s = "anicursor"; break;
1623 	    case RT_ANIICON: s = "aniicon"; break;
1624 	    default: s = NULL; break;
1625 	    }
1626 
1627 	  if (s != NULL)
1628 	    fprintf (e, "%s", s);
1629 	  else
1630 	    res_id_print (e, re->id, 1);
1631 	}
1632       fprintf (e, "\n");
1633       break;
1634 
1635     case 2:
1636       fprintf (e, "// Name: ");
1637       res_id_print (e, re->id, 1);
1638       fprintf (e, "\n");
1639       break;
1640 
1641     case 3:
1642       fprintf (e, "// Language: ");
1643       res_id_print (e, re->id, 1);
1644       fprintf (e, "\n");
1645       break;
1646 
1647     default:
1648       fprintf (e, "// Level %d: ", level);
1649       res_id_print (e, re->id, 1);
1650       fprintf (e, "\n");
1651     }
1652 
1653   write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1654 }
1655 
1656 /* Write out a single resource.  E is the file to write to.  TYPE is a
1657    pointer to the type of the resource.  NAME is a pointer to the name
1658    of the resource; it will be NULL if there is a level mismatch.  RES
1659    is the resource data.  LANGUAGE is a pointer to the current
1660    language.  */
1661 
1662 static void
1663 write_rc_resource (FILE *e, const struct res_id *type,
1664 		   const struct res_id *name, const struct res_resource *res,
1665 		   int *language)
1666 {
1667   const char *s;
1668   int rt;
1669   int menuex = 0;
1670 
1671   fprintf (e, "\n");
1672 
1673   switch (res->type)
1674     {
1675     default:
1676       abort ();
1677 
1678     case RES_TYPE_ACCELERATOR:
1679       s = "ACCELERATOR";
1680       rt = RT_ACCELERATOR;
1681       break;
1682 
1683     case RES_TYPE_BITMAP:
1684       s = "BITMAP";
1685       rt = RT_BITMAP;
1686       break;
1687 
1688     case RES_TYPE_CURSOR:
1689       s = "CURSOR";
1690       rt = RT_CURSOR;
1691       break;
1692 
1693     case RES_TYPE_GROUP_CURSOR:
1694       s = "GROUP_CURSOR";
1695       rt = RT_GROUP_CURSOR;
1696       break;
1697 
1698     case RES_TYPE_DIALOG:
1699       if (extended_dialog (res->u.dialog))
1700 	s = "DIALOGEX";
1701       else
1702 	s = "DIALOG";
1703       rt = RT_DIALOG;
1704       break;
1705 
1706     case RES_TYPE_FONT:
1707       s = "FONT";
1708       rt = RT_FONT;
1709       break;
1710 
1711     case RES_TYPE_FONTDIR:
1712       s = "FONTDIR";
1713       rt = RT_FONTDIR;
1714       break;
1715 
1716     case RES_TYPE_ICON:
1717       s = "ICON";
1718       rt = RT_ICON;
1719       break;
1720 
1721     case RES_TYPE_GROUP_ICON:
1722       s = "GROUP_ICON";
1723       rt = RT_GROUP_ICON;
1724       break;
1725 
1726     case RES_TYPE_MENU:
1727       if (extended_menu (res->u.menu))
1728 	{
1729 	  s = "MENUEX";
1730 	  menuex = 1;
1731 	}
1732       else
1733 	{
1734 	  s = "MENU";
1735 	  menuex = 0;
1736 	}
1737       rt = RT_MENU;
1738       break;
1739 
1740     case RES_TYPE_MESSAGETABLE:
1741       s = "MESSAGETABLE";
1742       rt = RT_MESSAGETABLE;
1743       break;
1744 
1745     case RES_TYPE_RCDATA:
1746       s = "RCDATA";
1747       rt = RT_RCDATA;
1748       break;
1749 
1750     case RES_TYPE_STRINGTABLE:
1751       s = "STRINGTABLE";
1752       rt = RT_STRING;
1753       break;
1754 
1755     case RES_TYPE_USERDATA:
1756       s = NULL;
1757       rt = 0;
1758       break;
1759 
1760     case RES_TYPE_VERSIONINFO:
1761       s = "VERSIONINFO";
1762       rt = RT_VERSION;
1763       break;
1764     }
1765 
1766   if (rt != 0
1767       && type != NULL
1768       && (type->named || type->u.id != (unsigned long) rt))
1769     {
1770       fprintf (e, "// Unexpected resource type mismatch: ");
1771       res_id_print (e, *type, 1);
1772       fprintf (e, " != %d", rt);
1773     }
1774 
1775   if (res->coff_info.codepage != 0)
1776     fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1777   if (res->coff_info.reserved != 0)
1778     fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1779 
1780   if (name != NULL)
1781     res_id_print (e, *name, 0);
1782   else
1783     fprintf (e, "??Unknown-Name??");
1784 
1785   fprintf (e, " ");
1786   if (s != NULL)
1787     fprintf (e, "%s", s);
1788   else if (type != NULL)
1789     res_id_print (e, *type, 0);
1790   else
1791     fprintf (e, "??Unknown-Type??");
1792 
1793   if (res->res_info.memflags != 0)
1794     {
1795       if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1796 	fprintf (e, " MOVEABLE");
1797       if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1798 	fprintf (e, " PURE");
1799       if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1800 	fprintf (e, " PRELOAD");
1801       if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1802 	fprintf (e, " DISCARDABLE");
1803     }
1804 
1805   if (res->type == RES_TYPE_DIALOG)
1806     {
1807       fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1808 	       res->u.dialog->width, res->u.dialog->height);
1809       if (res->u.dialog->ex != NULL
1810 	  && res->u.dialog->ex->help != 0)
1811 	fprintf (e, ", %lu", res->u.dialog->ex->help);
1812     }
1813 
1814   fprintf (e, "\n");
1815 
1816   if ((res->res_info.language != 0 && res->res_info.language != *language)
1817       || res->res_info.characteristics != 0
1818       || res->res_info.version != 0)
1819     {
1820       int modifiers;
1821 
1822       switch (res->type)
1823 	{
1824 	case RES_TYPE_ACCELERATOR:
1825 	case RES_TYPE_DIALOG:
1826 	case RES_TYPE_MENU:
1827 	case RES_TYPE_RCDATA:
1828 	case RES_TYPE_STRINGTABLE:
1829 	  modifiers = 1;
1830 	  break;
1831 
1832 	default:
1833 	  modifiers = 0;
1834 	  break;
1835 	}
1836 
1837       if (res->res_info.language != 0 && res->res_info.language != *language)
1838 	fprintf (e, "%sLANGUAGE %d, %d\n",
1839 		 modifiers ? "// " : "",
1840 		 res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
1841 		 (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
1842       if (res->res_info.characteristics != 0)
1843 	fprintf (e, "%sCHARACTERISTICS %lu\n",
1844 		 modifiers ? "// " : "",
1845 		 res->res_info.characteristics);
1846       if (res->res_info.version != 0)
1847 	fprintf (e, "%sVERSION %lu\n",
1848 		 modifiers ? "// " : "",
1849 		 res->res_info.version);
1850     }
1851 
1852   switch (res->type)
1853     {
1854     default:
1855       abort ();
1856 
1857     case RES_TYPE_ACCELERATOR:
1858       write_rc_accelerators (e, res->u.acc);
1859       break;
1860 
1861     case RES_TYPE_CURSOR:
1862       write_rc_cursor (e, res->u.cursor);
1863       break;
1864 
1865     case RES_TYPE_GROUP_CURSOR:
1866       write_rc_group_cursor (e, res->u.group_cursor);
1867       break;
1868 
1869     case RES_TYPE_DIALOG:
1870       write_rc_dialog (e, res->u.dialog);
1871       break;
1872 
1873     case RES_TYPE_FONTDIR:
1874       write_rc_fontdir (e, res->u.fontdir);
1875       break;
1876 
1877     case RES_TYPE_GROUP_ICON:
1878       write_rc_group_icon (e, res->u.group_icon);
1879       break;
1880 
1881     case RES_TYPE_MENU:
1882       write_rc_menu (e, res->u.menu, menuex);
1883       break;
1884 
1885     case RES_TYPE_RCDATA:
1886       write_rc_rcdata (e, res->u.rcdata, 0);
1887       break;
1888 
1889     case RES_TYPE_STRINGTABLE:
1890       write_rc_stringtable (e, name, res->u.stringtable);
1891       break;
1892 
1893     case RES_TYPE_USERDATA:
1894       write_rc_rcdata (e, res->u.userdata, 0);
1895       break;
1896 
1897     case RES_TYPE_VERSIONINFO:
1898       write_rc_versioninfo (e, res->u.versioninfo);
1899       break;
1900 
1901     case RES_TYPE_BITMAP:
1902     case RES_TYPE_FONT:
1903     case RES_TYPE_ICON:
1904     case RES_TYPE_MESSAGETABLE:
1905       write_rc_filedata (e, res->u.data.length, res->u.data.data);
1906       break;
1907     }
1908 }
1909 
1910 /* Write out accelerator information.  */
1911 
1912 static void
1913 write_rc_accelerators (FILE *e, const struct accelerator *accelerators)
1914 {
1915   const struct accelerator *acc;
1916 
1917   fprintf (e, "BEGIN\n");
1918   for (acc = accelerators; acc != NULL; acc = acc->next)
1919     {
1920       int printable;
1921 
1922       fprintf (e, "  ");
1923 
1924       if ((acc->key & 0x7f) == acc->key
1925 	  && ISPRINT (acc->key)
1926 	  && (acc->flags & ACC_VIRTKEY) == 0)
1927 	{
1928 	  fprintf (e, "\"%c\"", acc->key);
1929 	  printable = 1;
1930 	}
1931       else
1932 	{
1933 	  fprintf (e, "%d", acc->key);
1934 	  printable = 0;
1935 	}
1936 
1937       fprintf (e, ", %d", acc->id);
1938 
1939       if (! printable)
1940 	{
1941 	  if ((acc->flags & ACC_VIRTKEY) != 0)
1942 	    fprintf (e, ", VIRTKEY");
1943 	  else
1944 	    fprintf (e, ", ASCII");
1945 	}
1946 
1947       if ((acc->flags & ACC_SHIFT) != 0)
1948 	fprintf (e, ", SHIFT");
1949       if ((acc->flags & ACC_CONTROL) != 0)
1950 	fprintf (e, ", CONTROL");
1951       if ((acc->flags & ACC_ALT) != 0)
1952 	fprintf (e, ", ALT");
1953 
1954       fprintf (e, "\n");
1955     }
1956 
1957   fprintf (e, "END\n");
1958 }
1959 
1960 /* Write out cursor information.  This would normally be in a separate
1961    file, which the rc file would include.  */
1962 
1963 static void
1964 write_rc_cursor (FILE *e, const struct cursor *cursor)
1965 {
1966   fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
1967 	   cursor->yhotspot);
1968   write_rc_filedata (e, cursor->length, cursor->data);
1969 }
1970 
1971 /* Write out group cursor data.  This would normally be built from the
1972    cursor data.  */
1973 
1974 static void
1975 write_rc_group_cursor (FILE *e, const struct group_cursor *group_cursor)
1976 {
1977   const struct group_cursor *gc;
1978 
1979   for (gc = group_cursor; gc != NULL; gc = gc->next)
1980     {
1981       fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
1982 	     gc->width, gc->height, gc->planes, gc->bits);
1983       fprintf (e, "// data bytes: %lu; index: %d\n",
1984 	       gc->bytes, gc->index);
1985     }
1986 }
1987 
1988 /* Write dialog data.  */
1989 
1990 static void
1991 write_rc_dialog (FILE *e, const struct dialog *dialog)
1992 {
1993   const struct dialog_control *control;
1994 
1995   fprintf (e, "STYLE 0x%lx\n", dialog->style);
1996 
1997   if (dialog->exstyle != 0)
1998     fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
1999 
2000   if ((dialog->class.named && dialog->class.u.n.length > 0)
2001       || dialog->class.u.id != 0)
2002     {
2003       fprintf (e, "CLASS ");
2004       res_id_print (e, dialog->class, 1);
2005       fprintf (e, "\n");
2006     }
2007 
2008   if (dialog->caption != NULL)
2009     {
2010       fprintf (e, "CAPTION \"");
2011       unicode_print (e, dialog->caption, -1);
2012       fprintf (e, "\"\n");
2013     }
2014 
2015   if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2016       || dialog->menu.u.id != 0)
2017     {
2018       fprintf (e, "MENU ");
2019       res_id_print (e, dialog->menu, 0);
2020       fprintf (e, "\n");
2021     }
2022 
2023   if (dialog->font != NULL)
2024     {
2025       fprintf (e, "FONT %d, \"", dialog->pointsize);
2026       unicode_print (e, dialog->font, -1);
2027       fprintf (e, "\"");
2028       if (dialog->ex != NULL
2029 	  && (dialog->ex->weight != 0
2030 	      || dialog->ex->italic != 0
2031 	      || dialog->ex->charset != 1))
2032 	fprintf (e, ", %d, %d, %d",
2033 		 dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
2034       fprintf (e, "\n");
2035     }
2036 
2037   fprintf (e, "BEGIN\n");
2038 
2039   for (control = dialog->controls; control != NULL; control = control->next)
2040     write_rc_dialog_control (e, control);
2041 
2042   fprintf (e, "END\n");
2043 }
2044 
2045 /* For each predefined control keyword, this table provides the class
2046    and the style.  */
2047 
2048 struct control_info
2049 {
2050   const char *name;
2051   unsigned short class;
2052   unsigned long style;
2053 };
2054 
2055 static const struct control_info control_info[] =
2056 {
2057   { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2058   { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2059   { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2060   { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2061   { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2062   { "CTEXT", CTL_STATIC, SS_CENTER },
2063   { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2064   { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2065   { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2066   { "ICON", CTL_STATIC, SS_ICON },
2067   { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2068   { "LTEXT", CTL_STATIC, SS_LEFT },
2069   { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2070   { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2071   { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2072   { "RTEXT", CTL_STATIC, SS_RIGHT },
2073   { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2074   { "STATE3", CTL_BUTTON, BS_3STATE },
2075   /* It's important that USERBUTTON come after all the other button
2076      types, so that it won't be matched too early.  */
2077   { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2078   { NULL, 0, 0 }
2079 };
2080 
2081 /* Write a dialog control.  */
2082 
2083 static void
2084 write_rc_dialog_control (FILE *e, const struct dialog_control *control)
2085 {
2086   const struct control_info *ci;
2087 
2088   fprintf (e, "  ");
2089 
2090   if (control->class.named)
2091     ci = NULL;
2092   else
2093     {
2094       for (ci = control_info; ci->name != NULL; ++ci)
2095 	if (ci->class == control->class.u.id
2096 	    && (ci->style == (unsigned long) -1
2097 		|| ci->style == (control->style & 0xff)))
2098 	  break;
2099     }
2100   if (ci == NULL)
2101     fprintf (e, "CONTROL");
2102   else if (ci->name != NULL)
2103     fprintf (e, "%s", ci->name);
2104   else
2105     fprintf (e, "CONTROL");
2106 
2107   if (control->text.named || control->text.u.id != 0)
2108     {
2109       fprintf (e, " ");
2110       res_id_print (e, control->text, 1);
2111       fprintf (e, ",");
2112     }
2113 
2114   fprintf (e, " %d, ", control->id);
2115 
2116   if (ci == NULL)
2117     {
2118       if (control->class.named)
2119 	fprintf (e, "\"");
2120       res_id_print (e, control->class, 0);
2121       if (control->class.named)
2122 	fprintf (e, "\"");
2123       fprintf (e, ", 0x%lx, ", control->style);
2124     }
2125 
2126   fprintf (e, "%d, %d", control->x, control->y);
2127 
2128   if (control->style != SS_ICON
2129       || control->exstyle != 0
2130       || control->width != 0
2131       || control->height != 0
2132       || control->help != 0)
2133     {
2134       fprintf (e, ", %d, %d", control->width, control->height);
2135 
2136       /* FIXME: We don't need to print the style if it is the default.
2137 	 More importantly, in certain cases we actually need to turn
2138 	 off parts of the forced style, by using NOT.  */
2139       fprintf (e, ", 0x%lx", control->style);
2140 
2141       if (control->exstyle != 0 || control->help != 0)
2142 	fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
2143     }
2144 
2145   fprintf (e, "\n");
2146 
2147   if (control->data != NULL)
2148     write_rc_rcdata (e, control->data, 2);
2149 }
2150 
2151 /* Write out font directory data.  This would normally be built from
2152    the font data.  */
2153 
2154 static void
2155 write_rc_fontdir (FILE *e, const struct fontdir *fontdir)
2156 {
2157   const struct fontdir *fc;
2158 
2159   for (fc = fontdir; fc != NULL; fc = fc->next)
2160     {
2161       fprintf (e, "// Font index: %d\n", fc->index);
2162       write_rc_filedata (e, fc->length, fc->data);
2163     }
2164 }
2165 
2166 /* Write out group icon data.  This would normally be built from the
2167    icon data.  */
2168 
2169 static void
2170 write_rc_group_icon (FILE *e, const struct group_icon *group_icon)
2171 {
2172   const struct group_icon *gi;
2173 
2174   for (gi = group_icon; gi != NULL; gi = gi->next)
2175     {
2176       fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
2177 	       gi->width, gi->height, gi->colors, gi->planes, gi->bits);
2178       fprintf (e, "// data bytes: %lu; index: %d\n",
2179 	       gi->bytes, gi->index);
2180     }
2181 }
2182 
2183 /* Write out a menu resource.  */
2184 
2185 static void
2186 write_rc_menu (FILE *e, const struct menu *menu, int menuex)
2187 {
2188   if (menu->help != 0)
2189     fprintf (e, "// Help ID: %lu\n", menu->help);
2190   write_rc_menuitems (e, menu->items, menuex, 0);
2191 }
2192 
2193 /* Write out menuitems.  */
2194 
2195 static void
2196 write_rc_menuitems (FILE *e, const struct menuitem *menuitems, int menuex,
2197 		    int ind)
2198 {
2199   const struct menuitem *mi;
2200 
2201   indent (e, ind);
2202   fprintf (e, "BEGIN\n");
2203 
2204   for (mi = menuitems; mi != NULL; mi = mi->next)
2205     {
2206       indent (e, ind + 2);
2207 
2208       if (mi->popup == NULL)
2209 	fprintf (e, "MENUITEM");
2210       else
2211 	fprintf (e, "POPUP");
2212 
2213       if (! menuex
2214 	  && mi->popup == NULL
2215 	  && mi->text == NULL
2216 	  && mi->type == 0
2217 	  && mi->id == 0)
2218 	{
2219 	  fprintf (e, " SEPARATOR\n");
2220 	  continue;
2221 	}
2222 
2223       if (mi->text == NULL)
2224 	fprintf (e, " \"\"");
2225       else
2226 	{
2227 	  fprintf (e, " \"");
2228 	  unicode_print (e, mi->text, -1);
2229 	  fprintf (e, "\"");
2230 	}
2231 
2232       if (! menuex)
2233 	{
2234 	  if (mi->popup == NULL)
2235 	    fprintf (e, ", %d", mi->id);
2236 
2237 	  if ((mi->type & MENUITEM_CHECKED) != 0)
2238 	    fprintf (e, ", CHECKED");
2239 	  if ((mi->type & MENUITEM_GRAYED) != 0)
2240 	    fprintf (e, ", GRAYED");
2241 	  if ((mi->type & MENUITEM_HELP) != 0)
2242 	    fprintf (e, ", HELP");
2243 	  if ((mi->type & MENUITEM_INACTIVE) != 0)
2244 	    fprintf (e, ", INACTIVE");
2245 	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2246 	    fprintf (e, ", MENUBARBREAK");
2247 	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
2248 	    fprintf (e, ", MENUBREAK");
2249 	}
2250       else
2251 	{
2252 	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2253 	    {
2254 	      fprintf (e, ", %d", mi->id);
2255 	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2256 		{
2257 		  fprintf (e, ", %lu", mi->type);
2258 		  if (mi->state != 0 || mi->help != 0)
2259 		    {
2260 		      fprintf (e, ", %lu", mi->state);
2261 		      if (mi->help != 0)
2262 			fprintf (e, ", %lu", mi->help);
2263 		    }
2264 		}
2265 	    }
2266 	}
2267 
2268       fprintf (e, "\n");
2269 
2270       if (mi->popup != NULL)
2271 	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2272     }
2273 
2274   indent (e, ind);
2275   fprintf (e, "END\n");
2276 }
2277 
2278 /* Write out an rcdata resource.  This is also used for other types of
2279    resources that need to print arbitrary data.  */
2280 
2281 static void
2282 write_rc_rcdata (FILE *e, const struct rcdata_item *rcdata, int ind)
2283 {
2284   const struct rcdata_item *ri;
2285 
2286   indent (e, ind);
2287   fprintf (e, "BEGIN\n");
2288 
2289   for (ri = rcdata; ri != NULL; ri = ri->next)
2290     {
2291       if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2292 	continue;
2293 
2294       indent (e, ind + 2);
2295 
2296       switch (ri->type)
2297 	{
2298 	default:
2299 	  abort ();
2300 
2301 	case RCDATA_WORD:
2302 	  fprintf (e, "%d", ri->u.word);
2303 	  break;
2304 
2305 	case RCDATA_DWORD:
2306 	  fprintf (e, "%luL", ri->u.dword);
2307 	  break;
2308 
2309 	case RCDATA_STRING:
2310 	  {
2311 	    const char *s;
2312 	    unsigned long i;
2313 
2314 	    fprintf (e, "\"");
2315 	    s = ri->u.string.s;
2316 	    for (i = 0; i < ri->u.string.length; i++)
2317 	      {
2318 		if (ISPRINT (*s))
2319 		  putc (*s, e);
2320 		else
2321 		  fprintf (e, "\\%03o", *s);
2322 	      }
2323 	    fprintf (e, "\"");
2324 	    break;
2325 	  }
2326 
2327 	case RCDATA_WSTRING:
2328 	  fprintf (e, "L\"");
2329 	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2330 	  fprintf (e, "\"");
2331 	  break;
2332 
2333 	case RCDATA_BUFFER:
2334 	  {
2335 	    unsigned long i;
2336 	    int first;
2337 
2338 	    /* Assume little endian data.  */
2339 
2340 	    first = 1;
2341 	    for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2342 	      {
2343 		unsigned long l;
2344 		int j;
2345 
2346 		if (! first)
2347 		  indent (e, ind + 2);
2348 		l = ((((((ri->u.buffer.data[i + 3] << 8)
2349 			 | ri->u.buffer.data[i + 2]) << 8)
2350 		       | ri->u.buffer.data[i + 1]) << 8)
2351 		     | ri->u.buffer.data[i]);
2352 		fprintf (e, "%luL", l);
2353 		if (i + 4 < ri->u.buffer.length || ri->next != NULL)
2354 		  fprintf (e, ",");
2355 		for (j = 0; j < 4; ++j)
2356 		  if (! ISPRINT (ri->u.buffer.data[i + j])
2357 		      && ri->u.buffer.data[i + j] != 0)
2358 		    break;
2359 		if (j >= 4)
2360 		  {
2361 		    fprintf (e, "\t// ");
2362 		    for (j = 0; j < 4; ++j)
2363 		      {
2364 			if (! ISPRINT (ri->u.buffer.data[i + j]))
2365 			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2366 			else
2367 			  {
2368 			    if (ri->u.buffer.data[i + j] == '\\')
2369 			      fprintf (e, "\\");
2370 			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
2371 			  }
2372 		      }
2373 		  }
2374 		fprintf (e, "\n");
2375 		first = 0;
2376 	      }
2377 
2378 	    if (i + 1 < ri->u.buffer.length)
2379 	      {
2380 		int s;
2381 		int j;
2382 
2383 		if (! first)
2384 		  indent (e, ind + 2);
2385 		s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2386 		fprintf (e, "%d", s);
2387 		if (i + 2 < ri->u.buffer.length || ri->next != NULL)
2388 		  fprintf (e, ",");
2389 		for (j = 0; j < 2; ++j)
2390 		  if (! ISPRINT (ri->u.buffer.data[i + j])
2391 		      && ri->u.buffer.data[i + j] != 0)
2392 		    break;
2393 		if (j >= 2)
2394 		  {
2395 		    fprintf (e, "\t// ");
2396 		    for (j = 0; j < 2; ++j)
2397 		      {
2398 			if (! ISPRINT (ri->u.buffer.data[i + j]))
2399 			  fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2400 			else
2401 			  {
2402 			    if (ri->u.buffer.data[i + j] == '\\')
2403 			      fprintf (e, "\\");
2404 			    fprintf (e, "%c", ri->u.buffer.data[i + j]);
2405 			  }
2406 		      }
2407 		  }
2408 		fprintf (e, "\n");
2409 		i += 2;
2410 		first = 0;
2411 	      }
2412 
2413 	    if (i < ri->u.buffer.length)
2414 	      {
2415 		if (! first)
2416 		  indent (e, ind + 2);
2417 		if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2418 		    && ISPRINT (ri->u.buffer.data[i]))
2419 		  fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2420 		else
2421 		  fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
2422 		if (ri->next != NULL)
2423 		  fprintf (e, ",");
2424 		fprintf (e, "\n");
2425 		first = 0;
2426 	      }
2427 
2428 	    break;
2429 	  }
2430 	}
2431 
2432       if (ri->type != RCDATA_BUFFER)
2433 	{
2434 	  if (ri->next != NULL)
2435 	    fprintf (e, ",");
2436 	  fprintf (e, "\n");
2437 	}
2438     }
2439 
2440   indent (e, ind);
2441   fprintf (e, "END\n");
2442 }
2443 
2444 /* Write out a stringtable resource.  */
2445 
2446 static void
2447 write_rc_stringtable (FILE *e, const struct res_id *name,
2448 		      const struct stringtable *stringtable)
2449 {
2450   unsigned long offset;
2451   int i;
2452 
2453   if (name != NULL && ! name->named)
2454     offset = (name->u.id - 1) << 4;
2455   else
2456     {
2457       fprintf (e, "// %s string table name\n",
2458 	       name == NULL ? "Missing" : "Invalid");
2459       offset = 0;
2460     }
2461 
2462   fprintf (e, "BEGIN\n");
2463 
2464   for (i = 0; i < 16; i++)
2465     {
2466       if (stringtable->strings[i].length != 0)
2467 	{
2468 	  fprintf (e, "  %lu, \"", offset + i);
2469 	  unicode_print (e, stringtable->strings[i].string,
2470 			 stringtable->strings[i].length);
2471 	  fprintf (e, "\"\n");
2472 	}
2473     }
2474 
2475   fprintf (e, "END\n");
2476 }
2477 
2478 /* Write out a versioninfo resource.  */
2479 
2480 static void
2481 write_rc_versioninfo (FILE *e, const struct versioninfo *versioninfo)
2482 {
2483   const struct fixed_versioninfo *f;
2484   const struct ver_info *vi;
2485 
2486   f = versioninfo->fixed;
2487   if (f->file_version_ms != 0 || f->file_version_ls != 0)
2488     fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2489 	     (f->file_version_ms >> 16) & 0xffff,
2490 	     f->file_version_ms & 0xffff,
2491 	     (f->file_version_ls >> 16) & 0xffff,
2492 	     f->file_version_ls & 0xffff);
2493   if (f->product_version_ms != 0 || f->product_version_ls != 0)
2494     fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2495 	     (f->product_version_ms >> 16) & 0xffff,
2496 	     f->product_version_ms & 0xffff,
2497 	     (f->product_version_ls >> 16) & 0xffff,
2498 	     f->product_version_ls & 0xffff);
2499   if (f->file_flags_mask != 0)
2500     fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2501   if (f->file_flags != 0)
2502     fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2503   if (f->file_os != 0)
2504     fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2505   if (f->file_type != 0)
2506     fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2507   if (f->file_subtype != 0)
2508     fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2509   if (f->file_date_ms != 0 || f->file_date_ls != 0)
2510     fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2511 
2512   fprintf (e, "BEGIN\n");
2513 
2514   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2515     {
2516       switch (vi->type)
2517 	{
2518 	case VERINFO_STRING:
2519 	  {
2520 	    const struct ver_stringinfo *vs;
2521 
2522 	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
2523 	    fprintf (e, "  BEGIN\n");
2524 	    fprintf (e, "    BLOCK \"");
2525 	    unicode_print (e, vi->u.string.language, -1);
2526 	    fprintf (e, "\"\n");
2527 	    fprintf (e, "    BEGIN\n");
2528 
2529 	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2530 	      {
2531 		fprintf (e, "      VALUE \"");
2532 		unicode_print (e, vs->key, -1);
2533 		fprintf (e, "\", \"");
2534 		unicode_print (e, vs->value, -1);
2535 		fprintf (e, "\"\n");
2536 	      }
2537 
2538 	    fprintf (e, "    END\n");
2539 	    fprintf (e, "  END\n");
2540 	    break;
2541 	  }
2542 
2543 	case VERINFO_VAR:
2544 	  {
2545 	    const struct ver_varinfo *vv;
2546 
2547 	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
2548 	    fprintf (e, "  BEGIN\n");
2549 	    fprintf (e, "    VALUE \"");
2550 	    unicode_print (e, vi->u.var.key, -1);
2551 	    fprintf (e, "\"");
2552 
2553 	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2554 	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2555 		       vv->charset);
2556 
2557 	    fprintf (e, "\n  END\n");
2558 
2559 	    break;
2560 	  }
2561 	}
2562     }
2563 
2564   fprintf (e, "END\n");
2565 }
2566 
2567 /* Write out data which would normally be read from a file.  */
2568 
2569 static void
2570 write_rc_filedata (FILE *e, unsigned long length, const unsigned char *data)
2571 {
2572   unsigned long i;
2573 
2574   for (i = 0; i + 15 < length; i += 16)
2575     {
2576       fprintf (e, "// %4lx: ", i);
2577       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2578 	       data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2579 	       data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2580       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2581 	       data[i +  8], data[i +  9], data[i + 10], data[i + 11],
2582 	       data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2583     }
2584 
2585   if (i < length)
2586     {
2587       fprintf (e, "// %4lx:", i);
2588       while (i < length)
2589 	{
2590 	  fprintf (e, " %02x", data[i]);
2591 	  ++i;
2592 	}
2593       fprintf (e, "\n");
2594     }
2595 }
2596