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