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