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