138889Sjdp/* resrc.c -- read and write Windows rc files.
2218822Sdim   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007
3218822Sdim   Free Software Foundation, Inc.
438889Sjdp   Written by Ian Lance Taylor, Cygnus Support.
5218822Sdim   Rewritten by Kai Tietz, Onevision.
638889Sjdp
738889Sjdp   This file is part of GNU Binutils.
838889Sjdp
938889Sjdp   This program is free software; you can redistribute it and/or modify
1038889Sjdp   it under the terms of the GNU General Public License as published by
1138889Sjdp   the Free Software Foundation; either version 2 of the License, or
1238889Sjdp   (at your option) any later version.
1338889Sjdp
1438889Sjdp   This program is distributed in the hope that it will be useful,
1538889Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1638889Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1738889Sjdp   GNU General Public License for more details.
1838889Sjdp
1938889Sjdp   You should have received a copy of the GNU General Public License
2038889Sjdp   along with this program; if not, write to the Free Software
21218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22218822Sdim   02110-1301, USA.  */
2338889Sjdp
2438889Sjdp/* This file contains functions that read and write Windows rc files.
2538889Sjdp   These are text files that represent resources.  */
2638889Sjdp
27218822Sdim#include "sysdep.h"
2838889Sjdp#include "bfd.h"
2938889Sjdp#include "bucomm.h"
3038889Sjdp#include "libiberty.h"
3189857Sobrien#include "safe-ctype.h"
3238889Sjdp#include "windres.h"
3338889Sjdp
3438889Sjdp#include <assert.h>
3560484Sobrien#include <errno.h>
3638889Sjdp#include <sys/stat.h>
3760484Sobrien#ifdef HAVE_UNISTD_H
3860484Sobrien#include <unistd.h>
3960484Sobrien#endif
4038889Sjdp
4160484Sobrien#ifdef HAVE_SYS_WAIT_H
4260484Sobrien#include <sys/wait.h>
4360484Sobrien#else /* ! HAVE_SYS_WAIT_H */
4460484Sobrien#if ! defined (_WIN32) || defined (__CYGWIN__)
4560484Sobrien#ifndef WIFEXITED
4660484Sobrien#define WIFEXITED(w)	(((w)&0377) == 0)
4760484Sobrien#endif
4860484Sobrien#ifndef WIFSIGNALED
4960484Sobrien#define WIFSIGNALED(w)	(((w)&0377) != 0177 && ((w)&~0377) == 0)
5060484Sobrien#endif
5160484Sobrien#ifndef WTERMSIG
5260484Sobrien#define WTERMSIG(w)	((w) & 0177)
5360484Sobrien#endif
5460484Sobrien#ifndef WEXITSTATUS
5560484Sobrien#define WEXITSTATUS(w)	(((w) >> 8) & 0377)
5660484Sobrien#endif
5760484Sobrien#else /* defined (_WIN32) && ! defined (__CYGWIN__) */
5860484Sobrien#ifndef WIFEXITED
5960484Sobrien#define WIFEXITED(w)	(((w) & 0xff) == 0)
6060484Sobrien#endif
6160484Sobrien#ifndef WIFSIGNALED
6260484Sobrien#define WIFSIGNALED(w)	(((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
6360484Sobrien#endif
6460484Sobrien#ifndef WTERMSIG
6560484Sobrien#define WTERMSIG(w)	((w) & 0x7f)
6660484Sobrien#endif
6760484Sobrien#ifndef WEXITSTATUS
6860484Sobrien#define WEXITSTATUS(w)	(((w) & 0xff00) >> 8)
6960484Sobrien#endif
7060484Sobrien#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
7160484Sobrien#endif /* ! HAVE_SYS_WAIT_H */
7260484Sobrien
7360484Sobrien#ifndef STDOUT_FILENO
7460484Sobrien#define STDOUT_FILENO 1
7560484Sobrien#endif
76104834Sobrien
7760484Sobrien#if defined (_WIN32) && ! defined (__CYGWIN__)
7838889Sjdp#define popen _popen
7938889Sjdp#define pclose _pclose
8038889Sjdp#endif
8138889Sjdp
8238889Sjdp/* The default preprocessor.  */
8338889Sjdp
8477298Sobrien#define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
8538889Sjdp
8638889Sjdp/* We read the directory entries in a cursor or icon file into
8738889Sjdp   instances of this structure.  */
8838889Sjdp
8938889Sjdpstruct icondir
9038889Sjdp{
9138889Sjdp  /* Width of image.  */
92218822Sdim  bfd_byte width;
9338889Sjdp  /* Height of image.  */
94218822Sdim  bfd_byte height;
9538889Sjdp  /* Number of colors in image.  */
96218822Sdim  bfd_byte colorcount;
9738889Sjdp  union
9838889Sjdp  {
9938889Sjdp    struct
10038889Sjdp    {
10138889Sjdp      /* Color planes.  */
10238889Sjdp      unsigned short planes;
10338889Sjdp      /* Bits per pixel.  */
10438889Sjdp      unsigned short bits;
10538889Sjdp    } icon;
10638889Sjdp    struct
10738889Sjdp    {
10838889Sjdp      /* X coordinate of hotspot.  */
10938889Sjdp      unsigned short xhotspot;
11038889Sjdp      /* Y coordinate of hotspot.  */
11138889Sjdp      unsigned short yhotspot;
11238889Sjdp    } cursor;
11338889Sjdp  } u;
11438889Sjdp  /* Bytes in image.  */
11538889Sjdp  unsigned long bytes;
11638889Sjdp  /* File offset of image.  */
11738889Sjdp  unsigned long offset;
11838889Sjdp};
11938889Sjdp
12038889Sjdp/* The name of the rc file we are reading.  */
12138889Sjdp
12238889Sjdpchar *rc_filename;
12338889Sjdp
12438889Sjdp/* The line number in the rc file.  */
12538889Sjdp
12638889Sjdpint rc_lineno;
12738889Sjdp
12838889Sjdp/* The pipe we are reading from, so that we can close it if we exit.  */
12938889Sjdp
130218822SdimFILE *cpp_pipe;
13138889Sjdp
13260484Sobrien/* The temporary file used if we're not using popen, so we can delete it
13360484Sobrien   if we exit.  */
13460484Sobrien
13560484Sobrienstatic char *cpp_temp_file;
13660484Sobrien
13799461Sobrien/* Input stream is either a file or a pipe.  */
13860484Sobrien
13960484Sobrienstatic enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
14060484Sobrien
14138889Sjdp/* As we read the rc file, we attach information to this structure.  */
14238889Sjdp
143218822Sdimstatic rc_res_directory *resources;
14438889Sjdp
14538889Sjdp/* The number of cursor resources we have written out.  */
14638889Sjdp
14738889Sjdpstatic int cursors;
14838889Sjdp
14938889Sjdp/* The number of font resources we have written out.  */
15038889Sjdp
15138889Sjdpstatic int fonts;
15238889Sjdp
15338889Sjdp/* Font directory information.  */
15438889Sjdp
155218822Sdimrc_fontdir *fontdirs;
15638889Sjdp
15738889Sjdp/* Resource info to use for fontdirs.  */
15838889Sjdp
159218822Sdimrc_res_res_info fontdirs_resinfo;
16038889Sjdp
16138889Sjdp/* The number of icon resources we have written out.  */
16238889Sjdp
16338889Sjdpstatic int icons;
16438889Sjdp
165218822Sdim/* The windres target bfd .  */
16638889Sjdp
167218822Sdimstatic windres_bfd wrtarget =
168218822Sdim{
169218822Sdim  (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
170218822Sdim};
171218822Sdim
172218822Sdim/* Local functions for rcdata based resource definitions.  */
173218822Sdim
174218822Sdimstatic void define_font_rcdata (rc_res_id, const rc_res_res_info *,
175218822Sdim				rc_rcdata_item *);
176218822Sdimstatic void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
177218822Sdim				rc_rcdata_item *);
178218822Sdimstatic void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
179218822Sdim				  rc_rcdata_item *);
180218822Sdimstatic void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
181218822Sdim				  rc_rcdata_item *);
182218822Sdimstatic void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
183218822Sdim				   rc_rcdata_item *);
184218822Sdimstatic void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
185218822Sdim					rc_rcdata_item *);
186218822Sdimstatic rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
187218822Sdimstatic bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
188218822Sdim
189130561Sobrienstatic int run_cmd (char *, const char *);
190130561Sobrienstatic FILE *open_input_stream (char *);
191130561Sobrienstatic FILE *look_for_default
192130561Sobrien  (char *, const char *, int, const char *, const char *);
193130561Sobrienstatic void close_input_stream (void);
194130561Sobrienstatic void unexpected_eof (const char *);
195130561Sobrienstatic int get_word (FILE *, const char *);
196130561Sobrienstatic unsigned long get_long (FILE *, const char *);
197218822Sdimstatic void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
198130561Sobrienstatic void define_fontdirs (void);
19938889Sjdp
20099461Sobrien/* Run `cmd' and redirect the output to `redir'.  */
20160484Sobrien
20260484Sobrienstatic int
203130561Sobrienrun_cmd (char *cmd, const char *redir)
20460484Sobrien{
20560484Sobrien  char *s;
20660484Sobrien  int pid, wait_status, retcode;
20760484Sobrien  int i;
20860484Sobrien  const char **argv;
20960484Sobrien  char *errmsg_fmt, *errmsg_arg;
21060484Sobrien  char *temp_base = choose_temp_base ();
21160484Sobrien  int in_quote;
21260484Sobrien  char sep;
21360484Sobrien  int redir_handle = -1;
21460484Sobrien  int stdout_save = -1;
21560484Sobrien
21660484Sobrien  /* Count the args.  */
21760484Sobrien  i = 0;
218104834Sobrien
21960484Sobrien  for (s = cmd; *s; s++)
22060484Sobrien    if (*s == ' ')
22160484Sobrien      i++;
222104834Sobrien
22360484Sobrien  i++;
22460484Sobrien  argv = alloca (sizeof (char *) * (i + 3));
22560484Sobrien  i = 0;
22660484Sobrien  s = cmd;
227104834Sobrien
22860484Sobrien  while (1)
22960484Sobrien    {
23060484Sobrien      while (*s == ' ' && *s != 0)
23160484Sobrien	s++;
232104834Sobrien
23360484Sobrien      if (*s == 0)
23460484Sobrien	break;
235104834Sobrien
23660484Sobrien      in_quote = (*s == '\'' || *s == '"');
23760484Sobrien      sep = (in_quote) ? *s++ : ' ';
23860484Sobrien      argv[i++] = s;
239104834Sobrien
24060484Sobrien      while (*s != sep && *s != 0)
24160484Sobrien	s++;
242104834Sobrien
24360484Sobrien      if (*s == 0)
24460484Sobrien	break;
245104834Sobrien
24660484Sobrien      *s++ = 0;
247104834Sobrien
24860484Sobrien      if (in_quote)
249104834Sobrien	s++;
25060484Sobrien    }
25160484Sobrien  argv[i++] = NULL;
25260484Sobrien
25360484Sobrien  /* Setup the redirection.  We can't use the usual fork/exec and redirect
25460484Sobrien     since we may be running on non-POSIX Windows host.  */
25560484Sobrien
25660484Sobrien  fflush (stdout);
25760484Sobrien  fflush (stderr);
25860484Sobrien
25960484Sobrien  /* Open temporary output file.  */
26060484Sobrien  redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
26160484Sobrien  if (redir_handle == -1)
262104834Sobrien    fatal (_("can't open temporary file `%s': %s"), redir,
263104834Sobrien	   strerror (errno));
26460484Sobrien
26560484Sobrien  /* Duplicate the stdout file handle so it can be restored later.  */
26660484Sobrien  stdout_save = dup (STDOUT_FILENO);
26760484Sobrien  if (stdout_save == -1)
26860484Sobrien    fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
26960484Sobrien
27060484Sobrien  /* Redirect stdout to our output file.  */
27160484Sobrien  dup2 (redir_handle, STDOUT_FILENO);
27260484Sobrien
27360484Sobrien  pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
27460484Sobrien		  &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
27560484Sobrien
27660484Sobrien  /* Restore stdout to its previous setting.  */
27760484Sobrien  dup2 (stdout_save, STDOUT_FILENO);
27860484Sobrien
279130561Sobrien  /* Close response file.  */
28060484Sobrien  close (redir_handle);
28160484Sobrien
28260484Sobrien  if (pid == -1)
28360484Sobrien    {
28460484Sobrien      fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
28560484Sobrien      return 1;
28660484Sobrien    }
28760484Sobrien
28860484Sobrien  retcode = 0;
28960484Sobrien  pid = pwait (pid, &wait_status, 0);
290104834Sobrien
29160484Sobrien  if (pid == -1)
29260484Sobrien    {
29360484Sobrien      fatal (_("wait: %s"), strerror (errno));
29460484Sobrien      retcode = 1;
29560484Sobrien    }
29660484Sobrien  else if (WIFSIGNALED (wait_status))
29760484Sobrien    {
29860484Sobrien      fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
29960484Sobrien      retcode = 1;
30060484Sobrien    }
30160484Sobrien  else if (WIFEXITED (wait_status))
30260484Sobrien    {
30360484Sobrien      if (WEXITSTATUS (wait_status) != 0)
30460484Sobrien	{
305104834Sobrien	  fatal (_("%s exited with status %d"), cmd,
30660484Sobrien	         WEXITSTATUS (wait_status));
30760484Sobrien	  retcode = 1;
30860484Sobrien	}
30960484Sobrien    }
31060484Sobrien  else
31160484Sobrien    retcode = 1;
312104834Sobrien
31360484Sobrien  return retcode;
31460484Sobrien}
31560484Sobrien
31660484Sobrienstatic FILE *
317130561Sobrienopen_input_stream (char *cmd)
31860484Sobrien{
31960484Sobrien  if (istream_type == ISTREAM_FILE)
32060484Sobrien    {
32160484Sobrien      char *fileprefix;
32260484Sobrien
32360484Sobrien      fileprefix = choose_temp_base ();
32460484Sobrien      cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
32560484Sobrien      sprintf (cpp_temp_file, "%s.irc", fileprefix);
32660484Sobrien      free (fileprefix);
32760484Sobrien
32860484Sobrien      if (run_cmd (cmd, cpp_temp_file))
32960484Sobrien	fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
33060484Sobrien
33160484Sobrien      cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
33260484Sobrien      if (cpp_pipe == NULL)
333104834Sobrien	fatal (_("can't open temporary file `%s': %s"),
33460484Sobrien	       cpp_temp_file, strerror (errno));
335104834Sobrien
33660484Sobrien      if (verbose)
337104834Sobrien	fprintf (stderr,
33860484Sobrien	         _("Using temporary file `%s' to read preprocessor output\n"),
33960484Sobrien		 cpp_temp_file);
34060484Sobrien    }
34160484Sobrien  else
34260484Sobrien    {
34360484Sobrien      cpp_pipe = popen (cmd, FOPEN_RT);
34460484Sobrien      if (cpp_pipe == NULL)
345104834Sobrien	fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
34660484Sobrien      if (verbose)
34760484Sobrien	fprintf (stderr, _("Using popen to read preprocessor output\n"));
34860484Sobrien    }
34960484Sobrien
35060484Sobrien  xatexit (close_input_stream);
35160484Sobrien  return cpp_pipe;
35260484Sobrien}
35360484Sobrien
354218822Sdim/* Determine if FILENAME contains special characters that
355218822Sdim   can cause problems unless the entire filename is quoted.  */
35660484Sobrien
357218822Sdimstatic int
358218822Sdimfilename_need_quotes (const char *filename)
359218822Sdim{
360218822Sdim  if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
361218822Sdim    return 0;
362218822Sdim
363218822Sdim  while (*filename != 0)
364218822Sdim    {
365218822Sdim      switch (*filename)
366218822Sdim        {
367218822Sdim        case '&':
368218822Sdim        case ' ':
369218822Sdim        case '<':
370218822Sdim        case '>':
371218822Sdim        case '|':
372218822Sdim        case '%':
373218822Sdim          return 1;
374218822Sdim        }
375218822Sdim      ++filename;
376218822Sdim    }
377218822Sdim  return 0;
378218822Sdim}
379218822Sdim
380218822Sdim/* Look for the preprocessor program.  */
381218822Sdim
38260484Sobrienstatic FILE *
383130561Sobrienlook_for_default (char *cmd, const char *prefix, int end_prefix,
384130561Sobrien		  const char *preprocargs, const char *filename)
38560484Sobrien{
38660484Sobrien  char *space;
38760484Sobrien  int found;
38860484Sobrien  struct stat s;
389218822Sdim  const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
39060484Sobrien
39160484Sobrien  strcpy (cmd, prefix);
39260484Sobrien
39360484Sobrien  sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
39460484Sobrien  space = strchr (cmd + end_prefix, ' ');
39560484Sobrien  if (space)
39660484Sobrien    *space = 0;
39760484Sobrien
39860484Sobrien  if (
39960484Sobrien#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
40060484Sobrien      strchr (cmd, '\\') ||
40160484Sobrien#endif
40260484Sobrien      strchr (cmd, '/'))
40360484Sobrien    {
40460484Sobrien      found = (stat (cmd, &s) == 0
40560484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
40660484Sobrien	       || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
40760484Sobrien#endif
40860484Sobrien	       );
40960484Sobrien
41060484Sobrien      if (! found)
41160484Sobrien	{
41260484Sobrien	  if (verbose)
41360484Sobrien	    fprintf (stderr, _("Tried `%s'\n"), cmd);
41460484Sobrien	  return NULL;
41560484Sobrien	}
41660484Sobrien    }
41760484Sobrien
41860484Sobrien  strcpy (cmd, prefix);
41960484Sobrien
420218822Sdim  sprintf (cmd + end_prefix, "%s %s %s%s%s",
421218822Sdim	   DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
42260484Sobrien
42360484Sobrien  if (verbose)
42460484Sobrien    fprintf (stderr, _("Using `%s'\n"), cmd);
42560484Sobrien
42660484Sobrien  cpp_pipe = open_input_stream (cmd);
42760484Sobrien  return cpp_pipe;
42860484Sobrien}
42960484Sobrien
43038889Sjdp/* Read an rc file.  */
43138889Sjdp
432218822Sdimrc_res_directory *
433130561Sobrienread_rc_file (const char *filename, const char *preprocessor,
434130561Sobrien	      const char *preprocargs, int language, int use_temp_file)
43538889Sjdp{
43638889Sjdp  char *cmd;
437218822Sdim  const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
43838889Sjdp
43960484Sobrien  istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
44038889Sjdp
44138889Sjdp  if (preprocargs == NULL)
44238889Sjdp    preprocargs = "";
44338889Sjdp  if (filename == NULL)
44438889Sjdp    filename = "-";
44538889Sjdp
44660484Sobrien  if (preprocessor)
44760484Sobrien    {
44860484Sobrien      cmd = xmalloc (strlen (preprocessor)
44960484Sobrien		     + strlen (preprocargs)
45060484Sobrien		     + strlen (filename)
451218822Sdim		     + strlen (fnquotes) * 2
45260484Sobrien		     + 10);
453218822Sdim      sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
454218822Sdim	       fnquotes, filename, fnquotes);
45538889Sjdp
45660484Sobrien      cpp_pipe = open_input_stream (cmd);
45760484Sobrien    }
45860484Sobrien  else
45960484Sobrien    {
46060484Sobrien      char *dash, *slash, *cp;
46160484Sobrien
46260484Sobrien      preprocessor = DEFAULT_PREPROCESSOR;
46360484Sobrien
46460484Sobrien      cmd = xmalloc (strlen (program_name)
46560484Sobrien		     + strlen (preprocessor)
46660484Sobrien		     + strlen (preprocargs)
46760484Sobrien		     + strlen (filename)
468218822Sdim		     + strlen (fnquotes) * 2
46960484Sobrien#ifdef HAVE_EXECUTABLE_SUFFIX
47060484Sobrien		     + strlen (EXECUTABLE_SUFFIX)
47160484Sobrien#endif
47260484Sobrien		     + 10);
47360484Sobrien
47460484Sobrien
47560484Sobrien      dash = slash = 0;
47660484Sobrien      for (cp = program_name; *cp; cp++)
47760484Sobrien	{
47860484Sobrien	  if (*cp == '-')
47960484Sobrien	    dash = cp;
48060484Sobrien	  if (
48160484Sobrien#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
48260484Sobrien	      *cp == ':' || *cp == '\\' ||
48360484Sobrien#endif
48460484Sobrien	      *cp == '/')
48560484Sobrien	    {
48660484Sobrien	      slash = cp;
48760484Sobrien	      dash = 0;
48860484Sobrien	    }
48960484Sobrien	}
49060484Sobrien
49160484Sobrien      cpp_pipe = 0;
49260484Sobrien
49360484Sobrien      if (dash)
49460484Sobrien	{
49560484Sobrien	  /* First, try looking for a prefixed gcc in the windres
49660484Sobrien	     directory, with the same prefix as windres */
49760484Sobrien
498218822Sdim	  cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
49960484Sobrien				       preprocargs, filename);
50060484Sobrien	}
50160484Sobrien
502218822Sdim      if (slash && ! cpp_pipe)
50360484Sobrien	{
50460484Sobrien	  /* Next, try looking for a gcc in the same directory as
50560484Sobrien             that windres */
50660484Sobrien
507218822Sdim	  cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
50860484Sobrien				       preprocargs, filename);
50960484Sobrien	}
51060484Sobrien
511218822Sdim      if (! cpp_pipe)
51260484Sobrien	{
51360484Sobrien	  /* Sigh, try the default */
51460484Sobrien
51560484Sobrien	  cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
51660484Sobrien	}
51760484Sobrien
51860484Sobrien    }
519104834Sobrien
52038889Sjdp  free (cmd);
52138889Sjdp
52238889Sjdp  rc_filename = xstrdup (filename);
52338889Sjdp  rc_lineno = 1;
52438889Sjdp  if (language != -1)
52538889Sjdp    rcparse_set_language (language);
52638889Sjdp  yyparse ();
52799461Sobrien  rcparse_discard_strings ();
52838889Sjdp
52960484Sobrien  close_input_stream ();
530104834Sobrien
53138889Sjdp  if (fontdirs != NULL)
53238889Sjdp    define_fontdirs ();
53338889Sjdp
53438889Sjdp  free (rc_filename);
53538889Sjdp  rc_filename = NULL;
53638889Sjdp
53738889Sjdp  return resources;
53838889Sjdp}
53938889Sjdp
54060484Sobrien/* Close the input stream if it is open.  */
54138889Sjdp
54260484Sobrienstatic void
543130561Sobrienclose_input_stream (void)
54438889Sjdp{
54560484Sobrien  if (istream_type == ISTREAM_FILE)
54660484Sobrien    {
54760484Sobrien      if (cpp_pipe != NULL)
54860484Sobrien	fclose (cpp_pipe);
54960484Sobrien
55060484Sobrien      if (cpp_temp_file != NULL)
55160484Sobrien	{
55260484Sobrien	  int errno_save = errno;
553104834Sobrien
55460484Sobrien	  unlink (cpp_temp_file);
55560484Sobrien	  errno = errno_save;
55660484Sobrien	  free (cpp_temp_file);
55760484Sobrien	}
55860484Sobrien    }
55960484Sobrien  else
56060484Sobrien    {
56160484Sobrien      if (cpp_pipe != NULL)
56260484Sobrien	pclose (cpp_pipe);
56360484Sobrien    }
56460484Sobrien
56599461Sobrien  /* Since this is also run via xatexit, safeguard.  */
56660484Sobrien  cpp_pipe = NULL;
56760484Sobrien  cpp_temp_file = NULL;
56838889Sjdp}
56938889Sjdp
57038889Sjdp/* Report an error while reading an rc file.  */
57138889Sjdp
57238889Sjdpvoid
573130561Sobrienyyerror (const char *msg)
57438889Sjdp{
57538889Sjdp  fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
57638889Sjdp}
57738889Sjdp
57838889Sjdp/* Issue a warning while reading an rc file.  */
57938889Sjdp
58038889Sjdpvoid
581130561Sobrienrcparse_warning (const char *msg)
58238889Sjdp{
58360484Sobrien  fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
58438889Sjdp}
58538889Sjdp
58638889Sjdp/* Die if we get an unexpected end of file.  */
58738889Sjdp
58838889Sjdpstatic void
589130561Sobrienunexpected_eof (const char *msg)
59038889Sjdp{
59160484Sobrien  fatal (_("%s: unexpected EOF"), msg);
59238889Sjdp}
59338889Sjdp
59438889Sjdp/* Read a 16 bit word from a file.  The data is assumed to be little
59538889Sjdp   endian.  */
59638889Sjdp
59738889Sjdpstatic int
598130561Sobrienget_word (FILE *e, const char *msg)
59938889Sjdp{
60038889Sjdp  int b1, b2;
60138889Sjdp
60238889Sjdp  b1 = getc (e);
60338889Sjdp  b2 = getc (e);
60438889Sjdp  if (feof (e))
60538889Sjdp    unexpected_eof (msg);
60638889Sjdp  return ((b2 & 0xff) << 8) | (b1 & 0xff);
60738889Sjdp}
60838889Sjdp
60938889Sjdp/* Read a 32 bit word from a file.  The data is assumed to be little
61038889Sjdp   endian.  */
61138889Sjdp
61238889Sjdpstatic unsigned long
613130561Sobrienget_long (FILE *e, const char *msg)
61438889Sjdp{
61538889Sjdp  int b1, b2, b3, b4;
61638889Sjdp
61738889Sjdp  b1 = getc (e);
61838889Sjdp  b2 = getc (e);
61938889Sjdp  b3 = getc (e);
62038889Sjdp  b4 = getc (e);
62138889Sjdp  if (feof (e))
62238889Sjdp    unexpected_eof (msg);
62338889Sjdp  return (((((((b4 & 0xff) << 8)
62438889Sjdp	      | (b3 & 0xff)) << 8)
62538889Sjdp	    | (b2 & 0xff)) << 8)
62638889Sjdp	  | (b1 & 0xff));
62738889Sjdp}
62838889Sjdp
62938889Sjdp/* Read data from a file.  This is a wrapper to do error checking.  */
63038889Sjdp
63138889Sjdpstatic void
632218822Sdimget_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
63338889Sjdp{
634218822Sdim  rc_uint_type got; // $$$d
63538889Sjdp
636218822Sdim  got = (rc_uint_type) fread (p, 1, c, e);
63738889Sjdp  if (got == c)
63838889Sjdp    return;
63938889Sjdp
640218822Sdim  fatal (_("%s: read of %lu returned %lu"), msg, (long) c, (long) got);
64138889Sjdp}
64238889Sjdp
64338889Sjdp/* Define an accelerator resource.  */
64438889Sjdp
64538889Sjdpvoid
646218822Sdimdefine_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
647218822Sdim		    rc_accelerator *data)
64838889Sjdp{
649218822Sdim  rc_res_resource *r;
65038889Sjdp
65160484Sobrien  r = define_standard_resource (&resources, RT_ACCELERATOR, id,
65238889Sjdp				resinfo->language, 0);
65338889Sjdp  r->type = RES_TYPE_ACCELERATOR;
65438889Sjdp  r->u.acc = data;
65538889Sjdp  r->res_info = *resinfo;
65638889Sjdp}
65738889Sjdp
65838889Sjdp/* Define a bitmap resource.  Bitmap data is stored in a file.  The
65938889Sjdp   first 14 bytes of the file are a standard header, which is not
66038889Sjdp   included in the resource data.  */
66138889Sjdp
66238889Sjdp#define BITMAP_SKIP (14)
66338889Sjdp
66438889Sjdpvoid
665218822Sdimdefine_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
666130561Sobrien	       const char *filename)
66738889Sjdp{
66838889Sjdp  FILE *e;
66938889Sjdp  char *real_filename;
67038889Sjdp  struct stat s;
671218822Sdim  bfd_byte *data;
672218822Sdim  rc_uint_type i;
673218822Sdim  rc_res_resource *r;
67438889Sjdp
67538889Sjdp  e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
67638889Sjdp
67738889Sjdp  if (stat (real_filename, &s) < 0)
67860484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
67938889Sjdp	   strerror (errno));
68038889Sjdp
681218822Sdim  data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
68238889Sjdp
68338889Sjdp  for (i = 0; i < BITMAP_SKIP; i++)
68438889Sjdp    getc (e);
68538889Sjdp
68638889Sjdp  get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
68738889Sjdp
68838889Sjdp  fclose (e);
68938889Sjdp  free (real_filename);
69038889Sjdp
69138889Sjdp  r = define_standard_resource (&resources, RT_BITMAP, id,
69238889Sjdp				resinfo->language, 0);
69338889Sjdp
69438889Sjdp  r->type = RES_TYPE_BITMAP;
69538889Sjdp  r->u.data.length = s.st_size - BITMAP_SKIP;
69638889Sjdp  r->u.data.data = data;
69738889Sjdp  r->res_info = *resinfo;
69838889Sjdp}
69938889Sjdp
70038889Sjdp/* Define a cursor resource.  A cursor file may contain a set of
70138889Sjdp   bitmaps, each representing the same cursor at various different
70238889Sjdp   resolutions.  They each get written out with a different ID.  The
70338889Sjdp   real cursor resource is then a group resource which can be used to
70438889Sjdp   select one of the actual cursors.  */
70538889Sjdp
70638889Sjdpvoid
707218822Sdimdefine_cursor (rc_res_id id, const rc_res_res_info *resinfo,
708130561Sobrien	       const char *filename)
70938889Sjdp{
71038889Sjdp  FILE *e;
71138889Sjdp  char *real_filename;
71238889Sjdp  int type, count, i;
71338889Sjdp  struct icondir *icondirs;
71438889Sjdp  int first_cursor;
715218822Sdim  rc_res_resource *r;
716218822Sdim  rc_group_cursor *first, **pp;
71738889Sjdp
71838889Sjdp  e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
71938889Sjdp
72038889Sjdp  /* A cursor file is basically an icon file.  The start of the file
72138889Sjdp     is a three word structure.  The first word is ignored.  The
72238889Sjdp     second word is the type of data.  The third word is the number of
72338889Sjdp     entries.  */
72438889Sjdp
72538889Sjdp  get_word (e, real_filename);
72638889Sjdp  type = get_word (e, real_filename);
72738889Sjdp  count = get_word (e, real_filename);
72838889Sjdp  if (type != 2)
72960484Sobrien    fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
73038889Sjdp
73138889Sjdp  /* Read in the icon directory entries.  */
73238889Sjdp
73338889Sjdp  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
73438889Sjdp
73538889Sjdp  for (i = 0; i < count; i++)
73638889Sjdp    {
73738889Sjdp      icondirs[i].width = getc (e);
73838889Sjdp      icondirs[i].height = getc (e);
73938889Sjdp      icondirs[i].colorcount = getc (e);
74038889Sjdp      getc (e);
74138889Sjdp      icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
74238889Sjdp      icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
74338889Sjdp      icondirs[i].bytes = get_long (e, real_filename);
74438889Sjdp      icondirs[i].offset = get_long (e, real_filename);
74538889Sjdp
74638889Sjdp      if (feof (e))
74738889Sjdp	unexpected_eof (real_filename);
74838889Sjdp    }
74938889Sjdp
75038889Sjdp  /* Define each cursor as a unique resource.  */
75138889Sjdp
75238889Sjdp  first_cursor = cursors;
75338889Sjdp
75438889Sjdp  for (i = 0; i < count; i++)
75538889Sjdp    {
756218822Sdim      bfd_byte *data;
757218822Sdim      rc_res_id name;
758218822Sdim      rc_cursor *c;
75938889Sjdp
76038889Sjdp      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
76160484Sobrien	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
76238889Sjdp	       icondirs[i].offset, strerror (errno));
76338889Sjdp
764218822Sdim      data = (bfd_byte *) res_alloc (icondirs[i].bytes);
76538889Sjdp
76638889Sjdp      get_data (e, data, icondirs[i].bytes, real_filename);
76738889Sjdp
768218822Sdim      c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
76938889Sjdp      c->xhotspot = icondirs[i].u.cursor.xhotspot;
77038889Sjdp      c->yhotspot = icondirs[i].u.cursor.yhotspot;
77138889Sjdp      c->length = icondirs[i].bytes;
77238889Sjdp      c->data = data;
77338889Sjdp
77438889Sjdp      ++cursors;
77538889Sjdp
77638889Sjdp      name.named = 0;
77738889Sjdp      name.u.id = cursors;
77838889Sjdp
77938889Sjdp      r = define_standard_resource (&resources, RT_CURSOR, name,
78038889Sjdp				    resinfo->language, 0);
78138889Sjdp      r->type = RES_TYPE_CURSOR;
78238889Sjdp      r->u.cursor = c;
78338889Sjdp      r->res_info = *resinfo;
78438889Sjdp    }
78538889Sjdp
78638889Sjdp  fclose (e);
78738889Sjdp  free (real_filename);
78838889Sjdp
78938889Sjdp  /* Define a cursor group resource.  */
79038889Sjdp
79138889Sjdp  first = NULL;
79238889Sjdp  pp = &first;
79338889Sjdp  for (i = 0; i < count; i++)
79438889Sjdp    {
795218822Sdim      rc_group_cursor *cg;
79638889Sjdp
797218822Sdim      cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
79838889Sjdp      cg->next = NULL;
79938889Sjdp      cg->width = icondirs[i].width;
80038889Sjdp      cg->height = 2 * icondirs[i].height;
80138889Sjdp
80238889Sjdp      /* FIXME: What should these be set to?  */
80338889Sjdp      cg->planes = 1;
80438889Sjdp      cg->bits = 1;
80538889Sjdp
80638889Sjdp      cg->bytes = icondirs[i].bytes + 4;
80738889Sjdp      cg->index = first_cursor + i + 1;
80838889Sjdp
80938889Sjdp      *pp = cg;
81038889Sjdp      pp = &(*pp)->next;
81138889Sjdp    }
81238889Sjdp
81338889Sjdp  free (icondirs);
81438889Sjdp
81538889Sjdp  r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
81638889Sjdp				resinfo->language, 0);
81738889Sjdp  r->type = RES_TYPE_GROUP_CURSOR;
81838889Sjdp  r->u.group_cursor = first;
81938889Sjdp  r->res_info = *resinfo;
82038889Sjdp}
82138889Sjdp
82238889Sjdp/* Define a dialog resource.  */
82338889Sjdp
82438889Sjdpvoid
825218822Sdimdefine_dialog (rc_res_id id, const rc_res_res_info *resinfo,
826218822Sdim	       const rc_dialog *dialog)
82738889Sjdp{
828218822Sdim  rc_dialog *copy;
829218822Sdim  rc_res_resource *r;
83038889Sjdp
831218822Sdim  copy = (rc_dialog *) res_alloc (sizeof *copy);
83238889Sjdp  *copy = *dialog;
83338889Sjdp
83438889Sjdp  r = define_standard_resource (&resources, RT_DIALOG, id,
83538889Sjdp				resinfo->language, 0);
83638889Sjdp  r->type = RES_TYPE_DIALOG;
83738889Sjdp  r->u.dialog = copy;
83838889Sjdp  r->res_info = *resinfo;
83938889Sjdp}
84038889Sjdp
84138889Sjdp/* Define a dialog control.  This does not define a resource, but
84238889Sjdp   merely allocates and fills in a structure.  */
84338889Sjdp
844218822Sdimrc_dialog_control *
845218822Sdimdefine_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
846218822Sdim		rc_uint_type y, rc_uint_type width, rc_uint_type height,
847218822Sdim		const rc_res_id class, rc_uint_type style,
848218822Sdim		rc_uint_type exstyle)
84938889Sjdp{
850218822Sdim  rc_dialog_control *n;
85138889Sjdp
852218822Sdim  n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
85338889Sjdp  n->next = NULL;
85438889Sjdp  n->id = id;
85538889Sjdp  n->style = style;
85638889Sjdp  n->exstyle = exstyle;
85738889Sjdp  n->x = x;
85838889Sjdp  n->y = y;
85938889Sjdp  n->width = width;
86038889Sjdp  n->height = height;
861218822Sdim  n->class = class;
862130561Sobrien  n->text = iid;
86338889Sjdp  n->data = NULL;
86438889Sjdp  n->help = 0;
86538889Sjdp
86638889Sjdp  return n;
86738889Sjdp}
86838889Sjdp
869218822Sdimrc_dialog_control *
870218822Sdimdefine_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
871218822Sdim		     rc_uint_type y, rc_uint_type style,
872218822Sdim		     rc_uint_type exstyle, rc_uint_type help,
873218822Sdim		     rc_rcdata_item *data, rc_dialog_ex *ex)
87477298Sobrien{
875218822Sdim  rc_dialog_control *n;
876218822Sdim  rc_res_id tid;
877218822Sdim  rc_res_id cid;
878130561Sobrien
87977298Sobrien  if (style == 0)
88077298Sobrien    style = SS_ICON | WS_CHILD | WS_VISIBLE;
881130561Sobrien  res_string_to_id (&tid, "");
882218822Sdim  cid.named = 0;
883218822Sdim  cid.u.id = CTL_STATIC;
884218822Sdim  n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
88577298Sobrien  n->text = iid;
886218822Sdim  if (help && ! ex)
88777298Sobrien    rcparse_warning (_("help ID requires DIALOGEX"));
888218822Sdim  if (data && ! ex)
88977298Sobrien    rcparse_warning (_("control data requires DIALOGEX"));
89077298Sobrien  n->help = help;
89177298Sobrien  n->data = data;
89277298Sobrien
89377298Sobrien  return n;
89477298Sobrien}
89577298Sobrien
89638889Sjdp/* Define a font resource.  */
89738889Sjdp
89838889Sjdpvoid
899218822Sdimdefine_font (rc_res_id id, const rc_res_res_info *resinfo,
900130561Sobrien	     const char *filename)
90138889Sjdp{
90238889Sjdp  FILE *e;
90338889Sjdp  char *real_filename;
90438889Sjdp  struct stat s;
905218822Sdim  bfd_byte *data;
906218822Sdim  rc_res_resource *r;
90738889Sjdp  long offset;
90838889Sjdp  long fontdatalength;
909218822Sdim  bfd_byte *fontdata;
910218822Sdim  rc_fontdir *fd;
91138889Sjdp  const char *device, *face;
912218822Sdim  rc_fontdir **pp;
91338889Sjdp
91438889Sjdp  e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
91538889Sjdp
91638889Sjdp  if (stat (real_filename, &s) < 0)
917218822Sdim    fatal (_("stat failed on font file `%s': %s"), real_filename,
91838889Sjdp	   strerror (errno));
91938889Sjdp
920218822Sdim  data = (bfd_byte *) res_alloc (s.st_size);
92138889Sjdp
92238889Sjdp  get_data (e, data, s.st_size, real_filename);
92338889Sjdp
92438889Sjdp  fclose (e);
92538889Sjdp  free (real_filename);
92638889Sjdp
92738889Sjdp  r = define_standard_resource (&resources, RT_FONT, id,
92838889Sjdp				resinfo->language, 0);
92938889Sjdp
93038889Sjdp  r->type = RES_TYPE_FONT;
93138889Sjdp  r->u.data.length = s.st_size;
93238889Sjdp  r->u.data.data = data;
93338889Sjdp  r->res_info = *resinfo;
93438889Sjdp
93538889Sjdp  /* For each font resource, we must add an entry in the FONTDIR
93638889Sjdp     resource.  The FONTDIR resource includes some strings in the font
93738889Sjdp     file.  To find them, we have to do some magic on the data we have
93838889Sjdp     read.  */
93938889Sjdp
94038889Sjdp  offset = ((((((data[47] << 8)
94138889Sjdp		| data[46]) << 8)
94238889Sjdp	      | data[45]) << 8)
94338889Sjdp	    | data[44]);
94438889Sjdp  if (offset > 0 && offset < s.st_size)
94538889Sjdp    device = (char *) data + offset;
94638889Sjdp  else
94738889Sjdp    device = "";
94838889Sjdp
94938889Sjdp  offset = ((((((data[51] << 8)
95038889Sjdp		| data[50]) << 8)
95138889Sjdp	      | data[49]) << 8)
95238889Sjdp	    | data[48]);
95338889Sjdp  if (offset > 0 && offset < s.st_size)
95438889Sjdp    face = (char *) data + offset;
95538889Sjdp  else
95638889Sjdp    face = "";
95738889Sjdp
95838889Sjdp  ++fonts;
95938889Sjdp
96038889Sjdp  fontdatalength = 58 + strlen (device) + strlen (face);
961218822Sdim  fontdata = (bfd_byte *) res_alloc (fontdatalength);
96238889Sjdp  memcpy (fontdata, data, 56);
96338889Sjdp  strcpy ((char *) fontdata + 56, device);
96438889Sjdp  strcpy ((char *) fontdata + 57 + strlen (device), face);
96538889Sjdp
966218822Sdim  fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
96738889Sjdp  fd->next = NULL;
96838889Sjdp  fd->index = fonts;
96938889Sjdp  fd->length = fontdatalength;
97038889Sjdp  fd->data = fontdata;
97138889Sjdp
97238889Sjdp  for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
97338889Sjdp    ;
97438889Sjdp  *pp = fd;
97538889Sjdp
97638889Sjdp  /* For the single fontdirs resource, we always use the resource
97738889Sjdp     information of the last font.  I don't know what else to do.  */
97838889Sjdp  fontdirs_resinfo = *resinfo;
97938889Sjdp}
98038889Sjdp
981218822Sdimstatic void
982218822Sdimdefine_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
983218822Sdim		    rc_rcdata_item *data)
984218822Sdim{
985218822Sdim  rc_res_resource *r;
986218822Sdim  rc_uint_type len_data;
987218822Sdim  bfd_byte *pb_data;
988218822Sdim
989218822Sdim  r = define_standard_resource (&resources, RT_FONT, id,
990218822Sdim				resinfo->language, 0);
991218822Sdim
992218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
993218822Sdim
994218822Sdim  r->type = RES_TYPE_FONT;
995218822Sdim  r->u.data.length = len_data;
996218822Sdim  r->u.data.data = pb_data;
997218822Sdim  r->res_info = *resinfo;
998218822Sdim}
999218822Sdim
100038889Sjdp/* Define the fontdirs resource.  This is called after the entire rc
100138889Sjdp   file has been parsed, if any font resources were seen.  */
100238889Sjdp
100338889Sjdpstatic void
1004130561Sobriendefine_fontdirs (void)
100538889Sjdp{
1006218822Sdim  rc_res_resource *r;
1007218822Sdim  rc_res_id id;
100838889Sjdp
100938889Sjdp  id.named = 0;
101038889Sjdp  id.u.id = 1;
101138889Sjdp
101238889Sjdp  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
101338889Sjdp
101438889Sjdp  r->type = RES_TYPE_FONTDIR;
101538889Sjdp  r->u.fontdir = fontdirs;
101638889Sjdp  r->res_info = fontdirs_resinfo;
101738889Sjdp}
101838889Sjdp
1019218822Sdimstatic bfd_byte *
1020218822Sdimrcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
1021218822Sdim{
1022218822Sdim  const rc_rcdata_item *d;
1023218822Sdim  bfd_byte *ret = NULL, *pret;
1024218822Sdim  rc_uint_type len = 0;
1025218822Sdim
1026218822Sdim  for (d = data; d != NULL; d = d->next)
1027218822Sdim    len += rcdata_copy (d, NULL);
1028218822Sdim  if (len != 0)
1029218822Sdim    {
1030218822Sdim      ret = pret = (bfd_byte *) res_alloc (len);
1031218822Sdim      for (d = data; d != NULL; d = d->next)
1032218822Sdim	pret += rcdata_copy (d, pret);
1033218822Sdim    }
1034218822Sdim  if (plen)
1035218822Sdim    *plen = len;
1036218822Sdim  return ret;
1037218822Sdim}
1038218822Sdim
1039218822Sdimstatic void
1040218822Sdimdefine_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1041218822Sdim		       rc_rcdata_item *data)
1042218822Sdim{
1043218822Sdim  rc_res_resource *r;
1044218822Sdim  rc_fontdir *fd, *fd_first, *fd_cur;
1045218822Sdim  rc_uint_type len_data;
1046218822Sdim  bfd_byte *pb_data;
1047218822Sdim  rc_uint_type c;
1048218822Sdim
1049218822Sdim  fd_cur = fd_first = NULL;
1050218822Sdim  r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1051218822Sdim
1052218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
1053218822Sdim
1054218822Sdim  if (pb_data)
1055218822Sdim    {
1056218822Sdim      rc_uint_type off = 2;
1057218822Sdim      c = windres_get_16 (&wrtarget, pb_data, len_data);
1058218822Sdim      for (; c > 0; c--)
1059218822Sdim	{
1060218822Sdim	  size_t len;
1061218822Sdim	  rc_uint_type safe_pos = off;
1062218822Sdim	  const struct bin_fontdir_item *bfi;
1063218822Sdim
1064218822Sdim	  bfi = (const struct bin_fontdir_item *) pb_data + off;
1065218822Sdim	  fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1066218822Sdim	  fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
1067218822Sdim	  fd->data = pb_data + off;
1068218822Sdim	  off += 56;
1069218822Sdim	  len = strlen ((char *) bfi->device_name) + 1;
1070218822Sdim	  off += (rc_uint_type) len;
1071218822Sdim	  off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
1072218822Sdim	  fd->length = (off - safe_pos);
1073218822Sdim	  fd->next = NULL;
1074218822Sdim	  if (fd_first == NULL)
1075218822Sdim	    fd_first = fd;
1076218822Sdim	  else
1077218822Sdim	    fd_cur->next = fd;
1078218822Sdim	  fd_cur = fd;
1079218822Sdim	}
1080218822Sdim    }
1081218822Sdim  r->type = RES_TYPE_FONTDIR;
1082218822Sdim  r->u.fontdir = fd_first;
1083218822Sdim  r->res_info = *resinfo;
1084218822Sdim}
1085218822Sdim
1086218822Sdimstatic void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1087218822Sdim					rc_rcdata_item *data)
1088218822Sdim{
1089218822Sdim  rc_res_resource *r;
1090218822Sdim  rc_uint_type len_data;
1091218822Sdim  bfd_byte *pb_data;
1092218822Sdim
1093218822Sdim  r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
1094218822Sdim
1095218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
1096218822Sdim  r->type = RES_TYPE_MESSAGETABLE;
1097218822Sdim  r->u.data.length = len_data;
1098218822Sdim  r->u.data.data = pb_data;
1099218822Sdim  r->res_info = *resinfo;
1100218822Sdim}
1101218822Sdim
110238889Sjdp/* Define an icon resource.  An icon file may contain a set of
110338889Sjdp   bitmaps, each representing the same icon at various different
110438889Sjdp   resolutions.  They each get written out with a different ID.  The
110538889Sjdp   real icon resource is then a group resource which can be used to
110638889Sjdp   select one of the actual icon bitmaps.  */
110738889Sjdp
110838889Sjdpvoid
1109218822Sdimdefine_icon (rc_res_id id, const rc_res_res_info *resinfo,
1110130561Sobrien	     const char *filename)
111138889Sjdp{
111238889Sjdp  FILE *e;
111338889Sjdp  char *real_filename;
111438889Sjdp  int type, count, i;
111538889Sjdp  struct icondir *icondirs;
111638889Sjdp  int first_icon;
1117218822Sdim  rc_res_resource *r;
1118218822Sdim  rc_group_icon *first, **pp;
111938889Sjdp
112038889Sjdp  e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
112138889Sjdp
112238889Sjdp  /* The start of an icon file is a three word structure.  The first
112338889Sjdp     word is ignored.  The second word is the type of data.  The third
112438889Sjdp     word is the number of entries.  */
112538889Sjdp
112638889Sjdp  get_word (e, real_filename);
112738889Sjdp  type = get_word (e, real_filename);
112838889Sjdp  count = get_word (e, real_filename);
112938889Sjdp  if (type != 1)
113060484Sobrien    fatal (_("icon file `%s' does not contain icon data"), real_filename);
113138889Sjdp
113238889Sjdp  /* Read in the icon directory entries.  */
113338889Sjdp
113438889Sjdp  icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
113538889Sjdp
113638889Sjdp  for (i = 0; i < count; i++)
113738889Sjdp    {
113838889Sjdp      icondirs[i].width = getc (e);
113938889Sjdp      icondirs[i].height = getc (e);
114038889Sjdp      icondirs[i].colorcount = getc (e);
114138889Sjdp      getc (e);
114238889Sjdp      icondirs[i].u.icon.planes = get_word (e, real_filename);
114338889Sjdp      icondirs[i].u.icon.bits = get_word (e, real_filename);
114438889Sjdp      icondirs[i].bytes = get_long (e, real_filename);
114538889Sjdp      icondirs[i].offset = get_long (e, real_filename);
114638889Sjdp
114738889Sjdp      if (feof (e))
114838889Sjdp	unexpected_eof (real_filename);
114938889Sjdp    }
115038889Sjdp
115138889Sjdp  /* Define each icon as a unique resource.  */
115238889Sjdp
115338889Sjdp  first_icon = icons;
115438889Sjdp
115538889Sjdp  for (i = 0; i < count; i++)
115638889Sjdp    {
1157218822Sdim      bfd_byte *data;
1158218822Sdim      rc_res_id name;
115938889Sjdp
116038889Sjdp      if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
116160484Sobrien	fatal (_("%s: fseek to %lu failed: %s"), real_filename,
116238889Sjdp	       icondirs[i].offset, strerror (errno));
116338889Sjdp
1164218822Sdim      data = (bfd_byte *) res_alloc (icondirs[i].bytes);
116538889Sjdp
116638889Sjdp      get_data (e, data, icondirs[i].bytes, real_filename);
116738889Sjdp
116838889Sjdp      ++icons;
116938889Sjdp
117038889Sjdp      name.named = 0;
117138889Sjdp      name.u.id = icons;
117238889Sjdp
117338889Sjdp      r = define_standard_resource (&resources, RT_ICON, name,
117438889Sjdp				    resinfo->language, 0);
117538889Sjdp      r->type = RES_TYPE_ICON;
117638889Sjdp      r->u.data.length = icondirs[i].bytes;
117738889Sjdp      r->u.data.data = data;
117838889Sjdp      r->res_info = *resinfo;
117938889Sjdp    }
118038889Sjdp
118138889Sjdp  fclose (e);
118238889Sjdp  free (real_filename);
118338889Sjdp
118438889Sjdp  /* Define an icon group resource.  */
118538889Sjdp
118638889Sjdp  first = NULL;
118738889Sjdp  pp = &first;
118838889Sjdp  for (i = 0; i < count; i++)
118938889Sjdp    {
1190218822Sdim      rc_group_icon *cg;
119138889Sjdp
119238889Sjdp      /* For some reason, at least in some files the planes and bits
119338889Sjdp         are zero.  We instead set them from the color.  This is
119438889Sjdp         copied from rcl.  */
119538889Sjdp
1196218822Sdim      cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
119738889Sjdp      cg->next = NULL;
119838889Sjdp      cg->width = icondirs[i].width;
119938889Sjdp      cg->height = icondirs[i].height;
120038889Sjdp      cg->colors = icondirs[i].colorcount;
120138889Sjdp
1202130561Sobrien      if (icondirs[i].u.icon.planes)
1203130561Sobrien	cg->planes = icondirs[i].u.icon.planes;
1204130561Sobrien      else
1205130561Sobrien	cg->planes = 1;
120638889Sjdp
1207130561Sobrien      if (icondirs[i].u.icon.bits)
1208130561Sobrien	cg->bits = icondirs[i].u.icon.bits;
1209130561Sobrien      else
1210130561Sobrien	{
1211130561Sobrien	  cg->bits = 0;
1212130561Sobrien
1213130561Sobrien	  while ((1L << cg->bits) < cg->colors)
1214130561Sobrien	    ++cg->bits;
1215130561Sobrien	}
1216130561Sobrien
121738889Sjdp      cg->bytes = icondirs[i].bytes;
121838889Sjdp      cg->index = first_icon + i + 1;
121938889Sjdp
122038889Sjdp      *pp = cg;
122138889Sjdp      pp = &(*pp)->next;
122238889Sjdp    }
122338889Sjdp
122438889Sjdp  free (icondirs);
122538889Sjdp
122638889Sjdp  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
122738889Sjdp				resinfo->language, 0);
122838889Sjdp  r->type = RES_TYPE_GROUP_ICON;
122938889Sjdp  r->u.group_icon = first;
123038889Sjdp  r->res_info = *resinfo;
123138889Sjdp}
123238889Sjdp
1233218822Sdimstatic void
1234218822Sdimdefine_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1235218822Sdim			  rc_rcdata_item *data)
1236218822Sdim{
1237218822Sdim  rc_res_resource *r;
1238218822Sdim  rc_group_icon *cg, *first, *cur;
1239218822Sdim  rc_uint_type len_data;
1240218822Sdim  bfd_byte *pb_data;
1241218822Sdim
1242218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
1243218822Sdim
1244218822Sdim  cur = NULL;
1245218822Sdim  first = NULL;
1246218822Sdim
1247218822Sdim  while (len_data >= 6)
1248218822Sdim    {
1249218822Sdim      int c, i;
1250218822Sdim      unsigned short type;
1251218822Sdim      type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1252218822Sdim      if (type != 1)
1253218822Sdim	fatal (_("unexpected group icon type %d"), type);
1254218822Sdim      c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1255218822Sdim      len_data -= 6;
1256218822Sdim      pb_data += 6;
1257218822Sdim
1258218822Sdim      for (i = 0; i < c; i++)
1259218822Sdim	{
1260218822Sdim	  if (len_data < 14)
1261218822Sdim	    fatal ("too small group icon rcdata");
1262218822Sdim	  cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1263218822Sdim	  cg->next = NULL;
1264218822Sdim	  cg->width = pb_data[0];
1265218822Sdim	  cg->height = pb_data[1];
1266218822Sdim	  cg->colors = pb_data[2];
1267218822Sdim	  cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1268218822Sdim	  cg->bits =  windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1269218822Sdim	  cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1270218822Sdim	  cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1271218822Sdim	  if (! first)
1272218822Sdim	    first = cg;
1273218822Sdim	  else
1274218822Sdim	    cur->next = cg;
1275218822Sdim	  cur = cg;
1276218822Sdim	  pb_data += 14;
1277218822Sdim	  len_data -= 14;
1278218822Sdim	}
1279218822Sdim    }
1280218822Sdim  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1281218822Sdim				resinfo->language, 0);
1282218822Sdim  r->type = RES_TYPE_GROUP_ICON;
1283218822Sdim  r->u.group_icon = first;
1284218822Sdim  r->res_info = *resinfo;
1285218822Sdim}
1286218822Sdim
1287218822Sdimstatic void
1288218822Sdimdefine_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1289218822Sdim			    rc_rcdata_item *data)
1290218822Sdim{
1291218822Sdim  rc_res_resource *r;
1292218822Sdim  rc_group_cursor *cg, *first, *cur;
1293218822Sdim  rc_uint_type len_data;
1294218822Sdim  bfd_byte *pb_data;
1295218822Sdim
1296218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
1297218822Sdim
1298218822Sdim  first = cur = NULL;
1299218822Sdim
1300218822Sdim  while (len_data >= 6)
1301218822Sdim    {
1302218822Sdim      int c, i;
1303218822Sdim      unsigned short type;
1304218822Sdim      type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1305218822Sdim      if (type != 2)
1306218822Sdim	fatal (_("unexpected group cursor type %d"), type);
1307218822Sdim      c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1308218822Sdim      len_data -= 6;
1309218822Sdim      pb_data += 6;
1310218822Sdim
1311218822Sdim      for (i = 0; i < c; i++)
1312218822Sdim	{
1313218822Sdim	  if (len_data < 14)
1314218822Sdim	    fatal ("too small group icon rcdata");
1315218822Sdim	  cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
1316218822Sdim	  cg->next = NULL;
1317218822Sdim	  cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
1318218822Sdim	  cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1319218822Sdim	  cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1320218822Sdim	  cg->bits =  windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1321218822Sdim	  cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1322218822Sdim	  cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1323218822Sdim	  if (! first)
1324218822Sdim	    first = cg;
1325218822Sdim	  else
1326218822Sdim	    cur->next = cg;
1327218822Sdim	  cur = cg;
1328218822Sdim	  pb_data += 14;
1329218822Sdim	  len_data -= 14;
1330218822Sdim	}
1331218822Sdim    }
1332218822Sdim
1333218822Sdim  r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1334218822Sdim				resinfo->language, 0);
1335218822Sdim  r->type = RES_TYPE_GROUP_CURSOR;
1336218822Sdim  r->u.group_cursor = first;
1337218822Sdim  r->res_info = *resinfo;
1338218822Sdim}
1339218822Sdim
1340218822Sdimstatic void
1341218822Sdimdefine_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1342218822Sdim		      rc_rcdata_item *data)
1343218822Sdim{
1344218822Sdim  rc_cursor *c;
1345218822Sdim  rc_res_resource *r;
1346218822Sdim  rc_uint_type len_data;
1347218822Sdim  bfd_byte *pb_data;
1348218822Sdim
1349218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
1350218822Sdim
1351218822Sdim  c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
1352218822Sdim  c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
1353218822Sdim  c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1354218822Sdim  c->length = len_data - BIN_CURSOR_SIZE;
1355218822Sdim  c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
1356218822Sdim
1357218822Sdim  r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
1358218822Sdim  r->type = RES_TYPE_CURSOR;
1359218822Sdim  r->u.cursor = c;
1360218822Sdim  r->res_info = *resinfo;
1361218822Sdim}
1362218822Sdim
1363218822Sdimstatic void
1364218822Sdimdefine_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1365218822Sdim		      rc_rcdata_item *data)
1366218822Sdim{
1367218822Sdim  rc_res_resource *r;
1368218822Sdim  rc_uint_type len_data;
1369218822Sdim  bfd_byte *pb_data;
1370218822Sdim
1371218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
1372218822Sdim
1373218822Sdim  r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
1374218822Sdim  r->type = RES_TYPE_BITMAP;
1375218822Sdim  r->u.data.length = len_data;
1376218822Sdim  r->u.data.data = pb_data;
1377218822Sdim  r->res_info = *resinfo;
1378218822Sdim}
1379218822Sdim
1380218822Sdimstatic void
1381218822Sdimdefine_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1382218822Sdim		    rc_rcdata_item *data)
1383218822Sdim{
1384218822Sdim  rc_res_resource *r;
1385218822Sdim  rc_uint_type len_data;
1386218822Sdim  bfd_byte *pb_data;
1387218822Sdim
1388218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
1389218822Sdim
1390218822Sdim  r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
1391218822Sdim  r->type = RES_TYPE_ICON;
1392218822Sdim  r->u.data.length = len_data;
1393218822Sdim  r->u.data.data = pb_data;
1394218822Sdim  r->res_info = *resinfo;
1395218822Sdim}
1396218822Sdim
139738889Sjdp/* Define a menu resource.  */
139838889Sjdp
139938889Sjdpvoid
1400218822Sdimdefine_menu (rc_res_id id, const rc_res_res_info *resinfo,
1401218822Sdim	     rc_menuitem *menuitems)
140238889Sjdp{
1403218822Sdim  rc_menu *m;
1404218822Sdim  rc_res_resource *r;
140538889Sjdp
1406218822Sdim  m = (rc_menu *) res_alloc (sizeof (rc_menu));
140738889Sjdp  m->items = menuitems;
140838889Sjdp  m->help = 0;
140938889Sjdp
141038889Sjdp  r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
141138889Sjdp  r->type = RES_TYPE_MENU;
141238889Sjdp  r->u.menu = m;
141338889Sjdp  r->res_info = *resinfo;
141438889Sjdp}
141538889Sjdp
141638889Sjdp/* Define a menu item.  This does not define a resource, but merely
141738889Sjdp   allocates and fills in a structure.  */
141838889Sjdp
1419218822Sdimrc_menuitem *
1420218822Sdimdefine_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
1421218822Sdim		 rc_uint_type state, rc_uint_type help,
1422218822Sdim		 rc_menuitem *menuitems)
142338889Sjdp{
1424218822Sdim  rc_menuitem *mi;
142538889Sjdp
1426218822Sdim  mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
142738889Sjdp  mi->next = NULL;
142838889Sjdp  mi->type = type;
142938889Sjdp  mi->state = state;
143038889Sjdp  mi->id = menuid;
1431218822Sdim  mi->text = unichar_dup (text);
143238889Sjdp  mi->help = help;
143338889Sjdp  mi->popup = menuitems;
143438889Sjdp  return mi;
143538889Sjdp}
143638889Sjdp
143738889Sjdp/* Define a messagetable resource.  */
143838889Sjdp
143938889Sjdpvoid
1440218822Sdimdefine_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
1441130561Sobrien		     const char *filename)
144238889Sjdp{
144338889Sjdp  FILE *e;
144438889Sjdp  char *real_filename;
144538889Sjdp  struct stat s;
1446218822Sdim  bfd_byte *data;
1447218822Sdim  rc_res_resource *r;
144838889Sjdp
144938889Sjdp  e = open_file_search (filename, FOPEN_RB, "messagetable file",
145038889Sjdp			&real_filename);
145138889Sjdp
145238889Sjdp  if (stat (real_filename, &s) < 0)
145360484Sobrien    fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
145438889Sjdp	   strerror (errno));
145538889Sjdp
1456218822Sdim  data = (bfd_byte *) res_alloc (s.st_size);
145738889Sjdp
145838889Sjdp  get_data (e, data, s.st_size, real_filename);
145938889Sjdp
146038889Sjdp  fclose (e);
146138889Sjdp  free (real_filename);
146238889Sjdp
146338889Sjdp  r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
146438889Sjdp				resinfo->language, 0);
146538889Sjdp
146638889Sjdp  r->type = RES_TYPE_MESSAGETABLE;
146738889Sjdp  r->u.data.length = s.st_size;
146838889Sjdp  r->u.data.data = data;
146938889Sjdp  r->res_info = *resinfo;
147038889Sjdp}
147138889Sjdp
147238889Sjdp/* Define an rcdata resource.  */
147338889Sjdp
147438889Sjdpvoid
1475218822Sdimdefine_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1476218822Sdim	       rc_rcdata_item *data)
147738889Sjdp{
1478218822Sdim  rc_res_resource *r;
147938889Sjdp
148038889Sjdp  r = define_standard_resource (&resources, RT_RCDATA, id,
148138889Sjdp				resinfo->language, 0);
148238889Sjdp  r->type = RES_TYPE_RCDATA;
148338889Sjdp  r->u.rcdata = data;
148438889Sjdp  r->res_info = *resinfo;
148538889Sjdp}
148638889Sjdp
148738889Sjdp/* Create an rcdata item holding a string.  */
148838889Sjdp
1489218822Sdimrc_rcdata_item *
1490218822Sdimdefine_rcdata_string (const char *string, rc_uint_type len)
149138889Sjdp{
1492218822Sdim  rc_rcdata_item *ri;
149338889Sjdp  char *s;
149438889Sjdp
1495218822Sdim  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
149638889Sjdp  ri->next = NULL;
149738889Sjdp  ri->type = RCDATA_STRING;
149838889Sjdp  ri->u.string.length = len;
149938889Sjdp  s = (char *) res_alloc (len);
150038889Sjdp  memcpy (s, string, len);
150138889Sjdp  ri->u.string.s = s;
150238889Sjdp
150338889Sjdp  return ri;
150438889Sjdp}
150538889Sjdp
1506218822Sdim/* Create an rcdata item holding a unicode string.  */
1507218822Sdim
1508218822Sdimrc_rcdata_item *
1509218822Sdimdefine_rcdata_unistring (const unichar *string, rc_uint_type len)
1510218822Sdim{
1511218822Sdim  rc_rcdata_item *ri;
1512218822Sdim  unichar *s;
1513218822Sdim
1514218822Sdim  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1515218822Sdim  ri->next = NULL;
1516218822Sdim  ri->type = RCDATA_WSTRING;
1517218822Sdim  ri->u.wstring.length = len;
1518218822Sdim  s = (unichar *) res_alloc (len * sizeof (unichar));
1519218822Sdim  memcpy (s, string, len * sizeof (unichar));
1520218822Sdim  ri->u.wstring.w = s;
1521218822Sdim
1522218822Sdim  return ri;
1523218822Sdim}
1524218822Sdim
152538889Sjdp/* Create an rcdata item holding a number.  */
152638889Sjdp
1527218822Sdimrc_rcdata_item *
1528218822Sdimdefine_rcdata_number (rc_uint_type val, int dword)
152938889Sjdp{
1530218822Sdim  rc_rcdata_item *ri;
153138889Sjdp
1532218822Sdim  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
153338889Sjdp  ri->next = NULL;
153438889Sjdp  ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
153538889Sjdp  ri->u.word = val;
153638889Sjdp
153738889Sjdp  return ri;
153838889Sjdp}
153938889Sjdp
154038889Sjdp/* Define a stringtable resource.  This is called for each string
154138889Sjdp   which appears in a STRINGTABLE statement.  */
154238889Sjdp
154338889Sjdpvoid
1544218822Sdimdefine_stringtable (const rc_res_res_info *resinfo,
1545218822Sdim		    rc_uint_type stringid, const unichar *string)
154638889Sjdp{
1547218822Sdim  rc_res_id id;
1548218822Sdim  rc_res_resource *r;
154938889Sjdp
155038889Sjdp  id.named = 0;
155138889Sjdp  id.u.id = (stringid >> 4) + 1;
155238889Sjdp  r = define_standard_resource (&resources, RT_STRING, id,
155338889Sjdp				resinfo->language, 1);
155438889Sjdp
155538889Sjdp  if (r->type == RES_TYPE_UNINITIALIZED)
155638889Sjdp    {
155738889Sjdp      int i;
155838889Sjdp
155938889Sjdp      r->type = RES_TYPE_STRINGTABLE;
1560218822Sdim      r->u.stringtable = ((rc_stringtable *)
1561218822Sdim			  res_alloc (sizeof (rc_stringtable)));
156238889Sjdp      for (i = 0; i < 16; i++)
156338889Sjdp	{
156438889Sjdp	  r->u.stringtable->strings[i].length = 0;
156538889Sjdp	  r->u.stringtable->strings[i].string = NULL;
156638889Sjdp	}
156738889Sjdp
156838889Sjdp      r->res_info = *resinfo;
156938889Sjdp    }
157038889Sjdp
1571218822Sdim  r->u.stringtable->strings[stringid & 0xf].length = unichar_len (string);
1572218822Sdim  r->u.stringtable->strings[stringid & 0xf].string = unichar_dup (string);
157338889Sjdp}
157438889Sjdp
1575218822Sdimvoid
1576218822Sdimdefine_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
1577218822Sdim		rc_toolbar_item *items)
1578218822Sdim{
1579218822Sdim  rc_toolbar *t;
1580218822Sdim  rc_res_resource *r;
1581218822Sdim
1582218822Sdim  t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1583218822Sdim  t->button_width = width;
1584218822Sdim  t->button_height = height;
1585218822Sdim  t->nitems = 0;
1586218822Sdim  t->items = items;
1587218822Sdim  while (items != NULL)
1588218822Sdim  {
1589218822Sdim    t->nitems+=1;
1590218822Sdim    items = items->next;
1591218822Sdim  }
1592218822Sdim  r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
1593218822Sdim  r->type = RES_TYPE_TOOLBAR;
1594218822Sdim  r->u.toolbar = t;
1595218822Sdim  r->res_info = *resinfo;
1596218822Sdim}
1597218822Sdim
159838889Sjdp/* Define a user data resource where the data is in the rc file.  */
159938889Sjdp
160038889Sjdpvoid
1601218822Sdimdefine_user_data (rc_res_id id, rc_res_id type,
1602218822Sdim		  const rc_res_res_info *resinfo,
1603218822Sdim		  rc_rcdata_item *data)
160438889Sjdp{
1605218822Sdim  rc_res_id ids[3];
1606218822Sdim  rc_res_resource *r;
1607218822Sdim  bfd_byte *pb_data;
1608218822Sdim  rc_uint_type len_data;
160938889Sjdp
1610218822Sdim  /* We have to check if the binary data is parsed specially.  */
1611218822Sdim  if (type.named == 0)
1612218822Sdim    {
1613218822Sdim      switch (type.u.id)
1614218822Sdim      {
1615218822Sdim      case RT_FONTDIR:
1616218822Sdim	define_fontdir_rcdata (id, resinfo, data);
1617218822Sdim	return;
1618218822Sdim      case RT_FONT:
1619218822Sdim	define_font_rcdata (id, resinfo, data);
1620218822Sdim	return;
1621218822Sdim      case RT_ICON:
1622218822Sdim	define_icon_rcdata (id, resinfo, data);
1623218822Sdim	return;
1624218822Sdim      case RT_BITMAP:
1625218822Sdim	define_bitmap_rcdata (id, resinfo, data);
1626218822Sdim	return;
1627218822Sdim      case RT_CURSOR:
1628218822Sdim	define_cursor_rcdata (id, resinfo, data);
1629218822Sdim	return;
1630218822Sdim      case RT_GROUP_ICON:
1631218822Sdim	define_group_icon_rcdata (id, resinfo, data);
1632218822Sdim	return;
1633218822Sdim      case RT_GROUP_CURSOR:
1634218822Sdim	define_group_cursor_rcdata (id, resinfo, data);
1635218822Sdim	return;
1636218822Sdim      case RT_MESSAGETABLE:
1637218822Sdim	define_messagetable_rcdata (id, resinfo, data);
1638218822Sdim	return;
1639218822Sdim      default:
1640218822Sdim	/* Treat as normal user-data.  */
1641218822Sdim	break;
1642218822Sdim      }
1643218822Sdim    }
164438889Sjdp  ids[0] = type;
164538889Sjdp  ids[1] = id;
164638889Sjdp  ids[2].named = 0;
164738889Sjdp  ids[2].u.id = resinfo->language;
164838889Sjdp
1649218822Sdim  r = define_resource (& resources, 3, ids, 0);
165038889Sjdp  r->type = RES_TYPE_USERDATA;
1651218822Sdim  r->u.userdata = ((rc_rcdata_item *)
1652218822Sdim		   res_alloc (sizeof (rc_rcdata_item)));
1653218822Sdim  r->u.userdata->next = NULL;
1654218822Sdim  r->u.userdata->type = RCDATA_BUFFER;
1655218822Sdim  pb_data = rcdata_render_as_buffer (data, &len_data);
1656218822Sdim  r->u.userdata->u.buffer.length = len_data;
1657218822Sdim  r->u.userdata->u.buffer.data = pb_data;
165838889Sjdp  r->res_info = *resinfo;
165938889Sjdp}
166038889Sjdp
1661218822Sdimvoid
1662218822Sdimdefine_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
1663218822Sdim		    const char *filename)
1664218822Sdim{
1665218822Sdim  rc_rcdata_item *ri;
1666218822Sdim  FILE *e;
1667218822Sdim  char *real_filename;
1668218822Sdim  struct stat s;
1669218822Sdim  bfd_byte *data;
1670218822Sdim
1671218822Sdim  e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1672218822Sdim
1673218822Sdim
1674218822Sdim  if (stat (real_filename, &s) < 0)
1675218822Sdim    fatal (_("stat failed on file `%s': %s"), real_filename,
1676218822Sdim	   strerror (errno));
1677218822Sdim
1678218822Sdim  data = (bfd_byte *) res_alloc (s.st_size);
1679218822Sdim
1680218822Sdim  get_data (e, data, s.st_size, real_filename);
1681218822Sdim
1682218822Sdim  fclose (e);
1683218822Sdim  free (real_filename);
1684218822Sdim
1685218822Sdim  ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1686218822Sdim  ri->next = NULL;
1687218822Sdim  ri->type = RCDATA_BUFFER;
1688218822Sdim  ri->u.buffer.length = s.st_size;
1689218822Sdim  ri->u.buffer.data = data;
1690218822Sdim
1691218822Sdim  define_rcdata (id, resinfo, ri);
1692218822Sdim}
1693218822Sdim
169438889Sjdp/* Define a user data resource where the data is in a file.  */
169538889Sjdp
169638889Sjdpvoid
1697218822Sdimdefine_user_file (rc_res_id id, rc_res_id type,
1698218822Sdim		  const rc_res_res_info *resinfo, const char *filename)
169938889Sjdp{
170038889Sjdp  FILE *e;
170138889Sjdp  char *real_filename;
170238889Sjdp  struct stat s;
1703218822Sdim  bfd_byte *data;
1704218822Sdim  rc_res_id ids[3];
1705218822Sdim  rc_res_resource *r;
170638889Sjdp
1707218822Sdim  e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
170838889Sjdp
170938889Sjdp  if (stat (real_filename, &s) < 0)
1710218822Sdim    fatal (_("stat failed on file `%s': %s"), real_filename,
171138889Sjdp	   strerror (errno));
171238889Sjdp
1713218822Sdim  data = (bfd_byte *) res_alloc (s.st_size);
171438889Sjdp
171538889Sjdp  get_data (e, data, s.st_size, real_filename);
171638889Sjdp
171738889Sjdp  fclose (e);
171838889Sjdp  free (real_filename);
171938889Sjdp
172038889Sjdp  ids[0] = type;
172138889Sjdp  ids[1] = id;
172238889Sjdp  ids[2].named = 0;
172338889Sjdp  ids[2].u.id = resinfo->language;
172438889Sjdp
172538889Sjdp  r = define_resource (&resources, 3, ids, 0);
172638889Sjdp  r->type = RES_TYPE_USERDATA;
1727218822Sdim  r->u.userdata = ((rc_rcdata_item *)
1728218822Sdim		   res_alloc (sizeof (rc_rcdata_item)));
172938889Sjdp  r->u.userdata->next = NULL;
173038889Sjdp  r->u.userdata->type = RCDATA_BUFFER;
173138889Sjdp  r->u.userdata->u.buffer.length = s.st_size;
173238889Sjdp  r->u.userdata->u.buffer.data = data;
173338889Sjdp  r->res_info = *resinfo;
173438889Sjdp}
173538889Sjdp
173638889Sjdp/* Define a versioninfo resource.  */
173738889Sjdp
173838889Sjdpvoid
1739218822Sdimdefine_versioninfo (rc_res_id id, rc_uint_type language,
1740218822Sdim		    rc_fixed_versioninfo *fixedverinfo,
1741218822Sdim		    rc_ver_info *verinfo)
174238889Sjdp{
1743218822Sdim  rc_res_resource *r;
174438889Sjdp
174538889Sjdp  r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
174638889Sjdp  r->type = RES_TYPE_VERSIONINFO;
1747218822Sdim  r->u.versioninfo = ((rc_versioninfo *)
1748218822Sdim		      res_alloc (sizeof (rc_versioninfo)));
174938889Sjdp  r->u.versioninfo->fixed = fixedverinfo;
175038889Sjdp  r->u.versioninfo->var = verinfo;
175138889Sjdp  r->res_info.language = language;
175238889Sjdp}
175338889Sjdp
175438889Sjdp/* Add string version info to a list of version information.  */
175538889Sjdp
1756218822Sdimrc_ver_info *
1757218822Sdimappend_ver_stringfileinfo (rc_ver_info *verinfo, const char *language,
1758218822Sdim			   rc_ver_stringinfo *strings)
175938889Sjdp{
1760218822Sdim  rc_ver_info *vi, **pp;
176138889Sjdp
1762218822Sdim  vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
176338889Sjdp  vi->next = NULL;
176438889Sjdp  vi->type = VERINFO_STRING;
1765218822Sdim  unicode_from_ascii ((rc_uint_type *) NULL, &vi->u.string.language, language);
176638889Sjdp  vi->u.string.strings = strings;
176738889Sjdp
176838889Sjdp  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
176938889Sjdp    ;
177038889Sjdp  *pp = vi;
177138889Sjdp
177238889Sjdp  return verinfo;
177338889Sjdp}
177438889Sjdp
177538889Sjdp/* Add variable version info to a list of version information.  */
177638889Sjdp
1777218822Sdimrc_ver_info *
1778218822Sdimappend_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
1779218822Sdim			rc_ver_varinfo *var)
178038889Sjdp{
1781218822Sdim  rc_ver_info *vi, **pp;
178238889Sjdp
1783218822Sdim  vi = (rc_ver_info *) res_alloc (sizeof *vi);
178438889Sjdp  vi->next = NULL;
178538889Sjdp  vi->type = VERINFO_VAR;
1786218822Sdim  vi->u.var.key = unichar_dup (key);
178738889Sjdp  vi->u.var.var = var;
178838889Sjdp
178938889Sjdp  for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
179038889Sjdp    ;
179138889Sjdp  *pp = vi;
179238889Sjdp
179338889Sjdp  return verinfo;
179438889Sjdp}
179538889Sjdp
179638889Sjdp/* Append version string information to a list.  */
179738889Sjdp
1798218822Sdimrc_ver_stringinfo *
1799218822Sdimappend_verval (rc_ver_stringinfo *strings, const unichar *key,
1800218822Sdim	       const unichar *value)
180138889Sjdp{
1802218822Sdim  rc_ver_stringinfo *vs, **pp;
180338889Sjdp
1804218822Sdim  vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
180538889Sjdp  vs->next = NULL;
1806218822Sdim  vs->key = unichar_dup (key);
1807218822Sdim  vs->value = unichar_dup (value);
180838889Sjdp
180938889Sjdp  for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
181038889Sjdp    ;
181138889Sjdp  *pp = vs;
181238889Sjdp
181338889Sjdp  return strings;
181438889Sjdp}
181538889Sjdp
181638889Sjdp/* Append version variable information to a list.  */
181738889Sjdp
1818218822Sdimrc_ver_varinfo *
1819218822Sdimappend_vertrans (rc_ver_varinfo *var, rc_uint_type language,
1820218822Sdim		 rc_uint_type charset)
182138889Sjdp{
1822218822Sdim  rc_ver_varinfo *vv, **pp;
182338889Sjdp
1824218822Sdim  vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
182538889Sjdp  vv->next = NULL;
182638889Sjdp  vv->language = language;
182738889Sjdp  vv->charset = charset;
182838889Sjdp
182938889Sjdp  for (pp = &var; *pp != NULL; pp = &(*pp)->next)
183038889Sjdp    ;
183138889Sjdp  *pp = vv;
183238889Sjdp
183338889Sjdp  return var;
183438889Sjdp}
183538889Sjdp
183638889Sjdp/* Local functions used to write out an rc file.  */
183738889Sjdp
1838130561Sobrienstatic void indent (FILE *, int);
1839218822Sdimstatic void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
1840218822Sdim				const rc_res_id *, rc_uint_type *, int);
1841218822Sdimstatic void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
1842218822Sdim			     const rc_res_id *, rc_uint_type *, int);
1843218822Sdimstatic void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
1844218822Sdim			       const rc_res_resource *, rc_uint_type *);
1845218822Sdimstatic void write_rc_accelerators (FILE *, const rc_accelerator *);
1846218822Sdimstatic void write_rc_cursor (FILE *, const rc_cursor *);
1847218822Sdimstatic void write_rc_group_cursor (FILE *, const rc_group_cursor *);
1848218822Sdimstatic void write_rc_dialog (FILE *, const rc_dialog *);
1849218822Sdimstatic void write_rc_dialog_control (FILE *, const rc_dialog_control *);
1850218822Sdimstatic void write_rc_fontdir (FILE *, const rc_fontdir *);
1851218822Sdimstatic void write_rc_group_icon (FILE *, const rc_group_icon *);
1852218822Sdimstatic void write_rc_menu (FILE *, const rc_menu *, int);
1853218822Sdimstatic void write_rc_toolbar (FILE *, const rc_toolbar *);
1854218822Sdimstatic void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
1855218822Sdimstatic void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
185638889Sjdp
1857218822Sdimstatic void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
1858218822Sdimstatic void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
1859218822Sdimstatic void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
1860218822Sdimstatic void write_rc_versioninfo (FILE *, const rc_versioninfo *);
1861218822Sdim
186238889Sjdp/* Indent a given number of spaces.  */
186338889Sjdp
186438889Sjdpstatic void
1865130561Sobrienindent (FILE *e, int c)
186638889Sjdp{
186738889Sjdp  int i;
186838889Sjdp
186938889Sjdp  for (i = 0; i < c; i++)
187038889Sjdp    putc (' ', e);
187138889Sjdp}
187238889Sjdp
187338889Sjdp/* Dump the resources we have read in the format of an rc file.
187438889Sjdp
1875218822Sdim   Reasoned by the fact, that some resources need to be stored into file and
1876218822Sdim   refer to that file, we use the user-data model for that to express it binary
1877218822Sdim   without the need to store it somewhere externally.  */
187838889Sjdp
187938889Sjdpvoid
1880218822Sdimwrite_rc_file (const char *filename, const rc_res_directory *resources)
188138889Sjdp{
188238889Sjdp  FILE *e;
1883218822Sdim  rc_uint_type language;
188438889Sjdp
188538889Sjdp  if (filename == NULL)
188638889Sjdp    e = stdout;
188738889Sjdp  else
188838889Sjdp    {
188938889Sjdp      e = fopen (filename, FOPEN_WT);
189038889Sjdp      if (e == NULL)
189160484Sobrien	fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
189238889Sjdp    }
189338889Sjdp
1894218822Sdim  language = (rc_uint_type) ((bfd_signed_vma) -1);
1895218822Sdim  write_rc_directory (e, resources, (const rc_res_id *) NULL,
1896218822Sdim		      (const rc_res_id *) NULL, &language, 1);
189738889Sjdp}
189838889Sjdp
189938889Sjdp/* Write out a directory.  E is the file to write to.  RD is the
190038889Sjdp   directory.  TYPE is a pointer to the level 1 ID which serves as the
190138889Sjdp   resource type.  NAME is a pointer to the level 2 ID which serves as
190238889Sjdp   an individual resource name.  LANGUAGE is a pointer to the current
190338889Sjdp   language.  LEVEL is the level in the tree.  */
190438889Sjdp
190538889Sjdpstatic void
1906218822Sdimwrite_rc_directory (FILE *e, const rc_res_directory *rd,
1907218822Sdim		    const rc_res_id *type, const rc_res_id *name,
1908218822Sdim		    rc_uint_type *language, int level)
190938889Sjdp{
1910218822Sdim  const rc_res_entry *re;
191138889Sjdp
191238889Sjdp  /* Print out some COFF information that rc files can't represent.  */
1913218822Sdim  if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
1914218822Sdim    {
1915218822Sdim      wr_printcomment (e, "COFF information not part of RC");
191638889Sjdp  if (rd->time != 0)
1917218822Sdim	wr_printcomment (e, "Time stamp: %u", rd->time);
191838889Sjdp  if (rd->characteristics != 0)
1919218822Sdim	wr_printcomment (e, "Characteristics: %u", rd->characteristics);
192038889Sjdp  if (rd->major != 0 || rd->minor != 0)
1921218822Sdim	wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
1922218822Sdim    }
192338889Sjdp
192438889Sjdp  for (re = rd->entries;  re != NULL; re = re->next)
192538889Sjdp    {
192638889Sjdp      switch (level)
192738889Sjdp	{
192838889Sjdp	case 1:
192938889Sjdp	  /* If we're at level 1, the key of this resource is the
193038889Sjdp             type.  This normally duplicates the information we have
193138889Sjdp             stored with the resource itself, but we need to remember
193238889Sjdp             the type if this is a user define resource type.  */
193338889Sjdp	  type = &re->id;
193438889Sjdp	  break;
193538889Sjdp
193638889Sjdp	case 2:
193738889Sjdp	  /* If we're at level 2, the key of this resource is the name
193899461Sobrien	     we are going to use in the rc printout.  */
193938889Sjdp	  name = &re->id;
194038889Sjdp	  break;
194138889Sjdp
194238889Sjdp	case 3:
194338889Sjdp	  /* If we're at level 3, then this key represents a language.
194438889Sjdp	     Use it to update the current language.  */
194538889Sjdp	  if (! re->id.named
194660484Sobrien	      && re->id.u.id != (unsigned long) (unsigned int) *language
194738889Sjdp	      && (re->id.u.id & 0xffff) == re->id.u.id)
194838889Sjdp	    {
1949218822Sdim	      wr_print (e, "LANGUAGE %u, %u\n",
1950104834Sobrien		       re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
195199461Sobrien		       (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
195238889Sjdp	      *language = re->id.u.id;
195338889Sjdp	    }
195438889Sjdp	  break;
195538889Sjdp
195638889Sjdp	default:
195738889Sjdp	  break;
195838889Sjdp	}
195938889Sjdp
196038889Sjdp      if (re->subdir)
196138889Sjdp	write_rc_subdir (e, re, type, name, language, level);
196238889Sjdp      else
196338889Sjdp	{
196438889Sjdp	  if (level == 3)
196538889Sjdp	    {
196638889Sjdp	      /* This is the normal case: the three levels are
196738889Sjdp                 TYPE/NAME/LANGUAGE.  NAME will have been set at level
196838889Sjdp                 2, and represents the name to use.  We probably just
196938889Sjdp                 set LANGUAGE, and it will probably match what the
197038889Sjdp                 resource itself records if anything.  */
197138889Sjdp	      write_rc_resource (e, type, name, re->u.res, language);
197238889Sjdp	    }
197338889Sjdp	  else
197438889Sjdp	    {
1975218822Sdim	      wr_printcomment (e, "Resource at unexpected level %d", level);
1976218822Sdim	      write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
197738889Sjdp				 language);
197838889Sjdp	    }
197938889Sjdp	}
198038889Sjdp    }
1981218822Sdim  if (rd->entries == NULL)
1982218822Sdim    {
1983218822Sdim      wr_print_flush (e);
1984218822Sdim    }
198538889Sjdp}
198638889Sjdp
198738889Sjdp/* Write out a subdirectory entry.  E is the file to write to.  RE is
198838889Sjdp   the subdirectory entry.  TYPE and NAME are pointers to higher level
198938889Sjdp   IDs, or NULL.  LANGUAGE is a pointer to the current language.
199038889Sjdp   LEVEL is the level in the tree.  */
199138889Sjdp
199238889Sjdpstatic void
1993218822Sdimwrite_rc_subdir (FILE *e, const rc_res_entry *re,
1994218822Sdim		 const rc_res_id *type, const rc_res_id *name,
1995218822Sdim		 rc_uint_type *language, int level)
199638889Sjdp{
199738889Sjdp  fprintf (e, "\n");
199838889Sjdp  switch (level)
199938889Sjdp    {
200038889Sjdp    case 1:
2001218822Sdim      wr_printcomment (e, "Type: ");
200238889Sjdp      if (re->id.named)
200338889Sjdp	res_id_print (e, re->id, 1);
200438889Sjdp      else
200538889Sjdp	{
200638889Sjdp	  const char *s;
200738889Sjdp
200838889Sjdp	  switch (re->id.u.id)
200938889Sjdp	    {
201038889Sjdp	    case RT_CURSOR: s = "cursor"; break;
201138889Sjdp	    case RT_BITMAP: s = "bitmap"; break;
201238889Sjdp	    case RT_ICON: s = "icon"; break;
201338889Sjdp	    case RT_MENU: s = "menu"; break;
201438889Sjdp	    case RT_DIALOG: s = "dialog"; break;
201538889Sjdp	    case RT_STRING: s = "stringtable"; break;
201638889Sjdp	    case RT_FONTDIR: s = "fontdir"; break;
201738889Sjdp	    case RT_FONT: s = "font"; break;
201860484Sobrien	    case RT_ACCELERATOR: s = "accelerators"; break;
201938889Sjdp	    case RT_RCDATA: s = "rcdata"; break;
202038889Sjdp	    case RT_MESSAGETABLE: s = "messagetable"; break;
202138889Sjdp	    case RT_GROUP_CURSOR: s = "group cursor"; break;
202238889Sjdp	    case RT_GROUP_ICON: s = "group icon"; break;
202338889Sjdp	    case RT_VERSION: s = "version"; break;
202438889Sjdp	    case RT_DLGINCLUDE: s = "dlginclude"; break;
202538889Sjdp	    case RT_PLUGPLAY: s = "plugplay"; break;
202638889Sjdp	    case RT_VXD: s = "vxd"; break;
202738889Sjdp	    case RT_ANICURSOR: s = "anicursor"; break;
202838889Sjdp	    case RT_ANIICON: s = "aniicon"; break;
2029218822Sdim	    case RT_TOOLBAR: s = "toolbar"; break;
2030218822Sdim	    case RT_HTML: s = "html"; break;
203138889Sjdp	    default: s = NULL; break;
203238889Sjdp	    }
203338889Sjdp
203438889Sjdp	  if (s != NULL)
203538889Sjdp	    fprintf (e, "%s", s);
203638889Sjdp	  else
203738889Sjdp	    res_id_print (e, re->id, 1);
203838889Sjdp	}
203938889Sjdp      break;
204038889Sjdp
204138889Sjdp    case 2:
2042218822Sdim      wr_printcomment (e, "Name: ");
204338889Sjdp      res_id_print (e, re->id, 1);
204438889Sjdp      break;
204538889Sjdp
204638889Sjdp    case 3:
2047218822Sdim      wr_printcomment (e, "Language: ");
204838889Sjdp      res_id_print (e, re->id, 1);
204938889Sjdp      break;
205038889Sjdp
205138889Sjdp    default:
2052218822Sdim      wr_printcomment (e, "Level %d: ", level);
205338889Sjdp      res_id_print (e, re->id, 1);
2054104834Sobrien    }
205538889Sjdp
205638889Sjdp  write_rc_directory (e, re->u.dir, type, name, language, level + 1);
205738889Sjdp}
205838889Sjdp
205938889Sjdp/* Write out a single resource.  E is the file to write to.  TYPE is a
206038889Sjdp   pointer to the type of the resource.  NAME is a pointer to the name
206138889Sjdp   of the resource; it will be NULL if there is a level mismatch.  RES
206238889Sjdp   is the resource data.  LANGUAGE is a pointer to the current
206338889Sjdp   language.  */
206438889Sjdp
206538889Sjdpstatic void
2066218822Sdimwrite_rc_resource (FILE *e, const rc_res_id *type,
2067218822Sdim		   const rc_res_id *name, const rc_res_resource *res,
2068218822Sdim		   rc_uint_type *language)
206938889Sjdp{
207038889Sjdp  const char *s;
207138889Sjdp  int rt;
207238889Sjdp  int menuex = 0;
207338889Sjdp
207438889Sjdp  switch (res->type)
207538889Sjdp    {
207638889Sjdp    default:
207738889Sjdp      abort ();
207838889Sjdp
207938889Sjdp    case RES_TYPE_ACCELERATOR:
2080218822Sdim      s = "ACCELERATORS";
208160484Sobrien      rt = RT_ACCELERATOR;
208238889Sjdp      break;
208338889Sjdp
208438889Sjdp    case RES_TYPE_BITMAP:
2085218822Sdim      s = "2 /* RT_BITMAP */";
208638889Sjdp      rt = RT_BITMAP;
208738889Sjdp      break;
208838889Sjdp
208938889Sjdp    case RES_TYPE_CURSOR:
2090218822Sdim      s = "1 /* RT_CURSOR */";
209138889Sjdp      rt = RT_CURSOR;
209238889Sjdp      break;
209338889Sjdp
209438889Sjdp    case RES_TYPE_GROUP_CURSOR:
2095218822Sdim      s = "12 /* RT_GROUP_CURSOR */";
209638889Sjdp      rt = RT_GROUP_CURSOR;
209738889Sjdp      break;
209838889Sjdp
209938889Sjdp    case RES_TYPE_DIALOG:
210038889Sjdp      if (extended_dialog (res->u.dialog))
210138889Sjdp	s = "DIALOGEX";
210238889Sjdp      else
210338889Sjdp	s = "DIALOG";
210438889Sjdp      rt = RT_DIALOG;
210538889Sjdp      break;
210638889Sjdp
210738889Sjdp    case RES_TYPE_FONT:
2108218822Sdim      s = "8 /* RT_FONT */";
210938889Sjdp      rt = RT_FONT;
211038889Sjdp      break;
211138889Sjdp
211238889Sjdp    case RES_TYPE_FONTDIR:
2113218822Sdim      s = "7 /* RT_FONTDIR */";
211438889Sjdp      rt = RT_FONTDIR;
211538889Sjdp      break;
211638889Sjdp
211738889Sjdp    case RES_TYPE_ICON:
2118218822Sdim      s = "3 /* RT_ICON */";
211938889Sjdp      rt = RT_ICON;
212038889Sjdp      break;
212138889Sjdp
212238889Sjdp    case RES_TYPE_GROUP_ICON:
2123218822Sdim      s = "14 /* RT_GROUP_ICON */";
212438889Sjdp      rt = RT_GROUP_ICON;
212538889Sjdp      break;
212638889Sjdp
212738889Sjdp    case RES_TYPE_MENU:
212838889Sjdp      if (extended_menu (res->u.menu))
212938889Sjdp	{
213038889Sjdp	  s = "MENUEX";
213138889Sjdp	  menuex = 1;
213238889Sjdp	}
213338889Sjdp      else
213438889Sjdp	{
213538889Sjdp	  s = "MENU";
213638889Sjdp	  menuex = 0;
213738889Sjdp	}
213838889Sjdp      rt = RT_MENU;
213938889Sjdp      break;
214038889Sjdp
214138889Sjdp    case RES_TYPE_MESSAGETABLE:
2142218822Sdim      s = "11 /* RT_MESSAGETABLE */";
214338889Sjdp      rt = RT_MESSAGETABLE;
214438889Sjdp      break;
214538889Sjdp
214638889Sjdp    case RES_TYPE_RCDATA:
214738889Sjdp      s = "RCDATA";
214838889Sjdp      rt = RT_RCDATA;
214938889Sjdp      break;
215038889Sjdp
215138889Sjdp    case RES_TYPE_STRINGTABLE:
215238889Sjdp      s = "STRINGTABLE";
215338889Sjdp      rt = RT_STRING;
215438889Sjdp      break;
215538889Sjdp
215638889Sjdp    case RES_TYPE_USERDATA:
215738889Sjdp      s = NULL;
215838889Sjdp      rt = 0;
215938889Sjdp      break;
216038889Sjdp
216138889Sjdp    case RES_TYPE_VERSIONINFO:
216238889Sjdp      s = "VERSIONINFO";
216338889Sjdp      rt = RT_VERSION;
216438889Sjdp      break;
2165218822Sdim
2166218822Sdim    case RES_TYPE_TOOLBAR:
2167218822Sdim      s = "TOOLBAR";
2168218822Sdim      rt = RT_TOOLBAR;
2169218822Sdim      break;
217038889Sjdp    }
217138889Sjdp
217238889Sjdp  if (rt != 0
217338889Sjdp      && type != NULL
217460484Sobrien      && (type->named || type->u.id != (unsigned long) rt))
217538889Sjdp    {
2176218822Sdim      wr_printcomment (e, "Unexpected resource type mismatch: ");
217738889Sjdp      res_id_print (e, *type, 1);
217838889Sjdp      fprintf (e, " != %d", rt);
217938889Sjdp    }
218038889Sjdp
218138889Sjdp  if (res->coff_info.codepage != 0)
2182218822Sdim    wr_printcomment (e, "Code page: %u", res->coff_info.codepage);
218338889Sjdp  if (res->coff_info.reserved != 0)
2184218822Sdim    wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved);
218538889Sjdp
2186218822Sdim  wr_print (e, "\n");
2187218822Sdim  if (rt == RT_STRING)
2188218822Sdim    ;
2189218822Sdim  else
2190218822Sdim    {
219138889Sjdp  if (name != NULL)
2192218822Sdim	res_id_print (e, *name, 1);
219338889Sjdp  else
219438889Sjdp    fprintf (e, "??Unknown-Name??");
2195218822Sdim  fprintf (e, " ");
2196218822Sdim    }
219738889Sjdp
219838889Sjdp  if (s != NULL)
219938889Sjdp    fprintf (e, "%s", s);
220038889Sjdp  else if (type != NULL)
2201218822Sdim    {
2202218822Sdim      if (type->named == 0)
2203218822Sdim	{
2204218822Sdim#define PRINT_RT_NAME(NAME) case NAME: \
2205218822Sdim	fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2206218822Sdim	break
2207218822Sdim
2208218822Sdim	  switch (type->u.id)
2209218822Sdim	    {
2210218822Sdim	    default:
221138889Sjdp    res_id_print (e, *type, 0);
2212218822Sdim	      break;
2213218822Sdim
2214218822Sdim	    PRINT_RT_NAME(RT_MANIFEST);
2215218822Sdim	    PRINT_RT_NAME(RT_ANICURSOR);
2216218822Sdim	    PRINT_RT_NAME(RT_ANIICON);
2217218822Sdim	    PRINT_RT_NAME(RT_RCDATA);
2218218822Sdim	    PRINT_RT_NAME(RT_ICON);
2219218822Sdim	    PRINT_RT_NAME(RT_CURSOR);
2220218822Sdim	    PRINT_RT_NAME(RT_BITMAP);
2221218822Sdim	    PRINT_RT_NAME(RT_PLUGPLAY);
2222218822Sdim	    PRINT_RT_NAME(RT_VXD);
2223218822Sdim	    PRINT_RT_NAME(RT_FONT);
2224218822Sdim	    PRINT_RT_NAME(RT_FONTDIR);
2225218822Sdim	    PRINT_RT_NAME(RT_HTML);
2226218822Sdim	    PRINT_RT_NAME(RT_MESSAGETABLE);
2227218822Sdim	    PRINT_RT_NAME(RT_DLGINCLUDE);
2228218822Sdim	    PRINT_RT_NAME(RT_DLGINIT);
2229218822Sdim	    }
2230218822Sdim#undef PRINT_RT_NAME
2231218822Sdim	}
2232218822Sdim      else
2233218822Sdim	res_id_print (e, *type, 1);
2234218822Sdim    }
223538889Sjdp  else
223638889Sjdp    fprintf (e, "??Unknown-Type??");
223738889Sjdp
223838889Sjdp  if (res->res_info.memflags != 0)
223938889Sjdp    {
224038889Sjdp      if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
224138889Sjdp	fprintf (e, " MOVEABLE");
224238889Sjdp      if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
224338889Sjdp	fprintf (e, " PURE");
224438889Sjdp      if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
224538889Sjdp	fprintf (e, " PRELOAD");
224638889Sjdp      if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
224738889Sjdp	fprintf (e, " DISCARDABLE");
224838889Sjdp    }
224938889Sjdp
225038889Sjdp  if (res->type == RES_TYPE_DIALOG)
225138889Sjdp    {
2252218822Sdim      fprintf (e, " %d, %d, %d, %d",
2253218822Sdim	       (int) res->u.dialog->x, (int) res->u.dialog->y,
2254218822Sdim	       (int) res->u.dialog->width, (int) res->u.dialog->height);
225538889Sjdp      if (res->u.dialog->ex != NULL
225638889Sjdp	  && res->u.dialog->ex->help != 0)
2257218822Sdim	fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help);
225838889Sjdp    }
2259218822Sdim  else if (res->type == RES_TYPE_TOOLBAR)
2260218822Sdim  {
2261218822Sdim    fprintf (e, " %d, %d", (int) res->u.toolbar->button_width,
2262218822Sdim	     (int) res->u.toolbar->button_height);
2263218822Sdim    }
226438889Sjdp
226538889Sjdp  fprintf (e, "\n");
226638889Sjdp
226738889Sjdp  if ((res->res_info.language != 0 && res->res_info.language != *language)
226838889Sjdp      || res->res_info.characteristics != 0
226938889Sjdp      || res->res_info.version != 0)
227038889Sjdp    {
227138889Sjdp      int modifiers;
227238889Sjdp
227338889Sjdp      switch (res->type)
227438889Sjdp	{
227538889Sjdp	case RES_TYPE_ACCELERATOR:
227638889Sjdp	case RES_TYPE_DIALOG:
227738889Sjdp	case RES_TYPE_MENU:
227838889Sjdp	case RES_TYPE_RCDATA:
227938889Sjdp	case RES_TYPE_STRINGTABLE:
228038889Sjdp	  modifiers = 1;
228138889Sjdp	  break;
228238889Sjdp
228338889Sjdp	default:
228438889Sjdp	  modifiers = 0;
228538889Sjdp	  break;
228638889Sjdp	}
228738889Sjdp
228838889Sjdp      if (res->res_info.language != 0 && res->res_info.language != *language)
228938889Sjdp	fprintf (e, "%sLANGUAGE %d, %d\n",
229038889Sjdp		 modifiers ? "// " : "",
2291218822Sdim		 (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
2292218822Sdim		 (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
229338889Sjdp      if (res->res_info.characteristics != 0)
2294218822Sdim	fprintf (e, "%sCHARACTERISTICS %u\n",
229538889Sjdp		 modifiers ? "// " : "",
2296218822Sdim		 (unsigned int) res->res_info.characteristics);
229738889Sjdp      if (res->res_info.version != 0)
2298218822Sdim	fprintf (e, "%sVERSION %u\n",
229938889Sjdp		 modifiers ? "// " : "",
2300218822Sdim		 (unsigned int) res->res_info.version);
230138889Sjdp    }
230238889Sjdp
230338889Sjdp  switch (res->type)
230438889Sjdp    {
230538889Sjdp    default:
230638889Sjdp      abort ();
230738889Sjdp
230838889Sjdp    case RES_TYPE_ACCELERATOR:
230938889Sjdp      write_rc_accelerators (e, res->u.acc);
231038889Sjdp      break;
231138889Sjdp
231238889Sjdp    case RES_TYPE_CURSOR:
231338889Sjdp      write_rc_cursor (e, res->u.cursor);
231438889Sjdp      break;
231538889Sjdp
231638889Sjdp    case RES_TYPE_GROUP_CURSOR:
231738889Sjdp      write_rc_group_cursor (e, res->u.group_cursor);
231838889Sjdp      break;
231938889Sjdp
232038889Sjdp    case RES_TYPE_DIALOG:
232138889Sjdp      write_rc_dialog (e, res->u.dialog);
232238889Sjdp      break;
232338889Sjdp
232438889Sjdp    case RES_TYPE_FONTDIR:
232538889Sjdp      write_rc_fontdir (e, res->u.fontdir);
232638889Sjdp      break;
232738889Sjdp
232838889Sjdp    case RES_TYPE_GROUP_ICON:
232938889Sjdp      write_rc_group_icon (e, res->u.group_icon);
233038889Sjdp      break;
233138889Sjdp
233238889Sjdp    case RES_TYPE_MENU:
233338889Sjdp      write_rc_menu (e, res->u.menu, menuex);
233438889Sjdp      break;
233538889Sjdp
233638889Sjdp    case RES_TYPE_RCDATA:
233738889Sjdp      write_rc_rcdata (e, res->u.rcdata, 0);
233838889Sjdp      break;
233938889Sjdp
234038889Sjdp    case RES_TYPE_STRINGTABLE:
234138889Sjdp      write_rc_stringtable (e, name, res->u.stringtable);
234238889Sjdp      break;
234338889Sjdp
234438889Sjdp    case RES_TYPE_USERDATA:
234538889Sjdp      write_rc_rcdata (e, res->u.userdata, 0);
234638889Sjdp      break;
234738889Sjdp
2348218822Sdim    case RES_TYPE_TOOLBAR:
2349218822Sdim      write_rc_toolbar (e, res->u.toolbar);
2350218822Sdim      break;
2351218822Sdim
235238889Sjdp    case RES_TYPE_VERSIONINFO:
235338889Sjdp      write_rc_versioninfo (e, res->u.versioninfo);
235438889Sjdp      break;
235538889Sjdp
235638889Sjdp    case RES_TYPE_BITMAP:
235738889Sjdp    case RES_TYPE_FONT:
235838889Sjdp    case RES_TYPE_ICON:
2359218822Sdim      write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0);
2360218822Sdim      break;
236138889Sjdp    case RES_TYPE_MESSAGETABLE:
2362218822Sdim      write_rc_messagetable (e, res->u.data.length, res->u.data.data);
236338889Sjdp      break;
236438889Sjdp    }
236538889Sjdp}
236638889Sjdp
236738889Sjdp/* Write out accelerator information.  */
236838889Sjdp
236938889Sjdpstatic void
2370218822Sdimwrite_rc_accelerators (FILE *e, const rc_accelerator *accelerators)
237138889Sjdp{
2372218822Sdim  const rc_accelerator *acc;
237338889Sjdp
237438889Sjdp  fprintf (e, "BEGIN\n");
237538889Sjdp  for (acc = accelerators; acc != NULL; acc = acc->next)
237638889Sjdp    {
237738889Sjdp      int printable;
237838889Sjdp
237938889Sjdp      fprintf (e, "  ");
238038889Sjdp
238138889Sjdp      if ((acc->key & 0x7f) == acc->key
238289857Sobrien	  && ISPRINT (acc->key)
238338889Sjdp	  && (acc->flags & ACC_VIRTKEY) == 0)
238438889Sjdp	{
2385218822Sdim	  fprintf (e, "\"%c\"", (char) acc->key);
238638889Sjdp	  printable = 1;
238738889Sjdp	}
238838889Sjdp      else
238938889Sjdp	{
2390218822Sdim	  fprintf (e, "%d", (int) acc->key);
239138889Sjdp	  printable = 0;
239238889Sjdp	}
239338889Sjdp
2394218822Sdim      fprintf (e, ", %d", (int) acc->id);
239538889Sjdp
239638889Sjdp      if (! printable)
239738889Sjdp	{
239838889Sjdp	  if ((acc->flags & ACC_VIRTKEY) != 0)
239938889Sjdp	    fprintf (e, ", VIRTKEY");
240038889Sjdp	  else
240138889Sjdp	    fprintf (e, ", ASCII");
240238889Sjdp	}
240338889Sjdp
240438889Sjdp      if ((acc->flags & ACC_SHIFT) != 0)
240538889Sjdp	fprintf (e, ", SHIFT");
240638889Sjdp      if ((acc->flags & ACC_CONTROL) != 0)
240738889Sjdp	fprintf (e, ", CONTROL");
240838889Sjdp      if ((acc->flags & ACC_ALT) != 0)
240938889Sjdp	fprintf (e, ", ALT");
241038889Sjdp
241138889Sjdp      fprintf (e, "\n");
241238889Sjdp    }
241338889Sjdp
241438889Sjdp  fprintf (e, "END\n");
241538889Sjdp}
241638889Sjdp
241738889Sjdp/* Write out cursor information.  This would normally be in a separate
241838889Sjdp   file, which the rc file would include.  */
241938889Sjdp
242038889Sjdpstatic void
2421218822Sdimwrite_rc_cursor (FILE *e, const rc_cursor *cursor)
242238889Sjdp{
2423218822Sdim  fprintf (e, "BEGIN\n");
2424218822Sdim  indent (e, 2);
2425218822Sdim  fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d.  */\n",
2426218822Sdim	   (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot,
2427218822Sdim	   (int) cursor->xhotspot, (int) cursor->yhotspot);
2428218822Sdim  write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data,
2429218822Sdim  		      0, 0, 0);
2430218822Sdim  fprintf (e, "END\n");
243138889Sjdp}
243238889Sjdp
243338889Sjdp/* Write out group cursor data.  This would normally be built from the
243438889Sjdp   cursor data.  */
243538889Sjdp
243638889Sjdpstatic void
2437218822Sdimwrite_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor)
243838889Sjdp{
2439218822Sdim  const rc_group_cursor *gc;
2440218822Sdim  int c;
244138889Sjdp
2442218822Sdim  for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2443218822Sdim    ;
2444218822Sdim  fprintf (e, "BEGIN\n");
2445218822Sdim
2446218822Sdim  indent (e, 2);
2447218822Sdim  fprintf (e, "0, 2, %d%s\t /* Having %d items.  */\n", c, (c != 0 ? "," : ""), c);
2448218822Sdim  indent (e, 4);
2449218822Sdim  fprintf (e, "/* width, height, planes, bits, bytes, index.  */\n");
2450218822Sdim
2451218822Sdim  for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++)
245238889Sjdp    {
2453218822Sdim      indent (e, 4);
2454218822Sdim      fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2455218822Sdim	(int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits,
2456218822Sdim	(unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c);
2457218822Sdim      fprintf (e, "/* width: %d; height %d; planes %d; bits %d.  */\n",
2458218822Sdim	     (int) gc->width, (int) gc->height, (int) gc->planes,
2459218822Sdim	     (int) gc->bits);
246038889Sjdp    }
2461218822Sdim  fprintf (e, "END\n");
246238889Sjdp}
246338889Sjdp
246438889Sjdp/* Write dialog data.  */
246538889Sjdp
246638889Sjdpstatic void
2467218822Sdimwrite_rc_dialog (FILE *e, const rc_dialog *dialog)
246838889Sjdp{
2469218822Sdim  const rc_dialog_control *control;
247038889Sjdp
2471218822Sdim  fprintf (e, "STYLE 0x%x\n", dialog->style);
247299461Sobrien
247338889Sjdp  if (dialog->exstyle != 0)
2474218822Sdim    fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle);
247599461Sobrien
247638889Sjdp  if ((dialog->class.named && dialog->class.u.n.length > 0)
247738889Sjdp      || dialog->class.u.id != 0)
247838889Sjdp    {
247938889Sjdp      fprintf (e, "CLASS ");
248099461Sobrien      res_id_print (e, dialog->class, 1);
248138889Sjdp      fprintf (e, "\n");
248238889Sjdp    }
248399461Sobrien
248438889Sjdp  if (dialog->caption != NULL)
248538889Sjdp    {
2486218822Sdim      fprintf (e, "CAPTION ");
2487218822Sdim      unicode_print_quoted (e, dialog->caption, -1);
2488218822Sdim      fprintf (e, "\n");
248938889Sjdp    }
249099461Sobrien
249138889Sjdp  if ((dialog->menu.named && dialog->menu.u.n.length > 0)
249238889Sjdp      || dialog->menu.u.id != 0)
249338889Sjdp    {
249438889Sjdp      fprintf (e, "MENU ");
249538889Sjdp      res_id_print (e, dialog->menu, 0);
249638889Sjdp      fprintf (e, "\n");
249738889Sjdp    }
249899461Sobrien
249938889Sjdp  if (dialog->font != NULL)
250038889Sjdp    {
2501218822Sdim      fprintf (e, "FONT %d, ", (int) dialog->pointsize);
2502218822Sdim      unicode_print_quoted (e, dialog->font, -1);
250338889Sjdp      if (dialog->ex != NULL
250499461Sobrien	  && (dialog->ex->weight != 0
250599461Sobrien	      || dialog->ex->italic != 0
250699461Sobrien	      || dialog->ex->charset != 1))
250799461Sobrien	fprintf (e, ", %d, %d, %d",
2508218822Sdim		 (int) dialog->ex->weight,
2509218822Sdim		 (int) dialog->ex->italic,
2510218822Sdim		 (int) dialog->ex->charset);
251138889Sjdp      fprintf (e, "\n");
251238889Sjdp    }
251338889Sjdp
251438889Sjdp  fprintf (e, "BEGIN\n");
251538889Sjdp
251638889Sjdp  for (control = dialog->controls; control != NULL; control = control->next)
251738889Sjdp    write_rc_dialog_control (e, control);
251838889Sjdp
251938889Sjdp  fprintf (e, "END\n");
252038889Sjdp}
252138889Sjdp
252238889Sjdp/* For each predefined control keyword, this table provides the class
252338889Sjdp   and the style.  */
252438889Sjdp
252538889Sjdpstruct control_info
252638889Sjdp{
252738889Sjdp  const char *name;
252838889Sjdp  unsigned short class;
252938889Sjdp  unsigned long style;
253038889Sjdp};
253138889Sjdp
253238889Sjdpstatic const struct control_info control_info[] =
253338889Sjdp{
253438889Sjdp  { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
253538889Sjdp  { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
253638889Sjdp  { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
253738889Sjdp  { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
253838889Sjdp  { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
253938889Sjdp  { "CTEXT", CTL_STATIC, SS_CENTER },
254038889Sjdp  { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
254138889Sjdp  { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
254238889Sjdp  { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
254338889Sjdp  { "ICON", CTL_STATIC, SS_ICON },
254438889Sjdp  { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
254538889Sjdp  { "LTEXT", CTL_STATIC, SS_LEFT },
254638889Sjdp  { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
254738889Sjdp  { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
254838889Sjdp  { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
254938889Sjdp  { "RTEXT", CTL_STATIC, SS_RIGHT },
255038889Sjdp  { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
255138889Sjdp  { "STATE3", CTL_BUTTON, BS_3STATE },
255238889Sjdp  /* It's important that USERBUTTON come after all the other button
255338889Sjdp     types, so that it won't be matched too early.  */
255438889Sjdp  { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
255538889Sjdp  { NULL, 0, 0 }
255638889Sjdp};
255738889Sjdp
255838889Sjdp/* Write a dialog control.  */
255938889Sjdp
256038889Sjdpstatic void
2561218822Sdimwrite_rc_dialog_control (FILE *e, const rc_dialog_control *control)
256238889Sjdp{
256338889Sjdp  const struct control_info *ci;
256438889Sjdp
256538889Sjdp  fprintf (e, "  ");
256638889Sjdp
256738889Sjdp  if (control->class.named)
256838889Sjdp    ci = NULL;
256938889Sjdp  else
257038889Sjdp    {
257138889Sjdp      for (ci = control_info; ci->name != NULL; ++ci)
257238889Sjdp	if (ci->class == control->class.u.id
257338889Sjdp	    && (ci->style == (unsigned long) -1
257438889Sjdp		|| ci->style == (control->style & 0xff)))
257538889Sjdp	  break;
257638889Sjdp    }
257760484Sobrien  if (ci == NULL)
257860484Sobrien    fprintf (e, "CONTROL");
257960484Sobrien  else if (ci->name != NULL)
258038889Sjdp    fprintf (e, "%s", ci->name);
258138889Sjdp  else
2582218822Sdim    {
258338889Sjdp    fprintf (e, "CONTROL");
2584218822Sdim      ci = NULL;
2585218822Sdim    }
2586104834Sobrien
258738889Sjdp  if (control->text.named || control->text.u.id != 0)
258838889Sjdp    {
258938889Sjdp      fprintf (e, " ");
259038889Sjdp      res_id_print (e, control->text, 1);
259138889Sjdp      fprintf (e, ",");
259238889Sjdp    }
259338889Sjdp
2594218822Sdim  fprintf (e, " %d, ", (int) control->id);
259538889Sjdp
259660484Sobrien  if (ci == NULL)
259738889Sjdp    {
259860484Sobrien      if (control->class.named)
259960484Sobrien	fprintf (e, "\"");
260038889Sjdp      res_id_print (e, control->class, 0);
260160484Sobrien      if (control->class.named)
260260484Sobrien	fprintf (e, "\"");
2603218822Sdim      fprintf (e, ", 0x%x, ", (unsigned int) control->style);
260438889Sjdp    }
260538889Sjdp
2606218822Sdim  fprintf (e, "%d, %d", (int) control->x, (int) control->y);
260738889Sjdp
260838889Sjdp  if (control->style != SS_ICON
260938889Sjdp      || control->exstyle != 0
261038889Sjdp      || control->width != 0
261138889Sjdp      || control->height != 0
261238889Sjdp      || control->help != 0)
261338889Sjdp    {
2614218822Sdim      fprintf (e, ", %d, %d", (int) control->width, (int) control->height);
261538889Sjdp
261638889Sjdp      /* FIXME: We don't need to print the style if it is the default.
261738889Sjdp	 More importantly, in certain cases we actually need to turn
261838889Sjdp	 off parts of the forced style, by using NOT.  */
2619218822Sdim      if (ci != NULL)
2620218822Sdim	fprintf (e, ", 0x%x", (unsigned int) control->style);
262138889Sjdp
262238889Sjdp      if (control->exstyle != 0 || control->help != 0)
2623218822Sdim	fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle,
2624218822Sdim		 (unsigned int) control->help);
262538889Sjdp    }
262638889Sjdp
262738889Sjdp  fprintf (e, "\n");
262838889Sjdp
262938889Sjdp  if (control->data != NULL)
263038889Sjdp    write_rc_rcdata (e, control->data, 2);
263138889Sjdp}
263238889Sjdp
263338889Sjdp/* Write out font directory data.  This would normally be built from
263438889Sjdp   the font data.  */
263538889Sjdp
263638889Sjdpstatic void
2637218822Sdimwrite_rc_fontdir (FILE *e, const rc_fontdir *fontdir)
263838889Sjdp{
2639218822Sdim  const rc_fontdir *fc;
2640218822Sdim  int c;
264138889Sjdp
2642218822Sdim  for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++)
2643218822Sdim    ;
2644218822Sdim  fprintf (e, "BEGIN\n");
2645218822Sdim  indent (e, 2);
2646218822Sdim  fprintf (e, "%d%s\t /* Has %d elements.  */\n", c, (c != 0 ? "," : ""), c);
2647218822Sdim  for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++)
264838889Sjdp    {
2649218822Sdim      indent (e, 4);
2650218822Sdim      fprintf (e, "%d,\t/* Font no %d with index %d.  */\n",
2651218822Sdim	(int) fc->index, c, (int) fc->index);
2652218822Sdim      write_rc_datablock (e, (rc_uint_type) fc->length - 2,
2653218822Sdim			  (const bfd_byte *) fc->data + 4,fc->next != NULL,
2654218822Sdim			  0, 0);
265538889Sjdp    }
2656218822Sdim  fprintf (e, "END\n");
265738889Sjdp}
265838889Sjdp
265938889Sjdp/* Write out group icon data.  This would normally be built from the
266038889Sjdp   icon data.  */
266138889Sjdp
266238889Sjdpstatic void
2663218822Sdimwrite_rc_group_icon (FILE *e, const rc_group_icon *group_icon)
266438889Sjdp{
2665218822Sdim  const rc_group_icon *gi;
2666218822Sdim  int c;
266738889Sjdp
2668218822Sdim  for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++)
2669218822Sdim    ;
2670218822Sdim
2671218822Sdim  fprintf (e, "BEGIN\n");
2672218822Sdim  indent (e, 2);
2673218822Sdim  fprintf (e, " 0, 1, %d%s\t /* Has %d elements.  */\n", c, (c != 0 ? "," : ""), c);
2674218822Sdim
2675218822Sdim  indent (e, 4);
2676218822Sdim  fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index.  */\n");
2677218822Sdim  for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++)
267838889Sjdp    {
2679218822Sdim      indent (e, 4);
2680218822Sdim      fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d.  */\n",
2681218822Sdim	gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits,
2682218822Sdim	(unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c);
268338889Sjdp    }
2684218822Sdim  fprintf (e, "END\n");
268538889Sjdp}
268638889Sjdp
268738889Sjdp/* Write out a menu resource.  */
268838889Sjdp
268938889Sjdpstatic void
2690218822Sdimwrite_rc_menu (FILE *e, const rc_menu *menu, int menuex)
269138889Sjdp{
269238889Sjdp  if (menu->help != 0)
2693218822Sdim    fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help);
269438889Sjdp  write_rc_menuitems (e, menu->items, menuex, 0);
269538889Sjdp}
269638889Sjdp
2697218822Sdimstatic void
2698218822Sdimwrite_rc_toolbar (FILE *e, const rc_toolbar *tb)
2699218822Sdim{
2700218822Sdim  rc_toolbar_item *it;
2701218822Sdim  indent (e, 0);
2702218822Sdim  fprintf (e, "BEGIN\n");
2703218822Sdim  it = tb->items;
2704218822Sdim  while(it != NULL)
2705218822Sdim  {
2706218822Sdim    indent (e, 2);
2707218822Sdim    if (it->id.u.id == 0)
2708218822Sdim      fprintf (e, "SEPARATOR\n");
2709218822Sdim    else
2710218822Sdim      fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
2711218822Sdim    it = it->next;
2712218822Sdim  }
2713218822Sdim  indent (e, 0);
2714218822Sdim  fprintf (e, "END\n");
2715218822Sdim}
2716218822Sdim
271738889Sjdp/* Write out menuitems.  */
271838889Sjdp
271938889Sjdpstatic void
2720218822Sdimwrite_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex,
2721130561Sobrien		    int ind)
272238889Sjdp{
2723218822Sdim  const rc_menuitem *mi;
272438889Sjdp
272538889Sjdp  indent (e, ind);
272638889Sjdp  fprintf (e, "BEGIN\n");
272738889Sjdp
272838889Sjdp  for (mi = menuitems; mi != NULL; mi = mi->next)
272938889Sjdp    {
273038889Sjdp      indent (e, ind + 2);
273138889Sjdp
273238889Sjdp      if (mi->popup == NULL)
273338889Sjdp	fprintf (e, "MENUITEM");
273438889Sjdp      else
273538889Sjdp	fprintf (e, "POPUP");
273638889Sjdp
273738889Sjdp      if (! menuex
273838889Sjdp	  && mi->popup == NULL
273938889Sjdp	  && mi->text == NULL
274038889Sjdp	  && mi->type == 0
274138889Sjdp	  && mi->id == 0)
274238889Sjdp	{
274338889Sjdp	  fprintf (e, " SEPARATOR\n");
274438889Sjdp	  continue;
274538889Sjdp	}
274638889Sjdp
274738889Sjdp      if (mi->text == NULL)
274838889Sjdp	fprintf (e, " \"\"");
274938889Sjdp      else
275038889Sjdp	{
2751218822Sdim	  fprintf (e, " ");
2752218822Sdim	  unicode_print_quoted (e, mi->text, -1);
275338889Sjdp	}
275438889Sjdp
275538889Sjdp      if (! menuex)
275638889Sjdp	{
275738889Sjdp	  if (mi->popup == NULL)
2758218822Sdim	    fprintf (e, ", %d", (int) mi->id);
275938889Sjdp
276038889Sjdp	  if ((mi->type & MENUITEM_CHECKED) != 0)
276138889Sjdp	    fprintf (e, ", CHECKED");
276238889Sjdp	  if ((mi->type & MENUITEM_GRAYED) != 0)
276338889Sjdp	    fprintf (e, ", GRAYED");
276438889Sjdp	  if ((mi->type & MENUITEM_HELP) != 0)
276538889Sjdp	    fprintf (e, ", HELP");
276638889Sjdp	  if ((mi->type & MENUITEM_INACTIVE) != 0)
276738889Sjdp	    fprintf (e, ", INACTIVE");
276838889Sjdp	  if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
276938889Sjdp	    fprintf (e, ", MENUBARBREAK");
277038889Sjdp	  if ((mi->type & MENUITEM_MENUBREAK) != 0)
277138889Sjdp	    fprintf (e, ", MENUBREAK");
277238889Sjdp	}
277338889Sjdp      else
277438889Sjdp	{
277538889Sjdp	  if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
277638889Sjdp	    {
2777218822Sdim	      fprintf (e, ", %d", (int) mi->id);
277838889Sjdp	      if (mi->type != 0 || mi->state != 0 || mi->help != 0)
277938889Sjdp		{
2780218822Sdim		  fprintf (e, ", %u", (unsigned int) mi->type);
278138889Sjdp		  if (mi->state != 0 || mi->help != 0)
278238889Sjdp		    {
2783218822Sdim		      fprintf (e, ", %u", (unsigned int) mi->state);
278438889Sjdp		      if (mi->help != 0)
2785218822Sdim			fprintf (e, ", %u", (unsigned int) mi->help);
278638889Sjdp		    }
278738889Sjdp		}
278838889Sjdp	    }
278938889Sjdp	}
279038889Sjdp
279138889Sjdp      fprintf (e, "\n");
279238889Sjdp
279338889Sjdp      if (mi->popup != NULL)
279438889Sjdp	write_rc_menuitems (e, mi->popup, menuex, ind + 2);
279538889Sjdp    }
279638889Sjdp
279738889Sjdp  indent (e, ind);
279838889Sjdp  fprintf (e, "END\n");
279938889Sjdp}
280038889Sjdp
2801218822Sdimstatic int
2802218822Sdimtest_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
2803218822Sdim{
2804218822Sdim  rc_uint_type i;
2805218822Sdim  if ((length & 1) != 0)
2806218822Sdim    return 0;
280738889Sjdp
2808218822Sdim  for (i = 0; i < length; i += 2)
2809218822Sdim    {
2810218822Sdim      if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2811218822Sdim	return 0;
2812218822Sdim      if (data[i] == 0xff && data[i + 1] == 0xff)
2813218822Sdim	return 0;
2814218822Sdim    }
2815218822Sdim  return 1;
2816218822Sdim}
2817218822Sdim
2818218822Sdimstatic int
2819218822Sdimtest_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2820218822Sdim{
2821218822Sdim  int has_nl;
2822218822Sdim  rc_uint_type c;
2823218822Sdim  rc_uint_type i;
2824218822Sdim
2825218822Sdim  if (length <= 1)
2826218822Sdim    return 0;
2827218822Sdim
2828218822Sdim  has_nl = 0;
2829218822Sdim  for (i = 0, c = 0; i < length; i++)
2830218822Sdim    {
2831218822Sdim      if (! ISPRINT (data[i]) && data[i] != '\n'
2832218822Sdim      	  && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2833218822Sdim      	  && data[i] != '\t'
2834218822Sdim	  && ! (data[i] == 0 && (i + 1) != length))
2835218822Sdim	{
2836218822Sdim	  if (data[i] <= 7)
2837218822Sdim	    return 0;
2838218822Sdim	  c++;
2839218822Sdim	}
2840218822Sdim      else if (data[i] == '\n') has_nl++;
2841218822Sdim    }
2842218822Sdim  if (length > 80 && ! has_nl)
2843218822Sdim    return 0;
2844218822Sdim  c = (((c * 10000) + (i / 100) - 1)) / i;
2845218822Sdim  if (c >= 150)
2846218822Sdim    return 0;
2847218822Sdim  return 1;
2848218822Sdim}
2849218822Sdim
285038889Sjdpstatic void
2851218822Sdimwrite_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
285238889Sjdp{
2853218822Sdim  int has_error = 0;
2854218822Sdim  const struct bin_messagetable *mt;
285538889Sjdp  fprintf (e, "BEGIN\n");
285638889Sjdp
2857218822Sdim  write_rc_datablock (e, length, data, 0, 0, 0);
285838889Sjdp
2859218822Sdim  fprintf (e, "\n");
2860218822Sdim  wr_printcomment (e, "MC syntax dump");
2861218822Sdim  if (length < BIN_MESSAGETABLE_SIZE)
2862218822Sdim    has_error = 1;
2863218822Sdim  else
2864218822Sdim    do {
2865218822Sdim      rc_uint_type m, i;
2866218822Sdim      mt = (const struct bin_messagetable *) data;
2867218822Sdim      m = windres_get_32 (&wrtarget, mt->cblocks, length);
2868218822Sdim      if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
286938889Sjdp	{
2870218822Sdim	  has_error = 1;
287138889Sjdp	  break;
2872218822Sdim	}
2873218822Sdim      for (i = 0; i < m; i++)
2874218822Sdim	{
2875218822Sdim	  rc_uint_type low, high, offset;
2876218822Sdim	  const struct bin_messagetable_item *mti;
287738889Sjdp
2878218822Sdim	  low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2879218822Sdim	  high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2880218822Sdim	  offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2881218822Sdim	  while (low <= high)
2882218822Sdim	    {
2883218822Sdim	      rc_uint_type elen, flags;
2884218822Sdim	      if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2885218822Sdim		{
2886218822Sdim		  has_error = 1;
288738889Sjdp	  break;
2888218822Sdim		}
2889218822Sdim	      mti = (const struct bin_messagetable_item *) &data[offset];
2890218822Sdim	      elen = windres_get_16 (&wrtarget, mti->length, 2);
2891218822Sdim	      flags = windres_get_16 (&wrtarget, mti->flags, 2);
2892218822Sdim	      if ((offset + elen) > length)
2893218822Sdim		{
2894218822Sdim		  has_error = 1;
2895218822Sdim		  break;
2896218822Sdim		}
2897218822Sdim	      wr_printcomment (e, "MessageId = 0x%x", low);
2898218822Sdim	      wr_printcomment (e, "");
2899218822Sdim	      if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2900218822Sdim		unicode_print (e, (const unichar *) mti->data,
2901218822Sdim			       (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2902218822Sdim	      else
2903218822Sdim		ascii_print (e, (const char *) mti->data,
2904218822Sdim			     (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2905218822Sdim	      wr_printcomment (e,"");
2906218822Sdim	      ++low;
2907218822Sdim	      offset += elen;
2908218822Sdim	    }
2909218822Sdim	}
2910218822Sdim    } while (0);
2911218822Sdim  if (has_error)
2912218822Sdim    wr_printcomment (e, "Illegal data");
2913218822Sdim  wr_print_flush (e);
2914218822Sdim  fprintf (e, "END\n");
2915218822Sdim}
291638889Sjdp
2917218822Sdimstatic void
2918218822Sdimwrite_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
2919218822Sdim		    int hasblock, int show_comment)
2920218822Sdim{
2921218822Sdim  int plen;
2922218822Sdim
2923218822Sdim  if (hasblock)
2924218822Sdim    fprintf (e, "BEGIN\n");
2925218822Sdim
2926218822Sdim  if (show_comment == -1)
292738889Sjdp	  {
2928218822Sdim      if (test_rc_datablock_text(length, data))
2929218822Sdim	{
2930218822Sdim	  rc_uint_type i, c;
2931218822Sdim	  for (i = 0; i < length;)
2932218822Sdim	    {
2933218822Sdim	      indent (e, 2);
2934218822Sdim	      fprintf (e, "\"");
293538889Sjdp
2936218822Sdim	      for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
2937218822Sdim		;
2938218822Sdim	      if (i < length && data[i] == '\n')
2939218822Sdim		++i, ++c;
2940218822Sdim	      ascii_print (e, (const char *) &data[i - c], c);
294138889Sjdp	    fprintf (e, "\"");
2942218822Sdim	      if (i < length)
2943218822Sdim		fprintf (e, "\n");
2944218822Sdim	    }
2945218822Sdim
2946218822Sdim	  if (i == 0)
294738889Sjdp	      {
2948218822Sdim	      indent (e, 2);
2949218822Sdim	      fprintf (e, "\"\"");
295038889Sjdp	      }
2951218822Sdim	  if (has_next)
2952218822Sdim	    fprintf (e, ",");
2953218822Sdim	  fprintf (e, "\n");
2954218822Sdim	  if (hasblock)
2955218822Sdim	    fprintf (e, "END\n");
2956218822Sdim	  return;
295738889Sjdp	  }
2958218822Sdim      if (test_rc_datablock_unicode (length, data))
2959218822Sdim	{
2960218822Sdim	  rc_uint_type i, c;
2961218822Sdim	  for (i = 0; i < length;)
2962218822Sdim	    {
2963218822Sdim	      const unichar *u;
296438889Sjdp
2965218822Sdim	      u = (const unichar *) &data[i];
2966218822Sdim	      indent (e, 2);
296738889Sjdp	  fprintf (e, "L\"");
2968218822Sdim
2969218822Sdim	      for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
2970218822Sdim		;
2971218822Sdim	      if (i < length && u[c] == '\n')
2972218822Sdim		i += 2, ++c;
2973218822Sdim	      unicode_print (e, u, c);
297438889Sjdp	  fprintf (e, "\"");
2975218822Sdim	      if (i < length)
2976218822Sdim		fprintf (e, "\n");
2977218822Sdim	    }
297838889Sjdp
2979218822Sdim	  if (i == 0)
298038889Sjdp	  {
2981218822Sdim	      indent (e, 2);
2982218822Sdim	      fprintf (e, "L\"\"");
2983218822Sdim	    }
2984218822Sdim	  if (has_next)
2985218822Sdim	    fprintf (e, ",");
2986218822Sdim	  fprintf (e, "\n");
2987218822Sdim	  if (hasblock)
2988218822Sdim	    fprintf (e, "END\n");
2989218822Sdim	  return;
2990218822Sdim	}
299138889Sjdp
2992218822Sdim      show_comment = 0;
2993218822Sdim    }
299438889Sjdp
2995218822Sdim  if (length != 0)
299638889Sjdp	      {
2997218822Sdim      rc_uint_type i, max_row;
2998218822Sdim      int first = 1;
299938889Sjdp
3000218822Sdim      max_row = (show_comment ? 4 : 8);
3001218822Sdim      indent (e, 2);
3002218822Sdim      for (i = 0; i + 3 < length;)
300338889Sjdp		  {
3004218822Sdim	  rc_uint_type k;
3005218822Sdim	  rc_uint_type comment_start;
3006218822Sdim
3007218822Sdim	  comment_start = i;
3008218822Sdim
3009218822Sdim	  if (! first)
3010218822Sdim	    indent (e, 2);
3011218822Sdim
3012218822Sdim	  for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
301360484Sobrien		      {
3014218822Sdim	      if (k == 0)
3015218822Sdim		plen  = fprintf (e, "0x%lxL",
3016218822Sdim				 (long) windres_get_32 (&wrtarget, data + i, length - i));
301760484Sobrien			else
3018218822Sdim		plen = fprintf (e, " 0x%lxL",
3019218822Sdim				(long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
3020218822Sdim	      if (has_next || (i + 4) < length)
302160484Sobrien			  {
3022218822Sdim		  if (plen>0 && plen < 11)
3023218822Sdim		    indent (e, 11 - plen);
3024218822Sdim		  fprintf (e, ",");
302560484Sobrien			  }
302660484Sobrien		      }
3027218822Sdim	  if (show_comment)
3028218822Sdim	    {
3029218822Sdim	      fprintf (e, "\t/* ");
3030218822Sdim	      ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3031218822Sdim	      fprintf (e, ".  */");
303238889Sjdp		  }
303360484Sobrien		fprintf (e, "\n");
303460484Sobrien		first = 0;
303538889Sjdp	      }
303638889Sjdp
3037218822Sdim      if (i + 1 < length)
303838889Sjdp	      {
303960484Sobrien		if (! first)
3040218822Sdim	    indent (e, 2);
3041218822Sdim	  plen = fprintf (e, "0x%x",
3042218822Sdim	  		  (int) windres_get_16 (&wrtarget, data + i, length - i));
3043218822Sdim	  if (has_next || i + 2 < length)
304438889Sjdp		  {
3045218822Sdim	      if (plen > 0 && plen < 11)
3046218822Sdim		indent (e, 11 - plen);
3047218822Sdim	      fprintf (e, ",");
304860484Sobrien		      }
3049218822Sdim	  if (show_comment)
3050218822Sdim	    {
3051218822Sdim	      fprintf (e, "\t/* ");
3052218822Sdim	      ascii_print (e, (const char *) &data[i], 2);
3053218822Sdim	      fprintf (e, ".  */");
305438889Sjdp		  }
305560484Sobrien		fprintf (e, "\n");
305638889Sjdp		i += 2;
305760484Sobrien		first = 0;
305838889Sjdp	      }
305938889Sjdp
3060218822Sdim      if (i < length)
306138889Sjdp	      {
306260484Sobrien		if (! first)
3063218822Sdim	    indent (e, 2);
3064218822Sdim	  fprintf (e, "\"");
3065218822Sdim	  ascii_print (e, (const char *) &data[i], 1);
3066218822Sdim	  fprintf (e, "\"");
3067218822Sdim	  if (has_next)
306860484Sobrien		  fprintf (e, ",");
306960484Sobrien		fprintf (e, "\n");
307060484Sobrien		first = 0;
307138889Sjdp	      }
3072218822Sdim    }
3073218822Sdim  if (hasblock)
3074218822Sdim    fprintf (e, "END\n");
3075218822Sdim}
307638889Sjdp
3077218822Sdim/* Write out an rcdata resource.  This is also used for other types of
3078218822Sdim   resources that need to print arbitrary data.  */
3079218822Sdim
3080218822Sdimstatic void
3081218822Sdimwrite_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3082218822Sdim{
3083218822Sdim  const rc_rcdata_item *ri;
3084218822Sdim
3085218822Sdim  indent (e, ind);
3086218822Sdim  fprintf (e, "BEGIN\n");
3087218822Sdim
3088218822Sdim  for (ri = rcdata; ri != NULL; ri = ri->next)
3089218822Sdim    {
3090218822Sdim      if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3091218822Sdim	continue;
3092218822Sdim
3093218822Sdim      switch (ri->type)
3094218822Sdim	{
3095218822Sdim	default:
3096218822Sdim	  abort ();
3097218822Sdim
3098218822Sdim	case RCDATA_WORD:
3099218822Sdim	  indent (e, ind + 2);
3100218822Sdim	  fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3101218822Sdim	  break;
3102218822Sdim
3103218822Sdim	case RCDATA_DWORD:
3104218822Sdim	  indent (e, ind + 2);
3105218822Sdim	  fprintf (e, "%luL", (unsigned long) ri->u.dword);
3106218822Sdim	  break;
3107218822Sdim
3108218822Sdim	case RCDATA_STRING:
3109218822Sdim	  indent (e, ind + 2);
3110218822Sdim	  fprintf (e, "\"");
3111218822Sdim	  ascii_print (e, ri->u.string.s, ri->u.string.length);
3112218822Sdim	  fprintf (e, "\"");
3113218822Sdim	  break;
3114218822Sdim
3115218822Sdim	case RCDATA_WSTRING:
3116218822Sdim	  indent (e, ind + 2);
3117218822Sdim	  fprintf (e, "L\"");
3118218822Sdim	  unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3119218822Sdim	  fprintf (e, "\"");
3120218822Sdim	  break;
3121218822Sdim
3122218822Sdim	case RCDATA_BUFFER:
3123218822Sdim	  write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3124218822Sdim	  		      (const bfd_byte *) ri->u.buffer.data,
3125218822Sdim	    		      ri->next != NULL, 0, -1);
312638889Sjdp	    break;
312738889Sjdp	}
312838889Sjdp
312960484Sobrien      if (ri->type != RCDATA_BUFFER)
313060484Sobrien	{
313160484Sobrien	  if (ri->next != NULL)
313260484Sobrien	    fprintf (e, ",");
313360484Sobrien	  fprintf (e, "\n");
313460484Sobrien	}
313538889Sjdp    }
313638889Sjdp
313738889Sjdp  indent (e, ind);
313838889Sjdp  fprintf (e, "END\n");
313938889Sjdp}
314038889Sjdp
314138889Sjdp/* Write out a stringtable resource.  */
314238889Sjdp
314338889Sjdpstatic void
3144218822Sdimwrite_rc_stringtable (FILE *e, const rc_res_id *name,
3145218822Sdim		      const rc_stringtable *stringtable)
314638889Sjdp{
3147218822Sdim  rc_uint_type offset;
314838889Sjdp  int i;
314938889Sjdp
315038889Sjdp  if (name != NULL && ! name->named)
315138889Sjdp    offset = (name->u.id - 1) << 4;
315238889Sjdp  else
315338889Sjdp    {
3154218822Sdim      fprintf (e, "/* %s string table name.  */\n",
315538889Sjdp	       name == NULL ? "Missing" : "Invalid");
315638889Sjdp      offset = 0;
315738889Sjdp    }
315838889Sjdp
315938889Sjdp  fprintf (e, "BEGIN\n");
316038889Sjdp
316138889Sjdp  for (i = 0; i < 16; i++)
316238889Sjdp    {
316338889Sjdp      if (stringtable->strings[i].length != 0)
316438889Sjdp	{
3165218822Sdim	  fprintf (e, "  %lu, ", (long) offset + i);
3166218822Sdim	  unicode_print_quoted (e, stringtable->strings[i].string,
316738889Sjdp			 stringtable->strings[i].length);
3168218822Sdim	  fprintf (e, "\n");
316938889Sjdp	}
317038889Sjdp    }
317138889Sjdp
317238889Sjdp  fprintf (e, "END\n");
317338889Sjdp}
317438889Sjdp
317538889Sjdp/* Write out a versioninfo resource.  */
317638889Sjdp
317738889Sjdpstatic void
3178218822Sdimwrite_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
317938889Sjdp{
3180218822Sdim  const rc_fixed_versioninfo *f;
3181218822Sdim  const rc_ver_info *vi;
318238889Sjdp
318338889Sjdp  f = versioninfo->fixed;
318438889Sjdp  if (f->file_version_ms != 0 || f->file_version_ls != 0)
3185218822Sdim    fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3186218822Sdim	     (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3187218822Sdim	     (unsigned int) (f->file_version_ms & 0xffff),
3188218822Sdim	     (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3189218822Sdim	     (unsigned int) (f->file_version_ls & 0xffff));
319038889Sjdp  if (f->product_version_ms != 0 || f->product_version_ls != 0)
3191218822Sdim    fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3192218822Sdim	     (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3193218822Sdim	     (unsigned int) (f->product_version_ms & 0xffff),
3194218822Sdim	     (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3195218822Sdim	     (unsigned int) (f->product_version_ls & 0xffff));
319638889Sjdp  if (f->file_flags_mask != 0)
3197218822Sdim    fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
319838889Sjdp  if (f->file_flags != 0)
3199218822Sdim    fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
320038889Sjdp  if (f->file_os != 0)
3201218822Sdim    fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
320238889Sjdp  if (f->file_type != 0)
3203218822Sdim    fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
320438889Sjdp  if (f->file_subtype != 0)
3205218822Sdim    fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
320638889Sjdp  if (f->file_date_ms != 0 || f->file_date_ls != 0)
3207218822Sdim    fprintf (e, "/* Date: %u, %u.  */\n",
3208218822Sdim    	     (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
320938889Sjdp
321038889Sjdp  fprintf (e, "BEGIN\n");
321138889Sjdp
321238889Sjdp  for (vi = versioninfo->var; vi != NULL; vi = vi->next)
321338889Sjdp    {
321438889Sjdp      switch (vi->type)
321538889Sjdp	{
321638889Sjdp	case VERINFO_STRING:
321738889Sjdp	  {
3218218822Sdim	    const rc_ver_stringinfo *vs;
321938889Sjdp
322038889Sjdp	    fprintf (e, "  BLOCK \"StringFileInfo\"\n");
322138889Sjdp	    fprintf (e, "  BEGIN\n");
3222218822Sdim	    fprintf (e, "    BLOCK ");
3223218822Sdim	    unicode_print_quoted (e, vi->u.string.language, -1);
3224218822Sdim	    fprintf (e, "\n");
322538889Sjdp	    fprintf (e, "    BEGIN\n");
322638889Sjdp
322738889Sjdp	    for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
322838889Sjdp	      {
3229218822Sdim		fprintf (e, "      VALUE ");
3230218822Sdim		unicode_print_quoted (e, vs->key, -1);
3231218822Sdim		fprintf (e, ", ");
3232218822Sdim		unicode_print_quoted (e, vs->value, -1);
3233218822Sdim		fprintf (e, "\n");
323438889Sjdp	      }
323538889Sjdp
323638889Sjdp	    fprintf (e, "    END\n");
323738889Sjdp	    fprintf (e, "  END\n");
323838889Sjdp	    break;
323938889Sjdp	  }
324038889Sjdp
324138889Sjdp	case VERINFO_VAR:
324238889Sjdp	  {
3243218822Sdim	    const rc_ver_varinfo *vv;
324438889Sjdp
324538889Sjdp	    fprintf (e, "  BLOCK \"VarFileInfo\"\n");
324638889Sjdp	    fprintf (e, "  BEGIN\n");
3247218822Sdim	    fprintf (e, "    VALUE ");
3248218822Sdim	    unicode_print_quoted (e, vi->u.var.key, -1);
324938889Sjdp
325038889Sjdp	    for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
325138889Sjdp	      fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3252218822Sdim		       (int) vv->charset);
325338889Sjdp
325438889Sjdp	    fprintf (e, "\n  END\n");
325538889Sjdp
325638889Sjdp	    break;
325738889Sjdp	  }
325838889Sjdp	}
325938889Sjdp    }
326038889Sjdp
326138889Sjdp  fprintf (e, "END\n");
326238889Sjdp}
326338889Sjdp
3264218822Sdimstatic rc_uint_type
3265218822Sdimrcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
326638889Sjdp{
3267218822Sdim  if (! src)
3268218822Sdim    return 0;
3269218822Sdim  switch (src->type)
327038889Sjdp	{
3271218822Sdim    case RCDATA_WORD:
3272218822Sdim      if (dst)
3273218822Sdim	windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3274218822Sdim      return 2;
3275218822Sdim    case RCDATA_DWORD:
3276218822Sdim      if (dst)
3277218822Sdim	windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3278218822Sdim      return 4;
3279218822Sdim    case RCDATA_STRING:
3280218822Sdim      if (dst && src->u.string.length)
3281218822Sdim	memcpy (dst, src->u.string.s, src->u.string.length);
3282218822Sdim      return (rc_uint_type) src->u.string.length;
3283218822Sdim    case RCDATA_WSTRING:
3284218822Sdim      if (dst && src->u.wstring.length)
3285218822Sdim	memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3286218822Sdim      return (rc_uint_type) (src->u.wstring.length  * sizeof (unichar));
3287218822Sdim    case RCDATA_BUFFER:
3288218822Sdim      if (dst && src->u.buffer.length)
3289218822Sdim	memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3290218822Sdim      return (rc_uint_type) src->u.buffer.length;
3291218822Sdim    default:
3292218822Sdim      abort ();
329338889Sjdp    }
3294218822Sdim  /* Never reached.  */
3295218822Sdim  return 0;
329638889Sjdp}
3297