1 /* resrc.c -- read and write Windows rc files.
2 Copyright (C) 1997-2016 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;
2927 fprintf (e, "BEGIN\n");
2929 write_rc_datablock (e, length, data, 0, 0, 0);
2932 wr_printcomment (e, "MC syntax dump");
2933 if (length < BIN_MESSAGETABLE_SIZE)
2940 mt = (const struct bin_messagetable *) data;
2941 m = windres_get_32 (&wrtarget, mt->cblocks, length);
2943 if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2948 for (i = 0; i < m; i++)
2950 rc_uint_type low, high, offset;
2951 const struct bin_messagetable_item *mti;
2953 low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2954 high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2955 offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2959 rc_uint_type elen, flags;
2960 if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2965 mti = (const struct bin_messagetable_item *) &data[offset];
2966 elen = windres_get_16 (&wrtarget, mti->length, 2);
2967 flags = windres_get_16 (&wrtarget, mti->flags, 2);
2968 if ((offset + elen) > length)
2973 wr_printcomment (e, "MessageId = 0x%x", low);
2974 wr_printcomment (e, "");
2976 if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2978 /* PR 17512: file: 5c3232dc. */
2979 if (elen > BIN_MESSAGETABLE_ITEM_SIZE * 2)
2980 unicode_print (e, (const unichar *) mti->data,
2981 (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2985 if (elen > BIN_MESSAGETABLE_ITEM_SIZE)
2986 ascii_print (e, (const char *) mti->data,
2987 (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2990 wr_printcomment (e,"");
2999 wr_printcomment (e, "Illegal data");
3001 fprintf (e, "END\n");
3005 write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
3006 int hasblock, int show_comment)
3011 fprintf (e, "BEGIN\n");
3013 if (show_comment == -1)
3015 if (test_rc_datablock_text(length, data))
3018 for (i = 0; i < length;)
3023 for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
3025 if (i < length && data[i] == '\n')
3027 ascii_print(e, (const char *) &data[i - c], c);
3036 fprintf (e, "\"\"");
3042 fprintf (e, "END\n");
3045 if (test_rc_datablock_unicode (length, data))
3048 for (i = 0; i < length;)
3052 u = (const unichar *) &data[i];
3056 for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
3058 if (i < length && u[c] == '\n')
3060 unicode_print (e, u, c);
3069 fprintf (e, "L\"\"");
3075 fprintf (e, "END\n");
3084 rc_uint_type i, max_row;
3087 max_row = (show_comment ? 4 : 8);
3089 for (i = 0; i + 3 < length;)
3092 rc_uint_type comment_start;
3099 for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
3102 plen = fprintf (e, "0x%lxL",
3103 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
3105 plen = fprintf (e, " 0x%lxL",
3106 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
3107 if (has_next || (i + 4) < length)
3109 if (plen>0 && plen < 11)
3110 indent (e, 11 - plen);
3116 fprintf (e, "\t/* ");
3117 ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3118 fprintf (e, ". */");
3128 plen = fprintf (e, "0x%x",
3129 (int) windres_get_16 (&wrtarget, data + i, length - i));
3130 if (has_next || i + 2 < length)
3132 if (plen > 0 && plen < 11)
3133 indent (e, 11 - plen);
3138 fprintf (e, "\t/* ");
3139 ascii_print (e, (const char *) &data[i], 2);
3140 fprintf (e, ". */");
3152 ascii_print (e, (const char *) &data[i], 1);
3161 fprintf (e, "END\n");
3164 /* Write out an rcdata resource. This is also used for other types of
3165 resources that need to print arbitrary data. */
3168 write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3170 const rc_rcdata_item *ri;
3173 fprintf (e, "BEGIN\n");
3175 for (ri = rcdata; ri != NULL; ri = ri->next)
3177 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3186 indent (e, ind + 2);
3187 fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3191 indent (e, ind + 2);
3192 fprintf (e, "%luL", (unsigned long) ri->u.dword);
3196 indent (e, ind + 2);
3198 ascii_print (e, ri->u.string.s, ri->u.string.length);
3202 case RCDATA_WSTRING:
3203 indent (e, ind + 2);
3205 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3210 write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3211 (const bfd_byte *) ri->u.buffer.data,
3212 ri->next != NULL, 0, -1);
3216 if (ri->type != RCDATA_BUFFER)
3218 if (ri->next != NULL)
3225 fprintf (e, "END\n");
3228 /* Write out a stringtable resource. */
3231 write_rc_stringtable (FILE *e, const rc_res_id *name,
3232 const rc_stringtable *stringtable)
3234 rc_uint_type offset;
3237 if (name != NULL && ! name->named)
3238 offset = (name->u.id - 1) << 4;
3241 fprintf (e, "/* %s string table name. */\n",
3242 name == NULL ? "Missing" : "Invalid");
3246 fprintf (e, "BEGIN\n");
3248 for (i = 0; i < 16; i++)
3250 if (stringtable->strings[i].length != 0)
3252 fprintf (e, " %lu, ", (unsigned long) offset + i);
3253 unicode_print_quoted (e, stringtable->strings[i].string,
3254 stringtable->strings[i].length);
3259 fprintf (e, "END\n");
3262 /* Write out a versioninfo resource. */
3265 write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
3267 const rc_fixed_versioninfo *f;
3268 const rc_ver_info *vi;
3270 f = versioninfo->fixed;
3271 if (f->file_version_ms != 0 || f->file_version_ls != 0)
3272 fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3273 (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3274 (unsigned int) (f->file_version_ms & 0xffff),
3275 (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3276 (unsigned int) (f->file_version_ls & 0xffff));
3277 if (f->product_version_ms != 0 || f->product_version_ls != 0)
3278 fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3279 (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3280 (unsigned int) (f->product_version_ms & 0xffff),
3281 (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3282 (unsigned int) (f->product_version_ls & 0xffff));
3283 if (f->file_flags_mask != 0)
3284 fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
3285 if (f->file_flags != 0)
3286 fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
3287 if (f->file_os != 0)
3288 fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
3289 if (f->file_type != 0)
3290 fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
3291 if (f->file_subtype != 0)
3292 fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
3293 if (f->file_date_ms != 0 || f->file_date_ls != 0)
3294 fprintf (e, "/* Date: %u, %u. */\n",
3295 (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
3297 fprintf (e, "BEGIN\n");
3299 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3303 case VERINFO_STRING:
3305 const rc_ver_stringtable *vst;
3306 const rc_ver_stringinfo *vs;
3308 fprintf (e, " BLOCK \"StringFileInfo\"\n");
3309 fprintf (e, " BEGIN\n");
3311 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
3313 fprintf (e, " BLOCK ");
3314 unicode_print_quoted (e, vst->language, -1);
3317 fprintf (e, " BEGIN\n");
3319 for (vs = vst->strings; vs != NULL; vs = vs->next)
3321 fprintf (e, " VALUE ");
3322 unicode_print_quoted (e, vs->key, -1);
3324 unicode_print_quoted (e, vs->value, -1);
3328 fprintf (e, " END\n");
3330 fprintf (e, " END\n");
3336 const rc_ver_varinfo *vv;
3338 fprintf (e, " BLOCK \"VarFileInfo\"\n");
3339 fprintf (e, " BEGIN\n");
3340 fprintf (e, " VALUE ");
3341 unicode_print_quoted (e, vi->u.var.key, -1);
3343 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3344 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3347 fprintf (e, "\n END\n");
3354 fprintf (e, "END\n");
3358 rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
3366 windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3370 windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3373 if (dst && src->u.string.length)
3374 memcpy (dst, src->u.string.s, src->u.string.length);
3375 return (rc_uint_type) src->u.string.length;
3376 case RCDATA_WSTRING:
3377 if (dst && src->u.wstring.length)
3378 memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3379 return (rc_uint_type) (src->u.wstring.length * sizeof (unichar));
3381 if (dst && src->u.buffer.length)
3382 memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3383 return (rc_uint_type) src->u.buffer.length;
3387 /* Never reached. */