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