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