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