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