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