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