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