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