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