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