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