2001-03-22 Philip Blundell <philb@gnu.org>
[binutils.git] / binutils / resrc.c
blob68bc7c40302fea757fb8d7d9e849327cbb3c01f3
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.
5 This file is part of GNU Binutils.
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.
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.
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. */
22 /* This file contains functions that read and write Windows rc files.
23 These are text files that represent resources. */
25 #include "bfd.h"
26 #include "bucomm.h"
27 #include "libiberty.h"
28 #include "windres.h"
30 #include <assert.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <sys/stat.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
38 #ifdef HAVE_SYS_WAIT_H
39 #include <sys/wait.h>
40 #else /* ! HAVE_SYS_WAIT_H */
41 #if ! defined (_WIN32) || defined (__CYGWIN__)
42 #ifndef WIFEXITED
43 #define WIFEXITED(w) (((w)&0377) == 0)
44 #endif
45 #ifndef WIFSIGNALED
46 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
47 #endif
48 #ifndef WTERMSIG
49 #define WTERMSIG(w) ((w) & 0177)
50 #endif
51 #ifndef WEXITSTATUS
52 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
53 #endif
54 #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
55 #ifndef WIFEXITED
56 #define WIFEXITED(w) (((w) & 0xff) == 0)
57 #endif
58 #ifndef WIFSIGNALED
59 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
60 #endif
61 #ifndef WTERMSIG
62 #define WTERMSIG(w) ((w) & 0x7f)
63 #endif
64 #ifndef WEXITSTATUS
65 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
66 #endif
67 #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
68 #endif /* ! HAVE_SYS_WAIT_H */
70 #ifndef STDOUT_FILENO
71 #define STDOUT_FILENO 1
72 #endif
74 #if defined (_WIN32) && ! defined (__CYGWIN__)
75 #define popen _popen
76 #define pclose _pclose
77 #endif
79 /* The default preprocessor. */
81 #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
83 /* We read the directory entries in a cursor or icon file into
84 instances of this structure. */
86 struct icondir
88 /* Width of image. */
89 unsigned char width;
90 /* Height of image. */
91 unsigned char height;
92 /* Number of colors in image. */
93 unsigned char colorcount;
94 union
96 struct
98 /* Color planes. */
99 unsigned short planes;
100 /* Bits per pixel. */
101 unsigned short bits;
102 } icon;
103 struct
105 /* X coordinate of hotspot. */
106 unsigned short xhotspot;
107 /* Y coordinate of hotspot. */
108 unsigned short yhotspot;
109 } cursor;
110 } u;
111 /* Bytes in image. */
112 unsigned long bytes;
113 /* File offset of image. */
114 unsigned long offset;
117 /* The name of the rc file we are reading. */
119 char *rc_filename;
121 /* The line number in the rc file. */
123 int rc_lineno;
125 /* The pipe we are reading from, so that we can close it if we exit. */
127 static FILE *cpp_pipe;
129 /* The temporary file used if we're not using popen, so we can delete it
130 if we exit. */
132 static char *cpp_temp_file;
134 /* Input stream is either a file or a pipe. */
136 static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
138 /* As we read the rc file, we attach information to this structure. */
140 static struct res_directory *resources;
142 /* The number of cursor resources we have written out. */
144 static int cursors;
146 /* The number of font resources we have written out. */
148 static int fonts;
150 /* Font directory information. */
152 struct fontdir *fontdirs;
154 /* Resource info to use for fontdirs. */
156 struct res_res_info fontdirs_resinfo;
158 /* The number of icon resources we have written out. */
160 static int icons;
162 /* Local functions. */
164 static int run_cmd PARAMS ((char *, const char *));
165 static FILE *open_input_stream PARAMS ((char *));
166 static FILE *look_for_default PARAMS ((char *, const char *, int,
167 const char *, const char *));
168 static void close_input_stream PARAMS ((void));
169 static void unexpected_eof PARAMS ((const char *));
170 static int get_word PARAMS ((FILE *, const char *));
171 static unsigned long get_long PARAMS ((FILE *, const char *));
172 static void get_data
173 PARAMS ((FILE *, unsigned char *, unsigned long, const char *));
174 static void define_fontdirs PARAMS ((void));
176 /* Run `cmd' and redirect the output to `redir'. */
178 static int
179 run_cmd (cmd, redir)
180 char *cmd;
181 const char *redir;
183 char *s;
184 int pid, wait_status, retcode;
185 int i;
186 const char **argv;
187 char *errmsg_fmt, *errmsg_arg;
188 char *temp_base = choose_temp_base ();
189 int in_quote;
190 char sep;
191 int redir_handle = -1;
192 int stdout_save = -1;
194 /* Count the args. */
195 i = 0;
197 for (s = cmd; *s; s++)
198 if (*s == ' ')
199 i++;
201 i++;
202 argv = alloca (sizeof (char *) * (i + 3));
203 i = 0;
204 s = cmd;
206 while (1)
208 while (*s == ' ' && *s != 0)
209 s++;
211 if (*s == 0)
212 break;
214 in_quote = (*s == '\'' || *s == '"');
215 sep = (in_quote) ? *s++ : ' ';
216 argv[i++] = s;
218 while (*s != sep && *s != 0)
219 s++;
221 if (*s == 0)
222 break;
224 *s++ = 0;
226 if (in_quote)
227 s++;
229 argv[i++] = NULL;
231 /* Setup the redirection. We can't use the usual fork/exec and redirect
232 since we may be running on non-POSIX Windows host. */
234 fflush (stdout);
235 fflush (stderr);
237 /* Open temporary output file. */
238 redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
239 if (redir_handle == -1)
240 fatal (_("can't open temporary file `%s': %s"), redir,
241 strerror (errno));
243 /* Duplicate the stdout file handle so it can be restored later. */
244 stdout_save = dup (STDOUT_FILENO);
245 if (stdout_save == -1)
246 fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
248 /* Redirect stdout to our output file. */
249 dup2 (redir_handle, STDOUT_FILENO);
251 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
252 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
254 /* Restore stdout to its previous setting. */
255 dup2 (stdout_save, STDOUT_FILENO);
257 /* Close reponse file. */
258 close (redir_handle);
260 if (pid == -1)
262 fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
263 return 1;
266 retcode = 0;
267 pid = pwait (pid, &wait_status, 0);
269 if (pid == -1)
271 fatal (_("wait: %s"), strerror (errno));
272 retcode = 1;
274 else if (WIFSIGNALED (wait_status))
276 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
277 retcode = 1;
279 else if (WIFEXITED (wait_status))
281 if (WEXITSTATUS (wait_status) != 0)
283 fatal (_("%s exited with status %d"), cmd,
284 WEXITSTATUS (wait_status));
285 retcode = 1;
288 else
289 retcode = 1;
291 return retcode;
294 static FILE *
295 open_input_stream (cmd)
296 char *cmd;
298 if (istream_type == ISTREAM_FILE)
300 char *fileprefix;
302 fileprefix = choose_temp_base ();
303 cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
304 sprintf (cpp_temp_file, "%s.irc", fileprefix);
305 free (fileprefix);
307 if (run_cmd (cmd, cpp_temp_file))
308 fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
310 cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
311 if (cpp_pipe == NULL)
312 fatal (_("can't open temporary file `%s': %s"),
313 cpp_temp_file, strerror (errno));
315 if (verbose)
316 fprintf (stderr,
317 _("Using temporary file `%s' to read preprocessor output\n"),
318 cpp_temp_file);
320 else
322 cpp_pipe = popen (cmd, FOPEN_RT);
323 if (cpp_pipe == NULL)
324 fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
325 if (verbose)
326 fprintf (stderr, _("Using popen to read preprocessor output\n"));
329 xatexit (close_input_stream);
330 return cpp_pipe;
333 /* look for the preprocessor program */
335 static FILE *
336 look_for_default (cmd, prefix, end_prefix, preprocargs, filename)
337 char *cmd;
338 const char *prefix;
339 int end_prefix;
340 const char *preprocargs;
341 const char *filename;
343 char *space;
344 int found;
345 struct stat s;
347 strcpy (cmd, prefix);
349 sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
350 space = strchr (cmd + end_prefix, ' ');
351 if (space)
352 *space = 0;
354 if (
355 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
356 strchr (cmd, '\\') ||
357 #endif
358 strchr (cmd, '/'))
360 found = (stat (cmd, &s) == 0
361 #ifdef HAVE_EXECUTABLE_SUFFIX
362 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
363 #endif
366 if (! found)
368 if (verbose)
369 fprintf (stderr, _("Tried `%s'\n"), cmd);
370 return NULL;
374 strcpy (cmd, prefix);
376 sprintf (cmd + end_prefix, "%s %s %s",
377 DEFAULT_PREPROCESSOR, preprocargs, filename);
379 if (verbose)
380 fprintf (stderr, _("Using `%s'\n"), cmd);
382 cpp_pipe = open_input_stream (cmd);
383 return cpp_pipe;
386 /* Read an rc file. */
388 struct res_directory *
389 read_rc_file (filename, preprocessor, preprocargs, language, use_temp_file)
390 const char *filename;
391 const char *preprocessor;
392 const char *preprocargs;
393 int language;
394 int use_temp_file;
396 char *cmd;
398 istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
400 if (preprocargs == NULL)
401 preprocargs = "";
402 if (filename == NULL)
403 filename = "-";
405 if (preprocessor)
407 cmd = xmalloc (strlen (preprocessor)
408 + strlen (preprocargs)
409 + strlen (filename)
410 + 10);
411 sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
413 cpp_pipe = open_input_stream (cmd);
415 else
417 char *dash, *slash, *cp;
419 preprocessor = DEFAULT_PREPROCESSOR;
421 cmd = xmalloc (strlen (program_name)
422 + strlen (preprocessor)
423 + strlen (preprocargs)
424 + strlen (filename)
425 #ifdef HAVE_EXECUTABLE_SUFFIX
426 + strlen (EXECUTABLE_SUFFIX)
427 #endif
428 + 10);
431 dash = slash = 0;
432 for (cp = program_name; *cp; cp++)
434 if (*cp == '-')
435 dash = cp;
436 if (
437 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
438 *cp == ':' || *cp == '\\' ||
439 #endif
440 *cp == '/')
442 slash = cp;
443 dash = 0;
447 cpp_pipe = 0;
449 if (dash)
451 /* First, try looking for a prefixed gcc in the windres
452 directory, with the same prefix as windres */
454 cpp_pipe = look_for_default (cmd, program_name, dash-program_name+1,
455 preprocargs, filename);
458 if (slash && !cpp_pipe)
460 /* Next, try looking for a gcc in the same directory as
461 that windres */
463 cpp_pipe = look_for_default (cmd, program_name, slash-program_name+1,
464 preprocargs, filename);
467 if (!cpp_pipe)
469 /* Sigh, try the default */
471 cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
476 free (cmd);
478 rc_filename = xstrdup (filename);
479 rc_lineno = 1;
480 if (language != -1)
481 rcparse_set_language (language);
482 yyin = cpp_pipe;
483 yyparse ();
485 close_input_stream ();
487 if (fontdirs != NULL)
488 define_fontdirs ();
490 free (rc_filename);
491 rc_filename = NULL;
493 return resources;
496 /* Close the input stream if it is open. */
498 static void
499 close_input_stream ()
501 if (istream_type == ISTREAM_FILE)
503 if (cpp_pipe != NULL)
504 fclose (cpp_pipe);
506 if (cpp_temp_file != NULL)
508 int errno_save = errno;
510 unlink (cpp_temp_file);
511 errno = errno_save;
512 free (cpp_temp_file);
515 else
517 if (cpp_pipe != NULL)
518 pclose (cpp_pipe);
521 /* Since this is also run via xatexit, safeguard. */
522 cpp_pipe = NULL;
523 cpp_temp_file = NULL;
526 /* Report an error while reading an rc file. */
528 void
529 yyerror (msg)
530 const char *msg;
532 fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
535 /* Issue a warning while reading an rc file. */
537 void
538 rcparse_warning (msg)
539 const char *msg;
541 fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
544 /* Die if we get an unexpected end of file. */
546 static void
547 unexpected_eof (msg)
548 const char *msg;
550 fatal (_("%s: unexpected EOF"), msg);
553 /* Read a 16 bit word from a file. The data is assumed to be little
554 endian. */
556 static int
557 get_word (e, msg)
558 FILE *e;
559 const char *msg;
561 int b1, b2;
563 b1 = getc (e);
564 b2 = getc (e);
565 if (feof (e))
566 unexpected_eof (msg);
567 return ((b2 & 0xff) << 8) | (b1 & 0xff);
570 /* Read a 32 bit word from a file. The data is assumed to be little
571 endian. */
573 static unsigned long
574 get_long (e, msg)
575 FILE *e;
576 const char *msg;
578 int b1, b2, b3, b4;
580 b1 = getc (e);
581 b2 = getc (e);
582 b3 = getc (e);
583 b4 = getc (e);
584 if (feof (e))
585 unexpected_eof (msg);
586 return (((((((b4 & 0xff) << 8)
587 | (b3 & 0xff)) << 8)
588 | (b2 & 0xff)) << 8)
589 | (b1 & 0xff));
592 /* Read data from a file. This is a wrapper to do error checking. */
594 static void
595 get_data (e, p, c, msg)
596 FILE *e;
597 unsigned char *p;
598 unsigned long c;
599 const char *msg;
601 unsigned long got;
603 got = fread (p, 1, c, e);
604 if (got == c)
605 return;
607 fatal (_("%s: read of %lu returned %lu"), msg, c, got);
610 /* Define an accelerator resource. */
612 void
613 define_accelerator (id, resinfo, data)
614 struct res_id id;
615 const struct res_res_info *resinfo;
616 struct accelerator *data;
618 struct res_resource *r;
620 r = define_standard_resource (&resources, RT_ACCELERATOR, id,
621 resinfo->language, 0);
622 r->type = RES_TYPE_ACCELERATOR;
623 r->u.acc = data;
624 r->res_info = *resinfo;
627 /* Define a bitmap resource. Bitmap data is stored in a file. The
628 first 14 bytes of the file are a standard header, which is not
629 included in the resource data. */
631 #define BITMAP_SKIP (14)
633 void
634 define_bitmap (id, resinfo, filename)
635 struct res_id id;
636 const struct res_res_info *resinfo;
637 const char *filename;
639 FILE *e;
640 char *real_filename;
641 struct stat s;
642 unsigned char *data;
643 int i;
644 struct res_resource *r;
646 e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
648 if (stat (real_filename, &s) < 0)
649 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
650 strerror (errno));
652 data = (unsigned char *) res_alloc (s.st_size - BITMAP_SKIP);
654 for (i = 0; i < BITMAP_SKIP; i++)
655 getc (e);
657 get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
659 fclose (e);
660 free (real_filename);
662 r = define_standard_resource (&resources, RT_BITMAP, id,
663 resinfo->language, 0);
665 r->type = RES_TYPE_BITMAP;
666 r->u.data.length = s.st_size - BITMAP_SKIP;
667 r->u.data.data = data;
668 r->res_info = *resinfo;
671 /* Define a cursor resource. A cursor file may contain a set of
672 bitmaps, each representing the same cursor at various different
673 resolutions. They each get written out with a different ID. The
674 real cursor resource is then a group resource which can be used to
675 select one of the actual cursors. */
677 void
678 define_cursor (id, resinfo, filename)
679 struct res_id id;
680 const struct res_res_info *resinfo;
681 const char *filename;
683 FILE *e;
684 char *real_filename;
685 int type, count, i;
686 struct icondir *icondirs;
687 int first_cursor;
688 struct res_resource *r;
689 struct group_cursor *first, **pp;
691 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
693 /* A cursor file is basically an icon file. The start of the file
694 is a three word structure. The first word is ignored. The
695 second word is the type of data. The third word is the number of
696 entries. */
698 get_word (e, real_filename);
699 type = get_word (e, real_filename);
700 count = get_word (e, real_filename);
701 if (type != 2)
702 fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
704 /* Read in the icon directory entries. */
706 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
708 for (i = 0; i < count; i++)
710 icondirs[i].width = getc (e);
711 icondirs[i].height = getc (e);
712 icondirs[i].colorcount = getc (e);
713 getc (e);
714 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
715 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
716 icondirs[i].bytes = get_long (e, real_filename);
717 icondirs[i].offset = get_long (e, real_filename);
719 if (feof (e))
720 unexpected_eof (real_filename);
723 /* Define each cursor as a unique resource. */
725 first_cursor = cursors;
727 for (i = 0; i < count; i++)
729 unsigned char *data;
730 struct res_id name;
731 struct cursor *c;
733 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
734 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
735 icondirs[i].offset, strerror (errno));
737 data = (unsigned char *) res_alloc (icondirs[i].bytes);
739 get_data (e, data, icondirs[i].bytes, real_filename);
741 c = (struct cursor *) res_alloc (sizeof *c);
742 c->xhotspot = icondirs[i].u.cursor.xhotspot;
743 c->yhotspot = icondirs[i].u.cursor.yhotspot;
744 c->length = icondirs[i].bytes;
745 c->data = data;
747 ++cursors;
749 name.named = 0;
750 name.u.id = cursors;
752 r = define_standard_resource (&resources, RT_CURSOR, name,
753 resinfo->language, 0);
754 r->type = RES_TYPE_CURSOR;
755 r->u.cursor = c;
756 r->res_info = *resinfo;
759 fclose (e);
760 free (real_filename);
762 /* Define a cursor group resource. */
764 first = NULL;
765 pp = &first;
766 for (i = 0; i < count; i++)
768 struct group_cursor *cg;
770 cg = (struct group_cursor *) res_alloc (sizeof *cg);
771 cg->next = NULL;
772 cg->width = icondirs[i].width;
773 cg->height = 2 * icondirs[i].height;
775 /* FIXME: What should these be set to? */
776 cg->planes = 1;
777 cg->bits = 1;
779 cg->bytes = icondirs[i].bytes + 4;
780 cg->index = first_cursor + i + 1;
782 *pp = cg;
783 pp = &(*pp)->next;
786 free (icondirs);
788 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
789 resinfo->language, 0);
790 r->type = RES_TYPE_GROUP_CURSOR;
791 r->u.group_cursor = first;
792 r->res_info = *resinfo;
795 /* Define a dialog resource. */
797 void
798 define_dialog (id, resinfo, dialog)
799 struct res_id id;
800 const struct res_res_info *resinfo;
801 const struct dialog *dialog;
803 struct dialog *copy;
804 struct res_resource *r;
806 copy = (struct dialog *) res_alloc (sizeof *copy);
807 *copy = *dialog;
809 r = define_standard_resource (&resources, RT_DIALOG, id,
810 resinfo->language, 0);
811 r->type = RES_TYPE_DIALOG;
812 r->u.dialog = copy;
813 r->res_info = *resinfo;
816 /* Define a dialog control. This does not define a resource, but
817 merely allocates and fills in a structure. */
819 struct dialog_control *
820 define_control (text, id, x, y, width, height, class, style, exstyle)
821 const char *text;
822 unsigned long id;
823 unsigned long x;
824 unsigned long y;
825 unsigned long width;
826 unsigned long height;
827 unsigned long class;
828 unsigned long style;
829 unsigned long exstyle;
831 struct dialog_control *n;
833 n = (struct dialog_control *) res_alloc (sizeof *n);
834 n->next = NULL;
835 n->id = id;
836 n->style = style;
837 n->exstyle = exstyle;
838 n->x = x;
839 n->y = y;
840 n->width = width;
841 n->height = height;
842 n->class.named = 0;
843 n->class.u.id = class;
844 if (text == NULL)
845 text = "";
846 res_string_to_id (&n->text, text);
847 n->data = NULL;
848 n->help = 0;
850 return n;
853 struct dialog_control *
854 define_icon_control (iid, id, x, y, style, exstyle, help, data, ex)
855 struct res_id iid;
856 unsigned long id;
857 unsigned long x;
858 unsigned long y;
859 unsigned long style;
860 unsigned long exstyle;
861 unsigned long help;
862 struct rcdata_item *data;
863 struct dialog_ex *ex;
865 struct dialog_control *n;
866 if (style == 0)
867 style = SS_ICON | WS_CHILD | WS_VISIBLE;
868 n = define_control (0, id, x, y, 0, 0, CTL_STATIC, style, exstyle);
869 n->text = iid;
870 if (help && !ex)
871 rcparse_warning (_("help ID requires DIALOGEX"));
872 if (data && !ex)
873 rcparse_warning (_("control data requires DIALOGEX"));
874 n->help = help;
875 n->data = data;
877 return n;
880 /* Define a font resource. */
882 void
883 define_font (id, resinfo, filename)
884 struct res_id id;
885 const struct res_res_info *resinfo;
886 const char *filename;
888 FILE *e;
889 char *real_filename;
890 struct stat s;
891 unsigned char *data;
892 struct res_resource *r;
893 long offset;
894 long fontdatalength;
895 unsigned char *fontdata;
896 struct fontdir *fd;
897 const char *device, *face;
898 struct fontdir **pp;
900 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
902 if (stat (real_filename, &s) < 0)
903 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
904 strerror (errno));
906 data = (unsigned char *) res_alloc (s.st_size);
908 get_data (e, data, s.st_size, real_filename);
910 fclose (e);
911 free (real_filename);
913 r = define_standard_resource (&resources, RT_FONT, id,
914 resinfo->language, 0);
916 r->type = RES_TYPE_FONT;
917 r->u.data.length = s.st_size;
918 r->u.data.data = data;
919 r->res_info = *resinfo;
921 /* For each font resource, we must add an entry in the FONTDIR
922 resource. The FONTDIR resource includes some strings in the font
923 file. To find them, we have to do some magic on the data we have
924 read. */
926 offset = ((((((data[47] << 8)
927 | data[46]) << 8)
928 | data[45]) << 8)
929 | data[44]);
930 if (offset > 0 && offset < s.st_size)
931 device = (char *) data + offset;
932 else
933 device = "";
935 offset = ((((((data[51] << 8)
936 | data[50]) << 8)
937 | data[49]) << 8)
938 | data[48]);
939 if (offset > 0 && offset < s.st_size)
940 face = (char *) data + offset;
941 else
942 face = "";
944 ++fonts;
946 fontdatalength = 58 + strlen (device) + strlen (face);
947 fontdata = (unsigned char *) res_alloc (fontdatalength);
948 memcpy (fontdata, data, 56);
949 strcpy ((char *) fontdata + 56, device);
950 strcpy ((char *) fontdata + 57 + strlen (device), face);
952 fd = (struct fontdir *) res_alloc (sizeof *fd);
953 fd->next = NULL;
954 fd->index = fonts;
955 fd->length = fontdatalength;
956 fd->data = fontdata;
958 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
960 *pp = fd;
962 /* For the single fontdirs resource, we always use the resource
963 information of the last font. I don't know what else to do. */
964 fontdirs_resinfo = *resinfo;
967 /* Define the fontdirs resource. This is called after the entire rc
968 file has been parsed, if any font resources were seen. */
970 static void
971 define_fontdirs ()
973 struct res_resource *r;
974 struct res_id id;
976 id.named = 0;
977 id.u.id = 1;
979 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
981 r->type = RES_TYPE_FONTDIR;
982 r->u.fontdir = fontdirs;
983 r->res_info = fontdirs_resinfo;
986 /* Define an icon resource. An icon file may contain a set of
987 bitmaps, each representing the same icon at various different
988 resolutions. They each get written out with a different ID. The
989 real icon resource is then a group resource which can be used to
990 select one of the actual icon bitmaps. */
992 void
993 define_icon (id, resinfo, filename)
994 struct res_id id;
995 const struct res_res_info *resinfo;
996 const char *filename;
998 FILE *e;
999 char *real_filename;
1000 int type, count, i;
1001 struct icondir *icondirs;
1002 int first_icon;
1003 struct res_resource *r;
1004 struct group_icon *first, **pp;
1006 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1008 /* The start of an icon file is a three word structure. The first
1009 word is ignored. The second word is the type of data. The third
1010 word is the number of entries. */
1012 get_word (e, real_filename);
1013 type = get_word (e, real_filename);
1014 count = get_word (e, real_filename);
1015 if (type != 1)
1016 fatal (_("icon file `%s' does not contain icon data"), real_filename);
1018 /* Read in the icon directory entries. */
1020 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1022 for (i = 0; i < count; i++)
1024 icondirs[i].width = getc (e);
1025 icondirs[i].height = getc (e);
1026 icondirs[i].colorcount = getc (e);
1027 getc (e);
1028 icondirs[i].u.icon.planes = get_word (e, real_filename);
1029 icondirs[i].u.icon.bits = get_word (e, real_filename);
1030 icondirs[i].bytes = get_long (e, real_filename);
1031 icondirs[i].offset = get_long (e, real_filename);
1033 if (feof (e))
1034 unexpected_eof (real_filename);
1037 /* Define each icon as a unique resource. */
1039 first_icon = icons;
1041 for (i = 0; i < count; i++)
1043 unsigned char *data;
1044 struct res_id name;
1046 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1047 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1048 icondirs[i].offset, strerror (errno));
1050 data = (unsigned char *) res_alloc (icondirs[i].bytes);
1052 get_data (e, data, icondirs[i].bytes, real_filename);
1054 ++icons;
1056 name.named = 0;
1057 name.u.id = icons;
1059 r = define_standard_resource (&resources, RT_ICON, name,
1060 resinfo->language, 0);
1061 r->type = RES_TYPE_ICON;
1062 r->u.data.length = icondirs[i].bytes;
1063 r->u.data.data = data;
1064 r->res_info = *resinfo;
1067 fclose (e);
1068 free (real_filename);
1070 /* Define an icon group resource. */
1072 first = NULL;
1073 pp = &first;
1074 for (i = 0; i < count; i++)
1076 struct group_icon *cg;
1078 /* For some reason, at least in some files the planes and bits
1079 are zero. We instead set them from the color. This is
1080 copied from rcl. */
1082 cg = (struct group_icon *) res_alloc (sizeof *cg);
1083 cg->next = NULL;
1084 cg->width = icondirs[i].width;
1085 cg->height = icondirs[i].height;
1086 cg->colors = icondirs[i].colorcount;
1088 cg->planes = 1;
1089 cg->bits = 0;
1090 while ((1 << cg->bits) < cg->colors)
1091 ++cg->bits;
1093 cg->bytes = icondirs[i].bytes;
1094 cg->index = first_icon + i + 1;
1096 *pp = cg;
1097 pp = &(*pp)->next;
1100 free (icondirs);
1102 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1103 resinfo->language, 0);
1104 r->type = RES_TYPE_GROUP_ICON;
1105 r->u.group_icon = first;
1106 r->res_info = *resinfo;
1109 /* Define a menu resource. */
1111 void
1112 define_menu (id, resinfo, menuitems)
1113 struct res_id id;
1114 const struct res_res_info *resinfo;
1115 struct menuitem *menuitems;
1117 struct menu *m;
1118 struct res_resource *r;
1120 m = (struct menu *) res_alloc (sizeof *m);
1121 m->items = menuitems;
1122 m->help = 0;
1124 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1125 r->type = RES_TYPE_MENU;
1126 r->u.menu = m;
1127 r->res_info = *resinfo;
1130 /* Define a menu item. This does not define a resource, but merely
1131 allocates and fills in a structure. */
1133 struct menuitem *
1134 define_menuitem (text, menuid, type, state, help, menuitems)
1135 const char *text;
1136 int menuid;
1137 unsigned long type;
1138 unsigned long state;
1139 unsigned long help;
1140 struct menuitem *menuitems;
1142 struct menuitem *mi;
1144 mi = (struct menuitem *) res_alloc (sizeof *mi);
1145 mi->next = NULL;
1146 mi->type = type;
1147 mi->state = state;
1148 mi->id = menuid;
1149 if (text == NULL)
1150 mi->text = NULL;
1151 else
1152 unicode_from_ascii ((int *) NULL, &mi->text, text);
1153 mi->help = help;
1154 mi->popup = menuitems;
1155 return mi;
1158 /* Define a messagetable resource. */
1160 void
1161 define_messagetable (id, resinfo, filename)
1162 struct res_id id;
1163 const struct res_res_info *resinfo;
1164 const char *filename;
1166 FILE *e;
1167 char *real_filename;
1168 struct stat s;
1169 unsigned char *data;
1170 struct res_resource *r;
1172 e = open_file_search (filename, FOPEN_RB, "messagetable file",
1173 &real_filename);
1175 if (stat (real_filename, &s) < 0)
1176 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1177 strerror (errno));
1179 data = (unsigned char *) res_alloc (s.st_size);
1181 get_data (e, data, s.st_size, real_filename);
1183 fclose (e);
1184 free (real_filename);
1186 r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1187 resinfo->language, 0);
1189 r->type = RES_TYPE_MESSAGETABLE;
1190 r->u.data.length = s.st_size;
1191 r->u.data.data = data;
1192 r->res_info = *resinfo;
1195 /* Define an rcdata resource. */
1197 void
1198 define_rcdata (id, resinfo, data)
1199 struct res_id id;
1200 const struct res_res_info *resinfo;
1201 struct rcdata_item *data;
1203 struct res_resource *r;
1205 r = define_standard_resource (&resources, RT_RCDATA, id,
1206 resinfo->language, 0);
1207 r->type = RES_TYPE_RCDATA;
1208 r->u.rcdata = data;
1209 r->res_info = *resinfo;
1212 /* Create an rcdata item holding a string. */
1214 struct rcdata_item *
1215 define_rcdata_string (string, len)
1216 const char *string;
1217 unsigned long len;
1219 struct rcdata_item *ri;
1220 char *s;
1222 ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1223 ri->next = NULL;
1224 ri->type = RCDATA_STRING;
1225 ri->u.string.length = len;
1226 s = (char *) res_alloc (len);
1227 memcpy (s, string, len);
1228 ri->u.string.s = s;
1230 return ri;
1233 /* Create an rcdata item holding a number. */
1235 struct rcdata_item *
1236 define_rcdata_number (val, dword)
1237 unsigned long val;
1238 int dword;
1240 struct rcdata_item *ri;
1242 ri = (struct rcdata_item *) res_alloc (sizeof *ri);
1243 ri->next = NULL;
1244 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1245 ri->u.word = val;
1247 return ri;
1250 /* Define a stringtable resource. This is called for each string
1251 which appears in a STRINGTABLE statement. */
1253 void
1254 define_stringtable (resinfo, stringid, string)
1255 const struct res_res_info *resinfo;
1256 unsigned long stringid;
1257 const char *string;
1259 struct res_id id;
1260 struct res_resource *r;
1262 id.named = 0;
1263 id.u.id = (stringid >> 4) + 1;
1264 r = define_standard_resource (&resources, RT_STRING, id,
1265 resinfo->language, 1);
1267 if (r->type == RES_TYPE_UNINITIALIZED)
1269 int i;
1271 r->type = RES_TYPE_STRINGTABLE;
1272 r->u.stringtable = ((struct stringtable *)
1273 res_alloc (sizeof (struct stringtable)));
1274 for (i = 0; i < 16; i++)
1276 r->u.stringtable->strings[i].length = 0;
1277 r->u.stringtable->strings[i].string = NULL;
1280 r->res_info = *resinfo;
1283 unicode_from_ascii (&r->u.stringtable->strings[stringid & 0xf].length,
1284 &r->u.stringtable->strings[stringid & 0xf].string,
1285 string);
1288 /* Define a user data resource where the data is in the rc file. */
1290 void
1291 define_user_data (id, type, resinfo, data)
1292 struct res_id id;
1293 struct res_id type;
1294 const struct res_res_info *resinfo;
1295 struct rcdata_item *data;
1297 struct res_id ids[3];
1298 struct res_resource *r;
1300 ids[0] = type;
1301 ids[1] = id;
1302 ids[2].named = 0;
1303 ids[2].u.id = resinfo->language;
1305 r = define_resource (&resources, 3, ids, 0);
1306 r->type = RES_TYPE_USERDATA;
1307 r->u.userdata = data;
1308 r->res_info = *resinfo;
1311 /* Define a user data resource where the data is in a file. */
1313 void
1314 define_user_file (id, type, resinfo, filename)
1315 struct res_id id;
1316 struct res_id type;
1317 const struct res_res_info *resinfo;
1318 const char *filename;
1320 FILE *e;
1321 char *real_filename;
1322 struct stat s;
1323 unsigned char *data;
1324 struct res_id ids[3];
1325 struct res_resource *r;
1327 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
1329 if (stat (real_filename, &s) < 0)
1330 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1331 strerror (errno));
1333 data = (unsigned char *) res_alloc (s.st_size);
1335 get_data (e, data, s.st_size, real_filename);
1337 fclose (e);
1338 free (real_filename);
1340 ids[0] = type;
1341 ids[1] = id;
1342 ids[2].named = 0;
1343 ids[2].u.id = resinfo->language;
1345 r = define_resource (&resources, 3, ids, 0);
1346 r->type = RES_TYPE_USERDATA;
1347 r->u.userdata = ((struct rcdata_item *)
1348 res_alloc (sizeof (struct rcdata_item)));
1349 r->u.userdata->next = NULL;
1350 r->u.userdata->type = RCDATA_BUFFER;
1351 r->u.userdata->u.buffer.length = s.st_size;
1352 r->u.userdata->u.buffer.data = data;
1353 r->res_info = *resinfo;
1356 /* Define a versioninfo resource. */
1358 void
1359 define_versioninfo (id, language, fixedverinfo, verinfo)
1360 struct res_id id;
1361 int language;
1362 struct fixed_versioninfo *fixedverinfo;
1363 struct ver_info *verinfo;
1365 struct res_resource *r;
1367 r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1368 r->type = RES_TYPE_VERSIONINFO;
1369 r->u.versioninfo = ((struct versioninfo *)
1370 res_alloc (sizeof (struct versioninfo)));
1371 r->u.versioninfo->fixed = fixedverinfo;
1372 r->u.versioninfo->var = verinfo;
1373 r->res_info.language = language;
1376 /* Add string version info to a list of version information. */
1378 struct ver_info *
1379 append_ver_stringfileinfo (verinfo, language, strings)
1380 struct ver_info *verinfo;
1381 const char *language;
1382 struct ver_stringinfo *strings;
1384 struct ver_info *vi, **pp;
1386 vi = (struct ver_info *) res_alloc (sizeof *vi);
1387 vi->next = NULL;
1388 vi->type = VERINFO_STRING;
1389 unicode_from_ascii ((int *) NULL, &vi->u.string.language, language);
1390 vi->u.string.strings = strings;
1392 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1394 *pp = vi;
1396 return verinfo;
1399 /* Add variable version info to a list of version information. */
1401 struct ver_info *
1402 append_ver_varfileinfo (verinfo, key, var)
1403 struct ver_info *verinfo;
1404 const char *key;
1405 struct ver_varinfo *var;
1407 struct ver_info *vi, **pp;
1409 vi = (struct ver_info *) res_alloc (sizeof *vi);
1410 vi->next = NULL;
1411 vi->type = VERINFO_VAR;
1412 unicode_from_ascii ((int *) NULL, &vi->u.var.key, key);
1413 vi->u.var.var = var;
1415 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1417 *pp = vi;
1419 return verinfo;
1422 /* Append version string information to a list. */
1424 struct ver_stringinfo *
1425 append_verval (strings, key, value)
1426 struct ver_stringinfo *strings;
1427 const char *key;
1428 const char *value;
1430 struct ver_stringinfo *vs, **pp;
1432 vs = (struct ver_stringinfo *) res_alloc (sizeof *vs);
1433 vs->next = NULL;
1434 unicode_from_ascii ((int *) NULL, &vs->key, key);
1435 unicode_from_ascii ((int *) NULL, &vs->value, value);
1437 for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1439 *pp = vs;
1441 return strings;
1444 /* Append version variable information to a list. */
1446 struct ver_varinfo *
1447 append_vertrans (var, language, charset)
1448 struct ver_varinfo *var;
1449 unsigned long language;
1450 unsigned long charset;
1452 struct ver_varinfo *vv, **pp;
1454 vv = (struct ver_varinfo *) res_alloc (sizeof *vv);
1455 vv->next = NULL;
1456 vv->language = language;
1457 vv->charset = charset;
1459 for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1461 *pp = vv;
1463 return var;
1466 /* Local functions used to write out an rc file. */
1468 static void indent PARAMS ((FILE *, int));
1469 static void write_rc_directory
1470 PARAMS ((FILE *, const struct res_directory *, const struct res_id *,
1471 const struct res_id *, int *, int));
1472 static void write_rc_subdir
1473 PARAMS ((FILE *, const struct res_entry *, const struct res_id *,
1474 const struct res_id *, int *, int));
1475 static void write_rc_resource
1476 PARAMS ((FILE *, const struct res_id *, const struct res_id *,
1477 const struct res_resource *, int *));
1478 static void write_rc_accelerators
1479 PARAMS ((FILE *, const struct accelerator *));
1480 static void write_rc_cursor PARAMS ((FILE *, const struct cursor *));
1481 static void write_rc_group_cursor
1482 PARAMS ((FILE *, const struct group_cursor *));
1483 static void write_rc_dialog PARAMS ((FILE *, const struct dialog *));
1484 static void write_rc_dialog_control
1485 PARAMS ((FILE *, const struct dialog_control *));
1486 static void write_rc_fontdir PARAMS ((FILE *, const struct fontdir *));
1487 static void write_rc_group_icon PARAMS ((FILE *, const struct group_icon *));
1488 static void write_rc_menu PARAMS ((FILE *, const struct menu *, int));
1489 static void write_rc_menuitems
1490 PARAMS ((FILE *, const struct menuitem *, int, int));
1491 static void write_rc_rcdata PARAMS ((FILE *, const struct rcdata_item *, int));
1492 static void write_rc_stringtable
1493 PARAMS ((FILE *, const struct res_id *, const struct stringtable *));
1494 static void write_rc_versioninfo PARAMS ((FILE *, const struct versioninfo *));
1495 static void write_rc_filedata
1496 PARAMS ((FILE *, unsigned long, const unsigned char *));
1498 /* Indent a given number of spaces. */
1500 static void
1501 indent (e, c)
1502 FILE *e;
1503 int c;
1505 int i;
1507 for (i = 0; i < c; i++)
1508 putc (' ', e);
1511 /* Dump the resources we have read in the format of an rc file.
1513 Actually, we don't use the format of an rc file, because it's way
1514 too much of a pain--for example, we'd have to write icon resources
1515 into a file and refer to that file. We just generate a readable
1516 format that kind of looks like an rc file, and is useful for
1517 understanding the contents of a resource file. Someday we may want
1518 to generate an rc file which the rc compiler can read; if that day
1519 comes, this code will have to be fixed up. */
1521 void
1522 write_rc_file (filename, resources)
1523 const char *filename;
1524 const struct res_directory *resources;
1526 FILE *e;
1527 int language;
1529 if (filename == NULL)
1530 e = stdout;
1531 else
1533 e = fopen (filename, FOPEN_WT);
1534 if (e == NULL)
1535 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1538 language = -1;
1539 write_rc_directory (e, resources, (const struct res_id *) NULL,
1540 (const struct res_id *) NULL, &language, 1);
1543 /* Write out a directory. E is the file to write to. RD is the
1544 directory. TYPE is a pointer to the level 1 ID which serves as the
1545 resource type. NAME is a pointer to the level 2 ID which serves as
1546 an individual resource name. LANGUAGE is a pointer to the current
1547 language. LEVEL is the level in the tree. */
1549 static void
1550 write_rc_directory (e, rd, type, name, language, level)
1551 FILE *e;
1552 const struct res_directory *rd;
1553 const struct res_id *type;
1554 const struct res_id *name;
1555 int *language;
1556 int level;
1558 const struct res_entry *re;
1560 /* Print out some COFF information that rc files can't represent. */
1562 if (rd->time != 0)
1563 fprintf (e, "// Time stamp: %lu\n", rd->time);
1564 if (rd->characteristics != 0)
1565 fprintf (e, "// Characteristics: %lu\n", rd->characteristics);
1566 if (rd->major != 0 || rd->minor != 0)
1567 fprintf (e, "// Version: %d %d\n", rd->major, rd->minor);
1569 for (re = rd->entries; re != NULL; re = re->next)
1571 switch (level)
1573 case 1:
1574 /* If we're at level 1, the key of this resource is the
1575 type. This normally duplicates the information we have
1576 stored with the resource itself, but we need to remember
1577 the type if this is a user define resource type. */
1578 type = &re->id;
1579 break;
1581 case 2:
1582 /* If we're at level 2, the key of this resource is the name
1583 we are going to use in the rc printout. */
1584 name = &re->id;
1585 break;
1587 case 3:
1588 /* If we're at level 3, then this key represents a language.
1589 Use it to update the current language. */
1590 if (! re->id.named
1591 && re->id.u.id != (unsigned long) (unsigned int) *language
1592 && (re->id.u.id & 0xffff) == re->id.u.id)
1594 fprintf (e, "LANGUAGE %lu, %lu\n",
1595 re->id.u.id & 0xff, (re->id.u.id >> 8) & 0xff);
1596 *language = re->id.u.id;
1598 break;
1600 default:
1601 break;
1604 if (re->subdir)
1605 write_rc_subdir (e, re, type, name, language, level);
1606 else
1608 if (level == 3)
1610 /* This is the normal case: the three levels are
1611 TYPE/NAME/LANGUAGE. NAME will have been set at level
1612 2, and represents the name to use. We probably just
1613 set LANGUAGE, and it will probably match what the
1614 resource itself records if anything. */
1615 write_rc_resource (e, type, name, re->u.res, language);
1617 else
1619 fprintf (e, "// Resource at unexpected level %d\n", level);
1620 write_rc_resource (e, type, (struct res_id *) NULL, re->u.res,
1621 language);
1627 /* Write out a subdirectory entry. E is the file to write to. RE is
1628 the subdirectory entry. TYPE and NAME are pointers to higher level
1629 IDs, or NULL. LANGUAGE is a pointer to the current language.
1630 LEVEL is the level in the tree. */
1632 static void
1633 write_rc_subdir (e, re, type, name, language, level)
1634 FILE *e;
1635 const struct res_entry *re;
1636 const struct res_id *type;
1637 const struct res_id *name;
1638 int *language;
1639 int level;
1641 fprintf (e, "\n");
1642 switch (level)
1644 case 1:
1645 fprintf (e, "// Type: ");
1646 if (re->id.named)
1647 res_id_print (e, re->id, 1);
1648 else
1650 const char *s;
1652 switch (re->id.u.id)
1654 case RT_CURSOR: s = "cursor"; break;
1655 case RT_BITMAP: s = "bitmap"; break;
1656 case RT_ICON: s = "icon"; break;
1657 case RT_MENU: s = "menu"; break;
1658 case RT_DIALOG: s = "dialog"; break;
1659 case RT_STRING: s = "stringtable"; break;
1660 case RT_FONTDIR: s = "fontdir"; break;
1661 case RT_FONT: s = "font"; break;
1662 case RT_ACCELERATOR: s = "accelerators"; break;
1663 case RT_RCDATA: s = "rcdata"; break;
1664 case RT_MESSAGETABLE: s = "messagetable"; break;
1665 case RT_GROUP_CURSOR: s = "group cursor"; break;
1666 case RT_GROUP_ICON: s = "group icon"; break;
1667 case RT_VERSION: s = "version"; break;
1668 case RT_DLGINCLUDE: s = "dlginclude"; break;
1669 case RT_PLUGPLAY: s = "plugplay"; break;
1670 case RT_VXD: s = "vxd"; break;
1671 case RT_ANICURSOR: s = "anicursor"; break;
1672 case RT_ANIICON: s = "aniicon"; break;
1673 default: s = NULL; break;
1676 if (s != NULL)
1677 fprintf (e, "%s", s);
1678 else
1679 res_id_print (e, re->id, 1);
1681 fprintf (e, "\n");
1682 break;
1684 case 2:
1685 fprintf (e, "// Name: ");
1686 res_id_print (e, re->id, 1);
1687 fprintf (e, "\n");
1688 break;
1690 case 3:
1691 fprintf (e, "// Language: ");
1692 res_id_print (e, re->id, 1);
1693 fprintf (e, "\n");
1694 break;
1696 default:
1697 fprintf (e, "// Level %d: ", level);
1698 res_id_print (e, re->id, 1);
1699 fprintf (e, "\n");
1702 write_rc_directory (e, re->u.dir, type, name, language, level + 1);
1705 /* Write out a single resource. E is the file to write to. TYPE is a
1706 pointer to the type of the resource. NAME is a pointer to the name
1707 of the resource; it will be NULL if there is a level mismatch. RES
1708 is the resource data. LANGUAGE is a pointer to the current
1709 language. */
1711 static void
1712 write_rc_resource (e, type, name, res, language)
1713 FILE *e;
1714 const struct res_id *type;
1715 const struct res_id *name;
1716 const struct res_resource *res;
1717 int *language;
1719 const char *s;
1720 int rt;
1721 int menuex = 0;
1723 fprintf (e, "\n");
1725 switch (res->type)
1727 default:
1728 abort ();
1730 case RES_TYPE_ACCELERATOR:
1731 s = "ACCELERATOR";
1732 rt = RT_ACCELERATOR;
1733 break;
1735 case RES_TYPE_BITMAP:
1736 s = "BITMAP";
1737 rt = RT_BITMAP;
1738 break;
1740 case RES_TYPE_CURSOR:
1741 s = "CURSOR";
1742 rt = RT_CURSOR;
1743 break;
1745 case RES_TYPE_GROUP_CURSOR:
1746 s = "GROUP_CURSOR";
1747 rt = RT_GROUP_CURSOR;
1748 break;
1750 case RES_TYPE_DIALOG:
1751 if (extended_dialog (res->u.dialog))
1752 s = "DIALOGEX";
1753 else
1754 s = "DIALOG";
1755 rt = RT_DIALOG;
1756 break;
1758 case RES_TYPE_FONT:
1759 s = "FONT";
1760 rt = RT_FONT;
1761 break;
1763 case RES_TYPE_FONTDIR:
1764 s = "FONTDIR";
1765 rt = RT_FONTDIR;
1766 break;
1768 case RES_TYPE_ICON:
1769 s = "ICON";
1770 rt = RT_ICON;
1771 break;
1773 case RES_TYPE_GROUP_ICON:
1774 s = "GROUP_ICON";
1775 rt = RT_GROUP_ICON;
1776 break;
1778 case RES_TYPE_MENU:
1779 if (extended_menu (res->u.menu))
1781 s = "MENUEX";
1782 menuex = 1;
1784 else
1786 s = "MENU";
1787 menuex = 0;
1789 rt = RT_MENU;
1790 break;
1792 case RES_TYPE_MESSAGETABLE:
1793 s = "MESSAGETABLE";
1794 rt = RT_MESSAGETABLE;
1795 break;
1797 case RES_TYPE_RCDATA:
1798 s = "RCDATA";
1799 rt = RT_RCDATA;
1800 break;
1802 case RES_TYPE_STRINGTABLE:
1803 s = "STRINGTABLE";
1804 rt = RT_STRING;
1805 break;
1807 case RES_TYPE_USERDATA:
1808 s = NULL;
1809 rt = 0;
1810 break;
1812 case RES_TYPE_VERSIONINFO:
1813 s = "VERSIONINFO";
1814 rt = RT_VERSION;
1815 break;
1818 if (rt != 0
1819 && type != NULL
1820 && (type->named || type->u.id != (unsigned long) rt))
1822 fprintf (e, "// Unexpected resource type mismatch: ");
1823 res_id_print (e, *type, 1);
1824 fprintf (e, " != %d", rt);
1827 if (res->coff_info.codepage != 0)
1828 fprintf (e, "// Code page: %lu\n", res->coff_info.codepage);
1829 if (res->coff_info.reserved != 0)
1830 fprintf (e, "// COFF reserved value: %lu\n", res->coff_info.reserved);
1832 if (name != NULL)
1833 res_id_print (e, *name, 0);
1834 else
1835 fprintf (e, "??Unknown-Name??");
1837 fprintf (e, " ");
1838 if (s != NULL)
1839 fprintf (e, "%s", s);
1840 else if (type != NULL)
1841 res_id_print (e, *type, 0);
1842 else
1843 fprintf (e, "??Unknown-Type??");
1845 if (res->res_info.memflags != 0)
1847 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
1848 fprintf (e, " MOVEABLE");
1849 if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
1850 fprintf (e, " PURE");
1851 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
1852 fprintf (e, " PRELOAD");
1853 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
1854 fprintf (e, " DISCARDABLE");
1857 if (res->type == RES_TYPE_DIALOG)
1859 fprintf (e, " %d, %d, %d, %d", res->u.dialog->x, res->u.dialog->y,
1860 res->u.dialog->width, res->u.dialog->height);
1861 if (res->u.dialog->ex != NULL
1862 && res->u.dialog->ex->help != 0)
1863 fprintf (e, ", %lu", res->u.dialog->ex->help);
1866 fprintf (e, "\n");
1868 if ((res->res_info.language != 0 && res->res_info.language != *language)
1869 || res->res_info.characteristics != 0
1870 || res->res_info.version != 0)
1872 int modifiers;
1874 switch (res->type)
1876 case RES_TYPE_ACCELERATOR:
1877 case RES_TYPE_DIALOG:
1878 case RES_TYPE_MENU:
1879 case RES_TYPE_RCDATA:
1880 case RES_TYPE_STRINGTABLE:
1881 modifiers = 1;
1882 break;
1884 default:
1885 modifiers = 0;
1886 break;
1889 if (res->res_info.language != 0 && res->res_info.language != *language)
1890 fprintf (e, "%sLANGUAGE %d, %d\n",
1891 modifiers ? "// " : "",
1892 res->res_info.language & 0xff,
1893 (res->res_info.language >> 8) & 0xff);
1894 if (res->res_info.characteristics != 0)
1895 fprintf (e, "%sCHARACTERISTICS %lu\n",
1896 modifiers ? "// " : "",
1897 res->res_info.characteristics);
1898 if (res->res_info.version != 0)
1899 fprintf (e, "%sVERSION %lu\n",
1900 modifiers ? "// " : "",
1901 res->res_info.version);
1904 switch (res->type)
1906 default:
1907 abort ();
1909 case RES_TYPE_ACCELERATOR:
1910 write_rc_accelerators (e, res->u.acc);
1911 break;
1913 case RES_TYPE_CURSOR:
1914 write_rc_cursor (e, res->u.cursor);
1915 break;
1917 case RES_TYPE_GROUP_CURSOR:
1918 write_rc_group_cursor (e, res->u.group_cursor);
1919 break;
1921 case RES_TYPE_DIALOG:
1922 write_rc_dialog (e, res->u.dialog);
1923 break;
1925 case RES_TYPE_FONTDIR:
1926 write_rc_fontdir (e, res->u.fontdir);
1927 break;
1929 case RES_TYPE_GROUP_ICON:
1930 write_rc_group_icon (e, res->u.group_icon);
1931 break;
1933 case RES_TYPE_MENU:
1934 write_rc_menu (e, res->u.menu, menuex);
1935 break;
1937 case RES_TYPE_RCDATA:
1938 write_rc_rcdata (e, res->u.rcdata, 0);
1939 break;
1941 case RES_TYPE_STRINGTABLE:
1942 write_rc_stringtable (e, name, res->u.stringtable);
1943 break;
1945 case RES_TYPE_USERDATA:
1946 write_rc_rcdata (e, res->u.userdata, 0);
1947 break;
1949 case RES_TYPE_VERSIONINFO:
1950 write_rc_versioninfo (e, res->u.versioninfo);
1951 break;
1953 case RES_TYPE_BITMAP:
1954 case RES_TYPE_FONT:
1955 case RES_TYPE_ICON:
1956 case RES_TYPE_MESSAGETABLE:
1957 write_rc_filedata (e, res->u.data.length, res->u.data.data);
1958 break;
1962 /* Write out accelerator information. */
1964 static void
1965 write_rc_accelerators (e, accelerators)
1966 FILE *e;
1967 const struct accelerator *accelerators;
1969 const struct accelerator *acc;
1971 fprintf (e, "BEGIN\n");
1972 for (acc = accelerators; acc != NULL; acc = acc->next)
1974 int printable;
1976 fprintf (e, " ");
1978 if ((acc->key & 0x7f) == acc->key
1979 && isprint ((unsigned char) acc->key)
1980 && (acc->flags & ACC_VIRTKEY) == 0)
1982 fprintf (e, "\"%c\"", acc->key);
1983 printable = 1;
1985 else
1987 fprintf (e, "%d", acc->key);
1988 printable = 0;
1991 fprintf (e, ", %d", acc->id);
1993 if (! printable)
1995 if ((acc->flags & ACC_VIRTKEY) != 0)
1996 fprintf (e, ", VIRTKEY");
1997 else
1998 fprintf (e, ", ASCII");
2001 if ((acc->flags & ACC_SHIFT) != 0)
2002 fprintf (e, ", SHIFT");
2003 if ((acc->flags & ACC_CONTROL) != 0)
2004 fprintf (e, ", CONTROL");
2005 if ((acc->flags & ACC_ALT) != 0)
2006 fprintf (e, ", ALT");
2008 fprintf (e, "\n");
2011 fprintf (e, "END\n");
2014 /* Write out cursor information. This would normally be in a separate
2015 file, which the rc file would include. */
2017 static void
2018 write_rc_cursor (e, cursor)
2019 FILE *e;
2020 const struct cursor *cursor;
2022 fprintf (e, "// Hotspot: x: %d; y: %d\n", cursor->xhotspot,
2023 cursor->yhotspot);
2024 write_rc_filedata (e, cursor->length, cursor->data);
2027 /* Write out group cursor data. This would normally be built from the
2028 cursor data. */
2030 static void
2031 write_rc_group_cursor (e, group_cursor)
2032 FILE *e;
2033 const struct group_cursor *group_cursor;
2035 const struct group_cursor *gc;
2037 for (gc = group_cursor; gc != NULL; gc = gc->next)
2039 fprintf (e, "// width: %d; height %d; planes %d; bits %d\n",
2040 gc->width, gc->height, gc->planes, gc->bits);
2041 fprintf (e, "// data bytes: %lu; index: %d\n",
2042 gc->bytes, gc->index);
2046 /* Write dialog data. */
2048 static void
2049 write_rc_dialog (e, dialog)
2050 FILE *e;
2051 const struct dialog *dialog;
2053 const struct dialog_control *control;
2055 if (dialog->style != 0)
2056 fprintf (e, "STYLE 0x%lx\n", dialog->style);
2057 if (dialog->exstyle != 0)
2058 fprintf (e, "EXSTYLE 0x%lx\n", dialog->exstyle);
2059 if ((dialog->class.named && dialog->class.u.n.length > 0)
2060 || dialog->class.u.id != 0)
2062 fprintf (e, "CLASS ");
2063 res_id_print (e, dialog->class, 0);
2064 fprintf (e, "\n");
2066 if (dialog->caption != NULL)
2068 fprintf (e, "CAPTION \"");
2069 unicode_print (e, dialog->caption, -1);
2070 fprintf (e, "\"\n");
2072 if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2073 || dialog->menu.u.id != 0)
2075 fprintf (e, "MENU ");
2076 res_id_print (e, dialog->menu, 0);
2077 fprintf (e, "\n");
2079 if (dialog->font != NULL)
2081 fprintf (e, "FONT %d, \"", dialog->pointsize);
2082 unicode_print (e, dialog->font, -1);
2083 fprintf (e, "\"");
2084 if (dialog->ex != NULL
2085 && (dialog->ex->weight != 0 || dialog->ex->italic != 0))
2086 fprintf (e, ", %d, %d", dialog->ex->weight, dialog->ex->italic);
2087 fprintf (e, "\n");
2090 fprintf (e, "BEGIN\n");
2092 for (control = dialog->controls; control != NULL; control = control->next)
2093 write_rc_dialog_control (e, control);
2095 fprintf (e, "END\n");
2098 /* For each predefined control keyword, this table provides the class
2099 and the style. */
2101 struct control_info
2103 const char *name;
2104 unsigned short class;
2105 unsigned long style;
2108 static const struct control_info control_info[] =
2110 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2111 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2112 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2113 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2114 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2115 { "CTEXT", CTL_STATIC, SS_CENTER },
2116 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2117 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2118 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2119 { "ICON", CTL_STATIC, SS_ICON },
2120 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2121 { "LTEXT", CTL_STATIC, SS_LEFT },
2122 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2123 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2124 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2125 { "RTEXT", CTL_STATIC, SS_RIGHT },
2126 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2127 { "STATE3", CTL_BUTTON, BS_3STATE },
2128 /* It's important that USERBUTTON come after all the other button
2129 types, so that it won't be matched too early. */
2130 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2131 { NULL, 0, 0 }
2134 /* Write a dialog control. */
2136 static void
2137 write_rc_dialog_control (e, control)
2138 FILE *e;
2139 const struct dialog_control *control;
2141 const struct control_info *ci;
2143 fprintf (e, " ");
2145 if (control->class.named)
2146 ci = NULL;
2147 else
2149 for (ci = control_info; ci->name != NULL; ++ci)
2150 if (ci->class == control->class.u.id
2151 && (ci->style == (unsigned long) -1
2152 || ci->style == (control->style & 0xff)))
2153 break;
2155 if (ci == NULL)
2156 fprintf (e, "CONTROL");
2157 else if (ci->name != NULL)
2158 fprintf (e, "%s", ci->name);
2159 else
2160 fprintf (e, "CONTROL");
2162 if (control->text.named || control->text.u.id != 0)
2164 fprintf (e, " ");
2165 res_id_print (e, control->text, 1);
2166 fprintf (e, ",");
2169 fprintf (e, " %d, ", control->id);
2171 if (ci == NULL)
2173 if (control->class.named)
2174 fprintf (e, "\"");
2175 res_id_print (e, control->class, 0);
2176 if (control->class.named)
2177 fprintf (e, "\"");
2178 fprintf (e, ", 0x%lx, ", control->style);
2181 fprintf (e, "%d, %d", control->x, control->y);
2183 if (control->style != SS_ICON
2184 || control->exstyle != 0
2185 || control->width != 0
2186 || control->height != 0
2187 || control->help != 0)
2189 fprintf (e, ", %d, %d", control->width, control->height);
2191 /* FIXME: We don't need to print the style if it is the default.
2192 More importantly, in certain cases we actually need to turn
2193 off parts of the forced style, by using NOT. */
2194 fprintf (e, ", 0x%lx", control->style);
2196 if (control->exstyle != 0 || control->help != 0)
2197 fprintf (e, ", 0x%lx, %lu", control->exstyle, control->help);
2200 fprintf (e, "\n");
2202 if (control->data != NULL)
2203 write_rc_rcdata (e, control->data, 2);
2206 /* Write out font directory data. This would normally be built from
2207 the font data. */
2209 static void
2210 write_rc_fontdir (e, fontdir)
2211 FILE *e;
2212 const struct fontdir *fontdir;
2214 const struct fontdir *fc;
2216 for (fc = fontdir; fc != NULL; fc = fc->next)
2218 fprintf (e, "// Font index: %d\n", fc->index);
2219 write_rc_filedata (e, fc->length, fc->data);
2223 /* Write out group icon data. This would normally be built from the
2224 icon data. */
2226 static void
2227 write_rc_group_icon (e, group_icon)
2228 FILE *e;
2229 const struct group_icon *group_icon;
2231 const struct group_icon *gi;
2233 for (gi = group_icon; gi != NULL; gi = gi->next)
2235 fprintf (e, "// width: %d; height %d; colors: %d; planes %d; bits %d\n",
2236 gi->width, gi->height, gi->colors, gi->planes, gi->bits);
2237 fprintf (e, "// data bytes: %lu; index: %d\n",
2238 gi->bytes, gi->index);
2242 /* Write out a menu resource. */
2244 static void
2245 write_rc_menu (e, menu, menuex)
2246 FILE *e;
2247 const struct menu *menu;
2248 int menuex;
2250 if (menu->help != 0)
2251 fprintf (e, "// Help ID: %lu\n", menu->help);
2252 write_rc_menuitems (e, menu->items, menuex, 0);
2255 /* Write out menuitems. */
2257 static void
2258 write_rc_menuitems (e, menuitems, menuex, ind)
2259 FILE *e;
2260 const struct menuitem *menuitems;
2261 int menuex;
2262 int ind;
2264 const struct menuitem *mi;
2266 indent (e, ind);
2267 fprintf (e, "BEGIN\n");
2269 for (mi = menuitems; mi != NULL; mi = mi->next)
2271 indent (e, ind + 2);
2273 if (mi->popup == NULL)
2274 fprintf (e, "MENUITEM");
2275 else
2276 fprintf (e, "POPUP");
2278 if (! menuex
2279 && mi->popup == NULL
2280 && mi->text == NULL
2281 && mi->type == 0
2282 && mi->id == 0)
2284 fprintf (e, " SEPARATOR\n");
2285 continue;
2288 if (mi->text == NULL)
2289 fprintf (e, " \"\"");
2290 else
2292 fprintf (e, " \"");
2293 unicode_print (e, mi->text, -1);
2294 fprintf (e, "\"");
2297 if (! menuex)
2299 if (mi->popup == NULL)
2300 fprintf (e, ", %d", mi->id);
2302 if ((mi->type & MENUITEM_CHECKED) != 0)
2303 fprintf (e, ", CHECKED");
2304 if ((mi->type & MENUITEM_GRAYED) != 0)
2305 fprintf (e, ", GRAYED");
2306 if ((mi->type & MENUITEM_HELP) != 0)
2307 fprintf (e, ", HELP");
2308 if ((mi->type & MENUITEM_INACTIVE) != 0)
2309 fprintf (e, ", INACTIVE");
2310 if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2311 fprintf (e, ", MENUBARBREAK");
2312 if ((mi->type & MENUITEM_MENUBREAK) != 0)
2313 fprintf (e, ", MENUBREAK");
2315 else
2317 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2319 fprintf (e, ", %d", mi->id);
2320 if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2322 fprintf (e, ", %lu", mi->type);
2323 if (mi->state != 0 || mi->help != 0)
2325 fprintf (e, ", %lu", mi->state);
2326 if (mi->help != 0)
2327 fprintf (e, ", %lu", mi->help);
2333 fprintf (e, "\n");
2335 if (mi->popup != NULL)
2336 write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2339 indent (e, ind);
2340 fprintf (e, "END\n");
2343 /* Write out an rcdata resource. This is also used for other types of
2344 resources that need to print arbitrary data. */
2346 static void
2347 write_rc_rcdata (e, rcdata, ind)
2348 FILE *e;
2349 const struct rcdata_item *rcdata;
2350 int ind;
2352 const struct rcdata_item *ri;
2354 indent (e, ind);
2355 fprintf (e, "BEGIN\n");
2357 for (ri = rcdata; ri != NULL; ri = ri->next)
2359 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
2360 continue;
2362 indent (e, ind + 2);
2364 switch (ri->type)
2366 default:
2367 abort ();
2369 case RCDATA_WORD:
2370 fprintf (e, "%d", ri->u.word);
2371 break;
2373 case RCDATA_DWORD:
2374 fprintf (e, "%luL", ri->u.dword);
2375 break;
2377 case RCDATA_STRING:
2379 const char *s;
2380 unsigned long i;
2382 fprintf (e, "\"");
2383 s = ri->u.string.s;
2384 for (i = 0; i < ri->u.string.length; i++)
2386 if (isprint ((unsigned char) *s))
2387 putc (*s, e);
2388 else
2389 fprintf (e, "\\%03o", *s);
2391 fprintf (e, "\"");
2392 break;
2395 case RCDATA_WSTRING:
2396 fprintf (e, "L\"");
2397 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
2398 fprintf (e, "\"");
2399 break;
2401 case RCDATA_BUFFER:
2403 unsigned long i;
2404 int first;
2406 /* Assume little endian data. */
2408 first = 1;
2409 for (i = 0; i + 3 < ri->u.buffer.length; i += 4)
2411 unsigned long l;
2412 int j;
2414 if (! first)
2415 indent (e, ind + 2);
2416 l = ((((((ri->u.buffer.data[i + 3] << 8)
2417 | ri->u.buffer.data[i + 2]) << 8)
2418 | ri->u.buffer.data[i + 1]) << 8)
2419 | ri->u.buffer.data[i]);
2420 fprintf (e, "%luL", l);
2421 if (i + 4 < ri->u.buffer.length || ri->next != NULL)
2422 fprintf (e, ",");
2423 for (j = 0; j < 4; ++j)
2424 if (! isprint (ri->u.buffer.data[i + j])
2425 && ri->u.buffer.data[i + j] != 0)
2426 break;
2427 if (j >= 4)
2429 fprintf (e, "\t// ");
2430 for (j = 0; j < 4; ++j)
2432 if (! isprint (ri->u.buffer.data[i + j]))
2433 fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2434 else
2436 if (ri->u.buffer.data[i + j] == '\\')
2437 fprintf (e, "\\");
2438 fprintf (e, "%c", ri->u.buffer.data[i + j]);
2442 fprintf (e, "\n");
2443 first = 0;
2446 if (i + 1 < ri->u.buffer.length)
2448 int s;
2449 int j;
2451 if (! first)
2452 indent (e, ind + 2);
2453 s = (ri->u.buffer.data[i + 1] << 8) | ri->u.buffer.data[i];
2454 fprintf (e, "%d", s);
2455 if (i + 2 < ri->u.buffer.length || ri->next != NULL)
2456 fprintf (e, ",");
2457 for (j = 0; j < 2; ++j)
2458 if (! isprint (ri->u.buffer.data[i + j])
2459 && ri->u.buffer.data[i + j] != 0)
2460 break;
2461 if (j >= 2)
2463 fprintf (e, "\t// ");
2464 for (j = 0; j < 2; ++j)
2466 if (! isprint (ri->u.buffer.data[i + j]))
2467 fprintf (e, "\\%03o", ri->u.buffer.data[i + j]);
2468 else
2470 if (ri->u.buffer.data[i + j] == '\\')
2471 fprintf (e, "\\");
2472 fprintf (e, "%c", ri->u.buffer.data[i + j]);
2476 fprintf (e, "\n");
2477 i += 2;
2478 first = 0;
2481 if (i < ri->u.buffer.length)
2483 if (! first)
2484 indent (e, ind + 2);
2485 if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i]
2486 && isprint (ri->u.buffer.data[i]))
2487 fprintf (e, "\"%c\"", ri->u.buffer.data[i]);
2488 else
2489 fprintf (e, "\"\\%03o\"", ri->u.buffer.data[i]);
2490 if (ri->next != NULL)
2491 fprintf (e, ",");
2492 fprintf (e, "\n");
2493 first = 0;
2496 break;
2500 if (ri->type != RCDATA_BUFFER)
2502 if (ri->next != NULL)
2503 fprintf (e, ",");
2504 fprintf (e, "\n");
2508 indent (e, ind);
2509 fprintf (e, "END\n");
2512 /* Write out a stringtable resource. */
2514 static void
2515 write_rc_stringtable (e, name, stringtable)
2516 FILE *e;
2517 const struct res_id *name;
2518 const struct stringtable *stringtable;
2520 unsigned long offset;
2521 int i;
2523 if (name != NULL && ! name->named)
2524 offset = (name->u.id - 1) << 4;
2525 else
2527 fprintf (e, "// %s string table name\n",
2528 name == NULL ? "Missing" : "Invalid");
2529 offset = 0;
2532 fprintf (e, "BEGIN\n");
2534 for (i = 0; i < 16; i++)
2536 if (stringtable->strings[i].length != 0)
2538 fprintf (e, " %lu, \"", offset + i);
2539 unicode_print (e, stringtable->strings[i].string,
2540 stringtable->strings[i].length);
2541 fprintf (e, "\"\n");
2545 fprintf (e, "END\n");
2548 /* Write out a versioninfo resource. */
2550 static void
2551 write_rc_versioninfo (e, versioninfo)
2552 FILE *e;
2553 const struct versioninfo *versioninfo;
2555 const struct fixed_versioninfo *f;
2556 const struct ver_info *vi;
2558 f = versioninfo->fixed;
2559 if (f->file_version_ms != 0 || f->file_version_ls != 0)
2560 fprintf (e, " FILEVERSION %lu, %lu, %lu, %lu\n",
2561 (f->file_version_ms >> 16) & 0xffff,
2562 f->file_version_ms & 0xffff,
2563 (f->file_version_ls >> 16) & 0xffff,
2564 f->file_version_ls & 0xffff);
2565 if (f->product_version_ms != 0 || f->product_version_ls != 0)
2566 fprintf (e, " PRODUCTVERSION %lu, %lu, %lu, %lu\n",
2567 (f->product_version_ms >> 16) & 0xffff,
2568 f->product_version_ms & 0xffff,
2569 (f->product_version_ls >> 16) & 0xffff,
2570 f->product_version_ls & 0xffff);
2571 if (f->file_flags_mask != 0)
2572 fprintf (e, " FILEFLAGSMASK 0x%lx\n", f->file_flags_mask);
2573 if (f->file_flags != 0)
2574 fprintf (e, " FILEFLAGS 0x%lx\n", f->file_flags);
2575 if (f->file_os != 0)
2576 fprintf (e, " FILEOS 0x%lx\n", f->file_os);
2577 if (f->file_type != 0)
2578 fprintf (e, " FILETYPE 0x%lx\n", f->file_type);
2579 if (f->file_subtype != 0)
2580 fprintf (e, " FILESUBTYPE 0x%lx\n", f->file_subtype);
2581 if (f->file_date_ms != 0 || f->file_date_ls != 0)
2582 fprintf (e, "// Date: %lu, %lu\n", f->file_date_ms, f->file_date_ls);
2584 fprintf (e, "BEGIN\n");
2586 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
2588 switch (vi->type)
2590 case VERINFO_STRING:
2592 const struct ver_stringinfo *vs;
2594 fprintf (e, " BLOCK \"StringFileInfo\"\n");
2595 fprintf (e, " BEGIN\n");
2596 fprintf (e, " BLOCK \"");
2597 unicode_print (e, vi->u.string.language, -1);
2598 fprintf (e, "\"\n");
2599 fprintf (e, " BEGIN\n");
2601 for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
2603 fprintf (e, " VALUE \"");
2604 unicode_print (e, vs->key, -1);
2605 fprintf (e, "\", \"");
2606 unicode_print (e, vs->value, -1);
2607 fprintf (e, "\"\n");
2610 fprintf (e, " END\n");
2611 fprintf (e, " END\n");
2612 break;
2615 case VERINFO_VAR:
2617 const struct ver_varinfo *vv;
2619 fprintf (e, " BLOCK \"VarFileInfo\"\n");
2620 fprintf (e, " BEGIN\n");
2621 fprintf (e, " VALUE \"");
2622 unicode_print (e, vi->u.var.key, -1);
2623 fprintf (e, "\"");
2625 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
2626 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
2627 vv->charset);
2629 fprintf (e, "\n END\n");
2631 break;
2636 fprintf (e, "END\n");
2639 /* Write out data which would normally be read from a file. */
2641 static void
2642 write_rc_filedata (e, length, data)
2643 FILE *e;
2644 unsigned long length;
2645 const unsigned char *data;
2647 unsigned long i;
2649 for (i = 0; i + 15 < length; i += 16)
2651 fprintf (e, "// %4lx: ", i);
2652 fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x ",
2653 data[i + 0], data[i + 1], data[i + 2], data[i + 3],
2654 data[i + 4], data[i + 5], data[i + 6], data[i + 7]);
2655 fprintf (e, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
2656 data[i + 8], data[i + 9], data[i + 10], data[i + 11],
2657 data[i + 12], data[i + 13], data[i + 14], data[i + 15]);
2660 if (i < length)
2662 fprintf (e, "// %4lx:", i);
2663 while (i < length)
2665 fprintf (e, " %02x", data[i]);
2666 ++i;
2668 fprintf (e, "\n");