1 /* resrc.c -- read and write Windows rc files.
2    Copyright (C) 1997-2016 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Cygnus Support.
4    Rewritten by Kai Tietz, Onevision.
5 
6    This file is part of GNU Binutils.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21    02110-1301, USA.  */
22 
23 /* This file contains functions that read and write Windows rc files.
24    These are text files that represent resources.  */
25 
26 #include "sysdep.h"
27 #include "bfd.h"
28 #include "bucomm.h"
29 #include "libiberty.h"
30 #include "safe-ctype.h"
31 #include "windres.h"
32 
33 #include <assert.h>
34 
35 #ifdef HAVE_SYS_WAIT_H
36 #include <sys/wait.h>
37 #else /* ! HAVE_SYS_WAIT_H */
38 #if ! defined (_WIN32) || defined (__CYGWIN__)
39 #ifndef WIFEXITED
40 #define WIFEXITED(w)	(((w)&0377) == 0)
41 #endif
42 #ifndef WIFSIGNALED
43 #define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
44 #endif
45 #ifndef WTERMSIG
46 #define WTERMSIG(w)	((w) & 0177)
47 #endif
48 #ifndef WEXITSTATUS
49 #define WEXITSTATUS(w)	(((w) >> 8) & 0377)
50 #endif
51 #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
52 #ifndef WIFEXITED
53 #define WIFEXITED(w)	(((w) & 0xff) == 0)
54 #endif
55 #ifndef WIFSIGNALED
56 #define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
57 #endif
58 #ifndef WTERMSIG
59 #define WTERMSIG(w)	((w) & 0x7f)
60 #endif
61 #ifndef WEXITSTATUS
62 #define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
63 #endif
64 #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
65 #endif /* ! HAVE_SYS_WAIT_H */
66 
67 #ifndef STDOUT_FILENO
68 #define STDOUT_FILENO 1
69 #endif
70 
71 #if defined (_WIN32) && ! defined (__CYGWIN__)
72 #define popen _popen
73 #define pclose _pclose
74 #endif
75 
76 /* The default preprocessor.  */
77 
78 #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
79 
80 /* We read the directory entries in a cursor or icon file into
81    instances of this structure.  */
82 
83 struct icondir
84 {
85   /* Width of image.  */
86   bfd_byte width;
87   /* Height of image.  */
88   bfd_byte height;
89   /* Number of colors in image.  */
90   bfd_byte colorcount;
91   union
92   {
93     struct
94     {
95       /* Color planes.  */
96       unsigned short planes;
97       /* Bits per pixel.  */
98       unsigned short bits;
99     } icon;
100     struct
101     {
102       /* X coordinate of hotspot.  */
103       unsigned short xhotspot;
104       /* Y coordinate of hotspot.  */
105       unsigned short yhotspot;
106     } cursor;
107   } u;
108   /* Bytes in image.  */
109   unsigned long bytes;
110   /* File offset of image.  */
111   unsigned long offset;
112 };
113 
114 /* The name of the rc file we are reading.  */
115 
116 char *rc_filename;
117 
118 /* The line number in the rc file.  */
119 
120 int rc_lineno;
121 
122 /* The pipe we are reading from, so that we can close it if we exit.  */
123 
124 FILE *cpp_pipe;
125 
126 /* The temporary file used if we're not using popen, so we can delete it
127    if we exit.  */
128 
129 static char *cpp_temp_file;
130 
131 /* Input stream is either a file or a pipe.  */
132 
133 static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
134 
135 /* As we read the rc file, we attach information to this structure.  */
136 
137 static rc_res_directory *resources;
138 
139 /* The number of cursor resources we have written out.  */
140 
141 static int cursors;
142 
143 /* The number of font resources we have written out.  */
144 
145 static int fonts;
146 
147 /* Font directory information.  */
148 
149 rc_fontdir *fontdirs;
150 
151 /* Resource info to use for fontdirs.  */
152 
153 rc_res_res_info fontdirs_resinfo;
154 
155 /* The number of icon resources we have written out.  */
156 
157 static int icons;
158 
159 /* The windres target bfd .  */
160 
161 static windres_bfd wrtarget =
162 {
163   (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
164 };
165 
166 /* Local functions for rcdata based resource definitions.  */
167 
168 static void define_font_rcdata (rc_res_id, const rc_res_res_info *,
169 				rc_rcdata_item *);
170 static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
171 				rc_rcdata_item *);
172 static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
173 				  rc_rcdata_item *);
174 static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
175 				  rc_rcdata_item *);
176 static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
177 				   rc_rcdata_item *);
178 static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
179 					rc_rcdata_item *);
180 static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
181 static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
182 
183 static int run_cmd (char *, const char *);
184 static FILE *open_input_stream (char *);
185 static FILE *look_for_default
186   (char *, const char *, int, const char *, const char *);
187 static void close_input_stream (void);
188 static void unexpected_eof (const char *);
189 static int get_word (FILE *, const char *);
190 static unsigned long get_long (FILE *, const char *);
191 static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
192 static void define_fontdirs (void);
193 
194 /* Run `cmd' and redirect the output to `redir'.  */
195 
196 static int
run_cmd(char * cmd,const char * redir)197 run_cmd (char *cmd, const char *redir)
198 {
199   char *s;
200   int pid, wait_status, retcode;
201   int i;
202   const char **argv;
203   char *errmsg_fmt, *errmsg_arg;
204   char *temp_base = choose_temp_base ();
205   int in_quote;
206   char sep;
207   int redir_handle = -1;
208   int stdout_save = -1;
209 
210   /* Count the args.  */
211   i = 0;
212 
213   for (s = cmd; *s; s++)
214     if (*s == ' ')
215       i++;
216 
217   i++;
218   argv = xmalloc (sizeof (char *) * (i + 3));
219   i = 0;
220   s = cmd;
221 
222   while (1)
223     {
224       while (*s == ' ' && *s != 0)
225 	s++;
226 
227       if (*s == 0)
228 	break;
229 
230       in_quote = (*s == '\'' || *s == '"');
231       sep = (in_quote) ? *s++ : ' ';
232       argv[i++] = s;
233 
234       while (*s != sep && *s != 0)
235 	s++;
236 
237       if (*s == 0)
238 	break;
239 
240       *s++ = 0;
241 
242       if (in_quote)
243 	s++;
244     }
245   argv[i++] = NULL;
246 
247   /* Setup the redirection.  We can't use the usual fork/exec and redirect
248      since we may be running on non-POSIX Windows host.  */
249 
250   fflush (stdout);
251   fflush (stderr);
252 
253   /* Open temporary output file.  */
254   redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
255   if (redir_handle == -1)
256     fatal (_("can't open temporary file `%s': %s"), redir,
257 	   strerror (errno));
258 
259   /* Duplicate the stdout file handle so it can be restored later.  */
260   stdout_save = dup (STDOUT_FILENO);
261   if (stdout_save == -1)
262     fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
263 
264   /* Redirect stdout to our output file.  */
265   dup2 (redir_handle, STDOUT_FILENO);
266 
267   pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
268 		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
269   free (argv);
270 
271   /* Restore stdout to its previous setting.  */
272   dup2 (stdout_save, STDOUT_FILENO);
273 
274   /* Close response file.  */
275   close (redir_handle);
276 
277   if (pid == -1)
278     {
279       fatal ("%s %s: %s", errmsg_fmt, errmsg_arg, strerror (errno));
280       return 1;
281     }
282 
283   retcode = 0;
284   pid = pwait (pid, &wait_status, 0);
285 
286   if (pid == -1)
287     {
288       fatal (_("wait: %s"), strerror (errno));
289       retcode = 1;
290     }
291   else if (WIFSIGNALED (wait_status))
292     {
293       fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
294       retcode = 1;
295     }
296   else if (WIFEXITED (wait_status))
297     {
298       if (WEXITSTATUS (wait_status) != 0)
299 	{
300 	  fatal (_("%s exited with status %d"), cmd,
301 	         WEXITSTATUS (wait_status));
302 	  retcode = 1;
303 	}
304     }
305   else
306     retcode = 1;
307 
308   return retcode;
309 }
310 
311 static FILE *
open_input_stream(char * cmd)312 open_input_stream (char *cmd)
313 {
314   if (istream_type == ISTREAM_FILE)
315     {
316       char *fileprefix;
317 
318       fileprefix = choose_temp_base ();
319       cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
320       sprintf (cpp_temp_file, "%s.irc", fileprefix);
321       free (fileprefix);
322 
323       if (run_cmd (cmd, cpp_temp_file))
324 	fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
325 
326       cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);
327       if (cpp_pipe == NULL)
328 	fatal (_("can't open temporary file `%s': %s"),
329 	       cpp_temp_file, strerror (errno));
330 
331       if (verbose)
332 	fprintf (stderr,
333 	         _("Using temporary file `%s' to read preprocessor output\n"),
334 		 cpp_temp_file);
335     }
336   else
337     {
338       cpp_pipe = popen (cmd, FOPEN_RT);
339       if (cpp_pipe == NULL)
340 	fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
341       if (verbose)
342 	fprintf (stderr, _("Using popen to read preprocessor output\n"));
343     }
344 
345   xatexit (close_input_stream);
346   return cpp_pipe;
347 }
348 
349 /* Determine if FILENAME contains special characters that
350    can cause problems unless the entire filename is quoted.  */
351 
352 static int
filename_need_quotes(const char * filename)353 filename_need_quotes (const char *filename)
354 {
355   if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
356     return 0;
357 
358   while (*filename != 0)
359     {
360       switch (*filename)
361         {
362         case '&':
363         case ' ':
364         case '<':
365         case '>':
366         case '|':
367         case '%':
368           return 1;
369         }
370       ++filename;
371     }
372   return 0;
373 }
374 
375 /* Look for the preprocessor program.  */
376 
377 static FILE *
look_for_default(char * cmd,const char * prefix,int end_prefix,const char * preprocargs,const char * filename)378 look_for_default (char *cmd, const char *prefix, int end_prefix,
379 		  const char *preprocargs, const char *filename)
380 {
381   char *space;
382   int found;
383   struct stat s;
384   const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
385 
386   strcpy (cmd, prefix);
387 
388   sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
389   space = strchr (cmd + end_prefix, ' ');
390   if (space)
391     *space = 0;
392 
393   if (
394 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
395       strchr (cmd, '\\') ||
396 #endif
397       strchr (cmd, '/'))
398     {
399       found = (stat (cmd, &s) == 0
400 #ifdef HAVE_EXECUTABLE_SUFFIX
401 	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
402 #endif
403 	       );
404 
405       if (! found)
406 	{
407 	  if (verbose)
408 	    fprintf (stderr, _("Tried `%s'\n"), cmd);
409 	  return NULL;
410 	}
411     }
412 
413   strcpy (cmd, prefix);
414 
415   sprintf (cmd + end_prefix, "%s %s %s%s%s",
416 	   DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
417 
418   if (verbose)
419     fprintf (stderr, _("Using `%s'\n"), cmd);
420 
421   cpp_pipe = open_input_stream (cmd);
422   return cpp_pipe;
423 }
424 
425 /* Read an rc file.  */
426 
427 rc_res_directory *
read_rc_file(const char * filename,const char * preprocessor,const char * preprocargs,int language,int use_temp_file)428 read_rc_file (const char *filename, const char *preprocessor,
429 	      const char *preprocargs, int language, int use_temp_file)
430 {
431   char *cmd;
432   const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
433 
434   if (filename == NULL)
435     filename = "-";
436   /* Setup the default resource import path taken from input file.  */
437   else if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL)
438     {
439       char *edit, *dir;
440 
441       if (filename[0] == '/'
442 	  || filename[0] == '\\'
443 	  || filename[1] == ':')
444         /* Absolute path.  */
445 	edit = dir = xstrdup (filename);
446       else
447 	{
448 	  /* Relative path.  */
449 	  edit = dir = xmalloc (strlen (filename) + 3);
450 	  sprintf (dir, "./%s", filename);
451 	}
452 
453       /* Walk dir backwards stopping at the first directory separator.  */
454       edit += strlen (dir);
455       while (edit > dir && (edit[-1] != '\\' && edit[-1] != '/'))
456 	{
457 	  --edit;
458 	  edit[0] = 0;
459 	}
460 
461       /* Cut off trailing slash.  */
462       --edit;
463       edit[0] = 0;
464 
465       /* Convert all back slashes to forward slashes.  */
466       while ((edit = strchr (dir, '\\')) != NULL)
467 	*edit = '/';
468 
469       windres_add_include_dir (dir);
470     }
471 
472   istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
473 
474   if (preprocargs == NULL)
475     preprocargs = "";
476 
477   if (preprocessor)
478     {
479       cmd = xmalloc (strlen (preprocessor)
480 		     + strlen (preprocargs)
481 		     + strlen (filename)
482 		     + strlen (fnquotes) * 2
483 		     + 10);
484       sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
485 	       fnquotes, filename, fnquotes);
486 
487       cpp_pipe = open_input_stream (cmd);
488     }
489   else
490     {
491       char *dash, *slash, *cp;
492 
493       preprocessor = DEFAULT_PREPROCESSOR;
494 
495       cmd = xmalloc (strlen (program_name)
496 		     + strlen (preprocessor)
497 		     + strlen (preprocargs)
498 		     + strlen (filename)
499 		     + strlen (fnquotes) * 2
500 #ifdef HAVE_EXECUTABLE_SUFFIX
501 		     + strlen (EXECUTABLE_SUFFIX)
502 #endif
503 		     + 10);
504 
505 
506       dash = slash = 0;
507       for (cp = program_name; *cp; cp++)
508 	{
509 	  if (*cp == '-')
510 	    dash = cp;
511 	  if (
512 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
513 	      *cp == ':' || *cp == '\\' ||
514 #endif
515 	      *cp == '/')
516 	    {
517 	      slash = cp;
518 	      dash = 0;
519 	    }
520 	}
521 
522       cpp_pipe = 0;
523 
524       if (dash)
525 	{
526 	  /* First, try looking for a prefixed gcc in the windres
527 	     directory, with the same prefix as windres */
528 
529 	  cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
530 				       preprocargs, filename);
531 	}
532 
533       if (slash && ! cpp_pipe)
534 	{
535 	  /* Next, try looking for a gcc in the same directory as
536              that windres */
537 
538 	  cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
539 				       preprocargs, filename);
540 	}
541 
542       if (! cpp_pipe)
543 	{
544 	  /* Sigh, try the default */
545 
546 	  cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
547 	}
548 
549     }
550 
551   free (cmd);
552 
553   rc_filename = xstrdup (filename);
554   rc_lineno = 1;
555   if (language != -1)
556     rcparse_set_language (language);
557   yyparse ();
558   rcparse_discard_strings ();
559 
560   close_input_stream ();
561 
562   if (fontdirs != NULL)
563     define_fontdirs ();
564 
565   free (rc_filename);
566   rc_filename = NULL;
567 
568   return resources;
569 }
570 
571 /* Close the input stream if it is open.  */
572 
573 static void
close_input_stream(void)574 close_input_stream (void)
575 {
576   if (istream_type == ISTREAM_FILE)
577     {
578       if (cpp_pipe != NULL)
579 	fclose (cpp_pipe);
580 
581       if (cpp_temp_file != NULL)
582 	{
583 	  int errno_save = errno;
584 
585 	  unlink (cpp_temp_file);
586 	  errno = errno_save;
587 	  free (cpp_temp_file);
588 	}
589     }
590   else
591     {
592       if (cpp_pipe != NULL)
593         {
594 	  int err;
595 	  err = pclose (cpp_pipe);
596 	  /* We are reading from a pipe, therefore we don't
597              know if cpp failed or succeeded until pclose.  */
598 	  if (err != 0 || errno == ECHILD)
599 	    {
600 	      /* Since this is also run via xatexit, safeguard.  */
601 	      cpp_pipe = NULL;
602 	      cpp_temp_file = NULL;
603 	      fatal (_("preprocessing failed."));
604 	    }
605         }
606     }
607 
608   /* Since this is also run via xatexit, safeguard.  */
609   cpp_pipe = NULL;
610   cpp_temp_file = NULL;
611 }
612 
613 /* Report an error while reading an rc file.  */
614 
615 void
yyerror(const char * msg)616 yyerror (const char *msg)
617 {
618   fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
619 }
620 
621 /* Issue a warning while reading an rc file.  */
622 
623 void
rcparse_warning(const char * msg)624 rcparse_warning (const char *msg)
625 {
626   fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
627 }
628 
629 /* Die if we get an unexpected end of file.  */
630 
631 static void
unexpected_eof(const char * msg)632 unexpected_eof (const char *msg)
633 {
634   fatal (_("%s: unexpected EOF"), msg);
635 }
636 
637 /* Read a 16 bit word from a file.  The data is assumed to be little
638    endian.  */
639 
640 static int
get_word(FILE * e,const char * msg)641 get_word (FILE *e, const char *msg)
642 {
643   int b1, b2;
644 
645   b1 = getc (e);
646   b2 = getc (e);
647   if (feof (e))
648     unexpected_eof (msg);
649   return ((b2 & 0xff) << 8) | (b1 & 0xff);
650 }
651 
652 /* Read a 32 bit word from a file.  The data is assumed to be little
653    endian.  */
654 
655 static unsigned long
get_long(FILE * e,const char * msg)656 get_long (FILE *e, const char *msg)
657 {
658   int b1, b2, b3, b4;
659 
660   b1 = getc (e);
661   b2 = getc (e);
662   b3 = getc (e);
663   b4 = getc (e);
664   if (feof (e))
665     unexpected_eof (msg);
666   return (((((((b4 & 0xff) << 8)
667 	      | (b3 & 0xff)) << 8)
668 	    | (b2 & 0xff)) << 8)
669 	  | (b1 & 0xff));
670 }
671 
672 /* Read data from a file.  This is a wrapper to do error checking.  */
673 
674 static void
get_data(FILE * e,bfd_byte * p,rc_uint_type c,const char * msg)675 get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
676 {
677   rc_uint_type got; // $$$d
678 
679   got = (rc_uint_type) fread (p, 1, c, e);
680   if (got == c)
681     return;
682 
683   fatal (_("%s: read of %lu returned %lu"),
684 	 msg, (unsigned long) c, (unsigned long) got);
685 }
686 
687 /* Define an accelerator resource.  */
688 
689 void
define_accelerator(rc_res_id id,const rc_res_res_info * resinfo,rc_accelerator * data)690 define_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
691 		    rc_accelerator *data)
692 {
693   rc_res_resource *r;
694 
695   r = define_standard_resource (&resources, RT_ACCELERATOR, id,
696 				resinfo->language, 0);
697   r->type = RES_TYPE_ACCELERATOR;
698   r->u.acc = data;
699   r->res_info = *resinfo;
700 }
701 
702 /* Define a bitmap resource.  Bitmap data is stored in a file.  The
703    first 14 bytes of the file are a standard header, which is not
704    included in the resource data.  */
705 
706 #define BITMAP_SKIP (14)
707 
708 void
define_bitmap(rc_res_id id,const rc_res_res_info * resinfo,const char * filename)709 define_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
710 	       const char *filename)
711 {
712   FILE *e;
713   char *real_filename;
714   struct stat s;
715   bfd_byte *data;
716   rc_uint_type i;
717   rc_res_resource *r;
718 
719   e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
720 
721   if (stat (real_filename, &s) < 0)
722     fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
723 	   strerror (errno));
724 
725   data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
726 
727   for (i = 0; i < BITMAP_SKIP; i++)
728     getc (e);
729 
730   get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
731 
732   fclose (e);
733   free (real_filename);
734 
735   r = define_standard_resource (&resources, RT_BITMAP, id,
736 				resinfo->language, 0);
737 
738   r->type = RES_TYPE_BITMAP;
739   r->u.data.length = s.st_size - BITMAP_SKIP;
740   r->u.data.data = data;
741   r->res_info = *resinfo;
742 }
743 
744 /* Define a cursor resource.  A cursor file may contain a set of
745    bitmaps, each representing the same cursor at various different
746    resolutions.  They each get written out with a different ID.  The
747    real cursor resource is then a group resource which can be used to
748    select one of the actual cursors.  */
749 
750 void
define_cursor(rc_res_id id,const rc_res_res_info * resinfo,const char * filename)751 define_cursor (rc_res_id id, const rc_res_res_info *resinfo,
752 	       const char *filename)
753 {
754   FILE *e;
755   char *real_filename;
756   int type, count, i;
757   struct icondir *icondirs;
758   int first_cursor;
759   rc_res_resource *r;
760   rc_group_cursor *first, **pp;
761 
762   e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
763 
764   /* A cursor file is basically an icon file.  The start of the file
765      is a three word structure.  The first word is ignored.  The
766      second word is the type of data.  The third word is the number of
767      entries.  */
768 
769   get_word (e, real_filename);
770   type = get_word (e, real_filename);
771   count = get_word (e, real_filename);
772   if (type != 2)
773     fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
774 
775   /* Read in the icon directory entries.  */
776 
777   icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
778 
779   for (i = 0; i < count; i++)
780     {
781       icondirs[i].width = getc (e);
782       icondirs[i].height = getc (e);
783       icondirs[i].colorcount = getc (e);
784       getc (e);
785       icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
786       icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
787       icondirs[i].bytes = get_long (e, real_filename);
788       icondirs[i].offset = get_long (e, real_filename);
789 
790       if (feof (e))
791 	unexpected_eof (real_filename);
792     }
793 
794   /* Define each cursor as a unique resource.  */
795 
796   first_cursor = cursors;
797 
798   for (i = 0; i < count; i++)
799     {
800       bfd_byte *data;
801       rc_res_id name;
802       rc_cursor *c;
803 
804       if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
805 	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
806 	       icondirs[i].offset, strerror (errno));
807 
808       data = (bfd_byte *) res_alloc (icondirs[i].bytes);
809 
810       get_data (e, data, icondirs[i].bytes, real_filename);
811 
812       c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
813       c->xhotspot = icondirs[i].u.cursor.xhotspot;
814       c->yhotspot = icondirs[i].u.cursor.yhotspot;
815       c->length = icondirs[i].bytes;
816       c->data = data;
817 
818       ++cursors;
819 
820       name.named = 0;
821       name.u.id = cursors;
822 
823       r = define_standard_resource (&resources, RT_CURSOR, name,
824 				    resinfo->language, 0);
825       r->type = RES_TYPE_CURSOR;
826       r->u.cursor = c;
827       r->res_info = *resinfo;
828     }
829 
830   fclose (e);
831   free (real_filename);
832 
833   /* Define a cursor group resource.  */
834 
835   first = NULL;
836   pp = &first;
837   for (i = 0; i < count; i++)
838     {
839       rc_group_cursor *cg;
840 
841       cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
842       cg->next = NULL;
843       cg->width = icondirs[i].width;
844       cg->height = 2 * icondirs[i].height;
845 
846       /* FIXME: What should these be set to?  */
847       cg->planes = 1;
848       cg->bits = 1;
849 
850       cg->bytes = icondirs[i].bytes + 4;
851       cg->index = first_cursor + i + 1;
852 
853       *pp = cg;
854       pp = &(*pp)->next;
855     }
856 
857   free (icondirs);
858 
859   r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
860 				resinfo->language, 0);
861   r->type = RES_TYPE_GROUP_CURSOR;
862   r->u.group_cursor = first;
863   r->res_info = *resinfo;
864 }
865 
866 /* Define a dialog resource.  */
867 
868 void
define_dialog(rc_res_id id,const rc_res_res_info * resinfo,const rc_dialog * dialog)869 define_dialog (rc_res_id id, const rc_res_res_info *resinfo,
870 	       const rc_dialog *dialog)
871 {
872   rc_dialog *copy;
873   rc_res_resource *r;
874 
875   copy = (rc_dialog *) res_alloc (sizeof *copy);
876   *copy = *dialog;
877 
878   r = define_standard_resource (&resources, RT_DIALOG, id,
879 				resinfo->language, 0);
880   r->type = RES_TYPE_DIALOG;
881   r->u.dialog = copy;
882   r->res_info = *resinfo;
883 }
884 
885 /* Define a dialog control.  This does not define a resource, but
886    merely allocates and fills in a structure.  */
887 
888 rc_dialog_control *
define_control(const rc_res_id iid,rc_uint_type id,rc_uint_type x,rc_uint_type y,rc_uint_type width,rc_uint_type height,const rc_res_id class,rc_uint_type style,rc_uint_type exstyle)889 define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
890 		rc_uint_type y, rc_uint_type width, rc_uint_type height,
891 		const rc_res_id class, rc_uint_type style,
892 		rc_uint_type exstyle)
893 {
894   rc_dialog_control *n;
895 
896   n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
897   n->next = NULL;
898   n->id = id;
899   n->style = style;
900   n->exstyle = exstyle;
901   n->x = x;
902   n->y = y;
903   n->width = width;
904   n->height = height;
905   n->class = class;
906   n->text = iid;
907   n->data = NULL;
908   n->help = 0;
909 
910   return n;
911 }
912 
913 rc_dialog_control *
define_icon_control(rc_res_id iid,rc_uint_type id,rc_uint_type x,rc_uint_type y,rc_uint_type style,rc_uint_type exstyle,rc_uint_type help,rc_rcdata_item * data,rc_dialog_ex * ex)914 define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
915 		     rc_uint_type y, rc_uint_type style,
916 		     rc_uint_type exstyle, rc_uint_type help,
917 		     rc_rcdata_item *data, rc_dialog_ex *ex)
918 {
919   rc_dialog_control *n;
920   rc_res_id tid;
921   rc_res_id cid;
922 
923   if (style == 0)
924     style = SS_ICON | WS_CHILD | WS_VISIBLE;
925   res_string_to_id (&tid, "");
926   cid.named = 0;
927   cid.u.id = CTL_STATIC;
928   n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
929   n->text = iid;
930   if (help && ! ex)
931     rcparse_warning (_("help ID requires DIALOGEX"));
932   if (data && ! ex)
933     rcparse_warning (_("control data requires DIALOGEX"));
934   n->help = help;
935   n->data = data;
936 
937   return n;
938 }
939 
940 /* Define a font resource.  */
941 
942 void
define_font(rc_res_id id,const rc_res_res_info * resinfo,const char * filename)943 define_font (rc_res_id id, const rc_res_res_info *resinfo,
944 	     const char *filename)
945 {
946   FILE *e;
947   char *real_filename;
948   struct stat s;
949   bfd_byte *data;
950   rc_res_resource *r;
951   long offset;
952   long fontdatalength;
953   bfd_byte *fontdata;
954   rc_fontdir *fd;
955   const char *device, *face;
956   rc_fontdir **pp;
957 
958   e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
959 
960   if (stat (real_filename, &s) < 0)
961     fatal (_("stat failed on font file `%s': %s"), real_filename,
962 	   strerror (errno));
963 
964   data = (bfd_byte *) res_alloc (s.st_size);
965 
966   get_data (e, data, s.st_size, real_filename);
967 
968   fclose (e);
969   free (real_filename);
970 
971   r = define_standard_resource (&resources, RT_FONT, id,
972 				resinfo->language, 0);
973 
974   r->type = RES_TYPE_FONT;
975   r->u.data.length = s.st_size;
976   r->u.data.data = data;
977   r->res_info = *resinfo;
978 
979   /* For each font resource, we must add an entry in the FONTDIR
980      resource.  The FONTDIR resource includes some strings in the font
981      file.  To find them, we have to do some magic on the data we have
982      read.  */
983 
984   offset = ((((((data[47] << 8)
985 		| data[46]) << 8)
986 	      | data[45]) << 8)
987 	    | data[44]);
988   if (offset > 0 && offset < s.st_size)
989     device = (char *) data + offset;
990   else
991     device = "";
992 
993   offset = ((((((data[51] << 8)
994 		| data[50]) << 8)
995 	      | data[49]) << 8)
996 	    | data[48]);
997   if (offset > 0 && offset < s.st_size)
998     face = (char *) data + offset;
999   else
1000     face = "";
1001 
1002   ++fonts;
1003 
1004   fontdatalength = 58 + strlen (device) + strlen (face);
1005   fontdata = (bfd_byte *) res_alloc (fontdatalength);
1006   memcpy (fontdata, data, 56);
1007   strcpy ((char *) fontdata + 56, device);
1008   strcpy ((char *) fontdata + 57 + strlen (device), face);
1009 
1010   fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1011   fd->next = NULL;
1012   fd->index = fonts;
1013   fd->length = fontdatalength;
1014   fd->data = fontdata;
1015 
1016   for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
1017     ;
1018   *pp = fd;
1019 
1020   /* For the single fontdirs resource, we always use the resource
1021      information of the last font.  I don't know what else to do.  */
1022   fontdirs_resinfo = *resinfo;
1023 }
1024 
1025 static void
define_font_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1026 define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1027 		    rc_rcdata_item *data)
1028 {
1029   rc_res_resource *r;
1030   rc_uint_type len_data;
1031   bfd_byte *pb_data;
1032 
1033   r = define_standard_resource (&resources, RT_FONT, id,
1034 				resinfo->language, 0);
1035 
1036   pb_data = rcdata_render_as_buffer (data, &len_data);
1037 
1038   r->type = RES_TYPE_FONT;
1039   r->u.data.length = len_data;
1040   r->u.data.data = pb_data;
1041   r->res_info = *resinfo;
1042 }
1043 
1044 /* Define the fontdirs resource.  This is called after the entire rc
1045    file has been parsed, if any font resources were seen.  */
1046 
1047 static void
define_fontdirs(void)1048 define_fontdirs (void)
1049 {
1050   rc_res_resource *r;
1051   rc_res_id id;
1052 
1053   id.named = 0;
1054   id.u.id = 1;
1055 
1056   r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1057 
1058   r->type = RES_TYPE_FONTDIR;
1059   r->u.fontdir = fontdirs;
1060   r->res_info = fontdirs_resinfo;
1061 }
1062 
1063 static bfd_byte *
rcdata_render_as_buffer(const rc_rcdata_item * data,rc_uint_type * plen)1064 rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
1065 {
1066   const rc_rcdata_item *d;
1067   bfd_byte *ret = NULL, *pret;
1068   rc_uint_type len = 0;
1069 
1070   for (d = data; d != NULL; d = d->next)
1071     len += rcdata_copy (d, NULL);
1072   if (len != 0)
1073     {
1074       ret = pret = (bfd_byte *) res_alloc (len);
1075       for (d = data; d != NULL; d = d->next)
1076 	pret += rcdata_copy (d, pret);
1077     }
1078   if (plen)
1079     *plen = len;
1080   return ret;
1081 }
1082 
1083 static void
define_fontdir_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1084 define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1085 		       rc_rcdata_item *data)
1086 {
1087   rc_res_resource *r;
1088   rc_fontdir *fd, *fd_first, *fd_cur;
1089   rc_uint_type len_data;
1090   bfd_byte *pb_data;
1091   rc_uint_type c;
1092 
1093   fd_cur = fd_first = NULL;
1094   r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1095 
1096   pb_data = rcdata_render_as_buffer (data, &len_data);
1097 
1098   if (pb_data)
1099     {
1100       rc_uint_type off = 2;
1101       c = windres_get_16 (&wrtarget, pb_data, len_data);
1102       for (; c > 0; c--)
1103 	{
1104 	  size_t len;
1105 	  rc_uint_type safe_pos = off;
1106 	  const struct bin_fontdir_item *bfi;
1107 
1108 	  bfi = (const struct bin_fontdir_item *) pb_data + off;
1109 	  fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1110 	  fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
1111 	  fd->data = pb_data + off;
1112 	  off += 56;
1113 	  len = strlen ((char *) bfi->device_name) + 1;
1114 	  off += (rc_uint_type) len;
1115 	  off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
1116 	  fd->length = (off - safe_pos);
1117 	  fd->next = NULL;
1118 	  if (fd_first == NULL)
1119 	    fd_first = fd;
1120 	  else
1121 	    fd_cur->next = fd;
1122 	  fd_cur = fd;
1123 	}
1124     }
1125   r->type = RES_TYPE_FONTDIR;
1126   r->u.fontdir = fd_first;
1127   r->res_info = *resinfo;
1128 }
1129 
define_messagetable_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1130 static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1131 					rc_rcdata_item *data)
1132 {
1133   rc_res_resource *r;
1134   rc_uint_type len_data;
1135   bfd_byte *pb_data;
1136 
1137   r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
1138 
1139   pb_data = rcdata_render_as_buffer (data, &len_data);
1140   r->type = RES_TYPE_MESSAGETABLE;
1141   r->u.data.length = len_data;
1142   r->u.data.data = pb_data;
1143   r->res_info = *resinfo;
1144 }
1145 
1146 /* Define an icon resource.  An icon file may contain a set of
1147    bitmaps, each representing the same icon at various different
1148    resolutions.  They each get written out with a different ID.  The
1149    real icon resource is then a group resource which can be used to
1150    select one of the actual icon bitmaps.  */
1151 
1152 void
define_icon(rc_res_id id,const rc_res_res_info * resinfo,const char * filename)1153 define_icon (rc_res_id id, const rc_res_res_info *resinfo,
1154 	     const char *filename)
1155 {
1156   FILE *e;
1157   char *real_filename;
1158   int type, count, i;
1159   struct icondir *icondirs;
1160   int first_icon;
1161   rc_res_resource *r;
1162   rc_group_icon *first, **pp;
1163 
1164   e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1165 
1166   /* The start of an icon file is a three word structure.  The first
1167      word is ignored.  The second word is the type of data.  The third
1168      word is the number of entries.  */
1169 
1170   get_word (e, real_filename);
1171   type = get_word (e, real_filename);
1172   count = get_word (e, real_filename);
1173   if (type != 1)
1174     fatal (_("icon file `%s' does not contain icon data"), real_filename);
1175 
1176   /* Read in the icon directory entries.  */
1177 
1178   icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1179 
1180   for (i = 0; i < count; i++)
1181     {
1182       icondirs[i].width = getc (e);
1183       icondirs[i].height = getc (e);
1184       icondirs[i].colorcount = getc (e);
1185       getc (e);
1186       icondirs[i].u.icon.planes = get_word (e, real_filename);
1187       icondirs[i].u.icon.bits = get_word (e, real_filename);
1188       icondirs[i].bytes = get_long (e, real_filename);
1189       icondirs[i].offset = get_long (e, real_filename);
1190 
1191       if (feof (e))
1192 	unexpected_eof (real_filename);
1193     }
1194 
1195   /* Define each icon as a unique resource.  */
1196 
1197   first_icon = icons;
1198 
1199   for (i = 0; i < count; i++)
1200     {
1201       bfd_byte *data;
1202       rc_res_id name;
1203 
1204       if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1205 	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1206 	       icondirs[i].offset, strerror (errno));
1207 
1208       data = (bfd_byte *) res_alloc (icondirs[i].bytes);
1209 
1210       get_data (e, data, icondirs[i].bytes, real_filename);
1211 
1212       ++icons;
1213 
1214       name.named = 0;
1215       name.u.id = icons;
1216 
1217       r = define_standard_resource (&resources, RT_ICON, name,
1218 				    resinfo->language, 0);
1219       r->type = RES_TYPE_ICON;
1220       r->u.data.length = icondirs[i].bytes;
1221       r->u.data.data = data;
1222       r->res_info = *resinfo;
1223     }
1224 
1225   fclose (e);
1226   free (real_filename);
1227 
1228   /* Define an icon group resource.  */
1229 
1230   first = NULL;
1231   pp = &first;
1232   for (i = 0; i < count; i++)
1233     {
1234       rc_group_icon *cg;
1235 
1236       /* For some reason, at least in some files the planes and bits
1237          are zero.  We instead set them from the color.  This is
1238          copied from rcl.  */
1239 
1240       cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1241       cg->next = NULL;
1242       cg->width = icondirs[i].width;
1243       cg->height = icondirs[i].height;
1244       cg->colors = icondirs[i].colorcount;
1245 
1246       if (icondirs[i].u.icon.planes)
1247 	cg->planes = icondirs[i].u.icon.planes;
1248       else
1249 	cg->planes = 1;
1250 
1251       if (icondirs[i].u.icon.bits)
1252 	cg->bits = icondirs[i].u.icon.bits;
1253       else
1254 	{
1255 	  cg->bits = 0;
1256 
1257 	  while ((1L << cg->bits) < cg->colors)
1258 	    ++cg->bits;
1259 	}
1260 
1261       cg->bytes = icondirs[i].bytes;
1262       cg->index = first_icon + i + 1;
1263 
1264       *pp = cg;
1265       pp = &(*pp)->next;
1266     }
1267 
1268   free (icondirs);
1269 
1270   r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1271 				resinfo->language, 0);
1272   r->type = RES_TYPE_GROUP_ICON;
1273   r->u.group_icon = first;
1274   r->res_info = *resinfo;
1275 }
1276 
1277 static void
define_group_icon_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1278 define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1279 			  rc_rcdata_item *data)
1280 {
1281   rc_res_resource *r;
1282   rc_group_icon *cg, *first, *cur;
1283   rc_uint_type len_data;
1284   bfd_byte *pb_data;
1285 
1286   pb_data = rcdata_render_as_buffer (data, &len_data);
1287 
1288   cur = NULL;
1289   first = NULL;
1290 
1291   while (len_data >= 6)
1292     {
1293       int c, i;
1294       unsigned short type;
1295       type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1296       if (type != 1)
1297 	fatal (_("unexpected group icon type %d"), type);
1298       c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1299       len_data -= 6;
1300       pb_data += 6;
1301 
1302       for (i = 0; i < c; i++)
1303 	{
1304 	  if (len_data < 14)
1305 	    fatal ("too small group icon rcdata");
1306 	  cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1307 	  cg->next = NULL;
1308 	  cg->width = pb_data[0];
1309 	  cg->height = pb_data[1];
1310 	  cg->colors = pb_data[2];
1311 	  cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1312 	  cg->bits =  windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1313 	  cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1314 	  cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1315 	  if (! first)
1316 	    first = cg;
1317 	  else
1318 	    cur->next = cg;
1319 	  cur = cg;
1320 	  pb_data += 14;
1321 	  len_data -= 14;
1322 	}
1323     }
1324   r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1325 				resinfo->language, 0);
1326   r->type = RES_TYPE_GROUP_ICON;
1327   r->u.group_icon = first;
1328   r->res_info = *resinfo;
1329 }
1330 
1331 static void
define_group_cursor_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1332 define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1333 			    rc_rcdata_item *data)
1334 {
1335   rc_res_resource *r;
1336   rc_group_cursor *cg, *first, *cur;
1337   rc_uint_type len_data;
1338   bfd_byte *pb_data;
1339 
1340   pb_data = rcdata_render_as_buffer (data, &len_data);
1341 
1342   first = cur = NULL;
1343 
1344   while (len_data >= 6)
1345     {
1346       int c, i;
1347       unsigned short type;
1348       type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1349       if (type != 2)
1350 	fatal (_("unexpected group cursor type %d"), type);
1351       c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1352       len_data -= 6;
1353       pb_data += 6;
1354 
1355       for (i = 0; i < c; i++)
1356 	{
1357 	  if (len_data < 14)
1358 	    fatal ("too small group icon rcdata");
1359 	  cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
1360 	  cg->next = NULL;
1361 	  cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
1362 	  cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1363 	  cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1364 	  cg->bits =  windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1365 	  cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1366 	  cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1367 	  if (! first)
1368 	    first = cg;
1369 	  else
1370 	    cur->next = cg;
1371 	  cur = cg;
1372 	  pb_data += 14;
1373 	  len_data -= 14;
1374 	}
1375     }
1376 
1377   r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1378 				resinfo->language, 0);
1379   r->type = RES_TYPE_GROUP_CURSOR;
1380   r->u.group_cursor = first;
1381   r->res_info = *resinfo;
1382 }
1383 
1384 static void
define_cursor_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1385 define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1386 		      rc_rcdata_item *data)
1387 {
1388   rc_cursor *c;
1389   rc_res_resource *r;
1390   rc_uint_type len_data;
1391   bfd_byte *pb_data;
1392 
1393   pb_data = rcdata_render_as_buffer (data, &len_data);
1394 
1395   c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
1396   c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
1397   c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1398   c->length = len_data - BIN_CURSOR_SIZE;
1399   c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
1400 
1401   r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
1402   r->type = RES_TYPE_CURSOR;
1403   r->u.cursor = c;
1404   r->res_info = *resinfo;
1405 }
1406 
1407 static void
define_bitmap_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1408 define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1409 		      rc_rcdata_item *data)
1410 {
1411   rc_res_resource *r;
1412   rc_uint_type len_data;
1413   bfd_byte *pb_data;
1414 
1415   pb_data = rcdata_render_as_buffer (data, &len_data);
1416 
1417   r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
1418   r->type = RES_TYPE_BITMAP;
1419   r->u.data.length = len_data;
1420   r->u.data.data = pb_data;
1421   r->res_info = *resinfo;
1422 }
1423 
1424 static void
define_icon_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1425 define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1426 		    rc_rcdata_item *data)
1427 {
1428   rc_res_resource *r;
1429   rc_uint_type len_data;
1430   bfd_byte *pb_data;
1431 
1432   pb_data = rcdata_render_as_buffer (data, &len_data);
1433 
1434   r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
1435   r->type = RES_TYPE_ICON;
1436   r->u.data.length = len_data;
1437   r->u.data.data = pb_data;
1438   r->res_info = *resinfo;
1439 }
1440 
1441 /* Define a menu resource.  */
1442 
1443 void
define_menu(rc_res_id id,const rc_res_res_info * resinfo,rc_menuitem * menuitems)1444 define_menu (rc_res_id id, const rc_res_res_info *resinfo,
1445 	     rc_menuitem *menuitems)
1446 {
1447   rc_menu *m;
1448   rc_res_resource *r;
1449 
1450   m = (rc_menu *) res_alloc (sizeof (rc_menu));
1451   m->items = menuitems;
1452   m->help = 0;
1453 
1454   r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1455   r->type = RES_TYPE_MENU;
1456   r->u.menu = m;
1457   r->res_info = *resinfo;
1458 }
1459 
1460 /* Define a menu item.  This does not define a resource, but merely
1461    allocates and fills in a structure.  */
1462 
1463 rc_menuitem *
define_menuitem(const unichar * text,rc_uint_type menuid,rc_uint_type type,rc_uint_type state,rc_uint_type help,rc_menuitem * menuitems)1464 define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
1465 		 rc_uint_type state, rc_uint_type help,
1466 		 rc_menuitem *menuitems)
1467 {
1468   rc_menuitem *mi;
1469 
1470   mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
1471   mi->next = NULL;
1472   mi->type = type;
1473   mi->state = state;
1474   mi->id = menuid;
1475   mi->text = unichar_dup (text);
1476   mi->help = help;
1477   mi->popup = menuitems;
1478   return mi;
1479 }
1480 
1481 /* Define a messagetable resource.  */
1482 
1483 void
define_messagetable(rc_res_id id,const rc_res_res_info * resinfo,const char * filename)1484 define_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
1485 		     const char *filename)
1486 {
1487   FILE *e;
1488   char *real_filename;
1489   struct stat s;
1490   bfd_byte *data;
1491   rc_res_resource *r;
1492 
1493   e = open_file_search (filename, FOPEN_RB, "messagetable file",
1494 			&real_filename);
1495 
1496   if (stat (real_filename, &s) < 0)
1497     fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1498 	   strerror (errno));
1499 
1500   data = (bfd_byte *) res_alloc (s.st_size);
1501 
1502   get_data (e, data, s.st_size, real_filename);
1503 
1504   fclose (e);
1505   free (real_filename);
1506 
1507   r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1508 				resinfo->language, 0);
1509 
1510   r->type = RES_TYPE_MESSAGETABLE;
1511   r->u.data.length = s.st_size;
1512   r->u.data.data = data;
1513   r->res_info = *resinfo;
1514 }
1515 
1516 /* Define an rcdata resource.  */
1517 
1518 void
define_rcdata(rc_res_id id,const rc_res_res_info * resinfo,rc_rcdata_item * data)1519 define_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1520 	       rc_rcdata_item *data)
1521 {
1522   rc_res_resource *r;
1523 
1524   r = define_standard_resource (&resources, RT_RCDATA, id,
1525 				resinfo->language, 0);
1526   r->type = RES_TYPE_RCDATA;
1527   r->u.rcdata = data;
1528   r->res_info = *resinfo;
1529 }
1530 
1531 /* Create an rcdata item holding a string.  */
1532 
1533 rc_rcdata_item *
define_rcdata_string(const char * string,rc_uint_type len)1534 define_rcdata_string (const char *string, rc_uint_type len)
1535 {
1536   rc_rcdata_item *ri;
1537   char *s;
1538 
1539   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1540   ri->next = NULL;
1541   ri->type = RCDATA_STRING;
1542   ri->u.string.length = len;
1543   s = (char *) res_alloc (len);
1544   memcpy (s, string, len);
1545   ri->u.string.s = s;
1546 
1547   return ri;
1548 }
1549 
1550 /* Create an rcdata item holding a unicode string.  */
1551 
1552 rc_rcdata_item *
define_rcdata_unistring(const unichar * string,rc_uint_type len)1553 define_rcdata_unistring (const unichar *string, rc_uint_type len)
1554 {
1555   rc_rcdata_item *ri;
1556   unichar *s;
1557 
1558   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1559   ri->next = NULL;
1560   ri->type = RCDATA_WSTRING;
1561   ri->u.wstring.length = len;
1562   s = (unichar *) res_alloc (len * sizeof (unichar));
1563   memcpy (s, string, len * sizeof (unichar));
1564   ri->u.wstring.w = s;
1565 
1566   return ri;
1567 }
1568 
1569 /* Create an rcdata item holding a number.  */
1570 
1571 rc_rcdata_item *
define_rcdata_number(rc_uint_type val,int dword)1572 define_rcdata_number (rc_uint_type val, int dword)
1573 {
1574   rc_rcdata_item *ri;
1575 
1576   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1577   ri->next = NULL;
1578   ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1579   ri->u.word = val;
1580 
1581   return ri;
1582 }
1583 
1584 /* Define a stringtable resource.  This is called for each string
1585    which appears in a STRINGTABLE statement.  */
1586 
1587 void
define_stringtable(const rc_res_res_info * resinfo,rc_uint_type stringid,const unichar * string,int len)1588 define_stringtable (const rc_res_res_info *resinfo,
1589 		    rc_uint_type stringid, const unichar *string, int len)
1590 {
1591   unichar *h;
1592   rc_res_id id;
1593   rc_res_resource *r;
1594 
1595   id.named = 0;
1596   id.u.id = (stringid >> 4) + 1;
1597   r = define_standard_resource (&resources, RT_STRING, id,
1598 				resinfo->language, 1);
1599 
1600   if (r->type == RES_TYPE_UNINITIALIZED)
1601     {
1602       int i;
1603 
1604       r->type = RES_TYPE_STRINGTABLE;
1605       r->u.stringtable = ((rc_stringtable *)
1606 			  res_alloc (sizeof (rc_stringtable)));
1607       for (i = 0; i < 16; i++)
1608 	{
1609 	  r->u.stringtable->strings[i].length = 0;
1610 	  r->u.stringtable->strings[i].string = NULL;
1611 	}
1612 
1613       r->res_info = *resinfo;
1614     }
1615   h = (unichar *) res_alloc ((len + 1) * sizeof (unichar));
1616   if (len)
1617     memcpy (h, string, len * sizeof (unichar));
1618   h[len] = 0;
1619   r->u.stringtable->strings[stringid & 0xf].length = (rc_uint_type) len;
1620   r->u.stringtable->strings[stringid & 0xf].string = h;
1621 }
1622 
1623 void
define_toolbar(rc_res_id id,rc_res_res_info * resinfo,rc_uint_type width,rc_uint_type height,rc_toolbar_item * items)1624 define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
1625 		rc_toolbar_item *items)
1626 {
1627   rc_toolbar *t;
1628   rc_res_resource *r;
1629 
1630   t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1631   t->button_width = width;
1632   t->button_height = height;
1633   t->nitems = 0;
1634   t->items = items;
1635   while (items != NULL)
1636   {
1637     t->nitems+=1;
1638     items = items->next;
1639   }
1640   r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
1641   r->type = RES_TYPE_TOOLBAR;
1642   r->u.toolbar = t;
1643   r->res_info = *resinfo;
1644 }
1645 
1646 /* Define a user data resource where the data is in the rc file.  */
1647 
1648 void
define_user_data(rc_res_id id,rc_res_id type,const rc_res_res_info * resinfo,rc_rcdata_item * data)1649 define_user_data (rc_res_id id, rc_res_id type,
1650 		  const rc_res_res_info *resinfo,
1651 		  rc_rcdata_item *data)
1652 {
1653   rc_res_id ids[3];
1654   rc_res_resource *r;
1655   bfd_byte *pb_data;
1656   rc_uint_type len_data;
1657 
1658   /* We have to check if the binary data is parsed specially.  */
1659   if (type.named == 0)
1660     {
1661       switch (type.u.id)
1662       {
1663       case RT_FONTDIR:
1664 	define_fontdir_rcdata (id, resinfo, data);
1665 	return;
1666       case RT_FONT:
1667 	define_font_rcdata (id, resinfo, data);
1668 	return;
1669       case RT_ICON:
1670 	define_icon_rcdata (id, resinfo, data);
1671 	return;
1672       case RT_BITMAP:
1673 	define_bitmap_rcdata (id, resinfo, data);
1674 	return;
1675       case RT_CURSOR:
1676 	define_cursor_rcdata (id, resinfo, data);
1677 	return;
1678       case RT_GROUP_ICON:
1679 	define_group_icon_rcdata (id, resinfo, data);
1680 	return;
1681       case RT_GROUP_CURSOR:
1682 	define_group_cursor_rcdata (id, resinfo, data);
1683 	return;
1684       case RT_MESSAGETABLE:
1685 	define_messagetable_rcdata (id, resinfo, data);
1686 	return;
1687       default:
1688 	/* Treat as normal user-data.  */
1689 	break;
1690       }
1691     }
1692   ids[0] = type;
1693   ids[1] = id;
1694   ids[2].named = 0;
1695   ids[2].u.id = resinfo->language;
1696 
1697   r = define_resource (& resources, 3, ids, 0);
1698   r->type = RES_TYPE_USERDATA;
1699   r->u.userdata = ((rc_rcdata_item *)
1700 		   res_alloc (sizeof (rc_rcdata_item)));
1701   r->u.userdata->next = NULL;
1702   r->u.userdata->type = RCDATA_BUFFER;
1703   pb_data = rcdata_render_as_buffer (data, &len_data);
1704   r->u.userdata->u.buffer.length = len_data;
1705   r->u.userdata->u.buffer.data = pb_data;
1706   r->res_info = *resinfo;
1707 }
1708 
1709 void
define_rcdata_file(rc_res_id id,const rc_res_res_info * resinfo,const char * filename)1710 define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
1711 		    const char *filename)
1712 {
1713   rc_rcdata_item *ri;
1714   FILE *e;
1715   char *real_filename;
1716   struct stat s;
1717   bfd_byte *data;
1718 
1719   e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1720 
1721 
1722   if (stat (real_filename, &s) < 0)
1723     fatal (_("stat failed on file `%s': %s"), real_filename,
1724 	   strerror (errno));
1725 
1726   data = (bfd_byte *) res_alloc (s.st_size);
1727 
1728   get_data (e, data, s.st_size, real_filename);
1729 
1730   fclose (e);
1731   free (real_filename);
1732 
1733   ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1734   ri->next = NULL;
1735   ri->type = RCDATA_BUFFER;
1736   ri->u.buffer.length = s.st_size;
1737   ri->u.buffer.data = data;
1738 
1739   define_rcdata (id, resinfo, ri);
1740 }
1741 
1742 /* Define a user data resource where the data is in a file.  */
1743 
1744 void
define_user_file(rc_res_id id,rc_res_id type,const rc_res_res_info * resinfo,const char * filename)1745 define_user_file (rc_res_id id, rc_res_id type,
1746 		  const rc_res_res_info *resinfo, const char *filename)
1747 {
1748   FILE *e;
1749   char *real_filename;
1750   struct stat s;
1751   bfd_byte *data;
1752   rc_res_id ids[3];
1753   rc_res_resource *r;
1754 
1755   e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1756 
1757   if (stat (real_filename, &s) < 0)
1758     fatal (_("stat failed on file `%s': %s"), real_filename,
1759 	   strerror (errno));
1760 
1761   data = (bfd_byte *) res_alloc (s.st_size);
1762 
1763   get_data (e, data, s.st_size, real_filename);
1764 
1765   fclose (e);
1766   free (real_filename);
1767 
1768   ids[0] = type;
1769   ids[1] = id;
1770   ids[2].named = 0;
1771   ids[2].u.id = resinfo->language;
1772 
1773   r = define_resource (&resources, 3, ids, 0);
1774   r->type = RES_TYPE_USERDATA;
1775   r->u.userdata = ((rc_rcdata_item *)
1776 		   res_alloc (sizeof (rc_rcdata_item)));
1777   r->u.userdata->next = NULL;
1778   r->u.userdata->type = RCDATA_BUFFER;
1779   r->u.userdata->u.buffer.length = s.st_size;
1780   r->u.userdata->u.buffer.data = data;
1781   r->res_info = *resinfo;
1782 }
1783 
1784 /* Define a versioninfo resource.  */
1785 
1786 void
define_versioninfo(rc_res_id id,rc_uint_type language,rc_fixed_versioninfo * fixedverinfo,rc_ver_info * verinfo)1787 define_versioninfo (rc_res_id id, rc_uint_type language,
1788 		    rc_fixed_versioninfo *fixedverinfo,
1789 		    rc_ver_info *verinfo)
1790 {
1791   rc_res_resource *r;
1792 
1793   r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1794   r->type = RES_TYPE_VERSIONINFO;
1795   r->u.versioninfo = ((rc_versioninfo *)
1796 		      res_alloc (sizeof (rc_versioninfo)));
1797   r->u.versioninfo->fixed = fixedverinfo;
1798   r->u.versioninfo->var = verinfo;
1799   r->res_info.language = language;
1800 }
1801 
1802 /* Add string version info to a list of version information.  */
1803 
1804 rc_ver_info *
append_ver_stringfileinfo(rc_ver_info * verinfo,rc_ver_stringtable * stringtables)1805 append_ver_stringfileinfo (rc_ver_info *verinfo,
1806 			   rc_ver_stringtable *stringtables)
1807 {
1808   rc_ver_info *vi, **pp;
1809 
1810   vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1811   vi->next = NULL;
1812   vi->type = VERINFO_STRING;
1813   vi->u.string.stringtables = stringtables;
1814 
1815   for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1816     ;
1817   *pp = vi;
1818 
1819   return verinfo;
1820 }
1821 
1822 rc_ver_stringtable *
append_ver_stringtable(rc_ver_stringtable * stringtable,const char * language,rc_ver_stringinfo * strings)1823 append_ver_stringtable (rc_ver_stringtable *stringtable,
1824 			const char *language,
1825 			rc_ver_stringinfo *strings)
1826 {
1827   rc_ver_stringtable *vst, **pp;
1828 
1829   vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1830   vst->next = NULL;
1831   unicode_from_ascii ((rc_uint_type *) NULL, &vst->language, language);
1832   vst->strings = strings;
1833 
1834   for (pp = &stringtable; *pp != NULL; pp = &(*pp)->next)
1835     ;
1836   *pp = vst;
1837 
1838   return stringtable;
1839 }
1840 
1841 /* Add variable version info to a list of version information.  */
1842 
1843 rc_ver_info *
append_ver_varfileinfo(rc_ver_info * verinfo,const unichar * key,rc_ver_varinfo * var)1844 append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
1845 			rc_ver_varinfo *var)
1846 {
1847   rc_ver_info *vi, **pp;
1848 
1849   vi = (rc_ver_info *) res_alloc (sizeof *vi);
1850   vi->next = NULL;
1851   vi->type = VERINFO_VAR;
1852   vi->u.var.key = unichar_dup (key);
1853   vi->u.var.var = var;
1854 
1855   for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1856     ;
1857   *pp = vi;
1858 
1859   return verinfo;
1860 }
1861 
1862 /* Append version string information to a list.  */
1863 
1864 rc_ver_stringinfo *
append_verval(rc_ver_stringinfo * strings,const unichar * key,const unichar * value)1865 append_verval (rc_ver_stringinfo *strings, const unichar *key,
1866 	       const unichar *value)
1867 {
1868   rc_ver_stringinfo *vs, **pp;
1869 
1870   vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1871   vs->next = NULL;
1872   vs->key = unichar_dup (key);
1873   vs->value = unichar_dup (value);
1874 
1875   for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1876     ;
1877   *pp = vs;
1878 
1879   return strings;
1880 }
1881 
1882 /* Append version variable information to a list.  */
1883 
1884 rc_ver_varinfo *
append_vertrans(rc_ver_varinfo * var,rc_uint_type language,rc_uint_type charset)1885 append_vertrans (rc_ver_varinfo *var, rc_uint_type language,
1886 		 rc_uint_type charset)
1887 {
1888   rc_ver_varinfo *vv, **pp;
1889 
1890   vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1891   vv->next = NULL;
1892   vv->language = language;
1893   vv->charset = charset;
1894 
1895   for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1896     ;
1897   *pp = vv;
1898 
1899   return var;
1900 }
1901 
1902 /* Local functions used to write out an rc file.  */
1903 
1904 static void indent (FILE *, int);
1905 static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
1906 				const rc_res_id *, rc_uint_type *, int);
1907 static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
1908 			     const rc_res_id *, rc_uint_type *, int);
1909 static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
1910 			       const rc_res_resource *, rc_uint_type *);
1911 static void write_rc_accelerators (FILE *, const rc_accelerator *);
1912 static void write_rc_cursor (FILE *, const rc_cursor *);
1913 static void write_rc_group_cursor (FILE *, const rc_group_cursor *);
1914 static void write_rc_dialog (FILE *, const rc_dialog *);
1915 static void write_rc_dialog_control (FILE *, const rc_dialog_control *);
1916 static void write_rc_fontdir (FILE *, const rc_fontdir *);
1917 static void write_rc_group_icon (FILE *, const rc_group_icon *);
1918 static void write_rc_menu (FILE *, const rc_menu *, int);
1919 static void write_rc_toolbar (FILE *, const rc_toolbar *);
1920 static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
1921 static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
1922 
1923 static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
1924 static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
1925 static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
1926 static void write_rc_versioninfo (FILE *, const rc_versioninfo *);
1927 
1928 /* Indent a given number of spaces.  */
1929 
1930 static void
indent(FILE * e,int c)1931 indent (FILE *e, int c)
1932 {
1933   int i;
1934 
1935   for (i = 0; i < c; i++)
1936     putc (' ', e);
1937 }
1938 
1939 /* Dump the resources we have read in the format of an rc file.
1940 
1941    Reasoned by the fact, that some resources need to be stored into file and
1942    refer to that file, we use the user-data model for that to express it binary
1943    without the need to store it somewhere externally.  */
1944 
1945 void
write_rc_file(const char * filename,const rc_res_directory * res_dir)1946 write_rc_file (const char *filename, const rc_res_directory *res_dir)
1947 {
1948   FILE *e;
1949   rc_uint_type language;
1950 
1951   if (filename == NULL)
1952     e = stdout;
1953   else
1954     {
1955       e = fopen (filename, FOPEN_WT);
1956       if (e == NULL)
1957 	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1958     }
1959 
1960   language = (rc_uint_type) ((bfd_signed_vma) -1);
1961   write_rc_directory (e, res_dir, (const rc_res_id *) NULL,
1962 		      (const rc_res_id *) NULL, &language, 1);
1963 }
1964 
1965 /* Write out a directory.  E is the file to write to.  RD is the
1966    directory.  TYPE is a pointer to the level 1 ID which serves as the
1967    resource type.  NAME is a pointer to the level 2 ID which serves as
1968    an individual resource name.  LANGUAGE is a pointer to the current
1969    language.  LEVEL is the level in the tree.  */
1970 
1971 static void
write_rc_directory(FILE * e,const rc_res_directory * rd,const rc_res_id * type,const rc_res_id * name,rc_uint_type * language,int level)1972 write_rc_directory (FILE *e, const rc_res_directory *rd,
1973 		    const rc_res_id *type, const rc_res_id *name,
1974 		    rc_uint_type *language, int level)
1975 {
1976   const rc_res_entry *re;
1977 
1978   /* Print out some COFF information that rc files can't represent.  */
1979   if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
1980     {
1981       wr_printcomment (e, "COFF information not part of RC");
1982   if (rd->time != 0)
1983 	wr_printcomment (e, "Time stamp: %u", rd->time);
1984   if (rd->characteristics != 0)
1985 	wr_printcomment (e, "Characteristics: %u", rd->characteristics);
1986   if (rd->major != 0 || rd->minor != 0)
1987 	wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
1988     }
1989 
1990   for (re = rd->entries;  re != NULL; re = re->next)
1991     {
1992       switch (level)
1993 	{
1994 	case 1:
1995 	  /* If we're at level 1, the key of this resource is the
1996              type.  This normally duplicates the information we have
1997              stored with the resource itself, but we need to remember
1998              the type if this is a user define resource type.  */
1999 	  type = &re->id;
2000 	  break;
2001 
2002 	case 2:
2003 	  /* If we're at level 2, the key of this resource is the name
2004 	     we are going to use in the rc printout.  */
2005 	  name = &re->id;
2006 	  break;
2007 
2008 	case 3:
2009 	  /* If we're at level 3, then this key represents a language.
2010 	     Use it to update the current language.  */
2011 	  if (! re->id.named
2012 	      && re->id.u.id != (unsigned long) (unsigned int) *language
2013 	      && (re->id.u.id & 0xffff) == re->id.u.id)
2014 	    {
2015 	      wr_print (e, "LANGUAGE %u, %u\n",
2016 		       re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
2017 		       (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
2018 	      *language = re->id.u.id;
2019 	    }
2020 	  break;
2021 
2022 	default:
2023 	  break;
2024 	}
2025 
2026       if (re->subdir)
2027 	write_rc_subdir (e, re, type, name, language, level);
2028       else
2029 	{
2030 	  if (level == 3)
2031 	    {
2032 	      /* This is the normal case: the three levels are
2033                  TYPE/NAME/LANGUAGE.  NAME will have been set at level
2034                  2, and represents the name to use.  We probably just
2035                  set LANGUAGE, and it will probably match what the
2036                  resource itself records if anything.  */
2037 	      write_rc_resource (e, type, name, re->u.res, language);
2038 	    }
2039 	  else
2040 	    {
2041 	      wr_printcomment (e, "Resource at unexpected level %d", level);
2042 	      write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
2043 				 language);
2044 	    }
2045 	}
2046     }
2047   if (rd->entries == NULL)
2048     {
2049       wr_print_flush (e);
2050     }
2051 }
2052 
2053 /* Write out a subdirectory entry.  E is the file to write to.  RE is
2054    the subdirectory entry.  TYPE and NAME are pointers to higher level
2055    IDs, or NULL.  LANGUAGE is a pointer to the current language.
2056    LEVEL is the level in the tree.  */
2057 
2058 static void
write_rc_subdir(FILE * e,const rc_res_entry * re,const rc_res_id * type,const rc_res_id * name,rc_uint_type * language,int level)2059 write_rc_subdir (FILE *e, const rc_res_entry *re,
2060 		 const rc_res_id *type, const rc_res_id *name,
2061 		 rc_uint_type *language, int level)
2062 {
2063   fprintf (e, "\n");
2064   switch (level)
2065     {
2066     case 1:
2067       wr_printcomment (e, "Type: ");
2068       if (re->id.named)
2069 	res_id_print (e, re->id, 1);
2070       else
2071 	{
2072 	  const char *s;
2073 
2074 	  switch (re->id.u.id)
2075 	    {
2076 	    case RT_CURSOR: s = "cursor"; break;
2077 	    case RT_BITMAP: s = "bitmap"; break;
2078 	    case RT_ICON: s = "icon"; break;
2079 	    case RT_MENU: s = "menu"; break;
2080 	    case RT_DIALOG: s = "dialog"; break;
2081 	    case RT_STRING: s = "stringtable"; break;
2082 	    case RT_FONTDIR: s = "fontdir"; break;
2083 	    case RT_FONT: s = "font"; break;
2084 	    case RT_ACCELERATOR: s = "accelerators"; break;
2085 	    case RT_RCDATA: s = "rcdata"; break;
2086 	    case RT_MESSAGETABLE: s = "messagetable"; break;
2087 	    case RT_GROUP_CURSOR: s = "group cursor"; break;
2088 	    case RT_GROUP_ICON: s = "group icon"; break;
2089 	    case RT_VERSION: s = "version"; break;
2090 	    case RT_DLGINCLUDE: s = "dlginclude"; break;
2091 	    case RT_PLUGPLAY: s = "plugplay"; break;
2092 	    case RT_VXD: s = "vxd"; break;
2093 	    case RT_ANICURSOR: s = "anicursor"; break;
2094 	    case RT_ANIICON: s = "aniicon"; break;
2095 	    case RT_TOOLBAR: s = "toolbar"; break;
2096 	    case RT_HTML: s = "html"; break;
2097 	    default: s = NULL; break;
2098 	    }
2099 
2100 	  if (s != NULL)
2101 	    fprintf (e, "%s", s);
2102 	  else
2103 	    res_id_print (e, re->id, 1);
2104 	}
2105       break;
2106 
2107     case 2:
2108       wr_printcomment (e, "Name: ");
2109       res_id_print (e, re->id, 1);
2110       break;
2111 
2112     case 3:
2113       wr_printcomment (e, "Language: ");
2114       res_id_print (e, re->id, 1);
2115       break;
2116 
2117     default:
2118       wr_printcomment (e, "Level %d: ", level);
2119       res_id_print (e, re->id, 1);
2120     }
2121 
2122   write_rc_directory (e, re->u.dir, type, name, language, level + 1);
2123 }
2124 
2125 /* Write out a single resource.  E is the file to write to.  TYPE is a
2126    pointer to the type of the resource.  NAME is a pointer to the name
2127    of the resource; it will be NULL if there is a level mismatch.  RES
2128    is the resource data.  LANGUAGE is a pointer to the current
2129    language.  */
2130 
2131 static void
write_rc_resource(FILE * e,const rc_res_id * type,const rc_res_id * name,const rc_res_resource * res,rc_uint_type * language)2132 write_rc_resource (FILE *e, const rc_res_id *type,
2133 		   const rc_res_id *name, const rc_res_resource *res,
2134 		   rc_uint_type *language)
2135 {
2136   const char *s;
2137   int rt;
2138   int menuex = 0;
2139 
2140   switch (res->type)
2141     {
2142     default:
2143       abort ();
2144 
2145     case RES_TYPE_ACCELERATOR:
2146       s = "ACCELERATORS";
2147       rt = RT_ACCELERATOR;
2148       break;
2149 
2150     case RES_TYPE_BITMAP:
2151       s = "2 /* RT_BITMAP */";
2152       rt = RT_BITMAP;
2153       break;
2154 
2155     case RES_TYPE_CURSOR:
2156       s = "1 /* RT_CURSOR */";
2157       rt = RT_CURSOR;
2158       break;
2159 
2160     case RES_TYPE_GROUP_CURSOR:
2161       s = "12 /* RT_GROUP_CURSOR */";
2162       rt = RT_GROUP_CURSOR;
2163       break;
2164 
2165     case RES_TYPE_DIALOG:
2166       if (extended_dialog (res->u.dialog))
2167 	s = "DIALOGEX";
2168       else
2169 	s = "DIALOG";
2170       rt = RT_DIALOG;
2171       break;
2172 
2173     case RES_TYPE_FONT:
2174       s = "8 /* RT_FONT */";
2175       rt = RT_FONT;
2176       break;
2177 
2178     case RES_TYPE_FONTDIR:
2179       s = "7 /* RT_FONTDIR */";
2180       rt = RT_FONTDIR;
2181       break;
2182 
2183     case RES_TYPE_ICON:
2184       s = "3 /* RT_ICON */";
2185       rt = RT_ICON;
2186       break;
2187 
2188     case RES_TYPE_GROUP_ICON:
2189       s = "14 /* RT_GROUP_ICON */";
2190       rt = RT_GROUP_ICON;
2191       break;
2192 
2193     case RES_TYPE_MENU:
2194       if (extended_menu (res->u.menu))
2195 	{
2196 	  s = "MENUEX";
2197 	  menuex = 1;
2198 	}
2199       else
2200 	{
2201 	  s = "MENU";
2202 	  menuex = 0;
2203 	}
2204       rt = RT_MENU;
2205       break;
2206 
2207     case RES_TYPE_MESSAGETABLE:
2208       s = "11 /* RT_MESSAGETABLE */";
2209       rt = RT_MESSAGETABLE;
2210       break;
2211 
2212     case RES_TYPE_RCDATA:
2213       s = "RCDATA";
2214       rt = RT_RCDATA;
2215       break;
2216 
2217     case RES_TYPE_STRINGTABLE:
2218       s = "STRINGTABLE";
2219       rt = RT_STRING;
2220       break;
2221 
2222     case RES_TYPE_USERDATA:
2223       s = NULL;
2224       rt = 0;
2225       break;
2226 
2227     case RES_TYPE_VERSIONINFO:
2228       s = "VERSIONINFO";
2229       rt = RT_VERSION;
2230       break;
2231 
2232     case RES_TYPE_TOOLBAR:
2233       s = "TOOLBAR";
2234       rt = RT_TOOLBAR;
2235       break;
2236     }
2237 
2238   if (rt != 0
2239       && type != NULL
2240       && (type->named || type->u.id != (unsigned long) rt))
2241     {
2242       wr_printcomment (e, "Unexpected resource type mismatch: ");
2243       res_id_print (e, *type, 1);
2244       fprintf (e, " != %d", rt);
2245     }
2246 
2247   if (res->coff_info.codepage != 0)
2248     wr_printcomment (e, "Code page: %u", res->coff_info.codepage);
2249   if (res->coff_info.reserved != 0)
2250     wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved);
2251 
2252   wr_print (e, "\n");
2253   if (rt == RT_STRING)
2254     ;
2255   else
2256     {
2257   if (name != NULL)
2258 	res_id_print (e, *name, 1);
2259   else
2260     fprintf (e, "??Unknown-Name??");
2261   fprintf (e, " ");
2262     }
2263 
2264   if (s != NULL)
2265     fprintf (e, "%s", s);
2266   else if (type != NULL)
2267     {
2268       if (type->named == 0)
2269 	{
2270 #define PRINT_RT_NAME(NAME) case NAME: \
2271 	fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2272 	break
2273 
2274 	  switch (type->u.id)
2275 	    {
2276 	    default:
2277     res_id_print (e, *type, 0);
2278 	      break;
2279 
2280 	    PRINT_RT_NAME(RT_MANIFEST);
2281 	    PRINT_RT_NAME(RT_ANICURSOR);
2282 	    PRINT_RT_NAME(RT_ANIICON);
2283 	    PRINT_RT_NAME(RT_RCDATA);
2284 	    PRINT_RT_NAME(RT_ICON);
2285 	    PRINT_RT_NAME(RT_CURSOR);
2286 	    PRINT_RT_NAME(RT_BITMAP);
2287 	    PRINT_RT_NAME(RT_PLUGPLAY);
2288 	    PRINT_RT_NAME(RT_VXD);
2289 	    PRINT_RT_NAME(RT_FONT);
2290 	    PRINT_RT_NAME(RT_FONTDIR);
2291 	    PRINT_RT_NAME(RT_HTML);
2292 	    PRINT_RT_NAME(RT_MESSAGETABLE);
2293 	    PRINT_RT_NAME(RT_DLGINCLUDE);
2294 	    PRINT_RT_NAME(RT_DLGINIT);
2295 	    }
2296 #undef PRINT_RT_NAME
2297 	}
2298       else
2299 	res_id_print (e, *type, 1);
2300     }
2301   else
2302     fprintf (e, "??Unknown-Type??");
2303 
2304   if (res->res_info.memflags != 0)
2305     {
2306       if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
2307 	fprintf (e, " MOVEABLE");
2308       if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
2309 	fprintf (e, " PURE");
2310       if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
2311 	fprintf (e, " PRELOAD");
2312       if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
2313 	fprintf (e, " DISCARDABLE");
2314     }
2315 
2316   if (res->type == RES_TYPE_DIALOG)
2317     {
2318       fprintf (e, " %d, %d, %d, %d",
2319 	       (int) res->u.dialog->x, (int) res->u.dialog->y,
2320 	       (int) res->u.dialog->width, (int) res->u.dialog->height);
2321       if (res->u.dialog->ex != NULL
2322 	  && res->u.dialog->ex->help != 0)
2323 	fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help);
2324     }
2325   else if (res->type == RES_TYPE_TOOLBAR)
2326   {
2327     fprintf (e, " %d, %d", (int) res->u.toolbar->button_width,
2328 	     (int) res->u.toolbar->button_height);
2329     }
2330 
2331   fprintf (e, "\n");
2332 
2333   if ((res->res_info.language != 0 && res->res_info.language != *language)
2334       || res->res_info.characteristics != 0
2335       || res->res_info.version != 0)
2336     {
2337       int modifiers;
2338 
2339       switch (res->type)
2340 	{
2341 	case RES_TYPE_ACCELERATOR:
2342 	case RES_TYPE_DIALOG:
2343 	case RES_TYPE_MENU:
2344 	case RES_TYPE_RCDATA:
2345 	case RES_TYPE_STRINGTABLE:
2346 	  modifiers = 1;
2347 	  break;
2348 
2349 	default:
2350 	  modifiers = 0;
2351 	  break;
2352 	}
2353 
2354       if (res->res_info.language != 0 && res->res_info.language != *language)
2355 	fprintf (e, "%sLANGUAGE %d, %d\n",
2356 		 modifiers ? "// " : "",
2357 		 (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
2358 		 (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
2359       if (res->res_info.characteristics != 0)
2360 	fprintf (e, "%sCHARACTERISTICS %u\n",
2361 		 modifiers ? "// " : "",
2362 		 (unsigned int) res->res_info.characteristics);
2363       if (res->res_info.version != 0)
2364 	fprintf (e, "%sVERSION %u\n",
2365 		 modifiers ? "// " : "",
2366 		 (unsigned int) res->res_info.version);
2367     }
2368 
2369   switch (res->type)
2370     {
2371     default:
2372       abort ();
2373 
2374     case RES_TYPE_ACCELERATOR:
2375       write_rc_accelerators (e, res->u.acc);
2376       break;
2377 
2378     case RES_TYPE_CURSOR:
2379       write_rc_cursor (e, res->u.cursor);
2380       break;
2381 
2382     case RES_TYPE_GROUP_CURSOR:
2383       write_rc_group_cursor (e, res->u.group_cursor);
2384       break;
2385 
2386     case RES_TYPE_DIALOG:
2387       write_rc_dialog (e, res->u.dialog);
2388       break;
2389 
2390     case RES_TYPE_FONTDIR:
2391       write_rc_fontdir (e, res->u.fontdir);
2392       break;
2393 
2394     case RES_TYPE_GROUP_ICON:
2395       write_rc_group_icon (e, res->u.group_icon);
2396       break;
2397 
2398     case RES_TYPE_MENU:
2399       write_rc_menu (e, res->u.menu, menuex);
2400       break;
2401 
2402     case RES_TYPE_RCDATA:
2403       write_rc_rcdata (e, res->u.rcdata, 0);
2404       break;
2405 
2406     case RES_TYPE_STRINGTABLE:
2407       write_rc_stringtable (e, name, res->u.stringtable);
2408       break;
2409 
2410     case RES_TYPE_USERDATA:
2411       write_rc_rcdata (e, res->u.userdata, 0);
2412       break;
2413 
2414     case RES_TYPE_TOOLBAR:
2415       write_rc_toolbar (e, res->u.toolbar);
2416       break;
2417 
2418     case RES_TYPE_VERSIONINFO:
2419       write_rc_versioninfo (e, res->u.versioninfo);
2420       break;
2421 
2422     case RES_TYPE_BITMAP:
2423     case RES_TYPE_FONT:
2424     case RES_TYPE_ICON:
2425       write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0);
2426       break;
2427     case RES_TYPE_MESSAGETABLE:
2428       write_rc_messagetable (e, res->u.data.length, res->u.data.data);
2429       break;
2430     }
2431 }
2432 
2433 /* Write out accelerator information.  */
2434 
2435 static void
write_rc_accelerators(FILE * e,const rc_accelerator * accelerators)2436 write_rc_accelerators (FILE *e, const rc_accelerator *accelerators)
2437 {
2438   const rc_accelerator *acc;
2439 
2440   fprintf (e, "BEGIN\n");
2441   for (acc = accelerators; acc != NULL; acc = acc->next)
2442     {
2443       int printable;
2444 
2445       fprintf (e, "  ");
2446 
2447       if ((acc->key & 0x7f) == acc->key
2448 	  && ISPRINT (acc->key)
2449 	  && (acc->flags & ACC_VIRTKEY) == 0)
2450 	{
2451 	  fprintf (e, "\"%c\"", (char) acc->key);
2452 	  printable = 1;
2453 	}
2454       else
2455 	{
2456 	  fprintf (e, "%d", (int) acc->key);
2457 	  printable = 0;
2458 	}
2459 
2460       fprintf (e, ", %d", (int) acc->id);
2461 
2462       if (! printable)
2463 	{
2464 	  if ((acc->flags & ACC_VIRTKEY) != 0)
2465 	    fprintf (e, ", VIRTKEY");
2466 	  else
2467 	    fprintf (e, ", ASCII");
2468 	}
2469 
2470       if ((acc->flags & ACC_SHIFT) != 0)
2471 	fprintf (e, ", SHIFT");
2472       if ((acc->flags & ACC_CONTROL) != 0)
2473 	fprintf (e, ", CONTROL");
2474       if ((acc->flags & ACC_ALT) != 0)
2475 	fprintf (e, ", ALT");
2476 
2477       fprintf (e, "\n");
2478     }
2479 
2480   fprintf (e, "END\n");
2481 }
2482 
2483 /* Write out cursor information.  This would normally be in a separate
2484    file, which the rc file would include.  */
2485 
2486 static void
write_rc_cursor(FILE * e,const rc_cursor * cursor)2487 write_rc_cursor (FILE *e, const rc_cursor *cursor)
2488 {
2489   fprintf (e, "BEGIN\n");
2490   indent (e, 2);
2491   fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d.  */\n",
2492 	   (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot,
2493 	   (int) cursor->xhotspot, (int) cursor->yhotspot);
2494   write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data,
2495   		      0, 0, 0);
2496   fprintf (e, "END\n");
2497 }
2498 
2499 /* Write out group cursor data.  This would normally be built from the
2500    cursor data.  */
2501 
2502 static void
write_rc_group_cursor(FILE * e,const rc_group_cursor * group_cursor)2503 write_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor)
2504 {
2505   const rc_group_cursor *gc;
2506   int c;
2507 
2508   for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2509     ;
2510   fprintf (e, "BEGIN\n");
2511 
2512   indent (e, 2);
2513   fprintf (e, "0, 2, %d%s\t /* Having %d items.  */\n", c, (c != 0 ? "," : ""), c);
2514   indent (e, 4);
2515   fprintf (e, "/* width, height, planes, bits, bytes, index.  */\n");
2516 
2517   for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2518     {
2519       indent (e, 4);
2520       fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2521 	(int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits,
2522 	(unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c);
2523       fprintf (e, "/* width: %d; height %d; planes %d; bits %d.  */\n",
2524 	     (int) gc->width, (int) gc->height, (int) gc->planes,
2525 	     (int) gc->bits);
2526     }
2527   fprintf (e, "END\n");
2528 }
2529 
2530 /* Write dialog data.  */
2531 
2532 static void
write_rc_dialog(FILE * e,const rc_dialog * dialog)2533 write_rc_dialog (FILE *e, const rc_dialog *dialog)
2534 {
2535   const rc_dialog_control *control;
2536 
2537   fprintf (e, "STYLE 0x%x\n", dialog->style);
2538 
2539   if (dialog->exstyle != 0)
2540     fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle);
2541 
2542   if ((dialog->class.named && dialog->class.u.n.length > 0)
2543       || dialog->class.u.id != 0)
2544     {
2545       fprintf (e, "CLASS ");
2546       res_id_print (e, dialog->class, 1);
2547       fprintf (e, "\n");
2548     }
2549 
2550   if (dialog->caption != NULL)
2551     {
2552       fprintf (e, "CAPTION ");
2553       unicode_print_quoted (e, dialog->caption, -1);
2554       fprintf (e, "\n");
2555     }
2556 
2557   if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2558       || dialog->menu.u.id != 0)
2559     {
2560       fprintf (e, "MENU ");
2561       res_id_print (e, dialog->menu, 0);
2562       fprintf (e, "\n");
2563     }
2564 
2565   if (dialog->font != NULL)
2566     {
2567       fprintf (e, "FONT %d, ", (int) dialog->pointsize);
2568       unicode_print_quoted (e, dialog->font, -1);
2569       if (dialog->ex != NULL
2570 	  && (dialog->ex->weight != 0
2571 	      || dialog->ex->italic != 0
2572 	      || dialog->ex->charset != 1))
2573 	fprintf (e, ", %d, %d, %d",
2574 		 (int) dialog->ex->weight,
2575 		 (int) dialog->ex->italic,
2576 		 (int) dialog->ex->charset);
2577       fprintf (e, "\n");
2578     }
2579 
2580   fprintf (e, "BEGIN\n");
2581 
2582   for (control = dialog->controls; control != NULL; control = control->next)
2583     write_rc_dialog_control (e, control);
2584 
2585   fprintf (e, "END\n");
2586 }
2587 
2588 /* For each predefined control keyword, this table provides the class
2589    and the style.  */
2590 
2591 struct control_info
2592 {
2593   const char *name;
2594   unsigned short class;
2595   unsigned long style;
2596 };
2597 
2598 static const struct control_info control_info[] =
2599 {
2600   { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2601   { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2602   { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2603   { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2604   { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2605   { "CTEXT", CTL_STATIC, SS_CENTER },
2606   { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2607   { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2608   { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2609   { "ICON", CTL_STATIC, SS_ICON },
2610   { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2611   { "LTEXT", CTL_STATIC, SS_LEFT },
2612   { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2613   { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2614   { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2615   { "RTEXT", CTL_STATIC, SS_RIGHT },
2616   { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2617   { "STATE3", CTL_BUTTON, BS_3STATE },
2618   /* It's important that USERBUTTON come after all the other button
2619      types, so that it won't be matched too early.  */
2620   { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2621   { NULL, 0, 0 }
2622 };
2623 
2624 /* Write a dialog control.  */
2625 
2626 static void
write_rc_dialog_control(FILE * e,const rc_dialog_control * control)2627 write_rc_dialog_control (FILE *e, const rc_dialog_control *control)
2628 {
2629   const struct control_info *ci;
2630 
2631   fprintf (e, "  ");
2632 
2633   if (control->class.named)
2634     ci = NULL;
2635   else
2636     {
2637       for (ci = control_info; ci->name != NULL; ++ci)
2638 	if (ci->class == control->class.u.id
2639 	    && (ci->style == (unsigned long) -1
2640 		|| ci->style == (control->style & 0xff)))
2641 	  break;
2642     }
2643   if (ci == NULL)
2644     fprintf (e, "CONTROL");
2645   else if (ci->name != NULL)
2646     fprintf (e, "%s", ci->name);
2647   else
2648     {
2649     fprintf (e, "CONTROL");
2650       ci = NULL;
2651     }
2652 
2653   /* For EDITTEXT, COMBOBOX, LISTBOX, and SCROLLBAR don't dump text.  */
2654   if ((control->text.named || control->text.u.id != 0)
2655       && (!ci
2656           || (ci->class != CTL_EDIT
2657               && ci->class != CTL_COMBOBOX
2658               && ci->class != CTL_LISTBOX
2659               && ci->class != CTL_SCROLLBAR)))
2660     {
2661       fprintf (e, " ");
2662       res_id_print (e, control->text, 1);
2663       fprintf (e, ",");
2664     }
2665 
2666   fprintf (e, " %d, ", (int) control->id);
2667 
2668   if (ci == NULL)
2669     {
2670       if (control->class.named)
2671 	fprintf (e, "\"");
2672       res_id_print (e, control->class, 0);
2673       if (control->class.named)
2674 	fprintf (e, "\"");
2675       fprintf (e, ", 0x%x, ", (unsigned int) control->style);
2676     }
2677 
2678   fprintf (e, "%d, %d", (int) control->x, (int) control->y);
2679 
2680   if (control->style != SS_ICON
2681       || control->exstyle != 0
2682       || control->width != 0
2683       || control->height != 0
2684       || control->help != 0)
2685     {
2686       fprintf (e, ", %d, %d", (int) control->width, (int) control->height);
2687 
2688       /* FIXME: We don't need to print the style if it is the default.
2689 	 More importantly, in certain cases we actually need to turn
2690 	 off parts of the forced style, by using NOT.  */
2691       if (ci != NULL)
2692 	fprintf (e, ", 0x%x", (unsigned int) control->style);
2693 
2694       if (control->exstyle != 0 || control->help != 0)
2695 	fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle,
2696 		 (unsigned int) control->help);
2697     }
2698 
2699   fprintf (e, "\n");
2700 
2701   if (control->data != NULL)
2702     write_rc_rcdata (e, control->data, 2);
2703 }
2704 
2705 /* Write out font directory data.  This would normally be built from
2706    the font data.  */
2707 
2708 static void
write_rc_fontdir(FILE * e,const rc_fontdir * fontdir)2709 write_rc_fontdir (FILE *e, const rc_fontdir *fontdir)
2710 {
2711   const rc_fontdir *fc;
2712   int c;
2713 
2714   for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++)
2715     ;
2716   fprintf (e, "BEGIN\n");
2717   indent (e, 2);
2718   fprintf (e, "%d%s\t /* Has %d elements.  */\n", c, (c != 0 ? "," : ""), c);
2719   for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++)
2720     {
2721       indent (e, 4);
2722       fprintf (e, "%d,\t/* Font no %d with index %d.  */\n",
2723 	(int) fc->index, c, (int) fc->index);
2724       write_rc_datablock (e, (rc_uint_type) fc->length - 2,
2725 			  (const bfd_byte *) fc->data + 4,fc->next != NULL,
2726 			  0, 0);
2727     }
2728   fprintf (e, "END\n");
2729 }
2730 
2731 /* Write out group icon data.  This would normally be built from the
2732    icon data.  */
2733 
2734 static void
write_rc_group_icon(FILE * e,const rc_group_icon * group_icon)2735 write_rc_group_icon (FILE *e, const rc_group_icon *group_icon)
2736 {
2737   const rc_group_icon *gi;
2738   int c;
2739 
2740   for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++)
2741     ;
2742 
2743   fprintf (e, "BEGIN\n");
2744   indent (e, 2);
2745   fprintf (e, " 0, 1, %d%s\t /* Has %d elements.  */\n", c, (c != 0 ? "," : ""), c);
2746 
2747   indent (e, 4);
2748   fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index.  */\n");
2749   for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++)
2750     {
2751       indent (e, 4);
2752       fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d.  */\n",
2753 	gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits,
2754 	(unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c);
2755     }
2756   fprintf (e, "END\n");
2757 }
2758 
2759 /* Write out a menu resource.  */
2760 
2761 static void
write_rc_menu(FILE * e,const rc_menu * menu,int menuex)2762 write_rc_menu (FILE *e, const rc_menu *menu, int menuex)
2763 {
2764   if (menu->help != 0)
2765     fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help);
2766   write_rc_menuitems (e, menu->items, menuex, 0);
2767 }
2768 
2769 static void
write_rc_toolbar(FILE * e,const rc_toolbar * tb)2770 write_rc_toolbar (FILE *e, const rc_toolbar *tb)
2771 {
2772   rc_toolbar_item *it;
2773   indent (e, 0);
2774   fprintf (e, "BEGIN\n");
2775   it = tb->items;
2776   while(it != NULL)
2777   {
2778     indent (e, 2);
2779     if (it->id.u.id == 0)
2780       fprintf (e, "SEPARATOR\n");
2781     else
2782       fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
2783     it = it->next;
2784   }
2785   indent (e, 0);
2786   fprintf (e, "END\n");
2787 }
2788 
2789 /* Write out menuitems.  */
2790 
2791 static void
write_rc_menuitems(FILE * e,const rc_menuitem * menuitems,int menuex,int ind)2792 write_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex,
2793 		    int ind)
2794 {
2795   const rc_menuitem *mi;
2796 
2797   indent (e, ind);
2798   fprintf (e, "BEGIN\n");
2799 
2800   for (mi = menuitems; mi != NULL; mi = mi->next)
2801     {
2802       indent (e, ind + 2);
2803 
2804       if (mi->popup == NULL)
2805 	fprintf (e, "MENUITEM");
2806       else
2807 	fprintf (e, "POPUP");
2808 
2809       if (! menuex
2810 	  && mi->popup == NULL
2811 	  && mi->text == NULL
2812 	  && mi->type == 0
2813 	  && mi->id == 0)
2814 	{
2815 	  fprintf (e, " SEPARATOR\n");
2816 	  continue;
2817 	}
2818 
2819       if (mi->text == NULL)
2820 	fprintf (e, " \"\"");
2821       else
2822 	{
2823 	  fprintf (e, " ");
2824 	  unicode_print_quoted (e, mi->text, -1);
2825 	}
2826 
2827       if (! menuex)
2828 	{
2829 	  if (mi->popup == NULL)
2830 	    fprintf (e, ", %d", (int) mi->id);
2831 
2832 	  if ((mi->type & MENUITEM_CHECKED) != 0)
2833 	    fprintf (e, ", CHECKED");
2834 	  if ((mi->type & MENUITEM_GRAYED) != 0)
2835 	    fprintf (e, ", GRAYED");
2836 	  if ((mi->type & MENUITEM_HELP) != 0)
2837 	    fprintf (e, ", HELP");
2838 	  if ((mi->type & MENUITEM_INACTIVE) != 0)
2839 	    fprintf (e, ", INACTIVE");
2840 	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2841 	    fprintf (e, ", MENUBARBREAK");
2842 	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
2843 	    fprintf (e, ", MENUBREAK");
2844 	}
2845       else
2846 	{
2847 	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2848 	    {
2849 	      fprintf (e, ", %d", (int) mi->id);
2850 	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2851 		{
2852 		  fprintf (e, ", %u", (unsigned int) mi->type);
2853 		  if (mi->state != 0 || mi->help != 0)
2854 		    {
2855 		      fprintf (e, ", %u", (unsigned int) mi->state);
2856 		      if (mi->help != 0)
2857 			fprintf (e, ", %u", (unsigned int) mi->help);
2858 		    }
2859 		}
2860 	    }
2861 	}
2862 
2863       fprintf (e, "\n");
2864 
2865       if (mi->popup != NULL)
2866 	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2867     }
2868 
2869   indent (e, ind);
2870   fprintf (e, "END\n");
2871 }
2872 
2873 static int
test_rc_datablock_unicode(rc_uint_type length,const bfd_byte * data)2874 test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
2875 {
2876   rc_uint_type i;
2877   if ((length & 1) != 0)
2878     return 0;
2879 
2880   for (i = 0; i < length; i += 2)
2881     {
2882       if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2883 	return 0;
2884       if (data[i] == 0xff && data[i + 1] == 0xff)
2885 	return 0;
2886     }
2887   return 1;
2888 }
2889 
2890 static int
test_rc_datablock_text(rc_uint_type length,const bfd_byte * data)2891 test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2892 {
2893   int has_nl;
2894   rc_uint_type c;
2895   rc_uint_type i;
2896 
2897   if (length <= 1)
2898     return 0;
2899 
2900   has_nl = 0;
2901   for (i = 0, c = 0; i < length; i++)
2902     {
2903       if (! ISPRINT (data[i]) && data[i] != '\n'
2904       	  && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2905       	  && data[i] != '\t'
2906 	  && ! (data[i] == 0 && (i + 1) != length))
2907 	{
2908 	  if (data[i] <= 7)
2909 	    return 0;
2910 	  c++;
2911 	}
2912       else if (data[i] == '\n') has_nl++;
2913     }
2914   if (length > 80 && ! has_nl)
2915     return 0;
2916   c = (((c * 10000) + (i / 100) - 1)) / i;
2917   if (c >= 150)
2918     return 0;
2919   return 1;
2920 }
2921 
2922 static void
write_rc_messagetable(FILE * e,rc_uint_type length,const bfd_byte * data)2923 write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
2924 {
2925   int has_error = 0;
2926   const struct bin_messagetable *mt;
2927 
2928   fprintf (e, "BEGIN\n");
2929 
2930   write_rc_datablock (e, length, data, 0, 0, 0);
2931 
2932   fprintf (e, "\n");
2933   wr_printcomment (e, "MC syntax dump");
2934   if (length < BIN_MESSAGETABLE_SIZE)
2935     has_error = 1;
2936   else
2937     do
2938       {
2939 	rc_uint_type m, i;
2940 
2941 	mt = (const struct bin_messagetable *) data;
2942 	m = windres_get_32 (&wrtarget, mt->cblocks, length);
2943 
2944 	if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2945 	  {
2946 	    has_error = 1;
2947 	    break;
2948 	  }
2949 	for (i = 0; i < m; i++)
2950 	  {
2951 	    rc_uint_type low, high, offset;
2952 	    const struct bin_messagetable_item *mti;
2953 
2954 	    low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2955 	    high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2956 	    offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2957 
2958 	    while (low <= high)
2959 	      {
2960 		rc_uint_type elen, flags;
2961 		if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2962 		  {
2963 		    has_error = 1;
2964 		    break;
2965 		  }
2966 		mti = (const struct bin_messagetable_item *) &data[offset];
2967 		elen = windres_get_16 (&wrtarget, mti->length, 2);
2968 		flags = windres_get_16 (&wrtarget, mti->flags, 2);
2969 		if ((offset + elen) > length)
2970 		  {
2971 		    has_error = 1;
2972 		    break;
2973 		  }
2974 		wr_printcomment (e, "MessageId = 0x%x", low);
2975 		wr_printcomment (e, "");
2976 
2977 		if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2978 		  {
2979 		    /* PR 17512: file: 5c3232dc.  */
2980 		    if (elen > BIN_MESSAGETABLE_ITEM_SIZE * 2)
2981 		      unicode_print (e, (const unichar *) mti->data,
2982 				     (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2983 		  }
2984 		else
2985 		  {
2986 		    if (elen > BIN_MESSAGETABLE_ITEM_SIZE)
2987 		      ascii_print (e, (const char *) mti->data,
2988 				   (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2989 		  }
2990 
2991 		wr_printcomment (e,"");
2992 		++low;
2993 		offset += elen;
2994 	      }
2995 	  }
2996       }
2997     while (0);
2998 
2999   if (has_error)
3000     wr_printcomment (e, "Illegal data");
3001   wr_print_flush (e);
3002   fprintf (e, "END\n");
3003 }
3004 
3005 static void
write_rc_datablock(FILE * e,rc_uint_type length,const bfd_byte * data,int has_next,int hasblock,int show_comment)3006 write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
3007 		    int hasblock, int show_comment)
3008 {
3009   int plen;
3010 
3011   if (hasblock)
3012     fprintf (e, "BEGIN\n");
3013 
3014   if (show_comment == -1)
3015     {
3016       if (test_rc_datablock_text(length, data))
3017 	{
3018 	  rc_uint_type i, c;
3019 	  for (i = 0; i < length;)
3020 	    {
3021 	      indent (e, 2);
3022 	      fprintf (e, "\"");
3023 
3024 	      for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
3025 		;
3026 	      if (i < length && data[i] == '\n')
3027 		++i, ++c;
3028 	      ascii_print(e, (const char *) &data[i - c], c);
3029 	    fprintf (e, "\"");
3030 	      if (i < length)
3031 		fprintf (e, "\n");
3032 	    }
3033 
3034 	  if (i == 0)
3035 	      {
3036 	      indent (e, 2);
3037 	      fprintf (e, "\"\"");
3038 	      }
3039 	  if (has_next)
3040 	    fprintf (e, ",");
3041 	  fprintf (e, "\n");
3042 	  if (hasblock)
3043 	    fprintf (e, "END\n");
3044 	  return;
3045 	  }
3046       if (test_rc_datablock_unicode (length, data))
3047 	{
3048 	  rc_uint_type i, c;
3049 	  for (i = 0; i < length;)
3050 	    {
3051 	      const unichar *u;
3052 
3053 	      u = (const unichar *) &data[i];
3054 	      indent (e, 2);
3055 	  fprintf (e, "L\"");
3056 
3057 	      for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
3058 		;
3059 	      if (i < length && u[c] == '\n')
3060 		i += 2, ++c;
3061 	      unicode_print (e, u, c);
3062 	  fprintf (e, "\"");
3063 	      if (i < length)
3064 		fprintf (e, "\n");
3065 	    }
3066 
3067 	  if (i == 0)
3068 	  {
3069 	      indent (e, 2);
3070 	      fprintf (e, "L\"\"");
3071 	    }
3072 	  if (has_next)
3073 	    fprintf (e, ",");
3074 	  fprintf (e, "\n");
3075 	  if (hasblock)
3076 	    fprintf (e, "END\n");
3077 	  return;
3078 	}
3079 
3080       show_comment = 0;
3081     }
3082 
3083   if (length != 0)
3084 	      {
3085       rc_uint_type i, max_row;
3086       int first = 1;
3087 
3088       max_row = (show_comment ? 4 : 8);
3089       indent (e, 2);
3090       for (i = 0; i + 3 < length;)
3091 		  {
3092 	  rc_uint_type k;
3093 	  rc_uint_type comment_start;
3094 
3095 	  comment_start = i;
3096 
3097 	  if (! first)
3098 	    indent (e, 2);
3099 
3100 	  for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
3101 		      {
3102 	      if (k == 0)
3103 		plen  = fprintf (e, "0x%lxL",
3104 				 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
3105 			else
3106 		plen = fprintf (e, " 0x%lxL",
3107 				(unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
3108 	      if (has_next || (i + 4) < length)
3109 			  {
3110 		  if (plen>0 && plen < 11)
3111 		    indent (e, 11 - plen);
3112 		  fprintf (e, ",");
3113 			  }
3114 		      }
3115 	  if (show_comment)
3116 	    {
3117 	      fprintf (e, "\t/* ");
3118 	      ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3119 	      fprintf (e, ".  */");
3120 		  }
3121 		fprintf (e, "\n");
3122 		first = 0;
3123 	      }
3124 
3125       if (i + 1 < length)
3126 	      {
3127 		if (! first)
3128 	    indent (e, 2);
3129 	  plen = fprintf (e, "0x%x",
3130 	  		  (int) windres_get_16 (&wrtarget, data + i, length - i));
3131 	  if (has_next || i + 2 < length)
3132 		  {
3133 	      if (plen > 0 && plen < 11)
3134 		indent (e, 11 - plen);
3135 	      fprintf (e, ",");
3136 		      }
3137 	  if (show_comment)
3138 	    {
3139 	      fprintf (e, "\t/* ");
3140 	      ascii_print (e, (const char *) &data[i], 2);
3141 	      fprintf (e, ".  */");
3142 		  }
3143 		fprintf (e, "\n");
3144 		i += 2;
3145 		first = 0;
3146 	      }
3147 
3148       if (i < length)
3149 	      {
3150 		if (! first)
3151 	    indent (e, 2);
3152 	  fprintf (e, "\"");
3153 	  ascii_print (e, (const char *) &data[i], 1);
3154 	  fprintf (e, "\"");
3155 	  if (has_next)
3156 		  fprintf (e, ",");
3157 		fprintf (e, "\n");
3158 		first = 0;
3159 	      }
3160     }
3161   if (hasblock)
3162     fprintf (e, "END\n");
3163 }
3164 
3165 /* Write out an rcdata resource.  This is also used for other types of
3166    resources that need to print arbitrary data.  */
3167 
3168 static void
write_rc_rcdata(FILE * e,const rc_rcdata_item * rcdata,int ind)3169 write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3170 {
3171   const rc_rcdata_item *ri;
3172 
3173   indent (e, ind);
3174   fprintf (e, "BEGIN\n");
3175 
3176   for (ri = rcdata; ri != NULL; ri = ri->next)
3177     {
3178       if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3179 	continue;
3180 
3181       switch (ri->type)
3182 	{
3183 	default:
3184 	  abort ();
3185 
3186 	case RCDATA_WORD:
3187 	  indent (e, ind + 2);
3188 	  fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3189 	  break;
3190 
3191 	case RCDATA_DWORD:
3192 	  indent (e, ind + 2);
3193 	  fprintf (e, "%luL", (unsigned long) ri->u.dword);
3194 	  break;
3195 
3196 	case RCDATA_STRING:
3197 	  indent (e, ind + 2);
3198 	  fprintf (e, "\"");
3199 	  ascii_print (e, ri->u.string.s, ri->u.string.length);
3200 	  fprintf (e, "\"");
3201 	  break;
3202 
3203 	case RCDATA_WSTRING:
3204 	  indent (e, ind + 2);
3205 	  fprintf (e, "L\"");
3206 	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3207 	  fprintf (e, "\"");
3208 	  break;
3209 
3210 	case RCDATA_BUFFER:
3211 	  write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3212 	  		      (const bfd_byte *) ri->u.buffer.data,
3213 	    		      ri->next != NULL, 0, -1);
3214 	    break;
3215 	}
3216 
3217       if (ri->type != RCDATA_BUFFER)
3218 	{
3219 	  if (ri->next != NULL)
3220 	    fprintf (e, ",");
3221 	  fprintf (e, "\n");
3222 	}
3223     }
3224 
3225   indent (e, ind);
3226   fprintf (e, "END\n");
3227 }
3228 
3229 /* Write out a stringtable resource.  */
3230 
3231 static void
write_rc_stringtable(FILE * e,const rc_res_id * name,const rc_stringtable * stringtable)3232 write_rc_stringtable (FILE *e, const rc_res_id *name,
3233 		      const rc_stringtable *stringtable)
3234 {
3235   rc_uint_type offset;
3236   int i;
3237 
3238   if (name != NULL && ! name->named)
3239     offset = (name->u.id - 1) << 4;
3240   else
3241     {
3242       fprintf (e, "/* %s string table name.  */\n",
3243 	       name == NULL ? "Missing" : "Invalid");
3244       offset = 0;
3245     }
3246 
3247   fprintf (e, "BEGIN\n");
3248 
3249   for (i = 0; i < 16; i++)
3250     {
3251       if (stringtable->strings[i].length != 0)
3252 	{
3253 	  fprintf (e, "  %lu, ", (unsigned long) offset + i);
3254 	  unicode_print_quoted (e, stringtable->strings[i].string,
3255 			 stringtable->strings[i].length);
3256 	  fprintf (e, "\n");
3257 	}
3258     }
3259 
3260   fprintf (e, "END\n");
3261 }
3262 
3263 /* Write out a versioninfo resource.  */
3264 
3265 static void
write_rc_versioninfo(FILE * e,const rc_versioninfo * versioninfo)3266 write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
3267 {
3268   const rc_fixed_versioninfo *f;
3269   const rc_ver_info *vi;
3270 
3271   f = versioninfo->fixed;
3272   if (f->file_version_ms != 0 || f->file_version_ls != 0)
3273     fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3274 	     (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3275 	     (unsigned int) (f->file_version_ms & 0xffff),
3276 	     (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3277 	     (unsigned int) (f->file_version_ls & 0xffff));
3278   if (f->product_version_ms != 0 || f->product_version_ls != 0)
3279     fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3280 	     (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3281 	     (unsigned int) (f->product_version_ms & 0xffff),
3282 	     (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3283 	     (unsigned int) (f->product_version_ls & 0xffff));
3284   if (f->file_flags_mask != 0)
3285     fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
3286   if (f->file_flags != 0)
3287     fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
3288   if (f->file_os != 0)
3289     fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
3290   if (f->file_type != 0)
3291     fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
3292   if (f->file_subtype != 0)
3293     fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
3294   if (f->file_date_ms != 0 || f->file_date_ls != 0)
3295     fprintf (e, "/* Date: %u, %u.  */\n",
3296     	     (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
3297 
3298   fprintf (e, "BEGIN\n");
3299 
3300   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3301     {
3302       switch (vi->type)
3303 	{
3304 	case VERINFO_STRING:
3305 	  {
3306 	    const rc_ver_stringtable *vst;
3307 	    const rc_ver_stringinfo *vs;
3308 
3309 	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
3310 	    fprintf (e, "  BEGIN\n");
3311 
3312 	    for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
3313 	      {
3314 		fprintf (e, "    BLOCK ");
3315 		unicode_print_quoted (e, vst->language, -1);
3316 
3317 		fprintf (e, "\n");
3318 		fprintf (e, "    BEGIN\n");
3319 
3320 		for (vs = vst->strings; vs != NULL; vs = vs->next)
3321 		  {
3322 		    fprintf (e, "      VALUE ");
3323 		    unicode_print_quoted (e, vs->key, -1);
3324 		    fprintf (e, ", ");
3325 		    unicode_print_quoted (e, vs->value, -1);
3326 		    fprintf (e, "\n");
3327 		  }
3328 
3329 		fprintf (e, "    END\n");
3330 	      }
3331 	    fprintf (e, "  END\n");
3332 	    break;
3333 	  }
3334 
3335 	case VERINFO_VAR:
3336 	  {
3337 	    const rc_ver_varinfo *vv;
3338 
3339 	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
3340 	    fprintf (e, "  BEGIN\n");
3341 	    fprintf (e, "    VALUE ");
3342 	    unicode_print_quoted (e, vi->u.var.key, -1);
3343 
3344 	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3345 	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3346 		       (int) vv->charset);
3347 
3348 	    fprintf (e, "\n  END\n");
3349 
3350 	    break;
3351 	  }
3352 	}
3353     }
3354 
3355   fprintf (e, "END\n");
3356 }
3357 
3358 static rc_uint_type
rcdata_copy(const rc_rcdata_item * src,bfd_byte * dst)3359 rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
3360 {
3361   if (! src)
3362     return 0;
3363   switch (src->type)
3364 	{
3365     case RCDATA_WORD:
3366       if (dst)
3367 	windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3368       return 2;
3369     case RCDATA_DWORD:
3370       if (dst)
3371 	windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3372       return 4;
3373     case RCDATA_STRING:
3374       if (dst && src->u.string.length)
3375 	memcpy (dst, src->u.string.s, src->u.string.length);
3376       return (rc_uint_type) src->u.string.length;
3377     case RCDATA_WSTRING:
3378       if (dst && src->u.wstring.length)
3379 	memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3380       return (rc_uint_type) (src->u.wstring.length  * sizeof (unichar));
3381     case RCDATA_BUFFER:
3382       if (dst && src->u.buffer.length)
3383 	memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3384       return (rc_uint_type) src->u.buffer.length;
3385     default:
3386       abort ();
3387     }
3388   /* Never reached.  */
3389   return 0;
3390 }
3391