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