2007-10-01 Paolo Bonzini <bonzini@gnu.org>
[binutils.git] / binutils / resrc.c
bloba621319c5920ead17e931cf842fd86c0ca181d8f
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 Rewritten by Kai Tietz, Onevision.
7 This file is part of GNU Binutils.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
24 /* This file contains functions that read and write Windows rc files.
25 These are text files that represent resources. */
27 #include "sysdep.h"
28 #include "bfd.h"
29 #include "bucomm.h"
30 #include "libiberty.h"
31 #include "safe-ctype.h"
32 #include "windres.h"
34 #include <assert.h>
35 #include <errno.h>
36 #include <sys/stat.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
41 #ifdef HAVE_SYS_WAIT_H
42 #include <sys/wait.h>
43 #else /* ! HAVE_SYS_WAIT_H */
44 #if ! defined (_WIN32) || defined (__CYGWIN__)
45 #ifndef WIFEXITED
46 #define WIFEXITED(w) (((w)&0377) == 0)
47 #endif
48 #ifndef WIFSIGNALED
49 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
50 #endif
51 #ifndef WTERMSIG
52 #define WTERMSIG(w) ((w) & 0177)
53 #endif
54 #ifndef WEXITSTATUS
55 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
56 #endif
57 #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
58 #ifndef WIFEXITED
59 #define WIFEXITED(w) (((w) & 0xff) == 0)
60 #endif
61 #ifndef WIFSIGNALED
62 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
63 #endif
64 #ifndef WTERMSIG
65 #define WTERMSIG(w) ((w) & 0x7f)
66 #endif
67 #ifndef WEXITSTATUS
68 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
69 #endif
70 #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
71 #endif /* ! HAVE_SYS_WAIT_H */
73 #ifndef STDOUT_FILENO
74 #define STDOUT_FILENO 1
75 #endif
77 #if defined (_WIN32) && ! defined (__CYGWIN__)
78 #define popen _popen
79 #define pclose _pclose
80 #endif
82 /* The default preprocessor. */
84 #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
86 /* We read the directory entries in a cursor or icon file into
87 instances of this structure. */
89 struct icondir
91 /* Width of image. */
92 bfd_byte width;
93 /* Height of image. */
94 bfd_byte height;
95 /* Number of colors in image. */
96 bfd_byte colorcount;
97 union
99 struct
101 /* Color planes. */
102 unsigned short planes;
103 /* Bits per pixel. */
104 unsigned short bits;
105 } icon;
106 struct
108 /* X coordinate of hotspot. */
109 unsigned short xhotspot;
110 /* Y coordinate of hotspot. */
111 unsigned short yhotspot;
112 } cursor;
113 } u;
114 /* Bytes in image. */
115 unsigned long bytes;
116 /* File offset of image. */
117 unsigned long offset;
120 /* The name of the rc file we are reading. */
122 char *rc_filename;
124 /* The line number in the rc file. */
126 int rc_lineno;
128 /* The pipe we are reading from, so that we can close it if we exit. */
130 FILE *cpp_pipe;
132 /* The temporary file used if we're not using popen, so we can delete it
133 if we exit. */
135 static char *cpp_temp_file;
137 /* Input stream is either a file or a pipe. */
139 static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
141 /* As we read the rc file, we attach information to this structure. */
143 static rc_res_directory *resources;
145 /* The number of cursor resources we have written out. */
147 static int cursors;
149 /* The number of font resources we have written out. */
151 static int fonts;
153 /* Font directory information. */
155 rc_fontdir *fontdirs;
157 /* Resource info to use for fontdirs. */
159 rc_res_res_info fontdirs_resinfo;
161 /* The number of icon resources we have written out. */
163 static int icons;
165 /* The windres target bfd . */
167 static windres_bfd wrtarget =
169 (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
172 /* Local functions for rcdata based resource definitions. */
174 static void define_font_rcdata (rc_res_id, const rc_res_res_info *,
175 rc_rcdata_item *);
176 static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
177 rc_rcdata_item *);
178 static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
179 rc_rcdata_item *);
180 static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
181 rc_rcdata_item *);
182 static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
183 rc_rcdata_item *);
184 static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
185 rc_rcdata_item *);
186 static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
187 static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
189 static int run_cmd (char *, const char *);
190 static FILE *open_input_stream (char *);
191 static FILE *look_for_default
192 (char *, const char *, int, const char *, const char *);
193 static void close_input_stream (void);
194 static void unexpected_eof (const char *);
195 static int get_word (FILE *, const char *);
196 static unsigned long get_long (FILE *, const char *);
197 static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
198 static void define_fontdirs (void);
200 /* Run `cmd' and redirect the output to `redir'. */
202 static int
203 run_cmd (char *cmd, const char *redir)
205 char *s;
206 int pid, wait_status, retcode;
207 int i;
208 const char **argv;
209 char *errmsg_fmt, *errmsg_arg;
210 char *temp_base = choose_temp_base ();
211 int in_quote;
212 char sep;
213 int redir_handle = -1;
214 int stdout_save = -1;
216 /* Count the args. */
217 i = 0;
219 for (s = cmd; *s; s++)
220 if (*s == ' ')
221 i++;
223 i++;
224 argv = alloca (sizeof (char *) * (i + 3));
225 i = 0;
226 s = cmd;
228 while (1)
230 while (*s == ' ' && *s != 0)
231 s++;
233 if (*s == 0)
234 break;
236 in_quote = (*s == '\'' || *s == '"');
237 sep = (in_quote) ? *s++ : ' ';
238 argv[i++] = s;
240 while (*s != sep && *s != 0)
241 s++;
243 if (*s == 0)
244 break;
246 *s++ = 0;
248 if (in_quote)
249 s++;
251 argv[i++] = NULL;
253 /* Setup the redirection. We can't use the usual fork/exec and redirect
254 since we may be running on non-POSIX Windows host. */
256 fflush (stdout);
257 fflush (stderr);
259 /* Open temporary output file. */
260 redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
261 if (redir_handle == -1)
262 fatal (_("can't open temporary file `%s': %s"), redir,
263 strerror (errno));
265 /* Duplicate the stdout file handle so it can be restored later. */
266 stdout_save = dup (STDOUT_FILENO);
267 if (stdout_save == -1)
268 fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
270 /* Redirect stdout to our output file. */
271 dup2 (redir_handle, STDOUT_FILENO);
273 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
274 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
276 /* Restore stdout to its previous setting. */
277 dup2 (stdout_save, STDOUT_FILENO);
279 /* Close response file. */
280 close (redir_handle);
282 if (pid == -1)
284 fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
285 return 1;
288 retcode = 0;
289 pid = pwait (pid, &wait_status, 0);
291 if (pid == -1)
293 fatal (_("wait: %s"), strerror (errno));
294 retcode = 1;
296 else if (WIFSIGNALED (wait_status))
298 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
299 retcode = 1;
301 else if (WIFEXITED (wait_status))
303 if (WEXITSTATUS (wait_status) != 0)
305 fatal (_("%s exited with status %d"), cmd,
306 WEXITSTATUS (wait_status));
307 retcode = 1;
310 else
311 retcode = 1;
313 return retcode;
316 static FILE *
317 open_input_stream (char *cmd)
319 if (istream_type == ISTREAM_FILE)
321 char *fileprefix;
323 fileprefix = choose_temp_base ();
324 cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
325 sprintf (cpp_temp_file, "%s.irc", fileprefix);
326 free (fileprefix);
328 if (run_cmd (cmd, cpp_temp_file))
329 fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
331 cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
332 if (cpp_pipe == NULL)
333 fatal (_("can't open temporary file `%s': %s"),
334 cpp_temp_file, strerror (errno));
336 if (verbose)
337 fprintf (stderr,
338 _("Using temporary file `%s' to read preprocessor output\n"),
339 cpp_temp_file);
341 else
343 cpp_pipe = popen (cmd, FOPEN_RT);
344 if (cpp_pipe == NULL)
345 fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
346 if (verbose)
347 fprintf (stderr, _("Using popen to read preprocessor output\n"));
350 xatexit (close_input_stream);
351 return cpp_pipe;
354 /* Determine if FILENAME contains special characters that
355 can cause problems unless the entire filename is quoted. */
357 static int
358 filename_need_quotes (const char *filename)
360 if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
361 return 0;
363 while (*filename != 0)
365 switch (*filename)
367 case '&':
368 case ' ':
369 case '<':
370 case '>':
371 case '|':
372 case '%':
373 return 1;
375 ++filename;
377 return 0;
380 /* Look for the preprocessor program. */
382 static FILE *
383 look_for_default (char *cmd, const char *prefix, int end_prefix,
384 const char *preprocargs, const char *filename)
386 char *space;
387 int found;
388 struct stat s;
389 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
391 strcpy (cmd, prefix);
393 sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
394 space = strchr (cmd + end_prefix, ' ');
395 if (space)
396 *space = 0;
398 if (
399 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
400 strchr (cmd, '\\') ||
401 #endif
402 strchr (cmd, '/'))
404 found = (stat (cmd, &s) == 0
405 #ifdef HAVE_EXECUTABLE_SUFFIX
406 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
407 #endif
410 if (! found)
412 if (verbose)
413 fprintf (stderr, _("Tried `%s'\n"), cmd);
414 return NULL;
418 strcpy (cmd, prefix);
420 sprintf (cmd + end_prefix, "%s %s %s%s%s",
421 DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
423 if (verbose)
424 fprintf (stderr, _("Using `%s'\n"), cmd);
426 cpp_pipe = open_input_stream (cmd);
427 return cpp_pipe;
430 /* Read an rc file. */
432 rc_res_directory *
433 read_rc_file (const char *filename, const char *preprocessor,
434 const char *preprocargs, int language, int use_temp_file)
436 char *cmd;
437 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
439 if (filename == NULL)
440 filename = "-";
441 /* Setup the default resource import path taken from input file. */
442 else if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL)
444 char *e, *c;
446 if (filename[0] == '/'
447 || filename[0] == '\\'
448 || filename[1] == ':')
449 e = c = xstrdup (filename);
450 else
452 e = c = xmalloc (strlen (filename) + 3);
453 sprintf (c, "./%s", filename);
455 e += strlen (c);
456 while (e > c && (e[-1] != '\\' && e[-1] != '/'))
458 --e;
459 e[0] = 0;
461 /* Cut off trailing slash. */
462 --e;
463 e[0] = 0;
464 while ((e = strchr (c, '\\')) != NULL)
465 *e = '/';
467 windres_add_include_dir (e);
470 istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
472 if (preprocargs == NULL)
473 preprocargs = "";
475 if (preprocessor)
477 cmd = xmalloc (strlen (preprocessor)
478 + strlen (preprocargs)
479 + strlen (filename)
480 + strlen (fnquotes) * 2
481 + 10);
482 sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
483 fnquotes, filename, fnquotes);
485 cpp_pipe = open_input_stream (cmd);
487 else
489 char *dash, *slash, *cp;
491 preprocessor = DEFAULT_PREPROCESSOR;
493 cmd = xmalloc (strlen (program_name)
494 + strlen (preprocessor)
495 + strlen (preprocargs)
496 + strlen (filename)
497 + strlen (fnquotes) * 2
498 #ifdef HAVE_EXECUTABLE_SUFFIX
499 + strlen (EXECUTABLE_SUFFIX)
500 #endif
501 + 10);
504 dash = slash = 0;
505 for (cp = program_name; *cp; cp++)
507 if (*cp == '-')
508 dash = cp;
509 if (
510 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
511 *cp == ':' || *cp == '\\' ||
512 #endif
513 *cp == '/')
515 slash = cp;
516 dash = 0;
520 cpp_pipe = 0;
522 if (dash)
524 /* First, try looking for a prefixed gcc in the windres
525 directory, with the same prefix as windres */
527 cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
528 preprocargs, filename);
531 if (slash && ! cpp_pipe)
533 /* Next, try looking for a gcc in the same directory as
534 that windres */
536 cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
537 preprocargs, filename);
540 if (! cpp_pipe)
542 /* Sigh, try the default */
544 cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
549 free (cmd);
551 rc_filename = xstrdup (filename);
552 rc_lineno = 1;
553 if (language != -1)
554 rcparse_set_language (language);
555 yyparse ();
556 rcparse_discard_strings ();
558 close_input_stream ();
560 if (fontdirs != NULL)
561 define_fontdirs ();
563 free (rc_filename);
564 rc_filename = NULL;
566 return resources;
569 /* Close the input stream if it is open. */
571 static void
572 close_input_stream (void)
574 if (istream_type == ISTREAM_FILE)
576 if (cpp_pipe != NULL)
577 fclose (cpp_pipe);
579 if (cpp_temp_file != NULL)
581 int errno_save = errno;
583 unlink (cpp_temp_file);
584 errno = errno_save;
585 free (cpp_temp_file);
588 else
590 if (cpp_pipe != NULL)
591 pclose (cpp_pipe);
594 /* Since this is also run via xatexit, safeguard. */
595 cpp_pipe = NULL;
596 cpp_temp_file = NULL;
599 /* Report an error while reading an rc file. */
601 void
602 yyerror (const char *msg)
604 fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
607 /* Issue a warning while reading an rc file. */
609 void
610 rcparse_warning (const char *msg)
612 fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
615 /* Die if we get an unexpected end of file. */
617 static void
618 unexpected_eof (const char *msg)
620 fatal (_("%s: unexpected EOF"), msg);
623 /* Read a 16 bit word from a file. The data is assumed to be little
624 endian. */
626 static int
627 get_word (FILE *e, const char *msg)
629 int b1, b2;
631 b1 = getc (e);
632 b2 = getc (e);
633 if (feof (e))
634 unexpected_eof (msg);
635 return ((b2 & 0xff) << 8) | (b1 & 0xff);
638 /* Read a 32 bit word from a file. The data is assumed to be little
639 endian. */
641 static unsigned long
642 get_long (FILE *e, const char *msg)
644 int b1, b2, b3, b4;
646 b1 = getc (e);
647 b2 = getc (e);
648 b3 = getc (e);
649 b4 = getc (e);
650 if (feof (e))
651 unexpected_eof (msg);
652 return (((((((b4 & 0xff) << 8)
653 | (b3 & 0xff)) << 8)
654 | (b2 & 0xff)) << 8)
655 | (b1 & 0xff));
658 /* Read data from a file. This is a wrapper to do error checking. */
660 static void
661 get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
663 rc_uint_type got; // $$$d
665 got = (rc_uint_type) fread (p, 1, c, e);
666 if (got == c)
667 return;
669 fatal (_("%s: read of %lu returned %lu"), msg, (long) c, (long) got);
672 /* Define an accelerator resource. */
674 void
675 define_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
676 rc_accelerator *data)
678 rc_res_resource *r;
680 r = define_standard_resource (&resources, RT_ACCELERATOR, id,
681 resinfo->language, 0);
682 r->type = RES_TYPE_ACCELERATOR;
683 r->u.acc = data;
684 r->res_info = *resinfo;
687 /* Define a bitmap resource. Bitmap data is stored in a file. The
688 first 14 bytes of the file are a standard header, which is not
689 included in the resource data. */
691 #define BITMAP_SKIP (14)
693 void
694 define_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
695 const char *filename)
697 FILE *e;
698 char *real_filename;
699 struct stat s;
700 bfd_byte *data;
701 rc_uint_type i;
702 rc_res_resource *r;
704 e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
706 if (stat (real_filename, &s) < 0)
707 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
708 strerror (errno));
710 data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
712 for (i = 0; i < BITMAP_SKIP; i++)
713 getc (e);
715 get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
717 fclose (e);
718 free (real_filename);
720 r = define_standard_resource (&resources, RT_BITMAP, id,
721 resinfo->language, 0);
723 r->type = RES_TYPE_BITMAP;
724 r->u.data.length = s.st_size - BITMAP_SKIP;
725 r->u.data.data = data;
726 r->res_info = *resinfo;
729 /* Define a cursor resource. A cursor file may contain a set of
730 bitmaps, each representing the same cursor at various different
731 resolutions. They each get written out with a different ID. The
732 real cursor resource is then a group resource which can be used to
733 select one of the actual cursors. */
735 void
736 define_cursor (rc_res_id id, const rc_res_res_info *resinfo,
737 const char *filename)
739 FILE *e;
740 char *real_filename;
741 int type, count, i;
742 struct icondir *icondirs;
743 int first_cursor;
744 rc_res_resource *r;
745 rc_group_cursor *first, **pp;
747 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
749 /* A cursor file is basically an icon file. The start of the file
750 is a three word structure. The first word is ignored. The
751 second word is the type of data. The third word is the number of
752 entries. */
754 get_word (e, real_filename);
755 type = get_word (e, real_filename);
756 count = get_word (e, real_filename);
757 if (type != 2)
758 fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
760 /* Read in the icon directory entries. */
762 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
764 for (i = 0; i < count; i++)
766 icondirs[i].width = getc (e);
767 icondirs[i].height = getc (e);
768 icondirs[i].colorcount = getc (e);
769 getc (e);
770 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
771 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
772 icondirs[i].bytes = get_long (e, real_filename);
773 icondirs[i].offset = get_long (e, real_filename);
775 if (feof (e))
776 unexpected_eof (real_filename);
779 /* Define each cursor as a unique resource. */
781 first_cursor = cursors;
783 for (i = 0; i < count; i++)
785 bfd_byte *data;
786 rc_res_id name;
787 rc_cursor *c;
789 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
790 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
791 icondirs[i].offset, strerror (errno));
793 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
795 get_data (e, data, icondirs[i].bytes, real_filename);
797 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
798 c->xhotspot = icondirs[i].u.cursor.xhotspot;
799 c->yhotspot = icondirs[i].u.cursor.yhotspot;
800 c->length = icondirs[i].bytes;
801 c->data = data;
803 ++cursors;
805 name.named = 0;
806 name.u.id = cursors;
808 r = define_standard_resource (&resources, RT_CURSOR, name,
809 resinfo->language, 0);
810 r->type = RES_TYPE_CURSOR;
811 r->u.cursor = c;
812 r->res_info = *resinfo;
815 fclose (e);
816 free (real_filename);
818 /* Define a cursor group resource. */
820 first = NULL;
821 pp = &first;
822 for (i = 0; i < count; i++)
824 rc_group_cursor *cg;
826 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
827 cg->next = NULL;
828 cg->width = icondirs[i].width;
829 cg->height = 2 * icondirs[i].height;
831 /* FIXME: What should these be set to? */
832 cg->planes = 1;
833 cg->bits = 1;
835 cg->bytes = icondirs[i].bytes + 4;
836 cg->index = first_cursor + i + 1;
838 *pp = cg;
839 pp = &(*pp)->next;
842 free (icondirs);
844 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
845 resinfo->language, 0);
846 r->type = RES_TYPE_GROUP_CURSOR;
847 r->u.group_cursor = first;
848 r->res_info = *resinfo;
851 /* Define a dialog resource. */
853 void
854 define_dialog (rc_res_id id, const rc_res_res_info *resinfo,
855 const rc_dialog *dialog)
857 rc_dialog *copy;
858 rc_res_resource *r;
860 copy = (rc_dialog *) res_alloc (sizeof *copy);
861 *copy = *dialog;
863 r = define_standard_resource (&resources, RT_DIALOG, id,
864 resinfo->language, 0);
865 r->type = RES_TYPE_DIALOG;
866 r->u.dialog = copy;
867 r->res_info = *resinfo;
870 /* Define a dialog control. This does not define a resource, but
871 merely allocates and fills in a structure. */
873 rc_dialog_control *
874 define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
875 rc_uint_type y, rc_uint_type width, rc_uint_type height,
876 const rc_res_id class, rc_uint_type style,
877 rc_uint_type exstyle)
879 rc_dialog_control *n;
881 n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
882 n->next = NULL;
883 n->id = id;
884 n->style = style;
885 n->exstyle = exstyle;
886 n->x = x;
887 n->y = y;
888 n->width = width;
889 n->height = height;
890 n->class = class;
891 n->text = iid;
892 n->data = NULL;
893 n->help = 0;
895 return n;
898 rc_dialog_control *
899 define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
900 rc_uint_type y, rc_uint_type style,
901 rc_uint_type exstyle, rc_uint_type help,
902 rc_rcdata_item *data, rc_dialog_ex *ex)
904 rc_dialog_control *n;
905 rc_res_id tid;
906 rc_res_id cid;
908 if (style == 0)
909 style = SS_ICON | WS_CHILD | WS_VISIBLE;
910 res_string_to_id (&tid, "");
911 cid.named = 0;
912 cid.u.id = CTL_STATIC;
913 n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
914 n->text = iid;
915 if (help && ! ex)
916 rcparse_warning (_("help ID requires DIALOGEX"));
917 if (data && ! ex)
918 rcparse_warning (_("control data requires DIALOGEX"));
919 n->help = help;
920 n->data = data;
922 return n;
925 /* Define a font resource. */
927 void
928 define_font (rc_res_id id, const rc_res_res_info *resinfo,
929 const char *filename)
931 FILE *e;
932 char *real_filename;
933 struct stat s;
934 bfd_byte *data;
935 rc_res_resource *r;
936 long offset;
937 long fontdatalength;
938 bfd_byte *fontdata;
939 rc_fontdir *fd;
940 const char *device, *face;
941 rc_fontdir **pp;
943 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
945 if (stat (real_filename, &s) < 0)
946 fatal (_("stat failed on font file `%s': %s"), real_filename,
947 strerror (errno));
949 data = (bfd_byte *) res_alloc (s.st_size);
951 get_data (e, data, s.st_size, real_filename);
953 fclose (e);
954 free (real_filename);
956 r = define_standard_resource (&resources, RT_FONT, id,
957 resinfo->language, 0);
959 r->type = RES_TYPE_FONT;
960 r->u.data.length = s.st_size;
961 r->u.data.data = data;
962 r->res_info = *resinfo;
964 /* For each font resource, we must add an entry in the FONTDIR
965 resource. The FONTDIR resource includes some strings in the font
966 file. To find them, we have to do some magic on the data we have
967 read. */
969 offset = ((((((data[47] << 8)
970 | data[46]) << 8)
971 | data[45]) << 8)
972 | data[44]);
973 if (offset > 0 && offset < s.st_size)
974 device = (char *) data + offset;
975 else
976 device = "";
978 offset = ((((((data[51] << 8)
979 | data[50]) << 8)
980 | data[49]) << 8)
981 | data[48]);
982 if (offset > 0 && offset < s.st_size)
983 face = (char *) data + offset;
984 else
985 face = "";
987 ++fonts;
989 fontdatalength = 58 + strlen (device) + strlen (face);
990 fontdata = (bfd_byte *) res_alloc (fontdatalength);
991 memcpy (fontdata, data, 56);
992 strcpy ((char *) fontdata + 56, device);
993 strcpy ((char *) fontdata + 57 + strlen (device), face);
995 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
996 fd->next = NULL;
997 fd->index = fonts;
998 fd->length = fontdatalength;
999 fd->data = fontdata;
1001 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
1003 *pp = fd;
1005 /* For the single fontdirs resource, we always use the resource
1006 information of the last font. I don't know what else to do. */
1007 fontdirs_resinfo = *resinfo;
1010 static void
1011 define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1012 rc_rcdata_item *data)
1014 rc_res_resource *r;
1015 rc_uint_type len_data;
1016 bfd_byte *pb_data;
1018 r = define_standard_resource (&resources, RT_FONT, id,
1019 resinfo->language, 0);
1021 pb_data = rcdata_render_as_buffer (data, &len_data);
1023 r->type = RES_TYPE_FONT;
1024 r->u.data.length = len_data;
1025 r->u.data.data = pb_data;
1026 r->res_info = *resinfo;
1029 /* Define the fontdirs resource. This is called after the entire rc
1030 file has been parsed, if any font resources were seen. */
1032 static void
1033 define_fontdirs (void)
1035 rc_res_resource *r;
1036 rc_res_id id;
1038 id.named = 0;
1039 id.u.id = 1;
1041 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1043 r->type = RES_TYPE_FONTDIR;
1044 r->u.fontdir = fontdirs;
1045 r->res_info = fontdirs_resinfo;
1048 static bfd_byte *
1049 rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
1051 const rc_rcdata_item *d;
1052 bfd_byte *ret = NULL, *pret;
1053 rc_uint_type len = 0;
1055 for (d = data; d != NULL; d = d->next)
1056 len += rcdata_copy (d, NULL);
1057 if (len != 0)
1059 ret = pret = (bfd_byte *) res_alloc (len);
1060 for (d = data; d != NULL; d = d->next)
1061 pret += rcdata_copy (d, pret);
1063 if (plen)
1064 *plen = len;
1065 return ret;
1068 static void
1069 define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1070 rc_rcdata_item *data)
1072 rc_res_resource *r;
1073 rc_fontdir *fd, *fd_first, *fd_cur;
1074 rc_uint_type len_data;
1075 bfd_byte *pb_data;
1076 rc_uint_type c;
1078 fd_cur = fd_first = NULL;
1079 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1081 pb_data = rcdata_render_as_buffer (data, &len_data);
1083 if (pb_data)
1085 rc_uint_type off = 2;
1086 c = windres_get_16 (&wrtarget, pb_data, len_data);
1087 for (; c > 0; c--)
1089 size_t len;
1090 rc_uint_type safe_pos = off;
1091 const struct bin_fontdir_item *bfi;
1093 bfi = (const struct bin_fontdir_item *) pb_data + off;
1094 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1095 fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
1096 fd->data = pb_data + off;
1097 off += 56;
1098 len = strlen ((char *) bfi->device_name) + 1;
1099 off += (rc_uint_type) len;
1100 off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
1101 fd->length = (off - safe_pos);
1102 fd->next = NULL;
1103 if (fd_first == NULL)
1104 fd_first = fd;
1105 else
1106 fd_cur->next = fd;
1107 fd_cur = fd;
1110 r->type = RES_TYPE_FONTDIR;
1111 r->u.fontdir = fd_first;
1112 r->res_info = *resinfo;
1115 static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1116 rc_rcdata_item *data)
1118 rc_res_resource *r;
1119 rc_uint_type len_data;
1120 bfd_byte *pb_data;
1122 r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
1124 pb_data = rcdata_render_as_buffer (data, &len_data);
1125 r->type = RES_TYPE_MESSAGETABLE;
1126 r->u.data.length = len_data;
1127 r->u.data.data = pb_data;
1128 r->res_info = *resinfo;
1131 /* Define an icon resource. An icon file may contain a set of
1132 bitmaps, each representing the same icon at various different
1133 resolutions. They each get written out with a different ID. The
1134 real icon resource is then a group resource which can be used to
1135 select one of the actual icon bitmaps. */
1137 void
1138 define_icon (rc_res_id id, const rc_res_res_info *resinfo,
1139 const char *filename)
1141 FILE *e;
1142 char *real_filename;
1143 int type, count, i;
1144 struct icondir *icondirs;
1145 int first_icon;
1146 rc_res_resource *r;
1147 rc_group_icon *first, **pp;
1149 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1151 /* The start of an icon file is a three word structure. The first
1152 word is ignored. The second word is the type of data. The third
1153 word is the number of entries. */
1155 get_word (e, real_filename);
1156 type = get_word (e, real_filename);
1157 count = get_word (e, real_filename);
1158 if (type != 1)
1159 fatal (_("icon file `%s' does not contain icon data"), real_filename);
1161 /* Read in the icon directory entries. */
1163 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1165 for (i = 0; i < count; i++)
1167 icondirs[i].width = getc (e);
1168 icondirs[i].height = getc (e);
1169 icondirs[i].colorcount = getc (e);
1170 getc (e);
1171 icondirs[i].u.icon.planes = get_word (e, real_filename);
1172 icondirs[i].u.icon.bits = get_word (e, real_filename);
1173 icondirs[i].bytes = get_long (e, real_filename);
1174 icondirs[i].offset = get_long (e, real_filename);
1176 if (feof (e))
1177 unexpected_eof (real_filename);
1180 /* Define each icon as a unique resource. */
1182 first_icon = icons;
1184 for (i = 0; i < count; i++)
1186 bfd_byte *data;
1187 rc_res_id name;
1189 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1190 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1191 icondirs[i].offset, strerror (errno));
1193 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
1195 get_data (e, data, icondirs[i].bytes, real_filename);
1197 ++icons;
1199 name.named = 0;
1200 name.u.id = icons;
1202 r = define_standard_resource (&resources, RT_ICON, name,
1203 resinfo->language, 0);
1204 r->type = RES_TYPE_ICON;
1205 r->u.data.length = icondirs[i].bytes;
1206 r->u.data.data = data;
1207 r->res_info = *resinfo;
1210 fclose (e);
1211 free (real_filename);
1213 /* Define an icon group resource. */
1215 first = NULL;
1216 pp = &first;
1217 for (i = 0; i < count; i++)
1219 rc_group_icon *cg;
1221 /* For some reason, at least in some files the planes and bits
1222 are zero. We instead set them from the color. This is
1223 copied from rcl. */
1225 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1226 cg->next = NULL;
1227 cg->width = icondirs[i].width;
1228 cg->height = icondirs[i].height;
1229 cg->colors = icondirs[i].colorcount;
1231 if (icondirs[i].u.icon.planes)
1232 cg->planes = icondirs[i].u.icon.planes;
1233 else
1234 cg->planes = 1;
1236 if (icondirs[i].u.icon.bits)
1237 cg->bits = icondirs[i].u.icon.bits;
1238 else
1240 cg->bits = 0;
1242 while ((1L << cg->bits) < cg->colors)
1243 ++cg->bits;
1246 cg->bytes = icondirs[i].bytes;
1247 cg->index = first_icon + i + 1;
1249 *pp = cg;
1250 pp = &(*pp)->next;
1253 free (icondirs);
1255 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1256 resinfo->language, 0);
1257 r->type = RES_TYPE_GROUP_ICON;
1258 r->u.group_icon = first;
1259 r->res_info = *resinfo;
1262 static void
1263 define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1264 rc_rcdata_item *data)
1266 rc_res_resource *r;
1267 rc_group_icon *cg, *first, *cur;
1268 rc_uint_type len_data;
1269 bfd_byte *pb_data;
1271 pb_data = rcdata_render_as_buffer (data, &len_data);
1273 cur = NULL;
1274 first = NULL;
1276 while (len_data >= 6)
1278 int c, i;
1279 unsigned short type;
1280 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1281 if (type != 1)
1282 fatal (_("unexpected group icon type %d"), type);
1283 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1284 len_data -= 6;
1285 pb_data += 6;
1287 for (i = 0; i < c; i++)
1289 if (len_data < 14)
1290 fatal ("too small group icon rcdata");
1291 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1292 cg->next = NULL;
1293 cg->width = pb_data[0];
1294 cg->height = pb_data[1];
1295 cg->colors = pb_data[2];
1296 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1297 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1298 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1299 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1300 if (! first)
1301 first = cg;
1302 else
1303 cur->next = cg;
1304 cur = cg;
1305 pb_data += 14;
1306 len_data -= 14;
1309 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1310 resinfo->language, 0);
1311 r->type = RES_TYPE_GROUP_ICON;
1312 r->u.group_icon = first;
1313 r->res_info = *resinfo;
1316 static void
1317 define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1318 rc_rcdata_item *data)
1320 rc_res_resource *r;
1321 rc_group_cursor *cg, *first, *cur;
1322 rc_uint_type len_data;
1323 bfd_byte *pb_data;
1325 pb_data = rcdata_render_as_buffer (data, &len_data);
1327 first = cur = NULL;
1329 while (len_data >= 6)
1331 int c, i;
1332 unsigned short type;
1333 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1334 if (type != 2)
1335 fatal (_("unexpected group cursor type %d"), type);
1336 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1337 len_data -= 6;
1338 pb_data += 6;
1340 for (i = 0; i < c; i++)
1342 if (len_data < 14)
1343 fatal ("too small group icon rcdata");
1344 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
1345 cg->next = NULL;
1346 cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
1347 cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1348 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1349 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1350 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1351 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1352 if (! first)
1353 first = cg;
1354 else
1355 cur->next = cg;
1356 cur = cg;
1357 pb_data += 14;
1358 len_data -= 14;
1362 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1363 resinfo->language, 0);
1364 r->type = RES_TYPE_GROUP_CURSOR;
1365 r->u.group_cursor = first;
1366 r->res_info = *resinfo;
1369 static void
1370 define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1371 rc_rcdata_item *data)
1373 rc_cursor *c;
1374 rc_res_resource *r;
1375 rc_uint_type len_data;
1376 bfd_byte *pb_data;
1378 pb_data = rcdata_render_as_buffer (data, &len_data);
1380 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
1381 c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
1382 c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1383 c->length = len_data - BIN_CURSOR_SIZE;
1384 c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
1386 r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
1387 r->type = RES_TYPE_CURSOR;
1388 r->u.cursor = c;
1389 r->res_info = *resinfo;
1392 static void
1393 define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1394 rc_rcdata_item *data)
1396 rc_res_resource *r;
1397 rc_uint_type len_data;
1398 bfd_byte *pb_data;
1400 pb_data = rcdata_render_as_buffer (data, &len_data);
1402 r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
1403 r->type = RES_TYPE_BITMAP;
1404 r->u.data.length = len_data;
1405 r->u.data.data = pb_data;
1406 r->res_info = *resinfo;
1409 static void
1410 define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1411 rc_rcdata_item *data)
1413 rc_res_resource *r;
1414 rc_uint_type len_data;
1415 bfd_byte *pb_data;
1417 pb_data = rcdata_render_as_buffer (data, &len_data);
1419 r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
1420 r->type = RES_TYPE_ICON;
1421 r->u.data.length = len_data;
1422 r->u.data.data = pb_data;
1423 r->res_info = *resinfo;
1426 /* Define a menu resource. */
1428 void
1429 define_menu (rc_res_id id, const rc_res_res_info *resinfo,
1430 rc_menuitem *menuitems)
1432 rc_menu *m;
1433 rc_res_resource *r;
1435 m = (rc_menu *) res_alloc (sizeof (rc_menu));
1436 m->items = menuitems;
1437 m->help = 0;
1439 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1440 r->type = RES_TYPE_MENU;
1441 r->u.menu = m;
1442 r->res_info = *resinfo;
1445 /* Define a menu item. This does not define a resource, but merely
1446 allocates and fills in a structure. */
1448 rc_menuitem *
1449 define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
1450 rc_uint_type state, rc_uint_type help,
1451 rc_menuitem *menuitems)
1453 rc_menuitem *mi;
1455 mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
1456 mi->next = NULL;
1457 mi->type = type;
1458 mi->state = state;
1459 mi->id = menuid;
1460 mi->text = unichar_dup (text);
1461 mi->help = help;
1462 mi->popup = menuitems;
1463 return mi;
1466 /* Define a messagetable resource. */
1468 void
1469 define_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
1470 const char *filename)
1472 FILE *e;
1473 char *real_filename;
1474 struct stat s;
1475 bfd_byte *data;
1476 rc_res_resource *r;
1478 e = open_file_search (filename, FOPEN_RB, "messagetable file",
1479 &real_filename);
1481 if (stat (real_filename, &s) < 0)
1482 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1483 strerror (errno));
1485 data = (bfd_byte *) res_alloc (s.st_size);
1487 get_data (e, data, s.st_size, real_filename);
1489 fclose (e);
1490 free (real_filename);
1492 r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1493 resinfo->language, 0);
1495 r->type = RES_TYPE_MESSAGETABLE;
1496 r->u.data.length = s.st_size;
1497 r->u.data.data = data;
1498 r->res_info = *resinfo;
1501 /* Define an rcdata resource. */
1503 void
1504 define_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1505 rc_rcdata_item *data)
1507 rc_res_resource *r;
1509 r = define_standard_resource (&resources, RT_RCDATA, id,
1510 resinfo->language, 0);
1511 r->type = RES_TYPE_RCDATA;
1512 r->u.rcdata = data;
1513 r->res_info = *resinfo;
1516 /* Create an rcdata item holding a string. */
1518 rc_rcdata_item *
1519 define_rcdata_string (const char *string, rc_uint_type len)
1521 rc_rcdata_item *ri;
1522 char *s;
1524 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1525 ri->next = NULL;
1526 ri->type = RCDATA_STRING;
1527 ri->u.string.length = len;
1528 s = (char *) res_alloc (len);
1529 memcpy (s, string, len);
1530 ri->u.string.s = s;
1532 return ri;
1535 /* Create an rcdata item holding a unicode string. */
1537 rc_rcdata_item *
1538 define_rcdata_unistring (const unichar *string, rc_uint_type len)
1540 rc_rcdata_item *ri;
1541 unichar *s;
1543 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1544 ri->next = NULL;
1545 ri->type = RCDATA_WSTRING;
1546 ri->u.wstring.length = len;
1547 s = (unichar *) res_alloc (len * sizeof (unichar));
1548 memcpy (s, string, len * sizeof (unichar));
1549 ri->u.wstring.w = s;
1551 return ri;
1554 /* Create an rcdata item holding a number. */
1556 rc_rcdata_item *
1557 define_rcdata_number (rc_uint_type val, int dword)
1559 rc_rcdata_item *ri;
1561 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1562 ri->next = NULL;
1563 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1564 ri->u.word = val;
1566 return ri;
1569 /* Define a stringtable resource. This is called for each string
1570 which appears in a STRINGTABLE statement. */
1572 void
1573 define_stringtable (const rc_res_res_info *resinfo,
1574 rc_uint_type stringid, const unichar *string)
1576 rc_res_id id;
1577 rc_res_resource *r;
1579 id.named = 0;
1580 id.u.id = (stringid >> 4) + 1;
1581 r = define_standard_resource (&resources, RT_STRING, id,
1582 resinfo->language, 1);
1584 if (r->type == RES_TYPE_UNINITIALIZED)
1586 int i;
1588 r->type = RES_TYPE_STRINGTABLE;
1589 r->u.stringtable = ((rc_stringtable *)
1590 res_alloc (sizeof (rc_stringtable)));
1591 for (i = 0; i < 16; i++)
1593 r->u.stringtable->strings[i].length = 0;
1594 r->u.stringtable->strings[i].string = NULL;
1597 r->res_info = *resinfo;
1600 r->u.stringtable->strings[stringid & 0xf].length = unichar_len (string);
1601 r->u.stringtable->strings[stringid & 0xf].string = unichar_dup (string);
1604 void
1605 define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
1606 rc_toolbar_item *items)
1608 rc_toolbar *t;
1609 rc_res_resource *r;
1611 t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1612 t->button_width = width;
1613 t->button_height = height;
1614 t->nitems = 0;
1615 t->items = items;
1616 while (items != NULL)
1618 t->nitems+=1;
1619 items = items->next;
1621 r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
1622 r->type = RES_TYPE_TOOLBAR;
1623 r->u.toolbar = t;
1624 r->res_info = *resinfo;
1627 /* Define a user data resource where the data is in the rc file. */
1629 void
1630 define_user_data (rc_res_id id, rc_res_id type,
1631 const rc_res_res_info *resinfo,
1632 rc_rcdata_item *data)
1634 rc_res_id ids[3];
1635 rc_res_resource *r;
1636 bfd_byte *pb_data;
1637 rc_uint_type len_data;
1639 /* We have to check if the binary data is parsed specially. */
1640 if (type.named == 0)
1642 switch (type.u.id)
1644 case RT_FONTDIR:
1645 define_fontdir_rcdata (id, resinfo, data);
1646 return;
1647 case RT_FONT:
1648 define_font_rcdata (id, resinfo, data);
1649 return;
1650 case RT_ICON:
1651 define_icon_rcdata (id, resinfo, data);
1652 return;
1653 case RT_BITMAP:
1654 define_bitmap_rcdata (id, resinfo, data);
1655 return;
1656 case RT_CURSOR:
1657 define_cursor_rcdata (id, resinfo, data);
1658 return;
1659 case RT_GROUP_ICON:
1660 define_group_icon_rcdata (id, resinfo, data);
1661 return;
1662 case RT_GROUP_CURSOR:
1663 define_group_cursor_rcdata (id, resinfo, data);
1664 return;
1665 case RT_MESSAGETABLE:
1666 define_messagetable_rcdata (id, resinfo, data);
1667 return;
1668 default:
1669 /* Treat as normal user-data. */
1670 break;
1673 ids[0] = type;
1674 ids[1] = id;
1675 ids[2].named = 0;
1676 ids[2].u.id = resinfo->language;
1678 r = define_resource (& resources, 3, ids, 0);
1679 r->type = RES_TYPE_USERDATA;
1680 r->u.userdata = ((rc_rcdata_item *)
1681 res_alloc (sizeof (rc_rcdata_item)));
1682 r->u.userdata->next = NULL;
1683 r->u.userdata->type = RCDATA_BUFFER;
1684 pb_data = rcdata_render_as_buffer (data, &len_data);
1685 r->u.userdata->u.buffer.length = len_data;
1686 r->u.userdata->u.buffer.data = pb_data;
1687 r->res_info = *resinfo;
1690 void
1691 define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
1692 const char *filename)
1694 rc_rcdata_item *ri;
1695 FILE *e;
1696 char *real_filename;
1697 struct stat s;
1698 bfd_byte *data;
1700 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1703 if (stat (real_filename, &s) < 0)
1704 fatal (_("stat failed on file `%s': %s"), real_filename,
1705 strerror (errno));
1707 data = (bfd_byte *) res_alloc (s.st_size);
1709 get_data (e, data, s.st_size, real_filename);
1711 fclose (e);
1712 free (real_filename);
1714 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1715 ri->next = NULL;
1716 ri->type = RCDATA_BUFFER;
1717 ri->u.buffer.length = s.st_size;
1718 ri->u.buffer.data = data;
1720 define_rcdata (id, resinfo, ri);
1723 /* Define a user data resource where the data is in a file. */
1725 void
1726 define_user_file (rc_res_id id, rc_res_id type,
1727 const rc_res_res_info *resinfo, const char *filename)
1729 FILE *e;
1730 char *real_filename;
1731 struct stat s;
1732 bfd_byte *data;
1733 rc_res_id ids[3];
1734 rc_res_resource *r;
1736 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1738 if (stat (real_filename, &s) < 0)
1739 fatal (_("stat failed on file `%s': %s"), real_filename,
1740 strerror (errno));
1742 data = (bfd_byte *) res_alloc (s.st_size);
1744 get_data (e, data, s.st_size, real_filename);
1746 fclose (e);
1747 free (real_filename);
1749 ids[0] = type;
1750 ids[1] = id;
1751 ids[2].named = 0;
1752 ids[2].u.id = resinfo->language;
1754 r = define_resource (&resources, 3, ids, 0);
1755 r->type = RES_TYPE_USERDATA;
1756 r->u.userdata = ((rc_rcdata_item *)
1757 res_alloc (sizeof (rc_rcdata_item)));
1758 r->u.userdata->next = NULL;
1759 r->u.userdata->type = RCDATA_BUFFER;
1760 r->u.userdata->u.buffer.length = s.st_size;
1761 r->u.userdata->u.buffer.data = data;
1762 r->res_info = *resinfo;
1765 /* Define a versioninfo resource. */
1767 void
1768 define_versioninfo (rc_res_id id, rc_uint_type language,
1769 rc_fixed_versioninfo *fixedverinfo,
1770 rc_ver_info *verinfo)
1772 rc_res_resource *r;
1774 r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1775 r->type = RES_TYPE_VERSIONINFO;
1776 r->u.versioninfo = ((rc_versioninfo *)
1777 res_alloc (sizeof (rc_versioninfo)));
1778 r->u.versioninfo->fixed = fixedverinfo;
1779 r->u.versioninfo->var = verinfo;
1780 r->res_info.language = language;
1783 /* Add string version info to a list of version information. */
1785 rc_ver_info *
1786 append_ver_stringfileinfo (rc_ver_info *verinfo, const char *language,
1787 rc_ver_stringinfo *strings)
1789 rc_ver_info *vi, **pp;
1791 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1792 vi->next = NULL;
1793 vi->type = VERINFO_STRING;
1794 unicode_from_ascii ((rc_uint_type *) NULL, &vi->u.string.language, language);
1795 vi->u.string.strings = strings;
1797 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1799 *pp = vi;
1801 return verinfo;
1804 /* Add variable version info to a list of version information. */
1806 rc_ver_info *
1807 append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
1808 rc_ver_varinfo *var)
1810 rc_ver_info *vi, **pp;
1812 vi = (rc_ver_info *) res_alloc (sizeof *vi);
1813 vi->next = NULL;
1814 vi->type = VERINFO_VAR;
1815 vi->u.var.key = unichar_dup (key);
1816 vi->u.var.var = var;
1818 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1820 *pp = vi;
1822 return verinfo;
1825 /* Append version string information to a list. */
1827 rc_ver_stringinfo *
1828 append_verval (rc_ver_stringinfo *strings, const unichar *key,
1829 const unichar *value)
1831 rc_ver_stringinfo *vs, **pp;
1833 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1834 vs->next = NULL;
1835 vs->key = unichar_dup (key);
1836 vs->value = unichar_dup (value);
1838 for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1840 *pp = vs;
1842 return strings;
1845 /* Append version variable information to a list. */
1847 rc_ver_varinfo *
1848 append_vertrans (rc_ver_varinfo *var, rc_uint_type language,
1849 rc_uint_type charset)
1851 rc_ver_varinfo *vv, **pp;
1853 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1854 vv->next = NULL;
1855 vv->language = language;
1856 vv->charset = charset;
1858 for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1860 *pp = vv;
1862 return var;
1865 /* Local functions used to write out an rc file. */
1867 static void indent (FILE *, int);
1868 static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
1869 const rc_res_id *, rc_uint_type *, int);
1870 static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
1871 const rc_res_id *, rc_uint_type *, int);
1872 static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
1873 const rc_res_resource *, rc_uint_type *);
1874 static void write_rc_accelerators (FILE *, const rc_accelerator *);
1875 static void write_rc_cursor (FILE *, const rc_cursor *);
1876 static void write_rc_group_cursor (FILE *, const rc_group_cursor *);
1877 static void write_rc_dialog (FILE *, const rc_dialog *);
1878 static void write_rc_dialog_control (FILE *, const rc_dialog_control *);
1879 static void write_rc_fontdir (FILE *, const rc_fontdir *);
1880 static void write_rc_group_icon (FILE *, const rc_group_icon *);
1881 static void write_rc_menu (FILE *, const rc_menu *, int);
1882 static void write_rc_toolbar (FILE *, const rc_toolbar *);
1883 static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
1884 static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
1886 static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
1887 static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
1888 static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
1889 static void write_rc_versioninfo (FILE *, const rc_versioninfo *);
1891 /* Indent a given number of spaces. */
1893 static void
1894 indent (FILE *e, int c)
1896 int i;
1898 for (i = 0; i < c; i++)
1899 putc (' ', e);
1902 /* Dump the resources we have read in the format of an rc file.
1904 Reasoned by the fact, that some resources need to be stored into file and
1905 refer to that file, we use the user-data model for that to express it binary
1906 without the need to store it somewhere externally. */
1908 void
1909 write_rc_file (const char *filename, const rc_res_directory *resources)
1911 FILE *e;
1912 rc_uint_type language;
1914 if (filename == NULL)
1915 e = stdout;
1916 else
1918 e = fopen (filename, FOPEN_WT);
1919 if (e == NULL)
1920 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1923 language = (rc_uint_type) ((bfd_signed_vma) -1);
1924 write_rc_directory (e, resources, (const rc_res_id *) NULL,
1925 (const rc_res_id *) NULL, &language, 1);
1928 /* Write out a directory. E is the file to write to. RD is the
1929 directory. TYPE is a pointer to the level 1 ID which serves as the
1930 resource type. NAME is a pointer to the level 2 ID which serves as
1931 an individual resource name. LANGUAGE is a pointer to the current
1932 language. LEVEL is the level in the tree. */
1934 static void
1935 write_rc_directory (FILE *e, const rc_res_directory *rd,
1936 const rc_res_id *type, const rc_res_id *name,
1937 rc_uint_type *language, int level)
1939 const rc_res_entry *re;
1941 /* Print out some COFF information that rc files can't represent. */
1942 if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
1944 wr_printcomment (e, "COFF information not part of RC");
1945 if (rd->time != 0)
1946 wr_printcomment (e, "Time stamp: %u", rd->time);
1947 if (rd->characteristics != 0)
1948 wr_printcomment (e, "Characteristics: %u", rd->characteristics);
1949 if (rd->major != 0 || rd->minor != 0)
1950 wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
1953 for (re = rd->entries; re != NULL; re = re->next)
1955 switch (level)
1957 case 1:
1958 /* If we're at level 1, the key of this resource is the
1959 type. This normally duplicates the information we have
1960 stored with the resource itself, but we need to remember
1961 the type if this is a user define resource type. */
1962 type = &re->id;
1963 break;
1965 case 2:
1966 /* If we're at level 2, the key of this resource is the name
1967 we are going to use in the rc printout. */
1968 name = &re->id;
1969 break;
1971 case 3:
1972 /* If we're at level 3, then this key represents a language.
1973 Use it to update the current language. */
1974 if (! re->id.named
1975 && re->id.u.id != (unsigned long) (unsigned int) *language
1976 && (re->id.u.id & 0xffff) == re->id.u.id)
1978 wr_print (e, "LANGUAGE %u, %u\n",
1979 re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
1980 (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
1981 *language = re->id.u.id;
1983 break;
1985 default:
1986 break;
1989 if (re->subdir)
1990 write_rc_subdir (e, re, type, name, language, level);
1991 else
1993 if (level == 3)
1995 /* This is the normal case: the three levels are
1996 TYPE/NAME/LANGUAGE. NAME will have been set at level
1997 2, and represents the name to use. We probably just
1998 set LANGUAGE, and it will probably match what the
1999 resource itself records if anything. */
2000 write_rc_resource (e, type, name, re->u.res, language);
2002 else
2004 wr_printcomment (e, "Resource at unexpected level %d", level);
2005 write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
2006 language);
2010 if (rd->entries == NULL)
2012 wr_print_flush (e);
2016 /* Write out a subdirectory entry. E is the file to write to. RE is
2017 the subdirectory entry. TYPE and NAME are pointers to higher level
2018 IDs, or NULL. LANGUAGE is a pointer to the current language.
2019 LEVEL is the level in the tree. */
2021 static void
2022 write_rc_subdir (FILE *e, const rc_res_entry *re,
2023 const rc_res_id *type, const rc_res_id *name,
2024 rc_uint_type *language, int level)
2026 fprintf (e, "\n");
2027 switch (level)
2029 case 1:
2030 wr_printcomment (e, "Type: ");
2031 if (re->id.named)
2032 res_id_print (e, re->id, 1);
2033 else
2035 const char *s;
2037 switch (re->id.u.id)
2039 case RT_CURSOR: s = "cursor"; break;
2040 case RT_BITMAP: s = "bitmap"; break;
2041 case RT_ICON: s = "icon"; break;
2042 case RT_MENU: s = "menu"; break;
2043 case RT_DIALOG: s = "dialog"; break;
2044 case RT_STRING: s = "stringtable"; break;
2045 case RT_FONTDIR: s = "fontdir"; break;
2046 case RT_FONT: s = "font"; break;
2047 case RT_ACCELERATOR: s = "accelerators"; break;
2048 case RT_RCDATA: s = "rcdata"; break;
2049 case RT_MESSAGETABLE: s = "messagetable"; break;
2050 case RT_GROUP_CURSOR: s = "group cursor"; break;
2051 case RT_GROUP_ICON: s = "group icon"; break;
2052 case RT_VERSION: s = "version"; break;
2053 case RT_DLGINCLUDE: s = "dlginclude"; break;
2054 case RT_PLUGPLAY: s = "plugplay"; break;
2055 case RT_VXD: s = "vxd"; break;
2056 case RT_ANICURSOR: s = "anicursor"; break;
2057 case RT_ANIICON: s = "aniicon"; break;
2058 case RT_TOOLBAR: s = "toolbar"; break;
2059 case RT_HTML: s = "html"; break;
2060 default: s = NULL; break;
2063 if (s != NULL)
2064 fprintf (e, "%s", s);
2065 else
2066 res_id_print (e, re->id, 1);
2068 break;
2070 case 2:
2071 wr_printcomment (e, "Name: ");
2072 res_id_print (e, re->id, 1);
2073 break;
2075 case 3:
2076 wr_printcomment (e, "Language: ");
2077 res_id_print (e, re->id, 1);
2078 break;
2080 default:
2081 wr_printcomment (e, "Level %d: ", level);
2082 res_id_print (e, re->id, 1);
2085 write_rc_directory (e, re->u.dir, type, name, language, level + 1);
2088 /* Write out a single resource. E is the file to write to. TYPE is a
2089 pointer to the type of the resource. NAME is a pointer to the name
2090 of the resource; it will be NULL if there is a level mismatch. RES
2091 is the resource data. LANGUAGE is a pointer to the current
2092 language. */
2094 static void
2095 write_rc_resource (FILE *e, const rc_res_id *type,
2096 const rc_res_id *name, const rc_res_resource *res,
2097 rc_uint_type *language)
2099 const char *s;
2100 int rt;
2101 int menuex = 0;
2103 switch (res->type)
2105 default:
2106 abort ();
2108 case RES_TYPE_ACCELERATOR:
2109 s = "ACCELERATORS";
2110 rt = RT_ACCELERATOR;
2111 break;
2113 case RES_TYPE_BITMAP:
2114 s = "2 /* RT_BITMAP */";
2115 rt = RT_BITMAP;
2116 break;
2118 case RES_TYPE_CURSOR:
2119 s = "1 /* RT_CURSOR */";
2120 rt = RT_CURSOR;
2121 break;
2123 case RES_TYPE_GROUP_CURSOR:
2124 s = "12 /* RT_GROUP_CURSOR */";
2125 rt = RT_GROUP_CURSOR;
2126 break;
2128 case RES_TYPE_DIALOG:
2129 if (extended_dialog (res->u.dialog))
2130 s = "DIALOGEX";
2131 else
2132 s = "DIALOG";
2133 rt = RT_DIALOG;
2134 break;
2136 case RES_TYPE_FONT:
2137 s = "8 /* RT_FONT */";
2138 rt = RT_FONT;
2139 break;
2141 case RES_TYPE_FONTDIR:
2142 s = "7 /* RT_FONTDIR */";
2143 rt = RT_FONTDIR;
2144 break;
2146 case RES_TYPE_ICON:
2147 s = "3 /* RT_ICON */";
2148 rt = RT_ICON;
2149 break;
2151 case RES_TYPE_GROUP_ICON:
2152 s = "14 /* RT_GROUP_ICON */";
2153 rt = RT_GROUP_ICON;
2154 break;
2156 case RES_TYPE_MENU:
2157 if (extended_menu (res->u.menu))
2159 s = "MENUEX";
2160 menuex = 1;
2162 else
2164 s = "MENU";
2165 menuex = 0;
2167 rt = RT_MENU;
2168 break;
2170 case RES_TYPE_MESSAGETABLE:
2171 s = "11 /* RT_MESSAGETABLE */";
2172 rt = RT_MESSAGETABLE;
2173 break;
2175 case RES_TYPE_RCDATA:
2176 s = "RCDATA";
2177 rt = RT_RCDATA;
2178 break;
2180 case RES_TYPE_STRINGTABLE:
2181 s = "STRINGTABLE";
2182 rt = RT_STRING;
2183 break;
2185 case RES_TYPE_USERDATA:
2186 s = NULL;
2187 rt = 0;
2188 break;
2190 case RES_TYPE_VERSIONINFO:
2191 s = "VERSIONINFO";
2192 rt = RT_VERSION;
2193 break;
2195 case RES_TYPE_TOOLBAR:
2196 s = "TOOLBAR";
2197 rt = RT_TOOLBAR;
2198 break;
2201 if (rt != 0
2202 && type != NULL
2203 && (type->named || type->u.id != (unsigned long) rt))
2205 wr_printcomment (e, "Unexpected resource type mismatch: ");
2206 res_id_print (e, *type, 1);
2207 fprintf (e, " != %d", rt);
2210 if (res->coff_info.codepage != 0)
2211 wr_printcomment (e, "Code page: %u", res->coff_info.codepage);
2212 if (res->coff_info.reserved != 0)
2213 wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved);
2215 wr_print (e, "\n");
2216 if (rt == RT_STRING)
2218 else
2220 if (name != NULL)
2221 res_id_print (e, *name, 1);
2222 else
2223 fprintf (e, "??Unknown-Name??");
2224 fprintf (e, " ");
2227 if (s != NULL)
2228 fprintf (e, "%s", s);
2229 else if (type != NULL)
2231 if (type->named == 0)
2233 #define PRINT_RT_NAME(NAME) case NAME: \
2234 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2235 break
2237 switch (type->u.id)
2239 default:
2240 res_id_print (e, *type, 0);
2241 break;
2243 PRINT_RT_NAME(RT_MANIFEST);
2244 PRINT_RT_NAME(RT_ANICURSOR);
2245 PRINT_RT_NAME(RT_ANIICON);
2246 PRINT_RT_NAME(RT_RCDATA);
2247 PRINT_RT_NAME(RT_ICON);
2248 PRINT_RT_NAME(RT_CURSOR);
2249 PRINT_RT_NAME(RT_BITMAP);
2250 PRINT_RT_NAME(RT_PLUGPLAY);
2251 PRINT_RT_NAME(RT_VXD);
2252 PRINT_RT_NAME(RT_FONT);
2253 PRINT_RT_NAME(RT_FONTDIR);
2254 PRINT_RT_NAME(RT_HTML);
2255 PRINT_RT_NAME(RT_MESSAGETABLE);
2256 PRINT_RT_NAME(RT_DLGINCLUDE);
2257 PRINT_RT_NAME(RT_DLGINIT);
2259 #undef PRINT_RT_NAME
2261 else
2262 res_id_print (e, *type, 1);
2264 else
2265 fprintf (e, "??Unknown-Type??");
2267 if (res->res_info.memflags != 0)
2269 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
2270 fprintf (e, " MOVEABLE");
2271 if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
2272 fprintf (e, " PURE");
2273 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
2274 fprintf (e, " PRELOAD");
2275 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
2276 fprintf (e, " DISCARDABLE");
2279 if (res->type == RES_TYPE_DIALOG)
2281 fprintf (e, " %d, %d, %d, %d",
2282 (int) res->u.dialog->x, (int) res->u.dialog->y,
2283 (int) res->u.dialog->width, (int) res->u.dialog->height);
2284 if (res->u.dialog->ex != NULL
2285 && res->u.dialog->ex->help != 0)
2286 fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help);
2288 else if (res->type == RES_TYPE_TOOLBAR)
2290 fprintf (e, " %d, %d", (int) res->u.toolbar->button_width,
2291 (int) res->u.toolbar->button_height);
2294 fprintf (e, "\n");
2296 if ((res->res_info.language != 0 && res->res_info.language != *language)
2297 || res->res_info.characteristics != 0
2298 || res->res_info.version != 0)
2300 int modifiers;
2302 switch (res->type)
2304 case RES_TYPE_ACCELERATOR:
2305 case RES_TYPE_DIALOG:
2306 case RES_TYPE_MENU:
2307 case RES_TYPE_RCDATA:
2308 case RES_TYPE_STRINGTABLE:
2309 modifiers = 1;
2310 break;
2312 default:
2313 modifiers = 0;
2314 break;
2317 if (res->res_info.language != 0 && res->res_info.language != *language)
2318 fprintf (e, "%sLANGUAGE %d, %d\n",
2319 modifiers ? "// " : "",
2320 (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
2321 (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
2322 if (res->res_info.characteristics != 0)
2323 fprintf (e, "%sCHARACTERISTICS %u\n",
2324 modifiers ? "// " : "",
2325 (unsigned int) res->res_info.characteristics);
2326 if (res->res_info.version != 0)
2327 fprintf (e, "%sVERSION %u\n",
2328 modifiers ? "// " : "",
2329 (unsigned int) res->res_info.version);
2332 switch (res->type)
2334 default:
2335 abort ();
2337 case RES_TYPE_ACCELERATOR:
2338 write_rc_accelerators (e, res->u.acc);
2339 break;
2341 case RES_TYPE_CURSOR:
2342 write_rc_cursor (e, res->u.cursor);
2343 break;
2345 case RES_TYPE_GROUP_CURSOR:
2346 write_rc_group_cursor (e, res->u.group_cursor);
2347 break;
2349 case RES_TYPE_DIALOG:
2350 write_rc_dialog (e, res->u.dialog);
2351 break;
2353 case RES_TYPE_FONTDIR:
2354 write_rc_fontdir (e, res->u.fontdir);
2355 break;
2357 case RES_TYPE_GROUP_ICON:
2358 write_rc_group_icon (e, res->u.group_icon);
2359 break;
2361 case RES_TYPE_MENU:
2362 write_rc_menu (e, res->u.menu, menuex);
2363 break;
2365 case RES_TYPE_RCDATA:
2366 write_rc_rcdata (e, res->u.rcdata, 0);
2367 break;
2369 case RES_TYPE_STRINGTABLE:
2370 write_rc_stringtable (e, name, res->u.stringtable);
2371 break;
2373 case RES_TYPE_USERDATA:
2374 write_rc_rcdata (e, res->u.userdata, 0);
2375 break;
2377 case RES_TYPE_TOOLBAR:
2378 write_rc_toolbar (e, res->u.toolbar);
2379 break;
2381 case RES_TYPE_VERSIONINFO:
2382 write_rc_versioninfo (e, res->u.versioninfo);
2383 break;
2385 case RES_TYPE_BITMAP:
2386 case RES_TYPE_FONT:
2387 case RES_TYPE_ICON:
2388 write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0);
2389 break;
2390 case RES_TYPE_MESSAGETABLE:
2391 write_rc_messagetable (e, res->u.data.length, res->u.data.data);
2392 break;
2396 /* Write out accelerator information. */
2398 static void
2399 write_rc_accelerators (FILE *e, const rc_accelerator *accelerators)
2401 const rc_accelerator *acc;
2403 fprintf (e, "BEGIN\n");
2404 for (acc = accelerators; acc != NULL; acc = acc->next)
2406 int printable;
2408 fprintf (e, " ");
2410 if ((acc->key & 0x7f) == acc->key
2411 && ISPRINT (acc->key)
2412 && (acc->flags & ACC_VIRTKEY) == 0)
2414 fprintf (e, "\"%c\"", (char) acc->key);
2415 printable = 1;
2417 else
2419 fprintf (e, "%d", (int) acc->key);
2420 printable = 0;
2423 fprintf (e, ", %d", (int) acc->id);
2425 if (! printable)
2427 if ((acc->flags & ACC_VIRTKEY) != 0)
2428 fprintf (e, ", VIRTKEY");
2429 else
2430 fprintf (e, ", ASCII");
2433 if ((acc->flags & ACC_SHIFT) != 0)
2434 fprintf (e, ", SHIFT");
2435 if ((acc->flags & ACC_CONTROL) != 0)
2436 fprintf (e, ", CONTROL");
2437 if ((acc->flags & ACC_ALT) != 0)
2438 fprintf (e, ", ALT");
2440 fprintf (e, "\n");
2443 fprintf (e, "END\n");
2446 /* Write out cursor information. This would normally be in a separate
2447 file, which the rc file would include. */
2449 static void
2450 write_rc_cursor (FILE *e, const rc_cursor *cursor)
2452 fprintf (e, "BEGIN\n");
2453 indent (e, 2);
2454 fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2455 (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot,
2456 (int) cursor->xhotspot, (int) cursor->yhotspot);
2457 write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data,
2458 0, 0, 0);
2459 fprintf (e, "END\n");
2462 /* Write out group cursor data. This would normally be built from the
2463 cursor data. */
2465 static void
2466 write_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor)
2468 const rc_group_cursor *gc;
2469 int c;
2471 for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2473 fprintf (e, "BEGIN\n");
2475 indent (e, 2);
2476 fprintf (e, "0, 2, %d%s\t /* Having %d items. */\n", c, (c != 0 ? "," : ""), c);
2477 indent (e, 4);
2478 fprintf (e, "/* width, height, planes, bits, bytes, index. */\n");
2480 for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2482 indent (e, 4);
2483 fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2484 (int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits,
2485 (unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c);
2486 fprintf (e, "/* width: %d; height %d; planes %d; bits %d. */\n",
2487 (int) gc->width, (int) gc->height, (int) gc->planes,
2488 (int) gc->bits);
2490 fprintf (e, "END\n");
2493 /* Write dialog data. */
2495 static void
2496 write_rc_dialog (FILE *e, const rc_dialog *dialog)
2498 const rc_dialog_control *control;
2500 fprintf (e, "STYLE 0x%x\n", dialog->style);
2502 if (dialog->exstyle != 0)
2503 fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle);
2505 if ((dialog->class.named && dialog->class.u.n.length > 0)
2506 || dialog->class.u.id != 0)
2508 fprintf (e, "CLASS ");
2509 res_id_print (e, dialog->class, 1);
2510 fprintf (e, "\n");
2513 if (dialog->caption != NULL)
2515 fprintf (e, "CAPTION ");
2516 unicode_print_quoted (e, dialog->caption, -1);
2517 fprintf (e, "\n");
2520 if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2521 || dialog->menu.u.id != 0)
2523 fprintf (e, "MENU ");
2524 res_id_print (e, dialog->menu, 0);
2525 fprintf (e, "\n");
2528 if (dialog->font != NULL)
2530 fprintf (e, "FONT %d, ", (int) dialog->pointsize);
2531 unicode_print_quoted (e, dialog->font, -1);
2532 if (dialog->ex != NULL
2533 && (dialog->ex->weight != 0
2534 || dialog->ex->italic != 0
2535 || dialog->ex->charset != 1))
2536 fprintf (e, ", %d, %d, %d",
2537 (int) dialog->ex->weight,
2538 (int) dialog->ex->italic,
2539 (int) dialog->ex->charset);
2540 fprintf (e, "\n");
2543 fprintf (e, "BEGIN\n");
2545 for (control = dialog->controls; control != NULL; control = control->next)
2546 write_rc_dialog_control (e, control);
2548 fprintf (e, "END\n");
2551 /* For each predefined control keyword, this table provides the class
2552 and the style. */
2554 struct control_info
2556 const char *name;
2557 unsigned short class;
2558 unsigned long style;
2561 static const struct control_info control_info[] =
2563 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2564 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2565 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2566 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2567 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2568 { "CTEXT", CTL_STATIC, SS_CENTER },
2569 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2570 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2571 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2572 { "ICON", CTL_STATIC, SS_ICON },
2573 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2574 { "LTEXT", CTL_STATIC, SS_LEFT },
2575 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2576 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2577 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2578 { "RTEXT", CTL_STATIC, SS_RIGHT },
2579 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2580 { "STATE3", CTL_BUTTON, BS_3STATE },
2581 /* It's important that USERBUTTON come after all the other button
2582 types, so that it won't be matched too early. */
2583 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2584 { NULL, 0, 0 }
2587 /* Write a dialog control. */
2589 static void
2590 write_rc_dialog_control (FILE *e, const rc_dialog_control *control)
2592 const struct control_info *ci;
2594 fprintf (e, " ");
2596 if (control->class.named)
2597 ci = NULL;
2598 else
2600 for (ci = control_info; ci->name != NULL; ++ci)
2601 if (ci->class == control->class.u.id
2602 && (ci->style == (unsigned long) -1
2603 || ci->style == (control->style & 0xff)))
2604 break;
2606 if (ci == NULL)
2607 fprintf (e, "CONTROL");
2608 else if (ci->name != NULL)
2609 fprintf (e, "%s", ci->name);
2610 else
2612 fprintf (e, "CONTROL");
2613 ci = NULL;
2616 if (control->text.named || control->text.u.id != 0)
2618 fprintf (e, " ");
2619 res_id_print (e, control->text, 1);
2620 fprintf (e, ",");
2623 fprintf (e, " %d, ", (int) control->id);
2625 if (ci == NULL)
2627 if (control->class.named)
2628 fprintf (e, "\"");
2629 res_id_print (e, control->class, 0);
2630 if (control->class.named)
2631 fprintf (e, "\"");
2632 fprintf (e, ", 0x%x, ", (unsigned int) control->style);
2635 fprintf (e, "%d, %d", (int) control->x, (int) control->y);
2637 if (control->style != SS_ICON
2638 || control->exstyle != 0
2639 || control->width != 0
2640 || control->height != 0
2641 || control->help != 0)
2643 fprintf (e, ", %d, %d", (int) control->width, (int) control->height);
2645 /* FIXME: We don't need to print the style if it is the default.
2646 More importantly, in certain cases we actually need to turn
2647 off parts of the forced style, by using NOT. */
2648 if (ci != NULL)
2649 fprintf (e, ", 0x%x", (unsigned int) control->style);
2651 if (control->exstyle != 0 || control->help != 0)
2652 fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle,
2653 (unsigned int) control->help);
2656 fprintf (e, "\n");
2658 if (control->data != NULL)
2659 write_rc_rcdata (e, control->data, 2);
2662 /* Write out font directory data. This would normally be built from
2663 the font data. */
2665 static void
2666 write_rc_fontdir (FILE *e, const rc_fontdir *fontdir)
2668 const rc_fontdir *fc;
2669 int c;
2671 for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++)
2673 fprintf (e, "BEGIN\n");
2674 indent (e, 2);
2675 fprintf (e, "%d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2676 for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++)
2678 indent (e, 4);
2679 fprintf (e, "%d,\t/* Font no %d with index %d. */\n",
2680 (int) fc->index, c, (int) fc->index);
2681 write_rc_datablock (e, (rc_uint_type) fc->length - 2,
2682 (const bfd_byte *) fc->data + 4,fc->next != NULL,
2683 0, 0);
2685 fprintf (e, "END\n");
2688 /* Write out group icon data. This would normally be built from the
2689 icon data. */
2691 static void
2692 write_rc_group_icon (FILE *e, const rc_group_icon *group_icon)
2694 const rc_group_icon *gi;
2695 int c;
2697 for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++)
2700 fprintf (e, "BEGIN\n");
2701 indent (e, 2);
2702 fprintf (e, " 0, 1, %d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2704 indent (e, 4);
2705 fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2706 for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++)
2708 indent (e, 4);
2709 fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2710 gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits,
2711 (unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c);
2713 fprintf (e, "END\n");
2716 /* Write out a menu resource. */
2718 static void
2719 write_rc_menu (FILE *e, const rc_menu *menu, int menuex)
2721 if (menu->help != 0)
2722 fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help);
2723 write_rc_menuitems (e, menu->items, menuex, 0);
2726 static void
2727 write_rc_toolbar (FILE *e, const rc_toolbar *tb)
2729 rc_toolbar_item *it;
2730 indent (e, 0);
2731 fprintf (e, "BEGIN\n");
2732 it = tb->items;
2733 while(it != NULL)
2735 indent (e, 2);
2736 if (it->id.u.id == 0)
2737 fprintf (e, "SEPARATOR\n");
2738 else
2739 fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
2740 it = it->next;
2742 indent (e, 0);
2743 fprintf (e, "END\n");
2746 /* Write out menuitems. */
2748 static void
2749 write_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex,
2750 int ind)
2752 const rc_menuitem *mi;
2754 indent (e, ind);
2755 fprintf (e, "BEGIN\n");
2757 for (mi = menuitems; mi != NULL; mi = mi->next)
2759 indent (e, ind + 2);
2761 if (mi->popup == NULL)
2762 fprintf (e, "MENUITEM");
2763 else
2764 fprintf (e, "POPUP");
2766 if (! menuex
2767 && mi->popup == NULL
2768 && mi->text == NULL
2769 && mi->type == 0
2770 && mi->id == 0)
2772 fprintf (e, " SEPARATOR\n");
2773 continue;
2776 if (mi->text == NULL)
2777 fprintf (e, " \"\"");
2778 else
2780 fprintf (e, " ");
2781 unicode_print_quoted (e, mi->text, -1);
2784 if (! menuex)
2786 if (mi->popup == NULL)
2787 fprintf (e, ", %d", (int) mi->id);
2789 if ((mi->type & MENUITEM_CHECKED) != 0)
2790 fprintf (e, ", CHECKED");
2791 if ((mi->type & MENUITEM_GRAYED) != 0)
2792 fprintf (e, ", GRAYED");
2793 if ((mi->type & MENUITEM_HELP) != 0)
2794 fprintf (e, ", HELP");
2795 if ((mi->type & MENUITEM_INACTIVE) != 0)
2796 fprintf (e, ", INACTIVE");
2797 if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2798 fprintf (e, ", MENUBARBREAK");
2799 if ((mi->type & MENUITEM_MENUBREAK) != 0)
2800 fprintf (e, ", MENUBREAK");
2802 else
2804 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2806 fprintf (e, ", %d", (int) mi->id);
2807 if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2809 fprintf (e, ", %u", (unsigned int) mi->type);
2810 if (mi->state != 0 || mi->help != 0)
2812 fprintf (e, ", %u", (unsigned int) mi->state);
2813 if (mi->help != 0)
2814 fprintf (e, ", %u", (unsigned int) mi->help);
2820 fprintf (e, "\n");
2822 if (mi->popup != NULL)
2823 write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2826 indent (e, ind);
2827 fprintf (e, "END\n");
2830 static int
2831 test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
2833 rc_uint_type i;
2834 if ((length & 1) != 0)
2835 return 0;
2837 for (i = 0; i < length; i += 2)
2839 if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2840 return 0;
2841 if (data[i] == 0xff && data[i + 1] == 0xff)
2842 return 0;
2844 return 1;
2847 static int
2848 test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2850 int has_nl;
2851 rc_uint_type c;
2852 rc_uint_type i;
2854 if (length <= 1)
2855 return 0;
2857 has_nl = 0;
2858 for (i = 0, c = 0; i < length; i++)
2860 if (! ISPRINT (data[i]) && data[i] != '\n'
2861 && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2862 && data[i] != '\t'
2863 && ! (data[i] == 0 && (i + 1) != length))
2865 if (data[i] <= 7)
2866 return 0;
2867 c++;
2869 else if (data[i] == '\n') has_nl++;
2871 if (length > 80 && ! has_nl)
2872 return 0;
2873 c = (((c * 10000) + (i / 100) - 1)) / i;
2874 if (c >= 150)
2875 return 0;
2876 return 1;
2879 static void
2880 write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
2882 int has_error = 0;
2883 const struct bin_messagetable *mt;
2884 fprintf (e, "BEGIN\n");
2886 write_rc_datablock (e, length, data, 0, 0, 0);
2888 fprintf (e, "\n");
2889 wr_printcomment (e, "MC syntax dump");
2890 if (length < BIN_MESSAGETABLE_SIZE)
2891 has_error = 1;
2892 else
2893 do {
2894 rc_uint_type m, i;
2895 mt = (const struct bin_messagetable *) data;
2896 m = windres_get_32 (&wrtarget, mt->cblocks, length);
2897 if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2899 has_error = 1;
2900 break;
2902 for (i = 0; i < m; i++)
2904 rc_uint_type low, high, offset;
2905 const struct bin_messagetable_item *mti;
2907 low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2908 high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2909 offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2910 while (low <= high)
2912 rc_uint_type elen, flags;
2913 if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2915 has_error = 1;
2916 break;
2918 mti = (const struct bin_messagetable_item *) &data[offset];
2919 elen = windres_get_16 (&wrtarget, mti->length, 2);
2920 flags = windres_get_16 (&wrtarget, mti->flags, 2);
2921 if ((offset + elen) > length)
2923 has_error = 1;
2924 break;
2926 wr_printcomment (e, "MessageId = 0x%x", low);
2927 wr_printcomment (e, "");
2928 if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2929 unicode_print (e, (const unichar *) mti->data,
2930 (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2931 else
2932 ascii_print (e, (const char *) mti->data,
2933 (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2934 wr_printcomment (e,"");
2935 ++low;
2936 offset += elen;
2939 } while (0);
2940 if (has_error)
2941 wr_printcomment (e, "Illegal data");
2942 wr_print_flush (e);
2943 fprintf (e, "END\n");
2946 static void
2947 write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
2948 int hasblock, int show_comment)
2950 int plen;
2952 if (hasblock)
2953 fprintf (e, "BEGIN\n");
2955 if (show_comment == -1)
2957 if (test_rc_datablock_text(length, data))
2959 rc_uint_type i, c;
2960 for (i = 0; i < length;)
2962 indent (e, 2);
2963 fprintf (e, "\"");
2965 for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
2967 if (i < length && data[i] == '\n')
2968 ++i, ++c;
2969 ascii_print (e, (const char *) &data[i - c], c);
2970 fprintf (e, "\"");
2971 if (i < length)
2972 fprintf (e, "\n");
2975 if (i == 0)
2977 indent (e, 2);
2978 fprintf (e, "\"\"");
2980 if (has_next)
2981 fprintf (e, ",");
2982 fprintf (e, "\n");
2983 if (hasblock)
2984 fprintf (e, "END\n");
2985 return;
2987 if (test_rc_datablock_unicode (length, data))
2989 rc_uint_type i, c;
2990 for (i = 0; i < length;)
2992 const unichar *u;
2994 u = (const unichar *) &data[i];
2995 indent (e, 2);
2996 fprintf (e, "L\"");
2998 for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
3000 if (i < length && u[c] == '\n')
3001 i += 2, ++c;
3002 unicode_print (e, u, c);
3003 fprintf (e, "\"");
3004 if (i < length)
3005 fprintf (e, "\n");
3008 if (i == 0)
3010 indent (e, 2);
3011 fprintf (e, "L\"\"");
3013 if (has_next)
3014 fprintf (e, ",");
3015 fprintf (e, "\n");
3016 if (hasblock)
3017 fprintf (e, "END\n");
3018 return;
3021 show_comment = 0;
3024 if (length != 0)
3026 rc_uint_type i, max_row;
3027 int first = 1;
3029 max_row = (show_comment ? 4 : 8);
3030 indent (e, 2);
3031 for (i = 0; i + 3 < length;)
3033 rc_uint_type k;
3034 rc_uint_type comment_start;
3036 comment_start = i;
3038 if (! first)
3039 indent (e, 2);
3041 for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
3043 if (k == 0)
3044 plen = fprintf (e, "0x%lxL",
3045 (long) windres_get_32 (&wrtarget, data + i, length - i));
3046 else
3047 plen = fprintf (e, " 0x%lxL",
3048 (long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
3049 if (has_next || (i + 4) < length)
3051 if (plen>0 && plen < 11)
3052 indent (e, 11 - plen);
3053 fprintf (e, ",");
3056 if (show_comment)
3058 fprintf (e, "\t/* ");
3059 ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3060 fprintf (e, ". */");
3062 fprintf (e, "\n");
3063 first = 0;
3066 if (i + 1 < length)
3068 if (! first)
3069 indent (e, 2);
3070 plen = fprintf (e, "0x%x",
3071 (int) windres_get_16 (&wrtarget, data + i, length - i));
3072 if (has_next || i + 2 < length)
3074 if (plen > 0 && plen < 11)
3075 indent (e, 11 - plen);
3076 fprintf (e, ",");
3078 if (show_comment)
3080 fprintf (e, "\t/* ");
3081 ascii_print (e, (const char *) &data[i], 2);
3082 fprintf (e, ". */");
3084 fprintf (e, "\n");
3085 i += 2;
3086 first = 0;
3089 if (i < length)
3091 if (! first)
3092 indent (e, 2);
3093 fprintf (e, "\"");
3094 ascii_print (e, (const char *) &data[i], 1);
3095 fprintf (e, "\"");
3096 if (has_next)
3097 fprintf (e, ",");
3098 fprintf (e, "\n");
3099 first = 0;
3102 if (hasblock)
3103 fprintf (e, "END\n");
3106 /* Write out an rcdata resource. This is also used for other types of
3107 resources that need to print arbitrary data. */
3109 static void
3110 write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3112 const rc_rcdata_item *ri;
3114 indent (e, ind);
3115 fprintf (e, "BEGIN\n");
3117 for (ri = rcdata; ri != NULL; ri = ri->next)
3119 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3120 continue;
3122 switch (ri->type)
3124 default:
3125 abort ();
3127 case RCDATA_WORD:
3128 indent (e, ind + 2);
3129 fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3130 break;
3132 case RCDATA_DWORD:
3133 indent (e, ind + 2);
3134 fprintf (e, "%luL", (unsigned long) ri->u.dword);
3135 break;
3137 case RCDATA_STRING:
3138 indent (e, ind + 2);
3139 fprintf (e, "\"");
3140 ascii_print (e, ri->u.string.s, ri->u.string.length);
3141 fprintf (e, "\"");
3142 break;
3144 case RCDATA_WSTRING:
3145 indent (e, ind + 2);
3146 fprintf (e, "L\"");
3147 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3148 fprintf (e, "\"");
3149 break;
3151 case RCDATA_BUFFER:
3152 write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3153 (const bfd_byte *) ri->u.buffer.data,
3154 ri->next != NULL, 0, -1);
3155 break;
3158 if (ri->type != RCDATA_BUFFER)
3160 if (ri->next != NULL)
3161 fprintf (e, ",");
3162 fprintf (e, "\n");
3166 indent (e, ind);
3167 fprintf (e, "END\n");
3170 /* Write out a stringtable resource. */
3172 static void
3173 write_rc_stringtable (FILE *e, const rc_res_id *name,
3174 const rc_stringtable *stringtable)
3176 rc_uint_type offset;
3177 int i;
3179 if (name != NULL && ! name->named)
3180 offset = (name->u.id - 1) << 4;
3181 else
3183 fprintf (e, "/* %s string table name. */\n",
3184 name == NULL ? "Missing" : "Invalid");
3185 offset = 0;
3188 fprintf (e, "BEGIN\n");
3190 for (i = 0; i < 16; i++)
3192 if (stringtable->strings[i].length != 0)
3194 fprintf (e, " %lu, ", (long) offset + i);
3195 unicode_print_quoted (e, stringtable->strings[i].string,
3196 stringtable->strings[i].length);
3197 fprintf (e, "\n");
3201 fprintf (e, "END\n");
3204 /* Write out a versioninfo resource. */
3206 static void
3207 write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
3209 const rc_fixed_versioninfo *f;
3210 const rc_ver_info *vi;
3212 f = versioninfo->fixed;
3213 if (f->file_version_ms != 0 || f->file_version_ls != 0)
3214 fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3215 (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3216 (unsigned int) (f->file_version_ms & 0xffff),
3217 (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3218 (unsigned int) (f->file_version_ls & 0xffff));
3219 if (f->product_version_ms != 0 || f->product_version_ls != 0)
3220 fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3221 (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3222 (unsigned int) (f->product_version_ms & 0xffff),
3223 (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3224 (unsigned int) (f->product_version_ls & 0xffff));
3225 if (f->file_flags_mask != 0)
3226 fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
3227 if (f->file_flags != 0)
3228 fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
3229 if (f->file_os != 0)
3230 fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
3231 if (f->file_type != 0)
3232 fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
3233 if (f->file_subtype != 0)
3234 fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
3235 if (f->file_date_ms != 0 || f->file_date_ls != 0)
3236 fprintf (e, "/* Date: %u, %u. */\n",
3237 (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
3239 fprintf (e, "BEGIN\n");
3241 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3243 switch (vi->type)
3245 case VERINFO_STRING:
3247 const rc_ver_stringinfo *vs;
3249 fprintf (e, " BLOCK \"StringFileInfo\"\n");
3250 fprintf (e, " BEGIN\n");
3251 fprintf (e, " BLOCK ");
3252 unicode_print_quoted (e, vi->u.string.language, -1);
3253 fprintf (e, "\n");
3254 fprintf (e, " BEGIN\n");
3256 for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
3258 fprintf (e, " VALUE ");
3259 unicode_print_quoted (e, vs->key, -1);
3260 fprintf (e, ", ");
3261 unicode_print_quoted (e, vs->value, -1);
3262 fprintf (e, "\n");
3265 fprintf (e, " END\n");
3266 fprintf (e, " END\n");
3267 break;
3270 case VERINFO_VAR:
3272 const rc_ver_varinfo *vv;
3274 fprintf (e, " BLOCK \"VarFileInfo\"\n");
3275 fprintf (e, " BEGIN\n");
3276 fprintf (e, " VALUE ");
3277 unicode_print_quoted (e, vi->u.var.key, -1);
3279 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3280 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3281 (int) vv->charset);
3283 fprintf (e, "\n END\n");
3285 break;
3290 fprintf (e, "END\n");
3293 static rc_uint_type
3294 rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
3296 if (! src)
3297 return 0;
3298 switch (src->type)
3300 case RCDATA_WORD:
3301 if (dst)
3302 windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3303 return 2;
3304 case RCDATA_DWORD:
3305 if (dst)
3306 windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3307 return 4;
3308 case RCDATA_STRING:
3309 if (dst && src->u.string.length)
3310 memcpy (dst, src->u.string.s, src->u.string.length);
3311 return (rc_uint_type) src->u.string.length;
3312 case RCDATA_WSTRING:
3313 if (dst && src->u.wstring.length)
3314 memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3315 return (rc_uint_type) (src->u.wstring.length * sizeof (unichar));
3316 case RCDATA_BUFFER:
3317 if (dst && src->u.buffer.length)
3318 memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3319 return (rc_uint_type) src->u.buffer.length;
3320 default:
3321 abort ();
3323 /* Never reached. */
3324 return 0;