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