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