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