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