1 /* resrc.c -- read and write Windows rc files.
2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2011
3 Free Software Foundation, Inc.
4 Written by Ian Lance Taylor, Cygnus Support.
5 Rewritten by Kai Tietz, Onevision.
7 This file is part of GNU Binutils.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
24 /* This file contains functions that read and write Windows rc files.
25 These are text files that represent resources. */
30 #include "libiberty.h"
31 #include "safe-ctype.h"
41 #ifdef HAVE_SYS_WAIT_H
43 #else /* ! HAVE_SYS_WAIT_H */
44 #if ! defined (_WIN32) || defined (__CYGWIN__)
46 #define WIFEXITED(w) (((w)&0377) == 0)
49 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
52 #define WTERMSIG(w) ((w) & 0177)
55 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
57 #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
59 #define WIFEXITED(w) (((w) & 0xff) == 0)
62 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
65 #define WTERMSIG(w) ((w) & 0x7f)
68 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
70 #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
71 #endif /* ! HAVE_SYS_WAIT_H */
74 #define STDOUT_FILENO 1
77 #if defined (_WIN32) && ! defined (__CYGWIN__)
79 #define pclose _pclose
82 /* The default preprocessor. */
84 #define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
86 /* We read the directory entries in a cursor or icon file into
87 instances of this structure. */
93 /* Height of image. */
95 /* Number of colors in image. */
102 unsigned short planes
;
103 /* Bits per pixel. */
108 /* X coordinate of hotspot. */
109 unsigned short xhotspot
;
110 /* Y coordinate of hotspot. */
111 unsigned short yhotspot
;
114 /* Bytes in image. */
116 /* File offset of image. */
117 unsigned long offset
;
120 /* The name of the rc file we are reading. */
124 /* The line number in the rc file. */
128 /* The pipe we are reading from, so that we can close it if we exit. */
132 /* The temporary file used if we're not using popen, so we can delete it
135 static char *cpp_temp_file
;
137 /* Input stream is either a file or a pipe. */
139 static enum {ISTREAM_PIPE
, ISTREAM_FILE
} istream_type
;
141 /* As we read the rc file, we attach information to this structure. */
143 static rc_res_directory
*resources
;
145 /* The number of cursor resources we have written out. */
149 /* The number of font resources we have written out. */
153 /* Font directory information. */
155 rc_fontdir
*fontdirs
;
157 /* Resource info to use for fontdirs. */
159 rc_res_res_info fontdirs_resinfo
;
161 /* The number of icon resources we have written out. */
165 /* The windres target bfd . */
167 static windres_bfd wrtarget
=
169 (bfd
*) NULL
, (asection
*) NULL
, WR_KIND_TARGET
172 /* Local functions for rcdata based resource definitions. */
174 static void define_font_rcdata (rc_res_id
, const rc_res_res_info
*,
176 static void define_icon_rcdata (rc_res_id
, const rc_res_res_info
*,
178 static void define_bitmap_rcdata (rc_res_id
, const rc_res_res_info
*,
180 static void define_cursor_rcdata (rc_res_id
, const rc_res_res_info
*,
182 static void define_fontdir_rcdata (rc_res_id
, const rc_res_res_info
*,
184 static void define_messagetable_rcdata (rc_res_id
, const rc_res_res_info
*,
186 static rc_uint_type
rcdata_copy (const rc_rcdata_item
*, bfd_byte
*);
187 static bfd_byte
*rcdata_render_as_buffer (const rc_rcdata_item
*, rc_uint_type
*);
189 static int run_cmd (char *, const char *);
190 static FILE *open_input_stream (char *);
191 static FILE *look_for_default
192 (char *, const char *, int, const char *, const char *);
193 static void close_input_stream (void);
194 static void unexpected_eof (const char *);
195 static int get_word (FILE *, const char *);
196 static unsigned long get_long (FILE *, const char *);
197 static void get_data (FILE *, bfd_byte
*, rc_uint_type
, const char *);
198 static void define_fontdirs (void);
200 /* Run `cmd' and redirect the output to `redir'. */
203 run_cmd (char *cmd
, const char *redir
)
206 int pid
, wait_status
, retcode
;
209 char *errmsg_fmt
, *errmsg_arg
;
210 char *temp_base
= choose_temp_base ();
213 int redir_handle
= -1;
214 int stdout_save
= -1;
216 /* Count the args. */
219 for (s
= cmd
; *s
; s
++)
224 argv
= alloca (sizeof (char *) * (i
+ 3));
230 while (*s
== ' ' && *s
!= 0)
236 in_quote
= (*s
== '\'' || *s
== '"');
237 sep
= (in_quote
) ? *s
++ : ' ';
240 while (*s
!= sep
&& *s
!= 0)
253 /* Setup the redirection. We can't use the usual fork/exec and redirect
254 since we may be running on non-POSIX Windows host. */
259 /* Open temporary output file. */
260 redir_handle
= open (redir
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0666);
261 if (redir_handle
== -1)
262 fatal (_("can't open temporary file `%s': %s"), redir
,
265 /* Duplicate the stdout file handle so it can be restored later. */
266 stdout_save
= dup (STDOUT_FILENO
);
267 if (stdout_save
== -1)
268 fatal (_("can't redirect stdout: `%s': %s"), redir
, strerror (errno
));
270 /* Redirect stdout to our output file. */
271 dup2 (redir_handle
, STDOUT_FILENO
);
273 pid
= pexecute (argv
[0], (char * const *) argv
, program_name
, temp_base
,
274 &errmsg_fmt
, &errmsg_arg
, PEXECUTE_ONE
| PEXECUTE_SEARCH
);
276 /* Restore stdout to its previous setting. */
277 dup2 (stdout_save
, STDOUT_FILENO
);
279 /* Close response file. */
280 close (redir_handle
);
284 fatal ("%s %s: %s", errmsg_fmt
, errmsg_arg
, strerror (errno
));
289 pid
= pwait (pid
, &wait_status
, 0);
293 fatal (_("wait: %s"), strerror (errno
));
296 else if (WIFSIGNALED (wait_status
))
298 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status
));
301 else if (WIFEXITED (wait_status
))
303 if (WEXITSTATUS (wait_status
) != 0)
305 fatal (_("%s exited with status %d"), cmd
,
306 WEXITSTATUS (wait_status
));
317 open_input_stream (char *cmd
)
319 if (istream_type
== ISTREAM_FILE
)
323 fileprefix
= choose_temp_base ();
324 cpp_temp_file
= (char *) xmalloc (strlen (fileprefix
) + 5);
325 sprintf (cpp_temp_file
, "%s.irc", fileprefix
);
328 if (run_cmd (cmd
, cpp_temp_file
))
329 fatal (_("can't execute `%s': %s"), cmd
, strerror (errno
));
331 cpp_pipe
= fopen (cpp_temp_file
, FOPEN_RT
);;
332 if (cpp_pipe
== NULL
)
333 fatal (_("can't open temporary file `%s': %s"),
334 cpp_temp_file
, strerror (errno
));
338 _("Using temporary file `%s' to read preprocessor output\n"),
343 cpp_pipe
= popen (cmd
, FOPEN_RT
);
344 if (cpp_pipe
== NULL
)
345 fatal (_("can't popen `%s': %s"), cmd
, strerror (errno
));
347 fprintf (stderr
, _("Using popen to read preprocessor output\n"));
350 xatexit (close_input_stream
);
354 /* Determine if FILENAME contains special characters that
355 can cause problems unless the entire filename is quoted. */
358 filename_need_quotes (const char *filename
)
360 if (filename
== NULL
|| (filename
[0] == '-' && filename
[1] == 0))
363 while (*filename
!= 0)
380 /* Look for the preprocessor program. */
383 look_for_default (char *cmd
, const char *prefix
, int end_prefix
,
384 const char *preprocargs
, const char *filename
)
389 const char *fnquotes
= (filename_need_quotes (filename
) ? "\"" : "");
391 strcpy (cmd
, prefix
);
393 sprintf (cmd
+ end_prefix
, "%s", DEFAULT_PREPROCESSOR
);
394 space
= strchr (cmd
+ end_prefix
, ' ');
399 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
400 strchr (cmd
, '\\') ||
404 found
= (stat (cmd
, &s
) == 0
405 #ifdef HAVE_EXECUTABLE_SUFFIX
406 || stat (strcat (cmd
, EXECUTABLE_SUFFIX
), &s
) == 0
413 fprintf (stderr
, _("Tried `%s'\n"), cmd
);
418 strcpy (cmd
, prefix
);
420 sprintf (cmd
+ end_prefix
, "%s %s %s%s%s",
421 DEFAULT_PREPROCESSOR
, preprocargs
, fnquotes
, filename
, fnquotes
);
424 fprintf (stderr
, _("Using `%s'\n"), cmd
);
426 cpp_pipe
= open_input_stream (cmd
);
430 /* Read an rc file. */
433 read_rc_file (const char *filename
, const char *preprocessor
,
434 const char *preprocargs
, int language
, int use_temp_file
)
437 const char *fnquotes
= (filename_need_quotes (filename
) ? "\"" : "");
439 if (filename
== NULL
)
441 /* Setup the default resource import path taken from input file. */
442 else if (strchr (filename
, '/') != NULL
|| strchr (filename
, '\\') != NULL
)
446 if (filename
[0] == '/'
447 || filename
[0] == '\\'
448 || filename
[1] == ':')
450 edit
= dir
= xstrdup (filename
);
454 edit
= dir
= xmalloc (strlen (filename
) + 3);
455 sprintf (dir
, "./%s", filename
);
458 /* Walk dir backwards stopping at the first directory separator. */
459 edit
+= strlen (dir
);
460 while (edit
> dir
&& (edit
[-1] != '\\' && edit
[-1] != '/'))
466 /* Cut off trailing slash. */
470 /* Convert all back slashes to forward slashes. */
471 while ((edit
= strchr (dir
, '\\')) != NULL
)
474 windres_add_include_dir (dir
);
477 istream_type
= (use_temp_file
) ? ISTREAM_FILE
: ISTREAM_PIPE
;
479 if (preprocargs
== NULL
)
484 cmd
= xmalloc (strlen (preprocessor
)
485 + strlen (preprocargs
)
487 + strlen (fnquotes
) * 2
489 sprintf (cmd
, "%s %s %s%s%s", preprocessor
, preprocargs
,
490 fnquotes
, filename
, fnquotes
);
492 cpp_pipe
= open_input_stream (cmd
);
496 char *dash
, *slash
, *cp
;
498 preprocessor
= DEFAULT_PREPROCESSOR
;
500 cmd
= xmalloc (strlen (program_name
)
501 + strlen (preprocessor
)
502 + strlen (preprocargs
)
504 + strlen (fnquotes
) * 2
505 #ifdef HAVE_EXECUTABLE_SUFFIX
506 + strlen (EXECUTABLE_SUFFIX
)
512 for (cp
= program_name
; *cp
; cp
++)
517 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
518 *cp
== ':' || *cp
== '\\' ||
531 /* First, try looking for a prefixed gcc in the windres
532 directory, with the same prefix as windres */
534 cpp_pipe
= look_for_default (cmd
, program_name
, dash
- program_name
+ 1,
535 preprocargs
, filename
);
538 if (slash
&& ! cpp_pipe
)
540 /* Next, try looking for a gcc in the same directory as
543 cpp_pipe
= look_for_default (cmd
, program_name
, slash
- program_name
+ 1,
544 preprocargs
, filename
);
549 /* Sigh, try the default */
551 cpp_pipe
= look_for_default (cmd
, "", 0, preprocargs
, filename
);
558 rc_filename
= xstrdup (filename
);
561 rcparse_set_language (language
);
563 rcparse_discard_strings ();
565 close_input_stream ();
567 if (fontdirs
!= NULL
)
576 /* Close the input stream if it is open. */
579 close_input_stream (void)
581 if (istream_type
== ISTREAM_FILE
)
583 if (cpp_pipe
!= NULL
)
586 if (cpp_temp_file
!= NULL
)
588 int errno_save
= errno
;
590 unlink (cpp_temp_file
);
592 free (cpp_temp_file
);
597 if (cpp_pipe
!= NULL
)
600 err
= pclose (cpp_pipe
);
601 /* We are reading from a pipe, therefore we don't
602 know if cpp failed or succeeded until pclose. */
603 if (err
!= 0 || errno
== ECHILD
)
605 /* Since this is also run via xatexit, safeguard. */
607 cpp_temp_file
= NULL
;
608 fatal (_("preprocessing failed."));
613 /* Since this is also run via xatexit, safeguard. */
615 cpp_temp_file
= NULL
;
618 /* Report an error while reading an rc file. */
621 yyerror (const char *msg
)
623 fatal ("%s:%d: %s", rc_filename
, rc_lineno
, msg
);
626 /* Issue a warning while reading an rc file. */
629 rcparse_warning (const char *msg
)
631 fprintf (stderr
, "%s:%d: %s\n", rc_filename
, rc_lineno
, msg
);
634 /* Die if we get an unexpected end of file. */
637 unexpected_eof (const char *msg
)
639 fatal (_("%s: unexpected EOF"), msg
);
642 /* Read a 16 bit word from a file. The data is assumed to be little
646 get_word (FILE *e
, const char *msg
)
653 unexpected_eof (msg
);
654 return ((b2
& 0xff) << 8) | (b1
& 0xff);
657 /* Read a 32 bit word from a file. The data is assumed to be little
661 get_long (FILE *e
, const char *msg
)
670 unexpected_eof (msg
);
671 return (((((((b4
& 0xff) << 8)
677 /* Read data from a file. This is a wrapper to do error checking. */
680 get_data (FILE *e
, bfd_byte
*p
, rc_uint_type c
, const char *msg
)
682 rc_uint_type got
; // $$$d
684 got
= (rc_uint_type
) fread (p
, 1, c
, e
);
688 fatal (_("%s: read of %lu returned %lu"),
689 msg
, (unsigned long) c
, (unsigned long) got
);
692 /* Define an accelerator resource. */
695 define_accelerator (rc_res_id id
, const rc_res_res_info
*resinfo
,
696 rc_accelerator
*data
)
700 r
= define_standard_resource (&resources
, RT_ACCELERATOR
, id
,
701 resinfo
->language
, 0);
702 r
->type
= RES_TYPE_ACCELERATOR
;
704 r
->res_info
= *resinfo
;
707 /* Define a bitmap resource. Bitmap data is stored in a file. The
708 first 14 bytes of the file are a standard header, which is not
709 included in the resource data. */
711 #define BITMAP_SKIP (14)
714 define_bitmap (rc_res_id id
, const rc_res_res_info
*resinfo
,
715 const char *filename
)
724 e
= open_file_search (filename
, FOPEN_RB
, "bitmap file", &real_filename
);
726 if (stat (real_filename
, &s
) < 0)
727 fatal (_("stat failed on bitmap file `%s': %s"), real_filename
,
730 data
= (bfd_byte
*) res_alloc (s
.st_size
- BITMAP_SKIP
);
732 for (i
= 0; i
< BITMAP_SKIP
; i
++)
735 get_data (e
, data
, s
.st_size
- BITMAP_SKIP
, real_filename
);
738 free (real_filename
);
740 r
= define_standard_resource (&resources
, RT_BITMAP
, id
,
741 resinfo
->language
, 0);
743 r
->type
= RES_TYPE_BITMAP
;
744 r
->u
.data
.length
= s
.st_size
- BITMAP_SKIP
;
745 r
->u
.data
.data
= data
;
746 r
->res_info
= *resinfo
;
749 /* Define a cursor resource. A cursor file may contain a set of
750 bitmaps, each representing the same cursor at various different
751 resolutions. They each get written out with a different ID. The
752 real cursor resource is then a group resource which can be used to
753 select one of the actual cursors. */
756 define_cursor (rc_res_id id
, const rc_res_res_info
*resinfo
,
757 const char *filename
)
762 struct icondir
*icondirs
;
765 rc_group_cursor
*first
, **pp
;
767 e
= open_file_search (filename
, FOPEN_RB
, "cursor file", &real_filename
);
769 /* A cursor file is basically an icon file. The start of the file
770 is a three word structure. The first word is ignored. The
771 second word is the type of data. The third word is the number of
774 get_word (e
, real_filename
);
775 type
= get_word (e
, real_filename
);
776 count
= get_word (e
, real_filename
);
778 fatal (_("cursor file `%s' does not contain cursor data"), real_filename
);
780 /* Read in the icon directory entries. */
782 icondirs
= (struct icondir
*) xmalloc (count
* sizeof *icondirs
);
784 for (i
= 0; i
< count
; i
++)
786 icondirs
[i
].width
= getc (e
);
787 icondirs
[i
].height
= getc (e
);
788 icondirs
[i
].colorcount
= getc (e
);
790 icondirs
[i
].u
.cursor
.xhotspot
= get_word (e
, real_filename
);
791 icondirs
[i
].u
.cursor
.yhotspot
= get_word (e
, real_filename
);
792 icondirs
[i
].bytes
= get_long (e
, real_filename
);
793 icondirs
[i
].offset
= get_long (e
, real_filename
);
796 unexpected_eof (real_filename
);
799 /* Define each cursor as a unique resource. */
801 first_cursor
= cursors
;
803 for (i
= 0; i
< count
; i
++)
809 if (fseek (e
, icondirs
[i
].offset
, SEEK_SET
) != 0)
810 fatal (_("%s: fseek to %lu failed: %s"), real_filename
,
811 icondirs
[i
].offset
, strerror (errno
));
813 data
= (bfd_byte
*) res_alloc (icondirs
[i
].bytes
);
815 get_data (e
, data
, icondirs
[i
].bytes
, real_filename
);
817 c
= (rc_cursor
*) res_alloc (sizeof (rc_cursor
));
818 c
->xhotspot
= icondirs
[i
].u
.cursor
.xhotspot
;
819 c
->yhotspot
= icondirs
[i
].u
.cursor
.yhotspot
;
820 c
->length
= icondirs
[i
].bytes
;
828 r
= define_standard_resource (&resources
, RT_CURSOR
, name
,
829 resinfo
->language
, 0);
830 r
->type
= RES_TYPE_CURSOR
;
832 r
->res_info
= *resinfo
;
836 free (real_filename
);
838 /* Define a cursor group resource. */
842 for (i
= 0; i
< count
; i
++)
846 cg
= (rc_group_cursor
*) res_alloc (sizeof (rc_group_cursor
));
848 cg
->width
= icondirs
[i
].width
;
849 cg
->height
= 2 * icondirs
[i
].height
;
851 /* FIXME: What should these be set to? */
855 cg
->bytes
= icondirs
[i
].bytes
+ 4;
856 cg
->index
= first_cursor
+ i
+ 1;
864 r
= define_standard_resource (&resources
, RT_GROUP_CURSOR
, id
,
865 resinfo
->language
, 0);
866 r
->type
= RES_TYPE_GROUP_CURSOR
;
867 r
->u
.group_cursor
= first
;
868 r
->res_info
= *resinfo
;
871 /* Define a dialog resource. */
874 define_dialog (rc_res_id id
, const rc_res_res_info
*resinfo
,
875 const rc_dialog
*dialog
)
880 copy
= (rc_dialog
*) res_alloc (sizeof *copy
);
883 r
= define_standard_resource (&resources
, RT_DIALOG
, id
,
884 resinfo
->language
, 0);
885 r
->type
= RES_TYPE_DIALOG
;
887 r
->res_info
= *resinfo
;
890 /* Define a dialog control. This does not define a resource, but
891 merely allocates and fills in a structure. */
894 define_control (const rc_res_id iid
, rc_uint_type id
, rc_uint_type x
,
895 rc_uint_type y
, rc_uint_type width
, rc_uint_type height
,
896 const rc_res_id
class, rc_uint_type style
,
897 rc_uint_type exstyle
)
899 rc_dialog_control
*n
;
901 n
= (rc_dialog_control
*) res_alloc (sizeof (rc_dialog_control
));
905 n
->exstyle
= exstyle
;
919 define_icon_control (rc_res_id iid
, rc_uint_type id
, rc_uint_type x
,
920 rc_uint_type y
, rc_uint_type style
,
921 rc_uint_type exstyle
, rc_uint_type help
,
922 rc_rcdata_item
*data
, rc_dialog_ex
*ex
)
924 rc_dialog_control
*n
;
929 style
= SS_ICON
| WS_CHILD
| WS_VISIBLE
;
930 res_string_to_id (&tid
, "");
932 cid
.u
.id
= CTL_STATIC
;
933 n
= define_control (tid
, id
, x
, y
, 0, 0, cid
, style
, exstyle
);
936 rcparse_warning (_("help ID requires DIALOGEX"));
938 rcparse_warning (_("control data requires DIALOGEX"));
945 /* Define a font resource. */
948 define_font (rc_res_id id
, const rc_res_res_info
*resinfo
,
949 const char *filename
)
960 const char *device
, *face
;
963 e
= open_file_search (filename
, FOPEN_RB
, "font file", &real_filename
);
965 if (stat (real_filename
, &s
) < 0)
966 fatal (_("stat failed on font file `%s': %s"), real_filename
,
969 data
= (bfd_byte
*) res_alloc (s
.st_size
);
971 get_data (e
, data
, s
.st_size
, real_filename
);
974 free (real_filename
);
976 r
= define_standard_resource (&resources
, RT_FONT
, id
,
977 resinfo
->language
, 0);
979 r
->type
= RES_TYPE_FONT
;
980 r
->u
.data
.length
= s
.st_size
;
981 r
->u
.data
.data
= data
;
982 r
->res_info
= *resinfo
;
984 /* For each font resource, we must add an entry in the FONTDIR
985 resource. The FONTDIR resource includes some strings in the font
986 file. To find them, we have to do some magic on the data we have
989 offset
= ((((((data
[47] << 8)
993 if (offset
> 0 && offset
< s
.st_size
)
994 device
= (char *) data
+ offset
;
998 offset
= ((((((data
[51] << 8)
1002 if (offset
> 0 && offset
< s
.st_size
)
1003 face
= (char *) data
+ offset
;
1009 fontdatalength
= 58 + strlen (device
) + strlen (face
);
1010 fontdata
= (bfd_byte
*) res_alloc (fontdatalength
);
1011 memcpy (fontdata
, data
, 56);
1012 strcpy ((char *) fontdata
+ 56, device
);
1013 strcpy ((char *) fontdata
+ 57 + strlen (device
), face
);
1015 fd
= (rc_fontdir
*) res_alloc (sizeof (rc_fontdir
));
1018 fd
->length
= fontdatalength
;
1019 fd
->data
= fontdata
;
1021 for (pp
= &fontdirs
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1025 /* For the single fontdirs resource, we always use the resource
1026 information of the last font. I don't know what else to do. */
1027 fontdirs_resinfo
= *resinfo
;
1031 define_font_rcdata (rc_res_id id
,const rc_res_res_info
*resinfo
,
1032 rc_rcdata_item
*data
)
1035 rc_uint_type len_data
;
1038 r
= define_standard_resource (&resources
, RT_FONT
, id
,
1039 resinfo
->language
, 0);
1041 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1043 r
->type
= RES_TYPE_FONT
;
1044 r
->u
.data
.length
= len_data
;
1045 r
->u
.data
.data
= pb_data
;
1046 r
->res_info
= *resinfo
;
1049 /* Define the fontdirs resource. This is called after the entire rc
1050 file has been parsed, if any font resources were seen. */
1053 define_fontdirs (void)
1061 r
= define_standard_resource (&resources
, RT_FONTDIR
, id
, 0x409, 0);
1063 r
->type
= RES_TYPE_FONTDIR
;
1064 r
->u
.fontdir
= fontdirs
;
1065 r
->res_info
= fontdirs_resinfo
;
1069 rcdata_render_as_buffer (const rc_rcdata_item
*data
, rc_uint_type
*plen
)
1071 const rc_rcdata_item
*d
;
1072 bfd_byte
*ret
= NULL
, *pret
;
1073 rc_uint_type len
= 0;
1075 for (d
= data
; d
!= NULL
; d
= d
->next
)
1076 len
+= rcdata_copy (d
, NULL
);
1079 ret
= pret
= (bfd_byte
*) res_alloc (len
);
1080 for (d
= data
; d
!= NULL
; d
= d
->next
)
1081 pret
+= rcdata_copy (d
, pret
);
1089 define_fontdir_rcdata (rc_res_id id
,const rc_res_res_info
*resinfo
,
1090 rc_rcdata_item
*data
)
1093 rc_fontdir
*fd
, *fd_first
, *fd_cur
;
1094 rc_uint_type len_data
;
1098 fd_cur
= fd_first
= NULL
;
1099 r
= define_standard_resource (&resources
, RT_FONTDIR
, id
, 0x409, 0);
1101 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1105 rc_uint_type off
= 2;
1106 c
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1110 rc_uint_type safe_pos
= off
;
1111 const struct bin_fontdir_item
*bfi
;
1113 bfi
= (const struct bin_fontdir_item
*) pb_data
+ off
;
1114 fd
= (rc_fontdir
*) res_alloc (sizeof (rc_fontdir
));
1115 fd
->index
= windres_get_16 (&wrtarget
, bfi
->index
, len_data
- off
);
1116 fd
->data
= pb_data
+ off
;
1118 len
= strlen ((char *) bfi
->device_name
) + 1;
1119 off
+= (rc_uint_type
) len
;
1120 off
+= (rc_uint_type
) strlen ((char *) bfi
->device_name
+ len
) + 1;
1121 fd
->length
= (off
- safe_pos
);
1123 if (fd_first
== NULL
)
1130 r
->type
= RES_TYPE_FONTDIR
;
1131 r
->u
.fontdir
= fd_first
;
1132 r
->res_info
= *resinfo
;
1135 static void define_messagetable_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1136 rc_rcdata_item
*data
)
1139 rc_uint_type len_data
;
1142 r
= define_standard_resource (&resources
, RT_MESSAGETABLE
, id
, resinfo
->language
, 0);
1144 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1145 r
->type
= RES_TYPE_MESSAGETABLE
;
1146 r
->u
.data
.length
= len_data
;
1147 r
->u
.data
.data
= pb_data
;
1148 r
->res_info
= *resinfo
;
1151 /* Define an icon resource. An icon file may contain a set of
1152 bitmaps, each representing the same icon at various different
1153 resolutions. They each get written out with a different ID. The
1154 real icon resource is then a group resource which can be used to
1155 select one of the actual icon bitmaps. */
1158 define_icon (rc_res_id id
, const rc_res_res_info
*resinfo
,
1159 const char *filename
)
1162 char *real_filename
;
1164 struct icondir
*icondirs
;
1167 rc_group_icon
*first
, **pp
;
1169 e
= open_file_search (filename
, FOPEN_RB
, "icon file", &real_filename
);
1171 /* The start of an icon file is a three word structure. The first
1172 word is ignored. The second word is the type of data. The third
1173 word is the number of entries. */
1175 get_word (e
, real_filename
);
1176 type
= get_word (e
, real_filename
);
1177 count
= get_word (e
, real_filename
);
1179 fatal (_("icon file `%s' does not contain icon data"), real_filename
);
1181 /* Read in the icon directory entries. */
1183 icondirs
= (struct icondir
*) xmalloc (count
* sizeof *icondirs
);
1185 for (i
= 0; i
< count
; i
++)
1187 icondirs
[i
].width
= getc (e
);
1188 icondirs
[i
].height
= getc (e
);
1189 icondirs
[i
].colorcount
= getc (e
);
1191 icondirs
[i
].u
.icon
.planes
= get_word (e
, real_filename
);
1192 icondirs
[i
].u
.icon
.bits
= get_word (e
, real_filename
);
1193 icondirs
[i
].bytes
= get_long (e
, real_filename
);
1194 icondirs
[i
].offset
= get_long (e
, real_filename
);
1197 unexpected_eof (real_filename
);
1200 /* Define each icon as a unique resource. */
1204 for (i
= 0; i
< count
; i
++)
1209 if (fseek (e
, icondirs
[i
].offset
, SEEK_SET
) != 0)
1210 fatal (_("%s: fseek to %lu failed: %s"), real_filename
,
1211 icondirs
[i
].offset
, strerror (errno
));
1213 data
= (bfd_byte
*) res_alloc (icondirs
[i
].bytes
);
1215 get_data (e
, data
, icondirs
[i
].bytes
, real_filename
);
1222 r
= define_standard_resource (&resources
, RT_ICON
, name
,
1223 resinfo
->language
, 0);
1224 r
->type
= RES_TYPE_ICON
;
1225 r
->u
.data
.length
= icondirs
[i
].bytes
;
1226 r
->u
.data
.data
= data
;
1227 r
->res_info
= *resinfo
;
1231 free (real_filename
);
1233 /* Define an icon group resource. */
1237 for (i
= 0; i
< count
; i
++)
1241 /* For some reason, at least in some files the planes and bits
1242 are zero. We instead set them from the color. This is
1245 cg
= (rc_group_icon
*) res_alloc (sizeof (rc_group_icon
));
1247 cg
->width
= icondirs
[i
].width
;
1248 cg
->height
= icondirs
[i
].height
;
1249 cg
->colors
= icondirs
[i
].colorcount
;
1251 if (icondirs
[i
].u
.icon
.planes
)
1252 cg
->planes
= icondirs
[i
].u
.icon
.planes
;
1256 if (icondirs
[i
].u
.icon
.bits
)
1257 cg
->bits
= icondirs
[i
].u
.icon
.bits
;
1262 while ((1L << cg
->bits
) < cg
->colors
)
1266 cg
->bytes
= icondirs
[i
].bytes
;
1267 cg
->index
= first_icon
+ i
+ 1;
1275 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1276 resinfo
->language
, 0);
1277 r
->type
= RES_TYPE_GROUP_ICON
;
1278 r
->u
.group_icon
= first
;
1279 r
->res_info
= *resinfo
;
1283 define_group_icon_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1284 rc_rcdata_item
*data
)
1287 rc_group_icon
*cg
, *first
, *cur
;
1288 rc_uint_type len_data
;
1291 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1296 while (len_data
>= 6)
1299 unsigned short type
;
1300 type
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1302 fatal (_("unexpected group icon type %d"), type
);
1303 c
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1307 for (i
= 0; i
< c
; i
++)
1310 fatal ("too small group icon rcdata");
1311 cg
= (rc_group_icon
*) res_alloc (sizeof (rc_group_icon
));
1313 cg
->width
= pb_data
[0];
1314 cg
->height
= pb_data
[1];
1315 cg
->colors
= pb_data
[2];
1316 cg
->planes
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1317 cg
->bits
= windres_get_16 (&wrtarget
, pb_data
+ 6, len_data
- 6);
1318 cg
->bytes
= windres_get_32 (&wrtarget
, pb_data
+ 8, len_data
- 8);
1319 cg
->index
= windres_get_16 (&wrtarget
, pb_data
+ 12, len_data
- 12);
1329 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1330 resinfo
->language
, 0);
1331 r
->type
= RES_TYPE_GROUP_ICON
;
1332 r
->u
.group_icon
= first
;
1333 r
->res_info
= *resinfo
;
1337 define_group_cursor_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1338 rc_rcdata_item
*data
)
1341 rc_group_cursor
*cg
, *first
, *cur
;
1342 rc_uint_type len_data
;
1345 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1349 while (len_data
>= 6)
1352 unsigned short type
;
1353 type
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1355 fatal (_("unexpected group cursor type %d"), type
);
1356 c
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1360 for (i
= 0; i
< c
; i
++)
1363 fatal ("too small group icon rcdata");
1364 cg
= (rc_group_cursor
*) res_alloc (sizeof (rc_group_cursor
));
1366 cg
->width
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1367 cg
->height
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1368 cg
->planes
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1369 cg
->bits
= windres_get_16 (&wrtarget
, pb_data
+ 6, len_data
- 6);
1370 cg
->bytes
= windres_get_32 (&wrtarget
, pb_data
+ 8, len_data
- 8);
1371 cg
->index
= windres_get_16 (&wrtarget
, pb_data
+ 12, len_data
- 12);
1382 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1383 resinfo
->language
, 0);
1384 r
->type
= RES_TYPE_GROUP_CURSOR
;
1385 r
->u
.group_cursor
= first
;
1386 r
->res_info
= *resinfo
;
1390 define_cursor_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1391 rc_rcdata_item
*data
)
1395 rc_uint_type len_data
;
1398 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1400 c
= (rc_cursor
*) res_alloc (sizeof (rc_cursor
));
1401 c
->xhotspot
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1402 c
->yhotspot
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1403 c
->length
= len_data
- BIN_CURSOR_SIZE
;
1404 c
->data
= (const bfd_byte
*) (data
+ BIN_CURSOR_SIZE
);
1406 r
= define_standard_resource (&resources
, RT_CURSOR
, id
, resinfo
->language
, 0);
1407 r
->type
= RES_TYPE_CURSOR
;
1409 r
->res_info
= *resinfo
;
1413 define_bitmap_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1414 rc_rcdata_item
*data
)
1417 rc_uint_type len_data
;
1420 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1422 r
= define_standard_resource (&resources
, RT_BITMAP
, id
, resinfo
->language
, 0);
1423 r
->type
= RES_TYPE_BITMAP
;
1424 r
->u
.data
.length
= len_data
;
1425 r
->u
.data
.data
= pb_data
;
1426 r
->res_info
= *resinfo
;
1430 define_icon_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1431 rc_rcdata_item
*data
)
1434 rc_uint_type len_data
;
1437 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1439 r
= define_standard_resource (&resources
, RT_ICON
, id
, resinfo
->language
, 0);
1440 r
->type
= RES_TYPE_ICON
;
1441 r
->u
.data
.length
= len_data
;
1442 r
->u
.data
.data
= pb_data
;
1443 r
->res_info
= *resinfo
;
1446 /* Define a menu resource. */
1449 define_menu (rc_res_id id
, const rc_res_res_info
*resinfo
,
1450 rc_menuitem
*menuitems
)
1455 m
= (rc_menu
*) res_alloc (sizeof (rc_menu
));
1456 m
->items
= menuitems
;
1459 r
= define_standard_resource (&resources
, RT_MENU
, id
, resinfo
->language
, 0);
1460 r
->type
= RES_TYPE_MENU
;
1462 r
->res_info
= *resinfo
;
1465 /* Define a menu item. This does not define a resource, but merely
1466 allocates and fills in a structure. */
1469 define_menuitem (const unichar
*text
, rc_uint_type menuid
, rc_uint_type type
,
1470 rc_uint_type state
, rc_uint_type help
,
1471 rc_menuitem
*menuitems
)
1475 mi
= (rc_menuitem
*) res_alloc (sizeof (rc_menuitem
));
1480 mi
->text
= unichar_dup (text
);
1482 mi
->popup
= menuitems
;
1486 /* Define a messagetable resource. */
1489 define_messagetable (rc_res_id id
, const rc_res_res_info
*resinfo
,
1490 const char *filename
)
1493 char *real_filename
;
1498 e
= open_file_search (filename
, FOPEN_RB
, "messagetable file",
1501 if (stat (real_filename
, &s
) < 0)
1502 fatal (_("stat failed on bitmap file `%s': %s"), real_filename
,
1505 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1507 get_data (e
, data
, s
.st_size
, real_filename
);
1510 free (real_filename
);
1512 r
= define_standard_resource (&resources
, RT_MESSAGETABLE
, id
,
1513 resinfo
->language
, 0);
1515 r
->type
= RES_TYPE_MESSAGETABLE
;
1516 r
->u
.data
.length
= s
.st_size
;
1517 r
->u
.data
.data
= data
;
1518 r
->res_info
= *resinfo
;
1521 /* Define an rcdata resource. */
1524 define_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1525 rc_rcdata_item
*data
)
1529 r
= define_standard_resource (&resources
, RT_RCDATA
, id
,
1530 resinfo
->language
, 0);
1531 r
->type
= RES_TYPE_RCDATA
;
1533 r
->res_info
= *resinfo
;
1536 /* Create an rcdata item holding a string. */
1539 define_rcdata_string (const char *string
, rc_uint_type len
)
1544 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1546 ri
->type
= RCDATA_STRING
;
1547 ri
->u
.string
.length
= len
;
1548 s
= (char *) res_alloc (len
);
1549 memcpy (s
, string
, len
);
1555 /* Create an rcdata item holding a unicode string. */
1558 define_rcdata_unistring (const unichar
*string
, rc_uint_type len
)
1563 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1565 ri
->type
= RCDATA_WSTRING
;
1566 ri
->u
.wstring
.length
= len
;
1567 s
= (unichar
*) res_alloc (len
* sizeof (unichar
));
1568 memcpy (s
, string
, len
* sizeof (unichar
));
1569 ri
->u
.wstring
.w
= s
;
1574 /* Create an rcdata item holding a number. */
1577 define_rcdata_number (rc_uint_type val
, int dword
)
1581 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1583 ri
->type
= dword
? RCDATA_DWORD
: RCDATA_WORD
;
1589 /* Define a stringtable resource. This is called for each string
1590 which appears in a STRINGTABLE statement. */
1593 define_stringtable (const rc_res_res_info
*resinfo
,
1594 rc_uint_type stringid
, const unichar
*string
)
1600 id
.u
.id
= (stringid
>> 4) + 1;
1601 r
= define_standard_resource (&resources
, RT_STRING
, id
,
1602 resinfo
->language
, 1);
1604 if (r
->type
== RES_TYPE_UNINITIALIZED
)
1608 r
->type
= RES_TYPE_STRINGTABLE
;
1609 r
->u
.stringtable
= ((rc_stringtable
*)
1610 res_alloc (sizeof (rc_stringtable
)));
1611 for (i
= 0; i
< 16; i
++)
1613 r
->u
.stringtable
->strings
[i
].length
= 0;
1614 r
->u
.stringtable
->strings
[i
].string
= NULL
;
1617 r
->res_info
= *resinfo
;
1620 r
->u
.stringtable
->strings
[stringid
& 0xf].length
= unichar_len (string
);
1621 r
->u
.stringtable
->strings
[stringid
& 0xf].string
= unichar_dup (string
);
1625 define_toolbar (rc_res_id id
, rc_res_res_info
*resinfo
, rc_uint_type width
, rc_uint_type height
,
1626 rc_toolbar_item
*items
)
1631 t
= (rc_toolbar
*) res_alloc (sizeof (rc_toolbar
));
1632 t
->button_width
= width
;
1633 t
->button_height
= height
;
1636 while (items
!= NULL
)
1639 items
= items
->next
;
1641 r
= define_standard_resource (&resources
, RT_TOOLBAR
, id
, resinfo
->language
, 0);
1642 r
->type
= RES_TYPE_TOOLBAR
;
1644 r
->res_info
= *resinfo
;
1647 /* Define a user data resource where the data is in the rc file. */
1650 define_user_data (rc_res_id id
, rc_res_id type
,
1651 const rc_res_res_info
*resinfo
,
1652 rc_rcdata_item
*data
)
1657 rc_uint_type len_data
;
1659 /* We have to check if the binary data is parsed specially. */
1660 if (type
.named
== 0)
1665 define_fontdir_rcdata (id
, resinfo
, data
);
1668 define_font_rcdata (id
, resinfo
, data
);
1671 define_icon_rcdata (id
, resinfo
, data
);
1674 define_bitmap_rcdata (id
, resinfo
, data
);
1677 define_cursor_rcdata (id
, resinfo
, data
);
1680 define_group_icon_rcdata (id
, resinfo
, data
);
1682 case RT_GROUP_CURSOR
:
1683 define_group_cursor_rcdata (id
, resinfo
, data
);
1685 case RT_MESSAGETABLE
:
1686 define_messagetable_rcdata (id
, resinfo
, data
);
1689 /* Treat as normal user-data. */
1696 ids
[2].u
.id
= resinfo
->language
;
1698 r
= define_resource (& resources
, 3, ids
, 0);
1699 r
->type
= RES_TYPE_USERDATA
;
1700 r
->u
.userdata
= ((rc_rcdata_item
*)
1701 res_alloc (sizeof (rc_rcdata_item
)));
1702 r
->u
.userdata
->next
= NULL
;
1703 r
->u
.userdata
->type
= RCDATA_BUFFER
;
1704 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1705 r
->u
.userdata
->u
.buffer
.length
= len_data
;
1706 r
->u
.userdata
->u
.buffer
.data
= pb_data
;
1707 r
->res_info
= *resinfo
;
1711 define_rcdata_file (rc_res_id id
, const rc_res_res_info
*resinfo
,
1712 const char *filename
)
1716 char *real_filename
;
1720 e
= open_file_search (filename
, FOPEN_RB
, "file", &real_filename
);
1723 if (stat (real_filename
, &s
) < 0)
1724 fatal (_("stat failed on file `%s': %s"), real_filename
,
1727 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1729 get_data (e
, data
, s
.st_size
, real_filename
);
1732 free (real_filename
);
1734 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1736 ri
->type
= RCDATA_BUFFER
;
1737 ri
->u
.buffer
.length
= s
.st_size
;
1738 ri
->u
.buffer
.data
= data
;
1740 define_rcdata (id
, resinfo
, ri
);
1743 /* Define a user data resource where the data is in a file. */
1746 define_user_file (rc_res_id id
, rc_res_id type
,
1747 const rc_res_res_info
*resinfo
, const char *filename
)
1750 char *real_filename
;
1756 e
= open_file_search (filename
, FOPEN_RB
, "file", &real_filename
);
1758 if (stat (real_filename
, &s
) < 0)
1759 fatal (_("stat failed on file `%s': %s"), real_filename
,
1762 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1764 get_data (e
, data
, s
.st_size
, real_filename
);
1767 free (real_filename
);
1772 ids
[2].u
.id
= resinfo
->language
;
1774 r
= define_resource (&resources
, 3, ids
, 0);
1775 r
->type
= RES_TYPE_USERDATA
;
1776 r
->u
.userdata
= ((rc_rcdata_item
*)
1777 res_alloc (sizeof (rc_rcdata_item
)));
1778 r
->u
.userdata
->next
= NULL
;
1779 r
->u
.userdata
->type
= RCDATA_BUFFER
;
1780 r
->u
.userdata
->u
.buffer
.length
= s
.st_size
;
1781 r
->u
.userdata
->u
.buffer
.data
= data
;
1782 r
->res_info
= *resinfo
;
1785 /* Define a versioninfo resource. */
1788 define_versioninfo (rc_res_id id
, rc_uint_type language
,
1789 rc_fixed_versioninfo
*fixedverinfo
,
1790 rc_ver_info
*verinfo
)
1794 r
= define_standard_resource (&resources
, RT_VERSION
, id
, language
, 0);
1795 r
->type
= RES_TYPE_VERSIONINFO
;
1796 r
->u
.versioninfo
= ((rc_versioninfo
*)
1797 res_alloc (sizeof (rc_versioninfo
)));
1798 r
->u
.versioninfo
->fixed
= fixedverinfo
;
1799 r
->u
.versioninfo
->var
= verinfo
;
1800 r
->res_info
.language
= language
;
1803 /* Add string version info to a list of version information. */
1806 append_ver_stringfileinfo (rc_ver_info
*verinfo
,
1807 rc_ver_stringtable
*stringtables
)
1809 rc_ver_info
*vi
, **pp
;
1811 vi
= (rc_ver_info
*) res_alloc (sizeof (rc_ver_info
));
1813 vi
->type
= VERINFO_STRING
;
1814 vi
->u
.string
.stringtables
= stringtables
;
1816 for (pp
= &verinfo
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1823 rc_ver_stringtable
*
1824 append_ver_stringtable (rc_ver_stringtable
*stringtable
,
1825 const char *language
,
1826 rc_ver_stringinfo
*strings
)
1828 rc_ver_stringtable
*vst
, **pp
;
1830 vst
= (rc_ver_stringtable
*) res_alloc (sizeof (rc_ver_stringtable
));
1832 unicode_from_ascii ((rc_uint_type
*) NULL
, &vst
->language
, language
);
1833 vst
->strings
= strings
;
1835 for (pp
= &stringtable
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1842 /* Add variable version info to a list of version information. */
1845 append_ver_varfileinfo (rc_ver_info
*verinfo
, const unichar
*key
,
1846 rc_ver_varinfo
*var
)
1848 rc_ver_info
*vi
, **pp
;
1850 vi
= (rc_ver_info
*) res_alloc (sizeof *vi
);
1852 vi
->type
= VERINFO_VAR
;
1853 vi
->u
.var
.key
= unichar_dup (key
);
1854 vi
->u
.var
.var
= var
;
1856 for (pp
= &verinfo
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1863 /* Append version string information to a list. */
1866 append_verval (rc_ver_stringinfo
*strings
, const unichar
*key
,
1867 const unichar
*value
)
1869 rc_ver_stringinfo
*vs
, **pp
;
1871 vs
= (rc_ver_stringinfo
*) res_alloc (sizeof (rc_ver_stringinfo
));
1873 vs
->key
= unichar_dup (key
);
1874 vs
->value
= unichar_dup (value
);
1876 for (pp
= &strings
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1883 /* Append version variable information to a list. */
1886 append_vertrans (rc_ver_varinfo
*var
, rc_uint_type language
,
1887 rc_uint_type charset
)
1889 rc_ver_varinfo
*vv
, **pp
;
1891 vv
= (rc_ver_varinfo
*) res_alloc (sizeof (rc_ver_varinfo
));
1893 vv
->language
= language
;
1894 vv
->charset
= charset
;
1896 for (pp
= &var
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1903 /* Local functions used to write out an rc file. */
1905 static void indent (FILE *, int);
1906 static void write_rc_directory (FILE *, const rc_res_directory
*, const rc_res_id
*,
1907 const rc_res_id
*, rc_uint_type
*, int);
1908 static void write_rc_subdir (FILE *, const rc_res_entry
*, const rc_res_id
*,
1909 const rc_res_id
*, rc_uint_type
*, int);
1910 static void write_rc_resource (FILE *, const rc_res_id
*, const rc_res_id
*,
1911 const rc_res_resource
*, rc_uint_type
*);
1912 static void write_rc_accelerators (FILE *, const rc_accelerator
*);
1913 static void write_rc_cursor (FILE *, const rc_cursor
*);
1914 static void write_rc_group_cursor (FILE *, const rc_group_cursor
*);
1915 static void write_rc_dialog (FILE *, const rc_dialog
*);
1916 static void write_rc_dialog_control (FILE *, const rc_dialog_control
*);
1917 static void write_rc_fontdir (FILE *, const rc_fontdir
*);
1918 static void write_rc_group_icon (FILE *, const rc_group_icon
*);
1919 static void write_rc_menu (FILE *, const rc_menu
*, int);
1920 static void write_rc_toolbar (FILE *, const rc_toolbar
*);
1921 static void write_rc_menuitems (FILE *, const rc_menuitem
*, int, int);
1922 static void write_rc_messagetable (FILE *, rc_uint_type
, const bfd_byte
*);
1924 static void write_rc_datablock (FILE *, rc_uint_type
, const bfd_byte
*, int, int, int);
1925 static void write_rc_rcdata (FILE *, const rc_rcdata_item
*, int);
1926 static void write_rc_stringtable (FILE *, const rc_res_id
*, const rc_stringtable
*);
1927 static void write_rc_versioninfo (FILE *, const rc_versioninfo
*);
1929 /* Indent a given number of spaces. */
1932 indent (FILE *e
, int c
)
1936 for (i
= 0; i
< c
; i
++)
1940 /* Dump the resources we have read in the format of an rc file.
1942 Reasoned by the fact, that some resources need to be stored into file and
1943 refer to that file, we use the user-data model for that to express it binary
1944 without the need to store it somewhere externally. */
1947 write_rc_file (const char *filename
, const rc_res_directory
*res_dir
)
1950 rc_uint_type language
;
1952 if (filename
== NULL
)
1956 e
= fopen (filename
, FOPEN_WT
);
1958 fatal (_("can't open `%s' for output: %s"), filename
, strerror (errno
));
1961 language
= (rc_uint_type
) ((bfd_signed_vma
) -1);
1962 write_rc_directory (e
, res_dir
, (const rc_res_id
*) NULL
,
1963 (const rc_res_id
*) NULL
, &language
, 1);
1966 /* Write out a directory. E is the file to write to. RD is the
1967 directory. TYPE is a pointer to the level 1 ID which serves as the
1968 resource type. NAME is a pointer to the level 2 ID which serves as
1969 an individual resource name. LANGUAGE is a pointer to the current
1970 language. LEVEL is the level in the tree. */
1973 write_rc_directory (FILE *e
, const rc_res_directory
*rd
,
1974 const rc_res_id
*type
, const rc_res_id
*name
,
1975 rc_uint_type
*language
, int level
)
1977 const rc_res_entry
*re
;
1979 /* Print out some COFF information that rc files can't represent. */
1980 if (rd
->time
!= 0 || rd
->characteristics
!= 0 || rd
->major
!= 0 || rd
->minor
!= 0)
1982 wr_printcomment (e
, "COFF information not part of RC");
1984 wr_printcomment (e
, "Time stamp: %u", rd
->time
);
1985 if (rd
->characteristics
!= 0)
1986 wr_printcomment (e
, "Characteristics: %u", rd
->characteristics
);
1987 if (rd
->major
!= 0 || rd
->minor
!= 0)
1988 wr_printcomment (e
, "Version major:%d minor:%d", rd
->major
, rd
->minor
);
1991 for (re
= rd
->entries
; re
!= NULL
; re
= re
->next
)
1996 /* If we're at level 1, the key of this resource is the
1997 type. This normally duplicates the information we have
1998 stored with the resource itself, but we need to remember
1999 the type if this is a user define resource type. */
2004 /* If we're at level 2, the key of this resource is the name
2005 we are going to use in the rc printout. */
2010 /* If we're at level 3, then this key represents a language.
2011 Use it to update the current language. */
2013 && re
->id
.u
.id
!= (unsigned long) (unsigned int) *language
2014 && (re
->id
.u
.id
& 0xffff) == re
->id
.u
.id
)
2016 wr_print (e
, "LANGUAGE %u, %u\n",
2017 re
->id
.u
.id
& ((1 << SUBLANG_SHIFT
) - 1),
2018 (re
->id
.u
.id
>> SUBLANG_SHIFT
) & 0xff);
2019 *language
= re
->id
.u
.id
;
2028 write_rc_subdir (e
, re
, type
, name
, language
, level
);
2033 /* This is the normal case: the three levels are
2034 TYPE/NAME/LANGUAGE. NAME will have been set at level
2035 2, and represents the name to use. We probably just
2036 set LANGUAGE, and it will probably match what the
2037 resource itself records if anything. */
2038 write_rc_resource (e
, type
, name
, re
->u
.res
, language
);
2042 wr_printcomment (e
, "Resource at unexpected level %d", level
);
2043 write_rc_resource (e
, type
, (rc_res_id
*) NULL
, re
->u
.res
,
2048 if (rd
->entries
== NULL
)
2054 /* Write out a subdirectory entry. E is the file to write to. RE is
2055 the subdirectory entry. TYPE and NAME are pointers to higher level
2056 IDs, or NULL. LANGUAGE is a pointer to the current language.
2057 LEVEL is the level in the tree. */
2060 write_rc_subdir (FILE *e
, const rc_res_entry
*re
,
2061 const rc_res_id
*type
, const rc_res_id
*name
,
2062 rc_uint_type
*language
, int level
)
2068 wr_printcomment (e
, "Type: ");
2070 res_id_print (e
, re
->id
, 1);
2075 switch (re
->id
.u
.id
)
2077 case RT_CURSOR
: s
= "cursor"; break;
2078 case RT_BITMAP
: s
= "bitmap"; break;
2079 case RT_ICON
: s
= "icon"; break;
2080 case RT_MENU
: s
= "menu"; break;
2081 case RT_DIALOG
: s
= "dialog"; break;
2082 case RT_STRING
: s
= "stringtable"; break;
2083 case RT_FONTDIR
: s
= "fontdir"; break;
2084 case RT_FONT
: s
= "font"; break;
2085 case RT_ACCELERATOR
: s
= "accelerators"; break;
2086 case RT_RCDATA
: s
= "rcdata"; break;
2087 case RT_MESSAGETABLE
: s
= "messagetable"; break;
2088 case RT_GROUP_CURSOR
: s
= "group cursor"; break;
2089 case RT_GROUP_ICON
: s
= "group icon"; break;
2090 case RT_VERSION
: s
= "version"; break;
2091 case RT_DLGINCLUDE
: s
= "dlginclude"; break;
2092 case RT_PLUGPLAY
: s
= "plugplay"; break;
2093 case RT_VXD
: s
= "vxd"; break;
2094 case RT_ANICURSOR
: s
= "anicursor"; break;
2095 case RT_ANIICON
: s
= "aniicon"; break;
2096 case RT_TOOLBAR
: s
= "toolbar"; break;
2097 case RT_HTML
: s
= "html"; break;
2098 default: s
= NULL
; break;
2102 fprintf (e
, "%s", s
);
2104 res_id_print (e
, re
->id
, 1);
2109 wr_printcomment (e
, "Name: ");
2110 res_id_print (e
, re
->id
, 1);
2114 wr_printcomment (e
, "Language: ");
2115 res_id_print (e
, re
->id
, 1);
2119 wr_printcomment (e
, "Level %d: ", level
);
2120 res_id_print (e
, re
->id
, 1);
2123 write_rc_directory (e
, re
->u
.dir
, type
, name
, language
, level
+ 1);
2126 /* Write out a single resource. E is the file to write to. TYPE is a
2127 pointer to the type of the resource. NAME is a pointer to the name
2128 of the resource; it will be NULL if there is a level mismatch. RES
2129 is the resource data. LANGUAGE is a pointer to the current
2133 write_rc_resource (FILE *e
, const rc_res_id
*type
,
2134 const rc_res_id
*name
, const rc_res_resource
*res
,
2135 rc_uint_type
*language
)
2146 case RES_TYPE_ACCELERATOR
:
2148 rt
= RT_ACCELERATOR
;
2151 case RES_TYPE_BITMAP
:
2152 s
= "2 /* RT_BITMAP */";
2156 case RES_TYPE_CURSOR
:
2157 s
= "1 /* RT_CURSOR */";
2161 case RES_TYPE_GROUP_CURSOR
:
2162 s
= "12 /* RT_GROUP_CURSOR */";
2163 rt
= RT_GROUP_CURSOR
;
2166 case RES_TYPE_DIALOG
:
2167 if (extended_dialog (res
->u
.dialog
))
2175 s
= "8 /* RT_FONT */";
2179 case RES_TYPE_FONTDIR
:
2180 s
= "7 /* RT_FONTDIR */";
2185 s
= "3 /* RT_ICON */";
2189 case RES_TYPE_GROUP_ICON
:
2190 s
= "14 /* RT_GROUP_ICON */";
2195 if (extended_menu (res
->u
.menu
))
2208 case RES_TYPE_MESSAGETABLE
:
2209 s
= "11 /* RT_MESSAGETABLE */";
2210 rt
= RT_MESSAGETABLE
;
2213 case RES_TYPE_RCDATA
:
2218 case RES_TYPE_STRINGTABLE
:
2223 case RES_TYPE_USERDATA
:
2228 case RES_TYPE_VERSIONINFO
:
2233 case RES_TYPE_TOOLBAR
:
2241 && (type
->named
|| type
->u
.id
!= (unsigned long) rt
))
2243 wr_printcomment (e
, "Unexpected resource type mismatch: ");
2244 res_id_print (e
, *type
, 1);
2245 fprintf (e
, " != %d", rt
);
2248 if (res
->coff_info
.codepage
!= 0)
2249 wr_printcomment (e
, "Code page: %u", res
->coff_info
.codepage
);
2250 if (res
->coff_info
.reserved
!= 0)
2251 wr_printcomment (e
, "COFF reserved value: %u", res
->coff_info
.reserved
);
2254 if (rt
== RT_STRING
)
2259 res_id_print (e
, *name
, 1);
2261 fprintf (e
, "??Unknown-Name??");
2266 fprintf (e
, "%s", s
);
2267 else if (type
!= NULL
)
2269 if (type
->named
== 0)
2271 #define PRINT_RT_NAME(NAME) case NAME: \
2272 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2278 res_id_print (e
, *type
, 0);
2281 PRINT_RT_NAME(RT_MANIFEST
);
2282 PRINT_RT_NAME(RT_ANICURSOR
);
2283 PRINT_RT_NAME(RT_ANIICON
);
2284 PRINT_RT_NAME(RT_RCDATA
);
2285 PRINT_RT_NAME(RT_ICON
);
2286 PRINT_RT_NAME(RT_CURSOR
);
2287 PRINT_RT_NAME(RT_BITMAP
);
2288 PRINT_RT_NAME(RT_PLUGPLAY
);
2289 PRINT_RT_NAME(RT_VXD
);
2290 PRINT_RT_NAME(RT_FONT
);
2291 PRINT_RT_NAME(RT_FONTDIR
);
2292 PRINT_RT_NAME(RT_HTML
);
2293 PRINT_RT_NAME(RT_MESSAGETABLE
);
2294 PRINT_RT_NAME(RT_DLGINCLUDE
);
2295 PRINT_RT_NAME(RT_DLGINIT
);
2297 #undef PRINT_RT_NAME
2300 res_id_print (e
, *type
, 1);
2303 fprintf (e
, "??Unknown-Type??");
2305 if (res
->res_info
.memflags
!= 0)
2307 if ((res
->res_info
.memflags
& MEMFLAG_MOVEABLE
) != 0)
2308 fprintf (e
, " MOVEABLE");
2309 if ((res
->res_info
.memflags
& MEMFLAG_PURE
) != 0)
2310 fprintf (e
, " PURE");
2311 if ((res
->res_info
.memflags
& MEMFLAG_PRELOAD
) != 0)
2312 fprintf (e
, " PRELOAD");
2313 if ((res
->res_info
.memflags
& MEMFLAG_DISCARDABLE
) != 0)
2314 fprintf (e
, " DISCARDABLE");
2317 if (res
->type
== RES_TYPE_DIALOG
)
2319 fprintf (e
, " %d, %d, %d, %d",
2320 (int) res
->u
.dialog
->x
, (int) res
->u
.dialog
->y
,
2321 (int) res
->u
.dialog
->width
, (int) res
->u
.dialog
->height
);
2322 if (res
->u
.dialog
->ex
!= NULL
2323 && res
->u
.dialog
->ex
->help
!= 0)
2324 fprintf (e
, ", %u", (unsigned int) res
->u
.dialog
->ex
->help
);
2326 else if (res
->type
== RES_TYPE_TOOLBAR
)
2328 fprintf (e
, " %d, %d", (int) res
->u
.toolbar
->button_width
,
2329 (int) res
->u
.toolbar
->button_height
);
2334 if ((res
->res_info
.language
!= 0 && res
->res_info
.language
!= *language
)
2335 || res
->res_info
.characteristics
!= 0
2336 || res
->res_info
.version
!= 0)
2342 case RES_TYPE_ACCELERATOR
:
2343 case RES_TYPE_DIALOG
:
2345 case RES_TYPE_RCDATA
:
2346 case RES_TYPE_STRINGTABLE
:
2355 if (res
->res_info
.language
!= 0 && res
->res_info
.language
!= *language
)
2356 fprintf (e
, "%sLANGUAGE %d, %d\n",
2357 modifiers
? "// " : "",
2358 (int) res
->res_info
.language
& ((1<<SUBLANG_SHIFT
)-1),
2359 (int) (res
->res_info
.language
>> SUBLANG_SHIFT
) & 0xff);
2360 if (res
->res_info
.characteristics
!= 0)
2361 fprintf (e
, "%sCHARACTERISTICS %u\n",
2362 modifiers
? "// " : "",
2363 (unsigned int) res
->res_info
.characteristics
);
2364 if (res
->res_info
.version
!= 0)
2365 fprintf (e
, "%sVERSION %u\n",
2366 modifiers
? "// " : "",
2367 (unsigned int) res
->res_info
.version
);
2375 case RES_TYPE_ACCELERATOR
:
2376 write_rc_accelerators (e
, res
->u
.acc
);
2379 case RES_TYPE_CURSOR
:
2380 write_rc_cursor (e
, res
->u
.cursor
);
2383 case RES_TYPE_GROUP_CURSOR
:
2384 write_rc_group_cursor (e
, res
->u
.group_cursor
);
2387 case RES_TYPE_DIALOG
:
2388 write_rc_dialog (e
, res
->u
.dialog
);
2391 case RES_TYPE_FONTDIR
:
2392 write_rc_fontdir (e
, res
->u
.fontdir
);
2395 case RES_TYPE_GROUP_ICON
:
2396 write_rc_group_icon (e
, res
->u
.group_icon
);
2400 write_rc_menu (e
, res
->u
.menu
, menuex
);
2403 case RES_TYPE_RCDATA
:
2404 write_rc_rcdata (e
, res
->u
.rcdata
, 0);
2407 case RES_TYPE_STRINGTABLE
:
2408 write_rc_stringtable (e
, name
, res
->u
.stringtable
);
2411 case RES_TYPE_USERDATA
:
2412 write_rc_rcdata (e
, res
->u
.userdata
, 0);
2415 case RES_TYPE_TOOLBAR
:
2416 write_rc_toolbar (e
, res
->u
.toolbar
);
2419 case RES_TYPE_VERSIONINFO
:
2420 write_rc_versioninfo (e
, res
->u
.versioninfo
);
2423 case RES_TYPE_BITMAP
:
2426 write_rc_datablock (e
, res
->u
.data
.length
, res
->u
.data
.data
, 0, 1, 0);
2428 case RES_TYPE_MESSAGETABLE
:
2429 write_rc_messagetable (e
, res
->u
.data
.length
, res
->u
.data
.data
);
2434 /* Write out accelerator information. */
2437 write_rc_accelerators (FILE *e
, const rc_accelerator
*accelerators
)
2439 const rc_accelerator
*acc
;
2441 fprintf (e
, "BEGIN\n");
2442 for (acc
= accelerators
; acc
!= NULL
; acc
= acc
->next
)
2448 if ((acc
->key
& 0x7f) == acc
->key
2449 && ISPRINT (acc
->key
)
2450 && (acc
->flags
& ACC_VIRTKEY
) == 0)
2452 fprintf (e
, "\"%c\"", (char) acc
->key
);
2457 fprintf (e
, "%d", (int) acc
->key
);
2461 fprintf (e
, ", %d", (int) acc
->id
);
2465 if ((acc
->flags
& ACC_VIRTKEY
) != 0)
2466 fprintf (e
, ", VIRTKEY");
2468 fprintf (e
, ", ASCII");
2471 if ((acc
->flags
& ACC_SHIFT
) != 0)
2472 fprintf (e
, ", SHIFT");
2473 if ((acc
->flags
& ACC_CONTROL
) != 0)
2474 fprintf (e
, ", CONTROL");
2475 if ((acc
->flags
& ACC_ALT
) != 0)
2476 fprintf (e
, ", ALT");
2481 fprintf (e
, "END\n");
2484 /* Write out cursor information. This would normally be in a separate
2485 file, which the rc file would include. */
2488 write_rc_cursor (FILE *e
, const rc_cursor
*cursor
)
2490 fprintf (e
, "BEGIN\n");
2492 fprintf (e
, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2493 (unsigned int) cursor
->xhotspot
, (unsigned int) cursor
->yhotspot
,
2494 (int) cursor
->xhotspot
, (int) cursor
->yhotspot
);
2495 write_rc_datablock (e
, (rc_uint_type
) cursor
->length
, (const bfd_byte
*) cursor
->data
,
2497 fprintf (e
, "END\n");
2500 /* Write out group cursor data. This would normally be built from the
2504 write_rc_group_cursor (FILE *e
, const rc_group_cursor
*group_cursor
)
2506 const rc_group_cursor
*gc
;
2509 for (c
= 0, gc
= group_cursor
; gc
!= NULL
; gc
= gc
->next
, c
++)
2511 fprintf (e
, "BEGIN\n");
2514 fprintf (e
, "0, 2, %d%s\t /* Having %d items. */\n", c
, (c
!= 0 ? "," : ""), c
);
2516 fprintf (e
, "/* width, height, planes, bits, bytes, index. */\n");
2518 for (c
= 1, gc
= group_cursor
; gc
!= NULL
; gc
= gc
->next
, c
++)
2521 fprintf (e
, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2522 (int) gc
->width
, (int) gc
->height
, (int) gc
->planes
, (int) gc
->bits
,
2523 (unsigned int) gc
->bytes
, (int) gc
->index
, (gc
->next
!= NULL
? "," : ""), c
);
2524 fprintf (e
, "/* width: %d; height %d; planes %d; bits %d. */\n",
2525 (int) gc
->width
, (int) gc
->height
, (int) gc
->planes
,
2528 fprintf (e
, "END\n");
2531 /* Write dialog data. */
2534 write_rc_dialog (FILE *e
, const rc_dialog
*dialog
)
2536 const rc_dialog_control
*control
;
2538 fprintf (e
, "STYLE 0x%x\n", dialog
->style
);
2540 if (dialog
->exstyle
!= 0)
2541 fprintf (e
, "EXSTYLE 0x%x\n", (unsigned int) dialog
->exstyle
);
2543 if ((dialog
->class.named
&& dialog
->class.u
.n
.length
> 0)
2544 || dialog
->class.u
.id
!= 0)
2546 fprintf (e
, "CLASS ");
2547 res_id_print (e
, dialog
->class, 1);
2551 if (dialog
->caption
!= NULL
)
2553 fprintf (e
, "CAPTION ");
2554 unicode_print_quoted (e
, dialog
->caption
, -1);
2558 if ((dialog
->menu
.named
&& dialog
->menu
.u
.n
.length
> 0)
2559 || dialog
->menu
.u
.id
!= 0)
2561 fprintf (e
, "MENU ");
2562 res_id_print (e
, dialog
->menu
, 0);
2566 if (dialog
->font
!= NULL
)
2568 fprintf (e
, "FONT %d, ", (int) dialog
->pointsize
);
2569 unicode_print_quoted (e
, dialog
->font
, -1);
2570 if (dialog
->ex
!= NULL
2571 && (dialog
->ex
->weight
!= 0
2572 || dialog
->ex
->italic
!= 0
2573 || dialog
->ex
->charset
!= 1))
2574 fprintf (e
, ", %d, %d, %d",
2575 (int) dialog
->ex
->weight
,
2576 (int) dialog
->ex
->italic
,
2577 (int) dialog
->ex
->charset
);
2581 fprintf (e
, "BEGIN\n");
2583 for (control
= dialog
->controls
; control
!= NULL
; control
= control
->next
)
2584 write_rc_dialog_control (e
, control
);
2586 fprintf (e
, "END\n");
2589 /* For each predefined control keyword, this table provides the class
2595 unsigned short class;
2596 unsigned long style
;
2599 static const struct control_info control_info
[] =
2601 { "AUTO3STATE", CTL_BUTTON
, BS_AUTO3STATE
},
2602 { "AUTOCHECKBOX", CTL_BUTTON
, BS_AUTOCHECKBOX
},
2603 { "AUTORADIOBUTTON", CTL_BUTTON
, BS_AUTORADIOBUTTON
},
2604 { "CHECKBOX", CTL_BUTTON
, BS_CHECKBOX
},
2605 { "COMBOBOX", CTL_COMBOBOX
, (unsigned long) -1 },
2606 { "CTEXT", CTL_STATIC
, SS_CENTER
},
2607 { "DEFPUSHBUTTON", CTL_BUTTON
, BS_DEFPUSHBUTTON
},
2608 { "EDITTEXT", CTL_EDIT
, (unsigned long) -1 },
2609 { "GROUPBOX", CTL_BUTTON
, BS_GROUPBOX
},
2610 { "ICON", CTL_STATIC
, SS_ICON
},
2611 { "LISTBOX", CTL_LISTBOX
, (unsigned long) -1 },
2612 { "LTEXT", CTL_STATIC
, SS_LEFT
},
2613 { "PUSHBOX", CTL_BUTTON
, BS_PUSHBOX
},
2614 { "PUSHBUTTON", CTL_BUTTON
, BS_PUSHBUTTON
},
2615 { "RADIOBUTTON", CTL_BUTTON
, BS_RADIOBUTTON
},
2616 { "RTEXT", CTL_STATIC
, SS_RIGHT
},
2617 { "SCROLLBAR", CTL_SCROLLBAR
, (unsigned long) -1 },
2618 { "STATE3", CTL_BUTTON
, BS_3STATE
},
2619 /* It's important that USERBUTTON come after all the other button
2620 types, so that it won't be matched too early. */
2621 { "USERBUTTON", CTL_BUTTON
, (unsigned long) -1 },
2625 /* Write a dialog control. */
2628 write_rc_dialog_control (FILE *e
, const rc_dialog_control
*control
)
2630 const struct control_info
*ci
;
2634 if (control
->class.named
)
2638 for (ci
= control_info
; ci
->name
!= NULL
; ++ci
)
2639 if (ci
->class == control
->class.u
.id
2640 && (ci
->style
== (unsigned long) -1
2641 || ci
->style
== (control
->style
& 0xff)))
2645 fprintf (e
, "CONTROL");
2646 else if (ci
->name
!= NULL
)
2647 fprintf (e
, "%s", ci
->name
);
2650 fprintf (e
, "CONTROL");
2654 if (control
->text
.named
|| control
->text
.u
.id
!= 0)
2657 res_id_print (e
, control
->text
, 1);
2661 fprintf (e
, " %d, ", (int) control
->id
);
2665 if (control
->class.named
)
2667 res_id_print (e
, control
->class, 0);
2668 if (control
->class.named
)
2670 fprintf (e
, ", 0x%x, ", (unsigned int) control
->style
);
2673 fprintf (e
, "%d, %d", (int) control
->x
, (int) control
->y
);
2675 if (control
->style
!= SS_ICON
2676 || control
->exstyle
!= 0
2677 || control
->width
!= 0
2678 || control
->height
!= 0
2679 || control
->help
!= 0)
2681 fprintf (e
, ", %d, %d", (int) control
->width
, (int) control
->height
);
2683 /* FIXME: We don't need to print the style if it is the default.
2684 More importantly, in certain cases we actually need to turn
2685 off parts of the forced style, by using NOT. */
2687 fprintf (e
, ", 0x%x", (unsigned int) control
->style
);
2689 if (control
->exstyle
!= 0 || control
->help
!= 0)
2690 fprintf (e
, ", 0x%x, %u", (unsigned int) control
->exstyle
,
2691 (unsigned int) control
->help
);
2696 if (control
->data
!= NULL
)
2697 write_rc_rcdata (e
, control
->data
, 2);
2700 /* Write out font directory data. This would normally be built from
2704 write_rc_fontdir (FILE *e
, const rc_fontdir
*fontdir
)
2706 const rc_fontdir
*fc
;
2709 for (c
= 0, fc
= fontdir
; fc
!= NULL
; fc
= fc
->next
, c
++)
2711 fprintf (e
, "BEGIN\n");
2713 fprintf (e
, "%d%s\t /* Has %d elements. */\n", c
, (c
!= 0 ? "," : ""), c
);
2714 for (c
= 1, fc
= fontdir
; fc
!= NULL
; fc
= fc
->next
, c
++)
2717 fprintf (e
, "%d,\t/* Font no %d with index %d. */\n",
2718 (int) fc
->index
, c
, (int) fc
->index
);
2719 write_rc_datablock (e
, (rc_uint_type
) fc
->length
- 2,
2720 (const bfd_byte
*) fc
->data
+ 4,fc
->next
!= NULL
,
2723 fprintf (e
, "END\n");
2726 /* Write out group icon data. This would normally be built from the
2730 write_rc_group_icon (FILE *e
, const rc_group_icon
*group_icon
)
2732 const rc_group_icon
*gi
;
2735 for (c
= 0, gi
= group_icon
; gi
!= NULL
; gi
= gi
->next
, c
++)
2738 fprintf (e
, "BEGIN\n");
2740 fprintf (e
, " 0, 1, %d%s\t /* Has %d elements. */\n", c
, (c
!= 0 ? "," : ""), c
);
2743 fprintf (e
, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2744 for (c
= 1, gi
= group_icon
; gi
!= NULL
; gi
= gi
->next
, c
++)
2747 fprintf (e
, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2748 gi
->width
, gi
->height
, gi
->colors
, 0, (int) gi
->planes
, (int) gi
->bits
,
2749 (unsigned int) gi
->bytes
, (int) gi
->index
, (gi
->next
!= NULL
? "," : ""), c
);
2751 fprintf (e
, "END\n");
2754 /* Write out a menu resource. */
2757 write_rc_menu (FILE *e
, const rc_menu
*menu
, int menuex
)
2759 if (menu
->help
!= 0)
2760 fprintf (e
, "// Help ID: %u\n", (unsigned int) menu
->help
);
2761 write_rc_menuitems (e
, menu
->items
, menuex
, 0);
2765 write_rc_toolbar (FILE *e
, const rc_toolbar
*tb
)
2767 rc_toolbar_item
*it
;
2769 fprintf (e
, "BEGIN\n");
2774 if (it
->id
.u
.id
== 0)
2775 fprintf (e
, "SEPARATOR\n");
2777 fprintf (e
, "BUTTON %d\n", (int) it
->id
.u
.id
);
2781 fprintf (e
, "END\n");
2784 /* Write out menuitems. */
2787 write_rc_menuitems (FILE *e
, const rc_menuitem
*menuitems
, int menuex
,
2790 const rc_menuitem
*mi
;
2793 fprintf (e
, "BEGIN\n");
2795 for (mi
= menuitems
; mi
!= NULL
; mi
= mi
->next
)
2797 indent (e
, ind
+ 2);
2799 if (mi
->popup
== NULL
)
2800 fprintf (e
, "MENUITEM");
2802 fprintf (e
, "POPUP");
2805 && mi
->popup
== NULL
2810 fprintf (e
, " SEPARATOR\n");
2814 if (mi
->text
== NULL
)
2815 fprintf (e
, " \"\"");
2819 unicode_print_quoted (e
, mi
->text
, -1);
2824 if (mi
->popup
== NULL
)
2825 fprintf (e
, ", %d", (int) mi
->id
);
2827 if ((mi
->type
& MENUITEM_CHECKED
) != 0)
2828 fprintf (e
, ", CHECKED");
2829 if ((mi
->type
& MENUITEM_GRAYED
) != 0)
2830 fprintf (e
, ", GRAYED");
2831 if ((mi
->type
& MENUITEM_HELP
) != 0)
2832 fprintf (e
, ", HELP");
2833 if ((mi
->type
& MENUITEM_INACTIVE
) != 0)
2834 fprintf (e
, ", INACTIVE");
2835 if ((mi
->type
& MENUITEM_MENUBARBREAK
) != 0)
2836 fprintf (e
, ", MENUBARBREAK");
2837 if ((mi
->type
& MENUITEM_MENUBREAK
) != 0)
2838 fprintf (e
, ", MENUBREAK");
2842 if (mi
->id
!= 0 || mi
->type
!= 0 || mi
->state
!= 0 || mi
->help
!= 0)
2844 fprintf (e
, ", %d", (int) mi
->id
);
2845 if (mi
->type
!= 0 || mi
->state
!= 0 || mi
->help
!= 0)
2847 fprintf (e
, ", %u", (unsigned int) mi
->type
);
2848 if (mi
->state
!= 0 || mi
->help
!= 0)
2850 fprintf (e
, ", %u", (unsigned int) mi
->state
);
2852 fprintf (e
, ", %u", (unsigned int) mi
->help
);
2860 if (mi
->popup
!= NULL
)
2861 write_rc_menuitems (e
, mi
->popup
, menuex
, ind
+ 2);
2865 fprintf (e
, "END\n");
2869 test_rc_datablock_unicode (rc_uint_type length
, const bfd_byte
*data
)
2872 if ((length
& 1) != 0)
2875 for (i
= 0; i
< length
; i
+= 2)
2877 if (data
[i
] == 0 && data
[i
+ 1] == 0 && (i
+ 2) < length
)
2879 if (data
[i
] == 0xff && data
[i
+ 1] == 0xff)
2886 test_rc_datablock_text (rc_uint_type length
, const bfd_byte
*data
)
2896 for (i
= 0, c
= 0; i
< length
; i
++)
2898 if (! ISPRINT (data
[i
]) && data
[i
] != '\n'
2899 && ! (data
[i
] == '\r' && (i
+ 1) < length
&& data
[i
+ 1] == '\n')
2901 && ! (data
[i
] == 0 && (i
+ 1) != length
))
2907 else if (data
[i
] == '\n') has_nl
++;
2909 if (length
> 80 && ! has_nl
)
2911 c
= (((c
* 10000) + (i
/ 100) - 1)) / i
;
2918 write_rc_messagetable (FILE *e
, rc_uint_type length
, const bfd_byte
*data
)
2921 const struct bin_messagetable
*mt
;
2922 fprintf (e
, "BEGIN\n");
2924 write_rc_datablock (e
, length
, data
, 0, 0, 0);
2927 wr_printcomment (e
, "MC syntax dump");
2928 if (length
< BIN_MESSAGETABLE_SIZE
)
2933 mt
= (const struct bin_messagetable
*) data
;
2934 m
= windres_get_32 (&wrtarget
, mt
->cblocks
, length
);
2935 if (length
< (BIN_MESSAGETABLE_SIZE
+ m
* BIN_MESSAGETABLE_BLOCK_SIZE
))
2940 for (i
= 0; i
< m
; i
++)
2942 rc_uint_type low
, high
, offset
;
2943 const struct bin_messagetable_item
*mti
;
2945 low
= windres_get_32 (&wrtarget
, mt
->items
[i
].lowid
, 4);
2946 high
= windres_get_32 (&wrtarget
, mt
->items
[i
].highid
, 4);
2947 offset
= windres_get_32 (&wrtarget
, mt
->items
[i
].offset
, 4);
2950 rc_uint_type elen
, flags
;
2951 if ((offset
+ BIN_MESSAGETABLE_ITEM_SIZE
) > length
)
2956 mti
= (const struct bin_messagetable_item
*) &data
[offset
];
2957 elen
= windres_get_16 (&wrtarget
, mti
->length
, 2);
2958 flags
= windres_get_16 (&wrtarget
, mti
->flags
, 2);
2959 if ((offset
+ elen
) > length
)
2964 wr_printcomment (e
, "MessageId = 0x%x", low
);
2965 wr_printcomment (e
, "");
2966 if ((flags
& MESSAGE_RESOURCE_UNICODE
) == MESSAGE_RESOURCE_UNICODE
)
2967 unicode_print (e
, (const unichar
*) mti
->data
,
2968 (elen
- BIN_MESSAGETABLE_ITEM_SIZE
) / 2);
2970 ascii_print (e
, (const char *) mti
->data
,
2971 (elen
- BIN_MESSAGETABLE_ITEM_SIZE
));
2972 wr_printcomment (e
,"");
2979 wr_printcomment (e
, "Illegal data");
2981 fprintf (e
, "END\n");
2985 write_rc_datablock (FILE *e
, rc_uint_type length
, const bfd_byte
*data
, int has_next
,
2986 int hasblock
, int show_comment
)
2991 fprintf (e
, "BEGIN\n");
2993 if (show_comment
== -1)
2995 if (test_rc_datablock_text(length
, data
))
2998 for (i
= 0; i
< length
;)
3003 for (c
= 0; i
< length
&& c
< 160 && data
[i
] != '\n'; c
++, i
++)
3005 if (i
< length
&& data
[i
] == '\n')
3007 ascii_print (e
, (const char *) &data
[i
- c
], c
);
3016 fprintf (e
, "\"\"");
3022 fprintf (e
, "END\n");
3025 if (test_rc_datablock_unicode (length
, data
))
3028 for (i
= 0; i
< length
;)
3032 u
= (const unichar
*) &data
[i
];
3036 for (c
= 0; i
< length
&& c
< 160 && u
[c
] != '\n'; c
++, i
+= 2)
3038 if (i
< length
&& u
[c
] == '\n')
3040 unicode_print (e
, u
, c
);
3049 fprintf (e
, "L\"\"");
3055 fprintf (e
, "END\n");
3064 rc_uint_type i
, max_row
;
3067 max_row
= (show_comment
? 4 : 8);
3069 for (i
= 0; i
+ 3 < length
;)
3072 rc_uint_type comment_start
;
3079 for (k
= 0; k
< max_row
&& i
+ 3 < length
; k
++, i
+= 4)
3082 plen
= fprintf (e
, "0x%lxL",
3083 (unsigned long) windres_get_32 (&wrtarget
, data
+ i
, length
- i
));
3085 plen
= fprintf (e
, " 0x%lxL",
3086 (unsigned long) windres_get_32 (&wrtarget
, data
+ i
, length
- i
)) - 1;
3087 if (has_next
|| (i
+ 4) < length
)
3089 if (plen
>0 && plen
< 11)
3090 indent (e
, 11 - plen
);
3096 fprintf (e
, "\t/* ");
3097 ascii_print (e
, (const char *) &data
[comment_start
], i
- comment_start
);
3098 fprintf (e
, ". */");
3108 plen
= fprintf (e
, "0x%x",
3109 (int) windres_get_16 (&wrtarget
, data
+ i
, length
- i
));
3110 if (has_next
|| i
+ 2 < length
)
3112 if (plen
> 0 && plen
< 11)
3113 indent (e
, 11 - plen
);
3118 fprintf (e
, "\t/* ");
3119 ascii_print (e
, (const char *) &data
[i
], 2);
3120 fprintf (e
, ". */");
3132 ascii_print (e
, (const char *) &data
[i
], 1);
3141 fprintf (e
, "END\n");
3144 /* Write out an rcdata resource. This is also used for other types of
3145 resources that need to print arbitrary data. */
3148 write_rc_rcdata (FILE *e
, const rc_rcdata_item
*rcdata
, int ind
)
3150 const rc_rcdata_item
*ri
;
3153 fprintf (e
, "BEGIN\n");
3155 for (ri
= rcdata
; ri
!= NULL
; ri
= ri
->next
)
3157 if (ri
->type
== RCDATA_BUFFER
&& ri
->u
.buffer
.length
== 0)
3166 indent (e
, ind
+ 2);
3167 fprintf (e
, "%ld", (long) (ri
->u
.word
& 0xffff));
3171 indent (e
, ind
+ 2);
3172 fprintf (e
, "%luL", (unsigned long) ri
->u
.dword
);
3176 indent (e
, ind
+ 2);
3178 ascii_print (e
, ri
->u
.string
.s
, ri
->u
.string
.length
);
3182 case RCDATA_WSTRING
:
3183 indent (e
, ind
+ 2);
3185 unicode_print (e
, ri
->u
.wstring
.w
, ri
->u
.wstring
.length
);
3190 write_rc_datablock (e
, (rc_uint_type
) ri
->u
.buffer
.length
,
3191 (const bfd_byte
*) ri
->u
.buffer
.data
,
3192 ri
->next
!= NULL
, 0, -1);
3196 if (ri
->type
!= RCDATA_BUFFER
)
3198 if (ri
->next
!= NULL
)
3205 fprintf (e
, "END\n");
3208 /* Write out a stringtable resource. */
3211 write_rc_stringtable (FILE *e
, const rc_res_id
*name
,
3212 const rc_stringtable
*stringtable
)
3214 rc_uint_type offset
;
3217 if (name
!= NULL
&& ! name
->named
)
3218 offset
= (name
->u
.id
- 1) << 4;
3221 fprintf (e
, "/* %s string table name. */\n",
3222 name
== NULL
? "Missing" : "Invalid");
3226 fprintf (e
, "BEGIN\n");
3228 for (i
= 0; i
< 16; i
++)
3230 if (stringtable
->strings
[i
].length
!= 0)
3232 fprintf (e
, " %lu, ", (unsigned long) offset
+ i
);
3233 unicode_print_quoted (e
, stringtable
->strings
[i
].string
,
3234 stringtable
->strings
[i
].length
);
3239 fprintf (e
, "END\n");
3242 /* Write out a versioninfo resource. */
3245 write_rc_versioninfo (FILE *e
, const rc_versioninfo
*versioninfo
)
3247 const rc_fixed_versioninfo
*f
;
3248 const rc_ver_info
*vi
;
3250 f
= versioninfo
->fixed
;
3251 if (f
->file_version_ms
!= 0 || f
->file_version_ls
!= 0)
3252 fprintf (e
, " FILEVERSION %u, %u, %u, %u\n",
3253 (unsigned int) ((f
->file_version_ms
>> 16) & 0xffff),
3254 (unsigned int) (f
->file_version_ms
& 0xffff),
3255 (unsigned int) ((f
->file_version_ls
>> 16) & 0xffff),
3256 (unsigned int) (f
->file_version_ls
& 0xffff));
3257 if (f
->product_version_ms
!= 0 || f
->product_version_ls
!= 0)
3258 fprintf (e
, " PRODUCTVERSION %u, %u, %u, %u\n",
3259 (unsigned int) ((f
->product_version_ms
>> 16) & 0xffff),
3260 (unsigned int) (f
->product_version_ms
& 0xffff),
3261 (unsigned int) ((f
->product_version_ls
>> 16) & 0xffff),
3262 (unsigned int) (f
->product_version_ls
& 0xffff));
3263 if (f
->file_flags_mask
!= 0)
3264 fprintf (e
, " FILEFLAGSMASK 0x%x\n", (unsigned int) f
->file_flags_mask
);
3265 if (f
->file_flags
!= 0)
3266 fprintf (e
, " FILEFLAGS 0x%x\n", (unsigned int) f
->file_flags
);
3267 if (f
->file_os
!= 0)
3268 fprintf (e
, " FILEOS 0x%x\n", (unsigned int) f
->file_os
);
3269 if (f
->file_type
!= 0)
3270 fprintf (e
, " FILETYPE 0x%x\n", (unsigned int) f
->file_type
);
3271 if (f
->file_subtype
!= 0)
3272 fprintf (e
, " FILESUBTYPE 0x%x\n", (unsigned int) f
->file_subtype
);
3273 if (f
->file_date_ms
!= 0 || f
->file_date_ls
!= 0)
3274 fprintf (e
, "/* Date: %u, %u. */\n",
3275 (unsigned int) f
->file_date_ms
, (unsigned int) f
->file_date_ls
);
3277 fprintf (e
, "BEGIN\n");
3279 for (vi
= versioninfo
->var
; vi
!= NULL
; vi
= vi
->next
)
3283 case VERINFO_STRING
:
3285 const rc_ver_stringtable
*vst
;
3286 const rc_ver_stringinfo
*vs
;
3288 fprintf (e
, " BLOCK \"StringFileInfo\"\n");
3289 fprintf (e
, " BEGIN\n");
3291 for (vst
= vi
->u
.string
.stringtables
; vst
!= NULL
; vst
= vst
->next
)
3293 fprintf (e
, " BLOCK ");
3294 unicode_print_quoted (e
, vst
->language
, -1);
3297 fprintf (e
, " BEGIN\n");
3299 for (vs
= vst
->strings
; vs
!= NULL
; vs
= vs
->next
)
3301 fprintf (e
, " VALUE ");
3302 unicode_print_quoted (e
, vs
->key
, -1);
3304 unicode_print_quoted (e
, vs
->value
, -1);
3308 fprintf (e
, " END\n");
3310 fprintf (e
, " END\n");
3316 const rc_ver_varinfo
*vv
;
3318 fprintf (e
, " BLOCK \"VarFileInfo\"\n");
3319 fprintf (e
, " BEGIN\n");
3320 fprintf (e
, " VALUE ");
3321 unicode_print_quoted (e
, vi
->u
.var
.key
, -1);
3323 for (vv
= vi
->u
.var
.var
; vv
!= NULL
; vv
= vv
->next
)
3324 fprintf (e
, ", 0x%x, %d", (unsigned int) vv
->language
,
3327 fprintf (e
, "\n END\n");
3334 fprintf (e
, "END\n");
3338 rcdata_copy (const rc_rcdata_item
*src
, bfd_byte
*dst
)
3346 windres_put_16 (&wrtarget
, dst
, (rc_uint_type
) src
->u
.word
);
3350 windres_put_32 (&wrtarget
, dst
, (rc_uint_type
) src
->u
.dword
);
3353 if (dst
&& src
->u
.string
.length
)
3354 memcpy (dst
, src
->u
.string
.s
, src
->u
.string
.length
);
3355 return (rc_uint_type
) src
->u
.string
.length
;
3356 case RCDATA_WSTRING
:
3357 if (dst
&& src
->u
.wstring
.length
)
3358 memcpy (dst
, src
->u
.wstring
.w
, src
->u
.wstring
.length
* sizeof (unichar
));
3359 return (rc_uint_type
) (src
->u
.wstring
.length
* sizeof (unichar
));
3361 if (dst
&& src
->u
.buffer
.length
)
3362 memcpy (dst
, src
->u
.buffer
.data
, src
->u
.buffer
.length
);
3363 return (rc_uint_type
) src
->u
.buffer
.length
;
3367 /* Never reached. */