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