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