1/* resrc.c -- read and write Windows rc files.
2   Copyright (C) 1997-2017 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	}
2845      else
2846	{
2847	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2848	    {
2849	      fprintf (e, ", %d", (int) mi->id);
2850	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2851		{
2852		  fprintf (e, ", %u", (unsigned int) mi->type);
2853		  if (mi->state != 0 || mi->help != 0)
2854		    {
2855		      fprintf (e, ", %u", (unsigned int) mi->state);
2856		      if (mi->help != 0)
2857			fprintf (e, ", %u", (unsigned int) mi->help);
2858		    }
2859		}
2860	    }
2861	}
2862
2863      fprintf (e, "\n");
2864
2865      if (mi->popup != NULL)
2866	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2867    }
2868
2869  indent (e, ind);
2870  fprintf (e, "END\n");
2871}
2872
2873static int
2874test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
2875{
2876  rc_uint_type i;
2877  if ((length & 1) != 0)
2878    return 0;
2879
2880  for (i = 0; i < length; i += 2)
2881    {
2882      if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2883	return 0;
2884      if (data[i] == 0xff && data[i + 1] == 0xff)
2885	return 0;
2886    }
2887  return 1;
2888}
2889
2890static int
2891test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2892{
2893  int has_nl;
2894  rc_uint_type c;
2895  rc_uint_type i;
2896
2897  if (length <= 1)
2898    return 0;
2899
2900  has_nl = 0;
2901  for (i = 0, c = 0; i < length; i++)
2902    {
2903      if (! ISPRINT (data[i]) && data[i] != '\n'
2904      	  && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2905      	  && data[i] != '\t'
2906	  && ! (data[i] == 0 && (i + 1) != length))
2907	{
2908	  if (data[i] <= 7)
2909	    return 0;
2910	  c++;
2911	}
2912      else if (data[i] == '\n') has_nl++;
2913    }
2914  if (length > 80 && ! has_nl)
2915    return 0;
2916  c = (((c * 10000) + (i / 100) - 1)) / i;
2917  if (c >= 150)
2918    return 0;
2919  return 1;
2920}
2921
2922static void
2923write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
2924{
2925  int has_error = 0;
2926  const struct bin_messagetable *mt;
2927
2928  fprintf (e, "BEGIN\n");
2929
2930  write_rc_datablock (e, length, data, 0, 0, 0);
2931
2932  fprintf (e, "\n");
2933  wr_printcomment (e, "MC syntax dump");
2934  if (length < BIN_MESSAGETABLE_SIZE)
2935    has_error = 1;
2936  else
2937    do
2938      {
2939	rc_uint_type m, i;
2940
2941	mt = (const struct bin_messagetable *) data;
2942	m = windres_get_32 (&wrtarget, mt->cblocks, length);
2943
2944	if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2945	  {
2946	    has_error = 1;
2947	    break;
2948	  }
2949	for (i = 0; i < m; i++)
2950	  {
2951	    rc_uint_type low, high, offset;
2952	    const struct bin_messagetable_item *mti;
2953
2954	    low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2955	    high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2956	    offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2957
2958	    while (low <= high)
2959	      {
2960		rc_uint_type elen, flags;
2961		if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2962		  {
2963		    has_error = 1;
2964		    break;
2965		  }
2966		mti = (const struct bin_messagetable_item *) &data[offset];
2967		elen = windres_get_16 (&wrtarget, mti->length, 2);
2968		flags = windres_get_16 (&wrtarget, mti->flags, 2);
2969		if ((offset + elen) > length)
2970		  {
2971		    has_error = 1;
2972		    break;
2973		  }
2974		wr_printcomment (e, "MessageId = 0x%x", low);
2975		wr_printcomment (e, "");
2976
2977		if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2978		  {
2979		    /* PR 17512: file: 5c3232dc.  */
2980		    if (elen > BIN_MESSAGETABLE_ITEM_SIZE * 2)
2981		      unicode_print (e, (const unichar *) mti->data,
2982				     (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2983		  }
2984		else
2985		  {
2986		    if (elen > BIN_MESSAGETABLE_ITEM_SIZE)
2987		      ascii_print (e, (const char *) mti->data,
2988				   (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2989		  }
2990
2991		wr_printcomment (e,"");
2992		++low;
2993		offset += elen;
2994	      }
2995	  }
2996      }
2997    while (0);
2998
2999  if (has_error)
3000    wr_printcomment (e, "Illegal data");
3001  wr_print_flush (e);
3002  fprintf (e, "END\n");
3003}
3004
3005static void
3006write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
3007		    int hasblock, int show_comment)
3008{
3009  int plen;
3010
3011  if (hasblock)
3012    fprintf (e, "BEGIN\n");
3013
3014  if (show_comment == -1)
3015    {
3016      if (test_rc_datablock_text(length, data))
3017	{
3018	  rc_uint_type i, c;
3019	  for (i = 0; i < length;)
3020	    {
3021	      indent (e, 2);
3022	      fprintf (e, "\"");
3023
3024	      for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
3025		;
3026	      if (i < length && data[i] == '\n')
3027		++i, ++c;
3028	      ascii_print(e, (const char *) &data[i - c], c);
3029	    fprintf (e, "\"");
3030	      if (i < length)
3031		fprintf (e, "\n");
3032	    }
3033
3034	  if (i == 0)
3035	      {
3036	      indent (e, 2);
3037	      fprintf (e, "\"\"");
3038	      }
3039	  if (has_next)
3040	    fprintf (e, ",");
3041	  fprintf (e, "\n");
3042	  if (hasblock)
3043	    fprintf (e, "END\n");
3044	  return;
3045	  }
3046      if (test_rc_datablock_unicode (length, data))
3047	{
3048	  rc_uint_type i, c;
3049	  for (i = 0; i < length;)
3050	    {
3051	      const unichar *u;
3052
3053	      u = (const unichar *) &data[i];
3054	      indent (e, 2);
3055	  fprintf (e, "L\"");
3056
3057	      for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
3058		;
3059	      if (i < length && u[c] == '\n')
3060		i += 2, ++c;
3061	      unicode_print (e, u, c);
3062	  fprintf (e, "\"");
3063	      if (i < length)
3064		fprintf (e, "\n");
3065	    }
3066
3067	  if (i == 0)
3068	  {
3069	      indent (e, 2);
3070	      fprintf (e, "L\"\"");
3071	    }
3072	  if (has_next)
3073	    fprintf (e, ",");
3074	  fprintf (e, "\n");
3075	  if (hasblock)
3076	    fprintf (e, "END\n");
3077	  return;
3078	}
3079
3080      show_comment = 0;
3081    }
3082
3083  if (length != 0)
3084	      {
3085      rc_uint_type i, max_row;
3086      int first = 1;
3087
3088      max_row = (show_comment ? 4 : 8);
3089      indent (e, 2);
3090      for (i = 0; i + 3 < length;)
3091		  {
3092	  rc_uint_type k;
3093	  rc_uint_type comment_start;
3094
3095	  comment_start = i;
3096
3097	  if (! first)
3098	    indent (e, 2);
3099
3100	  for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
3101		      {
3102	      if (k == 0)
3103		plen  = fprintf (e, "0x%lxL",
3104				 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
3105			else
3106		plen = fprintf (e, " 0x%lxL",
3107				(unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
3108	      if (has_next || (i + 4) < length)
3109			  {
3110		  if (plen>0 && plen < 11)
3111		    indent (e, 11 - plen);
3112		  fprintf (e, ",");
3113			  }
3114		      }
3115	  if (show_comment)
3116	    {
3117	      fprintf (e, "\t/* ");
3118	      ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3119	      fprintf (e, ".  */");
3120		  }
3121		fprintf (e, "\n");
3122		first = 0;
3123	      }
3124
3125      if (i + 1 < length)
3126	      {
3127		if (! first)
3128	    indent (e, 2);
3129	  plen = fprintf (e, "0x%x",
3130	  		  (int) windres_get_16 (&wrtarget, data + i, length - i));
3131	  if (has_next || i + 2 < length)
3132		  {
3133	      if (plen > 0 && plen < 11)
3134		indent (e, 11 - plen);
3135	      fprintf (e, ",");
3136		      }
3137	  if (show_comment)
3138	    {
3139	      fprintf (e, "\t/* ");
3140	      ascii_print (e, (const char *) &data[i], 2);
3141	      fprintf (e, ".  */");
3142		  }
3143		fprintf (e, "\n");
3144		i += 2;
3145		first = 0;
3146	      }
3147
3148      if (i < length)
3149	      {
3150		if (! first)
3151	    indent (e, 2);
3152	  fprintf (e, "\"");
3153	  ascii_print (e, (const char *) &data[i], 1);
3154	  fprintf (e, "\"");
3155	  if (has_next)
3156		  fprintf (e, ",");
3157		fprintf (e, "\n");
3158		first = 0;
3159	      }
3160    }
3161  if (hasblock)
3162    fprintf (e, "END\n");
3163}
3164
3165/* Write out an rcdata resource.  This is also used for other types of
3166   resources that need to print arbitrary data.  */
3167
3168static void
3169write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3170{
3171  const rc_rcdata_item *ri;
3172
3173  indent (e, ind);
3174  fprintf (e, "BEGIN\n");
3175
3176  for (ri = rcdata; ri != NULL; ri = ri->next)
3177    {
3178      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3179	continue;
3180
3181      switch (ri->type)
3182	{
3183	default:
3184	  abort ();
3185
3186	case RCDATA_WORD:
3187	  indent (e, ind + 2);
3188	  fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3189	  break;
3190
3191	case RCDATA_DWORD:
3192	  indent (e, ind + 2);
3193	  fprintf (e, "%luL", (unsigned long) ri->u.dword);
3194	  break;
3195
3196	case RCDATA_STRING:
3197	  indent (e, ind + 2);
3198	  fprintf (e, "\"");
3199	  ascii_print (e, ri->u.string.s, ri->u.string.length);
3200	  fprintf (e, "\"");
3201	  break;
3202
3203	case RCDATA_WSTRING:
3204	  indent (e, ind + 2);
3205	  fprintf (e, "L\"");
3206	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3207	  fprintf (e, "\"");
3208	  break;
3209
3210	case RCDATA_BUFFER:
3211	  write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3212	  		      (const bfd_byte *) ri->u.buffer.data,
3213	    		      ri->next != NULL, 0, -1);
3214	    break;
3215	}
3216
3217      if (ri->type != RCDATA_BUFFER)
3218	{
3219	  if (ri->next != NULL)
3220	    fprintf (e, ",");
3221	  fprintf (e, "\n");
3222	}
3223    }
3224
3225  indent (e, ind);
3226  fprintf (e, "END\n");
3227}
3228
3229/* Write out a stringtable resource.  */
3230
3231static void
3232write_rc_stringtable (FILE *e, const rc_res_id *name,
3233		      const rc_stringtable *stringtable)
3234{
3235  rc_uint_type offset;
3236  int i;
3237
3238  if (name != NULL && ! name->named)
3239    offset = (name->u.id - 1) << 4;
3240  else
3241    {
3242      fprintf (e, "/* %s string table name.  */\n",
3243	       name == NULL ? "Missing" : "Invalid");
3244      offset = 0;
3245    }
3246
3247  fprintf (e, "BEGIN\n");
3248
3249  for (i = 0; i < 16; i++)
3250    {
3251      if (stringtable->strings[i].length != 0)
3252	{
3253	  fprintf (e, "  %lu, ", (unsigned long) offset + i);
3254	  unicode_print_quoted (e, stringtable->strings[i].string,
3255			 stringtable->strings[i].length);
3256	  fprintf (e, "\n");
3257	}
3258    }
3259
3260  fprintf (e, "END\n");
3261}
3262
3263/* Write out a versioninfo resource.  */
3264
3265static void
3266write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
3267{
3268  const rc_fixed_versioninfo *f;
3269  const rc_ver_info *vi;
3270
3271  f = versioninfo->fixed;
3272  if (f->file_version_ms != 0 || f->file_version_ls != 0)
3273    fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3274	     (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3275	     (unsigned int) (f->file_version_ms & 0xffff),
3276	     (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3277	     (unsigned int) (f->file_version_ls & 0xffff));
3278  if (f->product_version_ms != 0 || f->product_version_ls != 0)
3279    fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3280	     (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3281	     (unsigned int) (f->product_version_ms & 0xffff),
3282	     (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3283	     (unsigned int) (f->product_version_ls & 0xffff));
3284  if (f->file_flags_mask != 0)
3285    fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
3286  if (f->file_flags != 0)
3287    fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
3288  if (f->file_os != 0)
3289    fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
3290  if (f->file_type != 0)
3291    fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
3292  if (f->file_subtype != 0)
3293    fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
3294  if (f->file_date_ms != 0 || f->file_date_ls != 0)
3295    fprintf (e, "/* Date: %u, %u.  */\n",
3296    	     (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
3297
3298  fprintf (e, "BEGIN\n");
3299
3300  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3301    {
3302      switch (vi->type)
3303	{
3304	case VERINFO_STRING:
3305	  {
3306	    const rc_ver_stringtable *vst;
3307	    const rc_ver_stringinfo *vs;
3308
3309	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
3310	    fprintf (e, "  BEGIN\n");
3311
3312	    for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
3313	      {
3314		fprintf (e, "    BLOCK ");
3315		unicode_print_quoted (e, vst->language, -1);
3316
3317		fprintf (e, "\n");
3318		fprintf (e, "    BEGIN\n");
3319
3320		for (vs = vst->strings; vs != NULL; vs = vs->next)
3321		  {
3322		    fprintf (e, "      VALUE ");
3323		    unicode_print_quoted (e, vs->key, -1);
3324		    fprintf (e, ", ");
3325		    unicode_print_quoted (e, vs->value, -1);
3326		    fprintf (e, "\n");
3327		  }
3328
3329		fprintf (e, "    END\n");
3330	      }
3331	    fprintf (e, "  END\n");
3332	    break;
3333	  }
3334
3335	case VERINFO_VAR:
3336	  {
3337	    const rc_ver_varinfo *vv;
3338
3339	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
3340	    fprintf (e, "  BEGIN\n");
3341	    fprintf (e, "    VALUE ");
3342	    unicode_print_quoted (e, vi->u.var.key, -1);
3343
3344	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3345	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3346		       (int) vv->charset);
3347
3348	    fprintf (e, "\n  END\n");
3349
3350	    break;
3351	  }
3352	}
3353    }
3354
3355  fprintf (e, "END\n");
3356}
3357
3358static rc_uint_type
3359rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
3360{
3361  if (! src)
3362    return 0;
3363  switch (src->type)
3364	{
3365    case RCDATA_WORD:
3366      if (dst)
3367	windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3368      return 2;
3369    case RCDATA_DWORD:
3370      if (dst)
3371	windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3372      return 4;
3373    case RCDATA_STRING:
3374      if (dst && src->u.string.length)
3375	memcpy (dst, src->u.string.s, src->u.string.length);
3376      return (rc_uint_type) src->u.string.length;
3377    case RCDATA_WSTRING:
3378      if (dst && src->u.wstring.length)
3379	memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3380      return (rc_uint_type) (src->u.wstring.length  * sizeof (unichar));
3381    case RCDATA_BUFFER:
3382      if (dst && src->u.buffer.length)
3383	memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3384      return (rc_uint_type) src->u.buffer.length;
3385    default:
3386      abort ();
3387    }
3388  /* Never reached.  */
3389  return 0;
3390}
3391