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