Back to index

cell-binutils  2.17cvs20070401
resrc.c
Go to the documentation of this file.
00001 /* resrc.c -- read and write Windows rc files.
00002    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005
00003    Free Software Foundation, Inc.
00004    Written by Ian Lance Taylor, Cygnus Support.
00005 
00006    This file is part of GNU Binutils.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012 
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017 
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
00021    02110-1301, USA.  */
00022 
00023 /* This file contains functions that read and write Windows rc files.
00024    These are text files that represent resources.  */
00025 
00026 #include "bfd.h"
00027 #include "bucomm.h"
00028 #include "libiberty.h"
00029 #include "safe-ctype.h"
00030 #include "windres.h"
00031 
00032 #include <assert.h>
00033 #include <errno.h>
00034 #include <sys/stat.h>
00035 #ifdef HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif
00038 
00039 #ifdef HAVE_SYS_WAIT_H
00040 #include <sys/wait.h>
00041 #else /* ! HAVE_SYS_WAIT_H */
00042 #if ! defined (_WIN32) || defined (__CYGWIN__)
00043 #ifndef WIFEXITED
00044 #define WIFEXITED(w) (((w)&0377) == 0)
00045 #endif
00046 #ifndef WIFSIGNALED
00047 #define WIFSIGNALED(w)      (((w)&0377) != 0177 && ((w)&~0377) == 0)
00048 #endif
00049 #ifndef WTERMSIG
00050 #define WTERMSIG(w)  ((w) & 0177)
00051 #endif
00052 #ifndef WEXITSTATUS
00053 #define WEXITSTATUS(w)      (((w) >> 8) & 0377)
00054 #endif
00055 #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
00056 #ifndef WIFEXITED
00057 #define WIFEXITED(w) (((w) & 0xff) == 0)
00058 #endif
00059 #ifndef WIFSIGNALED
00060 #define WIFSIGNALED(w)      (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
00061 #endif
00062 #ifndef WTERMSIG
00063 #define WTERMSIG(w)  ((w) & 0x7f)
00064 #endif
00065 #ifndef WEXITSTATUS
00066 #define WEXITSTATUS(w)      (((w) & 0xff00) >> 8)
00067 #endif
00068 #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
00069 #endif /* ! HAVE_SYS_WAIT_H */
00070 
00071 #ifndef STDOUT_FILENO
00072 #define STDOUT_FILENO 1
00073 #endif
00074 
00075 #if defined (_WIN32) && ! defined (__CYGWIN__)
00076 #define popen _popen
00077 #define pclose _pclose
00078 #endif
00079 
00080 /* The default preprocessor.  */
00081 
00082 #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
00083 
00084 /* We read the directory entries in a cursor or icon file into
00085    instances of this structure.  */
00086 
00087 struct icondir
00088 {
00089   /* Width of image.  */
00090   unsigned char width;
00091   /* Height of image.  */
00092   unsigned char height;
00093   /* Number of colors in image.  */
00094   unsigned char colorcount;
00095   union
00096   {
00097     struct
00098     {
00099       /* Color planes.  */
00100       unsigned short planes;
00101       /* Bits per pixel.  */
00102       unsigned short bits;
00103     } icon;
00104     struct
00105     {
00106       /* X coordinate of hotspot.  */
00107       unsigned short xhotspot;
00108       /* Y coordinate of hotspot.  */
00109       unsigned short yhotspot;
00110     } cursor;
00111   } u;
00112   /* Bytes in image.  */
00113   unsigned long bytes;
00114   /* File offset of image.  */
00115   unsigned long offset;
00116 };
00117 
00118 /* The name of the rc file we are reading.  */
00119 
00120 char *rc_filename;
00121 
00122 /* The line number in the rc file.  */
00123 
00124 int rc_lineno;
00125 
00126 /* The pipe we are reading from, so that we can close it if we exit.  */
00127 
00128 static FILE *cpp_pipe;
00129 
00130 /* The temporary file used if we're not using popen, so we can delete it
00131    if we exit.  */
00132 
00133 static char *cpp_temp_file;
00134 
00135 /* Input stream is either a file or a pipe.  */
00136 
00137 static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
00138 
00139 /* As we read the rc file, we attach information to this structure.  */
00140 
00141 static struct res_directory *resources;
00142 
00143 /* The number of cursor resources we have written out.  */
00144 
00145 static int cursors;
00146 
00147 /* The number of font resources we have written out.  */
00148 
00149 static int fonts;
00150 
00151 /* Font directory information.  */
00152 
00153 struct fontdir *fontdirs;
00154 
00155 /* Resource info to use for fontdirs.  */
00156 
00157 struct res_res_info fontdirs_resinfo;
00158 
00159 /* The number of icon resources we have written out.  */
00160 
00161 static int icons;
00162 
00163 /* Local functions.  */
00164 
00165 static int run_cmd (char *, const char *);
00166 static FILE *open_input_stream (char *);
00167 static FILE *look_for_default
00168   (char *, const char *, int, const char *, const char *);
00169 static void close_input_stream (void);
00170 static void unexpected_eof (const char *);
00171 static int get_word (FILE *, const char *);
00172 static unsigned long get_long (FILE *, const char *);
00173 static void get_data (FILE *, unsigned char *, unsigned long, const char *);
00174 static void define_fontdirs (void);
00175 
00176 /* Run `cmd' and redirect the output to `redir'.  */
00177 
00178 static int
00179 run_cmd (char *cmd, const char *redir)
00180 {
00181   char *s;
00182   int pid, wait_status, retcode;
00183   int i;
00184   const char **argv;
00185   char *errmsg_fmt, *errmsg_arg;
00186   char *temp_base = choose_temp_base ();
00187   int in_quote;
00188   char sep;
00189   int redir_handle = -1;
00190   int stdout_save = -1;
00191 
00192   /* Count the args.  */
00193   i = 0;
00194 
00195   for (s = cmd; *s; s++)
00196     if (*s == ' ')
00197       i++;
00198 
00199   i++;
00200   argv = alloca (sizeof (char *) * (i + 3));
00201   i = 0;
00202   s = cmd;
00203 
00204   while (1)
00205     {
00206       while (*s == ' ' && *s != 0)
00207        s++;
00208 
00209       if (*s == 0)
00210        break;
00211 
00212       in_quote = (*s == '\'' || *s == '"');
00213       sep = (in_quote) ? *s++ : ' ';
00214       argv[i++] = s;
00215 
00216       while (*s != sep && *s != 0)
00217        s++;
00218 
00219       if (*s == 0)
00220        break;
00221 
00222       *s++ = 0;
00223 
00224       if (in_quote)
00225        s++;
00226     }
00227   argv[i++] = NULL;
00228 
00229   /* Setup the redirection.  We can't use the usual fork/exec and redirect
00230      since we may be running on non-POSIX Windows host.  */
00231 
00232   fflush (stdout);
00233   fflush (stderr);
00234 
00235   /* Open temporary output file.  */
00236   redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
00237   if (redir_handle == -1)
00238     fatal (_("can't open temporary file `%s': %s"), redir,
00239           strerror (errno));
00240 
00241   /* Duplicate the stdout file handle so it can be restored later.  */
00242   stdout_save = dup (STDOUT_FILENO);
00243   if (stdout_save == -1)
00244     fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
00245 
00246   /* Redirect stdout to our output file.  */
00247   dup2 (redir_handle, STDOUT_FILENO);
00248 
00249   pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
00250                 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
00251 
00252   /* Restore stdout to its previous setting.  */
00253   dup2 (stdout_save, STDOUT_FILENO);
00254 
00255   /* Close response file.  */
00256   close (redir_handle);
00257 
00258   if (pid == -1)
00259     {
00260       fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
00261       return 1;
00262     }
00263 
00264   retcode = 0;
00265   pid = pwait (pid, &wait_status, 0);
00266 
00267   if (pid == -1)
00268     {
00269       fatal (_("wait: %s"), strerror (errno));
00270       retcode = 1;
00271     }
00272   else if (WIFSIGNALED (wait_status))
00273     {
00274       fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
00275       retcode = 1;
00276     }
00277   else if (WIFEXITED (wait_status))
00278     {
00279       if (WEXITSTATUS (wait_status) != 0)
00280        {
00281          fatal (_("%s exited with status %d"), cmd,
00282                 WEXITSTATUS (wait_status));
00283          retcode = 1;
00284        }
00285     }
00286   else
00287     retcode = 1;
00288 
00289   return retcode;
00290 }
00291 
00292 static FILE *
00293 open_input_stream (char *cmd)
00294 {
00295   if (istream_type == ISTREAM_FILE)
00296     {
00297       char *fileprefix;
00298 
00299       fileprefix = choose_temp_base ();
00300       cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
00301       sprintf (cpp_temp_file, "%s.irc", fileprefix);
00302       free (fileprefix);
00303 
00304       if (run_cmd (cmd, cpp_temp_file))
00305        fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
00306 
00307       cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
00308       if (cpp_pipe == NULL)
00309        fatal (_("can't open temporary file `%s': %s"),
00310               cpp_temp_file, strerror (errno));
00311 
00312       if (verbose)
00313        fprintf (stderr,
00314                 _("Using temporary file `%s' to read preprocessor output\n"),
00315                cpp_temp_file);
00316     }
00317   else
00318     {
00319       cpp_pipe = popen (cmd, FOPEN_RT);
00320       if (cpp_pipe == NULL)
00321        fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
00322       if (verbose)
00323        fprintf (stderr, _("Using popen to read preprocessor output\n"));
00324     }
00325 
00326   xatexit (close_input_stream);
00327   return cpp_pipe;
00328 }
00329 
00330 /* look for the preprocessor program */
00331 
00332 static FILE *
00333 look_for_default (char *cmd, const char *prefix, int end_prefix,
00334                 const char *preprocargs, const char *filename)
00335 {
00336   char *space;
00337   int found;
00338   struct stat s;
00339 
00340   strcpy (cmd, prefix);
00341 
00342   sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
00343   space = strchr (cmd + end_prefix, ' ');
00344   if (space)
00345     *space = 0;
00346 
00347   if (
00348 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
00349       strchr (cmd, '\\') ||
00350 #endif
00351       strchr (cmd, '/'))
00352     {
00353       found = (stat (cmd, &s) == 0
00354 #ifdef HAVE_EXECUTABLE_SUFFIX
00355               || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
00356 #endif
00357               );
00358 
00359       if (! found)
00360        {
00361          if (verbose)
00362            fprintf (stderr, _("Tried `%s'\n"), cmd);
00363          return NULL;
00364        }
00365     }
00366 
00367   strcpy (cmd, prefix);
00368 
00369   sprintf (cmd + end_prefix, "%s %s %s",
00370           DEFAULT_PREPROCESSOR, preprocargs, filename);
00371 
00372   if (verbose)
00373     fprintf (stderr, _("Using `%s'\n"), cmd);
00374 
00375   cpp_pipe = open_input_stream (cmd);
00376   return cpp_pipe;
00377 }
00378 
00379 /* Read an rc file.  */
00380 
00381 struct res_directory *
00382 read_rc_file (const char *filename, const char *preprocessor,
00383              const char *preprocargs, int language, int use_temp_file)
00384 {
00385   char *cmd;
00386 
00387   istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
00388 
00389   if (preprocargs == NULL)
00390     preprocargs = "";
00391   if (filename == NULL)
00392     filename = "-";
00393 
00394   if (preprocessor)
00395     {
00396       cmd = xmalloc (strlen (preprocessor)
00397                    + strlen (preprocargs)
00398                    + strlen (filename)
00399                    + 10);
00400       sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
00401 
00402       cpp_pipe = open_input_stream (cmd);
00403     }
00404   else
00405     {
00406       char *dash, *slash, *cp;
00407 
00408       preprocessor = DEFAULT_PREPROCESSOR;
00409 
00410       cmd = xmalloc (strlen (program_name)
00411                    + strlen (preprocessor)
00412                    + strlen (preprocargs)
00413                    + strlen (filename)
00414 #ifdef HAVE_EXECUTABLE_SUFFIX
00415                    + strlen (EXECUTABLE_SUFFIX)
00416 #endif
00417                    + 10);
00418 
00419 
00420       dash = slash = 0;
00421       for (cp = program_name; *cp; cp++)
00422        {
00423          if (*cp == '-')
00424            dash = cp;
00425          if (
00426 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
00427              *cp == ':' || *cp == '\\' ||
00428 #endif
00429              *cp == '/')
00430            {
00431              slash = cp;
00432              dash = 0;
00433            }
00434        }
00435 
00436       cpp_pipe = 0;
00437 
00438       if (dash)
00439        {
00440          /* First, try looking for a prefixed gcc in the windres
00441             directory, with the same prefix as windres */
00442 
00443          cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1,
00444                                    preprocargs, filename);
00445        }
00446 
00447       if (slash && !cpp_pipe)
00448        {
00449          /* Next, try looking for a gcc in the same directory as
00450              that windres */
00451 
00452          cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1,
00453                                    preprocargs, filename);
00454        }
00455 
00456       if (!cpp_pipe)
00457        {
00458          /* Sigh, try the default */
00459 
00460          cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
00461        }
00462 
00463     }
00464 
00465   free (cmd);
00466 
00467   rc_filename = xstrdup (filename);
00468   rc_lineno = 1;
00469   if (language != -1)
00470     rcparse_set_language (language);
00471   yyin = cpp_pipe;
00472   yyparse ();
00473   rcparse_discard_strings ();
00474 
00475   close_input_stream ();
00476 
00477   if (fontdirs != NULL)
00478     define_fontdirs ();
00479 
00480   free (rc_filename);
00481   rc_filename = NULL;
00482 
00483   return resources;
00484 }
00485 
00486 /* Close the input stream if it is open.  */
00487 
00488 static void
00489 close_input_stream (void)
00490 {
00491   if (istream_type == ISTREAM_FILE)
00492     {
00493       if (cpp_pipe != NULL)
00494        fclose (cpp_pipe);
00495 
00496       if (cpp_temp_file != NULL)
00497        {
00498          int errno_save = errno;
00499 
00500          unlink (cpp_temp_file);
00501          errno = errno_save;
00502          free (cpp_temp_file);
00503        }
00504     }
00505   else
00506     {
00507       if (cpp_pipe != NULL)
00508        pclose (cpp_pipe);
00509     }
00510 
00511   /* Since this is also run via xatexit, safeguard.  */
00512   cpp_pipe = NULL;
00513   cpp_temp_file = NULL;
00514 }
00515 
00516 /* Report an error while reading an rc file.  */
00517 
00518 void
00519 yyerror (const char *msg)
00520 {
00521   fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
00522 }
00523 
00524 /* Issue a warning while reading an rc file.  */
00525 
00526 void
00527 rcparse_warning (const char *msg)
00528 {
00529   fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
00530 }
00531 
00532 /* Die if we get an unexpected end of file.  */
00533 
00534 static void
00535 unexpected_eof (const char *msg)
00536 {
00537   fatal (_("%s: unexpected EOF"), msg);
00538 }
00539 
00540 /* Read a 16 bit word from a file.  The data is assumed to be little
00541    endian.  */
00542 
00543 static int
00544 get_word (FILE *e, const char *msg)
00545 {
00546   int b1, b2;
00547 
00548   b1 = getc (e);
00549   b2 = getc (e);
00550   if (feof (e))
00551     unexpected_eof (msg);
00552   return ((b2 & 0xff) << 8) | (b1 & 0xff);
00553 }
00554 
00555 /* Read a 32 bit word from a file.  The data is assumed to be little
00556    endian.  */
00557 
00558 static unsigned long
00559 get_long (FILE *e, const char *msg)
00560 {
00561   int b1, b2, b3, b4;
00562 
00563   b1 = getc (e);
00564   b2 = getc (e);
00565   b3 = getc (e);
00566   b4 = getc (e);
00567   if (feof (e))
00568     unexpected_eof (msg);
00569   return (((((((b4 & 0xff) << 8)
00570              | (b3 & 0xff)) << 8)
00571            | (b2 & 0xff)) << 8)
00572          | (b1 & 0xff));
00573 }
00574 
00575 /* Read data from a file.  This is a wrapper to do error checking.  */
00576 
00577 static void
00578 get_data (FILE *e, unsigned char *p, unsigned long c, const char *msg)
00579 {
00580   unsigned long got;
00581 
00582   got = fread (p, 1, c, e);
00583   if (got == c)
00584     return;
00585 
00586   fatal (_("%s: read of %lu returned %lu"), msg, c, got);
00587 }
00588 
00589 /* Define an accelerator resource.  */
00590 
00591 void
00592 define_accelerator (struct res_id id, const struct res_res_info *resinfo,
00593                   struct accelerator *data)
00594 {
00595   struct res_resource *r;
00596 
00597   r = define_standard_resource (&resources, RT_ACCELERATOR, id,
00598                             resinfo->language, 0);
00599   r->type = RES_TYPE_ACCELERATOR;
00600   r->u.acc = data;
00601   r->res_info = *resinfo;
00602 }
00603 
00604 /* Define a bitmap resource.  Bitmap data is stored in a file.  The
00605    first 14 bytes of the file are a standard header, which is not
00606    included in the resource data.  */
00607 
00608 #define BITMAP_SKIP (14)
00609 
00610 void
00611 define_bitmap (struct res_id id, const struct res_res_info *resinfo,
00612               const char *filename)
00613 {
00614   FILE *e;
00615   char *real_filename;
00616   struct stat s;
00617   unsigned char *data;
00618   int i;
00619   struct res_resource *r;
00620 
00621   e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
00622 
00623   if (stat (real_filename, &s) < 0)
00624     fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
00625           strerror (errno));
00626 
00627   data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
00628 
00629   for (i = 0; i < BITMAP_SKIP; i++)
00630     getc (e);
00631 
00632   get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
00633 
00634   fclose (e);
00635   free (real_filename);
00636 
00637   r = define_standard_resource (&resources, RT_BITMAP, id,
00638                             resinfo->language, 0);
00639 
00640   r->type = RES_TYPE_BITMAP;
00641   r->u.data.length = s.st_size - BITMAP_SKIP;
00642   r->u.data.data = data;
00643   r->res_info = *resinfo;
00644 }
00645 
00646 /* Define a cursor resource.  A cursor file may contain a set of
00647    bitmaps, each representing the same cursor at various different
00648    resolutions.  They each get written out with a different ID.  The
00649    real cursor resource is then a group resource which can be used to
00650    select one of the actual cursors.  */
00651 
00652 void
00653 define_cursor (struct res_id id, const struct res_res_info *resinfo,
00654               const char *filename)
00655 {
00656   FILE *e;
00657   char *real_filename;
00658   int type, count, i;
00659   struct icondir *icondirs;
00660   int first_cursor;
00661   struct res_resource *r;
00662   struct group_cursor *first, **pp;
00663 
00664   e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
00665 
00666   /* A cursor file is basically an icon file.  The start of the file
00667      is a three word structure.  The first word is ignored.  The
00668      second word is the type of data.  The third word is the number of
00669      entries.  */
00670 
00671   get_word (e, real_filename);
00672   type = get_word (e, real_filename);
00673   count = get_word (e, real_filename);
00674   if (type != 2)
00675     fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
00676 
00677   /* Read in the icon directory entries.  */
00678 
00679   icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
00680 
00681   for (i = 0; i < count; i++)
00682     {
00683       icondirs[i].width = getc (e);
00684       icondirs[i].height = getc (e);
00685       icondirs[i].colorcount = getc (e);
00686       getc (e);
00687       icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
00688       icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
00689       icondirs[i].bytes = get_long (e, real_filename);
00690       icondirs[i].offset = get_long (e, real_filename);
00691 
00692       if (feof (e))
00693        unexpected_eof (real_filename);
00694     }
00695 
00696   /* Define each cursor as a unique resource.  */
00697 
00698   first_cursor = cursors;
00699 
00700   for (i = 0; i < count; i++)
00701     {
00702       unsigned char *data;
00703       struct res_id name;
00704       struct cursor *c;
00705 
00706       if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
00707        fatal (_("%s: fseek to %lu failed: %s"), real_filename,
00708               icondirs[i].offset, strerror (errno));
00709 
00710       data = (unsigned char *) res_alloc (icondirs[i].bytes);
00711 
00712       get_data (e, data, icondirs[i].bytes, real_filename);
00713 
00714       c = (struct cursor *) res_alloc (sizeof *c);
00715       c->xhotspot = icondirs[i].u.cursor.xhotspot;
00716       c->yhotspot = icondirs[i].u.cursor.yhotspot;
00717       c->length = icondirs[i].bytes;
00718       c->data = data;
00719 
00720       ++cursors;
00721 
00722       name.named = 0;
00723       name.u.id = cursors;
00724 
00725       r = define_standard_resource (&resources, RT_CURSOR, name,
00726                                 resinfo->language, 0);
00727       r->type = RES_TYPE_CURSOR;
00728       r->u.cursor = c;
00729       r->res_info = *resinfo;
00730     }
00731 
00732   fclose (e);
00733   free (real_filename);
00734 
00735   /* Define a cursor group resource.  */
00736 
00737   first = NULL;
00738   pp = &first;
00739   for (i = 0; i < count; i++)
00740     {
00741       struct group_cursor *cg;
00742 
00743       cg = (struct group_cursor *) res_alloc (sizeof *cg);
00744       cg->next = NULL;
00745       cg->width = icondirs[i].width;
00746       cg->height = 2 * icondirs[i].height;
00747 
00748       /* FIXME: What should these be set to?  */
00749       cg->planes = 1;
00750       cg->bits = 1;
00751 
00752       cg->bytes = icondirs[i].bytes + 4;
00753       cg->index = first_cursor + i + 1;
00754 
00755       *pp = cg;
00756       pp = &(*pp)->next;
00757     }
00758 
00759   free (icondirs);
00760 
00761   r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
00762                             resinfo->language, 0);
00763   r->type = RES_TYPE_GROUP_CURSOR;
00764   r->u.group_cursor = first;
00765   r->res_info = *resinfo;
00766 }
00767 
00768 /* Define a dialog resource.  */
00769 
00770 void
00771 define_dialog (struct res_id id, const struct res_res_info *resinfo,
00772               const struct dialog *dialog)
00773 {
00774   struct dialog *copy;
00775   struct res_resource *r;
00776 
00777   copy = (struct dialog *) res_alloc (sizeof *copy);
00778   *copy = *dialog;
00779 
00780   r = define_standard_resource (&resources, RT_DIALOG, id,
00781                             resinfo->language, 0);
00782   r->type = RES_TYPE_DIALOG;
00783   r->u.dialog = copy;
00784   r->res_info = *resinfo;
00785 }
00786 
00787 /* Define a dialog control.  This does not define a resource, but
00788    merely allocates and fills in a structure.  */
00789 
00790 struct dialog_control *
00791 define_control (const struct res_id iid, unsigned long id, unsigned long x,
00792               unsigned long y, unsigned long width, unsigned long height,
00793               unsigned long class, unsigned long style,
00794               unsigned long exstyle)
00795 {
00796   struct dialog_control *n;
00797 
00798   n = (struct dialog_control *) res_alloc (sizeof *n);
00799   n->next = NULL;
00800   n->id = id;
00801   n->style = style;
00802   n->exstyle = exstyle;
00803   n->x = x;
00804   n->y = y;
00805   n->width = width;
00806   n->height = height;
00807   n->class.named = 0;
00808   n->class.u.id = class;
00809   n->text = iid;
00810   n->data = NULL;
00811   n->help = 0;
00812 
00813   return n;
00814 }
00815 
00816 struct dialog_control *
00817 define_icon_control (struct res_id iid, unsigned long id, unsigned long x,
00818                    unsigned long y, unsigned long style,
00819                    unsigned long exstyle, unsigned long help,
00820                    struct rcdata_item *data, struct dialog_ex *ex)
00821 {
00822   struct dialog_control *n;
00823   struct res_id tid;
00824 
00825   if (style == 0)
00826     style = SS_ICON | WS_CHILD | WS_VISIBLE;
00827   res_string_to_id (&tid, "");
00828   n = define_control (tid, id, x, y, 0, 0, CTL_STATIC, style, exstyle);
00829   n->text = iid;
00830   if (help && !ex)
00831     rcparse_warning (_("help ID requires DIALOGEX"));
00832   if (data && !ex)
00833     rcparse_warning (_("control data requires DIALOGEX"));
00834   n->help = help;
00835   n->data = data;
00836 
00837   return n;
00838 }
00839 
00840 /* Define a font resource.  */
00841 
00842 void
00843 define_font (struct res_id id, const struct res_res_info *resinfo,
00844             const char *filename)
00845 {
00846   FILE *e;
00847   char *real_filename;
00848   struct stat s;
00849   unsigned char *data;
00850   struct res_resource *r;
00851   long offset;
00852   long fontdatalength;
00853   unsigned char *fontdata;
00854   struct fontdir *fd;
00855   const char *device, *face;
00856   struct fontdir **pp;
00857 
00858   e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
00859 
00860   if (stat (real_filename, &s) < 0)
00861     fatal (_("stat failed on font file `%s': %s"), real_filename,
00862           strerror (errno));
00863 
00864   data = (unsigned char *) res_alloc (s.st_size);
00865 
00866   get_data (e, data, s.st_size, real_filename);
00867 
00868   fclose (e);
00869   free (real_filename);
00870 
00871   r = define_standard_resource (&resources, RT_FONT, id,
00872                             resinfo->language, 0);
00873 
00874   r->type = RES_TYPE_FONT;
00875   r->u.data.length = s.st_size;
00876   r->u.data.data = data;
00877   r->res_info = *resinfo;
00878 
00879   /* For each font resource, we must add an entry in the FONTDIR
00880      resource.  The FONTDIR resource includes some strings in the font
00881      file.  To find them, we have to do some magic on the data we have
00882      read.  */
00883 
00884   offset = ((((((data[47] << 8)
00885               | data[46]) << 8)
00886              | data[45]) << 8)
00887            | data[44]);
00888   if (offset > 0 && offset < s.st_size)
00889     device = (char *) data + offset;
00890   else
00891     device = "";
00892 
00893   offset = ((((((data[51] << 8)
00894               | data[50]) << 8)
00895              | data[49]) << 8)
00896            | data[48]);
00897   if (offset > 0 && offset < s.st_size)
00898     face = (char *) data + offset;
00899   else
00900     face = "";
00901 
00902   ++fonts;
00903 
00904   fontdatalength = 58 + strlen (device) + strlen (face);
00905   fontdata = (unsigned char *) res_alloc (fontdatalength);
00906   memcpy (fontdata, data, 56);
00907   strcpy ((char *) fontdata + 56, device);
00908   strcpy ((char *) fontdata + 57 + strlen (device), face);
00909 
00910   fd = (struct fontdir *) res_alloc (sizeof *fd);
00911   fd->next = NULL;
00912   fd->index = fonts;
00913   fd->length = fontdatalength;
00914   fd->data = fontdata;
00915 
00916   for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
00917     ;
00918   *pp = fd;
00919 
00920   /* For the single fontdirs resource, we always use the resource
00921      information of the last font.  I don't know what else to do.  */
00922   fontdirs_resinfo = *resinfo;
00923 }
00924 
00925 /* Define the fontdirs resource.  This is called after the entire rc
00926    file has been parsed, if any font resources were seen.  */
00927 
00928 static void
00929 define_fontdirs (void)
00930 {
00931   struct res_resource *r;
00932   struct res_id id;
00933 
00934   id.named = 0;
00935   id.u.id = 1;
00936 
00937   r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
00938 
00939   r->type = RES_TYPE_FONTDIR;
00940   r->u.fontdir = fontdirs;
00941   r->res_info = fontdirs_resinfo;
00942 }
00943 
00944 /* Define an icon resource.  An icon file may contain a set of
00945    bitmaps, each representing the same icon at various different
00946    resolutions.  They each get written out with a different ID.  The
00947    real icon resource is then a group resource which can be used to
00948    select one of the actual icon bitmaps.  */
00949 
00950 void
00951 define_icon (struct res_id id, const struct res_res_info *resinfo,
00952             const char *filename)
00953 {
00954   FILE *e;
00955   char *real_filename;
00956   int type, count, i;
00957   struct icondir *icondirs;
00958   int first_icon;
00959   struct res_resource *r;
00960   struct group_icon *first, **pp;
00961 
00962   e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
00963 
00964   /* The start of an icon file is a three word structure.  The first
00965      word is ignored.  The second word is the type of data.  The third
00966      word is the number of entries.  */
00967 
00968   get_word (e, real_filename);
00969   type = get_word (e, real_filename);
00970   count = get_word (e, real_filename);
00971   if (type != 1)
00972     fatal (_("icon file `%s' does not contain icon data"), real_filename);
00973 
00974   /* Read in the icon directory entries.  */
00975 
00976   icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
00977 
00978   for (i = 0; i < count; i++)
00979     {
00980       icondirs[i].width = getc (e);
00981       icondirs[i].height = getc (e);
00982       icondirs[i].colorcount = getc (e);
00983       getc (e);
00984       icondirs[i].u.icon.planes = get_word (e, real_filename);
00985       icondirs[i].u.icon.bits = get_word (e, real_filename);
00986       icondirs[i].bytes = get_long (e, real_filename);
00987       icondirs[i].offset = get_long (e, real_filename);
00988 
00989       if (feof (e))
00990        unexpected_eof (real_filename);
00991     }
00992 
00993   /* Define each icon as a unique resource.  */
00994 
00995   first_icon = icons;
00996 
00997   for (i = 0; i < count; i++)
00998     {
00999       unsigned char *data;
01000       struct res_id name;
01001 
01002       if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
01003        fatal (_("%s: fseek to %lu failed: %s"), real_filename,
01004               icondirs[i].offset, strerror (errno));
01005 
01006       data = (unsigned char *) res_alloc (icondirs[i].bytes);
01007 
01008       get_data (e, data, icondirs[i].bytes, real_filename);
01009 
01010       ++icons;
01011 
01012       name.named = 0;
01013       name.u.id = icons;
01014 
01015       r = define_standard_resource (&resources, RT_ICON, name,
01016                                 resinfo->language, 0);
01017       r->type = RES_TYPE_ICON;
01018       r->u.data.length = icondirs[i].bytes;
01019       r->u.data.data = data;
01020       r->res_info = *resinfo;
01021     }
01022 
01023   fclose (e);
01024   free (real_filename);
01025 
01026   /* Define an icon group resource.  */
01027 
01028   first = NULL;
01029   pp = &first;
01030   for (i = 0; i < count; i++)
01031     {
01032       struct group_icon *cg;
01033 
01034       /* For some reason, at least in some files the planes and bits
01035          are zero.  We instead set them from the color.  This is
01036          copied from rcl.  */
01037 
01038       cg = (struct group_icon *) res_alloc (sizeof *cg);
01039       cg->next = NULL;
01040       cg->width = icondirs[i].width;
01041       cg->height = icondirs[i].height;
01042       cg->colors = icondirs[i].colorcount;
01043 
01044       if (icondirs[i].u.icon.planes)
01045        cg->planes = icondirs[i].u.icon.planes;
01046       else
01047        cg->planes = 1;
01048 
01049       if (icondirs[i].u.icon.bits)
01050        cg->bits = icondirs[i].u.icon.bits;
01051       else
01052        {
01053          cg->bits = 0;
01054 
01055          while ((1L << cg->bits) < cg->colors)
01056            ++cg->bits;
01057        }
01058 
01059       cg->bytes = icondirs[i].bytes;
01060       cg->index = first_icon + i + 1;
01061 
01062       *pp = cg;
01063       pp = &(*pp)->next;
01064     }
01065 
01066   free (icondirs);
01067 
01068   r = define_standard_resource (&resources, RT_GROUP_ICON, id,
01069                             resinfo->language, 0);
01070   r->type = RES_TYPE_GROUP_ICON;
01071   r->u.group_icon = first;
01072   r->res_info = *resinfo;
01073 }
01074 
01075 /* Define a menu resource.  */
01076 
01077 void
01078 define_menu (struct res_id id, const struct res_res_info *resinfo,
01079             struct menuitem *menuitems)
01080 {
01081   struct menu *m;
01082   struct res_resource *r;
01083 
01084   m = (struct menu *) res_alloc (sizeof *m);
01085   m->items = menuitems;
01086   m->help = 0;
01087 
01088   r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
01089   r->type = RES_TYPE_MENU;
01090   r->u.menu = m;
01091   r->res_info = *resinfo;
01092 }
01093 
01094 /* Define a menu item.  This does not define a resource, but merely
01095    allocates and fills in a structure.  */
01096 
01097 struct menuitem *
01098 define_menuitem (const char *text, int menuid, unsigned long type,
01099                unsigned long state, unsigned long help,
01100                struct menuitem *menuitems)
01101 {
01102   struct menuitem *mi;
01103 
01104   mi = (struct menuitem *) res_alloc (sizeof *mi);
01105   mi->next = NULL;
01106   mi->type = type;
01107   mi->state = state;
01108   mi->id = menuid;
01109   if (text == NULL)
01110     mi->text = NULL;
01111   else
01112     unicode_from_ascii ((int *) NULL, &mi->text, text);
01113   mi->help = help;
01114   mi->popup = menuitems;
01115   return mi;
01116 }
01117 
01118 /* Define a messagetable resource.  */
01119 
01120 void
01121 define_messagetable (struct res_id id, const struct res_res_info *resinfo,
01122                    const char *filename)
01123 {
01124   FILE *e;
01125   char *real_filename;
01126   struct stat s;
01127   unsigned char *data;
01128   struct res_resource *r;
01129 
01130   e = open_file_search (filename, FOPEN_RB, "messagetable file",
01131                      &real_filename);
01132 
01133   if (stat (real_filename, &s) < 0)
01134     fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
01135           strerror (errno));
01136 
01137   data = (unsigned char *) res_alloc (s.st_size);
01138 
01139   get_data (e, data, s.st_size, real_filename);
01140 
01141   fclose (e);
01142   free (real_filename);
01143 
01144   r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
01145                             resinfo->language, 0);
01146 
01147   r->type = RES_TYPE_MESSAGETABLE;
01148   r->u.data.length = s.st_size;
01149   r->u.data.data = data;
01150   r->res_info = *resinfo;
01151 }
01152 
01153 /* Define an rcdata resource.  */
01154 
01155 void
01156 define_rcdata (struct res_id id, const struct res_res_info *resinfo,
01157               struct rcdata_item *data)
01158 {
01159   struct res_resource *r;
01160 
01161   r = define_standard_resource (&resources, RT_RCDATA, id,
01162                             resinfo->language, 0);
01163   r->type = RES_TYPE_RCDATA;
01164   r->u.rcdata = data;
01165   r->res_info = *resinfo;
01166 }
01167 
01168 /* Create an rcdata item holding a string.  */
01169 
01170 struct rcdata_item *
01171 define_rcdata_string (const char *string, unsigned long len)
01172 {
01173   struct rcdata_item *ri;
01174   char *s;
01175 
01176   ri = (struct rcdata_item *) res_alloc (sizeof *ri);
01177   ri->next = NULL;
01178   ri->type = RCDATA_STRING;
01179   ri->u.string.length = len;
01180   s = (char *) res_alloc (len);
01181   memcpy (s, string, len);
01182   ri->u.string.s = s;
01183 
01184   return ri;
01185 }
01186 
01187 /* Create an rcdata item holding a number.  */
01188 
01189 struct rcdata_item *
01190 define_rcdata_number (unsigned long val, int dword)
01191 {
01192   struct rcdata_item *ri;
01193 
01194   ri = (struct rcdata_item *) res_alloc (sizeof *ri);
01195   ri->next = NULL;
01196   ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
01197   ri->u.word = val;
01198 
01199   return ri;
01200 }
01201 
01202 /* Define a stringtable resource.  This is called for each string
01203    which appears in a STRINGTABLE statement.  */
01204 
01205 void
01206 define_stringtable (const struct res_res_info *resinfo,
01207                   unsigned long stringid, const char *string)
01208 {
01209   struct res_id id;
01210   struct res_resource *r;
01211 
01212   id.named = 0;
01213   id.u.id = (stringid >> 4) + 1;
01214   r = define_standard_resource (&resources, RT_STRING, id,
01215                             resinfo->language, 1);
01216 
01217   if (r->type == RES_TYPE_UNINITIALIZED)
01218     {
01219       int i;
01220 
01221       r->type = RES_TYPE_STRINGTABLE;
01222       r->u.stringtable = ((struct stringtable *)
01223                        res_alloc (sizeof (struct stringtable)));
01224       for (i = 0; i < 16; i++)
01225        {
01226          r->u.stringtable->strings[i].length = 0;
01227          r->u.stringtable->strings[i].string = NULL;
01228        }
01229 
01230       r->res_info = *resinfo;
01231     }
01232 
01233   unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
01234                     &r->u.stringtable->strings[stringid & 0xf].string,
01235                     string);
01236 }
01237 
01238 /* Define a user data resource where the data is in the rc file.  */
01239 
01240 void
01241 define_user_data (struct res_id id, struct res_id type,
01242                 const struct res_res_info *resinfo,
01243                 struct rcdata_item *data)
01244 {
01245   struct res_id ids[3];
01246   struct res_resource *r;
01247 
01248   ids[0] = type;
01249   ids[1] = id;
01250   ids[2].named = 0;
01251   ids[2].u.id = resinfo->language;
01252 
01253   r = define_resource (& resources, 3, ids, 0);
01254   r->type = RES_TYPE_USERDATA;
01255   r->u.userdata = data;
01256   r->res_info = *resinfo;
01257 }
01258 
01259 void
01260 define_rcdata_file (struct res_id id, const struct res_res_info *resinfo,
01261                   const char *filename)
01262 {
01263   struct rcdata_item *ri;
01264   FILE *e;
01265   char *real_filename;
01266   struct stat s;
01267   unsigned char *data;
01268 
01269   e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
01270 
01271 
01272   if (stat (real_filename, &s) < 0)
01273     fatal (_("stat failed on file `%s': %s"), real_filename,
01274           strerror (errno));
01275 
01276   data = (unsigned char *) res_alloc (s.st_size);
01277 
01278   get_data (e, data, s.st_size, real_filename);
01279 
01280   fclose (e);
01281   free (real_filename);
01282 
01283   ri = (struct rcdata_item *) res_alloc (sizeof *ri);
01284   ri->next = NULL;
01285   ri->type = RCDATA_BUFFER;
01286   ri->u.buffer.length = s.st_size;
01287   ri->u.buffer.data = data;
01288 
01289   define_rcdata (id, resinfo, ri);
01290 }
01291 
01292 /* Define a user data resource where the data is in a file.  */
01293 
01294 void
01295 define_user_file (struct res_id id, struct res_id type,
01296                 const struct res_res_info *resinfo, const char *filename)
01297 {
01298   FILE *e;
01299   char *real_filename;
01300   struct stat s;
01301   unsigned char *data;
01302   struct res_id ids[3];
01303   struct res_resource *r;
01304 
01305   e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
01306 
01307   if (stat (real_filename, &s) < 0)
01308     fatal (_("stat failed on file `%s': %s"), real_filename,
01309           strerror (errno));
01310 
01311   data = (unsigned char *) res_alloc (s.st_size);
01312 
01313   get_data (e, data, s.st_size, real_filename);
01314 
01315   fclose (e);
01316   free (real_filename);
01317 
01318   ids[0] = type;
01319   ids[1] = id;
01320   ids[2].named = 0;
01321   ids[2].u.id = resinfo->language;
01322 
01323   r = define_resource (&resources, 3, ids, 0);
01324   r->type = RES_TYPE_USERDATA;
01325   r->u.userdata = ((struct rcdata_item *)
01326                  res_alloc (sizeof (struct rcdata_item)));
01327   r->u.userdata->next = NULL;
01328   r->u.userdata->type = RCDATA_BUFFER;
01329   r->u.userdata->u.buffer.length = s.st_size;
01330   r->u.userdata->u.buffer.data = data;
01331   r->res_info = *resinfo;
01332 }
01333 
01334 /* Define a versioninfo resource.  */
01335 
01336 void
01337 define_versioninfo (struct res_id id, int language,
01338                   struct fixed_versioninfo *fixedverinfo,
01339                   struct ver_info *verinfo)
01340 {
01341   struct res_resource *r;
01342 
01343   r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
01344   r->type = RES_TYPE_VERSIONINFO;
01345   r->u.versioninfo = ((struct versioninfo *)
01346                     res_alloc (sizeof (struct versioninfo)));
01347   r->u.versioninfo->fixed = fixedverinfo;
01348   r->u.versioninfo->var = verinfo;
01349   r->res_info.language = language;
01350 }
01351 
01352 /* Add string version info to a list of version information.  */
01353 
01354 struct ver_info *
01355 append_ver_stringfileinfo (struct ver_info *verinfo, const char *language,
01356                         struct ver_stringinfo *strings)
01357 {
01358   struct ver_info *vi, **pp;
01359 
01360   vi = (struct ver_info *) res_alloc (sizeof *vi);
01361   vi->next = NULL;
01362   vi->type = VERINFO_STRING;
01363   unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
01364   vi->u.string.strings = strings;
01365 
01366   for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
01367     ;
01368   *pp = vi;
01369 
01370   return verinfo;
01371 }
01372 
01373 /* Add variable version info to a list of version information.  */
01374 
01375 struct ver_info *
01376 append_ver_varfileinfo (struct ver_info *verinfo, const char *key,
01377                      struct ver_varinfo *var)
01378 {
01379   struct ver_info *vi, **pp;
01380 
01381   vi = (struct ver_info *) res_alloc (sizeof *vi);
01382   vi->next = NULL;
01383   vi->type = VERINFO_VAR;
01384   unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
01385   vi->u.var.var = var;
01386 
01387   for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
01388     ;
01389   *pp = vi;
01390 
01391   return verinfo;
01392 }
01393 
01394 /* Append version string information to a list.  */
01395 
01396 struct ver_stringinfo *
01397 append_verval (struct ver_stringinfo *strings, const char *key,
01398               const char *value)
01399 {
01400   struct ver_stringinfo *vs, **pp;
01401 
01402   vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
01403   vs->next = NULL;
01404   unicode_from_ascii ((int *) NULL, &vs->key, key);
01405   unicode_from_ascii ((int *) NULL, &vs->value, value);
01406 
01407   for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
01408     ;
01409   *pp = vs;
01410 
01411   return strings;
01412 }
01413 
01414 /* Append version variable information to a list.  */
01415 
01416 struct ver_varinfo *
01417 append_vertrans (struct ver_varinfo *var, unsigned long language,
01418                unsigned long charset)
01419 {
01420   struct ver_varinfo *vv, **pp;
01421 
01422   vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
01423   vv->next = NULL;
01424   vv->language = language;
01425   vv->charset = charset;
01426 
01427   for (pp = &var; *pp != NULL; pp = &(*pp)->next)
01428     ;
01429   *pp = vv;
01430 
01431   return var;
01432 }
01433 
01434 /* Local functions used to write out an rc file.  */
01435 
01436 static void indent (FILE *, int);
01437 static void write_rc_directory
01438   (FILE *, const struct res_directory *, const struct res_id *,
01439    const struct res_id *, int *, int);
01440 static void write_rc_subdir
01441   (FILE *, const struct res_entry *, const struct res_id *,
01442    const struct res_id *, int *, int);
01443 static void write_rc_resource
01444   (FILE *, const struct res_id *, const struct res_id *,
01445    const struct res_resource *, int *);
01446 static void write_rc_accelerators (FILE *, const struct accelerator *);
01447 static void write_rc_cursor (FILE *, const struct cursor *);
01448 static void write_rc_group_cursor (FILE *, const struct group_cursor *);
01449 static void write_rc_dialog (FILE *, const struct dialog *);
01450 static void write_rc_dialog_control (FILE *, const struct dialog_control *);
01451 static void write_rc_fontdir (FILE *, const struct fontdir *);
01452 static void write_rc_group_icon (FILE *, const struct group_icon *);
01453 static void write_rc_menu (FILE *, const struct menu *, int);
01454 static void write_rc_menuitems (FILE *, const struct menuitem *, int, int);
01455 static void write_rc_rcdata (FILE *, const struct rcdata_item *, int);
01456 static void write_rc_stringtable
01457   (FILE *, const struct res_id *, const struct stringtable *);
01458 static void write_rc_versioninfo (FILE *, const struct versioninfo *);
01459 static void write_rc_filedata (FILE *, unsigned long, const unsigned char *);
01460 
01461 /* Indent a given number of spaces.  */
01462 
01463 static void
01464 indent (FILE *e, int c)
01465 {
01466   int i;
01467 
01468   for (i = 0; i < c; i++)
01469     putc (' ', e);
01470 }
01471 
01472 /* Dump the resources we have read in the format of an rc file.
01473 
01474    Actually, we don't use the format of an rc file, because it's way
01475    too much of a pain--for example, we'd have to write icon resources
01476    into a file and refer to that file.  We just generate a readable
01477    format that kind of looks like an rc file, and is useful for
01478    understanding the contents of a resource file.  Someday we may want
01479    to generate an rc file which the rc compiler can read; if that day
01480    comes, this code will have to be fixed up.  */
01481 
01482 void
01483 write_rc_file (const char *filename, const struct res_directory *resources)
01484 {
01485   FILE *e;
01486   int language;
01487 
01488   if (filename == NULL)
01489     e = stdout;
01490   else
01491     {
01492       e = fopen (filename, FOPEN_WT);
01493       if (e == NULL)
01494        fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
01495     }
01496 
01497   language = -1;
01498   write_rc_directory (e, resources, (const struct res_id *) NULL,
01499                     (const struct res_id *) NULL, &language, 1);
01500 }
01501 
01502 /* Write out a directory.  E is the file to write to.  RD is the
01503    directory.  TYPE is a pointer to the level 1 ID which serves as the
01504    resource type.  NAME is a pointer to the level 2 ID which serves as
01505    an individual resource name.  LANGUAGE is a pointer to the current
01506    language.  LEVEL is the level in the tree.  */
01507 
01508 static void
01509 write_rc_directory (FILE *e, const struct res_directory *rd,
01510                   const struct res_id *type, const struct res_id *name,
01511                   int *language, int level)
01512 {
01513   const struct res_entry *re;
01514 
01515   /* Print out some COFF information that rc files can't represent.  */
01516 
01517   if (rd->time != 0)
01518     fprintf (e, "// Time stamp: %lu\n", rd->time);
01519   if (rd->characteristics != 0)
01520     fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
01521   if (rd->major != 0 || rd->minor != 0)
01522     fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
01523 
01524   for (re = rd->entries;  re != NULL; re = re->next)
01525     {
01526       switch (level)
01527        {
01528        case 1:
01529          /* If we're at level 1, the key of this resource is the
01530              type.  This normally duplicates the information we have
01531              stored with the resource itself, but we need to remember
01532              the type if this is a user define resource type.  */
01533          type = &re->id;
01534          break;
01535 
01536        case 2:
01537          /* If we're at level 2, the key of this resource is the name
01538             we are going to use in the rc printout.  */
01539          name = &re->id;
01540          break;
01541 
01542        case 3:
01543          /* If we're at level 3, then this key represents a language.
01544             Use it to update the current language.  */
01545          if (! re->id.named
01546              && re->id.u.id != (unsigned long) (unsigned int) *language
01547              && (re->id.u.id & 0xffff) == re->id.u.id)
01548            {
01549              fprintf (e, "LANGUAGE %lu, %lu\n",
01550                      re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
01551                      (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
01552              *language = re->id.u.id;
01553            }
01554          break;
01555 
01556        default:
01557          break;
01558        }
01559 
01560       if (re->subdir)
01561        write_rc_subdir (e, re, type, name, language, level);
01562       else
01563        {
01564          if (level == 3)
01565            {
01566              /* This is the normal case: the three levels are
01567                  TYPE/NAME/LANGUAGE.  NAME will have been set at level
01568                  2, and represents the name to use.  We probably just
01569                  set LANGUAGE, and it will probably match what the
01570                  resource itself records if anything.  */
01571              write_rc_resource (e, type, name, re->u.res, language);
01572            }
01573          else
01574            {
01575              fprintf (e, "// Resource at unexpected level %d\n", level);
01576              write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
01577                              language);
01578            }
01579        }
01580     }
01581 }
01582 
01583 /* Write out a subdirectory entry.  E is the file to write to.  RE is
01584    the subdirectory entry.  TYPE and NAME are pointers to higher level
01585    IDs, or NULL.  LANGUAGE is a pointer to the current language.
01586    LEVEL is the level in the tree.  */
01587 
01588 static void
01589 write_rc_subdir (FILE *e, const struct res_entry *re,
01590                const struct res_id *type, const struct res_id *name,
01591                int *language, int level)
01592 {
01593   fprintf (e, "\n");
01594   switch (level)
01595     {
01596     case 1:
01597       fprintf (e, "// Type: ");
01598       if (re->id.named)
01599        res_id_print (e, re->id, 1);
01600       else
01601        {
01602          const char *s;
01603 
01604          switch (re->id.u.id)
01605            {
01606            case RT_CURSOR: s = "cursor"; break;
01607            case RT_BITMAP: s = "bitmap"; break;
01608            case RT_ICON: s = "icon"; break;
01609            case RT_MENU: s = "menu"; break;
01610            case RT_DIALOG: s = "dialog"; break;
01611            case RT_STRING: s = "stringtable"; break;
01612            case RT_FONTDIR: s = "fontdir"; break;
01613            case RT_FONT: s = "font"; break;
01614            case RT_ACCELERATOR: s = "accelerators"; break;
01615            case RT_RCDATA: s = "rcdata"; break;
01616            case RT_MESSAGETABLE: s = "messagetable"; break;
01617            case RT_GROUP_CURSOR: s = "group cursor"; break;
01618            case RT_GROUP_ICON: s = "group icon"; break;
01619            case RT_VERSION: s = "version"; break;
01620            case RT_DLGINCLUDE: s = "dlginclude"; break;
01621            case RT_PLUGPLAY: s = "plugplay"; break;
01622            case RT_VXD: s = "vxd"; break;
01623            case RT_ANICURSOR: s = "anicursor"; break;
01624            case RT_ANIICON: s = "aniicon"; break;
01625            default: s = NULL; break;
01626            }
01627 
01628          if (s != NULL)
01629            fprintf (e, "%s", s);
01630          else
01631            res_id_print (e, re->id, 1);
01632        }
01633       fprintf (e, "\n");
01634       break;
01635 
01636     case 2:
01637       fprintf (e, "// Name: ");
01638       res_id_print (e, re->id, 1);
01639       fprintf (e, "\n");
01640       break;
01641 
01642     case 3:
01643       fprintf (e, "// Language: ");
01644       res_id_print (e, re->id, 1);
01645       fprintf (e, "\n");
01646       break;
01647 
01648     default:
01649       fprintf (e, "// Level %d: ", level);
01650       res_id_print (e, re->id, 1);
01651       fprintf (e, "\n");
01652     }
01653 
01654   write_rc_directory (e, re->u.dir, type, name, language, level + 1);
01655 }
01656 
01657 /* Write out a single resource.  E is the file to write to.  TYPE is a
01658    pointer to the type of the resource.  NAME is a pointer to the name
01659    of the resource; it will be NULL if there is a level mismatch.  RES
01660    is the resource data.  LANGUAGE is a pointer to the current
01661    language.  */
01662 
01663 static void
01664 write_rc_resource (FILE *e, const struct res_id *type,
01665                  const struct res_id *name, const struct res_resource *res,
01666                  int *language)
01667 {
01668   const char *s;
01669   int rt;
01670   int menuex = 0;
01671 
01672   fprintf (e, "\n");
01673 
01674   switch (res->type)
01675     {
01676     default:
01677       abort ();
01678 
01679     case RES_TYPE_ACCELERATOR:
01680       s = "ACCELERATOR";
01681       rt = RT_ACCELERATOR;
01682       break;
01683 
01684     case RES_TYPE_BITMAP:
01685       s = "BITMAP";
01686       rt = RT_BITMAP;
01687       break;
01688 
01689     case RES_TYPE_CURSOR:
01690       s = "CURSOR";
01691       rt = RT_CURSOR;
01692       break;
01693 
01694     case RES_TYPE_GROUP_CURSOR:
01695       s = "GROUP_CURSOR";
01696       rt = RT_GROUP_CURSOR;
01697       break;
01698 
01699     case RES_TYPE_DIALOG:
01700       if (extended_dialog (res->u.dialog))
01701        s = "DIALOGEX";
01702       else
01703        s = "DIALOG";
01704       rt = RT_DIALOG;
01705       break;
01706 
01707     case RES_TYPE_FONT:
01708       s = "FONT";
01709       rt = RT_FONT;
01710       break;
01711 
01712     case RES_TYPE_FONTDIR:
01713       s = "FONTDIR";
01714       rt = RT_FONTDIR;
01715       break;
01716 
01717     case RES_TYPE_ICON:
01718       s = "ICON";
01719       rt = RT_ICON;
01720       break;
01721 
01722     case RES_TYPE_GROUP_ICON:
01723       s = "GROUP_ICON";
01724       rt = RT_GROUP_ICON;
01725       break;
01726 
01727     case RES_TYPE_MENU:
01728       if (extended_menu (res->u.menu))
01729        {
01730          s = "MENUEX";
01731          menuex = 1;
01732        }
01733       else
01734        {
01735          s = "MENU";
01736          menuex = 0;
01737        }
01738       rt = RT_MENU;
01739       break;
01740 
01741     case RES_TYPE_MESSAGETABLE:
01742       s = "MESSAGETABLE";
01743       rt = RT_MESSAGETABLE;
01744       break;
01745 
01746     case RES_TYPE_RCDATA:
01747       s = "RCDATA";
01748       rt = RT_RCDATA;
01749       break;
01750 
01751     case RES_TYPE_STRINGTABLE:
01752       s = "STRINGTABLE";
01753       rt = RT_STRING;
01754       break;
01755 
01756     case RES_TYPE_USERDATA:
01757       s = NULL;
01758       rt = 0;
01759       break;
01760 
01761     case RES_TYPE_VERSIONINFO:
01762       s = "VERSIONINFO";
01763       rt = RT_VERSION;
01764       break;
01765     }
01766 
01767   if (rt != 0
01768       && type != NULL
01769       && (type->named || type->u.id != (unsigned long) rt))
01770     {
01771       fprintf (e, "// Unexpected resource type mismatch: ");
01772       res_id_print (e, *type, 1);
01773       fprintf (e, " != %d", rt);
01774     }
01775 
01776   if (res->coff_info.codepage != 0)
01777     fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
01778   if (res->coff_info.reserved != 0)
01779     fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
01780 
01781   if (name != NULL)
01782     res_id_print (e, *name, 0);
01783   else
01784     fprintf (e, "??Unknown-Name??");
01785 
01786   fprintf (e, " ");
01787   if (s != NULL)
01788     fprintf (e, "%s", s);
01789   else if (type != NULL)
01790     res_id_print (e, *type, 0);
01791   else
01792     fprintf (e, "??Unknown-Type??");
01793 
01794   if (res->res_info.memflags != 0)
01795     {
01796       if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
01797        fprintf (e, " MOVEABLE");
01798       if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
01799        fprintf (e, " PURE");
01800       if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
01801        fprintf (e, " PRELOAD");
01802       if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
01803        fprintf (e, " DISCARDABLE");
01804     }
01805 
01806   if (res->type == RES_TYPE_DIALOG)
01807     {
01808       fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
01809               res->u.dialog->width, res->u.dialog->height);
01810       if (res->u.dialog->ex != NULL
01811          && res->u.dialog->ex->help != 0)
01812        fprintf (e, ", %lu", res->u.dialog->ex->help);
01813     }
01814 
01815   fprintf (e, "\n");
01816 
01817   if ((res->res_info.language != 0 && res->res_info.language != *language)
01818       || res->res_info.characteristics != 0
01819       || res->res_info.version != 0)
01820     {
01821       int modifiers;
01822 
01823       switch (res->type)
01824        {
01825        case RES_TYPE_ACCELERATOR:
01826        case RES_TYPE_DIALOG:
01827        case RES_TYPE_MENU:
01828        case RES_TYPE_RCDATA:
01829        case RES_TYPE_STRINGTABLE:
01830          modifiers = 1;
01831          break;
01832 
01833        default:
01834          modifiers = 0;
01835          break;
01836        }
01837 
01838       if (res->res_info.language != 0 && res->res_info.language != *language)
01839        fprintf (e, "%sLANGUAGE %d, %d\n",
01840                modifiers ? "// " : "",
01841                res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
01842                (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
01843       if (res->res_info.characteristics != 0)
01844        fprintf (e, "%sCHARACTERISTICS %lu\n",
01845                modifiers ? "// " : "",
01846                res->res_info.characteristics);
01847       if (res->res_info.version != 0)
01848        fprintf (e, "%sVERSION %lu\n",
01849                modifiers ? "// " : "",
01850                res->res_info.version);
01851     }
01852 
01853   switch (res->type)
01854     {
01855     default:
01856       abort ();
01857 
01858     case RES_TYPE_ACCELERATOR:
01859       write_rc_accelerators (e, res->u.acc);
01860       break;
01861 
01862     case RES_TYPE_CURSOR:
01863       write_rc_cursor (e, res->u.cursor);
01864       break;
01865 
01866     case RES_TYPE_GROUP_CURSOR:
01867       write_rc_group_cursor (e, res->u.group_cursor);
01868       break;
01869 
01870     case RES_TYPE_DIALOG:
01871       write_rc_dialog (e, res->u.dialog);
01872       break;
01873 
01874     case RES_TYPE_FONTDIR:
01875       write_rc_fontdir (e, res->u.fontdir);
01876       break;
01877 
01878     case RES_TYPE_GROUP_ICON:
01879       write_rc_group_icon (e, res->u.group_icon);
01880       break;
01881 
01882     case RES_TYPE_MENU:
01883       write_rc_menu (e, res->u.menu, menuex);
01884       break;
01885 
01886     case RES_TYPE_RCDATA:
01887       write_rc_rcdata (e, res->u.rcdata, 0);
01888       break;
01889 
01890     case RES_TYPE_STRINGTABLE:
01891       write_rc_stringtable (e, name, res->u.stringtable);
01892       break;
01893 
01894     case RES_TYPE_USERDATA:
01895       write_rc_rcdata (e, res->u.userdata, 0);
01896       break;
01897 
01898     case RES_TYPE_VERSIONINFO:
01899       write_rc_versioninfo (e, res->u.versioninfo);
01900       break;
01901 
01902     case RES_TYPE_BITMAP:
01903     case RES_TYPE_FONT:
01904     case RES_TYPE_ICON:
01905     case RES_TYPE_MESSAGETABLE:
01906       write_rc_filedata (e, res->u.data.length, res->u.data.data);
01907       break;
01908     }
01909 }
01910 
01911 /* Write out accelerator information.  */
01912 
01913 static void
01914 write_rc_accelerators (FILE *e, const struct accelerator *accelerators)
01915 {
01916   const struct accelerator *acc;
01917 
01918   fprintf (e, "BEGIN\n");
01919   for (acc = accelerators; acc != NULL; acc = acc->next)
01920     {
01921       int printable;
01922 
01923       fprintf (e, "  ");
01924 
01925       if ((acc->key & 0x7f) == acc->key
01926          && ISPRINT (acc->key)
01927          && (acc->flags & ACC_VIRTKEY) == 0)
01928        {
01929          fprintf (e, "\"%c\"", acc->key);
01930          printable = 1;
01931        }
01932       else
01933        {
01934          fprintf (e, "%d", acc->key);
01935          printable = 0;
01936        }
01937 
01938       fprintf (e, ", %d", acc->id);
01939 
01940       if (! printable)
01941        {
01942          if ((acc->flags & ACC_VIRTKEY) != 0)
01943            fprintf (e, ", VIRTKEY");
01944          else
01945            fprintf (e, ", ASCII");
01946        }
01947 
01948       if ((acc->flags & ACC_SHIFT) != 0)
01949        fprintf (e, ", SHIFT");
01950       if ((acc->flags & ACC_CONTROL) != 0)
01951        fprintf (e, ", CONTROL");
01952       if ((acc->flags & ACC_ALT) != 0)
01953        fprintf (e, ", ALT");
01954 
01955       fprintf (e, "\n");
01956     }
01957 
01958   fprintf (e, "END\n");
01959 }
01960 
01961 /* Write out cursor information.  This would normally be in a separate
01962    file, which the rc file would include.  */
01963 
01964 static void
01965 write_rc_cursor (FILE *e, const struct cursor *cursor)
01966 {
01967   fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
01968           cursor->yhotspot);
01969   write_rc_filedata (e, cursor->length, cursor->data);
01970 }
01971 
01972 /* Write out group cursor data.  This would normally be built from the
01973    cursor data.  */
01974 
01975 static void
01976 write_rc_group_cursor (FILE *e, const struct group_cursor *group_cursor)
01977 {
01978   const struct group_cursor *gc;
01979 
01980   for (gc = group_cursor; gc != NULL; gc = gc->next)
01981     {
01982       fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
01983             gc->width, gc->height, gc->planes, gc->bits);
01984       fprintf (e, "// data bytes: %lu; index: %d\n",
01985               gc->bytes, gc->index);
01986     }
01987 }
01988 
01989 /* Write dialog data.  */
01990 
01991 static void
01992 write_rc_dialog (FILE *e, const struct dialog *dialog)
01993 {
01994   const struct dialog_control *control;
01995 
01996   fprintf (e, "STYLE 0x%lx\n", dialog->style);
01997 
01998   if (dialog->exstyle != 0)
01999     fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
02000 
02001   if ((dialog->class.named && dialog->class.u.n.length > 0)
02002       || dialog->class.u.id != 0)
02003     {
02004       fprintf (e, "CLASS ");
02005       res_id_print (e, dialog->class, 1);
02006       fprintf (e, "\n");
02007     }
02008 
02009   if (dialog->caption != NULL)
02010     {
02011       fprintf (e, "CAPTION \"");
02012       unicode_print (e, dialog->caption, -1);
02013       fprintf (e, "\"\n");
02014     }
02015 
02016   if ((dialog->menu.named && dialog->menu.u.n.length > 0)
02017       || dialog->menu.u.id != 0)
02018     {
02019       fprintf (e, "MENU ");
02020       res_id_print (e, dialog->menu, 0);
02021       fprintf (e, "\n");
02022     }
02023 
02024   if (dialog->font != NULL)
02025     {
02026       fprintf (e, "FONT %d, \"", dialog->pointsize);
02027       unicode_print (e, dialog->font, -1);
02028       fprintf (e, "\"");
02029       if (dialog->ex != NULL
02030          && (dialog->ex->weight != 0
02031              || dialog->ex->italic != 0
02032              || dialog->ex->charset != 1))
02033        fprintf (e, ", %d, %d, %d",
02034                dialog->ex->weight, dialog->ex->italic, dialog->ex->charset);
02035       fprintf (e, "\n");
02036     }
02037 
02038   fprintf (e, "BEGIN\n");
02039 
02040   for (control = dialog->controls; control != NULL; control = control->next)
02041     write_rc_dialog_control (e, control);
02042 
02043   fprintf (e, "END\n");
02044 }
02045 
02046 /* For each predefined control keyword, this table provides the class
02047    and the style.  */
02048 
02049 struct control_info
02050 {
02051   const char *name;
02052   unsigned short class;
02053   unsigned long style;
02054 };
02055 
02056 static const struct control_info control_info[] =
02057 {
02058   { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
02059   { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
02060   { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
02061   { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
02062   { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
02063   { "CTEXT", CTL_STATIC, SS_CENTER },
02064   { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
02065   { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
02066   { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
02067   { "ICON", CTL_STATIC, SS_ICON },
02068   { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
02069   { "LTEXT", CTL_STATIC, SS_LEFT },
02070   { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
02071   { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
02072   { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
02073   { "RTEXT", CTL_STATIC, SS_RIGHT },
02074   { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
02075   { "STATE3", CTL_BUTTON, BS_3STATE },
02076   /* It's important that USERBUTTON come after all the other button
02077      types, so that it won't be matched too early.  */
02078   { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
02079   { NULL, 0, 0 }
02080 };
02081 
02082 /* Write a dialog control.  */
02083 
02084 static void
02085 write_rc_dialog_control (FILE *e, const struct dialog_control *control)
02086 {
02087   const struct control_info *ci;
02088 
02089   fprintf (e, "  ");
02090 
02091   if (control->class.named)
02092     ci = NULL;
02093   else
02094     {
02095       for (ci = control_info; ci->name != NULL; ++ci)
02096        if (ci->class == control->class.u.id
02097            && (ci->style == (unsigned long) -1
02098               || ci->style == (control->style & 0xff)))
02099          break;
02100     }
02101   if (ci == NULL)
02102     fprintf (e, "CONTROL");
02103   else if (ci->name != NULL)
02104     fprintf (e, "%s", ci->name);
02105   else
02106     fprintf (e, "CONTROL");
02107 
02108   if (control->text.named || control->text.u.id != 0)
02109     {
02110       fprintf (e, " ");
02111       res_id_print (e, control->text, 1);
02112       fprintf (e, ",");
02113     }
02114 
02115   fprintf (e, " %d, ", control->id);
02116 
02117   if (ci == NULL)
02118     {
02119       if (control->class.named)
02120        fprintf (e, "\"");
02121       res_id_print (e, control->class, 0);
02122       if (control->class.named)
02123        fprintf (e, "\"");
02124       fprintf (e, ", 0x%lx, ", control->style);
02125     }
02126 
02127   fprintf (e, "%d, %d", control->x, control->y);
02128 
02129   if (control->style != SS_ICON
02130       || control->exstyle != 0
02131       || control->width != 0
02132       || control->height != 0
02133       || control->help != 0)
02134     {
02135       fprintf (e, ", %d, %d", control->width, control->height);
02136 
02137       /* FIXME: We don't need to print the style if it is the default.
02138         More importantly, in certain cases we actually need to turn
02139         off parts of the forced style, by using NOT.  */
02140       fprintf (e, ", 0x%lx", control->style);
02141 
02142       if (control->exstyle != 0 || control->help != 0)
02143        fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
02144     }
02145 
02146   fprintf (e, "\n");
02147 
02148   if (control->data != NULL)
02149     write_rc_rcdata (e, control->data, 2);
02150 }
02151 
02152 /* Write out font directory data.  This would normally be built from
02153    the font data.  */
02154 
02155 static void
02156 write_rc_fontdir (FILE *e, const struct fontdir *fontdir)
02157 {
02158   const struct fontdir *fc;
02159 
02160   for (fc = fontdir; fc != NULL; fc = fc->next)
02161     {
02162       fprintf (e, "// Font index: %d\n", fc->index);
02163       write_rc_filedata (e, fc->length, fc->data);
02164     }
02165 }
02166 
02167 /* Write out group icon data.  This would normally be built from the
02168    icon data.  */
02169 
02170 static void
02171 write_rc_group_icon (FILE *e, const struct group_icon *group_icon)
02172 {
02173   const struct group_icon *gi;
02174 
02175   for (gi = group_icon; gi != NULL; gi = gi->next)
02176     {
02177       fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
02178               gi->width, gi->height, gi->colors, gi->planes, gi->bits);
02179       fprintf (e, "// data bytes: %lu; index: %d\n",
02180               gi->bytes, gi->index);
02181     }
02182 }
02183 
02184 /* Write out a menu resource.  */
02185 
02186 static void
02187 write_rc_menu (FILE *e, const struct menu *menu, int menuex)
02188 {
02189   if (menu->help != 0)
02190     fprintf (e, "// Help ID: %lu\n", menu->help);
02191   write_rc_menuitems (e, menu->items, menuex, 0);
02192 }
02193 
02194 /* Write out menuitems.  */
02195 
02196 static void
02197 write_rc_menuitems (FILE *e, const struct menuitem *menuitems, int menuex,
02198                   int ind)
02199 {
02200   const struct menuitem *mi;
02201 
02202   indent (e, ind);
02203   fprintf (e, "BEGIN\n");
02204 
02205   for (mi = menuitems; mi != NULL; mi = mi->next)
02206     {
02207       indent (e, ind + 2);
02208 
02209       if (mi->popup == NULL)
02210        fprintf (e, "MENUITEM");
02211       else
02212        fprintf (e, "POPUP");
02213 
02214       if (! menuex
02215          && mi->popup == NULL
02216          && mi->text == NULL
02217          && mi->type == 0
02218          && mi->id == 0)
02219        {
02220          fprintf (e, " SEPARATOR\n");
02221          continue;
02222        }
02223 
02224       if (mi->text == NULL)
02225        fprintf (e, " \"\"");
02226       else
02227        {
02228          fprintf (e, " \"");
02229          unicode_print (e, mi->text, -1);
02230          fprintf (e, "\"");
02231        }
02232 
02233       if (! menuex)
02234        {
02235          if (mi->popup == NULL)
02236            fprintf (e, ", %d", mi->id);
02237 
02238          if ((mi->type & MENUITEM_CHECKED) != 0)
02239            fprintf (e, ", CHECKED");
02240          if ((mi->type & MENUITEM_GRAYED) != 0)
02241            fprintf (e, ", GRAYED");
02242          if ((mi->type & MENUITEM_HELP) != 0)
02243            fprintf (e, ", HELP");
02244          if ((mi->type & MENUITEM_INACTIVE) != 0)
02245            fprintf (e, ", INACTIVE");
02246          if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
02247            fprintf (e, ", MENUBARBREAK");
02248          if ((mi->type & MENUITEM_MENUBREAK) != 0)
02249            fprintf (e, ", MENUBREAK");
02250        }
02251       else
02252        {
02253          if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
02254            {
02255              fprintf (e, ", %d", mi->id);
02256              if (mi->type != 0 || mi->state != 0 || mi->help != 0)
02257               {
02258                 fprintf (e, ", %lu", mi->type);
02259                 if (mi->state != 0 || mi->help != 0)
02260                   {
02261                     fprintf (e, ", %lu", mi->state);
02262                     if (mi->help != 0)
02263                      fprintf (e, ", %lu", mi->help);
02264                   }
02265               }
02266            }
02267        }
02268 
02269       fprintf (e, "\n");
02270 
02271       if (mi->popup != NULL)
02272        write_rc_menuitems (e, mi->popup, menuex, ind + 2);
02273     }
02274 
02275   indent (e, ind);
02276   fprintf (e, "END\n");
02277 }
02278 
02279 /* Write out an rcdata resource.  This is also used for other types of
02280    resources that need to print arbitrary data.  */
02281 
02282 static void
02283 write_rc_rcdata (FILE *e, const struct rcdata_item *rcdata, int ind)
02284 {
02285   const struct rcdata_item *ri;
02286 
02287   indent (e, ind);
02288   fprintf (e, "BEGIN\n");
02289 
02290   for (ri = rcdata; ri != NULL; ri = ri->next)
02291     {
02292       if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
02293        continue;
02294 
02295       indent (e, ind + 2);
02296 
02297       switch (ri->type)
02298        {
02299        default:
02300          abort ();
02301 
02302        case RCDATA_WORD:
02303          fprintf (e, "%d", ri->u.word);
02304          break;
02305 
02306        case RCDATA_DWORD:
02307          fprintf (e, "%luL", ri->u.dword);
02308          break;
02309 
02310        case RCDATA_STRING:
02311          {
02312            const char *s;
02313            unsigned long i;
02314 
02315            fprintf (e, "\"");
02316            s = ri->u.string.s;
02317            for (i = 0; i < ri->u.string.length; i++)
02318              {
02319               if (ISPRINT (*s))
02320                 putc (*s, e);
02321               else
02322                 fprintf (e, "\\%03o", *s);
02323              }
02324            fprintf (e, "\"");
02325            break;
02326          }
02327 
02328        case RCDATA_WSTRING:
02329          fprintf (e, "L\"");
02330          unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
02331          fprintf (e, "\"");
02332          break;
02333 
02334        case RCDATA_BUFFER:
02335          {
02336            unsigned long i;
02337            int first;
02338 
02339            /* Assume little endian data.  */
02340 
02341            first = 1;
02342            for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
02343              {
02344               unsigned long l;
02345               int j;
02346 
02347               if (! first)
02348                 indent (e, ind + 2);
02349               l = ((((((ri->u.buffer.data[i + 3] << 8)
02350                       | ri->u.buffer.data[i + 2]) << 8)
02351                      | ri->u.buffer.data[i + 1]) << 8)
02352                    | ri->u.buffer.data[i]);
02353               fprintf (e, "%luL", l);
02354               if (i + 4 < ri->u.buffer.length || ri->next != NULL)
02355                 fprintf (e, ",");
02356               for (j = 0; j < 4; ++j)
02357                 if (! ISPRINT (ri->u.buffer.data[i + j])
02358                     && ri->u.buffer.data[i + j] != 0)
02359                   break;
02360               if (j >= 4)
02361                 {
02362                   fprintf (e, "\t// ");
02363                   for (j = 0; j < 4; ++j)
02364                     {
02365                      if (! ISPRINT (ri->u.buffer.data[i + j]))
02366                        fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
02367                      else
02368                        {
02369                          if (ri->u.buffer.data[i + j] == '\\')
02370                            fprintf (e, "\\");
02371                          fprintf (e, "%c", ri->u.buffer.data[i + j]);
02372                        }
02373                     }
02374                 }
02375               fprintf (e, "\n");
02376               first = 0;
02377              }
02378 
02379            if (i + 1 < ri->u.buffer.length)
02380              {
02381               int s;
02382               int j;
02383 
02384               if (! first)
02385                 indent (e, ind + 2);
02386               s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
02387               fprintf (e, "%d", s);
02388               if (i + 2 < ri->u.buffer.length || ri->next != NULL)
02389                 fprintf (e, ",");
02390               for (j = 0; j < 2; ++j)
02391                 if (! ISPRINT (ri->u.buffer.data[i + j])
02392                     && ri->u.buffer.data[i + j] != 0)
02393                   break;
02394               if (j >= 2)
02395                 {
02396                   fprintf (e, "\t// ");
02397                   for (j = 0; j < 2; ++j)
02398                     {
02399                      if (! ISPRINT (ri->u.buffer.data[i + j]))
02400                        fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
02401                      else
02402                        {
02403                          if (ri->u.buffer.data[i + j] == '\\')
02404                            fprintf (e, "\\");
02405                          fprintf (e, "%c", ri->u.buffer.data[i + j]);
02406                        }
02407                     }
02408                 }
02409               fprintf (e, "\n");
02410               i += 2;
02411               first = 0;
02412              }
02413 
02414            if (i < ri->u.buffer.length)
02415              {
02416               if (! first)
02417                 indent (e, ind + 2);
02418               if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
02419                   && ISPRINT (ri->u.buffer.data[i]))
02420                 fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
02421               else
02422                 fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
02423               if (ri->next != NULL)
02424                 fprintf (e, ",");
02425               fprintf (e, "\n");
02426               first = 0;
02427              }
02428 
02429            break;
02430          }
02431        }
02432 
02433       if (ri->type != RCDATA_BUFFER)
02434        {
02435          if (ri->next != NULL)
02436            fprintf (e, ",");
02437          fprintf (e, "\n");
02438        }
02439     }
02440 
02441   indent (e, ind);
02442   fprintf (e, "END\n");
02443 }
02444 
02445 /* Write out a stringtable resource.  */
02446 
02447 static void
02448 write_rc_stringtable (FILE *e, const struct res_id *name,
02449                     const struct stringtable *stringtable)
02450 {
02451   unsigned long offset;
02452   int i;
02453 
02454   if (name != NULL && ! name->named)
02455     offset = (name->u.id - 1) << 4;
02456   else
02457     {
02458       fprintf (e, "// %s string table name\n",
02459               name == NULL ? "Missing" : "Invalid");
02460       offset = 0;
02461     }
02462 
02463   fprintf (e, "BEGIN\n");
02464 
02465   for (i = 0; i < 16; i++)
02466     {
02467       if (stringtable->strings[i].length != 0)
02468        {
02469          fprintf (e, "  %lu, \"", offset + i);
02470          unicode_print (e, stringtable->strings[i].string,
02471                       stringtable->strings[i].length);
02472          fprintf (e, "\"\n");
02473        }
02474     }
02475 
02476   fprintf (e, "END\n");
02477 }
02478 
02479 /* Write out a versioninfo resource.  */
02480 
02481 static void
02482 write_rc_versioninfo (FILE *e, const struct versioninfo *versioninfo)
02483 {
02484   const struct fixed_versioninfo *f;
02485   const struct ver_info *vi;
02486 
02487   f = versioninfo->fixed;
02488   if (f->file_version_ms != 0 || f->file_version_ls != 0)
02489     fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
02490             (f->file_version_ms >> 16) & 0xffff,
02491             f->file_version_ms & 0xffff,
02492             (f->file_version_ls >> 16) & 0xffff,
02493             f->file_version_ls & 0xffff);
02494   if (f->product_version_ms != 0 || f->product_version_ls != 0)
02495     fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
02496             (f->product_version_ms >> 16) & 0xffff,
02497             f->product_version_ms & 0xffff,
02498             (f->product_version_ls >> 16) & 0xffff,
02499             f->product_version_ls & 0xffff);
02500   if (f->file_flags_mask != 0)
02501     fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
02502   if (f->file_flags != 0)
02503     fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
02504   if (f->file_os != 0)
02505     fprintf (e, " FILEOS 0x%lx\n", f->file_os);
02506   if (f->file_type != 0)
02507     fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
02508   if (f->file_subtype != 0)
02509     fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
02510   if (f->file_date_ms != 0 || f->file_date_ls != 0)
02511     fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
02512 
02513   fprintf (e, "BEGIN\n");
02514 
02515   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
02516     {
02517       switch (vi->type)
02518        {
02519        case VERINFO_STRING:
02520          {
02521            const struct ver_stringinfo *vs;
02522 
02523            fprintf (e, "  BLOCK \"StringFileInfo\"\n");
02524            fprintf (e, "  BEGIN\n");
02525            fprintf (e, "    BLOCK \"");
02526            unicode_print (e, vi->u.string.language, -1);
02527            fprintf (e, "\"\n");
02528            fprintf (e, "    BEGIN\n");
02529 
02530            for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
02531              {
02532               fprintf (e, "      VALUE \"");
02533               unicode_print (e, vs->key, -1);
02534               fprintf (e, "\", \"");
02535               unicode_print (e, vs->value, -1);
02536               fprintf (e, "\"\n");
02537              }
02538 
02539            fprintf (e, "    END\n");
02540            fprintf (e, "  END\n");
02541            break;
02542          }
02543 
02544        case VERINFO_VAR:
02545          {
02546            const struct ver_varinfo *vv;
02547 
02548            fprintf (e, "  BLOCK \"VarFileInfo\"\n");
02549            fprintf (e, "  BEGIN\n");
02550            fprintf (e, "    VALUE \"");
02551            unicode_print (e, vi->u.var.key, -1);
02552            fprintf (e, "\"");
02553 
02554            for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
02555              fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
02556                      vv->charset);
02557 
02558            fprintf (e, "\n  END\n");
02559 
02560            break;
02561          }
02562        }
02563     }
02564 
02565   fprintf (e, "END\n");
02566 }
02567 
02568 /* Write out data which would normally be read from a file.  */
02569 
02570 static void
02571 write_rc_filedata (FILE *e, unsigned long length, const unsigned char *data)
02572 {
02573   unsigned long i;
02574 
02575   for (i = 0; i + 15 < length; i += 16)
02576     {
02577       fprintf (e, "// %4lx: ", i);
02578       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
02579               data[i + 0], data[i + 1], data[i + 2], data[i + 3],
02580               data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
02581       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
02582               data[i +  8], data[i +  9], data[i + 10], data[i + 11],
02583               data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
02584     }
02585 
02586   if (i < length)
02587     {
02588       fprintf (e, "// %4lx:", i);
02589       while (i < length)
02590        {
02591          fprintf (e, " %02x", data[i]);
02592          ++i;
02593        }
02594       fprintf (e, "\n");
02595     }
02596 }