OSDN Git Service

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