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