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