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