ed6a36a4f74e92b48ea43765ff2aed7e655080bf
[external/binutils.git] / binutils / resrc.c
1 /* resrc.c -- read and write Windows rc files.
2    Copyright 1997, 1998, 1999 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Cygnus Support.
4
5    This file is part of GNU Binutils.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 /* This file contains functions that read and write Windows rc files.
23    These are text files that represent resources.  */
24
25 #include "bfd.h"
26 #include "bucomm.h"
27 #include "libiberty.h"
28 #include "windres.h"
29
30 #include <assert.h>
31 #include <ctype.h>
32 #include <sys/stat.h>
33
34 #if defined (_WIN32) && ! defined (__CYGWIN32__)
35 #define popen _popen
36 #define pclose _pclose
37 #endif
38
39 /* The default preprocessor.  */
40
41 #define DEFAULT_PREPROCESSOR "gcc -E -xc-header -DRC_INVOKED"
42
43 /* We read the directory entries in a cursor or icon file into
44    instances of this structure.  */
45
46 struct icondir
47 {
48   /* Width of image.  */
49   unsigned char width;
50   /* Height of image.  */
51   unsigned char height;
52   /* Number of colors in image.  */
53   unsigned char colorcount;
54   union
55   {
56     struct
57     {
58       /* Color planes.  */
59       unsigned short planes;
60       /* Bits per pixel.  */
61       unsigned short bits;
62     } icon;
63     struct
64     {
65       /* X coordinate of hotspot.  */
66       unsigned short xhotspot;
67       /* Y coordinate of hotspot.  */
68       unsigned short yhotspot;
69     } cursor;
70   } u;
71   /* Bytes in image.  */
72   unsigned long bytes;
73   /* File offset of image.  */
74   unsigned long offset;
75 };
76
77 /* The name of the rc file we are reading.  */
78
79 char *rc_filename;
80
81 /* The line number in the rc file.  */
82
83 int rc_lineno;
84
85 /* The pipe we are reading from, so that we can close it if we exit.  */
86
87 static FILE *cpp_pipe;
88
89 /* As we read the rc file, we attach information to this structure.  */
90
91 static struct res_directory *resources;
92
93 /* The number of cursor resources we have written out.  */
94
95 static int cursors;
96
97 /* The number of font resources we have written out.  */
98
99 static int fonts;
100
101 /* Font directory information.  */
102
103 struct fontdir *fontdirs;
104
105 /* Resource info to use for fontdirs.  */
106
107 struct res_res_info fontdirs_resinfo;
108
109 /* The number of icon resources we have written out.  */
110
111 static int icons;
112
113 /* Local functions.  */
114
115 static FILE *look_for_default PARAMS ((char *, const char *, int,
116                                        const char *, const char *));
117 static void close_pipe PARAMS ((void));
118 static void unexpected_eof PARAMS ((const char *));
119 static int get_word PARAMS ((FILE *, const char *));
120 static unsigned long get_long PARAMS ((FILE *, const char *));
121 static void get_data
122   PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
123 static void define_fontdirs PARAMS ((void));
124 \f
125 /* look for the preprocessor program */
126
127 static FILE *
128 look_for_default (cmd, prefix, end_prefix, preprocargs, filename)
129      char *cmd;
130      const char *prefix;
131      int end_prefix;
132      const char *preprocargs;
133      const char *filename;
134 {
135   char *space;
136   int found;
137   struct stat s;
138
139   strcpy (cmd, prefix);
140
141   sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
142   space = strchr (cmd + end_prefix, ' ');
143   if (space)
144     *space = 0;
145
146   if (strchr (cmd, '/'))
147     {
148       found = (stat (cmd, &s) == 0
149 #ifdef EXECUTABLE_SUFFIX
150                || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
151 #endif
152                );
153
154       if (! found)
155         {
156           if (verbose)
157             fprintf (stderr, "Tried `%s'\n", cmd);
158           return NULL;
159         }
160     }
161
162   strcpy (cmd, prefix);
163
164   sprintf (cmd + end_prefix, "%s %s %s",
165            DEFAULT_PREPROCESSOR, preprocargs, filename);
166
167   if (verbose)
168     fprintf (stderr, "Using `%s'\n", cmd);
169
170   cpp_pipe = popen (cmd, FOPEN_RT);
171   return cpp_pipe;
172 }
173
174 /* Read an rc file.  */
175
176 struct res_directory *
177 read_rc_file (filename, preprocessor, preprocargs, language)
178      const char *filename;
179      const char *preprocessor;
180      const char *preprocargs;
181      int language;
182 {
183   char *cmd;
184
185   if (preprocargs == NULL)
186     preprocargs = "";
187   if (filename == NULL)
188     filename = "-";
189
190   if (preprocessor)
191     {
192       cmd = xmalloc (strlen (preprocessor)
193                      + strlen (preprocargs)
194                      + strlen (filename)
195                      + 10);
196       sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
197
198       cpp_pipe = popen (cmd, FOPEN_RT);
199     }
200   else
201     {
202       char *dash, *slash, *cp;
203
204       preprocessor = DEFAULT_PREPROCESSOR;
205
206       cmd = xmalloc (strlen (program_name)
207                      + strlen (preprocessor)
208                      + strlen (preprocargs)
209                      + strlen (filename)
210 #ifdef EXECUTABLE_SUFFIX
211                      + strlen (EXECUTABLE_SUFFIX)
212 #endif
213                      + 10);
214
215
216       dash = slash = 0;
217       for (cp = program_name; *cp; cp++)
218         {
219           if (*cp == '-')
220             dash = cp;
221           if (
222 #if defined(__DJGPP__) || defined (__CYGWIN__) || defined(__WIN32__)
223               *cp == ':' || *cp == '\\' ||
224 #endif
225               *cp == '/')
226             {
227               slash = cp;
228               dash = 0;
229             }
230         }
231
232       cpp_pipe = 0;
233
234       if (dash)
235         {
236           /* First, try looking for a prefixed gcc in the windres
237              directory, with the same prefix as windres */
238
239           cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1,
240                                        preprocargs, filename);
241         }
242
243       if (slash && !cpp_pipe)
244         {
245           /* Next, try looking for a gcc in the same directory as
246              that windres */
247
248           cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1,
249                                        preprocargs, filename);
250         }
251
252       if (!cpp_pipe)
253         {
254           /* Sigh, try the default */
255
256           cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
257         }
258
259     }
260   if (cpp_pipe == NULL)
261     fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
262   free (cmd);
263
264   xatexit (close_pipe);
265
266   rc_filename = xstrdup (filename);
267   rc_lineno = 1;
268   if (language != -1)
269     rcparse_set_language (language);
270   yyin = cpp_pipe;
271   yyparse ();
272
273   if (pclose (cpp_pipe) != 0)
274     fprintf (stderr, _("%s: warning: preprocessor failed\n"), program_name);
275   cpp_pipe = NULL;
276
277   if (fontdirs != NULL)
278     define_fontdirs ();
279
280   free (rc_filename);
281   rc_filename = NULL;
282
283   return resources;
284 }
285
286 /* Close the pipe if it is open.  This is called via xatexit.  */
287
288 void
289 close_pipe ()
290 {
291   if (cpp_pipe != NULL)
292     pclose (cpp_pipe);
293 }
294
295 /* Report an error while reading an rc file.  */
296
297 void
298 yyerror (msg)
299      const char *msg;
300 {
301   fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
302 }
303
304 /* Issue a warning while reading an rc file.  */
305
306 void
307 rcparse_warning (msg)
308      const char *msg;
309 {
310   fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
311 }
312
313 /* Die if we get an unexpected end of file.  */
314
315 static void
316 unexpected_eof (msg)
317      const char *msg;
318 {
319   fatal (_("%s: unexpected EOF"), msg);
320 }
321
322 /* Read a 16 bit word from a file.  The data is assumed to be little
323    endian.  */
324
325 static int
326 get_word (e, msg)
327      FILE *e;
328      const char *msg;
329 {
330   int b1, b2;
331
332   b1 = getc (e);
333   b2 = getc (e);
334   if (feof (e))
335     unexpected_eof (msg);
336   return ((b2 & 0xff) << 8) | (b1 & 0xff);
337 }
338
339 /* Read a 32 bit word from a file.  The data is assumed to be little
340    endian.  */
341
342 static unsigned long
343 get_long (e, msg)
344      FILE *e;
345      const char *msg;
346 {
347   int b1, b2, b3, b4;
348
349   b1 = getc (e);
350   b2 = getc (e);
351   b3 = getc (e);
352   b4 = getc (e);
353   if (feof (e))
354     unexpected_eof (msg);
355   return (((((((b4 & 0xff) << 8)
356               | (b3 & 0xff)) << 8)
357             | (b2 & 0xff)) << 8)
358           | (b1 & 0xff));
359 }
360
361 /* Read data from a file.  This is a wrapper to do error checking.  */
362
363 static void
364 get_data (e, p, c, msg)
365      FILE *e;
366      unsigned char *p;
367      unsigned long c;
368      const char *msg;
369 {
370   unsigned long got;
371
372   got = fread (p, 1, c, e);
373   if (got == c)
374     return;
375
376   fatal (_("%s: read of %lu returned %lu"), msg, c, got);
377 }
378 \f
379 /* Define an accelerator resource.  */
380
381 void
382 define_accelerator (id, resinfo, data)
383      struct res_id id;
384      const struct res_res_info *resinfo;
385      struct accelerator *data;
386 {
387   struct res_resource *r;
388
389   r = define_standard_resource (&resources, RT_ACCELERATOR, id,
390                                 resinfo->language, 0);
391   r->type = RES_TYPE_ACCELERATOR;
392   r->u.acc = data;
393   r->res_info = *resinfo;
394 }
395
396 /* Define a bitmap resource.  Bitmap data is stored in a file.  The
397    first 14 bytes of the file are a standard header, which is not
398    included in the resource data.  */
399
400 #define BITMAP_SKIP (14)
401
402 void
403 define_bitmap (id, resinfo, filename)
404      struct res_id id;
405      const struct res_res_info *resinfo;
406      const char *filename;
407 {
408   FILE *e;
409   char *real_filename;
410   struct stat s;
411   unsigned char *data;
412   int i;
413   struct res_resource *r;
414
415   e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
416
417   if (stat (real_filename, &s) < 0)
418     fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
419            strerror (errno));
420
421   data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
422
423   for (i = 0; i < BITMAP_SKIP; i++)
424     getc (e);
425
426   get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
427
428   fclose (e);
429   free (real_filename);
430
431   r = define_standard_resource (&resources, RT_BITMAP, id,
432                                 resinfo->language, 0);
433
434   r->type = RES_TYPE_BITMAP;
435   r->u.data.length = s.st_size - BITMAP_SKIP;
436   r->u.data.data = data;
437   r->res_info = *resinfo;
438 }
439
440 /* Define a cursor resource.  A cursor file may contain a set of
441    bitmaps, each representing the same cursor at various different
442    resolutions.  They each get written out with a different ID.  The
443    real cursor resource is then a group resource which can be used to
444    select one of the actual cursors.  */
445
446 void
447 define_cursor (id, resinfo, filename)
448      struct res_id id;
449      const struct res_res_info *resinfo;
450      const char *filename;
451 {
452   FILE *e;
453   char *real_filename;
454   int type, count, i;
455   struct icondir *icondirs;
456   int first_cursor;
457   struct res_resource *r;
458   struct group_cursor *first, **pp;
459
460   e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
461
462   /* A cursor file is basically an icon file.  The start of the file
463      is a three word structure.  The first word is ignored.  The
464      second word is the type of data.  The third word is the number of
465      entries.  */
466
467   get_word (e, real_filename);
468   type = get_word (e, real_filename);
469   count = get_word (e, real_filename);
470   if (type != 2)
471     fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
472
473   /* Read in the icon directory entries.  */
474
475   icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
476
477   for (i = 0; i < count; i++)
478     {
479       icondirs[i].width = getc (e);
480       icondirs[i].height = getc (e);
481       icondirs[i].colorcount = getc (e);
482       getc (e);
483       icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
484       icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
485       icondirs[i].bytes = get_long (e, real_filename);
486       icondirs[i].offset = get_long (e, real_filename);
487
488       if (feof (e))
489         unexpected_eof (real_filename);
490     }
491
492   /* Define each cursor as a unique resource.  */
493
494   first_cursor = cursors;
495
496   for (i = 0; i < count; i++)
497     {
498       unsigned char *data;
499       struct res_id name;
500       struct cursor *c;
501
502       if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
503         fatal (_("%s: fseek to %lu failed: %s"), real_filename,
504                icondirs[i].offset, strerror (errno));
505
506       data = (unsigned char *) res_alloc (icondirs[i].bytes);
507
508       get_data (e, data, icondirs[i].bytes, real_filename);
509
510       c = (struct cursor *) res_alloc (sizeof *c);
511       c->xhotspot = icondirs[i].u.cursor.xhotspot;
512       c->yhotspot = icondirs[i].u.cursor.yhotspot;
513       c->length = icondirs[i].bytes;
514       c->data = data;
515
516       ++cursors;
517
518       name.named = 0;
519       name.u.id = cursors;
520
521       r = define_standard_resource (&resources, RT_CURSOR, name,
522                                     resinfo->language, 0);
523       r->type = RES_TYPE_CURSOR;
524       r->u.cursor = c;
525       r->res_info = *resinfo;
526     }
527
528   fclose (e);
529   free (real_filename);
530
531   /* Define a cursor group resource.  */
532
533   first = NULL;
534   pp = &first;
535   for (i = 0; i < count; i++)
536     {
537       struct group_cursor *cg;
538
539       cg = (struct group_cursor *) res_alloc (sizeof *cg);
540       cg->next = NULL;
541       cg->width = icondirs[i].width;
542       cg->height = 2 * icondirs[i].height;
543
544       /* FIXME: What should these be set to?  */
545       cg->planes = 1;
546       cg->bits = 1;
547
548       cg->bytes = icondirs[i].bytes + 4;
549       cg->index = first_cursor + i + 1;
550
551       *pp = cg;
552       pp = &(*pp)->next;
553     }
554
555   free (icondirs);
556
557   r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
558                                 resinfo->language, 0);
559   r->type = RES_TYPE_GROUP_CURSOR;
560   r->u.group_cursor = first;
561   r->res_info = *resinfo;
562 }
563
564 /* Define a dialog resource.  */
565
566 void
567 define_dialog (id, resinfo, dialog)
568      struct res_id id;
569      const struct res_res_info *resinfo;
570      const struct dialog *dialog;
571 {
572   struct dialog *copy;
573   struct res_resource *r;
574
575   copy = (struct dialog *) res_alloc (sizeof *copy);
576   *copy = *dialog;
577
578   r = define_standard_resource (&resources, RT_DIALOG, id,
579                                 resinfo->language, 0);
580   r->type = RES_TYPE_DIALOG;
581   r->u.dialog = copy;
582   r->res_info = *resinfo;
583 }
584
585 /* Define a dialog control.  This does not define a resource, but
586    merely allocates and fills in a structure.  */
587
588 struct dialog_control *
589 define_control (text, id, x, y, width, height, class, style, exstyle)
590      const char *text;
591      unsigned long id;
592      unsigned long x;
593      unsigned long y;
594      unsigned long width;
595      unsigned long height;
596      unsigned long class;
597      unsigned long style;
598      unsigned long exstyle;
599 {
600   struct dialog_control *n;
601
602   n = (struct dialog_control *) res_alloc (sizeof *n);
603   n->next = NULL;
604   n->id = id;
605   n->style = style;
606   n->exstyle = exstyle;
607   n->x = x;
608   n->y = y;
609   n->width = width;
610   n->height = height;
611   n->class.named = 0;
612   n->class.u.id = class;
613   if (text != NULL)
614     res_string_to_id (&n->text, text);
615   else
616     {
617       n->text.named = 0;
618       n->text.u.id = 0;
619     }
620   n->data = NULL;
621   n->help = 0;
622
623   return n;
624 }
625
626 /* Define a font resource.  */
627
628 void
629 define_font (id, resinfo, filename)
630      struct res_id id;
631      const struct res_res_info *resinfo;
632      const char *filename;
633 {
634   FILE *e;
635   char *real_filename;
636   struct stat s;
637   unsigned char *data;
638   struct res_resource *r;
639   long offset;
640   long fontdatalength;
641   unsigned char *fontdata;
642   struct fontdir *fd;
643   const char *device, *face;
644   struct fontdir **pp;
645
646   e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
647
648   if (stat (real_filename, &s) < 0)
649     fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
650            strerror (errno));
651
652   data = (unsigned char *) res_alloc (s.st_size);
653
654   get_data (e, data, s.st_size, real_filename);
655
656   fclose (e);
657   free (real_filename);
658
659   r = define_standard_resource (&resources, RT_FONT, id,
660                                 resinfo->language, 0);
661
662   r->type = RES_TYPE_FONT;
663   r->u.data.length = s.st_size;
664   r->u.data.data = data;
665   r->res_info = *resinfo;
666
667   /* For each font resource, we must add an entry in the FONTDIR
668      resource.  The FONTDIR resource includes some strings in the font
669      file.  To find them, we have to do some magic on the data we have
670      read.  */
671
672   offset = ((((((data[47] << 8)
673                 | data[46]) << 8)
674               | data[45]) << 8)
675             | data[44]);
676   if (offset > 0 && offset < s.st_size)
677     device = (char *) data + offset;
678   else
679     device = "";
680
681   offset = ((((((data[51] << 8)
682                 | data[50]) << 8)
683               | data[49]) << 8)
684             | data[48]);
685   if (offset > 0 && offset < s.st_size)
686     face = (char *) data + offset;
687   else
688     face = "";
689
690   ++fonts;
691
692   fontdatalength = 58 + strlen (device) + strlen (face);
693   fontdata = (unsigned char *) res_alloc (fontdatalength);
694   memcpy (fontdata, data, 56);
695   strcpy ((char *) fontdata + 56, device);
696   strcpy ((char *) fontdata + 57 + strlen (device), face);
697
698   fd = (struct fontdir *) res_alloc (sizeof *fd);
699   fd->next = NULL;
700   fd->index = fonts;
701   fd->length = fontdatalength;
702   fd->data = fontdata;
703
704   for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
705     ;
706   *pp = fd;
707
708   /* For the single fontdirs resource, we always use the resource
709      information of the last font.  I don't know what else to do.  */
710   fontdirs_resinfo = *resinfo;
711 }
712
713 /* Define the fontdirs resource.  This is called after the entire rc
714    file has been parsed, if any font resources were seen.  */
715
716 static void
717 define_fontdirs ()
718 {
719   struct res_resource *r;
720   struct res_id id;
721
722   id.named = 0;
723   id.u.id = 1;
724
725   r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
726
727   r->type = RES_TYPE_FONTDIR;
728   r->u.fontdir = fontdirs;
729   r->res_info = fontdirs_resinfo;
730 }
731
732 /* Define an icon resource.  An icon file may contain a set of
733    bitmaps, each representing the same icon at various different
734    resolutions.  They each get written out with a different ID.  The
735    real icon resource is then a group resource which can be used to
736    select one of the actual icon bitmaps.  */
737
738 void
739 define_icon (id, resinfo, filename)
740      struct res_id id;
741      const struct res_res_info *resinfo;
742      const char *filename;
743 {
744   FILE *e;
745   char *real_filename;
746   int type, count, i;
747   struct icondir *icondirs;
748   int first_icon;
749   struct res_resource *r;
750   struct group_icon *first, **pp;
751
752   e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
753
754   /* The start of an icon file is a three word structure.  The first
755      word is ignored.  The second word is the type of data.  The third
756      word is the number of entries.  */
757
758   get_word (e, real_filename);
759   type = get_word (e, real_filename);
760   count = get_word (e, real_filename);
761   if (type != 1)
762     fatal (_("icon file `%s' does not contain icon data"), real_filename);
763
764   /* Read in the icon directory entries.  */
765
766   icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
767
768   for (i = 0; i < count; i++)
769     {
770       icondirs[i].width = getc (e);
771       icondirs[i].height = getc (e);
772       icondirs[i].colorcount = getc (e);
773       getc (e);
774       icondirs[i].u.icon.planes = get_word (e, real_filename);
775       icondirs[i].u.icon.bits = get_word (e, real_filename);
776       icondirs[i].bytes = get_long (e, real_filename);
777       icondirs[i].offset = get_long (e, real_filename);
778
779       if (feof (e))
780         unexpected_eof (real_filename);
781     }
782
783   /* Define each icon as a unique resource.  */
784
785   first_icon = icons;
786
787   for (i = 0; i < count; i++)
788     {
789       unsigned char *data;
790       struct res_id name;
791
792       if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
793         fatal (_("%s: fseek to %lu failed: %s"), real_filename,
794                icondirs[i].offset, strerror (errno));
795
796       data = (unsigned char *) res_alloc (icondirs[i].bytes);
797
798       get_data (e, data, icondirs[i].bytes, real_filename);
799
800       ++icons;
801
802       name.named = 0;
803       name.u.id = icons;
804
805       r = define_standard_resource (&resources, RT_ICON, name,
806                                     resinfo->language, 0);
807       r->type = RES_TYPE_ICON;
808       r->u.data.length = icondirs[i].bytes;
809       r->u.data.data = data;
810       r->res_info = *resinfo;
811     }
812
813   fclose (e);
814   free (real_filename);
815
816   /* Define an icon group resource.  */
817
818   first = NULL;
819   pp = &first;
820   for (i = 0; i < count; i++)
821     {
822       struct group_icon *cg;
823
824       /* For some reason, at least in some files the planes and bits
825          are zero.  We instead set them from the color.  This is
826          copied from rcl.  */
827
828       cg = (struct group_icon *) res_alloc (sizeof *cg);
829       cg->next = NULL;
830       cg->width = icondirs[i].width;
831       cg->height = icondirs[i].height;
832       cg->colors = icondirs[i].colorcount;
833
834       cg->planes = 1;
835       cg->bits = 0;
836       while ((1 << cg->bits) < cg->colors)
837         ++cg->bits;
838
839       cg->bytes = icondirs[i].bytes;
840       cg->index = first_icon + i + 1;
841
842       *pp = cg;
843       pp = &(*pp)->next;
844     }
845
846   free (icondirs);
847
848   r = define_standard_resource (&resources, RT_GROUP_ICON, id,
849                                 resinfo->language, 0);
850   r->type = RES_TYPE_GROUP_ICON;
851   r->u.group_icon = first;
852   r->res_info = *resinfo;
853 }
854
855 /* Define a menu resource.  */
856
857 void
858 define_menu (id, resinfo, menuitems)
859      struct res_id id;
860      const struct res_res_info *resinfo;
861      struct menuitem *menuitems;
862 {
863   struct menu *m;
864   struct res_resource *r;
865
866   m = (struct menu *) res_alloc (sizeof *m);
867   m->items = menuitems;
868   m->help = 0;
869
870   r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
871   r->type = RES_TYPE_MENU;
872   r->u.menu = m;
873   r->res_info = *resinfo;
874 }
875
876 /* Define a menu item.  This does not define a resource, but merely
877    allocates and fills in a structure.  */
878
879 struct menuitem *
880 define_menuitem (text, menuid, type, state, help, menuitems)
881      const char *text;
882      int menuid;
883      unsigned long type;
884      unsigned long state;
885      unsigned long help;
886      struct menuitem *menuitems;
887 {
888   struct menuitem *mi;
889
890   mi = (struct menuitem *) res_alloc (sizeof *mi);
891   mi->next = NULL;
892   mi->type = type;
893   mi->state = state;
894   mi->id = menuid;
895   if (text == NULL)
896     mi->text = NULL;
897   else
898     unicode_from_ascii ((int *) NULL, &mi->text, text);
899   mi->help = help;
900   mi->popup = menuitems;
901   return mi;
902 }
903
904 /* Define a messagetable resource.  */
905
906 void
907 define_messagetable (id, resinfo, filename)
908      struct res_id id;
909      const struct res_res_info *resinfo;
910      const char *filename;
911 {
912   FILE *e;
913   char *real_filename;
914   struct stat s;
915   unsigned char *data;
916   struct res_resource *r;
917
918   e = open_file_search (filename, FOPEN_RB, "messagetable file",
919                         &real_filename);
920
921   if (stat (real_filename, &s) < 0)
922     fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
923            strerror (errno));
924
925   data = (unsigned char *) res_alloc (s.st_size);
926
927   get_data (e, data, s.st_size, real_filename);
928
929   fclose (e);
930   free (real_filename);
931
932   r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
933                                 resinfo->language, 0);
934
935   r->type = RES_TYPE_MESSAGETABLE;
936   r->u.data.length = s.st_size;
937   r->u.data.data = data;
938   r->res_info = *resinfo;
939 }
940
941 /* Define an rcdata resource.  */
942
943 void
944 define_rcdata (id, resinfo, data)
945      struct res_id id;
946      const struct res_res_info *resinfo;
947      struct rcdata_item *data;
948 {
949   struct res_resource *r;
950
951   r = define_standard_resource (&resources, RT_RCDATA, id,
952                                 resinfo->language, 0);
953   r->type = RES_TYPE_RCDATA;
954   r->u.rcdata = data;
955   r->res_info = *resinfo;
956 }
957
958 /* Create an rcdata item holding a string.  */
959
960 struct rcdata_item *
961 define_rcdata_string (string, len)
962      const char *string;
963      unsigned long len;
964 {
965   struct rcdata_item *ri;
966   char *s;
967
968   ri = (struct rcdata_item *) res_alloc (sizeof *ri);
969   ri->next = NULL;
970   ri->type = RCDATA_STRING;
971   ri->u.string.length = len;
972   s = (char *) res_alloc (len);
973   memcpy (s, string, len);
974   ri->u.string.s = s;
975
976   return ri;
977 }
978
979 /* Create an rcdata item holding a number.  */
980
981 struct rcdata_item *
982 define_rcdata_number (val, dword)
983      unsigned long val;
984      int dword;
985 {
986   struct rcdata_item *ri;
987
988   ri = (struct rcdata_item *) res_alloc (sizeof *ri);
989   ri->next = NULL;
990   ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
991   ri->u.word = val;
992
993   return ri;
994 }
995
996 /* Define a stringtable resource.  This is called for each string
997    which appears in a STRINGTABLE statement.  */
998
999 void
1000 define_stringtable (resinfo, stringid, string)
1001      const struct res_res_info *resinfo;
1002      unsigned long stringid;
1003      const char *string;
1004 {
1005   struct res_id id;
1006   struct res_resource *r;
1007
1008   id.named = 0;
1009   id.u.id = (stringid >> 4) + 1;
1010   r = define_standard_resource (&resources, RT_STRING, id,
1011                                 resinfo->language, 1);
1012
1013   if (r->type == RES_TYPE_UNINITIALIZED)
1014     {
1015       int i;
1016
1017       r->type = RES_TYPE_STRINGTABLE;
1018       r->u.stringtable = ((struct stringtable *)
1019                           res_alloc (sizeof (struct stringtable)));
1020       for (i = 0; i < 16; i++)
1021         {
1022           r->u.stringtable->strings[i].length = 0;
1023           r->u.stringtable->strings[i].string = NULL;
1024         }
1025
1026       r->res_info = *resinfo;
1027     }
1028
1029   unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
1030                       &r->u.stringtable->strings[stringid & 0xf].string,
1031                       string);
1032 }
1033
1034 /* Define a user data resource where the data is in the rc file.  */
1035
1036 void
1037 define_user_data (id, type, resinfo, data)
1038      struct res_id id;
1039      struct res_id type;
1040      const struct res_res_info *resinfo;
1041      struct rcdata_item *data;
1042 {
1043   struct res_id ids[3];
1044   struct res_resource *r;
1045
1046   ids[0] = type;
1047   ids[1] = id;
1048   ids[2].named = 0;
1049   ids[2].u.id = resinfo->language;
1050
1051   r = define_resource (&resources, 3, ids, 0);
1052   r->type = RES_TYPE_USERDATA;
1053   r->u.userdata = data;
1054   r->res_info = *resinfo;
1055 }
1056
1057 /* Define a user data resource where the data is in a file.  */
1058
1059 void
1060 define_user_file (id, type, resinfo, filename)
1061      struct res_id id;
1062      struct res_id type;
1063      const struct res_res_info *resinfo;
1064      const char *filename;
1065 {
1066   FILE *e;
1067   char *real_filename;
1068   struct stat s;
1069   unsigned char *data;
1070   struct res_id ids[3];
1071   struct res_resource *r;
1072
1073   e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
1074
1075   if (stat (real_filename, &s) < 0)
1076     fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1077            strerror (errno));
1078
1079   data = (unsigned char *) res_alloc (s.st_size);
1080
1081   get_data (e, data, s.st_size, real_filename);
1082
1083   fclose (e);
1084   free (real_filename);
1085
1086   ids[0] = type;
1087   ids[1] = id;
1088   ids[2].named = 0;
1089   ids[2].u.id = resinfo->language;
1090
1091   r = define_resource (&resources, 3, ids, 0);
1092   r->type = RES_TYPE_USERDATA;
1093   r->u.userdata = ((struct rcdata_item *)
1094                    res_alloc (sizeof (struct rcdata_item)));
1095   r->u.userdata->next = NULL;
1096   r->u.userdata->type = RCDATA_BUFFER;
1097   r->u.userdata->u.buffer.length = s.st_size;
1098   r->u.userdata->u.buffer.data = data;
1099   r->res_info = *resinfo;
1100 }
1101
1102 /* Define a versioninfo resource.  */
1103
1104 void
1105 define_versioninfo (id, language, fixedverinfo, verinfo)
1106      struct res_id id;
1107      int language;
1108      struct fixed_versioninfo *fixedverinfo;
1109      struct ver_info *verinfo;
1110 {
1111   struct res_resource *r;
1112
1113   r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1114   r->type = RES_TYPE_VERSIONINFO;
1115   r->u.versioninfo = ((struct versioninfo *)
1116                       res_alloc (sizeof (struct versioninfo)));
1117   r->u.versioninfo->fixed = fixedverinfo;
1118   r->u.versioninfo->var = verinfo;
1119   r->res_info.language = language;
1120 }
1121
1122 /* Add string version info to a list of version information.  */
1123
1124 struct ver_info *
1125 append_ver_stringfileinfo (verinfo, language, strings)
1126      struct ver_info *verinfo;
1127      const char *language;
1128      struct ver_stringinfo *strings;
1129 {
1130   struct ver_info *vi, **pp;
1131
1132   vi = (struct ver_info *) res_alloc (sizeof *vi);
1133   vi->next = NULL;
1134   vi->type = VERINFO_STRING;
1135   unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
1136   vi->u.string.strings = strings;
1137
1138   for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1139     ;
1140   *pp = vi;
1141
1142   return verinfo;
1143 }
1144
1145 /* Add variable version info to a list of version information.  */
1146
1147 struct ver_info *
1148 append_ver_varfileinfo (verinfo, key, var)
1149      struct ver_info *verinfo;
1150      const char *key;
1151      struct ver_varinfo *var;
1152 {
1153   struct ver_info *vi, **pp;
1154
1155   vi = (struct ver_info *) res_alloc (sizeof *vi);
1156   vi->next = NULL;
1157   vi->type = VERINFO_VAR;
1158   unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
1159   vi->u.var.var = var;
1160
1161   for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1162     ;
1163   *pp = vi;
1164
1165   return verinfo;
1166 }
1167
1168 /* Append version string information to a list.  */
1169
1170 struct ver_stringinfo *
1171 append_verval (strings, key, value)
1172      struct ver_stringinfo *strings;
1173      const char *key;
1174      const char *value;
1175 {
1176   struct ver_stringinfo *vs, **pp;
1177
1178   vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
1179   vs->next = NULL;
1180   unicode_from_ascii ((int *) NULL, &vs->key, key);
1181   unicode_from_ascii ((int *) NULL, &vs->value, value);
1182
1183   for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1184     ;
1185   *pp = vs;
1186
1187   return strings;
1188 }
1189
1190 /* Append version variable information to a list.  */
1191
1192 struct ver_varinfo *
1193 append_vertrans (var, language, charset)
1194      struct ver_varinfo *var;
1195      unsigned long language;
1196      unsigned long charset;
1197 {
1198   struct ver_varinfo *vv, **pp;
1199
1200   vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
1201   vv->next = NULL;
1202   vv->language = language;
1203   vv->charset = charset;
1204
1205   for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1206     ;
1207   *pp = vv;
1208
1209   return var;
1210 }
1211 \f
1212 /* Local functions used to write out an rc file.  */
1213
1214 static void indent PARAMS ((FILE *, int));
1215 static void write_rc_directory
1216   PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
1217            const struct res_id *, int *, int));
1218 static void write_rc_subdir
1219   PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
1220            const struct res_id *, int *, int));
1221 static void write_rc_resource
1222   PARAMS ((FILE *, const struct res_id *, const struct res_id *,
1223            const struct res_resource *, int *));
1224 static void write_rc_accelerators
1225   PARAMS ((FILE *, const struct accelerator *));
1226 static void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
1227 static void write_rc_group_cursor
1228   PARAMS ((FILE *, const struct group_cursor *));
1229 static void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
1230 static void write_rc_dialog_control
1231   PARAMS ((FILE *, const struct dialog_control *));
1232 static void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
1233 static void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
1234 static void write_rc_menu PARAMS ((FILE *, const struct menu *, int));
1235 static void write_rc_menuitems
1236   PARAMS ((FILE *, const struct menuitem *, int, int));
1237 static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_item *, int));
1238 static void write_rc_stringtable
1239   PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
1240 static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
1241 static void write_rc_filedata
1242   PARAMS ((FILE *, unsigned long, const unsigned char *));
1243
1244 /* Indent a given number of spaces.  */
1245
1246 static void
1247 indent (e, c)
1248      FILE *e;
1249      int c;
1250 {
1251   int i;
1252
1253   for (i = 0; i < c; i++)
1254     putc (' ', e);
1255 }
1256
1257 /* Dump the resources we have read in the format of an rc file.
1258
1259    Actually, we don't use the format of an rc file, because it's way
1260    too much of a pain--for example, we'd have to write icon resources
1261    into a file and refer to that file.  We just generate a readable
1262    format that kind of looks like an rc file, and is useful for
1263    understanding the contents of a resource file.  Someday we may want
1264    to generate an rc file which the rc compiler can read; if that day
1265    comes, this code will have to be fixed up.  */
1266
1267 void
1268 write_rc_file (filename, resources)
1269      const char *filename;
1270      const struct res_directory *resources;
1271 {
1272   FILE *e;
1273   int language;
1274
1275   if (filename == NULL)
1276     e = stdout;
1277   else
1278     {
1279       e = fopen (filename, FOPEN_WT);
1280       if (e == NULL)
1281         fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1282     }
1283
1284   language = -1;
1285   write_rc_directory (e, resources, (const struct res_id *) NULL,
1286                       (const struct res_id *) NULL, &language, 1);
1287 }
1288
1289 /* Write out a directory.  E is the file to write to.  RD is the
1290    directory.  TYPE is a pointer to the level 1 ID which serves as the
1291    resource type.  NAME is a pointer to the level 2 ID which serves as
1292    an individual resource name.  LANGUAGE is a pointer to the current
1293    language.  LEVEL is the level in the tree.  */
1294
1295 static void
1296 write_rc_directory (e, rd, type, name, language, level)
1297      FILE *e;
1298      const struct res_directory *rd;
1299      const struct res_id *type;
1300      const struct res_id *name;
1301      int *language;
1302      int level;
1303 {
1304   const struct res_entry *re;
1305
1306   /* Print out some COFF information that rc files can't represent.  */
1307
1308   if (rd->time != 0)
1309     fprintf (e, "// Time stamp: %lu\n", rd->time);
1310   if (rd->characteristics != 0)
1311     fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
1312   if (rd->major != 0 || rd->minor != 0)
1313     fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
1314
1315   for (re = rd->entries;  re != NULL; re = re->next)
1316     {
1317       switch (level)
1318         {
1319         case 1:
1320           /* If we're at level 1, the key of this resource is the
1321              type.  This normally duplicates the information we have
1322              stored with the resource itself, but we need to remember
1323              the type if this is a user define resource type.  */
1324           type = &re->id;
1325           break;
1326
1327         case 2:
1328           /* If we're at level 2, the key of this resource is the name
1329              we are going to use in the rc printout. */
1330           name = &re->id;
1331           break;
1332
1333         case 3:
1334           /* If we're at level 3, then this key represents a language.
1335              Use it to update the current language.  */
1336           if (! re->id.named
1337               && re->id.u.id != (unsigned long) (unsigned int) *language
1338               && (re->id.u.id & 0xffff) == re->id.u.id)
1339             {
1340               fprintf (e, "LANGUAGE %lu, %lu\n",
1341                        re->id.u.id & 0xff, (re->id.u.id >> 8) & 0xff);
1342               *language = re->id.u.id;
1343             }
1344           break;
1345
1346         default:
1347           break;
1348         }
1349
1350       if (re->subdir)
1351         write_rc_subdir (e, re, type, name, language, level);
1352       else
1353         {
1354           if (level == 3)
1355             {
1356               /* This is the normal case: the three levels are
1357                  TYPE/NAME/LANGUAGE.  NAME will have been set at level
1358                  2, and represents the name to use.  We probably just
1359                  set LANGUAGE, and it will probably match what the
1360                  resource itself records if anything.  */
1361               write_rc_resource (e, type, name, re->u.res, language);
1362             }
1363           else
1364             {
1365               fprintf (e, "// Resource at unexpected level %d\n", level);
1366               write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1367                                  language);
1368             }
1369         }
1370     }
1371 }
1372
1373 /* Write out a subdirectory entry.  E is the file to write to.  RE is
1374    the subdirectory entry.  TYPE and NAME are pointers to higher level
1375    IDs, or NULL.  LANGUAGE is a pointer to the current language.
1376    LEVEL is the level in the tree.  */
1377
1378 static void
1379 write_rc_subdir (e, re, type, name, language, level)
1380      FILE *e;
1381      const struct res_entry *re;
1382      const struct res_id *type;
1383      const struct res_id *name;
1384      int *language;
1385      int level;
1386 {
1387   fprintf (e, "\n");
1388   switch (level)
1389     {
1390     case 1:
1391       fprintf (e, "// Type: ");
1392       if (re->id.named)
1393         res_id_print (e, re->id, 1);
1394       else
1395         {
1396           const char *s;
1397
1398           switch (re->id.u.id)
1399             {
1400             case RT_CURSOR: s = "cursor"; break;
1401             case RT_BITMAP: s = "bitmap"; break;
1402             case RT_ICON: s = "icon"; break;
1403             case RT_MENU: s = "menu"; break;
1404             case RT_DIALOG: s = "dialog"; break;
1405             case RT_STRING: s = "stringtable"; break;
1406             case RT_FONTDIR: s = "fontdir"; break;
1407             case RT_FONT: s = "font"; break;
1408             case RT_ACCELERATOR: s = "accelerators"; break;
1409             case RT_RCDATA: s = "rcdata"; break;
1410             case RT_MESSAGETABLE: s = "messagetable"; break;
1411             case RT_GROUP_CURSOR: s = "group cursor"; break;
1412             case RT_GROUP_ICON: s = "group icon"; break;
1413             case RT_VERSION: s = "version"; break;
1414             case RT_DLGINCLUDE: s = "dlginclude"; break;
1415             case RT_PLUGPLAY: s = "plugplay"; break;
1416             case RT_VXD: s = "vxd"; break;
1417             case RT_ANICURSOR: s = "anicursor"; break;
1418             case RT_ANIICON: s = "aniicon"; break;
1419             default: s = NULL; break;
1420             }
1421
1422           if (s != NULL)
1423             fprintf (e, "%s", s);
1424           else
1425             res_id_print (e, re->id, 1);
1426         }
1427       fprintf (e, "\n");
1428       break;
1429
1430     case 2:
1431       fprintf (e, "// Name: ");
1432       res_id_print (e, re->id, 1);
1433       fprintf (e, "\n");
1434       break;
1435
1436     case 3:
1437       fprintf (e, "// Language: ");
1438       res_id_print (e, re->id, 1);
1439       fprintf (e, "\n");
1440       break;
1441
1442     default:
1443       fprintf (e, "// Level %d: ", level);
1444       res_id_print (e, re->id, 1);
1445       fprintf (e, "\n");
1446     }           
1447
1448   write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1449 }
1450
1451 /* Write out a single resource.  E is the file to write to.  TYPE is a
1452    pointer to the type of the resource.  NAME is a pointer to the name
1453    of the resource; it will be NULL if there is a level mismatch.  RES
1454    is the resource data.  LANGUAGE is a pointer to the current
1455    language.  */
1456
1457 static void
1458 write_rc_resource (e, type, name, res, language)
1459      FILE *e;
1460      const struct res_id *type;
1461      const struct res_id *name;
1462      const struct res_resource *res;
1463      int *language;
1464 {
1465   const char *s;
1466   int rt;
1467   int menuex = 0;
1468
1469   fprintf (e, "\n");
1470
1471   switch (res->type)
1472     {
1473     default:
1474       abort ();
1475
1476     case RES_TYPE_ACCELERATOR:
1477       s = "ACCELERATOR";
1478       rt = RT_ACCELERATOR;
1479       break;
1480
1481     case RES_TYPE_BITMAP:
1482       s = "BITMAP";
1483       rt = RT_BITMAP;
1484       break;
1485
1486     case RES_TYPE_CURSOR:
1487       s = "CURSOR";
1488       rt = RT_CURSOR;
1489       break;
1490
1491     case RES_TYPE_GROUP_CURSOR:
1492       s = "GROUP_CURSOR";
1493       rt = RT_GROUP_CURSOR;
1494       break;
1495
1496     case RES_TYPE_DIALOG:
1497       if (extended_dialog (res->u.dialog))
1498         s = "DIALOGEX";
1499       else
1500         s = "DIALOG";
1501       rt = RT_DIALOG;
1502       break;
1503
1504     case RES_TYPE_FONT:
1505       s = "FONT";
1506       rt = RT_FONT;
1507       break;
1508
1509     case RES_TYPE_FONTDIR:
1510       s = "FONTDIR";
1511       rt = RT_FONTDIR;
1512       break;
1513
1514     case RES_TYPE_ICON:
1515       s = "ICON";
1516       rt = RT_ICON;
1517       break;
1518
1519     case RES_TYPE_GROUP_ICON:
1520       s = "GROUP_ICON";
1521       rt = RT_GROUP_ICON;
1522       break;
1523
1524     case RES_TYPE_MENU:
1525       if (extended_menu (res->u.menu))
1526         {
1527           s = "MENUEX";
1528           menuex = 1;
1529         }
1530       else
1531         {
1532           s = "MENU";
1533           menuex = 0;
1534         }
1535       rt = RT_MENU;
1536       break;
1537
1538     case RES_TYPE_MESSAGETABLE:
1539       s = "MESSAGETABLE";
1540       rt = RT_MESSAGETABLE;
1541       break;
1542
1543     case RES_TYPE_RCDATA:
1544       s = "RCDATA";
1545       rt = RT_RCDATA;
1546       break;
1547
1548     case RES_TYPE_STRINGTABLE:
1549       s = "STRINGTABLE";
1550       rt = RT_STRING;
1551       break;
1552
1553     case RES_TYPE_USERDATA:
1554       s = NULL;
1555       rt = 0;
1556       break;
1557
1558     case RES_TYPE_VERSIONINFO:
1559       s = "VERSIONINFO";
1560       rt = RT_VERSION;
1561       break;
1562     }
1563
1564   if (rt != 0
1565       && type != NULL
1566       && (type->named || type->u.id != (unsigned long) rt))
1567     {
1568       fprintf (e, "// Unexpected resource type mismatch: ");
1569       res_id_print (e, *type, 1);
1570       fprintf (e, " != %d", rt);
1571     }
1572
1573   if (res->coff_info.codepage != 0)
1574     fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1575   if (res->coff_info.reserved != 0)
1576     fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1577
1578   if (name != NULL)
1579     res_id_print (e, *name, 0);
1580   else
1581     fprintf (e, "??Unknown-Name??");
1582
1583   fprintf (e, " ");
1584   if (s != NULL)
1585     fprintf (e, "%s", s);
1586   else if (type != NULL)
1587     res_id_print (e, *type, 0);
1588   else
1589     fprintf (e, "??Unknown-Type??");
1590
1591   if (res->res_info.memflags != 0)
1592     {
1593       if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1594         fprintf (e, " MOVEABLE");
1595       if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1596         fprintf (e, " PURE");
1597       if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1598         fprintf (e, " PRELOAD");
1599       if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1600         fprintf (e, " DISCARDABLE");
1601     }
1602
1603   if (res->type == RES_TYPE_DIALOG)
1604     {
1605       fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1606                res->u.dialog->width, res->u.dialog->height);
1607       if (res->u.dialog->ex != NULL
1608           && res->u.dialog->ex->help != 0)
1609         fprintf (e, ", %lu", res->u.dialog->ex->help);
1610     }
1611
1612   fprintf (e, "\n");
1613
1614   if ((res->res_info.language != 0 && res->res_info.language != *language)
1615       || res->res_info.characteristics != 0
1616       || res->res_info.version != 0)
1617     {
1618       int modifiers;
1619
1620       switch (res->type)
1621         {
1622         case RES_TYPE_ACCELERATOR:
1623         case RES_TYPE_DIALOG:
1624         case RES_TYPE_MENU:
1625         case RES_TYPE_RCDATA:
1626         case RES_TYPE_STRINGTABLE:
1627           modifiers = 1;
1628           break;
1629
1630         default:
1631           modifiers = 0;
1632           break;
1633         }
1634
1635       if (res->res_info.language != 0 && res->res_info.language != *language)
1636         fprintf (e, "%sLANGUAGE %d, %d\n",
1637                  modifiers ? "// " : "",
1638                  res->res_info.language & 0xff,
1639                  (res->res_info.language >> 8) & 0xff);
1640       if (res->res_info.characteristics != 0)
1641         fprintf (e, "%sCHARACTERISTICS %lu\n",
1642                  modifiers ? "// " : "",
1643                  res->res_info.characteristics);
1644       if (res->res_info.version != 0)
1645         fprintf (e, "%sVERSION %lu\n",
1646                  modifiers ? "// " : "",
1647                  res->res_info.version);
1648     }
1649
1650   switch (res->type)
1651     {
1652     default:
1653       abort ();
1654
1655     case RES_TYPE_ACCELERATOR:
1656       write_rc_accelerators (e, res->u.acc);
1657       break;
1658
1659     case RES_TYPE_CURSOR:
1660       write_rc_cursor (e, res->u.cursor);
1661       break;
1662
1663     case RES_TYPE_GROUP_CURSOR:
1664       write_rc_group_cursor (e, res->u.group_cursor);
1665       break;
1666
1667     case RES_TYPE_DIALOG:
1668       write_rc_dialog (e, res->u.dialog);
1669       break;
1670
1671     case RES_TYPE_FONTDIR:
1672       write_rc_fontdir (e, res->u.fontdir);
1673       break;
1674
1675     case RES_TYPE_GROUP_ICON:
1676       write_rc_group_icon (e, res->u.group_icon);
1677       break;
1678
1679     case RES_TYPE_MENU:
1680       write_rc_menu (e, res->u.menu, menuex);
1681       break;
1682
1683     case RES_TYPE_RCDATA:
1684       write_rc_rcdata (e, res->u.rcdata, 0);
1685       break;
1686
1687     case RES_TYPE_STRINGTABLE:
1688       write_rc_stringtable (e, name, res->u.stringtable);
1689       break;
1690
1691     case RES_TYPE_USERDATA:
1692       write_rc_rcdata (e, res->u.userdata, 0);
1693       break;
1694
1695     case RES_TYPE_VERSIONINFO:
1696       write_rc_versioninfo (e, res->u.versioninfo);
1697       break;
1698
1699     case RES_TYPE_BITMAP:
1700     case RES_TYPE_FONT:
1701     case RES_TYPE_ICON:
1702     case RES_TYPE_MESSAGETABLE:
1703       write_rc_filedata (e, res->u.data.length, res->u.data.data);
1704       break;
1705     }
1706 }
1707
1708 /* Write out accelerator information.  */
1709
1710 static void
1711 write_rc_accelerators (e, accelerators)
1712      FILE *e;
1713      const struct accelerator *accelerators;
1714 {
1715   const struct accelerator *acc;
1716
1717   fprintf (e, "BEGIN\n");
1718   for (acc = accelerators; acc != NULL; acc = acc->next)
1719     {
1720       int printable;
1721
1722       fprintf (e, "  ");
1723
1724       if ((acc->key & 0x7f) == acc->key
1725           && isprint ((unsigned char) acc->key)
1726           && (acc->flags & ACC_VIRTKEY) == 0)
1727         {
1728           fprintf (e, "\"%c\"", acc->key);
1729           printable = 1;
1730         }
1731       else
1732         {
1733           fprintf (e, "%d", acc->key);
1734           printable = 0;
1735         }
1736
1737       fprintf (e, ", %d", acc->id);
1738
1739       if (! printable)
1740         {
1741           if ((acc->flags & ACC_VIRTKEY) != 0)
1742             fprintf (e, ", VIRTKEY");
1743           else
1744             fprintf (e, ", ASCII");
1745         }
1746
1747       if ((acc->flags & ACC_SHIFT) != 0)
1748         fprintf (e, ", SHIFT");
1749       if ((acc->flags & ACC_CONTROL) != 0)
1750         fprintf (e, ", CONTROL");
1751       if ((acc->flags & ACC_ALT) != 0)
1752         fprintf (e, ", ALT");
1753
1754       fprintf (e, "\n");
1755     }
1756
1757   fprintf (e, "END\n");
1758 }
1759
1760 /* Write out cursor information.  This would normally be in a separate
1761    file, which the rc file would include.  */
1762
1763 static void
1764 write_rc_cursor (e, cursor)
1765      FILE *e;
1766      const struct cursor *cursor;
1767 {
1768   fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
1769            cursor->yhotspot);
1770   write_rc_filedata (e, cursor->length, cursor->data);
1771 }
1772
1773 /* Write out group cursor data.  This would normally be built from the
1774    cursor data.  */
1775
1776 static void
1777 write_rc_group_cursor (e, group_cursor)
1778      FILE *e;
1779      const struct group_cursor *group_cursor;
1780 {
1781   const struct group_cursor *gc;
1782
1783   for (gc = group_cursor; gc != NULL; gc = gc->next)
1784     {
1785       fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
1786              gc->width, gc->height, gc->planes, gc->bits);
1787       fprintf (e, "// data bytes: %lu; index: %d\n",
1788                gc->bytes, gc->index);
1789     }
1790 }
1791
1792 /* Write dialog data.  */
1793
1794 static void
1795 write_rc_dialog (e, dialog)
1796      FILE *e;
1797      const struct dialog *dialog;
1798 {
1799   const struct dialog_control *control;
1800
1801   if (dialog->style != 0)
1802     fprintf (e, "STYLE 0x%lx\n", dialog->style);
1803   if (dialog->exstyle != 0)
1804     fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
1805   if ((dialog->class.named && dialog->class.u.n.length > 0)
1806       || dialog->class.u.id != 0)
1807     {
1808       fprintf (e, "CLASS ");
1809       res_id_print (e, dialog->class, 0);
1810       fprintf (e, "\n");
1811     }
1812   if (dialog->caption != NULL)
1813     {
1814       fprintf (e, "CAPTION \"");
1815       unicode_print (e, dialog->caption, -1);
1816       fprintf (e, "\"\n");
1817     }
1818   if ((dialog->menu.named && dialog->menu.u.n.length > 0)
1819       || dialog->menu.u.id != 0)
1820     {
1821       fprintf (e, "MENU ");
1822       res_id_print (e, dialog->menu, 0);
1823       fprintf (e, "\n");
1824     }
1825   if (dialog->font != NULL)
1826     {
1827       fprintf (e, "FONT %d, \"", dialog->pointsize);
1828       unicode_print (e, dialog->font, -1);
1829       fprintf (e, "\"");
1830       if (dialog->ex != NULL
1831           && (dialog->ex->weight != 0 || dialog->ex->italic != 0))
1832         fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
1833       fprintf (e, "\n");
1834     }
1835
1836   fprintf (e, "BEGIN\n");
1837
1838   for (control = dialog->controls; control != NULL; control = control->next)
1839     write_rc_dialog_control (e, control);
1840
1841   fprintf (e, "END\n");
1842 }
1843
1844 /* For each predefined control keyword, this table provides the class
1845    and the style.  */
1846
1847 struct control_info
1848 {
1849   const char *name;
1850   unsigned short class;
1851   unsigned long style;
1852 };
1853
1854 static const struct control_info control_info[] =
1855 {
1856   { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
1857   { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
1858   { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
1859   { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
1860   { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
1861   { "CTEXT", CTL_STATIC, SS_CENTER },
1862   { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
1863   { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
1864   { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
1865   { "ICON", CTL_STATIC, SS_ICON },
1866   { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
1867   { "LTEXT", CTL_STATIC, SS_LEFT },
1868   { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
1869   { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
1870   { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
1871   { "RTEXT", CTL_STATIC, SS_RIGHT },
1872   { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
1873   { "STATE3", CTL_BUTTON, BS_3STATE },
1874   /* It's important that USERBUTTON come after all the other button
1875      types, so that it won't be matched too early.  */
1876   { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
1877   { NULL, 0, 0 }
1878 };
1879
1880 /* Write a dialog control.  */
1881
1882 static void
1883 write_rc_dialog_control (e, control)
1884      FILE *e;
1885      const struct dialog_control *control;
1886 {
1887   const struct control_info *ci;
1888
1889   fprintf (e, "  ");
1890
1891   if (control->class.named)
1892     ci = NULL;
1893   else
1894     {
1895       for (ci = control_info; ci->name != NULL; ++ci)
1896         if (ci->class == control->class.u.id
1897             && (ci->style == (unsigned long) -1
1898                 || ci->style == (control->style & 0xff)))
1899           break;
1900     }
1901   if (ci == NULL)
1902     fprintf (e, "CONTROL");
1903   else if (ci->name != NULL)
1904     fprintf (e, "%s", ci->name);
1905   else
1906     fprintf (e, "CONTROL");
1907   
1908   if (control->text.named || control->text.u.id != 0)
1909     {
1910       fprintf (e, " ");
1911       res_id_print (e, control->text, 1);
1912       fprintf (e, ",");
1913     }
1914
1915   fprintf (e, " %d, ", control->id);
1916
1917   if (ci == NULL)
1918     {
1919       if (control->class.named)
1920         fprintf (e, "\"");
1921       res_id_print (e, control->class, 0);
1922       if (control->class.named)
1923         fprintf (e, "\"");
1924       fprintf (e, ", 0x%lx, ", control->style);
1925     }
1926
1927   fprintf (e, "%d, %d", control->x, control->y);
1928
1929   if (control->style != SS_ICON
1930       || control->exstyle != 0
1931       || control->width != 0
1932       || control->height != 0
1933       || control->help != 0)
1934     {
1935       fprintf (e, ", %d, %d", control->width, control->height);
1936
1937       /* FIXME: We don't need to print the style if it is the default.
1938          More importantly, in certain cases we actually need to turn
1939          off parts of the forced style, by using NOT.  */
1940       fprintf (e, ", 0x%lx", control->style);
1941
1942       if (control->exstyle != 0 || control->help != 0)
1943         fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
1944     }
1945
1946   fprintf (e, "\n");
1947
1948   if (control->data != NULL)
1949     write_rc_rcdata (e, control->data, 2);
1950 }
1951
1952 /* Write out font directory data.  This would normally be built from
1953    the font data.  */
1954
1955 static void
1956 write_rc_fontdir (e, fontdir)
1957      FILE *e;
1958      const struct fontdir *fontdir;
1959 {
1960   const struct fontdir *fc;
1961
1962   for (fc = fontdir; fc != NULL; fc = fc->next)
1963     {
1964       fprintf (e, "// Font index: %d\n", fc->index);
1965       write_rc_filedata (e, fc->length, fc->data);
1966     }
1967 }
1968
1969 /* Write out group icon data.  This would normally be built from the
1970    icon data.  */
1971
1972 static void
1973 write_rc_group_icon (e, group_icon)
1974      FILE *e;
1975      const struct group_icon *group_icon;
1976 {
1977   const struct group_icon *gi;
1978
1979   for (gi = group_icon; gi != NULL; gi = gi->next)
1980     {
1981       fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
1982                gi->width, gi->height, gi->colors, gi->planes, gi->bits);
1983       fprintf (e, "// data bytes: %lu; index: %d\n",
1984                gi->bytes, gi->index);
1985     }
1986 }
1987
1988 /* Write out a menu resource.  */
1989
1990 static void
1991 write_rc_menu (e, menu, menuex)
1992      FILE *e;
1993      const struct menu *menu;
1994      int menuex;
1995 {
1996   if (menu->help != 0)
1997     fprintf (e, "// Help ID: %lu\n", menu->help);
1998   write_rc_menuitems (e, menu->items, menuex, 0);
1999 }
2000
2001 /* Write out menuitems.  */
2002
2003 static void
2004 write_rc_menuitems (e, menuitems, menuex, ind)
2005      FILE *e;
2006      const struct menuitem *menuitems;
2007      int menuex;
2008      int ind;
2009 {
2010   const struct menuitem *mi;
2011
2012   indent (e, ind);
2013   fprintf (e, "BEGIN\n");
2014
2015   for (mi = menuitems; mi != NULL; mi = mi->next)
2016     {
2017       indent (e, ind + 2);
2018
2019       if (mi->popup == NULL)
2020         fprintf (e, "MENUITEM");
2021       else
2022         fprintf (e, "POPUP");
2023
2024       if (! menuex
2025           && mi->popup == NULL
2026           && mi->text == NULL
2027           && mi->type == 0
2028           && mi->id == 0)
2029         {
2030           fprintf (e, " SEPARATOR\n");
2031           continue;
2032         }
2033
2034       if (mi->text == NULL)
2035         fprintf (e, " \"\"");
2036       else
2037         {
2038           fprintf (e, " \"");
2039           unicode_print (e, mi->text, -1);
2040           fprintf (e, "\"");
2041         }
2042
2043       if (! menuex)
2044         {
2045           if (mi->popup == NULL)
2046             fprintf (e, ", %d", mi->id);
2047
2048           if ((mi->type & MENUITEM_CHECKED) != 0)
2049             fprintf (e, ", CHECKED");
2050           if ((mi->type & MENUITEM_GRAYED) != 0)
2051             fprintf (e, ", GRAYED");
2052           if ((mi->type & MENUITEM_HELP) != 0)
2053             fprintf (e, ", HELP");
2054           if ((mi->type & MENUITEM_INACTIVE) != 0)
2055             fprintf (e, ", INACTIVE");
2056           if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2057             fprintf (e, ", MENUBARBREAK");
2058           if ((mi->type & MENUITEM_MENUBREAK) != 0)
2059             fprintf (e, ", MENUBREAK");
2060         }
2061       else
2062         {
2063           if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2064             {
2065               fprintf (e, ", %d", mi->id);
2066               if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2067                 {
2068                   fprintf (e, ", %lu", mi->type);
2069                   if (mi->state != 0 || mi->help != 0)
2070                     {
2071                       fprintf (e, ", %lu", mi->state);
2072                       if (mi->help != 0)
2073                         fprintf (e, ", %lu", mi->help);
2074                     }
2075                 }
2076             }
2077         }
2078
2079       fprintf (e, "\n");
2080
2081       if (mi->popup != NULL)
2082         write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2083     }
2084
2085   indent (e, ind);
2086   fprintf (e, "END\n");
2087 }
2088
2089 /* Write out an rcdata resource.  This is also used for other types of
2090    resources that need to print arbitrary data.  */
2091
2092 static void
2093 write_rc_rcdata (e, rcdata, ind)
2094      FILE *e;
2095      const struct rcdata_item *rcdata;
2096      int ind;
2097 {
2098   const struct rcdata_item *ri;
2099
2100   indent (e, ind);
2101   fprintf (e, "BEGIN\n");
2102
2103   for (ri = rcdata; ri != NULL; ri = ri->next)
2104     {
2105       if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2106         continue;
2107
2108       indent (e, ind + 2);
2109
2110       switch (ri->type)
2111         {
2112         default:
2113           abort ();
2114
2115         case RCDATA_WORD:
2116           fprintf (e, "%d", ri->u.word);
2117           break;
2118
2119         case RCDATA_DWORD:
2120           fprintf (e, "%luL", ri->u.dword);
2121           break;
2122
2123         case RCDATA_STRING:
2124           {
2125             const char *s;
2126             unsigned long i;
2127
2128             fprintf (e, "\"");
2129             s = ri->u.string.s;
2130             for (i = 0; i < ri->u.string.length; i++)
2131               {
2132                 if (isprint ((unsigned char) *s))
2133                   putc (*s, e);
2134                 else
2135                   fprintf (e, "\\%03o", *s);
2136               }
2137             fprintf (e, "\"");
2138             break;
2139           }
2140
2141         case RCDATA_WSTRING:
2142           fprintf (e, "L\"");
2143           unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2144           fprintf (e, "\"");
2145           break;
2146
2147         case RCDATA_BUFFER:
2148           {
2149             unsigned long i;
2150             int first;
2151
2152             /* Assume little endian data.  */
2153
2154             first = 1;
2155             for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2156               {
2157                 unsigned long l;
2158
2159                 l = ((((((ri->u.buffer.data[i + 3] << 8)
2160                          | ri->u.buffer.data[i + 2]) << 8)
2161                        | ri->u.buffer.data[i + 1]) << 8)
2162                      | ri->u.buffer.data[i]);
2163                 if (first)
2164                   first = 0;
2165                 else
2166                   {
2167                     fprintf (e, ",\n");
2168                     indent (e, ind + 2);
2169                   }
2170                 fprintf (e, "%luL", l);
2171               }
2172
2173             if (i + 1 < ri->u.buffer.length)
2174               {
2175                 int i;
2176
2177                 i = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2178                 if (first)
2179                   first = 0;
2180                 else
2181                   {
2182                     fprintf (e, ",\n");
2183                     indent (e, ind + 2);
2184                   }
2185                 fprintf (e, "%d", i);
2186                 i += 2;
2187               }
2188
2189             if (i < ri->u.buffer.length)
2190               {
2191                 if (first)
2192                   first = 0;
2193                 else
2194                   {
2195                     fprintf (e, ",\n");
2196                     indent (e, ind + 2);
2197                   }
2198                 if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2199                     && isprint (ri->u.buffer.data[i]))
2200                   fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2201                 else
2202                   fprintf (e, "\"\%03o\"", ri->u.buffer.data[i]);
2203               }
2204
2205             break;
2206           }
2207         }
2208
2209       if (ri->next != NULL)
2210         fprintf (e, ",");
2211       fprintf (e, "\n");
2212     }
2213
2214   indent (e, ind);
2215   fprintf (e, "END\n");
2216 }
2217
2218 /* Write out a stringtable resource.  */
2219
2220 static void
2221 write_rc_stringtable (e, name, stringtable)
2222      FILE *e;
2223      const struct res_id *name;
2224      const struct stringtable *stringtable;
2225 {
2226   unsigned long offset;
2227   int i;
2228
2229   if (name != NULL && ! name->named)
2230     offset = (name->u.id - 1) << 4;
2231   else
2232     {
2233       fprintf (e, "// %s string table name\n",
2234                name == NULL ? "Missing" : "Invalid");
2235       offset = 0;
2236     }
2237
2238   fprintf (e, "BEGIN\n");
2239
2240   for (i = 0; i < 16; i++)
2241     {
2242       if (stringtable->strings[i].length != 0)
2243         {
2244           fprintf (e, "  %lu, \"", offset + i);
2245           unicode_print (e, stringtable->strings[i].string,
2246                          stringtable->strings[i].length);
2247           fprintf (e, "\"\n");
2248         }
2249     }
2250
2251   fprintf (e, "END\n");
2252 }
2253
2254 /* Write out a versioninfo resource.  */
2255
2256 static void
2257 write_rc_versioninfo (e, versioninfo)
2258      FILE *e;
2259      const struct versioninfo *versioninfo;
2260 {
2261   const struct fixed_versioninfo *f;
2262   const struct ver_info *vi;
2263
2264   f = versioninfo->fixed;
2265   if (f->file_version_ms != 0 || f->file_version_ls != 0)
2266     fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2267              (f->file_version_ms >> 16) & 0xffff,
2268              f->file_version_ms & 0xffff,
2269              (f->file_version_ls >> 16) & 0xffff,
2270              f->file_version_ls & 0xffff);
2271   if (f->product_version_ms != 0 || f->product_version_ls != 0)
2272     fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2273              (f->product_version_ms >> 16) & 0xffff,
2274              f->product_version_ms & 0xffff,
2275              (f->product_version_ls >> 16) & 0xffff,
2276              f->product_version_ls & 0xffff);
2277   if (f->file_flags_mask != 0)
2278     fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2279   if (f->file_flags != 0)
2280     fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2281   if (f->file_os != 0)
2282     fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2283   if (f->file_type != 0)
2284     fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2285   if (f->file_subtype != 0)
2286     fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2287   if (f->file_date_ms != 0 || f->file_date_ls != 0)
2288     fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2289
2290   fprintf (e, "BEGIN\n");
2291
2292   for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2293     {
2294       switch (vi->type)
2295         {
2296         case VERINFO_STRING:
2297           {
2298             const struct ver_stringinfo *vs;
2299
2300             fprintf (e, "  BLOCK \"StringFileInfo\"\n");
2301             fprintf (e, "  BEGIN\n");
2302             fprintf (e, "    BLOCK \"");
2303             unicode_print (e, vi->u.string.language, -1);
2304             fprintf (e, "\"\n");
2305             fprintf (e, "    BEGIN\n");
2306
2307             for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2308               {
2309                 fprintf (e, "      VALUE \"");
2310                 unicode_print (e, vs->key, -1);
2311                 fprintf (e, "\", \"");
2312                 unicode_print (e, vs->value, -1);
2313                 fprintf (e, "\"\n");
2314               }
2315
2316             fprintf (e, "    END\n");
2317             fprintf (e, "  END\n");
2318             break;
2319           }
2320
2321         case VERINFO_VAR:
2322           {
2323             const struct ver_varinfo *vv;
2324
2325             fprintf (e, "  BLOCK \"VarFileInfo\"\n");
2326             fprintf (e, "  BEGIN\n");
2327             fprintf (e, "    VALUE \"");
2328             unicode_print (e, vi->u.var.key, -1);
2329             fprintf (e, "\"");
2330
2331             for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2332               fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2333                        vv->charset);
2334
2335             fprintf (e, "\n  END\n");
2336
2337             break;
2338           }
2339         }
2340     }
2341
2342   fprintf (e, "END\n");
2343 }
2344
2345 /* Write out data which would normally be read from a file.  */
2346
2347 static void
2348 write_rc_filedata (e, length, data)
2349      FILE *e;
2350      unsigned long length;
2351      const unsigned char *data;
2352 {
2353   unsigned long i;
2354
2355   for (i = 0; i + 15 < length; i += 16)
2356     {
2357       fprintf (e, "// %4lx: ", i);
2358       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2359                data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2360                data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2361       fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2362                data[i +  8], data[i +  9], data[i + 10], data[i + 11],
2363                data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2364     }
2365
2366   if (i < length)
2367     {
2368       fprintf (e, "// %4lx:", i);
2369       while (i < length)
2370         {
2371           fprintf (e, " %02x", data[i]);
2372           ++i;
2373         }
2374       fprintf (e, "\n");
2375     }
2376 }