1 /* resrc.c -- read and write Windows rc files.
2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2011
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
24 /* This file contains functions that read and write Windows rc files.
25 These are text files that represent resources. */
30 #include "libiberty.h"
31 #include "safe-ctype.h"
36 #ifdef HAVE_SYS_WAIT_H
38 #else /* ! HAVE_SYS_WAIT_H */
39 #if ! defined (_WIN32) || defined (__CYGWIN__)
41 #define WIFEXITED(w) (((w)&0377) == 0)
44 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
47 #define WTERMSIG(w) ((w) & 0177)
50 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
52 #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
54 #define WIFEXITED(w) (((w) & 0xff) == 0)
57 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
60 #define WTERMSIG(w) ((w) & 0x7f)
63 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
65 #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
66 #endif /* ! HAVE_SYS_WAIT_H */
69 #define STDOUT_FILENO 1
72 #if defined (_WIN32) && ! defined (__CYGWIN__)
74 #define pclose _pclose
77 /* The default preprocessor. */
79 #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
81 /* We read the directory entries in a cursor or icon file into
82 instances of this structure. */
88 /* Height of image. */
90 /* Number of colors in image. */
97 unsigned short planes;
103 /* X coordinate of hotspot. */
104 unsigned short xhotspot;
105 /* Y coordinate of hotspot. */
106 unsigned short yhotspot;
109 /* Bytes in image. */
111 /* File offset of image. */
112 unsigned long offset;
115 /* The name of the rc file we are reading. */
119 /* The line number in the rc file. */
123 /* The pipe we are reading from, so that we can close it if we exit. */
127 /* The temporary file used if we're not using popen, so we can delete it
130 static char *cpp_temp_file;
132 /* Input stream is either a file or a pipe. */
134 static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
136 /* As we read the rc file, we attach information to this structure. */
138 static rc_res_directory *resources;
140 /* The number of cursor resources we have written out. */
144 /* The number of font resources we have written out. */
148 /* Font directory information. */
150 rc_fontdir *fontdirs;
152 /* Resource info to use for fontdirs. */
154 rc_res_res_info fontdirs_resinfo;
156 /* The number of icon resources we have written out. */
160 /* The windres target bfd . */
162 static windres_bfd wrtarget =
164 (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
167 /* Local functions for rcdata based resource definitions. */
169 static void define_font_rcdata (rc_res_id, const rc_res_res_info *,
171 static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
173 static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
175 static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
177 static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
179 static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
181 static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
182 static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
184 static int run_cmd (char *, const char *);
185 static FILE *open_input_stream (char *);
186 static FILE *look_for_default
187 (char *, const char *, int, const char *, const char *);
188 static void close_input_stream (void);
189 static void unexpected_eof (const char *);
190 static int get_word (FILE *, const char *);
191 static unsigned long get_long (FILE *, const char *);
192 static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
193 static void define_fontdirs (void);
195 /* Run `cmd' and redirect the output to `redir'. */
198 run_cmd (char *cmd, const char *redir)
201 int pid, wait_status, retcode;
204 char *errmsg_fmt, *errmsg_arg;
205 char *temp_base = choose_temp_base ();
208 int redir_handle = -1;
209 int stdout_save = -1;
211 /* Count the args. */
214 for (s = cmd; *s; s++)
219 argv = alloca (sizeof (char *) * (i + 3));
225 while (*s == ' ' && *s != 0)
231 in_quote = (*s == '\'' || *s == '"');
232 sep = (in_quote) ? *s++ : ' ';
235 while (*s != sep && *s != 0)
248 /* Setup the redirection. We can't use the usual fork/exec and redirect
249 since we may be running on non-POSIX Windows host. */
254 /* Open temporary output file. */
255 redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
256 if (redir_handle == -1)
257 fatal (_("can't open temporary file `%s': %s"), redir,
260 /* Duplicate the stdout file handle so it can be restored later. */
261 stdout_save = dup (STDOUT_FILENO);
262 if (stdout_save == -1)
263 fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
265 /* Redirect stdout to our output file. */
266 dup2 (redir_handle, STDOUT_FILENO);
268 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
269 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
271 /* Restore stdout to its previous setting. */
272 dup2 (stdout_save, STDOUT_FILENO);
274 /* Close response file. */
275 close (redir_handle);
279 fatal ("%s %s: %s", errmsg_fmt, errmsg_arg, strerror (errno));
284 pid = pwait (pid, &wait_status, 0);
288 fatal (_("wait: %s"), strerror (errno));
291 else if (WIFSIGNALED (wait_status))
293 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
296 else if (WIFEXITED (wait_status))
298 if (WEXITSTATUS (wait_status) != 0)
300 fatal (_("%s exited with status %d"), cmd,
301 WEXITSTATUS (wait_status));
312 open_input_stream (char *cmd)
314 if (istream_type == ISTREAM_FILE)
318 fileprefix = choose_temp_base ();
319 cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
320 sprintf (cpp_temp_file, "%s.irc", fileprefix);
323 if (run_cmd (cmd, cpp_temp_file))
324 fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
326 cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
327 if (cpp_pipe == NULL)
328 fatal (_("can't open temporary file `%s': %s"),
329 cpp_temp_file, strerror (errno));
333 _("Using temporary file `%s' to read preprocessor output\n"),
338 cpp_pipe = popen (cmd, FOPEN_RT);
339 if (cpp_pipe == NULL)
340 fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
342 fprintf (stderr, _("Using popen to read preprocessor output\n"));
345 xatexit (close_input_stream);
349 /* Determine if FILENAME contains special characters that
350 can cause problems unless the entire filename is quoted. */
353 filename_need_quotes (const char *filename)
355 if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
358 while (*filename != 0)
375 /* Look for the preprocessor program. */
378 look_for_default (char *cmd, const char *prefix, int end_prefix,
379 const char *preprocargs, const char *filename)
384 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
386 strcpy (cmd, prefix);
388 sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
389 space = strchr (cmd + end_prefix, ' ');
394 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
395 strchr (cmd, '\\') ||
399 found = (stat (cmd, &s) == 0
400 #ifdef HAVE_EXECUTABLE_SUFFIX
401 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
408 fprintf (stderr, _("Tried `%s'\n"), cmd);
413 strcpy (cmd, prefix);
415 sprintf (cmd + end_prefix, "%s %s %s%s%s",
416 DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
419 fprintf (stderr, _("Using `%s'\n"), cmd);
421 cpp_pipe = open_input_stream (cmd);
425 /* Read an rc file. */
428 read_rc_file (const char *filename, const char *preprocessor,
429 const char *preprocargs, int language, int use_temp_file)
432 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
434 if (filename == NULL)
436 /* Setup the default resource import path taken from input file. */
437 else if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL)
441 if (filename[0] == '/'
442 || filename[0] == '\\'
443 || filename[1] == ':')
445 edit = dir = xstrdup (filename);
449 edit = dir = xmalloc (strlen (filename) + 3);
450 sprintf (dir, "./%s", filename);
453 /* Walk dir backwards stopping at the first directory separator. */
454 edit += strlen (dir);
455 while (edit > dir && (edit[-1] != '\\' && edit[-1] != '/'))
461 /* Cut off trailing slash. */
465 /* Convert all back slashes to forward slashes. */
466 while ((edit = strchr (dir, '\\')) != NULL)
469 windres_add_include_dir (dir);
472 istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
474 if (preprocargs == NULL)
479 cmd = xmalloc (strlen (preprocessor)
480 + strlen (preprocargs)
482 + strlen (fnquotes) * 2
484 sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
485 fnquotes, filename, fnquotes);
487 cpp_pipe = open_input_stream (cmd);
491 char *dash, *slash, *cp;
493 preprocessor = DEFAULT_PREPROCESSOR;
495 cmd = xmalloc (strlen (program_name)
496 + strlen (preprocessor)
497 + strlen (preprocargs)
499 + strlen (fnquotes) * 2
500 #ifdef HAVE_EXECUTABLE_SUFFIX
501 + strlen (EXECUTABLE_SUFFIX)
507 for (cp = program_name; *cp; cp++)
512 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
513 *cp == ':' || *cp == '\\' ||
526 /* First, try looking for a prefixed gcc in the windres
527 directory, with the same prefix as windres */
529 cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
530 preprocargs, filename);
533 if (slash && ! cpp_pipe)
535 /* Next, try looking for a gcc in the same directory as
538 cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
539 preprocargs, filename);
544 /* Sigh, try the default */
546 cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
553 rc_filename = xstrdup (filename);
556 rcparse_set_language (language);
558 rcparse_discard_strings ();
560 close_input_stream ();
562 if (fontdirs != NULL)
571 /* Close the input stream if it is open. */
574 close_input_stream (void)
576 if (istream_type == ISTREAM_FILE)
578 if (cpp_pipe != NULL)
581 if (cpp_temp_file != NULL)
583 int errno_save = errno;
585 unlink (cpp_temp_file);
587 free (cpp_temp_file);
592 if (cpp_pipe != NULL)
595 err = pclose (cpp_pipe);
596 /* We are reading from a pipe, therefore we don't
597 know if cpp failed or succeeded until pclose. */
598 if (err != 0 || errno == ECHILD)
600 /* Since this is also run via xatexit, safeguard. */
602 cpp_temp_file = NULL;
603 fatal (_("preprocessing failed."));
608 /* Since this is also run via xatexit, safeguard. */
610 cpp_temp_file = NULL;
613 /* Report an error while reading an rc file. */
616 yyerror (const char *msg)
618 fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
621 /* Issue a warning while reading an rc file. */
624 rcparse_warning (const char *msg)
626 fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
629 /* Die if we get an unexpected end of file. */
632 unexpected_eof (const char *msg)
634 fatal (_("%s: unexpected EOF"), msg);
637 /* Read a 16 bit word from a file. The data is assumed to be little
641 get_word (FILE *e, const char *msg)
648 unexpected_eof (msg);
649 return ((b2 & 0xff) << 8) | (b1 & 0xff);
652 /* Read a 32 bit word from a file. The data is assumed to be little
656 get_long (FILE *e, const char *msg)
665 unexpected_eof (msg);
666 return (((((((b4 & 0xff) << 8)
672 /* Read data from a file. This is a wrapper to do error checking. */
675 get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
677 rc_uint_type got; // $$$d
679 got = (rc_uint_type) fread (p, 1, c, e);
683 fatal (_("%s: read of %lu returned %lu"),
684 msg, (unsigned long) c, (unsigned long) got);
687 /* Define an accelerator resource. */
690 define_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
691 rc_accelerator *data)
695 r = define_standard_resource (&resources, RT_ACCELERATOR, id,
696 resinfo->language, 0);
697 r->type = RES_TYPE_ACCELERATOR;
699 r->res_info = *resinfo;
702 /* Define a bitmap resource. Bitmap data is stored in a file. The
703 first 14 bytes of the file are a standard header, which is not
704 included in the resource data. */
706 #define BITMAP_SKIP (14)
709 define_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
710 const char *filename)
719 e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
721 if (stat (real_filename, &s) < 0)
722 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
725 data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
727 for (i = 0; i < BITMAP_SKIP; i++)
730 get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
733 free (real_filename);
735 r = define_standard_resource (&resources, RT_BITMAP, id,
736 resinfo->language, 0);
738 r->type = RES_TYPE_BITMAP;
739 r->u.data.length = s.st_size - BITMAP_SKIP;
740 r->u.data.data = data;
741 r->res_info = *resinfo;
744 /* Define a cursor resource. A cursor file may contain a set of
745 bitmaps, each representing the same cursor at various different
746 resolutions. They each get written out with a different ID. The
747 real cursor resource is then a group resource which can be used to
748 select one of the actual cursors. */
751 define_cursor (rc_res_id id, const rc_res_res_info *resinfo,
752 const char *filename)
757 struct icondir *icondirs;
760 rc_group_cursor *first, **pp;
762 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
764 /* A cursor file is basically an icon file. The start of the file
765 is a three word structure. The first word is ignored. The
766 second word is the type of data. The third word is the number of
769 get_word (e, real_filename);
770 type = get_word (e, real_filename);
771 count = get_word (e, real_filename);
773 fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
775 /* Read in the icon directory entries. */
777 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
779 for (i = 0; i < count; i++)
781 icondirs[i].width = getc (e);
782 icondirs[i].height = getc (e);
783 icondirs[i].colorcount = getc (e);
785 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
786 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
787 icondirs[i].bytes = get_long (e, real_filename);
788 icondirs[i].offset = get_long (e, real_filename);
791 unexpected_eof (real_filename);
794 /* Define each cursor as a unique resource. */
796 first_cursor = cursors;
798 for (i = 0; i < count; i++)
804 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
805 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
806 icondirs[i].offset, strerror (errno));
808 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
810 get_data (e, data, icondirs[i].bytes, real_filename);
812 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
813 c->xhotspot = icondirs[i].u.cursor.xhotspot;
814 c->yhotspot = icondirs[i].u.cursor.yhotspot;
815 c->length = icondirs[i].bytes;
823 r = define_standard_resource (&resources, RT_CURSOR, name,
824 resinfo->language, 0);
825 r->type = RES_TYPE_CURSOR;
827 r->res_info = *resinfo;
831 free (real_filename);
833 /* Define a cursor group resource. */
837 for (i = 0; i < count; i++)
841 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
843 cg->width = icondirs[i].width;
844 cg->height = 2 * icondirs[i].height;
846 /* FIXME: What should these be set to? */
850 cg->bytes = icondirs[i].bytes + 4;
851 cg->index = first_cursor + i + 1;
859 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
860 resinfo->language, 0);
861 r->type = RES_TYPE_GROUP_CURSOR;
862 r->u.group_cursor = first;
863 r->res_info = *resinfo;
866 /* Define a dialog resource. */
869 define_dialog (rc_res_id id, const rc_res_res_info *resinfo,
870 const rc_dialog *dialog)
875 copy = (rc_dialog *) res_alloc (sizeof *copy);
878 r = define_standard_resource (&resources, RT_DIALOG, id,
879 resinfo->language, 0);
880 r->type = RES_TYPE_DIALOG;
882 r->res_info = *resinfo;
885 /* Define a dialog control. This does not define a resource, but
886 merely allocates and fills in a structure. */
889 define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
890 rc_uint_type y, rc_uint_type width, rc_uint_type height,
891 const rc_res_id class, rc_uint_type style,
892 rc_uint_type exstyle)
894 rc_dialog_control *n;
896 n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
900 n->exstyle = exstyle;
914 define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
915 rc_uint_type y, rc_uint_type style,
916 rc_uint_type exstyle, rc_uint_type help,
917 rc_rcdata_item *data, rc_dialog_ex *ex)
919 rc_dialog_control *n;
924 style = SS_ICON | WS_CHILD | WS_VISIBLE;
925 res_string_to_id (&tid, "");
927 cid.u.id = CTL_STATIC;
928 n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
931 rcparse_warning (_("help ID requires DIALOGEX"));
933 rcparse_warning (_("control data requires DIALOGEX"));
940 /* Define a font resource. */
943 define_font (rc_res_id id, const rc_res_res_info *resinfo,
944 const char *filename)
955 const char *device, *face;
958 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
960 if (stat (real_filename, &s) < 0)
961 fatal (_("stat failed on font file `%s': %s"), real_filename,
964 data = (bfd_byte *) res_alloc (s.st_size);
966 get_data (e, data, s.st_size, real_filename);
969 free (real_filename);
971 r = define_standard_resource (&resources, RT_FONT, id,
972 resinfo->language, 0);
974 r->type = RES_TYPE_FONT;
975 r->u.data.length = s.st_size;
976 r->u.data.data = data;
977 r->res_info = *resinfo;
979 /* For each font resource, we must add an entry in the FONTDIR
980 resource. The FONTDIR resource includes some strings in the font
981 file. To find them, we have to do some magic on the data we have
984 offset = ((((((data[47] << 8)
988 if (offset > 0 && offset < s.st_size)
989 device = (char *) data + offset;
993 offset = ((((((data[51] << 8)
997 if (offset > 0 && offset < s.st_size)
998 face = (char *) data + offset;
1004 fontdatalength = 58 + strlen (device) + strlen (face);
1005 fontdata = (bfd_byte *) res_alloc (fontdatalength);
1006 memcpy (fontdata, data, 56);
1007 strcpy ((char *) fontdata + 56, device);
1008 strcpy ((char *) fontdata + 57 + strlen (device), face);
1010 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1013 fd->length = fontdatalength;
1014 fd->data = fontdata;
1016 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
1020 /* For the single fontdirs resource, we always use the resource
1021 information of the last font. I don't know what else to do. */
1022 fontdirs_resinfo = *resinfo;
1026 define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1027 rc_rcdata_item *data)
1030 rc_uint_type len_data;
1033 r = define_standard_resource (&resources, RT_FONT, id,
1034 resinfo->language, 0);
1036 pb_data = rcdata_render_as_buffer (data, &len_data);
1038 r->type = RES_TYPE_FONT;
1039 r->u.data.length = len_data;
1040 r->u.data.data = pb_data;
1041 r->res_info = *resinfo;
1044 /* Define the fontdirs resource. This is called after the entire rc
1045 file has been parsed, if any font resources were seen. */
1048 define_fontdirs (void)
1056 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1058 r->type = RES_TYPE_FONTDIR;
1059 r->u.fontdir = fontdirs;
1060 r->res_info = fontdirs_resinfo;
1064 rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
1066 const rc_rcdata_item *d;
1067 bfd_byte *ret = NULL, *pret;
1068 rc_uint_type len = 0;
1070 for (d = data; d != NULL; d = d->next)
1071 len += rcdata_copy (d, NULL);
1074 ret = pret = (bfd_byte *) res_alloc (len);
1075 for (d = data; d != NULL; d = d->next)
1076 pret += rcdata_copy (d, pret);
1084 define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1085 rc_rcdata_item *data)
1088 rc_fontdir *fd, *fd_first, *fd_cur;
1089 rc_uint_type len_data;
1093 fd_cur = fd_first = NULL;
1094 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1096 pb_data = rcdata_render_as_buffer (data, &len_data);
1100 rc_uint_type off = 2;
1101 c = windres_get_16 (&wrtarget, pb_data, len_data);
1105 rc_uint_type safe_pos = off;
1106 const struct bin_fontdir_item *bfi;
1108 bfi = (const struct bin_fontdir_item *) pb_data + off;
1109 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1110 fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
1111 fd->data = pb_data + off;
1113 len = strlen ((char *) bfi->device_name) + 1;
1114 off += (rc_uint_type) len;
1115 off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
1116 fd->length = (off - safe_pos);
1118 if (fd_first == NULL)
1125 r->type = RES_TYPE_FONTDIR;
1126 r->u.fontdir = fd_first;
1127 r->res_info = *resinfo;
1130 static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1131 rc_rcdata_item *data)
1134 rc_uint_type len_data;
1137 r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
1139 pb_data = rcdata_render_as_buffer (data, &len_data);
1140 r->type = RES_TYPE_MESSAGETABLE;
1141 r->u.data.length = len_data;
1142 r->u.data.data = pb_data;
1143 r->res_info = *resinfo;
1146 /* Define an icon resource. An icon file may contain a set of
1147 bitmaps, each representing the same icon at various different
1148 resolutions. They each get written out with a different ID. The
1149 real icon resource is then a group resource which can be used to
1150 select one of the actual icon bitmaps. */
1153 define_icon (rc_res_id id, const rc_res_res_info *resinfo,
1154 const char *filename)
1157 char *real_filename;
1159 struct icondir *icondirs;
1162 rc_group_icon *first, **pp;
1164 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1166 /* The start of an icon file is a three word structure. The first
1167 word is ignored. The second word is the type of data. The third
1168 word is the number of entries. */
1170 get_word (e, real_filename);
1171 type = get_word (e, real_filename);
1172 count = get_word (e, real_filename);
1174 fatal (_("icon file `%s' does not contain icon data"), real_filename);
1176 /* Read in the icon directory entries. */
1178 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1180 for (i = 0; i < count; i++)
1182 icondirs[i].width = getc (e);
1183 icondirs[i].height = getc (e);
1184 icondirs[i].colorcount = getc (e);
1186 icondirs[i].u.icon.planes = get_word (e, real_filename);
1187 icondirs[i].u.icon.bits = get_word (e, real_filename);
1188 icondirs[i].bytes = get_long (e, real_filename);
1189 icondirs[i].offset = get_long (e, real_filename);
1192 unexpected_eof (real_filename);
1195 /* Define each icon as a unique resource. */
1199 for (i = 0; i < count; i++)
1204 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1205 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1206 icondirs[i].offset, strerror (errno));
1208 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
1210 get_data (e, data, icondirs[i].bytes, real_filename);
1217 r = define_standard_resource (&resources, RT_ICON, name,
1218 resinfo->language, 0);
1219 r->type = RES_TYPE_ICON;
1220 r->u.data.length = icondirs[i].bytes;
1221 r->u.data.data = data;
1222 r->res_info = *resinfo;
1226 free (real_filename);
1228 /* Define an icon group resource. */
1232 for (i = 0; i < count; i++)
1236 /* For some reason, at least in some files the planes and bits
1237 are zero. We instead set them from the color. This is
1240 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1242 cg->width = icondirs[i].width;
1243 cg->height = icondirs[i].height;
1244 cg->colors = icondirs[i].colorcount;
1246 if (icondirs[i].u.icon.planes)
1247 cg->planes = icondirs[i].u.icon.planes;
1251 if (icondirs[i].u.icon.bits)
1252 cg->bits = icondirs[i].u.icon.bits;
1257 while ((1L << cg->bits) < cg->colors)
1261 cg->bytes = icondirs[i].bytes;
1262 cg->index = first_icon + i + 1;
1270 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1271 resinfo->language, 0);
1272 r->type = RES_TYPE_GROUP_ICON;
1273 r->u.group_icon = first;
1274 r->res_info = *resinfo;
1278 define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1279 rc_rcdata_item *data)
1282 rc_group_icon *cg, *first, *cur;
1283 rc_uint_type len_data;
1286 pb_data = rcdata_render_as_buffer (data, &len_data);
1291 while (len_data >= 6)
1294 unsigned short type;
1295 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1297 fatal (_("unexpected group icon type %d"), type);
1298 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1302 for (i = 0; i < c; i++)
1305 fatal ("too small group icon rcdata");
1306 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1308 cg->width = pb_data[0];
1309 cg->height = pb_data[1];
1310 cg->colors = pb_data[2];
1311 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1312 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1313 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1314 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1324 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1325 resinfo->language, 0);
1326 r->type = RES_TYPE_GROUP_ICON;
1327 r->u.group_icon = first;
1328 r->res_info = *resinfo;
1332 define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1333 rc_rcdata_item *data)
1336 rc_group_cursor *cg, *first, *cur;
1337 rc_uint_type len_data;
1340 pb_data = rcdata_render_as_buffer (data, &len_data);
1344 while (len_data >= 6)
1347 unsigned short type;
1348 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1350 fatal (_("unexpected group cursor type %d"), type);
1351 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1355 for (i = 0; i < c; i++)
1358 fatal ("too small group icon rcdata");
1359 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
1361 cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
1362 cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1363 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1364 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1365 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1366 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1377 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1378 resinfo->language, 0);
1379 r->type = RES_TYPE_GROUP_CURSOR;
1380 r->u.group_cursor = first;
1381 r->res_info = *resinfo;
1385 define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1386 rc_rcdata_item *data)
1390 rc_uint_type len_data;
1393 pb_data = rcdata_render_as_buffer (data, &len_data);
1395 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
1396 c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
1397 c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1398 c->length = len_data - BIN_CURSOR_SIZE;
1399 c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
1401 r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
1402 r->type = RES_TYPE_CURSOR;
1404 r->res_info = *resinfo;
1408 define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1409 rc_rcdata_item *data)
1412 rc_uint_type len_data;
1415 pb_data = rcdata_render_as_buffer (data, &len_data);
1417 r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
1418 r->type = RES_TYPE_BITMAP;
1419 r->u.data.length = len_data;
1420 r->u.data.data = pb_data;
1421 r->res_info = *resinfo;
1425 define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1426 rc_rcdata_item *data)
1429 rc_uint_type len_data;
1432 pb_data = rcdata_render_as_buffer (data, &len_data);
1434 r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
1435 r->type = RES_TYPE_ICON;
1436 r->u.data.length = len_data;
1437 r->u.data.data = pb_data;
1438 r->res_info = *resinfo;
1441 /* Define a menu resource. */
1444 define_menu (rc_res_id id, const rc_res_res_info *resinfo,
1445 rc_menuitem *menuitems)
1450 m = (rc_menu *) res_alloc (sizeof (rc_menu));
1451 m->items = menuitems;
1454 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1455 r->type = RES_TYPE_MENU;
1457 r->res_info = *resinfo;
1460 /* Define a menu item. This does not define a resource, but merely
1461 allocates and fills in a structure. */
1464 define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
1465 rc_uint_type state, rc_uint_type help,
1466 rc_menuitem *menuitems)
1470 mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
1475 mi->text = unichar_dup (text);
1477 mi->popup = menuitems;
1481 /* Define a messagetable resource. */
1484 define_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
1485 const char *filename)
1488 char *real_filename;
1493 e = open_file_search (filename, FOPEN_RB, "messagetable file",
1496 if (stat (real_filename, &s) < 0)
1497 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1500 data = (bfd_byte *) res_alloc (s.st_size);
1502 get_data (e, data, s.st_size, real_filename);
1505 free (real_filename);
1507 r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1508 resinfo->language, 0);
1510 r->type = RES_TYPE_MESSAGETABLE;
1511 r->u.data.length = s.st_size;
1512 r->u.data.data = data;
1513 r->res_info = *resinfo;
1516 /* Define an rcdata resource. */
1519 define_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1520 rc_rcdata_item *data)
1524 r = define_standard_resource (&resources, RT_RCDATA, id,
1525 resinfo->language, 0);
1526 r->type = RES_TYPE_RCDATA;
1528 r->res_info = *resinfo;
1531 /* Create an rcdata item holding a string. */
1534 define_rcdata_string (const char *string, rc_uint_type len)
1539 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1541 ri->type = RCDATA_STRING;
1542 ri->u.string.length = len;
1543 s = (char *) res_alloc (len);
1544 memcpy (s, string, len);
1550 /* Create an rcdata item holding a unicode string. */
1553 define_rcdata_unistring (const unichar *string, rc_uint_type len)
1558 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1560 ri->type = RCDATA_WSTRING;
1561 ri->u.wstring.length = len;
1562 s = (unichar *) res_alloc (len * sizeof (unichar));
1563 memcpy (s, string, len * sizeof (unichar));
1564 ri->u.wstring.w = s;
1569 /* Create an rcdata item holding a number. */
1572 define_rcdata_number (rc_uint_type val, int dword)
1576 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1578 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1584 /* Define a stringtable resource. This is called for each string
1585 which appears in a STRINGTABLE statement. */
1588 define_stringtable (const rc_res_res_info *resinfo,
1589 rc_uint_type stringid, const unichar *string, int len)
1596 id.u.id = (stringid >> 4) + 1;
1597 r = define_standard_resource (&resources, RT_STRING, id,
1598 resinfo->language, 1);
1600 if (r->type == RES_TYPE_UNINITIALIZED)
1604 r->type = RES_TYPE_STRINGTABLE;
1605 r->u.stringtable = ((rc_stringtable *)
1606 res_alloc (sizeof (rc_stringtable)));
1607 for (i = 0; i < 16; i++)
1609 r->u.stringtable->strings[i].length = 0;
1610 r->u.stringtable->strings[i].string = NULL;
1613 r->res_info = *resinfo;
1615 h = (unichar *) res_alloc ((len + 1) * sizeof (unichar));
1617 memcpy (h, string, len * sizeof (unichar));
1619 r->u.stringtable->strings[stringid & 0xf].length = (rc_uint_type) len;
1620 r->u.stringtable->strings[stringid & 0xf].string = h;
1624 define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
1625 rc_toolbar_item *items)
1630 t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1631 t->button_width = width;
1632 t->button_height = height;
1635 while (items != NULL)
1638 items = items->next;
1640 r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
1641 r->type = RES_TYPE_TOOLBAR;
1643 r->res_info = *resinfo;
1646 /* Define a user data resource where the data is in the rc file. */
1649 define_user_data (rc_res_id id, rc_res_id type,
1650 const rc_res_res_info *resinfo,
1651 rc_rcdata_item *data)
1656 rc_uint_type len_data;
1658 /* We have to check if the binary data is parsed specially. */
1659 if (type.named == 0)
1664 define_fontdir_rcdata (id, resinfo, data);
1667 define_font_rcdata (id, resinfo, data);
1670 define_icon_rcdata (id, resinfo, data);
1673 define_bitmap_rcdata (id, resinfo, data);
1676 define_cursor_rcdata (id, resinfo, data);
1679 define_group_icon_rcdata (id, resinfo, data);
1681 case RT_GROUP_CURSOR:
1682 define_group_cursor_rcdata (id, resinfo, data);
1684 case RT_MESSAGETABLE:
1685 define_messagetable_rcdata (id, resinfo, data);
1688 /* Treat as normal user-data. */
1695 ids[2].u.id = resinfo->language;
1697 r = define_resource (& resources, 3, ids, 0);
1698 r->type = RES_TYPE_USERDATA;
1699 r->u.userdata = ((rc_rcdata_item *)
1700 res_alloc (sizeof (rc_rcdata_item)));
1701 r->u.userdata->next = NULL;
1702 r->u.userdata->type = RCDATA_BUFFER;
1703 pb_data = rcdata_render_as_buffer (data, &len_data);
1704 r->u.userdata->u.buffer.length = len_data;
1705 r->u.userdata->u.buffer.data = pb_data;
1706 r->res_info = *resinfo;
1710 define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
1711 const char *filename)
1715 char *real_filename;
1719 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1722 if (stat (real_filename, &s) < 0)
1723 fatal (_("stat failed on file `%s': %s"), real_filename,
1726 data = (bfd_byte *) res_alloc (s.st_size);
1728 get_data (e, data, s.st_size, real_filename);
1731 free (real_filename);
1733 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1735 ri->type = RCDATA_BUFFER;
1736 ri->u.buffer.length = s.st_size;
1737 ri->u.buffer.data = data;
1739 define_rcdata (id, resinfo, ri);
1742 /* Define a user data resource where the data is in a file. */
1745 define_user_file (rc_res_id id, rc_res_id type,
1746 const rc_res_res_info *resinfo, const char *filename)
1749 char *real_filename;
1755 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1757 if (stat (real_filename, &s) < 0)
1758 fatal (_("stat failed on file `%s': %s"), real_filename,
1761 data = (bfd_byte *) res_alloc (s.st_size);
1763 get_data (e, data, s.st_size, real_filename);
1766 free (real_filename);
1771 ids[2].u.id = resinfo->language;
1773 r = define_resource (&resources, 3, ids, 0);
1774 r->type = RES_TYPE_USERDATA;
1775 r->u.userdata = ((rc_rcdata_item *)
1776 res_alloc (sizeof (rc_rcdata_item)));
1777 r->u.userdata->next = NULL;
1778 r->u.userdata->type = RCDATA_BUFFER;
1779 r->u.userdata->u.buffer.length = s.st_size;
1780 r->u.userdata->u.buffer.data = data;
1781 r->res_info = *resinfo;
1784 /* Define a versioninfo resource. */
1787 define_versioninfo (rc_res_id id, rc_uint_type language,
1788 rc_fixed_versioninfo *fixedverinfo,
1789 rc_ver_info *verinfo)
1793 r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1794 r->type = RES_TYPE_VERSIONINFO;
1795 r->u.versioninfo = ((rc_versioninfo *)
1796 res_alloc (sizeof (rc_versioninfo)));
1797 r->u.versioninfo->fixed = fixedverinfo;
1798 r->u.versioninfo->var = verinfo;
1799 r->res_info.language = language;
1802 /* Add string version info to a list of version information. */
1805 append_ver_stringfileinfo (rc_ver_info *verinfo,
1806 rc_ver_stringtable *stringtables)
1808 rc_ver_info *vi, **pp;
1810 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1812 vi->type = VERINFO_STRING;
1813 vi->u.string.stringtables = stringtables;
1815 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1822 rc_ver_stringtable *
1823 append_ver_stringtable (rc_ver_stringtable *stringtable,
1824 const char *language,
1825 rc_ver_stringinfo *strings)
1827 rc_ver_stringtable *vst, **pp;
1829 vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1831 unicode_from_ascii ((rc_uint_type *) NULL, &vst->language, language);
1832 vst->strings = strings;
1834 for (pp = &stringtable; *pp != NULL; pp = &(*pp)->next)
1841 /* Add variable version info to a list of version information. */
1844 append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
1845 rc_ver_varinfo *var)
1847 rc_ver_info *vi, **pp;
1849 vi = (rc_ver_info *) res_alloc (sizeof *vi);
1851 vi->type = VERINFO_VAR;
1852 vi->u.var.key = unichar_dup (key);
1853 vi->u.var.var = var;
1855 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1862 /* Append version string information to a list. */
1865 append_verval (rc_ver_stringinfo *strings, const unichar *key,
1866 const unichar *value)
1868 rc_ver_stringinfo *vs, **pp;
1870 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1872 vs->key = unichar_dup (key);
1873 vs->value = unichar_dup (value);
1875 for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1882 /* Append version variable information to a list. */
1885 append_vertrans (rc_ver_varinfo *var, rc_uint_type language,
1886 rc_uint_type charset)
1888 rc_ver_varinfo *vv, **pp;
1890 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1892 vv->language = language;
1893 vv->charset = charset;
1895 for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1902 /* Local functions used to write out an rc file. */
1904 static void indent (FILE *, int);
1905 static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
1906 const rc_res_id *, rc_uint_type *, int);
1907 static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
1908 const rc_res_id *, rc_uint_type *, int);
1909 static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
1910 const rc_res_resource *, rc_uint_type *);
1911 static void write_rc_accelerators (FILE *, const rc_accelerator *);
1912 static void write_rc_cursor (FILE *, const rc_cursor *);
1913 static void write_rc_group_cursor (FILE *, const rc_group_cursor *);
1914 static void write_rc_dialog (FILE *, const rc_dialog *);
1915 static void write_rc_dialog_control (FILE *, const rc_dialog_control *);
1916 static void write_rc_fontdir (FILE *, const rc_fontdir *);
1917 static void write_rc_group_icon (FILE *, const rc_group_icon *);
1918 static void write_rc_menu (FILE *, const rc_menu *, int);
1919 static void write_rc_toolbar (FILE *, const rc_toolbar *);
1920 static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
1921 static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
1923 static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
1924 static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
1925 static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
1926 static void write_rc_versioninfo (FILE *, const rc_versioninfo *);
1928 /* Indent a given number of spaces. */
1931 indent (FILE *e, int c)
1935 for (i = 0; i < c; i++)
1939 /* Dump the resources we have read in the format of an rc file.
1941 Reasoned by the fact, that some resources need to be stored into file and
1942 refer to that file, we use the user-data model for that to express it binary
1943 without the need to store it somewhere externally. */
1946 write_rc_file (const char *filename, const rc_res_directory *res_dir)
1949 rc_uint_type language;
1951 if (filename == NULL)
1955 e = fopen (filename, FOPEN_WT);
1957 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1960 language = (rc_uint_type) ((bfd_signed_vma) -1);
1961 write_rc_directory (e, res_dir, (const rc_res_id *) NULL,
1962 (const rc_res_id *) NULL, &language, 1);
1965 /* Write out a directory. E is the file to write to. RD is the
1966 directory. TYPE is a pointer to the level 1 ID which serves as the
1967 resource type. NAME is a pointer to the level 2 ID which serves as
1968 an individual resource name. LANGUAGE is a pointer to the current
1969 language. LEVEL is the level in the tree. */
1972 write_rc_directory (FILE *e, const rc_res_directory *rd,
1973 const rc_res_id *type, const rc_res_id *name,
1974 rc_uint_type *language, int level)
1976 const rc_res_entry *re;
1978 /* Print out some COFF information that rc files can't represent. */
1979 if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
1981 wr_printcomment (e, "COFF information not part of RC");
1983 wr_printcomment (e, "Time stamp: %u", rd->time);
1984 if (rd->characteristics != 0)
1985 wr_printcomment (e, "Characteristics: %u", rd->characteristics);
1986 if (rd->major != 0 || rd->minor != 0)
1987 wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
1990 for (re = rd->entries; re != NULL; re = re->next)
1995 /* If we're at level 1, the key of this resource is the
1996 type. This normally duplicates the information we have
1997 stored with the resource itself, but we need to remember
1998 the type if this is a user define resource type. */
2003 /* If we're at level 2, the key of this resource is the name
2004 we are going to use in the rc printout. */
2009 /* If we're at level 3, then this key represents a language.
2010 Use it to update the current language. */
2012 && re->id.u.id != (unsigned long) (unsigned int) *language
2013 && (re->id.u.id & 0xffff) == re->id.u.id)
2015 wr_print (e, "LANGUAGE %u, %u\n",
2016 re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
2017 (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
2018 *language = re->id.u.id;
2027 write_rc_subdir (e, re, type, name, language, level);
2032 /* This is the normal case: the three levels are
2033 TYPE/NAME/LANGUAGE. NAME will have been set at level
2034 2, and represents the name to use. We probably just
2035 set LANGUAGE, and it will probably match what the
2036 resource itself records if anything. */
2037 write_rc_resource (e, type, name, re->u.res, language);
2041 wr_printcomment (e, "Resource at unexpected level %d", level);
2042 write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
2047 if (rd->entries == NULL)
2053 /* Write out a subdirectory entry. E is the file to write to. RE is
2054 the subdirectory entry. TYPE and NAME are pointers to higher level
2055 IDs, or NULL. LANGUAGE is a pointer to the current language.
2056 LEVEL is the level in the tree. */
2059 write_rc_subdir (FILE *e, const rc_res_entry *re,
2060 const rc_res_id *type, const rc_res_id *name,
2061 rc_uint_type *language, int level)
2067 wr_printcomment (e, "Type: ");
2069 res_id_print (e, re->id, 1);
2074 switch (re->id.u.id)
2076 case RT_CURSOR: s = "cursor"; break;
2077 case RT_BITMAP: s = "bitmap"; break;
2078 case RT_ICON: s = "icon"; break;
2079 case RT_MENU: s = "menu"; break;
2080 case RT_DIALOG: s = "dialog"; break;
2081 case RT_STRING: s = "stringtable"; break;
2082 case RT_FONTDIR: s = "fontdir"; break;
2083 case RT_FONT: s = "font"; break;
2084 case RT_ACCELERATOR: s = "accelerators"; break;
2085 case RT_RCDATA: s = "rcdata"; break;
2086 case RT_MESSAGETABLE: s = "messagetable"; break;
2087 case RT_GROUP_CURSOR: s = "group cursor"; break;
2088 case RT_GROUP_ICON: s = "group icon"; break;
2089 case RT_VERSION: s = "version"; break;
2090 case RT_DLGINCLUDE: s = "dlginclude"; break;
2091 case RT_PLUGPLAY: s = "plugplay"; break;
2092 case RT_VXD: s = "vxd"; break;
2093 case RT_ANICURSOR: s = "anicursor"; break;
2094 case RT_ANIICON: s = "aniicon"; break;
2095 case RT_TOOLBAR: s = "toolbar"; break;
2096 case RT_HTML: s = "html"; break;
2097 default: s = NULL; break;
2101 fprintf (e, "%s", s);
2103 res_id_print (e, re->id, 1);
2108 wr_printcomment (e, "Name: ");
2109 res_id_print (e, re->id, 1);
2113 wr_printcomment (e, "Language: ");
2114 res_id_print (e, re->id, 1);
2118 wr_printcomment (e, "Level %d: ", level);
2119 res_id_print (e, re->id, 1);
2122 write_rc_directory (e, re->u.dir, type, name, language, level + 1);
2125 /* Write out a single resource. E is the file to write to. TYPE is a
2126 pointer to the type of the resource. NAME is a pointer to the name
2127 of the resource; it will be NULL if there is a level mismatch. RES
2128 is the resource data. LANGUAGE is a pointer to the current
2132 write_rc_resource (FILE *e, const rc_res_id *type,
2133 const rc_res_id *name, const rc_res_resource *res,
2134 rc_uint_type *language)
2145 case RES_TYPE_ACCELERATOR:
2147 rt = RT_ACCELERATOR;
2150 case RES_TYPE_BITMAP:
2151 s = "2 /* RT_BITMAP */";
2155 case RES_TYPE_CURSOR:
2156 s = "1 /* RT_CURSOR */";
2160 case RES_TYPE_GROUP_CURSOR:
2161 s = "12 /* RT_GROUP_CURSOR */";
2162 rt = RT_GROUP_CURSOR;
2165 case RES_TYPE_DIALOG:
2166 if (extended_dialog (res->u.dialog))
2174 s = "8 /* RT_FONT */";
2178 case RES_TYPE_FONTDIR:
2179 s = "7 /* RT_FONTDIR */";
2184 s = "3 /* RT_ICON */";
2188 case RES_TYPE_GROUP_ICON:
2189 s = "14 /* RT_GROUP_ICON */";
2194 if (extended_menu (res->u.menu))
2207 case RES_TYPE_MESSAGETABLE:
2208 s = "11 /* RT_MESSAGETABLE */";
2209 rt = RT_MESSAGETABLE;
2212 case RES_TYPE_RCDATA:
2217 case RES_TYPE_STRINGTABLE:
2222 case RES_TYPE_USERDATA:
2227 case RES_TYPE_VERSIONINFO:
2232 case RES_TYPE_TOOLBAR:
2240 && (type->named || type->u.id != (unsigned long) rt))
2242 wr_printcomment (e, "Unexpected resource type mismatch: ");
2243 res_id_print (e, *type, 1);
2244 fprintf (e, " != %d", rt);
2247 if (res->coff_info.codepage != 0)
2248 wr_printcomment (e, "Code page: %u", res->coff_info.codepage);
2249 if (res->coff_info.reserved != 0)
2250 wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved);
2253 if (rt == RT_STRING)
2258 res_id_print (e, *name, 1);
2260 fprintf (e, "??Unknown-Name??");
2265 fprintf (e, "%s", s);
2266 else if (type != NULL)
2268 if (type->named == 0)
2270 #define PRINT_RT_NAME(NAME) case NAME: \
2271 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2277 res_id_print (e, *type, 0);
2280 PRINT_RT_NAME(RT_MANIFEST);
2281 PRINT_RT_NAME(RT_ANICURSOR);
2282 PRINT_RT_NAME(RT_ANIICON);
2283 PRINT_RT_NAME(RT_RCDATA);
2284 PRINT_RT_NAME(RT_ICON);
2285 PRINT_RT_NAME(RT_CURSOR);
2286 PRINT_RT_NAME(RT_BITMAP);
2287 PRINT_RT_NAME(RT_PLUGPLAY);
2288 PRINT_RT_NAME(RT_VXD);
2289 PRINT_RT_NAME(RT_FONT);
2290 PRINT_RT_NAME(RT_FONTDIR);
2291 PRINT_RT_NAME(RT_HTML);
2292 PRINT_RT_NAME(RT_MESSAGETABLE);
2293 PRINT_RT_NAME(RT_DLGINCLUDE);
2294 PRINT_RT_NAME(RT_DLGINIT);
2296 #undef PRINT_RT_NAME
2299 res_id_print (e, *type, 1);
2302 fprintf (e, "??Unknown-Type??");
2304 if (res->res_info.memflags != 0)
2306 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
2307 fprintf (e, " MOVEABLE");
2308 if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
2309 fprintf (e, " PURE");
2310 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
2311 fprintf (e, " PRELOAD");
2312 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
2313 fprintf (e, " DISCARDABLE");
2316 if (res->type == RES_TYPE_DIALOG)
2318 fprintf (e, " %d, %d, %d, %d",
2319 (int) res->u.dialog->x, (int) res->u.dialog->y,
2320 (int) res->u.dialog->width, (int) res->u.dialog->height);
2321 if (res->u.dialog->ex != NULL
2322 && res->u.dialog->ex->help != 0)
2323 fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help);
2325 else if (res->type == RES_TYPE_TOOLBAR)
2327 fprintf (e, " %d, %d", (int) res->u.toolbar->button_width,
2328 (int) res->u.toolbar->button_height);
2333 if ((res->res_info.language != 0 && res->res_info.language != *language)
2334 || res->res_info.characteristics != 0
2335 || res->res_info.version != 0)
2341 case RES_TYPE_ACCELERATOR:
2342 case RES_TYPE_DIALOG:
2344 case RES_TYPE_RCDATA:
2345 case RES_TYPE_STRINGTABLE:
2354 if (res->res_info.language != 0 && res->res_info.language != *language)
2355 fprintf (e, "%sLANGUAGE %d, %d\n",
2356 modifiers ? "// " : "",
2357 (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
2358 (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
2359 if (res->res_info.characteristics != 0)
2360 fprintf (e, "%sCHARACTERISTICS %u\n",
2361 modifiers ? "// " : "",
2362 (unsigned int) res->res_info.characteristics);
2363 if (res->res_info.version != 0)
2364 fprintf (e, "%sVERSION %u\n",
2365 modifiers ? "// " : "",
2366 (unsigned int) res->res_info.version);
2374 case RES_TYPE_ACCELERATOR:
2375 write_rc_accelerators (e, res->u.acc);
2378 case RES_TYPE_CURSOR:
2379 write_rc_cursor (e, res->u.cursor);
2382 case RES_TYPE_GROUP_CURSOR:
2383 write_rc_group_cursor (e, res->u.group_cursor);
2386 case RES_TYPE_DIALOG:
2387 write_rc_dialog (e, res->u.dialog);
2390 case RES_TYPE_FONTDIR:
2391 write_rc_fontdir (e, res->u.fontdir);
2394 case RES_TYPE_GROUP_ICON:
2395 write_rc_group_icon (e, res->u.group_icon);
2399 write_rc_menu (e, res->u.menu, menuex);
2402 case RES_TYPE_RCDATA:
2403 write_rc_rcdata (e, res->u.rcdata, 0);
2406 case RES_TYPE_STRINGTABLE:
2407 write_rc_stringtable (e, name, res->u.stringtable);
2410 case RES_TYPE_USERDATA:
2411 write_rc_rcdata (e, res->u.userdata, 0);
2414 case RES_TYPE_TOOLBAR:
2415 write_rc_toolbar (e, res->u.toolbar);
2418 case RES_TYPE_VERSIONINFO:
2419 write_rc_versioninfo (e, res->u.versioninfo);
2422 case RES_TYPE_BITMAP:
2425 write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0);
2427 case RES_TYPE_MESSAGETABLE:
2428 write_rc_messagetable (e, res->u.data.length, res->u.data.data);
2433 /* Write out accelerator information. */
2436 write_rc_accelerators (FILE *e, const rc_accelerator *accelerators)
2438 const rc_accelerator *acc;
2440 fprintf (e, "BEGIN\n");
2441 for (acc = accelerators; acc != NULL; acc = acc->next)
2447 if ((acc->key & 0x7f) == acc->key
2448 && ISPRINT (acc->key)
2449 && (acc->flags & ACC_VIRTKEY) == 0)
2451 fprintf (e, "\"%c\"", (char) acc->key);
2456 fprintf (e, "%d", (int) acc->key);
2460 fprintf (e, ", %d", (int) acc->id);
2464 if ((acc->flags & ACC_VIRTKEY) != 0)
2465 fprintf (e, ", VIRTKEY");
2467 fprintf (e, ", ASCII");
2470 if ((acc->flags & ACC_SHIFT) != 0)
2471 fprintf (e, ", SHIFT");
2472 if ((acc->flags & ACC_CONTROL) != 0)
2473 fprintf (e, ", CONTROL");
2474 if ((acc->flags & ACC_ALT) != 0)
2475 fprintf (e, ", ALT");
2480 fprintf (e, "END\n");
2483 /* Write out cursor information. This would normally be in a separate
2484 file, which the rc file would include. */
2487 write_rc_cursor (FILE *e, const rc_cursor *cursor)
2489 fprintf (e, "BEGIN\n");
2491 fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2492 (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot,
2493 (int) cursor->xhotspot, (int) cursor->yhotspot);
2494 write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data,
2496 fprintf (e, "END\n");
2499 /* Write out group cursor data. This would normally be built from the
2503 write_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor)
2505 const rc_group_cursor *gc;
2508 for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2510 fprintf (e, "BEGIN\n");
2513 fprintf (e, "0, 2, %d%s\t /* Having %d items. */\n", c, (c != 0 ? "," : ""), c);
2515 fprintf (e, "/* width, height, planes, bits, bytes, index. */\n");
2517 for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2520 fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2521 (int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits,
2522 (unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c);
2523 fprintf (e, "/* width: %d; height %d; planes %d; bits %d. */\n",
2524 (int) gc->width, (int) gc->height, (int) gc->planes,
2527 fprintf (e, "END\n");
2530 /* Write dialog data. */
2533 write_rc_dialog (FILE *e, const rc_dialog *dialog)
2535 const rc_dialog_control *control;
2537 fprintf (e, "STYLE 0x%x\n", dialog->style);
2539 if (dialog->exstyle != 0)
2540 fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle);
2542 if ((dialog->class.named && dialog->class.u.n.length > 0)
2543 || dialog->class.u.id != 0)
2545 fprintf (e, "CLASS ");
2546 res_id_print (e, dialog->class, 1);
2550 if (dialog->caption != NULL)
2552 fprintf (e, "CAPTION ");
2553 unicode_print_quoted (e, dialog->caption, -1);
2557 if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2558 || dialog->menu.u.id != 0)
2560 fprintf (e, "MENU ");
2561 res_id_print (e, dialog->menu, 0);
2565 if (dialog->font != NULL)
2567 fprintf (e, "FONT %d, ", (int) dialog->pointsize);
2568 unicode_print_quoted (e, dialog->font, -1);
2569 if (dialog->ex != NULL
2570 && (dialog->ex->weight != 0
2571 || dialog->ex->italic != 0
2572 || dialog->ex->charset != 1))
2573 fprintf (e, ", %d, %d, %d",
2574 (int) dialog->ex->weight,
2575 (int) dialog->ex->italic,
2576 (int) dialog->ex->charset);
2580 fprintf (e, "BEGIN\n");
2582 for (control = dialog->controls; control != NULL; control = control->next)
2583 write_rc_dialog_control (e, control);
2585 fprintf (e, "END\n");
2588 /* For each predefined control keyword, this table provides the class
2594 unsigned short class;
2595 unsigned long style;
2598 static const struct control_info control_info[] =
2600 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2601 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2602 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2603 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2604 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2605 { "CTEXT", CTL_STATIC, SS_CENTER },
2606 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2607 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2608 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2609 { "ICON", CTL_STATIC, SS_ICON },
2610 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2611 { "LTEXT", CTL_STATIC, SS_LEFT },
2612 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2613 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2614 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2615 { "RTEXT", CTL_STATIC, SS_RIGHT },
2616 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2617 { "STATE3", CTL_BUTTON, BS_3STATE },
2618 /* It's important that USERBUTTON come after all the other button
2619 types, so that it won't be matched too early. */
2620 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2624 /* Write a dialog control. */
2627 write_rc_dialog_control (FILE *e, const rc_dialog_control *control)
2629 const struct control_info *ci;
2633 if (control->class.named)
2637 for (ci = control_info; ci->name != NULL; ++ci)
2638 if (ci->class == control->class.u.id
2639 && (ci->style == (unsigned long) -1
2640 || ci->style == (control->style & 0xff)))
2644 fprintf (e, "CONTROL");
2645 else if (ci->name != NULL)
2646 fprintf (e, "%s", ci->name);
2649 fprintf (e, "CONTROL");
2653 if (control->text.named || control->text.u.id != 0)
2656 res_id_print (e, control->text, 1);
2660 fprintf (e, " %d, ", (int) control->id);
2664 if (control->class.named)
2666 res_id_print (e, control->class, 0);
2667 if (control->class.named)
2669 fprintf (e, ", 0x%x, ", (unsigned int) control->style);
2672 fprintf (e, "%d, %d", (int) control->x, (int) control->y);
2674 if (control->style != SS_ICON
2675 || control->exstyle != 0
2676 || control->width != 0
2677 || control->height != 0
2678 || control->help != 0)
2680 fprintf (e, ", %d, %d", (int) control->width, (int) control->height);
2682 /* FIXME: We don't need to print the style if it is the default.
2683 More importantly, in certain cases we actually need to turn
2684 off parts of the forced style, by using NOT. */
2686 fprintf (e, ", 0x%x", (unsigned int) control->style);
2688 if (control->exstyle != 0 || control->help != 0)
2689 fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle,
2690 (unsigned int) control->help);
2695 if (control->data != NULL)
2696 write_rc_rcdata (e, control->data, 2);
2699 /* Write out font directory data. This would normally be built from
2703 write_rc_fontdir (FILE *e, const rc_fontdir *fontdir)
2705 const rc_fontdir *fc;
2708 for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++)
2710 fprintf (e, "BEGIN\n");
2712 fprintf (e, "%d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2713 for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++)
2716 fprintf (e, "%d,\t/* Font no %d with index %d. */\n",
2717 (int) fc->index, c, (int) fc->index);
2718 write_rc_datablock (e, (rc_uint_type) fc->length - 2,
2719 (const bfd_byte *) fc->data + 4,fc->next != NULL,
2722 fprintf (e, "END\n");
2725 /* Write out group icon data. This would normally be built from the
2729 write_rc_group_icon (FILE *e, const rc_group_icon *group_icon)
2731 const rc_group_icon *gi;
2734 for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++)
2737 fprintf (e, "BEGIN\n");
2739 fprintf (e, " 0, 1, %d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2742 fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2743 for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++)
2746 fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2747 gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits,
2748 (unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c);
2750 fprintf (e, "END\n");
2753 /* Write out a menu resource. */
2756 write_rc_menu (FILE *e, const rc_menu *menu, int menuex)
2758 if (menu->help != 0)
2759 fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help);
2760 write_rc_menuitems (e, menu->items, menuex, 0);
2764 write_rc_toolbar (FILE *e, const rc_toolbar *tb)
2766 rc_toolbar_item *it;
2768 fprintf (e, "BEGIN\n");
2773 if (it->id.u.id == 0)
2774 fprintf (e, "SEPARATOR\n");
2776 fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
2780 fprintf (e, "END\n");
2783 /* Write out menuitems. */
2786 write_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex,
2789 const rc_menuitem *mi;
2792 fprintf (e, "BEGIN\n");
2794 for (mi = menuitems; mi != NULL; mi = mi->next)
2796 indent (e, ind + 2);
2798 if (mi->popup == NULL)
2799 fprintf (e, "MENUITEM");
2801 fprintf (e, "POPUP");
2804 && mi->popup == NULL
2809 fprintf (e, " SEPARATOR\n");
2813 if (mi->text == NULL)
2814 fprintf (e, " \"\"");
2818 unicode_print_quoted (e, mi->text, -1);
2823 if (mi->popup == NULL)
2824 fprintf (e, ", %d", (int) mi->id);
2826 if ((mi->type & MENUITEM_CHECKED) != 0)
2827 fprintf (e, ", CHECKED");
2828 if ((mi->type & MENUITEM_GRAYED) != 0)
2829 fprintf (e, ", GRAYED");
2830 if ((mi->type & MENUITEM_HELP) != 0)
2831 fprintf (e, ", HELP");
2832 if ((mi->type & MENUITEM_INACTIVE) != 0)
2833 fprintf (e, ", INACTIVE");
2834 if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2835 fprintf (e, ", MENUBARBREAK");
2836 if ((mi->type & MENUITEM_MENUBREAK) != 0)
2837 fprintf (e, ", MENUBREAK");
2841 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2843 fprintf (e, ", %d", (int) mi->id);
2844 if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2846 fprintf (e, ", %u", (unsigned int) mi->type);
2847 if (mi->state != 0 || mi->help != 0)
2849 fprintf (e, ", %u", (unsigned int) mi->state);
2851 fprintf (e, ", %u", (unsigned int) mi->help);
2859 if (mi->popup != NULL)
2860 write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2864 fprintf (e, "END\n");
2868 test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
2871 if ((length & 1) != 0)
2874 for (i = 0; i < length; i += 2)
2876 if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2878 if (data[i] == 0xff && data[i + 1] == 0xff)
2885 test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2895 for (i = 0, c = 0; i < length; i++)
2897 if (! ISPRINT (data[i]) && data[i] != '\n'
2898 && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2900 && ! (data[i] == 0 && (i + 1) != length))
2906 else if (data[i] == '\n') has_nl++;
2908 if (length > 80 && ! has_nl)
2910 c = (((c * 10000) + (i / 100) - 1)) / i;
2917 write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
2920 const struct bin_messagetable *mt;
2921 fprintf (e, "BEGIN\n");
2923 write_rc_datablock (e, length, data, 0, 0, 0);
2926 wr_printcomment (e, "MC syntax dump");
2927 if (length < BIN_MESSAGETABLE_SIZE)
2932 mt = (const struct bin_messagetable *) data;
2933 m = windres_get_32 (&wrtarget, mt->cblocks, length);
2934 if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2939 for (i = 0; i < m; i++)
2941 rc_uint_type low, high, offset;
2942 const struct bin_messagetable_item *mti;
2944 low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2945 high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2946 offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2949 rc_uint_type elen, flags;
2950 if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2955 mti = (const struct bin_messagetable_item *) &data[offset];
2956 elen = windres_get_16 (&wrtarget, mti->length, 2);
2957 flags = windres_get_16 (&wrtarget, mti->flags, 2);
2958 if ((offset + elen) > length)
2963 wr_printcomment (e, "MessageId = 0x%x", low);
2964 wr_printcomment (e, "");
2965 if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2966 unicode_print (e, (const unichar *) mti->data,
2967 (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2969 ascii_print (e, (const char *) mti->data,
2970 (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2971 wr_printcomment (e,"");
2978 wr_printcomment (e, "Illegal data");
2980 fprintf (e, "END\n");
2984 write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
2985 int hasblock, int show_comment)
2990 fprintf (e, "BEGIN\n");
2992 if (show_comment == -1)
2994 if (test_rc_datablock_text(length, data))
2997 for (i = 0; i < length;)
3002 for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
3004 if (i < length && data[i] == '\n')
3006 ascii_print (e, (const char *) &data[i - c], c);
3015 fprintf (e, "\"\"");
3021 fprintf (e, "END\n");
3024 if (test_rc_datablock_unicode (length, data))
3027 for (i = 0; i < length;)
3031 u = (const unichar *) &data[i];
3035 for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
3037 if (i < length && u[c] == '\n')
3039 unicode_print (e, u, c);
3048 fprintf (e, "L\"\"");
3054 fprintf (e, "END\n");
3063 rc_uint_type i, max_row;
3066 max_row = (show_comment ? 4 : 8);
3068 for (i = 0; i + 3 < length;)
3071 rc_uint_type comment_start;
3078 for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
3081 plen = fprintf (e, "0x%lxL",
3082 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
3084 plen = fprintf (e, " 0x%lxL",
3085 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
3086 if (has_next || (i + 4) < length)
3088 if (plen>0 && plen < 11)
3089 indent (e, 11 - plen);
3095 fprintf (e, "\t/* ");
3096 ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3097 fprintf (e, ". */");
3107 plen = fprintf (e, "0x%x",
3108 (int) windres_get_16 (&wrtarget, data + i, length - i));
3109 if (has_next || i + 2 < length)
3111 if (plen > 0 && plen < 11)
3112 indent (e, 11 - plen);
3117 fprintf (e, "\t/* ");
3118 ascii_print (e, (const char *) &data[i], 2);
3119 fprintf (e, ". */");
3131 ascii_print (e, (const char *) &data[i], 1);
3140 fprintf (e, "END\n");
3143 /* Write out an rcdata resource. This is also used for other types of
3144 resources that need to print arbitrary data. */
3147 write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3149 const rc_rcdata_item *ri;
3152 fprintf (e, "BEGIN\n");
3154 for (ri = rcdata; ri != NULL; ri = ri->next)
3156 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3165 indent (e, ind + 2);
3166 fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3170 indent (e, ind + 2);
3171 fprintf (e, "%luL", (unsigned long) ri->u.dword);
3175 indent (e, ind + 2);
3177 ascii_print (e, ri->u.string.s, ri->u.string.length);
3181 case RCDATA_WSTRING:
3182 indent (e, ind + 2);
3184 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3189 write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3190 (const bfd_byte *) ri->u.buffer.data,
3191 ri->next != NULL, 0, -1);
3195 if (ri->type != RCDATA_BUFFER)
3197 if (ri->next != NULL)
3204 fprintf (e, "END\n");
3207 /* Write out a stringtable resource. */
3210 write_rc_stringtable (FILE *e, const rc_res_id *name,
3211 const rc_stringtable *stringtable)
3213 rc_uint_type offset;
3216 if (name != NULL && ! name->named)
3217 offset = (name->u.id - 1) << 4;
3220 fprintf (e, "/* %s string table name. */\n",
3221 name == NULL ? "Missing" : "Invalid");
3225 fprintf (e, "BEGIN\n");
3227 for (i = 0; i < 16; i++)
3229 if (stringtable->strings[i].length != 0)
3231 fprintf (e, " %lu, ", (unsigned long) offset + i);
3232 unicode_print_quoted (e, stringtable->strings[i].string,
3233 stringtable->strings[i].length);
3238 fprintf (e, "END\n");
3241 /* Write out a versioninfo resource. */
3244 write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
3246 const rc_fixed_versioninfo *f;
3247 const rc_ver_info *vi;
3249 f = versioninfo->fixed;
3250 if (f->file_version_ms != 0 || f->file_version_ls != 0)
3251 fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3252 (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3253 (unsigned int) (f->file_version_ms & 0xffff),
3254 (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3255 (unsigned int) (f->file_version_ls & 0xffff));
3256 if (f->product_version_ms != 0 || f->product_version_ls != 0)
3257 fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3258 (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3259 (unsigned int) (f->product_version_ms & 0xffff),
3260 (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3261 (unsigned int) (f->product_version_ls & 0xffff));
3262 if (f->file_flags_mask != 0)
3263 fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
3264 if (f->file_flags != 0)
3265 fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
3266 if (f->file_os != 0)
3267 fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
3268 if (f->file_type != 0)
3269 fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
3270 if (f->file_subtype != 0)
3271 fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
3272 if (f->file_date_ms != 0 || f->file_date_ls != 0)
3273 fprintf (e, "/* Date: %u, %u. */\n",
3274 (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
3276 fprintf (e, "BEGIN\n");
3278 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3282 case VERINFO_STRING:
3284 const rc_ver_stringtable *vst;
3285 const rc_ver_stringinfo *vs;
3287 fprintf (e, " BLOCK \"StringFileInfo\"\n");
3288 fprintf (e, " BEGIN\n");
3290 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
3292 fprintf (e, " BLOCK ");
3293 unicode_print_quoted (e, vst->language, -1);
3296 fprintf (e, " BEGIN\n");
3298 for (vs = vst->strings; vs != NULL; vs = vs->next)
3300 fprintf (e, " VALUE ");
3301 unicode_print_quoted (e, vs->key, -1);
3303 unicode_print_quoted (e, vs->value, -1);
3307 fprintf (e, " END\n");
3309 fprintf (e, " END\n");
3315 const rc_ver_varinfo *vv;
3317 fprintf (e, " BLOCK \"VarFileInfo\"\n");
3318 fprintf (e, " BEGIN\n");
3319 fprintf (e, " VALUE ");
3320 unicode_print_quoted (e, vi->u.var.key, -1);
3322 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3323 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3326 fprintf (e, "\n END\n");
3333 fprintf (e, "END\n");
3337 rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
3345 windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3349 windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3352 if (dst && src->u.string.length)
3353 memcpy (dst, src->u.string.s, src->u.string.length);
3354 return (rc_uint_type) src->u.string.length;
3355 case RCDATA_WSTRING:
3356 if (dst && src->u.wstring.length)
3357 memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3358 return (rc_uint_type) (src->u.wstring.length * sizeof (unichar));
3360 if (dst && src->u.buffer.length)
3361 memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3362 return (rc_uint_type) src->u.buffer.length;
3366 /* Never reached. */