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