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