1 /* resrc.c -- read and write Windows rc files.
2 Copyright (C) 1997-2014 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Cygnus Support.
4 Rewritten by Kai Tietz, Onevision.
6 This file is part of GNU Binutils.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
23 /* This file contains functions that read and write Windows rc files.
24 These are text files that represent resources. */
29 #include "libiberty.h"
30 #include "safe-ctype.h"
35 #ifdef HAVE_SYS_WAIT_H
37 #else /* ! HAVE_SYS_WAIT_H */
38 #if ! defined (_WIN32) || defined (__CYGWIN__)
40 #define WIFEXITED(w) (((w)&0377) == 0)
43 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
46 #define WTERMSIG(w) ((w) & 0177)
49 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
51 #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
53 #define WIFEXITED(w) (((w) & 0xff) == 0)
56 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
59 #define WTERMSIG(w) ((w) & 0x7f)
62 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
64 #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
65 #endif /* ! HAVE_SYS_WAIT_H */
68 #define STDOUT_FILENO 1
71 #if defined (_WIN32) && ! defined (__CYGWIN__)
73 #define pclose _pclose
76 /* The default preprocessor. */
78 #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
80 /* We read the directory entries in a cursor or icon file into
81 instances of this structure. */
87 /* Height of image. */
89 /* Number of colors in image. */
96 unsigned short planes;
102 /* X coordinate of hotspot. */
103 unsigned short xhotspot;
104 /* Y coordinate of hotspot. */
105 unsigned short yhotspot;
108 /* Bytes in image. */
110 /* File offset of image. */
111 unsigned long offset;
114 /* The name of the rc file we are reading. */
118 /* The line number in the rc file. */
122 /* The pipe we are reading from, so that we can close it if we exit. */
126 /* The temporary file used if we're not using popen, so we can delete it
129 static char *cpp_temp_file;
131 /* Input stream is either a file or a pipe. */
133 static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
135 /* As we read the rc file, we attach information to this structure. */
137 static rc_res_directory *resources;
139 /* The number of cursor resources we have written out. */
143 /* The number of font resources we have written out. */
147 /* Font directory information. */
149 rc_fontdir *fontdirs;
151 /* Resource info to use for fontdirs. */
153 rc_res_res_info fontdirs_resinfo;
155 /* The number of icon resources we have written out. */
159 /* The windres target bfd . */
161 static windres_bfd wrtarget =
163 (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
166 /* Local functions for rcdata based resource definitions. */
168 static void define_font_rcdata (rc_res_id, const rc_res_res_info *,
170 static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
172 static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
174 static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
176 static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
178 static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
180 static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
181 static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
183 static int run_cmd (char *, const char *);
184 static FILE *open_input_stream (char *);
185 static FILE *look_for_default
186 (char *, const char *, int, const char *, const char *);
187 static void close_input_stream (void);
188 static void unexpected_eof (const char *);
189 static int get_word (FILE *, const char *);
190 static unsigned long get_long (FILE *, const char *);
191 static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
192 static void define_fontdirs (void);
194 /* Run `cmd' and redirect the output to `redir'. */
197 run_cmd (char *cmd, const char *redir)
200 int pid, wait_status, retcode;
203 char *errmsg_fmt, *errmsg_arg;
204 char *temp_base = choose_temp_base ();
207 int redir_handle = -1;
208 int stdout_save = -1;
210 /* Count the args. */
213 for (s = cmd; *s; s++)
218 argv = alloca (sizeof (char *) * (i + 3));
224 while (*s == ' ' && *s != 0)
230 in_quote = (*s == '\'' || *s == '"');
231 sep = (in_quote) ? *s++ : ' ';
234 while (*s != sep && *s != 0)
247 /* Setup the redirection. We can't use the usual fork/exec and redirect
248 since we may be running on non-POSIX Windows host. */
253 /* Open temporary output file. */
254 redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
255 if (redir_handle == -1)
256 fatal (_("can't open temporary file `%s': %s"), redir,
259 /* Duplicate the stdout file handle so it can be restored later. */
260 stdout_save = dup (STDOUT_FILENO);
261 if (stdout_save == -1)
262 fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno));
264 /* Redirect stdout to our output file. */
265 dup2 (redir_handle, STDOUT_FILENO);
267 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
268 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
270 /* Restore stdout to its previous setting. */
271 dup2 (stdout_save, STDOUT_FILENO);
273 /* Close response file. */
274 close (redir_handle);
278 fatal ("%s %s: %s", errmsg_fmt, errmsg_arg, strerror (errno));
283 pid = pwait (pid, &wait_status, 0);
287 fatal (_("wait: %s"), strerror (errno));
290 else if (WIFSIGNALED (wait_status))
292 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
295 else if (WIFEXITED (wait_status))
297 if (WEXITSTATUS (wait_status) != 0)
299 fatal (_("%s exited with status %d"), cmd,
300 WEXITSTATUS (wait_status));
311 open_input_stream (char *cmd)
313 if (istream_type == ISTREAM_FILE)
317 fileprefix = choose_temp_base ();
318 cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
319 sprintf (cpp_temp_file, "%s.irc", fileprefix);
322 if (run_cmd (cmd, cpp_temp_file))
323 fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
325 cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);
326 if (cpp_pipe == NULL)
327 fatal (_("can't open temporary file `%s': %s"),
328 cpp_temp_file, strerror (errno));
332 _("Using temporary file `%s' to read preprocessor output\n"),
337 cpp_pipe = popen (cmd, FOPEN_RT);
338 if (cpp_pipe == NULL)
339 fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
341 fprintf (stderr, _("Using popen to read preprocessor output\n"));
344 xatexit (close_input_stream);
348 /* Determine if FILENAME contains special characters that
349 can cause problems unless the entire filename is quoted. */
352 filename_need_quotes (const char *filename)
354 if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
357 while (*filename != 0)
374 /* Look for the preprocessor program. */
377 look_for_default (char *cmd, const char *prefix, int end_prefix,
378 const char *preprocargs, const char *filename)
383 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
385 strcpy (cmd, prefix);
387 sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
388 space = strchr (cmd + end_prefix, ' ');
393 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
394 strchr (cmd, '\\') ||
398 found = (stat (cmd, &s) == 0
399 #ifdef HAVE_EXECUTABLE_SUFFIX
400 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
407 fprintf (stderr, _("Tried `%s'\n"), cmd);
412 strcpy (cmd, prefix);
414 sprintf (cmd + end_prefix, "%s %s %s%s%s",
415 DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
418 fprintf (stderr, _("Using `%s'\n"), cmd);
420 cpp_pipe = open_input_stream (cmd);
424 /* Read an rc file. */
427 read_rc_file (const char *filename, const char *preprocessor,
428 const char *preprocargs, int language, int use_temp_file)
431 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
433 if (filename == NULL)
435 /* Setup the default resource import path taken from input file. */
436 else if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL)
440 if (filename[0] == '/'
441 || filename[0] == '\\'
442 || filename[1] == ':')
444 edit = dir = xstrdup (filename);
448 edit = dir = xmalloc (strlen (filename) + 3);
449 sprintf (dir, "./%s", filename);
452 /* Walk dir backwards stopping at the first directory separator. */
453 edit += strlen (dir);
454 while (edit > dir && (edit[-1] != '\\' && edit[-1] != '/'))
460 /* Cut off trailing slash. */
464 /* Convert all back slashes to forward slashes. */
465 while ((edit = strchr (dir, '\\')) != NULL)
468 windres_add_include_dir (dir);
471 istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
473 if (preprocargs == NULL)
478 cmd = xmalloc (strlen (preprocessor)
479 + strlen (preprocargs)
481 + strlen (fnquotes) * 2
483 sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
484 fnquotes, filename, fnquotes);
486 cpp_pipe = open_input_stream (cmd);
490 char *dash, *slash, *cp;
492 preprocessor = DEFAULT_PREPROCESSOR;
494 cmd = xmalloc (strlen (program_name)
495 + strlen (preprocessor)
496 + strlen (preprocargs)
498 + strlen (fnquotes) * 2
499 #ifdef HAVE_EXECUTABLE_SUFFIX
500 + strlen (EXECUTABLE_SUFFIX)
506 for (cp = program_name; *cp; cp++)
511 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
512 *cp == ':' || *cp == '\\' ||
525 /* First, try looking for a prefixed gcc in the windres
526 directory, with the same prefix as windres */
528 cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
529 preprocargs, filename);
532 if (slash && ! cpp_pipe)
534 /* Next, try looking for a gcc in the same directory as
537 cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
538 preprocargs, filename);
543 /* Sigh, try the default */
545 cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
552 rc_filename = xstrdup (filename);
555 rcparse_set_language (language);
557 rcparse_discard_strings ();
559 close_input_stream ();
561 if (fontdirs != NULL)
570 /* Close the input stream if it is open. */
573 close_input_stream (void)
575 if (istream_type == ISTREAM_FILE)
577 if (cpp_pipe != NULL)
580 if (cpp_temp_file != NULL)
582 int errno_save = errno;
584 unlink (cpp_temp_file);
586 free (cpp_temp_file);
591 if (cpp_pipe != NULL)
594 err = pclose (cpp_pipe);
595 /* We are reading from a pipe, therefore we don't
596 know if cpp failed or succeeded until pclose. */
597 if (err != 0 || errno == ECHILD)
599 /* Since this is also run via xatexit, safeguard. */
601 cpp_temp_file = NULL;
602 fatal (_("preprocessing failed."));
607 /* Since this is also run via xatexit, safeguard. */
609 cpp_temp_file = NULL;
612 /* Report an error while reading an rc file. */
615 yyerror (const char *msg)
617 fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
620 /* Issue a warning while reading an rc file. */
623 rcparse_warning (const char *msg)
625 fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
628 /* Die if we get an unexpected end of file. */
631 unexpected_eof (const char *msg)
633 fatal (_("%s: unexpected EOF"), msg);
636 /* Read a 16 bit word from a file. The data is assumed to be little
640 get_word (FILE *e, const char *msg)
647 unexpected_eof (msg);
648 return ((b2 & 0xff) << 8) | (b1 & 0xff);
651 /* Read a 32 bit word from a file. The data is assumed to be little
655 get_long (FILE *e, const char *msg)
664 unexpected_eof (msg);
665 return (((((((b4 & 0xff) << 8)
671 /* Read data from a file. This is a wrapper to do error checking. */
674 get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
676 rc_uint_type got; // $$$d
678 got = (rc_uint_type) fread (p, 1, c, e);
682 fatal (_("%s: read of %lu returned %lu"),
683 msg, (unsigned long) c, (unsigned long) got);
686 /* Define an accelerator resource. */
689 define_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
690 rc_accelerator *data)
694 r = define_standard_resource (&resources, RT_ACCELERATOR, id,
695 resinfo->language, 0);
696 r->type = RES_TYPE_ACCELERATOR;
698 r->res_info = *resinfo;
701 /* Define a bitmap resource. Bitmap data is stored in a file. The
702 first 14 bytes of the file are a standard header, which is not
703 included in the resource data. */
705 #define BITMAP_SKIP (14)
708 define_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
709 const char *filename)
718 e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
720 if (stat (real_filename, &s) < 0)
721 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
724 data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
726 for (i = 0; i < BITMAP_SKIP; i++)
729 get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
732 free (real_filename);
734 r = define_standard_resource (&resources, RT_BITMAP, id,
735 resinfo->language, 0);
737 r->type = RES_TYPE_BITMAP;
738 r->u.data.length = s.st_size - BITMAP_SKIP;
739 r->u.data.data = data;
740 r->res_info = *resinfo;
743 /* Define a cursor resource. A cursor file may contain a set of
744 bitmaps, each representing the same cursor at various different
745 resolutions. They each get written out with a different ID. The
746 real cursor resource is then a group resource which can be used to
747 select one of the actual cursors. */
750 define_cursor (rc_res_id id, const rc_res_res_info *resinfo,
751 const char *filename)
756 struct icondir *icondirs;
759 rc_group_cursor *first, **pp;
761 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
763 /* A cursor file is basically an icon file. The start of the file
764 is a three word structure. The first word is ignored. The
765 second word is the type of data. The third word is the number of
768 get_word (e, real_filename);
769 type = get_word (e, real_filename);
770 count = get_word (e, real_filename);
772 fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
774 /* Read in the icon directory entries. */
776 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
778 for (i = 0; i < count; i++)
780 icondirs[i].width = getc (e);
781 icondirs[i].height = getc (e);
782 icondirs[i].colorcount = getc (e);
784 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
785 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
786 icondirs[i].bytes = get_long (e, real_filename);
787 icondirs[i].offset = get_long (e, real_filename);
790 unexpected_eof (real_filename);
793 /* Define each cursor as a unique resource. */
795 first_cursor = cursors;
797 for (i = 0; i < count; i++)
803 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
804 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
805 icondirs[i].offset, strerror (errno));
807 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
809 get_data (e, data, icondirs[i].bytes, real_filename);
811 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
812 c->xhotspot = icondirs[i].u.cursor.xhotspot;
813 c->yhotspot = icondirs[i].u.cursor.yhotspot;
814 c->length = icondirs[i].bytes;
822 r = define_standard_resource (&resources, RT_CURSOR, name,
823 resinfo->language, 0);
824 r->type = RES_TYPE_CURSOR;
826 r->res_info = *resinfo;
830 free (real_filename);
832 /* Define a cursor group resource. */
836 for (i = 0; i < count; i++)
840 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
842 cg->width = icondirs[i].width;
843 cg->height = 2 * icondirs[i].height;
845 /* FIXME: What should these be set to? */
849 cg->bytes = icondirs[i].bytes + 4;
850 cg->index = first_cursor + i + 1;
858 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
859 resinfo->language, 0);
860 r->type = RES_TYPE_GROUP_CURSOR;
861 r->u.group_cursor = first;
862 r->res_info = *resinfo;
865 /* Define a dialog resource. */
868 define_dialog (rc_res_id id, const rc_res_res_info *resinfo,
869 const rc_dialog *dialog)
874 copy = (rc_dialog *) res_alloc (sizeof *copy);
877 r = define_standard_resource (&resources, RT_DIALOG, id,
878 resinfo->language, 0);
879 r->type = RES_TYPE_DIALOG;
881 r->res_info = *resinfo;
884 /* Define a dialog control. This does not define a resource, but
885 merely allocates and fills in a structure. */
888 define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
889 rc_uint_type y, rc_uint_type width, rc_uint_type height,
890 const rc_res_id class, rc_uint_type style,
891 rc_uint_type exstyle)
893 rc_dialog_control *n;
895 n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
899 n->exstyle = exstyle;
913 define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
914 rc_uint_type y, rc_uint_type style,
915 rc_uint_type exstyle, rc_uint_type help,
916 rc_rcdata_item *data, rc_dialog_ex *ex)
918 rc_dialog_control *n;
923 style = SS_ICON | WS_CHILD | WS_VISIBLE;
924 res_string_to_id (&tid, "");
926 cid.u.id = CTL_STATIC;
927 n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
930 rcparse_warning (_("help ID requires DIALOGEX"));
932 rcparse_warning (_("control data requires DIALOGEX"));
939 /* Define a font resource. */
942 define_font (rc_res_id id, const rc_res_res_info *resinfo,
943 const char *filename)
954 const char *device, *face;
957 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
959 if (stat (real_filename, &s) < 0)
960 fatal (_("stat failed on font file `%s': %s"), real_filename,
963 data = (bfd_byte *) res_alloc (s.st_size);
965 get_data (e, data, s.st_size, real_filename);
968 free (real_filename);
970 r = define_standard_resource (&resources, RT_FONT, id,
971 resinfo->language, 0);
973 r->type = RES_TYPE_FONT;
974 r->u.data.length = s.st_size;
975 r->u.data.data = data;
976 r->res_info = *resinfo;
978 /* For each font resource, we must add an entry in the FONTDIR
979 resource. The FONTDIR resource includes some strings in the font
980 file. To find them, we have to do some magic on the data we have
983 offset = ((((((data[47] << 8)
987 if (offset > 0 && offset < s.st_size)
988 device = (char *) data + offset;
992 offset = ((((((data[51] << 8)
996 if (offset > 0 && offset < s.st_size)
997 face = (char *) data + offset;
1003 fontdatalength = 58 + strlen (device) + strlen (face);
1004 fontdata = (bfd_byte *) res_alloc (fontdatalength);
1005 memcpy (fontdata, data, 56);
1006 strcpy ((char *) fontdata + 56, device);
1007 strcpy ((char *) fontdata + 57 + strlen (device), face);
1009 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1012 fd->length = fontdatalength;
1013 fd->data = fontdata;
1015 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
1019 /* For the single fontdirs resource, we always use the resource
1020 information of the last font. I don't know what else to do. */
1021 fontdirs_resinfo = *resinfo;
1025 define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1026 rc_rcdata_item *data)
1029 rc_uint_type len_data;
1032 r = define_standard_resource (&resources, RT_FONT, id,
1033 resinfo->language, 0);
1035 pb_data = rcdata_render_as_buffer (data, &len_data);
1037 r->type = RES_TYPE_FONT;
1038 r->u.data.length = len_data;
1039 r->u.data.data = pb_data;
1040 r->res_info = *resinfo;
1043 /* Define the fontdirs resource. This is called after the entire rc
1044 file has been parsed, if any font resources were seen. */
1047 define_fontdirs (void)
1055 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1057 r->type = RES_TYPE_FONTDIR;
1058 r->u.fontdir = fontdirs;
1059 r->res_info = fontdirs_resinfo;
1063 rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
1065 const rc_rcdata_item *d;
1066 bfd_byte *ret = NULL, *pret;
1067 rc_uint_type len = 0;
1069 for (d = data; d != NULL; d = d->next)
1070 len += rcdata_copy (d, NULL);
1073 ret = pret = (bfd_byte *) res_alloc (len);
1074 for (d = data; d != NULL; d = d->next)
1075 pret += rcdata_copy (d, pret);
1083 define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1084 rc_rcdata_item *data)
1087 rc_fontdir *fd, *fd_first, *fd_cur;
1088 rc_uint_type len_data;
1092 fd_cur = fd_first = NULL;
1093 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1095 pb_data = rcdata_render_as_buffer (data, &len_data);
1099 rc_uint_type off = 2;
1100 c = windres_get_16 (&wrtarget, pb_data, len_data);
1104 rc_uint_type safe_pos = off;
1105 const struct bin_fontdir_item *bfi;
1107 bfi = (const struct bin_fontdir_item *) pb_data + off;
1108 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1109 fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
1110 fd->data = pb_data + off;
1112 len = strlen ((char *) bfi->device_name) + 1;
1113 off += (rc_uint_type) len;
1114 off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
1115 fd->length = (off - safe_pos);
1117 if (fd_first == NULL)
1124 r->type = RES_TYPE_FONTDIR;
1125 r->u.fontdir = fd_first;
1126 r->res_info = *resinfo;
1129 static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1130 rc_rcdata_item *data)
1133 rc_uint_type len_data;
1136 r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
1138 pb_data = rcdata_render_as_buffer (data, &len_data);
1139 r->type = RES_TYPE_MESSAGETABLE;
1140 r->u.data.length = len_data;
1141 r->u.data.data = pb_data;
1142 r->res_info = *resinfo;
1145 /* Define an icon resource. An icon file may contain a set of
1146 bitmaps, each representing the same icon at various different
1147 resolutions. They each get written out with a different ID. The
1148 real icon resource is then a group resource which can be used to
1149 select one of the actual icon bitmaps. */
1152 define_icon (rc_res_id id, const rc_res_res_info *resinfo,
1153 const char *filename)
1156 char *real_filename;
1158 struct icondir *icondirs;
1161 rc_group_icon *first, **pp;
1163 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1165 /* The start of an icon file is a three word structure. The first
1166 word is ignored. The second word is the type of data. The third
1167 word is the number of entries. */
1169 get_word (e, real_filename);
1170 type = get_word (e, real_filename);
1171 count = get_word (e, real_filename);
1173 fatal (_("icon file `%s' does not contain icon data"), real_filename);
1175 /* Read in the icon directory entries. */
1177 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1179 for (i = 0; i < count; i++)
1181 icondirs[i].width = getc (e);
1182 icondirs[i].height = getc (e);
1183 icondirs[i].colorcount = getc (e);
1185 icondirs[i].u.icon.planes = get_word (e, real_filename);
1186 icondirs[i].u.icon.bits = get_word (e, real_filename);
1187 icondirs[i].bytes = get_long (e, real_filename);
1188 icondirs[i].offset = get_long (e, real_filename);
1191 unexpected_eof (real_filename);
1194 /* Define each icon as a unique resource. */
1198 for (i = 0; i < count; i++)
1203 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1204 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1205 icondirs[i].offset, strerror (errno));
1207 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
1209 get_data (e, data, icondirs[i].bytes, real_filename);
1216 r = define_standard_resource (&resources, RT_ICON, name,
1217 resinfo->language, 0);
1218 r->type = RES_TYPE_ICON;
1219 r->u.data.length = icondirs[i].bytes;
1220 r->u.data.data = data;
1221 r->res_info = *resinfo;
1225 free (real_filename);
1227 /* Define an icon group resource. */
1231 for (i = 0; i < count; i++)
1235 /* For some reason, at least in some files the planes and bits
1236 are zero. We instead set them from the color. This is
1239 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1241 cg->width = icondirs[i].width;
1242 cg->height = icondirs[i].height;
1243 cg->colors = icondirs[i].colorcount;
1245 if (icondirs[i].u.icon.planes)
1246 cg->planes = icondirs[i].u.icon.planes;
1250 if (icondirs[i].u.icon.bits)
1251 cg->bits = icondirs[i].u.icon.bits;
1256 while ((1L << cg->bits) < cg->colors)
1260 cg->bytes = icondirs[i].bytes;
1261 cg->index = first_icon + i + 1;
1269 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1270 resinfo->language, 0);
1271 r->type = RES_TYPE_GROUP_ICON;
1272 r->u.group_icon = first;
1273 r->res_info = *resinfo;
1277 define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1278 rc_rcdata_item *data)
1281 rc_group_icon *cg, *first, *cur;
1282 rc_uint_type len_data;
1285 pb_data = rcdata_render_as_buffer (data, &len_data);
1290 while (len_data >= 6)
1293 unsigned short type;
1294 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1296 fatal (_("unexpected group icon type %d"), type);
1297 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1301 for (i = 0; i < c; i++)
1304 fatal ("too small group icon rcdata");
1305 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1307 cg->width = pb_data[0];
1308 cg->height = pb_data[1];
1309 cg->colors = pb_data[2];
1310 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1311 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1312 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1313 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1323 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1324 resinfo->language, 0);
1325 r->type = RES_TYPE_GROUP_ICON;
1326 r->u.group_icon = first;
1327 r->res_info = *resinfo;
1331 define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1332 rc_rcdata_item *data)
1335 rc_group_cursor *cg, *first, *cur;
1336 rc_uint_type len_data;
1339 pb_data = rcdata_render_as_buffer (data, &len_data);
1343 while (len_data >= 6)
1346 unsigned short type;
1347 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1349 fatal (_("unexpected group cursor type %d"), type);
1350 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1354 for (i = 0; i < c; i++)
1357 fatal ("too small group icon rcdata");
1358 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
1360 cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
1361 cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1362 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1363 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1364 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1365 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1376 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1377 resinfo->language, 0);
1378 r->type = RES_TYPE_GROUP_CURSOR;
1379 r->u.group_cursor = first;
1380 r->res_info = *resinfo;
1384 define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1385 rc_rcdata_item *data)
1389 rc_uint_type len_data;
1392 pb_data = rcdata_render_as_buffer (data, &len_data);
1394 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
1395 c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
1396 c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1397 c->length = len_data - BIN_CURSOR_SIZE;
1398 c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
1400 r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
1401 r->type = RES_TYPE_CURSOR;
1403 r->res_info = *resinfo;
1407 define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1408 rc_rcdata_item *data)
1411 rc_uint_type len_data;
1414 pb_data = rcdata_render_as_buffer (data, &len_data);
1416 r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
1417 r->type = RES_TYPE_BITMAP;
1418 r->u.data.length = len_data;
1419 r->u.data.data = pb_data;
1420 r->res_info = *resinfo;
1424 define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1425 rc_rcdata_item *data)
1428 rc_uint_type len_data;
1431 pb_data = rcdata_render_as_buffer (data, &len_data);
1433 r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
1434 r->type = RES_TYPE_ICON;
1435 r->u.data.length = len_data;
1436 r->u.data.data = pb_data;
1437 r->res_info = *resinfo;
1440 /* Define a menu resource. */
1443 define_menu (rc_res_id id, const rc_res_res_info *resinfo,
1444 rc_menuitem *menuitems)
1449 m = (rc_menu *) res_alloc (sizeof (rc_menu));
1450 m->items = menuitems;
1453 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1454 r->type = RES_TYPE_MENU;
1456 r->res_info = *resinfo;
1459 /* Define a menu item. This does not define a resource, but merely
1460 allocates and fills in a structure. */
1463 define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
1464 rc_uint_type state, rc_uint_type help,
1465 rc_menuitem *menuitems)
1469 mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
1474 mi->text = unichar_dup (text);
1476 mi->popup = menuitems;
1480 /* Define a messagetable resource. */
1483 define_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
1484 const char *filename)
1487 char *real_filename;
1492 e = open_file_search (filename, FOPEN_RB, "messagetable file",
1495 if (stat (real_filename, &s) < 0)
1496 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1499 data = (bfd_byte *) res_alloc (s.st_size);
1501 get_data (e, data, s.st_size, real_filename);
1504 free (real_filename);
1506 r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1507 resinfo->language, 0);
1509 r->type = RES_TYPE_MESSAGETABLE;
1510 r->u.data.length = s.st_size;
1511 r->u.data.data = data;
1512 r->res_info = *resinfo;
1515 /* Define an rcdata resource. */
1518 define_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1519 rc_rcdata_item *data)
1523 r = define_standard_resource (&resources, RT_RCDATA, id,
1524 resinfo->language, 0);
1525 r->type = RES_TYPE_RCDATA;
1527 r->res_info = *resinfo;
1530 /* Create an rcdata item holding a string. */
1533 define_rcdata_string (const char *string, rc_uint_type len)
1538 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1540 ri->type = RCDATA_STRING;
1541 ri->u.string.length = len;
1542 s = (char *) res_alloc (len);
1543 memcpy (s, string, len);
1549 /* Create an rcdata item holding a unicode string. */
1552 define_rcdata_unistring (const unichar *string, rc_uint_type len)
1557 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1559 ri->type = RCDATA_WSTRING;
1560 ri->u.wstring.length = len;
1561 s = (unichar *) res_alloc (len * sizeof (unichar));
1562 memcpy (s, string, len * sizeof (unichar));
1563 ri->u.wstring.w = s;
1568 /* Create an rcdata item holding a number. */
1571 define_rcdata_number (rc_uint_type val, int dword)
1575 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1577 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1583 /* Define a stringtable resource. This is called for each string
1584 which appears in a STRINGTABLE statement. */
1587 define_stringtable (const rc_res_res_info *resinfo,
1588 rc_uint_type stringid, const unichar *string, int len)
1595 id.u.id = (stringid >> 4) + 1;
1596 r = define_standard_resource (&resources, RT_STRING, id,
1597 resinfo->language, 1);
1599 if (r->type == RES_TYPE_UNINITIALIZED)
1603 r->type = RES_TYPE_STRINGTABLE;
1604 r->u.stringtable = ((rc_stringtable *)
1605 res_alloc (sizeof (rc_stringtable)));
1606 for (i = 0; i < 16; i++)
1608 r->u.stringtable->strings[i].length = 0;
1609 r->u.stringtable->strings[i].string = NULL;
1612 r->res_info = *resinfo;
1614 h = (unichar *) res_alloc ((len + 1) * sizeof (unichar));
1616 memcpy (h, string, len * sizeof (unichar));
1618 r->u.stringtable->strings[stringid & 0xf].length = (rc_uint_type) len;
1619 r->u.stringtable->strings[stringid & 0xf].string = h;
1623 define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
1624 rc_toolbar_item *items)
1629 t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1630 t->button_width = width;
1631 t->button_height = height;
1634 while (items != NULL)
1637 items = items->next;
1639 r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
1640 r->type = RES_TYPE_TOOLBAR;
1642 r->res_info = *resinfo;
1645 /* Define a user data resource where the data is in the rc file. */
1648 define_user_data (rc_res_id id, rc_res_id type,
1649 const rc_res_res_info *resinfo,
1650 rc_rcdata_item *data)
1655 rc_uint_type len_data;
1657 /* We have to check if the binary data is parsed specially. */
1658 if (type.named == 0)
1663 define_fontdir_rcdata (id, resinfo, data);
1666 define_font_rcdata (id, resinfo, data);
1669 define_icon_rcdata (id, resinfo, data);
1672 define_bitmap_rcdata (id, resinfo, data);
1675 define_cursor_rcdata (id, resinfo, data);
1678 define_group_icon_rcdata (id, resinfo, data);
1680 case RT_GROUP_CURSOR:
1681 define_group_cursor_rcdata (id, resinfo, data);
1683 case RT_MESSAGETABLE:
1684 define_messagetable_rcdata (id, resinfo, data);
1687 /* Treat as normal user-data. */
1694 ids[2].u.id = resinfo->language;
1696 r = define_resource (& resources, 3, ids, 0);
1697 r->type = RES_TYPE_USERDATA;
1698 r->u.userdata = ((rc_rcdata_item *)
1699 res_alloc (sizeof (rc_rcdata_item)));
1700 r->u.userdata->next = NULL;
1701 r->u.userdata->type = RCDATA_BUFFER;
1702 pb_data = rcdata_render_as_buffer (data, &len_data);
1703 r->u.userdata->u.buffer.length = len_data;
1704 r->u.userdata->u.buffer.data = pb_data;
1705 r->res_info = *resinfo;
1709 define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
1710 const char *filename)
1714 char *real_filename;
1718 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1721 if (stat (real_filename, &s) < 0)
1722 fatal (_("stat failed on file `%s': %s"), real_filename,
1725 data = (bfd_byte *) res_alloc (s.st_size);
1727 get_data (e, data, s.st_size, real_filename);
1730 free (real_filename);
1732 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1734 ri->type = RCDATA_BUFFER;
1735 ri->u.buffer.length = s.st_size;
1736 ri->u.buffer.data = data;
1738 define_rcdata (id, resinfo, ri);
1741 /* Define a user data resource where the data is in a file. */
1744 define_user_file (rc_res_id id, rc_res_id type,
1745 const rc_res_res_info *resinfo, const char *filename)
1748 char *real_filename;
1754 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1756 if (stat (real_filename, &s) < 0)
1757 fatal (_("stat failed on file `%s': %s"), real_filename,
1760 data = (bfd_byte *) res_alloc (s.st_size);
1762 get_data (e, data, s.st_size, real_filename);
1765 free (real_filename);
1770 ids[2].u.id = resinfo->language;
1772 r = define_resource (&resources, 3, ids, 0);
1773 r->type = RES_TYPE_USERDATA;
1774 r->u.userdata = ((rc_rcdata_item *)
1775 res_alloc (sizeof (rc_rcdata_item)));
1776 r->u.userdata->next = NULL;
1777 r->u.userdata->type = RCDATA_BUFFER;
1778 r->u.userdata->u.buffer.length = s.st_size;
1779 r->u.userdata->u.buffer.data = data;
1780 r->res_info = *resinfo;
1783 /* Define a versioninfo resource. */
1786 define_versioninfo (rc_res_id id, rc_uint_type language,
1787 rc_fixed_versioninfo *fixedverinfo,
1788 rc_ver_info *verinfo)
1792 r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1793 r->type = RES_TYPE_VERSIONINFO;
1794 r->u.versioninfo = ((rc_versioninfo *)
1795 res_alloc (sizeof (rc_versioninfo)));
1796 r->u.versioninfo->fixed = fixedverinfo;
1797 r->u.versioninfo->var = verinfo;
1798 r->res_info.language = language;
1801 /* Add string version info to a list of version information. */
1804 append_ver_stringfileinfo (rc_ver_info *verinfo,
1805 rc_ver_stringtable *stringtables)
1807 rc_ver_info *vi, **pp;
1809 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1811 vi->type = VERINFO_STRING;
1812 vi->u.string.stringtables = stringtables;
1814 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1821 rc_ver_stringtable *
1822 append_ver_stringtable (rc_ver_stringtable *stringtable,
1823 const char *language,
1824 rc_ver_stringinfo *strings)
1826 rc_ver_stringtable *vst, **pp;
1828 vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1830 unicode_from_ascii ((rc_uint_type *) NULL, &vst->language, language);
1831 vst->strings = strings;
1833 for (pp = &stringtable; *pp != NULL; pp = &(*pp)->next)
1840 /* Add variable version info to a list of version information. */
1843 append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
1844 rc_ver_varinfo *var)
1846 rc_ver_info *vi, **pp;
1848 vi = (rc_ver_info *) res_alloc (sizeof *vi);
1850 vi->type = VERINFO_VAR;
1851 vi->u.var.key = unichar_dup (key);
1852 vi->u.var.var = var;
1854 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1861 /* Append version string information to a list. */
1864 append_verval (rc_ver_stringinfo *strings, const unichar *key,
1865 const unichar *value)
1867 rc_ver_stringinfo *vs, **pp;
1869 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1871 vs->key = unichar_dup (key);
1872 vs->value = unichar_dup (value);
1874 for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1881 /* Append version variable information to a list. */
1884 append_vertrans (rc_ver_varinfo *var, rc_uint_type language,
1885 rc_uint_type charset)
1887 rc_ver_varinfo *vv, **pp;
1889 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1891 vv->language = language;
1892 vv->charset = charset;
1894 for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1901 /* Local functions used to write out an rc file. */
1903 static void indent (FILE *, int);
1904 static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
1905 const rc_res_id *, rc_uint_type *, int);
1906 static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
1907 const rc_res_id *, rc_uint_type *, int);
1908 static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
1909 const rc_res_resource *, rc_uint_type *);
1910 static void write_rc_accelerators (FILE *, const rc_accelerator *);
1911 static void write_rc_cursor (FILE *, const rc_cursor *);
1912 static void write_rc_group_cursor (FILE *, const rc_group_cursor *);
1913 static void write_rc_dialog (FILE *, const rc_dialog *);
1914 static void write_rc_dialog_control (FILE *, const rc_dialog_control *);
1915 static void write_rc_fontdir (FILE *, const rc_fontdir *);
1916 static void write_rc_group_icon (FILE *, const rc_group_icon *);
1917 static void write_rc_menu (FILE *, const rc_menu *, int);
1918 static void write_rc_toolbar (FILE *, const rc_toolbar *);
1919 static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
1920 static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
1922 static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
1923 static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
1924 static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
1925 static void write_rc_versioninfo (FILE *, const rc_versioninfo *);
1927 /* Indent a given number of spaces. */
1930 indent (FILE *e, int c)
1934 for (i = 0; i < c; i++)
1938 /* Dump the resources we have read in the format of an rc file.
1940 Reasoned by the fact, that some resources need to be stored into file and
1941 refer to that file, we use the user-data model for that to express it binary
1942 without the need to store it somewhere externally. */
1945 write_rc_file (const char *filename, const rc_res_directory *res_dir)
1948 rc_uint_type language;
1950 if (filename == NULL)
1954 e = fopen (filename, FOPEN_WT);
1956 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1959 language = (rc_uint_type) ((bfd_signed_vma) -1);
1960 write_rc_directory (e, res_dir, (const rc_res_id *) NULL,
1961 (const rc_res_id *) NULL, &language, 1);
1964 /* Write out a directory. E is the file to write to. RD is the
1965 directory. TYPE is a pointer to the level 1 ID which serves as the
1966 resource type. NAME is a pointer to the level 2 ID which serves as
1967 an individual resource name. LANGUAGE is a pointer to the current
1968 language. LEVEL is the level in the tree. */
1971 write_rc_directory (FILE *e, const rc_res_directory *rd,
1972 const rc_res_id *type, const rc_res_id *name,
1973 rc_uint_type *language, int level)
1975 const rc_res_entry *re;
1977 /* Print out some COFF information that rc files can't represent. */
1978 if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
1980 wr_printcomment (e, "COFF information not part of RC");
1982 wr_printcomment (e, "Time stamp: %u", rd->time);
1983 if (rd->characteristics != 0)
1984 wr_printcomment (e, "Characteristics: %u", rd->characteristics);
1985 if (rd->major != 0 || rd->minor != 0)
1986 wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
1989 for (re = rd->entries; re != NULL; re = re->next)
1994 /* If we're at level 1, the key of this resource is the
1995 type. This normally duplicates the information we have
1996 stored with the resource itself, but we need to remember
1997 the type if this is a user define resource type. */
2002 /* If we're at level 2, the key of this resource is the name
2003 we are going to use in the rc printout. */
2008 /* If we're at level 3, then this key represents a language.
2009 Use it to update the current language. */
2011 && re->id.u.id != (unsigned long) (unsigned int) *language
2012 && (re->id.u.id & 0xffff) == re->id.u.id)
2014 wr_print (e, "LANGUAGE %u, %u\n",
2015 re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
2016 (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
2017 *language = re->id.u.id;
2026 write_rc_subdir (e, re, type, name, language, level);
2031 /* This is the normal case: the three levels are
2032 TYPE/NAME/LANGUAGE. NAME will have been set at level
2033 2, and represents the name to use. We probably just
2034 set LANGUAGE, and it will probably match what the
2035 resource itself records if anything. */
2036 write_rc_resource (e, type, name, re->u.res, language);
2040 wr_printcomment (e, "Resource at unexpected level %d", level);
2041 write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
2046 if (rd->entries == NULL)
2052 /* Write out a subdirectory entry. E is the file to write to. RE is
2053 the subdirectory entry. TYPE and NAME are pointers to higher level
2054 IDs, or NULL. LANGUAGE is a pointer to the current language.
2055 LEVEL is the level in the tree. */
2058 write_rc_subdir (FILE *e, const rc_res_entry *re,
2059 const rc_res_id *type, const rc_res_id *name,
2060 rc_uint_type *language, int level)
2066 wr_printcomment (e, "Type: ");
2068 res_id_print (e, re->id, 1);
2073 switch (re->id.u.id)
2075 case RT_CURSOR: s = "cursor"; break;
2076 case RT_BITMAP: s = "bitmap"; break;
2077 case RT_ICON: s = "icon"; break;
2078 case RT_MENU: s = "menu"; break;
2079 case RT_DIALOG: s = "dialog"; break;
2080 case RT_STRING: s = "stringtable"; break;
2081 case RT_FONTDIR: s = "fontdir"; break;
2082 case RT_FONT: s = "font"; break;
2083 case RT_ACCELERATOR: s = "accelerators"; break;
2084 case RT_RCDATA: s = "rcdata"; break;
2085 case RT_MESSAGETABLE: s = "messagetable"; break;
2086 case RT_GROUP_CURSOR: s = "group cursor"; break;
2087 case RT_GROUP_ICON: s = "group icon"; break;
2088 case RT_VERSION: s = "version"; break;
2089 case RT_DLGINCLUDE: s = "dlginclude"; break;
2090 case RT_PLUGPLAY: s = "plugplay"; break;
2091 case RT_VXD: s = "vxd"; break;
2092 case RT_ANICURSOR: s = "anicursor"; break;
2093 case RT_ANIICON: s = "aniicon"; break;
2094 case RT_TOOLBAR: s = "toolbar"; break;
2095 case RT_HTML: s = "html"; break;
2096 default: s = NULL; break;
2100 fprintf (e, "%s", s);
2102 res_id_print (e, re->id, 1);
2107 wr_printcomment (e, "Name: ");
2108 res_id_print (e, re->id, 1);
2112 wr_printcomment (e, "Language: ");
2113 res_id_print (e, re->id, 1);
2117 wr_printcomment (e, "Level %d: ", level);
2118 res_id_print (e, re->id, 1);
2121 write_rc_directory (e, re->u.dir, type, name, language, level + 1);
2124 /* Write out a single resource. E is the file to write to. TYPE is a
2125 pointer to the type of the resource. NAME is a pointer to the name
2126 of the resource; it will be NULL if there is a level mismatch. RES
2127 is the resource data. LANGUAGE is a pointer to the current
2131 write_rc_resource (FILE *e, const rc_res_id *type,
2132 const rc_res_id *name, const rc_res_resource *res,
2133 rc_uint_type *language)
2144 case RES_TYPE_ACCELERATOR:
2146 rt = RT_ACCELERATOR;
2149 case RES_TYPE_BITMAP:
2150 s = "2 /* RT_BITMAP */";
2154 case RES_TYPE_CURSOR:
2155 s = "1 /* RT_CURSOR */";
2159 case RES_TYPE_GROUP_CURSOR:
2160 s = "12 /* RT_GROUP_CURSOR */";
2161 rt = RT_GROUP_CURSOR;
2164 case RES_TYPE_DIALOG:
2165 if (extended_dialog (res->u.dialog))
2173 s = "8 /* RT_FONT */";
2177 case RES_TYPE_FONTDIR:
2178 s = "7 /* RT_FONTDIR */";
2183 s = "3 /* RT_ICON */";
2187 case RES_TYPE_GROUP_ICON:
2188 s = "14 /* RT_GROUP_ICON */";
2193 if (extended_menu (res->u.menu))
2206 case RES_TYPE_MESSAGETABLE:
2207 s = "11 /* RT_MESSAGETABLE */";
2208 rt = RT_MESSAGETABLE;
2211 case RES_TYPE_RCDATA:
2216 case RES_TYPE_STRINGTABLE:
2221 case RES_TYPE_USERDATA:
2226 case RES_TYPE_VERSIONINFO:
2231 case RES_TYPE_TOOLBAR:
2239 && (type->named || type->u.id != (unsigned long) rt))
2241 wr_printcomment (e, "Unexpected resource type mismatch: ");
2242 res_id_print (e, *type, 1);
2243 fprintf (e, " != %d", rt);
2246 if (res->coff_info.codepage != 0)
2247 wr_printcomment (e, "Code page: %u", res->coff_info.codepage);
2248 if (res->coff_info.reserved != 0)
2249 wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved);
2252 if (rt == RT_STRING)
2257 res_id_print (e, *name, 1);
2259 fprintf (e, "??Unknown-Name??");
2264 fprintf (e, "%s", s);
2265 else if (type != NULL)
2267 if (type->named == 0)
2269 #define PRINT_RT_NAME(NAME) case NAME: \
2270 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2276 res_id_print (e, *type, 0);
2279 PRINT_RT_NAME(RT_MANIFEST);
2280 PRINT_RT_NAME(RT_ANICURSOR);
2281 PRINT_RT_NAME(RT_ANIICON);
2282 PRINT_RT_NAME(RT_RCDATA);
2283 PRINT_RT_NAME(RT_ICON);
2284 PRINT_RT_NAME(RT_CURSOR);
2285 PRINT_RT_NAME(RT_BITMAP);
2286 PRINT_RT_NAME(RT_PLUGPLAY);
2287 PRINT_RT_NAME(RT_VXD);
2288 PRINT_RT_NAME(RT_FONT);
2289 PRINT_RT_NAME(RT_FONTDIR);
2290 PRINT_RT_NAME(RT_HTML);
2291 PRINT_RT_NAME(RT_MESSAGETABLE);
2292 PRINT_RT_NAME(RT_DLGINCLUDE);
2293 PRINT_RT_NAME(RT_DLGINIT);
2295 #undef PRINT_RT_NAME
2298 res_id_print (e, *type, 1);
2301 fprintf (e, "??Unknown-Type??");
2303 if (res->res_info.memflags != 0)
2305 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
2306 fprintf (e, " MOVEABLE");
2307 if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
2308 fprintf (e, " PURE");
2309 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
2310 fprintf (e, " PRELOAD");
2311 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
2312 fprintf (e, " DISCARDABLE");
2315 if (res->type == RES_TYPE_DIALOG)
2317 fprintf (e, " %d, %d, %d, %d",
2318 (int) res->u.dialog->x, (int) res->u.dialog->y,
2319 (int) res->u.dialog->width, (int) res->u.dialog->height);
2320 if (res->u.dialog->ex != NULL
2321 && res->u.dialog->ex->help != 0)
2322 fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help);
2324 else if (res->type == RES_TYPE_TOOLBAR)
2326 fprintf (e, " %d, %d", (int) res->u.toolbar->button_width,
2327 (int) res->u.toolbar->button_height);
2332 if ((res->res_info.language != 0 && res->res_info.language != *language)
2333 || res->res_info.characteristics != 0
2334 || res->res_info.version != 0)
2340 case RES_TYPE_ACCELERATOR:
2341 case RES_TYPE_DIALOG:
2343 case RES_TYPE_RCDATA:
2344 case RES_TYPE_STRINGTABLE:
2353 if (res->res_info.language != 0 && res->res_info.language != *language)
2354 fprintf (e, "%sLANGUAGE %d, %d\n",
2355 modifiers ? "// " : "",
2356 (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
2357 (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
2358 if (res->res_info.characteristics != 0)
2359 fprintf (e, "%sCHARACTERISTICS %u\n",
2360 modifiers ? "// " : "",
2361 (unsigned int) res->res_info.characteristics);
2362 if (res->res_info.version != 0)
2363 fprintf (e, "%sVERSION %u\n",
2364 modifiers ? "// " : "",
2365 (unsigned int) res->res_info.version);
2373 case RES_TYPE_ACCELERATOR:
2374 write_rc_accelerators (e, res->u.acc);
2377 case RES_TYPE_CURSOR:
2378 write_rc_cursor (e, res->u.cursor);
2381 case RES_TYPE_GROUP_CURSOR:
2382 write_rc_group_cursor (e, res->u.group_cursor);
2385 case RES_TYPE_DIALOG:
2386 write_rc_dialog (e, res->u.dialog);
2389 case RES_TYPE_FONTDIR:
2390 write_rc_fontdir (e, res->u.fontdir);
2393 case RES_TYPE_GROUP_ICON:
2394 write_rc_group_icon (e, res->u.group_icon);
2398 write_rc_menu (e, res->u.menu, menuex);
2401 case RES_TYPE_RCDATA:
2402 write_rc_rcdata (e, res->u.rcdata, 0);
2405 case RES_TYPE_STRINGTABLE:
2406 write_rc_stringtable (e, name, res->u.stringtable);
2409 case RES_TYPE_USERDATA:
2410 write_rc_rcdata (e, res->u.userdata, 0);
2413 case RES_TYPE_TOOLBAR:
2414 write_rc_toolbar (e, res->u.toolbar);
2417 case RES_TYPE_VERSIONINFO:
2418 write_rc_versioninfo (e, res->u.versioninfo);
2421 case RES_TYPE_BITMAP:
2424 write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0);
2426 case RES_TYPE_MESSAGETABLE:
2427 write_rc_messagetable (e, res->u.data.length, res->u.data.data);
2432 /* Write out accelerator information. */
2435 write_rc_accelerators (FILE *e, const rc_accelerator *accelerators)
2437 const rc_accelerator *acc;
2439 fprintf (e, "BEGIN\n");
2440 for (acc = accelerators; acc != NULL; acc = acc->next)
2446 if ((acc->key & 0x7f) == acc->key
2447 && ISPRINT (acc->key)
2448 && (acc->flags & ACC_VIRTKEY) == 0)
2450 fprintf (e, "\"%c\"", (char) acc->key);
2455 fprintf (e, "%d", (int) acc->key);
2459 fprintf (e, ", %d", (int) acc->id);
2463 if ((acc->flags & ACC_VIRTKEY) != 0)
2464 fprintf (e, ", VIRTKEY");
2466 fprintf (e, ", ASCII");
2469 if ((acc->flags & ACC_SHIFT) != 0)
2470 fprintf (e, ", SHIFT");
2471 if ((acc->flags & ACC_CONTROL) != 0)
2472 fprintf (e, ", CONTROL");
2473 if ((acc->flags & ACC_ALT) != 0)
2474 fprintf (e, ", ALT");
2479 fprintf (e, "END\n");
2482 /* Write out cursor information. This would normally be in a separate
2483 file, which the rc file would include. */
2486 write_rc_cursor (FILE *e, const rc_cursor *cursor)
2488 fprintf (e, "BEGIN\n");
2490 fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2491 (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot,
2492 (int) cursor->xhotspot, (int) cursor->yhotspot);
2493 write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data,
2495 fprintf (e, "END\n");
2498 /* Write out group cursor data. This would normally be built from the
2502 write_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor)
2504 const rc_group_cursor *gc;
2507 for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2509 fprintf (e, "BEGIN\n");
2512 fprintf (e, "0, 2, %d%s\t /* Having %d items. */\n", c, (c != 0 ? "," : ""), c);
2514 fprintf (e, "/* width, height, planes, bits, bytes, index. */\n");
2516 for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2519 fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2520 (int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits,
2521 (unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c);
2522 fprintf (e, "/* width: %d; height %d; planes %d; bits %d. */\n",
2523 (int) gc->width, (int) gc->height, (int) gc->planes,
2526 fprintf (e, "END\n");
2529 /* Write dialog data. */
2532 write_rc_dialog (FILE *e, const rc_dialog *dialog)
2534 const rc_dialog_control *control;
2536 fprintf (e, "STYLE 0x%x\n", dialog->style);
2538 if (dialog->exstyle != 0)
2539 fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle);
2541 if ((dialog->class.named && dialog->class.u.n.length > 0)
2542 || dialog->class.u.id != 0)
2544 fprintf (e, "CLASS ");
2545 res_id_print (e, dialog->class, 1);
2549 if (dialog->caption != NULL)
2551 fprintf (e, "CAPTION ");
2552 unicode_print_quoted (e, dialog->caption, -1);
2556 if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2557 || dialog->menu.u.id != 0)
2559 fprintf (e, "MENU ");
2560 res_id_print (e, dialog->menu, 0);
2564 if (dialog->font != NULL)
2566 fprintf (e, "FONT %d, ", (int) dialog->pointsize);
2567 unicode_print_quoted (e, dialog->font, -1);
2568 if (dialog->ex != NULL
2569 && (dialog->ex->weight != 0
2570 || dialog->ex->italic != 0
2571 || dialog->ex->charset != 1))
2572 fprintf (e, ", %d, %d, %d",
2573 (int) dialog->ex->weight,
2574 (int) dialog->ex->italic,
2575 (int) dialog->ex->charset);
2579 fprintf (e, "BEGIN\n");
2581 for (control = dialog->controls; control != NULL; control = control->next)
2582 write_rc_dialog_control (e, control);
2584 fprintf (e, "END\n");
2587 /* For each predefined control keyword, this table provides the class
2593 unsigned short class;
2594 unsigned long style;
2597 static const struct control_info control_info[] =
2599 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2600 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2601 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2602 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2603 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2604 { "CTEXT", CTL_STATIC, SS_CENTER },
2605 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2606 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2607 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2608 { "ICON", CTL_STATIC, SS_ICON },
2609 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2610 { "LTEXT", CTL_STATIC, SS_LEFT },
2611 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2612 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2613 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2614 { "RTEXT", CTL_STATIC, SS_RIGHT },
2615 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2616 { "STATE3", CTL_BUTTON, BS_3STATE },
2617 /* It's important that USERBUTTON come after all the other button
2618 types, so that it won't be matched too early. */
2619 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2623 /* Write a dialog control. */
2626 write_rc_dialog_control (FILE *e, const rc_dialog_control *control)
2628 const struct control_info *ci;
2632 if (control->class.named)
2636 for (ci = control_info; ci->name != NULL; ++ci)
2637 if (ci->class == control->class.u.id
2638 && (ci->style == (unsigned long) -1
2639 || ci->style == (control->style & 0xff)))
2643 fprintf (e, "CONTROL");
2644 else if (ci->name != NULL)
2645 fprintf (e, "%s", ci->name);
2648 fprintf (e, "CONTROL");
2652 /* For EDITTEXT, COMBOBOX, LISTBOX, and SCROLLBAR don't dump text. */
2653 if ((control->text.named || control->text.u.id != 0)
2655 || (ci->class != CTL_EDIT
2656 && ci->class != CTL_COMBOBOX
2657 && ci->class != CTL_LISTBOX
2658 && ci->class != CTL_SCROLLBAR)))
2661 res_id_print (e, control->text, 1);
2665 fprintf (e, " %d, ", (int) control->id);
2669 if (control->class.named)
2671 res_id_print (e, control->class, 0);
2672 if (control->class.named)
2674 fprintf (e, ", 0x%x, ", (unsigned int) control->style);
2677 fprintf (e, "%d, %d", (int) control->x, (int) control->y);
2679 if (control->style != SS_ICON
2680 || control->exstyle != 0
2681 || control->width != 0
2682 || control->height != 0
2683 || control->help != 0)
2685 fprintf (e, ", %d, %d", (int) control->width, (int) control->height);
2687 /* FIXME: We don't need to print the style if it is the default.
2688 More importantly, in certain cases we actually need to turn
2689 off parts of the forced style, by using NOT. */
2691 fprintf (e, ", 0x%x", (unsigned int) control->style);
2693 if (control->exstyle != 0 || control->help != 0)
2694 fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle,
2695 (unsigned int) control->help);
2700 if (control->data != NULL)
2701 write_rc_rcdata (e, control->data, 2);
2704 /* Write out font directory data. This would normally be built from
2708 write_rc_fontdir (FILE *e, const rc_fontdir *fontdir)
2710 const rc_fontdir *fc;
2713 for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++)
2715 fprintf (e, "BEGIN\n");
2717 fprintf (e, "%d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2718 for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++)
2721 fprintf (e, "%d,\t/* Font no %d with index %d. */\n",
2722 (int) fc->index, c, (int) fc->index);
2723 write_rc_datablock (e, (rc_uint_type) fc->length - 2,
2724 (const bfd_byte *) fc->data + 4,fc->next != NULL,
2727 fprintf (e, "END\n");
2730 /* Write out group icon data. This would normally be built from the
2734 write_rc_group_icon (FILE *e, const rc_group_icon *group_icon)
2736 const rc_group_icon *gi;
2739 for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++)
2742 fprintf (e, "BEGIN\n");
2744 fprintf (e, " 0, 1, %d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2747 fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2748 for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++)
2751 fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2752 gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits,
2753 (unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c);
2755 fprintf (e, "END\n");
2758 /* Write out a menu resource. */
2761 write_rc_menu (FILE *e, const rc_menu *menu, int menuex)
2763 if (menu->help != 0)
2764 fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help);
2765 write_rc_menuitems (e, menu->items, menuex, 0);
2769 write_rc_toolbar (FILE *e, const rc_toolbar *tb)
2771 rc_toolbar_item *it;
2773 fprintf (e, "BEGIN\n");
2778 if (it->id.u.id == 0)
2779 fprintf (e, "SEPARATOR\n");
2781 fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
2785 fprintf (e, "END\n");
2788 /* Write out menuitems. */
2791 write_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex,
2794 const rc_menuitem *mi;
2797 fprintf (e, "BEGIN\n");
2799 for (mi = menuitems; mi != NULL; mi = mi->next)
2801 indent (e, ind + 2);
2803 if (mi->popup == NULL)
2804 fprintf (e, "MENUITEM");
2806 fprintf (e, "POPUP");
2809 && mi->popup == NULL
2814 fprintf (e, " SEPARATOR\n");
2818 if (mi->text == NULL)
2819 fprintf (e, " \"\"");
2823 unicode_print_quoted (e, mi->text, -1);
2828 if (mi->popup == NULL)
2829 fprintf (e, ", %d", (int) mi->id);
2831 if ((mi->type & MENUITEM_CHECKED) != 0)
2832 fprintf (e, ", CHECKED");
2833 if ((mi->type & MENUITEM_GRAYED) != 0)
2834 fprintf (e, ", GRAYED");
2835 if ((mi->type & MENUITEM_HELP) != 0)
2836 fprintf (e, ", HELP");
2837 if ((mi->type & MENUITEM_INACTIVE) != 0)
2838 fprintf (e, ", INACTIVE");
2839 if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2840 fprintf (e, ", MENUBARBREAK");
2841 if ((mi->type & MENUITEM_MENUBREAK) != 0)
2842 fprintf (e, ", MENUBREAK");
2846 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2848 fprintf (e, ", %d", (int) mi->id);
2849 if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2851 fprintf (e, ", %u", (unsigned int) mi->type);
2852 if (mi->state != 0 || mi->help != 0)
2854 fprintf (e, ", %u", (unsigned int) mi->state);
2856 fprintf (e, ", %u", (unsigned int) mi->help);
2864 if (mi->popup != NULL)
2865 write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2869 fprintf (e, "END\n");
2873 test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
2876 if ((length & 1) != 0)
2879 for (i = 0; i < length; i += 2)
2881 if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2883 if (data[i] == 0xff && data[i + 1] == 0xff)
2890 test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2900 for (i = 0, c = 0; i < length; i++)
2902 if (! ISPRINT (data[i]) && data[i] != '\n'
2903 && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2905 && ! (data[i] == 0 && (i + 1) != length))
2911 else if (data[i] == '\n') has_nl++;
2913 if (length > 80 && ! has_nl)
2915 c = (((c * 10000) + (i / 100) - 1)) / i;
2922 write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
2925 const struct bin_messagetable *mt;
2926 fprintf (e, "BEGIN\n");
2928 write_rc_datablock (e, length, data, 0, 0, 0);
2931 wr_printcomment (e, "MC syntax dump");
2932 if (length < BIN_MESSAGETABLE_SIZE)
2937 mt = (const struct bin_messagetable *) data;
2938 m = windres_get_32 (&wrtarget, mt->cblocks, length);
2939 if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2944 for (i = 0; i < m; i++)
2946 rc_uint_type low, high, offset;
2947 const struct bin_messagetable_item *mti;
2949 low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2950 high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2951 offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2954 rc_uint_type elen, flags;
2955 if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2960 mti = (const struct bin_messagetable_item *) &data[offset];
2961 elen = windres_get_16 (&wrtarget, mti->length, 2);
2962 flags = windres_get_16 (&wrtarget, mti->flags, 2);
2963 if ((offset + elen) > length)
2968 wr_printcomment (e, "MessageId = 0x%x", low);
2969 wr_printcomment (e, "");
2970 if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2971 unicode_print (e, (const unichar *) mti->data,
2972 (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2974 ascii_print (e, (const char *) mti->data,
2975 (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2976 wr_printcomment (e,"");
2983 wr_printcomment (e, "Illegal data");
2985 fprintf (e, "END\n");
2989 write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
2990 int hasblock, int show_comment)
2995 fprintf (e, "BEGIN\n");
2997 if (show_comment == -1)
2999 if (test_rc_datablock_text(length, data))
3002 for (i = 0; i < length;)
3007 for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
3009 if (i < length && data[i] == '\n')
3011 ascii_print (e, (const char *) &data[i - c], c);
3020 fprintf (e, "\"\"");
3026 fprintf (e, "END\n");
3029 if (test_rc_datablock_unicode (length, data))
3032 for (i = 0; i < length;)
3036 u = (const unichar *) &data[i];
3040 for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
3042 if (i < length && u[c] == '\n')
3044 unicode_print (e, u, c);
3053 fprintf (e, "L\"\"");
3059 fprintf (e, "END\n");
3068 rc_uint_type i, max_row;
3071 max_row = (show_comment ? 4 : 8);
3073 for (i = 0; i + 3 < length;)
3076 rc_uint_type comment_start;
3083 for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
3086 plen = fprintf (e, "0x%lxL",
3087 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
3089 plen = fprintf (e, " 0x%lxL",
3090 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
3091 if (has_next || (i + 4) < length)
3093 if (plen>0 && plen < 11)
3094 indent (e, 11 - plen);
3100 fprintf (e, "\t/* ");
3101 ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3102 fprintf (e, ". */");
3112 plen = fprintf (e, "0x%x",
3113 (int) windres_get_16 (&wrtarget, data + i, length - i));
3114 if (has_next || i + 2 < length)
3116 if (plen > 0 && plen < 11)
3117 indent (e, 11 - plen);
3122 fprintf (e, "\t/* ");
3123 ascii_print (e, (const char *) &data[i], 2);
3124 fprintf (e, ". */");
3136 ascii_print (e, (const char *) &data[i], 1);
3145 fprintf (e, "END\n");
3148 /* Write out an rcdata resource. This is also used for other types of
3149 resources that need to print arbitrary data. */
3152 write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3154 const rc_rcdata_item *ri;
3157 fprintf (e, "BEGIN\n");
3159 for (ri = rcdata; ri != NULL; ri = ri->next)
3161 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3170 indent (e, ind + 2);
3171 fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3175 indent (e, ind + 2);
3176 fprintf (e, "%luL", (unsigned long) ri->u.dword);
3180 indent (e, ind + 2);
3182 ascii_print (e, ri->u.string.s, ri->u.string.length);
3186 case RCDATA_WSTRING:
3187 indent (e, ind + 2);
3189 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3194 write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3195 (const bfd_byte *) ri->u.buffer.data,
3196 ri->next != NULL, 0, -1);
3200 if (ri->type != RCDATA_BUFFER)
3202 if (ri->next != NULL)
3209 fprintf (e, "END\n");
3212 /* Write out a stringtable resource. */
3215 write_rc_stringtable (FILE *e, const rc_res_id *name,
3216 const rc_stringtable *stringtable)
3218 rc_uint_type offset;
3221 if (name != NULL && ! name->named)
3222 offset = (name->u.id - 1) << 4;
3225 fprintf (e, "/* %s string table name. */\n",
3226 name == NULL ? "Missing" : "Invalid");
3230 fprintf (e, "BEGIN\n");
3232 for (i = 0; i < 16; i++)
3234 if (stringtable->strings[i].length != 0)
3236 fprintf (e, " %lu, ", (unsigned long) offset + i);
3237 unicode_print_quoted (e, stringtable->strings[i].string,
3238 stringtable->strings[i].length);
3243 fprintf (e, "END\n");
3246 /* Write out a versioninfo resource. */
3249 write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
3251 const rc_fixed_versioninfo *f;
3252 const rc_ver_info *vi;
3254 f = versioninfo->fixed;
3255 if (f->file_version_ms != 0 || f->file_version_ls != 0)
3256 fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3257 (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3258 (unsigned int) (f->file_version_ms & 0xffff),
3259 (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3260 (unsigned int) (f->file_version_ls & 0xffff));
3261 if (f->product_version_ms != 0 || f->product_version_ls != 0)
3262 fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3263 (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3264 (unsigned int) (f->product_version_ms & 0xffff),
3265 (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3266 (unsigned int) (f->product_version_ls & 0xffff));
3267 if (f->file_flags_mask != 0)
3268 fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
3269 if (f->file_flags != 0)
3270 fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
3271 if (f->file_os != 0)
3272 fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
3273 if (f->file_type != 0)
3274 fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
3275 if (f->file_subtype != 0)
3276 fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
3277 if (f->file_date_ms != 0 || f->file_date_ls != 0)
3278 fprintf (e, "/* Date: %u, %u. */\n",
3279 (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
3281 fprintf (e, "BEGIN\n");
3283 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3287 case VERINFO_STRING:
3289 const rc_ver_stringtable *vst;
3290 const rc_ver_stringinfo *vs;
3292 fprintf (e, " BLOCK \"StringFileInfo\"\n");
3293 fprintf (e, " BEGIN\n");
3295 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
3297 fprintf (e, " BLOCK ");
3298 unicode_print_quoted (e, vst->language, -1);
3301 fprintf (e, " BEGIN\n");
3303 for (vs = vst->strings; vs != NULL; vs = vs->next)
3305 fprintf (e, " VALUE ");
3306 unicode_print_quoted (e, vs->key, -1);
3308 unicode_print_quoted (e, vs->value, -1);
3312 fprintf (e, " END\n");
3314 fprintf (e, " END\n");
3320 const rc_ver_varinfo *vv;
3322 fprintf (e, " BLOCK \"VarFileInfo\"\n");
3323 fprintf (e, " BEGIN\n");
3324 fprintf (e, " VALUE ");
3325 unicode_print_quoted (e, vi->u.var.key, -1);
3327 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3328 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3331 fprintf (e, "\n END\n");
3338 fprintf (e, "END\n");
3342 rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
3350 windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3354 windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3357 if (dst && src->u.string.length)
3358 memcpy (dst, src->u.string.s, src->u.string.length);
3359 return (rc_uint_type) src->u.string.length;
3360 case RCDATA_WSTRING:
3361 if (dst && src->u.wstring.length)
3362 memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3363 return (rc_uint_type) (src->u.wstring.length * sizeof (unichar));
3365 if (dst && src->u.buffer.length)
3366 memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3367 return (rc_uint_type) src->u.buffer.length;
3371 /* Never reached. */