1 /* resrc.c -- read and write Windows rc files.
2 Copyright (C) 1997-2024 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_CMD "gcc"
79 #define DEFAULT_PREPROCESSOR_ARGS "-E -xc -DRC_INVOKED"
81 /* We read the directory entries in a cursor or icon file into
82 instances of this structure. */
88 /* Height of image. */
90 /* Number of colors in image. */
97 unsigned short planes
;
103 /* X coordinate of hotspot. */
104 unsigned short xhotspot
;
105 /* Y coordinate of hotspot. */
106 unsigned short yhotspot
;
109 /* Bytes in image. */
111 /* File offset of image. */
112 unsigned long offset
;
115 /* The name of the rc file we are reading. */
119 /* The line number in the rc file. */
123 /* The pipe we are reading from, so that we can close it if we exit. */
127 /* The temporary file used if we're not using popen, so we can delete it
130 static char *cpp_temp_file
;
132 /* Input stream is either a file or a pipe. */
134 static enum {ISTREAM_PIPE
, ISTREAM_FILE
} istream_type
;
136 /* As we read the rc file, we attach information to this structure. */
138 static rc_res_directory
*resources
;
140 /* The number of cursor resources we have written out. */
144 /* The number of font resources we have written out. */
148 /* Font directory information. */
150 rc_fontdir
*fontdirs
;
152 /* Resource info to use for fontdirs. */
154 rc_res_res_info fontdirs_resinfo
;
156 /* The number of icon resources we have written out. */
160 /* The windres target bfd . */
162 static windres_bfd wrtarget
=
164 (bfd
*) NULL
, (asection
*) NULL
, WR_KIND_TARGET
167 /* Local functions for rcdata based resource definitions. */
169 static void define_font_rcdata (rc_res_id
, const rc_res_res_info
*,
171 static void define_icon_rcdata (rc_res_id
, const rc_res_res_info
*,
173 static void define_bitmap_rcdata (rc_res_id
, const rc_res_res_info
*,
175 static void define_cursor_rcdata (rc_res_id
, const rc_res_res_info
*,
177 static void define_fontdir_rcdata (rc_res_id
, const rc_res_res_info
*,
179 static void define_messagetable_rcdata (rc_res_id
, const rc_res_res_info
*,
181 static rc_uint_type
rcdata_copy (const rc_rcdata_item
*, bfd_byte
*);
182 static bfd_byte
*rcdata_render_as_buffer (const rc_rcdata_item
*, rc_uint_type
*);
184 static int run_cmd (char *, const char *);
185 static FILE *open_input_stream (char *);
186 static FILE *look_for_default
187 (char *, const char *, int, const char *, const char *);
188 static void close_input_stream (void);
189 static void unexpected_eof (const char *);
190 static int get_word (FILE *, const char *);
191 static unsigned long get_long (FILE *, const char *);
192 static void get_data (FILE *, bfd_byte
*, rc_uint_type
, const char *);
193 static void define_fontdirs (void);
195 /* Run `cmd' and redirect the output to `redir'. */
198 run_cmd (char *cmd
, const char *redir
)
201 int pid
, wait_status
, retcode
;
204 char *errmsg_fmt
= NULL
, *errmsg_arg
= NULL
;
205 char *temp_base
= make_temp_file (NULL
);
208 int redir_handle
= -1;
209 int stdout_save
= -1;
211 /* Count the args. */
214 for (s
= cmd
; *s
; s
++)
219 argv
= xmalloc (sizeof (char *) * (i
+ 3));
225 while (*s
== ' ' && *s
!= 0)
231 in_quote
= (*s
== '\'' || *s
== '"');
232 sep
= (in_quote
) ? *s
++ : ' ';
235 while (*s
!= sep
&& *s
!= 0)
248 /* Setup the redirection. We can't use the usual fork/exec and redirect
249 since we may be running on non-POSIX Windows host. */
254 /* Open temporary output file. */
255 redir_handle
= open (redir
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0666);
256 if (redir_handle
== -1)
257 fatal (_("can't open temporary file `%s': %s"), redir
,
260 /* Duplicate the stdout file handle so it can be restored later. */
261 stdout_save
= dup (STDOUT_FILENO
);
262 if (stdout_save
== -1)
263 fatal (_("can't redirect stdout: `%s': %s"), redir
, strerror (errno
));
265 /* Redirect stdout to our output file. */
266 dup2 (redir_handle
, STDOUT_FILENO
);
268 pid
= pexecute (argv
[0], (char * const *) argv
, program_name
, temp_base
,
269 &errmsg_fmt
, &errmsg_arg
, PEXECUTE_ONE
| PEXECUTE_SEARCH
);
272 /* Restore stdout to its previous setting. */
273 dup2 (stdout_save
, STDOUT_FILENO
);
275 /* Close response file. */
276 close (redir_handle
);
280 fatal ("%s %s: %s", errmsg_fmt
, errmsg_arg
, strerror (errno
));
285 pid
= pwait (pid
, &wait_status
, 0);
289 fatal (_("wait: %s"), strerror (errno
));
292 else if (WIFSIGNALED (wait_status
))
294 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status
));
297 else if (WIFEXITED (wait_status
))
299 if (WEXITSTATUS (wait_status
) != 0)
301 fatal (_("%s exited with status %d"), cmd
,
302 WEXITSTATUS (wait_status
));
313 open_input_stream (char *cmd
)
315 if (istream_type
== ISTREAM_FILE
)
319 fileprefix
= make_temp_file (NULL
);
320 cpp_temp_file
= (char *) xmalloc (strlen (fileprefix
) + 5);
321 sprintf (cpp_temp_file
, "%s.irc", fileprefix
);
324 if (run_cmd (cmd
, cpp_temp_file
))
325 fatal (_("can't execute `%s': %s"), cmd
, strerror (errno
));
327 cpp_pipe
= fopen (cpp_temp_file
, FOPEN_RT
);
328 if (cpp_pipe
== NULL
)
329 fatal (_("can't open temporary file `%s': %s"),
330 cpp_temp_file
, strerror (errno
));
334 _("Using temporary file `%s' to read preprocessor output\n"),
339 cpp_pipe
= popen (cmd
, FOPEN_RT
);
340 if (cpp_pipe
== NULL
)
341 fatal (_("can't popen `%s': %s"), cmd
, strerror (errno
));
343 fprintf (stderr
, _("Using popen to read preprocessor output\n"));
346 xatexit (close_input_stream
);
350 /* Determine if FILENAME contains special characters that
351 can cause problems unless the entire filename is quoted. */
354 filename_need_quotes (const char *filename
)
356 if (filename
== NULL
|| (filename
[0] == '-' && filename
[1] == 0))
359 while (*filename
!= 0)
376 /* Look for the preprocessor program. */
379 look_for_default (char *cmd
, const char *prefix
, int end_prefix
,
380 const char *preprocargs
, const char *filename
)
384 const char *fnquotes
= (filename_need_quotes (filename
) ? "\"" : "");
386 memcpy (cmd
, prefix
, end_prefix
);
388 char *out
= stpcpy (cmd
+ end_prefix
, DEFAULT_PREPROCESSOR_CMD
);
391 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
392 strchr (cmd
, '\\') ||
396 found
= (stat (cmd
, &s
) == 0
397 #ifdef HAVE_EXECUTABLE_SUFFIX
398 || stat (strcat (cmd
, EXECUTABLE_SUFFIX
), &s
) == 0
405 fprintf (stderr
, _("Tried `%s'\n"), cmd
);
410 if (filename_need_quotes (cmd
))
412 memmove (cmd
+ 1, cmd
, out
- cmd
);
418 sprintf (out
, " %s %s %s%s%s",
419 DEFAULT_PREPROCESSOR_ARGS
, preprocargs
, fnquotes
, filename
, fnquotes
);
422 fprintf (stderr
, _("Using `%s'\n"), cmd
);
424 cpp_pipe
= open_input_stream (cmd
);
428 /* Read an rc file. */
431 read_rc_file (const char *filename
, const char *preprocessor
,
432 const char *preprocargs
, int language
, int use_temp_file
)
435 const char *fnquotes
= (filename_need_quotes (filename
) ? "\"" : "");
437 if (filename
== NULL
)
439 /* Setup the default resource import path taken from input file. */
440 else if (strchr (filename
, '/') != NULL
|| strchr (filename
, '\\') != NULL
)
444 edit
= dir
= xmalloc (strlen (filename
) + 3);
445 if (filename
[0] != '/'
446 && filename
[0] != '\\'
447 && filename
[1] != ':')
453 edit
= stpcpy (edit
, filename
);
455 /* Walk dir backwards stopping at the first directory separator. */
456 while (edit
> dir
&& (edit
[-1] != '\\' && edit
[-1] != '/'))
459 /* Cut off trailing slash. */
462 /* Convert all back slashes to forward slashes. */
463 while ((edit
= strchr (dir
, '\\')) != NULL
)
466 windres_add_include_dir (dir
);
469 istream_type
= (use_temp_file
) ? ISTREAM_FILE
: ISTREAM_PIPE
;
471 if (preprocargs
== NULL
)
476 cmd
= xmalloc (strlen (preprocessor
)
477 + strlen (preprocargs
)
479 + strlen (fnquotes
) * 2
481 sprintf (cmd
, "%s %s %s%s%s", preprocessor
, preprocargs
,
482 fnquotes
, filename
, fnquotes
);
484 cpp_pipe
= open_input_stream (cmd
);
488 char *dash
, *slash
, *cp
;
490 cmd
= xmalloc (strlen (program_name
)
491 + strlen (DEFAULT_PREPROCESSOR_CMD
)
492 + strlen (DEFAULT_PREPROCESSOR_ARGS
)
493 + strlen (preprocargs
)
495 + strlen (fnquotes
) * 2
496 #ifdef HAVE_EXECUTABLE_SUFFIX
497 + strlen (EXECUTABLE_SUFFIX
)
503 for (cp
= program_name
; *cp
; cp
++)
508 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
509 *cp
== ':' || *cp
== '\\' ||
522 /* First, try looking for a prefixed gcc in the windres
523 directory, with the same prefix as windres */
525 cpp_pipe
= look_for_default (cmd
, program_name
, dash
- program_name
+ 1,
526 preprocargs
, filename
);
529 if (slash
&& ! cpp_pipe
)
531 /* Next, try looking for a gcc in the same directory as
534 cpp_pipe
= look_for_default (cmd
, program_name
, slash
- program_name
+ 1,
535 preprocargs
, filename
);
540 /* Sigh, try the default */
542 cpp_pipe
= look_for_default (cmd
, "", 0, preprocargs
, filename
);
549 rc_filename
= xstrdup (filename
);
552 rcparse_set_language (language
);
554 rcparse_discard_strings ();
556 close_input_stream ();
558 if (fontdirs
!= NULL
)
567 /* Close the input stream if it is open. */
570 close_input_stream (void)
572 if (istream_type
== ISTREAM_FILE
)
574 if (cpp_pipe
!= NULL
)
577 if (cpp_temp_file
!= NULL
)
579 int errno_save
= errno
;
581 unlink (cpp_temp_file
);
583 free (cpp_temp_file
);
588 if (cpp_pipe
!= NULL
)
591 err
= pclose (cpp_pipe
);
592 /* We are reading from a pipe, therefore we don't
593 know if cpp failed or succeeded until pclose. */
594 if (err
!= 0 || errno
== ECHILD
)
596 /* Since this is also run via xatexit, safeguard. */
598 cpp_temp_file
= NULL
;
599 fatal (_("preprocessing failed."));
604 /* Since this is also run via xatexit, safeguard. */
606 cpp_temp_file
= NULL
;
609 /* Report an error while reading an rc file. */
612 yyerror (const char *msg
)
614 fatal ("%s:%d: %s", rc_filename
, rc_lineno
, msg
);
617 /* Issue a warning while reading an rc file. */
620 rcparse_warning (const char *msg
)
622 fprintf (stderr
, "%s:%d: %s\n", rc_filename
, rc_lineno
, msg
);
625 /* Die if we get an unexpected end of file. */
628 unexpected_eof (const char *msg
)
630 fatal (_("%s: unexpected EOF"), msg
);
633 /* Read a 16 bit word from a file. The data is assumed to be little
637 get_word (FILE *e
, const char *msg
)
644 unexpected_eof (msg
);
645 return ((b2
& 0xff) << 8) | (b1
& 0xff);
648 /* Read a 32 bit word from a file. The data is assumed to be little
652 get_long (FILE *e
, const char *msg
)
661 unexpected_eof (msg
);
662 return (((((((b4
& 0xff) << 8)
668 /* Read data from a file. This is a wrapper to do error checking. */
671 get_data (FILE *e
, bfd_byte
*p
, rc_uint_type c
, const char *msg
)
673 rc_uint_type got
; /* $$$d */
675 got
= (rc_uint_type
) fread (p
, 1, c
, e
);
679 fatal (_("%s: read of %lu returned %lu"),
680 msg
, (unsigned long) c
, (unsigned long) got
);
683 /* Define an accelerator resource. */
686 define_accelerator (rc_res_id id
, const rc_res_res_info
*resinfo
,
687 rc_accelerator
*data
)
691 r
= define_standard_resource (&resources
, RT_ACCELERATOR
, id
,
692 resinfo
->language
, 0);
693 r
->type
= RES_TYPE_ACCELERATOR
;
695 r
->res_info
= *resinfo
;
698 /* Define a bitmap resource. Bitmap data is stored in a file. The
699 first 14 bytes of the file are a standard header, which is not
700 included in the resource data. */
702 #define BITMAP_SKIP (14)
705 define_bitmap (rc_res_id id
, const rc_res_res_info
*resinfo
,
706 const char *filename
)
715 e
= open_file_search (filename
, FOPEN_RB
, "bitmap file", &real_filename
);
717 if (stat (real_filename
, &s
) < 0)
718 fatal (_("stat failed on bitmap file `%s': %s"), real_filename
,
721 data
= (bfd_byte
*) res_alloc (s
.st_size
- BITMAP_SKIP
);
723 for (i
= 0; i
< BITMAP_SKIP
; i
++)
726 get_data (e
, data
, s
.st_size
- BITMAP_SKIP
, real_filename
);
729 free (real_filename
);
731 r
= define_standard_resource (&resources
, RT_BITMAP
, id
,
732 resinfo
->language
, 0);
734 r
->type
= RES_TYPE_BITMAP
;
735 r
->u
.data
.length
= s
.st_size
- BITMAP_SKIP
;
736 r
->u
.data
.data
= data
;
737 r
->res_info
= *resinfo
;
740 /* Define a cursor resource. A cursor file may contain a set of
741 bitmaps, each representing the same cursor at various different
742 resolutions. They each get written out with a different ID. The
743 real cursor resource is then a group resource which can be used to
744 select one of the actual cursors. */
747 define_cursor (rc_res_id id
, const rc_res_res_info
*resinfo
,
748 const char *filename
)
753 struct icondir
*icondirs
;
756 rc_group_cursor
*first
, **pp
;
758 e
= open_file_search (filename
, FOPEN_RB
, "cursor file", &real_filename
);
760 /* A cursor file is basically an icon file. The start of the file
761 is a three word structure. The first word is ignored. The
762 second word is the type of data. The third word is the number of
765 get_word (e
, real_filename
);
766 type
= get_word (e
, real_filename
);
767 count
= get_word (e
, real_filename
);
769 fatal (_("cursor file `%s' does not contain cursor data"), real_filename
);
771 /* Read in the icon directory entries. */
773 icondirs
= (struct icondir
*) xmalloc (count
* sizeof *icondirs
);
775 for (i
= 0; i
< count
; i
++)
777 icondirs
[i
].width
= getc (e
);
778 icondirs
[i
].height
= getc (e
);
779 icondirs
[i
].colorcount
= getc (e
);
781 icondirs
[i
].u
.cursor
.xhotspot
= get_word (e
, real_filename
);
782 icondirs
[i
].u
.cursor
.yhotspot
= get_word (e
, real_filename
);
783 icondirs
[i
].bytes
= get_long (e
, real_filename
);
784 icondirs
[i
].offset
= get_long (e
, real_filename
);
787 unexpected_eof (real_filename
);
790 /* Define each cursor as a unique resource. */
792 first_cursor
= cursors
;
794 for (i
= 0; i
< count
; i
++)
800 if (fseek (e
, icondirs
[i
].offset
, SEEK_SET
) != 0)
801 fatal (_("%s: fseek to %lu failed: %s"), real_filename
,
802 icondirs
[i
].offset
, strerror (errno
));
804 data
= (bfd_byte
*) res_alloc (icondirs
[i
].bytes
);
806 get_data (e
, data
, icondirs
[i
].bytes
, real_filename
);
808 c
= (rc_cursor
*) res_alloc (sizeof (rc_cursor
));
809 c
->xhotspot
= icondirs
[i
].u
.cursor
.xhotspot
;
810 c
->yhotspot
= icondirs
[i
].u
.cursor
.yhotspot
;
811 c
->length
= icondirs
[i
].bytes
;
819 r
= define_standard_resource (&resources
, RT_CURSOR
, name
,
820 resinfo
->language
, 0);
821 r
->type
= RES_TYPE_CURSOR
;
823 r
->res_info
= *resinfo
;
827 free (real_filename
);
829 /* Define a cursor group resource. */
833 for (i
= 0; i
< count
; i
++)
837 cg
= (rc_group_cursor
*) res_alloc (sizeof (rc_group_cursor
));
839 cg
->width
= icondirs
[i
].width
;
840 cg
->height
= 2 * icondirs
[i
].height
;
842 /* FIXME: What should these be set to? */
846 cg
->bytes
= icondirs
[i
].bytes
+ 4;
847 cg
->index
= first_cursor
+ i
+ 1;
855 r
= define_standard_resource (&resources
, RT_GROUP_CURSOR
, id
,
856 resinfo
->language
, 0);
857 r
->type
= RES_TYPE_GROUP_CURSOR
;
858 r
->u
.group_cursor
= first
;
859 r
->res_info
= *resinfo
;
862 /* Define a dialog resource. */
865 define_dialog (rc_res_id id
, const rc_res_res_info
*resinfo
,
866 const rc_dialog
*dialog
)
871 copy
= (rc_dialog
*) res_alloc (sizeof *copy
);
874 r
= define_standard_resource (&resources
, RT_DIALOG
, id
,
875 resinfo
->language
, 0);
876 r
->type
= RES_TYPE_DIALOG
;
878 r
->res_info
= *resinfo
;
881 /* Define a dialog control. This does not define a resource, but
882 merely allocates and fills in a structure. */
885 define_control (const rc_res_id iid
, rc_uint_type id
, rc_uint_type x
,
886 rc_uint_type y
, rc_uint_type width
, rc_uint_type height
,
887 const rc_res_id
class, rc_uint_type style
,
888 rc_uint_type exstyle
)
890 rc_dialog_control
*n
;
892 n
= (rc_dialog_control
*) res_alloc (sizeof (rc_dialog_control
));
896 n
->exstyle
= exstyle
;
910 define_icon_control (rc_res_id iid
, rc_uint_type id
, rc_uint_type x
,
911 rc_uint_type y
, rc_uint_type style
,
912 rc_uint_type exstyle
, rc_uint_type help
,
913 rc_rcdata_item
*data
, rc_dialog_ex
*ex
)
915 rc_dialog_control
*n
;
920 style
= SS_ICON
| WS_CHILD
| WS_VISIBLE
;
921 res_string_to_id (&tid
, "");
923 cid
.u
.id
= CTL_STATIC
;
924 n
= define_control (tid
, id
, x
, y
, 0, 0, cid
, style
, exstyle
);
927 rcparse_warning (_("help ID requires DIALOGEX"));
929 rcparse_warning (_("control data requires DIALOGEX"));
936 /* Define a font resource. */
939 define_font (rc_res_id id
, const rc_res_res_info
*resinfo
,
940 const char *filename
)
951 const char *device
, *face
;
954 e
= open_file_search (filename
, FOPEN_RB
, "font file", &real_filename
);
956 if (stat (real_filename
, &s
) < 0)
957 fatal (_("stat failed on font file `%s': %s"), real_filename
,
960 data
= (bfd_byte
*) res_alloc (s
.st_size
);
962 get_data (e
, data
, s
.st_size
, real_filename
);
965 free (real_filename
);
967 r
= define_standard_resource (&resources
, RT_FONT
, id
,
968 resinfo
->language
, 0);
970 r
->type
= RES_TYPE_FONT
;
971 r
->u
.data
.length
= s
.st_size
;
972 r
->u
.data
.data
= data
;
973 r
->res_info
= *resinfo
;
975 /* For each font resource, we must add an entry in the FONTDIR
976 resource. The FONTDIR resource includes some strings in the font
977 file. To find them, we have to do some magic on the data we have
980 offset
= ((((((data
[47] << 8)
984 if (offset
> 0 && offset
< s
.st_size
)
985 device
= (char *) data
+ offset
;
989 offset
= ((((((data
[51] << 8)
993 if (offset
> 0 && offset
< s
.st_size
)
994 face
= (char *) data
+ offset
;
1000 fontdatalength
= 58 + strlen (device
) + strlen (face
);
1001 fontdata
= (bfd_byte
*) res_alloc (fontdatalength
);
1002 memcpy (fontdata
, data
, 56);
1003 strcpy ((char *) fontdata
+ 56, device
);
1004 strcpy ((char *) fontdata
+ 57 + strlen (device
), face
);
1006 fd
= (rc_fontdir
*) res_alloc (sizeof (rc_fontdir
));
1009 fd
->length
= fontdatalength
;
1010 fd
->data
= fontdata
;
1012 for (pp
= &fontdirs
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1016 /* For the single fontdirs resource, we always use the resource
1017 information of the last font. I don't know what else to do. */
1018 fontdirs_resinfo
= *resinfo
;
1022 define_font_rcdata (rc_res_id id
,const rc_res_res_info
*resinfo
,
1023 rc_rcdata_item
*data
)
1026 rc_uint_type len_data
;
1029 r
= define_standard_resource (&resources
, RT_FONT
, id
,
1030 resinfo
->language
, 0);
1032 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1034 r
->type
= RES_TYPE_FONT
;
1035 r
->u
.data
.length
= len_data
;
1036 r
->u
.data
.data
= pb_data
;
1037 r
->res_info
= *resinfo
;
1040 /* Define the fontdirs resource. This is called after the entire rc
1041 file has been parsed, if any font resources were seen. */
1044 define_fontdirs (void)
1052 r
= define_standard_resource (&resources
, RT_FONTDIR
, id
, 0x409, 0);
1054 r
->type
= RES_TYPE_FONTDIR
;
1055 r
->u
.fontdir
= fontdirs
;
1056 r
->res_info
= fontdirs_resinfo
;
1060 rcdata_render_as_buffer (const rc_rcdata_item
*data
, rc_uint_type
*plen
)
1062 const rc_rcdata_item
*d
;
1063 bfd_byte
*ret
= NULL
, *pret
;
1064 rc_uint_type len
= 0;
1066 for (d
= data
; d
!= NULL
; d
= d
->next
)
1067 len
+= rcdata_copy (d
, NULL
);
1070 ret
= pret
= (bfd_byte
*) res_alloc (len
);
1071 for (d
= data
; d
!= NULL
; d
= d
->next
)
1072 pret
+= rcdata_copy (d
, pret
);
1080 define_fontdir_rcdata (rc_res_id id
,const rc_res_res_info
*resinfo
,
1081 rc_rcdata_item
*data
)
1084 rc_fontdir
*fd
, *fd_first
, *fd_cur
;
1085 rc_uint_type len_data
;
1089 fd_cur
= fd_first
= NULL
;
1090 r
= define_standard_resource (&resources
, RT_FONTDIR
, id
, 0x409, 0);
1092 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1096 rc_uint_type off
= 2;
1097 c
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1101 rc_uint_type safe_pos
= off
;
1102 const struct bin_fontdir_item
*bfi
;
1104 bfi
= (const struct bin_fontdir_item
*) pb_data
+ off
;
1105 fd
= (rc_fontdir
*) res_alloc (sizeof (rc_fontdir
));
1106 fd
->index
= windres_get_16 (&wrtarget
, bfi
->index
, len_data
- off
);
1107 fd
->data
= pb_data
+ off
;
1109 len
= strlen ((char *) bfi
->device_name
) + 1;
1110 off
+= (rc_uint_type
) len
;
1111 off
+= (rc_uint_type
) strlen ((char *) bfi
->device_name
+ len
) + 1;
1112 fd
->length
= (off
- safe_pos
);
1114 if (fd_first
== NULL
)
1121 r
->type
= RES_TYPE_FONTDIR
;
1122 r
->u
.fontdir
= fd_first
;
1123 r
->res_info
= *resinfo
;
1126 static void define_messagetable_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1127 rc_rcdata_item
*data
)
1130 rc_uint_type len_data
;
1133 r
= define_standard_resource (&resources
, RT_MESSAGETABLE
, id
, resinfo
->language
, 0);
1135 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1136 r
->type
= RES_TYPE_MESSAGETABLE
;
1137 r
->u
.data
.length
= len_data
;
1138 r
->u
.data
.data
= pb_data
;
1139 r
->res_info
= *resinfo
;
1142 /* Define an icon resource. An icon file may contain a set of
1143 bitmaps, each representing the same icon at various different
1144 resolutions. They each get written out with a different ID. The
1145 real icon resource is then a group resource which can be used to
1146 select one of the actual icon bitmaps. */
1149 define_icon (rc_res_id id
, const rc_res_res_info
*resinfo
,
1150 const char *filename
)
1153 char *real_filename
;
1155 struct icondir
*icondirs
;
1158 rc_group_icon
*first
, **pp
;
1160 e
= open_file_search (filename
, FOPEN_RB
, "icon file", &real_filename
);
1162 /* The start of an icon file is a three word structure. The first
1163 word is ignored. The second word is the type of data. The third
1164 word is the number of entries. */
1166 get_word (e
, real_filename
);
1167 type
= get_word (e
, real_filename
);
1168 count
= get_word (e
, real_filename
);
1170 fatal (_("icon file `%s' does not contain icon data"), real_filename
);
1172 /* Read in the icon directory entries. */
1174 icondirs
= (struct icondir
*) xmalloc (count
* sizeof *icondirs
);
1176 for (i
= 0; i
< count
; i
++)
1178 icondirs
[i
].width
= getc (e
);
1179 icondirs
[i
].height
= getc (e
);
1180 icondirs
[i
].colorcount
= getc (e
);
1182 icondirs
[i
].u
.icon
.planes
= get_word (e
, real_filename
);
1183 icondirs
[i
].u
.icon
.bits
= get_word (e
, real_filename
);
1184 icondirs
[i
].bytes
= get_long (e
, real_filename
);
1185 icondirs
[i
].offset
= get_long (e
, real_filename
);
1188 unexpected_eof (real_filename
);
1191 /* Define each icon as a unique resource. */
1195 for (i
= 0; i
< count
; i
++)
1200 if (fseek (e
, icondirs
[i
].offset
, SEEK_SET
) != 0)
1201 fatal (_("%s: fseek to %lu failed: %s"), real_filename
,
1202 icondirs
[i
].offset
, strerror (errno
));
1204 data
= (bfd_byte
*) res_alloc (icondirs
[i
].bytes
);
1206 get_data (e
, data
, icondirs
[i
].bytes
, real_filename
);
1213 r
= define_standard_resource (&resources
, RT_ICON
, name
,
1214 resinfo
->language
, 0);
1215 r
->type
= RES_TYPE_ICON
;
1216 r
->u
.data
.length
= icondirs
[i
].bytes
;
1217 r
->u
.data
.data
= data
;
1218 r
->res_info
= *resinfo
;
1222 free (real_filename
);
1224 /* Define an icon group resource. */
1228 for (i
= 0; i
< count
; i
++)
1232 /* For some reason, at least in some files the planes and bits
1233 are zero. We instead set them from the color. This is
1236 cg
= (rc_group_icon
*) res_alloc (sizeof (rc_group_icon
));
1238 cg
->width
= icondirs
[i
].width
;
1239 cg
->height
= icondirs
[i
].height
;
1240 cg
->colors
= icondirs
[i
].colorcount
;
1242 if (icondirs
[i
].u
.icon
.planes
)
1243 cg
->planes
= icondirs
[i
].u
.icon
.planes
;
1247 if (icondirs
[i
].u
.icon
.bits
)
1248 cg
->bits
= icondirs
[i
].u
.icon
.bits
;
1253 while ((1L << cg
->bits
) < cg
->colors
)
1257 cg
->bytes
= icondirs
[i
].bytes
;
1258 cg
->index
= first_icon
+ i
+ 1;
1266 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1267 resinfo
->language
, 0);
1268 r
->type
= RES_TYPE_GROUP_ICON
;
1269 r
->u
.group_icon
= first
;
1270 r
->res_info
= *resinfo
;
1274 define_group_icon_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1275 rc_rcdata_item
*data
)
1278 rc_group_icon
*cg
, *first
, *cur
;
1279 rc_uint_type len_data
;
1282 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1287 while (len_data
>= 6)
1290 unsigned short type
;
1291 type
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1293 fatal (_("unexpected group icon type %d"), type
);
1294 c
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1298 for (i
= 0; i
< c
; i
++)
1301 fatal ("too small group icon rcdata");
1302 cg
= (rc_group_icon
*) res_alloc (sizeof (rc_group_icon
));
1304 cg
->width
= pb_data
[0];
1305 cg
->height
= pb_data
[1];
1306 cg
->colors
= pb_data
[2];
1307 cg
->planes
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1308 cg
->bits
= windres_get_16 (&wrtarget
, pb_data
+ 6, len_data
- 6);
1309 cg
->bytes
= windres_get_32 (&wrtarget
, pb_data
+ 8, len_data
- 8);
1310 cg
->index
= windres_get_16 (&wrtarget
, pb_data
+ 12, len_data
- 12);
1320 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1321 resinfo
->language
, 0);
1322 r
->type
= RES_TYPE_GROUP_ICON
;
1323 r
->u
.group_icon
= first
;
1324 r
->res_info
= *resinfo
;
1328 define_group_cursor_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1329 rc_rcdata_item
*data
)
1332 rc_group_cursor
*cg
, *first
, *cur
;
1333 rc_uint_type len_data
;
1336 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1340 while (len_data
>= 6)
1343 unsigned short type
;
1344 type
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1346 fatal (_("unexpected group cursor type %d"), type
);
1347 c
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1351 for (i
= 0; i
< c
; i
++)
1354 fatal ("too small group icon rcdata");
1355 cg
= (rc_group_cursor
*) res_alloc (sizeof (rc_group_cursor
));
1357 cg
->width
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1358 cg
->height
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1359 cg
->planes
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1360 cg
->bits
= windres_get_16 (&wrtarget
, pb_data
+ 6, len_data
- 6);
1361 cg
->bytes
= windres_get_32 (&wrtarget
, pb_data
+ 8, len_data
- 8);
1362 cg
->index
= windres_get_16 (&wrtarget
, pb_data
+ 12, len_data
- 12);
1373 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1374 resinfo
->language
, 0);
1375 r
->type
= RES_TYPE_GROUP_CURSOR
;
1376 r
->u
.group_cursor
= first
;
1377 r
->res_info
= *resinfo
;
1381 define_cursor_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1382 rc_rcdata_item
*data
)
1386 rc_uint_type len_data
;
1389 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1391 c
= (rc_cursor
*) res_alloc (sizeof (rc_cursor
));
1392 c
->xhotspot
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1393 c
->yhotspot
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1394 c
->length
= len_data
- BIN_CURSOR_SIZE
;
1395 c
->data
= (const bfd_byte
*) (data
+ BIN_CURSOR_SIZE
);
1397 r
= define_standard_resource (&resources
, RT_CURSOR
, id
, resinfo
->language
, 0);
1398 r
->type
= RES_TYPE_CURSOR
;
1400 r
->res_info
= *resinfo
;
1404 define_bitmap_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1405 rc_rcdata_item
*data
)
1408 rc_uint_type len_data
;
1411 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1413 r
= define_standard_resource (&resources
, RT_BITMAP
, id
, resinfo
->language
, 0);
1414 r
->type
= RES_TYPE_BITMAP
;
1415 r
->u
.data
.length
= len_data
;
1416 r
->u
.data
.data
= pb_data
;
1417 r
->res_info
= *resinfo
;
1421 define_icon_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1422 rc_rcdata_item
*data
)
1425 rc_uint_type len_data
;
1428 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1430 r
= define_standard_resource (&resources
, RT_ICON
, id
, resinfo
->language
, 0);
1431 r
->type
= RES_TYPE_ICON
;
1432 r
->u
.data
.length
= len_data
;
1433 r
->u
.data
.data
= pb_data
;
1434 r
->res_info
= *resinfo
;
1437 /* Define a menu resource. */
1440 define_menu (rc_res_id id
, const rc_res_res_info
*resinfo
,
1441 rc_menuitem
*menuitems
)
1446 m
= (rc_menu
*) res_alloc (sizeof (rc_menu
));
1447 m
->items
= menuitems
;
1450 r
= define_standard_resource (&resources
, RT_MENU
, id
, resinfo
->language
, 0);
1451 r
->type
= RES_TYPE_MENU
;
1453 r
->res_info
= *resinfo
;
1456 /* Define a menu item. This does not define a resource, but merely
1457 allocates and fills in a structure. */
1460 define_menuitem (const unichar
*text
, rc_uint_type menuid
, rc_uint_type type
,
1461 rc_uint_type state
, rc_uint_type help
,
1462 rc_menuitem
*menuitems
)
1466 mi
= (rc_menuitem
*) res_alloc (sizeof (rc_menuitem
));
1471 mi
->text
= unichar_dup (text
);
1473 mi
->popup
= menuitems
;
1477 /* Define a messagetable resource. */
1480 define_messagetable (rc_res_id id
, const rc_res_res_info
*resinfo
,
1481 const char *filename
)
1484 char *real_filename
;
1489 e
= open_file_search (filename
, FOPEN_RB
, "messagetable file",
1492 if (stat (real_filename
, &s
) < 0)
1493 fatal (_("stat failed on bitmap file `%s': %s"), real_filename
,
1496 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1498 get_data (e
, data
, s
.st_size
, real_filename
);
1501 free (real_filename
);
1503 r
= define_standard_resource (&resources
, RT_MESSAGETABLE
, id
,
1504 resinfo
->language
, 0);
1506 r
->type
= RES_TYPE_MESSAGETABLE
;
1507 r
->u
.data
.length
= s
.st_size
;
1508 r
->u
.data
.data
= data
;
1509 r
->res_info
= *resinfo
;
1512 /* Define an rcdata resource. */
1515 define_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1516 rc_rcdata_item
*data
)
1520 r
= define_standard_resource (&resources
, RT_RCDATA
, id
,
1521 resinfo
->language
, 0);
1522 r
->type
= RES_TYPE_RCDATA
;
1524 r
->res_info
= *resinfo
;
1527 /* Create an rcdata item holding a string. */
1530 define_rcdata_string (const char *string
, rc_uint_type len
)
1535 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1537 ri
->type
= RCDATA_STRING
;
1538 ri
->u
.string
.length
= len
;
1539 s
= (char *) res_alloc (len
);
1540 memcpy (s
, string
, len
);
1546 /* Create an rcdata item holding a unicode string. */
1549 define_rcdata_unistring (const unichar
*string
, rc_uint_type len
)
1554 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1556 ri
->type
= RCDATA_WSTRING
;
1557 ri
->u
.wstring
.length
= len
;
1558 s
= (unichar
*) res_alloc (len
* sizeof (unichar
));
1559 memcpy (s
, string
, len
* sizeof (unichar
));
1560 ri
->u
.wstring
.w
= s
;
1565 /* Create an rcdata item holding a number. */
1568 define_rcdata_number (rc_uint_type val
, int dword
)
1572 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1574 ri
->type
= dword
? RCDATA_DWORD
: RCDATA_WORD
;
1580 /* Define a stringtable resource. This is called for each string
1581 which appears in a STRINGTABLE statement. */
1584 define_stringtable (const rc_res_res_info
*resinfo
,
1585 rc_uint_type stringid
, const unichar
*string
, int len
)
1592 id
.u
.id
= (stringid
>> 4) + 1;
1593 r
= define_standard_resource (&resources
, RT_STRING
, id
,
1594 resinfo
->language
, 1);
1596 if (r
->type
== RES_TYPE_UNINITIALIZED
)
1600 r
->type
= RES_TYPE_STRINGTABLE
;
1601 r
->u
.stringtable
= ((rc_stringtable
*)
1602 res_alloc (sizeof (rc_stringtable
)));
1603 for (i
= 0; i
< 16; i
++)
1605 r
->u
.stringtable
->strings
[i
].length
= 0;
1606 r
->u
.stringtable
->strings
[i
].string
= NULL
;
1609 r
->res_info
= *resinfo
;
1611 h
= (unichar
*) res_alloc ((len
+ 1) * sizeof (unichar
));
1613 memcpy (h
, string
, len
* sizeof (unichar
));
1615 r
->u
.stringtable
->strings
[stringid
& 0xf].length
= (rc_uint_type
) len
;
1616 r
->u
.stringtable
->strings
[stringid
& 0xf].string
= h
;
1620 define_toolbar (rc_res_id id
, rc_res_res_info
*resinfo
, rc_uint_type width
, rc_uint_type height
,
1621 rc_toolbar_item
*items
)
1626 t
= (rc_toolbar
*) res_alloc (sizeof (rc_toolbar
));
1627 t
->button_width
= width
;
1628 t
->button_height
= height
;
1631 while (items
!= NULL
)
1634 items
= items
->next
;
1636 r
= define_standard_resource (&resources
, RT_TOOLBAR
, id
, resinfo
->language
, 0);
1637 r
->type
= RES_TYPE_TOOLBAR
;
1639 r
->res_info
= *resinfo
;
1642 /* Define a user data resource where the data is in the rc file. */
1645 define_user_data (rc_res_id id
, rc_res_id type
,
1646 const rc_res_res_info
*resinfo
,
1647 rc_rcdata_item
*data
)
1652 rc_uint_type len_data
;
1654 /* We have to check if the binary data is parsed specially. */
1655 if (type
.named
== 0)
1660 define_fontdir_rcdata (id
, resinfo
, data
);
1663 define_font_rcdata (id
, resinfo
, data
);
1666 define_icon_rcdata (id
, resinfo
, data
);
1669 define_bitmap_rcdata (id
, resinfo
, data
);
1672 define_cursor_rcdata (id
, resinfo
, data
);
1675 define_group_icon_rcdata (id
, resinfo
, data
);
1677 case RT_GROUP_CURSOR
:
1678 define_group_cursor_rcdata (id
, resinfo
, data
);
1680 case RT_MESSAGETABLE
:
1681 define_messagetable_rcdata (id
, resinfo
, data
);
1684 /* Treat as normal user-data. */
1691 ids
[2].u
.id
= resinfo
->language
;
1693 r
= define_resource (& resources
, 3, ids
, 0);
1694 r
->type
= RES_TYPE_USERDATA
;
1695 r
->u
.userdata
= ((rc_rcdata_item
*)
1696 res_alloc (sizeof (rc_rcdata_item
)));
1697 r
->u
.userdata
->next
= NULL
;
1698 r
->u
.userdata
->type
= RCDATA_BUFFER
;
1699 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1700 r
->u
.userdata
->u
.buffer
.length
= len_data
;
1701 r
->u
.userdata
->u
.buffer
.data
= pb_data
;
1702 r
->res_info
= *resinfo
;
1706 define_rcdata_file (rc_res_id id
, const rc_res_res_info
*resinfo
,
1707 const char *filename
)
1711 char *real_filename
;
1715 e
= open_file_search (filename
, FOPEN_RB
, "file", &real_filename
);
1718 if (stat (real_filename
, &s
) < 0)
1719 fatal (_("stat failed on file `%s': %s"), real_filename
,
1722 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1724 get_data (e
, data
, s
.st_size
, real_filename
);
1727 free (real_filename
);
1729 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1731 ri
->type
= RCDATA_BUFFER
;
1732 ri
->u
.buffer
.length
= s
.st_size
;
1733 ri
->u
.buffer
.data
= data
;
1735 define_rcdata (id
, resinfo
, ri
);
1738 /* Define a user data resource where the data is in a file. */
1741 define_user_file (rc_res_id id
, rc_res_id type
,
1742 const rc_res_res_info
*resinfo
, const char *filename
)
1745 char *real_filename
;
1751 e
= open_file_search (filename
, FOPEN_RB
, "file", &real_filename
);
1753 if (stat (real_filename
, &s
) < 0)
1754 fatal (_("stat failed on file `%s': %s"), real_filename
,
1757 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1759 get_data (e
, data
, s
.st_size
, real_filename
);
1762 free (real_filename
);
1767 ids
[2].u
.id
= resinfo
->language
;
1769 r
= define_resource (&resources
, 3, ids
, 0);
1770 r
->type
= RES_TYPE_USERDATA
;
1771 r
->u
.userdata
= ((rc_rcdata_item
*)
1772 res_alloc (sizeof (rc_rcdata_item
)));
1773 r
->u
.userdata
->next
= NULL
;
1774 r
->u
.userdata
->type
= RCDATA_BUFFER
;
1775 r
->u
.userdata
->u
.buffer
.length
= s
.st_size
;
1776 r
->u
.userdata
->u
.buffer
.data
= data
;
1777 r
->res_info
= *resinfo
;
1780 /* Define a versioninfo resource. */
1783 define_versioninfo (rc_res_id id
, rc_uint_type language
,
1784 rc_fixed_versioninfo
*fixedverinfo
,
1785 rc_ver_info
*verinfo
)
1789 r
= define_standard_resource (&resources
, RT_VERSION
, id
, language
, 0);
1790 r
->type
= RES_TYPE_VERSIONINFO
;
1791 r
->u
.versioninfo
= ((rc_versioninfo
*)
1792 res_alloc (sizeof (rc_versioninfo
)));
1793 r
->u
.versioninfo
->fixed
= fixedverinfo
;
1794 r
->u
.versioninfo
->var
= verinfo
;
1795 r
->res_info
.language
= language
;
1798 /* Add string version info to a list of version information. */
1801 append_ver_stringfileinfo (rc_ver_info
*verinfo
,
1802 rc_ver_stringtable
*stringtables
)
1804 rc_ver_info
*vi
, **pp
;
1806 vi
= (rc_ver_info
*) res_alloc (sizeof (rc_ver_info
));
1808 vi
->type
= VERINFO_STRING
;
1809 vi
->u
.string
.stringtables
= stringtables
;
1811 for (pp
= &verinfo
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1818 rc_ver_stringtable
*
1819 append_ver_stringtable (rc_ver_stringtable
*stringtable
,
1820 const char *language
,
1821 rc_ver_stringinfo
*strings
)
1823 rc_ver_stringtable
*vst
, **pp
;
1825 vst
= (rc_ver_stringtable
*) res_alloc (sizeof (rc_ver_stringtable
));
1827 unicode_from_ascii ((rc_uint_type
*) NULL
, &vst
->language
, language
);
1828 vst
->strings
= strings
;
1830 for (pp
= &stringtable
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1837 /* Add variable version info to a list of version information. */
1840 append_ver_varfileinfo (rc_ver_info
*verinfo
, const unichar
*key
,
1841 rc_ver_varinfo
*var
)
1843 rc_ver_info
*vi
, **pp
;
1845 vi
= (rc_ver_info
*) res_alloc (sizeof *vi
);
1847 vi
->type
= VERINFO_VAR
;
1848 vi
->u
.var
.key
= unichar_dup (key
);
1849 vi
->u
.var
.var
= var
;
1851 for (pp
= &verinfo
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1858 /* Append version string information to a list. */
1861 append_verval (rc_ver_stringinfo
*strings
, const unichar
*key
,
1862 const unichar
*value
)
1864 rc_ver_stringinfo
*vs
, **pp
;
1866 vs
= (rc_ver_stringinfo
*) res_alloc (sizeof (rc_ver_stringinfo
));
1868 vs
->key
= unichar_dup (key
);
1869 vs
->value
= unichar_dup (value
);
1871 for (pp
= &strings
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1878 /* Append version variable information to a list. */
1881 append_vertrans (rc_ver_varinfo
*var
, rc_uint_type language
,
1882 rc_uint_type charset
)
1884 rc_ver_varinfo
*vv
, **pp
;
1886 vv
= (rc_ver_varinfo
*) res_alloc (sizeof (rc_ver_varinfo
));
1888 vv
->language
= language
;
1889 vv
->charset
= charset
;
1891 for (pp
= &var
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1898 /* Local functions used to write out an rc file. */
1900 static void indent (FILE *, int);
1901 static void write_rc_directory (FILE *, const rc_res_directory
*, const rc_res_id
*,
1902 const rc_res_id
*, rc_uint_type
*, int);
1903 static void write_rc_subdir (FILE *, const rc_res_entry
*, const rc_res_id
*,
1904 const rc_res_id
*, rc_uint_type
*, int);
1905 static void write_rc_resource (FILE *, const rc_res_id
*, const rc_res_id
*,
1906 const rc_res_resource
*, rc_uint_type
*);
1907 static void write_rc_accelerators (FILE *, const rc_accelerator
*);
1908 static void write_rc_cursor (FILE *, const rc_cursor
*);
1909 static void write_rc_group_cursor (FILE *, const rc_group_cursor
*);
1910 static void write_rc_dialog (FILE *, const rc_dialog
*);
1911 static void write_rc_dialog_control (FILE *, const rc_dialog_control
*);
1912 static void write_rc_fontdir (FILE *, const rc_fontdir
*);
1913 static void write_rc_group_icon (FILE *, const rc_group_icon
*);
1914 static void write_rc_menu (FILE *, const rc_menu
*, int);
1915 static void write_rc_toolbar (FILE *, const rc_toolbar
*);
1916 static void write_rc_menuitems (FILE *, const rc_menuitem
*, int, int);
1917 static void write_rc_messagetable (FILE *, rc_uint_type
, const bfd_byte
*);
1919 static void write_rc_datablock (FILE *, rc_uint_type
, const bfd_byte
*, int, int, int);
1920 static void write_rc_rcdata (FILE *, const rc_rcdata_item
*, int);
1921 static void write_rc_stringtable (FILE *, const rc_res_id
*, const rc_stringtable
*);
1922 static void write_rc_versioninfo (FILE *, const rc_versioninfo
*);
1924 /* Indent a given number of spaces. */
1927 indent (FILE *e
, int c
)
1931 for (i
= 0; i
< c
; i
++)
1935 /* Dump the resources we have read in the format of an rc file.
1937 Reasoned by the fact, that some resources need to be stored into file and
1938 refer to that file, we use the user-data model for that to express it binary
1939 without the need to store it somewhere externally. */
1942 write_rc_file (const char *filename
, const rc_res_directory
*res_dir
)
1945 rc_uint_type language
;
1947 if (filename
== NULL
)
1951 e
= fopen (filename
, FOPEN_WT
);
1953 fatal (_("can't open `%s' for output: %s"), filename
, strerror (errno
));
1956 language
= (rc_uint_type
) ((bfd_signed_vma
) -1);
1957 write_rc_directory (e
, res_dir
, (const rc_res_id
*) NULL
,
1958 (const rc_res_id
*) NULL
, &language
, 1);
1961 /* Write out a directory. E is the file to write to. RD is the
1962 directory. TYPE is a pointer to the level 1 ID which serves as the
1963 resource type. NAME is a pointer to the level 2 ID which serves as
1964 an individual resource name. LANGUAGE is a pointer to the current
1965 language. LEVEL is the level in the tree. */
1968 write_rc_directory (FILE *e
, const rc_res_directory
*rd
,
1969 const rc_res_id
*type
, const rc_res_id
*name
,
1970 rc_uint_type
*language
, int level
)
1972 const rc_res_entry
*re
;
1974 /* Print out some COFF information that rc files can't represent. */
1975 if (rd
->time
!= 0 || rd
->characteristics
!= 0 || rd
->major
!= 0 || rd
->minor
!= 0)
1977 wr_printcomment (e
, "COFF information not part of RC");
1979 wr_printcomment (e
, "Time stamp: %u", rd
->time
);
1980 if (rd
->characteristics
!= 0)
1981 wr_printcomment (e
, "Characteristics: %u", rd
->characteristics
);
1982 if (rd
->major
!= 0 || rd
->minor
!= 0)
1983 wr_printcomment (e
, "Version major:%d minor:%d", rd
->major
, rd
->minor
);
1986 for (re
= rd
->entries
; re
!= NULL
; re
= re
->next
)
1991 /* If we're at level 1, the key of this resource is the
1992 type. This normally duplicates the information we have
1993 stored with the resource itself, but we need to remember
1994 the type if this is a user define resource type. */
1999 /* If we're at level 2, the key of this resource is the name
2000 we are going to use in the rc printout. */
2005 /* If we're at level 3, then this key represents a language.
2006 Use it to update the current language. */
2008 && re
->id
.u
.id
!= (unsigned long) (unsigned int) *language
2009 && (re
->id
.u
.id
& 0xffff) == re
->id
.u
.id
)
2011 wr_print (e
, "LANGUAGE %u, %u\n",
2012 re
->id
.u
.id
& ((1 << SUBLANG_SHIFT
) - 1),
2013 (re
->id
.u
.id
>> SUBLANG_SHIFT
) & 0xff);
2014 *language
= re
->id
.u
.id
;
2023 write_rc_subdir (e
, re
, type
, name
, language
, level
);
2028 /* This is the normal case: the three levels are
2029 TYPE/NAME/LANGUAGE. NAME will have been set at level
2030 2, and represents the name to use. We probably just
2031 set LANGUAGE, and it will probably match what the
2032 resource itself records if anything. */
2033 write_rc_resource (e
, type
, name
, re
->u
.res
, language
);
2037 wr_printcomment (e
, "Resource at unexpected level %d", level
);
2038 write_rc_resource (e
, type
, (rc_res_id
*) NULL
, re
->u
.res
,
2043 if (rd
->entries
== NULL
)
2049 /* Write out a subdirectory entry. E is the file to write to. RE is
2050 the subdirectory entry. TYPE and NAME are pointers to higher level
2051 IDs, or NULL. LANGUAGE is a pointer to the current language.
2052 LEVEL is the level in the tree. */
2055 write_rc_subdir (FILE *e
, const rc_res_entry
*re
,
2056 const rc_res_id
*type
, const rc_res_id
*name
,
2057 rc_uint_type
*language
, int level
)
2063 wr_printcomment (e
, "Type: ");
2065 res_id_print (e
, re
->id
, 1);
2070 switch (re
->id
.u
.id
)
2072 case RT_CURSOR
: s
= "cursor"; break;
2073 case RT_BITMAP
: s
= "bitmap"; break;
2074 case RT_ICON
: s
= "icon"; break;
2075 case RT_MENU
: s
= "menu"; break;
2076 case RT_DIALOG
: s
= "dialog"; break;
2077 case RT_STRING
: s
= "stringtable"; break;
2078 case RT_FONTDIR
: s
= "fontdir"; break;
2079 case RT_FONT
: s
= "font"; break;
2080 case RT_ACCELERATOR
: s
= "accelerators"; break;
2081 case RT_RCDATA
: s
= "rcdata"; break;
2082 case RT_MESSAGETABLE
: s
= "messagetable"; break;
2083 case RT_GROUP_CURSOR
: s
= "group cursor"; break;
2084 case RT_GROUP_ICON
: s
= "group icon"; break;
2085 case RT_VERSION
: s
= "version"; break;
2086 case RT_DLGINCLUDE
: s
= "dlginclude"; break;
2087 case RT_PLUGPLAY
: s
= "plugplay"; break;
2088 case RT_VXD
: s
= "vxd"; break;
2089 case RT_ANICURSOR
: s
= "anicursor"; break;
2090 case RT_ANIICON
: s
= "aniicon"; break;
2091 case RT_TOOLBAR
: s
= "toolbar"; break;
2092 case RT_HTML
: s
= "html"; break;
2093 default: s
= NULL
; break;
2097 fprintf (e
, "%s", s
);
2099 res_id_print (e
, re
->id
, 1);
2104 wr_printcomment (e
, "Name: ");
2105 res_id_print (e
, re
->id
, 1);
2109 wr_printcomment (e
, "Language: ");
2110 res_id_print (e
, re
->id
, 1);
2114 wr_printcomment (e
, "Level %d: ", level
);
2115 res_id_print (e
, re
->id
, 1);
2118 write_rc_directory (e
, re
->u
.dir
, type
, name
, language
, level
+ 1);
2121 /* Write out a single resource. E is the file to write to. TYPE is a
2122 pointer to the type of the resource. NAME is a pointer to the name
2123 of the resource; it will be NULL if there is a level mismatch. RES
2124 is the resource data. LANGUAGE is a pointer to the current
2128 write_rc_resource (FILE *e
, const rc_res_id
*type
,
2129 const rc_res_id
*name
, const rc_res_resource
*res
,
2130 rc_uint_type
*language
)
2141 case RES_TYPE_ACCELERATOR
:
2143 rt
= RT_ACCELERATOR
;
2146 case RES_TYPE_BITMAP
:
2147 s
= "2 /* RT_BITMAP */";
2151 case RES_TYPE_CURSOR
:
2152 s
= "1 /* RT_CURSOR */";
2156 case RES_TYPE_GROUP_CURSOR
:
2157 s
= "12 /* RT_GROUP_CURSOR */";
2158 rt
= RT_GROUP_CURSOR
;
2161 case RES_TYPE_DIALOG
:
2162 if (extended_dialog (res
->u
.dialog
))
2170 s
= "8 /* RT_FONT */";
2174 case RES_TYPE_FONTDIR
:
2175 s
= "7 /* RT_FONTDIR */";
2180 s
= "3 /* RT_ICON */";
2184 case RES_TYPE_GROUP_ICON
:
2185 s
= "14 /* RT_GROUP_ICON */";
2190 if (extended_menu (res
->u
.menu
))
2203 case RES_TYPE_MESSAGETABLE
:
2204 s
= "11 /* RT_MESSAGETABLE */";
2205 rt
= RT_MESSAGETABLE
;
2208 case RES_TYPE_RCDATA
:
2213 case RES_TYPE_STRINGTABLE
:
2218 case RES_TYPE_USERDATA
:
2223 case RES_TYPE_VERSIONINFO
:
2228 case RES_TYPE_TOOLBAR
:
2236 && (type
->named
|| type
->u
.id
!= (unsigned long) rt
))
2238 wr_printcomment (e
, "Unexpected resource type mismatch: ");
2239 res_id_print (e
, *type
, 1);
2240 fprintf (e
, " != %d", rt
);
2243 if (res
->coff_info
.codepage
!= 0)
2244 wr_printcomment (e
, "Code page: %u", res
->coff_info
.codepage
);
2245 if (res
->coff_info
.reserved
!= 0)
2246 wr_printcomment (e
, "COFF reserved value: %u", res
->coff_info
.reserved
);
2249 if (rt
== RT_STRING
)
2254 res_id_print (e
, *name
, 1);
2256 fprintf (e
, "??Unknown-Name??");
2261 fprintf (e
, "%s", s
);
2262 else if (type
!= NULL
)
2264 if (type
->named
== 0)
2266 #define PRINT_RT_NAME(NAME) case NAME: \
2267 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2273 res_id_print (e
, *type
, 0);
2276 PRINT_RT_NAME(RT_MANIFEST
);
2277 PRINT_RT_NAME(RT_ANICURSOR
);
2278 PRINT_RT_NAME(RT_ANIICON
);
2279 PRINT_RT_NAME(RT_RCDATA
);
2280 PRINT_RT_NAME(RT_ICON
);
2281 PRINT_RT_NAME(RT_CURSOR
);
2282 PRINT_RT_NAME(RT_BITMAP
);
2283 PRINT_RT_NAME(RT_PLUGPLAY
);
2284 PRINT_RT_NAME(RT_VXD
);
2285 PRINT_RT_NAME(RT_FONT
);
2286 PRINT_RT_NAME(RT_FONTDIR
);
2287 PRINT_RT_NAME(RT_HTML
);
2288 PRINT_RT_NAME(RT_MESSAGETABLE
);
2289 PRINT_RT_NAME(RT_DLGINCLUDE
);
2290 PRINT_RT_NAME(RT_DLGINIT
);
2292 #undef PRINT_RT_NAME
2295 res_id_print (e
, *type
, 1);
2298 fprintf (e
, "??Unknown-Type??");
2300 if (res
->res_info
.memflags
!= 0)
2302 if ((res
->res_info
.memflags
& MEMFLAG_MOVEABLE
) != 0)
2303 fprintf (e
, " MOVEABLE");
2304 if ((res
->res_info
.memflags
& MEMFLAG_PURE
) != 0)
2305 fprintf (e
, " PURE");
2306 if ((res
->res_info
.memflags
& MEMFLAG_PRELOAD
) != 0)
2307 fprintf (e
, " PRELOAD");
2308 if ((res
->res_info
.memflags
& MEMFLAG_DISCARDABLE
) != 0)
2309 fprintf (e
, " DISCARDABLE");
2312 if (res
->type
== RES_TYPE_DIALOG
)
2314 fprintf (e
, " %d, %d, %d, %d",
2315 (int) res
->u
.dialog
->x
, (int) res
->u
.dialog
->y
,
2316 (int) res
->u
.dialog
->width
, (int) res
->u
.dialog
->height
);
2317 if (res
->u
.dialog
->ex
!= NULL
2318 && res
->u
.dialog
->ex
->help
!= 0)
2319 fprintf (e
, ", %u", (unsigned int) res
->u
.dialog
->ex
->help
);
2321 else if (res
->type
== RES_TYPE_TOOLBAR
)
2323 fprintf (e
, " %d, %d", (int) res
->u
.toolbar
->button_width
,
2324 (int) res
->u
.toolbar
->button_height
);
2329 if ((res
->res_info
.language
!= 0 && res
->res_info
.language
!= *language
)
2330 || res
->res_info
.characteristics
!= 0
2331 || res
->res_info
.version
!= 0)
2337 case RES_TYPE_ACCELERATOR
:
2338 case RES_TYPE_DIALOG
:
2340 case RES_TYPE_RCDATA
:
2341 case RES_TYPE_STRINGTABLE
:
2350 if (res
->res_info
.language
!= 0 && res
->res_info
.language
!= *language
)
2351 fprintf (e
, "%sLANGUAGE %d, %d\n",
2352 modifiers
? "// " : "",
2353 (int) res
->res_info
.language
& ((1<<SUBLANG_SHIFT
)-1),
2354 (int) (res
->res_info
.language
>> SUBLANG_SHIFT
) & 0xff);
2355 if (res
->res_info
.characteristics
!= 0)
2356 fprintf (e
, "%sCHARACTERISTICS %u\n",
2357 modifiers
? "// " : "",
2358 (unsigned int) res
->res_info
.characteristics
);
2359 if (res
->res_info
.version
!= 0)
2360 fprintf (e
, "%sVERSION %u\n",
2361 modifiers
? "// " : "",
2362 (unsigned int) res
->res_info
.version
);
2370 case RES_TYPE_ACCELERATOR
:
2371 write_rc_accelerators (e
, res
->u
.acc
);
2374 case RES_TYPE_CURSOR
:
2375 write_rc_cursor (e
, res
->u
.cursor
);
2378 case RES_TYPE_GROUP_CURSOR
:
2379 write_rc_group_cursor (e
, res
->u
.group_cursor
);
2382 case RES_TYPE_DIALOG
:
2383 write_rc_dialog (e
, res
->u
.dialog
);
2386 case RES_TYPE_FONTDIR
:
2387 write_rc_fontdir (e
, res
->u
.fontdir
);
2390 case RES_TYPE_GROUP_ICON
:
2391 write_rc_group_icon (e
, res
->u
.group_icon
);
2395 write_rc_menu (e
, res
->u
.menu
, menuex
);
2398 case RES_TYPE_RCDATA
:
2399 write_rc_rcdata (e
, res
->u
.rcdata
, 0);
2402 case RES_TYPE_STRINGTABLE
:
2403 write_rc_stringtable (e
, name
, res
->u
.stringtable
);
2406 case RES_TYPE_USERDATA
:
2407 write_rc_rcdata (e
, res
->u
.userdata
, 0);
2410 case RES_TYPE_TOOLBAR
:
2411 write_rc_toolbar (e
, res
->u
.toolbar
);
2414 case RES_TYPE_VERSIONINFO
:
2415 write_rc_versioninfo (e
, res
->u
.versioninfo
);
2418 case RES_TYPE_BITMAP
:
2421 write_rc_datablock (e
, res
->u
.data
.length
, res
->u
.data
.data
, 0, 1, 0);
2423 case RES_TYPE_MESSAGETABLE
:
2424 write_rc_messagetable (e
, res
->u
.data
.length
, res
->u
.data
.data
);
2429 /* Write out accelerator information. */
2432 write_rc_accelerators (FILE *e
, const rc_accelerator
*accelerators
)
2434 const rc_accelerator
*acc
;
2436 fprintf (e
, "BEGIN\n");
2437 for (acc
= accelerators
; acc
!= NULL
; acc
= acc
->next
)
2443 if ((acc
->key
& 0x7f) == acc
->key
2444 && ISPRINT (acc
->key
)
2445 && (acc
->flags
& ACC_VIRTKEY
) == 0)
2447 fprintf (e
, "\"%c\"", (char) acc
->key
);
2452 fprintf (e
, "%d", (int) acc
->key
);
2456 fprintf (e
, ", %d", (int) acc
->id
);
2460 if ((acc
->flags
& ACC_VIRTKEY
) != 0)
2461 fprintf (e
, ", VIRTKEY");
2463 fprintf (e
, ", ASCII");
2466 if ((acc
->flags
& ACC_SHIFT
) != 0)
2467 fprintf (e
, ", SHIFT");
2468 if ((acc
->flags
& ACC_CONTROL
) != 0)
2469 fprintf (e
, ", CONTROL");
2470 if ((acc
->flags
& ACC_ALT
) != 0)
2471 fprintf (e
, ", ALT");
2476 fprintf (e
, "END\n");
2479 /* Write out cursor information. This would normally be in a separate
2480 file, which the rc file would include. */
2483 write_rc_cursor (FILE *e
, const rc_cursor
*cursor
)
2485 fprintf (e
, "BEGIN\n");
2487 fprintf (e
, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2488 (unsigned int) cursor
->xhotspot
, (unsigned int) cursor
->yhotspot
,
2489 (int) cursor
->xhotspot
, (int) cursor
->yhotspot
);
2490 write_rc_datablock (e
, (rc_uint_type
) cursor
->length
, (const bfd_byte
*) cursor
->data
,
2492 fprintf (e
, "END\n");
2495 /* Write out group cursor data. This would normally be built from the
2499 write_rc_group_cursor (FILE *e
, const rc_group_cursor
*group_cursor
)
2501 const rc_group_cursor
*gc
;
2504 for (c
= 0, gc
= group_cursor
; gc
!= NULL
; gc
= gc
->next
, c
++)
2506 fprintf (e
, "BEGIN\n");
2509 fprintf (e
, "0, 2, %d%s\t /* Having %d items. */\n", c
, (c
!= 0 ? "," : ""), c
);
2511 fprintf (e
, "/* width, height, planes, bits, bytes, index. */\n");
2513 for (c
= 1, gc
= group_cursor
; gc
!= NULL
; gc
= gc
->next
, c
++)
2516 fprintf (e
, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2517 (int) gc
->width
, (int) gc
->height
, (int) gc
->planes
, (int) gc
->bits
,
2518 (unsigned int) gc
->bytes
, (int) gc
->index
, (gc
->next
!= NULL
? "," : ""), c
);
2519 fprintf (e
, "/* width: %d; height %d; planes %d; bits %d. */\n",
2520 (int) gc
->width
, (int) gc
->height
, (int) gc
->planes
,
2523 fprintf (e
, "END\n");
2526 /* Write dialog data. */
2529 write_rc_dialog (FILE *e
, const rc_dialog
*dialog
)
2531 const rc_dialog_control
*control
;
2533 fprintf (e
, "STYLE 0x%x\n", dialog
->style
);
2535 if (dialog
->exstyle
!= 0)
2536 fprintf (e
, "EXSTYLE 0x%x\n", (unsigned int) dialog
->exstyle
);
2538 if ((dialog
->class.named
&& dialog
->class.u
.n
.length
> 0)
2539 || dialog
->class.u
.id
!= 0)
2541 fprintf (e
, "CLASS ");
2542 res_id_print (e
, dialog
->class, 1);
2546 if (dialog
->caption
!= NULL
)
2548 fprintf (e
, "CAPTION ");
2549 unicode_print_quoted (e
, dialog
->caption
, -1);
2553 if ((dialog
->menu
.named
&& dialog
->menu
.u
.n
.length
> 0)
2554 || dialog
->menu
.u
.id
!= 0)
2556 fprintf (e
, "MENU ");
2557 res_id_print (e
, dialog
->menu
, 0);
2561 if (dialog
->font
!= NULL
)
2563 fprintf (e
, "FONT %d, ", (int) dialog
->pointsize
);
2564 unicode_print_quoted (e
, dialog
->font
, -1);
2565 if (dialog
->ex
!= NULL
2566 && (dialog
->ex
->weight
!= 0
2567 || dialog
->ex
->italic
!= 0
2568 || dialog
->ex
->charset
!= 1))
2569 fprintf (e
, ", %d, %d, %d",
2570 (int) dialog
->ex
->weight
,
2571 (int) dialog
->ex
->italic
,
2572 (int) dialog
->ex
->charset
);
2576 fprintf (e
, "BEGIN\n");
2578 for (control
= dialog
->controls
; control
!= NULL
; control
= control
->next
)
2579 write_rc_dialog_control (e
, control
);
2581 fprintf (e
, "END\n");
2584 /* For each predefined control keyword, this table provides the class
2590 unsigned short class;
2591 unsigned long style
;
2594 static const struct control_info control_info
[] =
2596 { "AUTO3STATE", CTL_BUTTON
, BS_AUTO3STATE
},
2597 { "AUTOCHECKBOX", CTL_BUTTON
, BS_AUTOCHECKBOX
},
2598 { "AUTORADIOBUTTON", CTL_BUTTON
, BS_AUTORADIOBUTTON
},
2599 { "CHECKBOX", CTL_BUTTON
, BS_CHECKBOX
},
2600 { "COMBOBOX", CTL_COMBOBOX
, (unsigned long) -1 },
2601 { "CTEXT", CTL_STATIC
, SS_CENTER
},
2602 { "DEFPUSHBUTTON", CTL_BUTTON
, BS_DEFPUSHBUTTON
},
2603 { "EDITTEXT", CTL_EDIT
, (unsigned long) -1 },
2604 { "GROUPBOX", CTL_BUTTON
, BS_GROUPBOX
},
2605 { "ICON", CTL_STATIC
, SS_ICON
},
2606 { "LISTBOX", CTL_LISTBOX
, (unsigned long) -1 },
2607 { "LTEXT", CTL_STATIC
, SS_LEFT
},
2608 { "PUSHBOX", CTL_BUTTON
, BS_PUSHBOX
},
2609 { "PUSHBUTTON", CTL_BUTTON
, BS_PUSHBUTTON
},
2610 { "RADIOBUTTON", CTL_BUTTON
, BS_RADIOBUTTON
},
2611 { "RTEXT", CTL_STATIC
, SS_RIGHT
},
2612 { "SCROLLBAR", CTL_SCROLLBAR
, (unsigned long) -1 },
2613 { "STATE3", CTL_BUTTON
, BS_3STATE
},
2614 /* It's important that USERBUTTON come after all the other button
2615 types, so that it won't be matched too early. */
2616 { "USERBUTTON", CTL_BUTTON
, (unsigned long) -1 },
2620 /* Write a dialog control. */
2623 write_rc_dialog_control (FILE *e
, const rc_dialog_control
*control
)
2625 const struct control_info
*ci
;
2629 if (control
->class.named
)
2633 for (ci
= control_info
; ci
->name
!= NULL
; ++ci
)
2634 if (ci
->class == control
->class.u
.id
2635 && (ci
->style
== (unsigned long) -1
2636 || ci
->style
== (control
->style
& 0xff)))
2640 fprintf (e
, "CONTROL");
2641 else if (ci
->name
!= NULL
)
2642 fprintf (e
, "%s", ci
->name
);
2645 fprintf (e
, "CONTROL");
2649 /* For EDITTEXT, COMBOBOX, LISTBOX, and SCROLLBAR don't dump text. */
2650 if ((control
->text
.named
|| control
->text
.u
.id
!= 0)
2652 || (ci
->class != CTL_EDIT
2653 && ci
->class != CTL_COMBOBOX
2654 && ci
->class != CTL_LISTBOX
2655 && ci
->class != CTL_SCROLLBAR
)))
2658 res_id_print (e
, control
->text
, 1);
2662 fprintf (e
, " %d, ", (int) control
->id
);
2666 if (control
->class.named
)
2668 res_id_print (e
, control
->class, 0);
2669 if (control
->class.named
)
2671 fprintf (e
, ", 0x%x, ", (unsigned int) control
->style
);
2674 fprintf (e
, "%d, %d", (int) control
->x
, (int) control
->y
);
2676 if (control
->style
!= SS_ICON
2677 || control
->exstyle
!= 0
2678 || control
->width
!= 0
2679 || control
->height
!= 0
2680 || control
->help
!= 0)
2682 fprintf (e
, ", %d, %d", (int) control
->width
, (int) control
->height
);
2684 /* FIXME: We don't need to print the style if it is the default.
2685 More importantly, in certain cases we actually need to turn
2686 off parts of the forced style, by using NOT. */
2688 fprintf (e
, ", 0x%x", (unsigned int) control
->style
);
2690 if (control
->exstyle
!= 0 || control
->help
!= 0)
2691 fprintf (e
, ", 0x%x, %u", (unsigned int) control
->exstyle
,
2692 (unsigned int) control
->help
);
2697 if (control
->data
!= NULL
)
2698 write_rc_rcdata (e
, control
->data
, 2);
2701 /* Write out font directory data. This would normally be built from
2705 write_rc_fontdir (FILE *e
, const rc_fontdir
*fontdir
)
2707 const rc_fontdir
*fc
;
2710 for (c
= 0, fc
= fontdir
; fc
!= NULL
; fc
= fc
->next
, c
++)
2712 fprintf (e
, "BEGIN\n");
2714 fprintf (e
, "%d%s\t /* Has %d elements. */\n", c
, (c
!= 0 ? "," : ""), c
);
2715 for (c
= 1, fc
= fontdir
; fc
!= NULL
; fc
= fc
->next
, c
++)
2718 fprintf (e
, "%d,\t/* Font no %d with index %d. */\n",
2719 (int) fc
->index
, c
, (int) fc
->index
);
2720 write_rc_datablock (e
, (rc_uint_type
) fc
->length
- 2,
2721 (const bfd_byte
*) fc
->data
+ 4,fc
->next
!= NULL
,
2724 fprintf (e
, "END\n");
2727 /* Write out group icon data. This would normally be built from the
2731 write_rc_group_icon (FILE *e
, const rc_group_icon
*group_icon
)
2733 const rc_group_icon
*gi
;
2736 for (c
= 0, gi
= group_icon
; gi
!= NULL
; gi
= gi
->next
, c
++)
2739 fprintf (e
, "BEGIN\n");
2741 fprintf (e
, " 0, 1, %d%s\t /* Has %d elements. */\n", c
, (c
!= 0 ? "," : ""), c
);
2744 fprintf (e
, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2745 for (c
= 1, gi
= group_icon
; gi
!= NULL
; gi
= gi
->next
, c
++)
2748 fprintf (e
, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2749 gi
->width
, gi
->height
, gi
->colors
, 0, (int) gi
->planes
, (int) gi
->bits
,
2750 (unsigned int) gi
->bytes
, (int) gi
->index
, (gi
->next
!= NULL
? "," : ""), c
);
2752 fprintf (e
, "END\n");
2755 /* Write out a menu resource. */
2758 write_rc_menu (FILE *e
, const rc_menu
*menu
, int menuex
)
2760 if (menu
->help
!= 0)
2761 fprintf (e
, "// Help ID: %u\n", (unsigned int) menu
->help
);
2762 write_rc_menuitems (e
, menu
->items
, menuex
, 0);
2766 write_rc_toolbar (FILE *e
, const rc_toolbar
*tb
)
2768 rc_toolbar_item
*it
;
2770 fprintf (e
, "BEGIN\n");
2775 if (it
->id
.u
.id
== 0)
2776 fprintf (e
, "SEPARATOR\n");
2778 fprintf (e
, "BUTTON %d\n", (int) it
->id
.u
.id
);
2782 fprintf (e
, "END\n");
2785 /* Write out menuitems. */
2788 write_rc_menuitems (FILE *e
, const rc_menuitem
*menuitems
, int menuex
,
2791 const rc_menuitem
*mi
;
2794 fprintf (e
, "BEGIN\n");
2796 for (mi
= menuitems
; mi
!= NULL
; mi
= mi
->next
)
2798 indent (e
, ind
+ 2);
2800 if (mi
->popup
== NULL
)
2801 fprintf (e
, "MENUITEM");
2803 fprintf (e
, "POPUP");
2806 && mi
->popup
== NULL
2811 fprintf (e
, " SEPARATOR\n");
2815 if (mi
->text
== NULL
)
2816 fprintf (e
, " \"\"");
2820 unicode_print_quoted (e
, mi
->text
, -1);
2825 if (mi
->popup
== NULL
)
2826 fprintf (e
, ", %d", (int) mi
->id
);
2828 if ((mi
->type
& MENUITEM_CHECKED
) != 0)
2829 fprintf (e
, ", CHECKED");
2830 if ((mi
->type
& MENUITEM_GRAYED
) != 0)
2831 fprintf (e
, ", GRAYED");
2832 if ((mi
->type
& MENUITEM_HELP
) != 0)
2833 fprintf (e
, ", HELP");
2834 if ((mi
->type
& MENUITEM_INACTIVE
) != 0)
2835 fprintf (e
, ", INACTIVE");
2836 if ((mi
->type
& MENUITEM_MENUBARBREAK
) != 0)
2837 fprintf (e
, ", MENUBARBREAK");
2838 if ((mi
->type
& MENUITEM_MENUBREAK
) != 0)
2839 fprintf (e
, ", MENUBREAK");
2840 if ((mi
->type
& MENUITEM_OWNERDRAW
) != 0)
2841 fprintf (e
, ", OWNERDRAW");
2842 if ((mi
->type
& MENUITEM_BITMAP
) != 0)
2843 fprintf (e
, ", BITMAP");
2847 if (mi
->id
!= 0 || mi
->type
!= 0 || mi
->state
!= 0 || mi
->help
!= 0)
2849 fprintf (e
, ", %d", (int) mi
->id
);
2850 if (mi
->type
!= 0 || mi
->state
!= 0 || mi
->help
!= 0)
2852 fprintf (e
, ", %u", (unsigned int) mi
->type
);
2853 if (mi
->state
!= 0 || mi
->help
!= 0)
2855 fprintf (e
, ", %u", (unsigned int) mi
->state
);
2857 fprintf (e
, ", %u", (unsigned int) mi
->help
);
2865 if (mi
->popup
!= NULL
)
2866 write_rc_menuitems (e
, mi
->popup
, menuex
, ind
+ 2);
2870 fprintf (e
, "END\n");
2874 test_rc_datablock_unicode (rc_uint_type length
, const bfd_byte
*data
)
2877 if ((length
& 1) != 0)
2880 for (i
= 0; i
< length
; i
+= 2)
2882 if (data
[i
] == 0 && data
[i
+ 1] == 0 && (i
+ 2) < length
)
2884 if (data
[i
] == 0xff && data
[i
+ 1] == 0xff)
2891 test_rc_datablock_text (rc_uint_type length
, const bfd_byte
*data
)
2901 for (i
= 0, c
= 0; i
< length
; i
++)
2903 if (! ISPRINT (data
[i
]) && data
[i
] != '\n'
2904 && ! (data
[i
] == '\r' && (i
+ 1) < length
&& data
[i
+ 1] == '\n')
2906 && ! (data
[i
] == 0 && (i
+ 1) != length
))
2912 else if (data
[i
] == '\n') has_nl
++;
2914 if (length
> 80 && ! has_nl
)
2916 c
= (((c
* 10000) + (i
/ 100) - 1)) / i
;
2923 write_rc_messagetable (FILE *e
, rc_uint_type length
, const bfd_byte
*data
)
2926 const struct bin_messagetable
*mt
;
2928 fprintf (e
, "BEGIN\n");
2930 write_rc_datablock (e
, length
, data
, 0, 0, 0);
2933 wr_printcomment (e
, "MC syntax dump");
2934 if (length
< BIN_MESSAGETABLE_SIZE
)
2941 mt
= (const struct bin_messagetable
*) data
;
2942 m
= windres_get_32 (&wrtarget
, mt
->cblocks
, length
);
2944 if (length
< (BIN_MESSAGETABLE_SIZE
+ m
* BIN_MESSAGETABLE_BLOCK_SIZE
))
2949 for (i
= 0; i
< m
; i
++)
2951 rc_uint_type low
, high
, offset
;
2952 const struct bin_messagetable_item
*mti
;
2954 low
= windres_get_32 (&wrtarget
, mt
->items
[i
].lowid
, 4);
2955 high
= windres_get_32 (&wrtarget
, mt
->items
[i
].highid
, 4);
2956 offset
= windres_get_32 (&wrtarget
, mt
->items
[i
].offset
, 4);
2960 rc_uint_type elen
, flags
;
2961 if ((offset
+ BIN_MESSAGETABLE_ITEM_SIZE
) > length
)
2966 mti
= (const struct bin_messagetable_item
*) &data
[offset
];
2967 elen
= windres_get_16 (&wrtarget
, mti
->length
, 2);
2968 flags
= windres_get_16 (&wrtarget
, mti
->flags
, 2);
2969 if ((offset
+ elen
) > length
)
2974 wr_printcomment (e
, "MessageId = 0x%x", low
);
2975 wr_printcomment (e
, "");
2977 if ((flags
& MESSAGE_RESOURCE_UNICODE
) == MESSAGE_RESOURCE_UNICODE
)
2979 /* PR 17512: file: 5c3232dc. */
2980 if (elen
> BIN_MESSAGETABLE_ITEM_SIZE
* 2)
2981 unicode_print (e
, (const unichar
*) mti
->data
,
2982 (elen
- BIN_MESSAGETABLE_ITEM_SIZE
) / 2);
2986 if (elen
> BIN_MESSAGETABLE_ITEM_SIZE
)
2987 ascii_print (e
, (const char *) mti
->data
,
2988 (elen
- BIN_MESSAGETABLE_ITEM_SIZE
));
2991 wr_printcomment (e
,"");
3000 wr_printcomment (e
, "Illegal data");
3002 fprintf (e
, "END\n");
3006 write_rc_datablock (FILE *e
, rc_uint_type length
, const bfd_byte
*data
, int has_next
,
3007 int hasblock
, int show_comment
)
3012 fprintf (e
, "BEGIN\n");
3014 if (show_comment
== -1)
3016 if (test_rc_datablock_text(length
, data
))
3019 for (i
= 0; i
< length
;)
3024 for (c
= 0; i
< length
&& c
< 160 && data
[i
] != '\n'; c
++, i
++)
3026 if (i
< length
&& data
[i
] == '\n')
3028 ascii_print(e
, (const char *) &data
[i
- c
], c
);
3037 fprintf (e
, "\"\"");
3043 fprintf (e
, "END\n");
3046 if (test_rc_datablock_unicode (length
, data
))
3049 for (i
= 0; i
< length
;)
3053 u
= (const unichar
*) &data
[i
];
3057 for (c
= 0; i
< length
&& c
< 160 && u
[c
] != '\n'; c
++, i
+= 2)
3059 if (i
< length
&& u
[c
] == '\n')
3061 unicode_print (e
, u
, c
);
3070 fprintf (e
, "L\"\"");
3076 fprintf (e
, "END\n");
3085 rc_uint_type i
, max_row
;
3088 max_row
= (show_comment
? 4 : 8);
3090 for (i
= 0; i
+ 3 < length
;)
3093 rc_uint_type comment_start
;
3100 for (k
= 0; k
< max_row
&& i
+ 3 < length
; k
++, i
+= 4)
3103 plen
= fprintf (e
, "0x%lxL",
3104 (unsigned long) windres_get_32 (&wrtarget
, data
+ i
, length
- i
));
3106 plen
= fprintf (e
, " 0x%lxL",
3107 (unsigned long) windres_get_32 (&wrtarget
, data
+ i
, length
- i
)) - 1;
3108 if (has_next
|| (i
+ 4) < length
)
3110 if (plen
>0 && plen
< 11)
3111 indent (e
, 11 - plen
);
3117 fprintf (e
, "\t/* ");
3118 ascii_print (e
, (const char *) &data
[comment_start
], i
- comment_start
);
3119 fprintf (e
, ". */");
3129 plen
= fprintf (e
, "0x%x",
3130 (int) windres_get_16 (&wrtarget
, data
+ i
, length
- i
));
3131 if (has_next
|| i
+ 2 < length
)
3133 if (plen
> 0 && plen
< 11)
3134 indent (e
, 11 - plen
);
3139 fprintf (e
, "\t/* ");
3140 ascii_print (e
, (const char *) &data
[i
], 2);
3141 fprintf (e
, ". */");
3153 ascii_print (e
, (const char *) &data
[i
], 1);
3162 fprintf (e
, "END\n");
3165 /* Write out an rcdata resource. This is also used for other types of
3166 resources that need to print arbitrary data. */
3169 write_rc_rcdata (FILE *e
, const rc_rcdata_item
*rcdata
, int ind
)
3171 const rc_rcdata_item
*ri
;
3174 fprintf (e
, "BEGIN\n");
3176 for (ri
= rcdata
; ri
!= NULL
; ri
= ri
->next
)
3178 if (ri
->type
== RCDATA_BUFFER
&& ri
->u
.buffer
.length
== 0)
3187 indent (e
, ind
+ 2);
3188 fprintf (e
, "%ld", (long) (ri
->u
.word
& 0xffff));
3192 indent (e
, ind
+ 2);
3193 fprintf (e
, "%luL", (unsigned long) ri
->u
.dword
);
3197 indent (e
, ind
+ 2);
3199 ascii_print (e
, ri
->u
.string
.s
, ri
->u
.string
.length
);
3203 case RCDATA_WSTRING
:
3204 indent (e
, ind
+ 2);
3206 unicode_print (e
, ri
->u
.wstring
.w
, ri
->u
.wstring
.length
);
3211 write_rc_datablock (e
, (rc_uint_type
) ri
->u
.buffer
.length
,
3212 (const bfd_byte
*) ri
->u
.buffer
.data
,
3213 ri
->next
!= NULL
, 0, -1);
3217 if (ri
->type
!= RCDATA_BUFFER
)
3219 if (ri
->next
!= NULL
)
3226 fprintf (e
, "END\n");
3229 /* Write out a stringtable resource. */
3232 write_rc_stringtable (FILE *e
, const rc_res_id
*name
,
3233 const rc_stringtable
*stringtable
)
3235 rc_uint_type offset
;
3238 if (name
!= NULL
&& ! name
->named
)
3239 offset
= (name
->u
.id
- 1) << 4;
3242 fprintf (e
, "/* %s string table name. */\n",
3243 name
== NULL
? "Missing" : "Invalid");
3247 fprintf (e
, "BEGIN\n");
3249 for (i
= 0; i
< 16; i
++)
3251 if (stringtable
->strings
[i
].length
!= 0)
3253 fprintf (e
, " %lu, ", (unsigned long) offset
+ i
);
3254 unicode_print_quoted (e
, stringtable
->strings
[i
].string
,
3255 stringtable
->strings
[i
].length
);
3260 fprintf (e
, "END\n");
3263 /* Write out a versioninfo resource. */
3266 write_rc_versioninfo (FILE *e
, const rc_versioninfo
*versioninfo
)
3268 const rc_fixed_versioninfo
*f
;
3269 const rc_ver_info
*vi
;
3271 f
= versioninfo
->fixed
;
3272 if (f
->file_version_ms
!= 0 || f
->file_version_ls
!= 0)
3273 fprintf (e
, " FILEVERSION %u, %u, %u, %u\n",
3274 (unsigned int) ((f
->file_version_ms
>> 16) & 0xffff),
3275 (unsigned int) (f
->file_version_ms
& 0xffff),
3276 (unsigned int) ((f
->file_version_ls
>> 16) & 0xffff),
3277 (unsigned int) (f
->file_version_ls
& 0xffff));
3278 if (f
->product_version_ms
!= 0 || f
->product_version_ls
!= 0)
3279 fprintf (e
, " PRODUCTVERSION %u, %u, %u, %u\n",
3280 (unsigned int) ((f
->product_version_ms
>> 16) & 0xffff),
3281 (unsigned int) (f
->product_version_ms
& 0xffff),
3282 (unsigned int) ((f
->product_version_ls
>> 16) & 0xffff),
3283 (unsigned int) (f
->product_version_ls
& 0xffff));
3284 if (f
->file_flags_mask
!= 0)
3285 fprintf (e
, " FILEFLAGSMASK 0x%x\n", (unsigned int) f
->file_flags_mask
);
3286 if (f
->file_flags
!= 0)
3287 fprintf (e
, " FILEFLAGS 0x%x\n", (unsigned int) f
->file_flags
);
3288 if (f
->file_os
!= 0)
3289 fprintf (e
, " FILEOS 0x%x\n", (unsigned int) f
->file_os
);
3290 if (f
->file_type
!= 0)
3291 fprintf (e
, " FILETYPE 0x%x\n", (unsigned int) f
->file_type
);
3292 if (f
->file_subtype
!= 0)
3293 fprintf (e
, " FILESUBTYPE 0x%x\n", (unsigned int) f
->file_subtype
);
3294 if (f
->file_date_ms
!= 0 || f
->file_date_ls
!= 0)
3295 fprintf (e
, "/* Date: %u, %u. */\n",
3296 (unsigned int) f
->file_date_ms
, (unsigned int) f
->file_date_ls
);
3298 fprintf (e
, "BEGIN\n");
3300 for (vi
= versioninfo
->var
; vi
!= NULL
; vi
= vi
->next
)
3304 case VERINFO_STRING
:
3306 const rc_ver_stringtable
*vst
;
3307 const rc_ver_stringinfo
*vs
;
3309 fprintf (e
, " BLOCK \"StringFileInfo\"\n");
3310 fprintf (e
, " BEGIN\n");
3312 for (vst
= vi
->u
.string
.stringtables
; vst
!= NULL
; vst
= vst
->next
)
3314 fprintf (e
, " BLOCK ");
3315 unicode_print_quoted (e
, vst
->language
, -1);
3318 fprintf (e
, " BEGIN\n");
3320 for (vs
= vst
->strings
; vs
!= NULL
; vs
= vs
->next
)
3322 fprintf (e
, " VALUE ");
3323 unicode_print_quoted (e
, vs
->key
, -1);
3325 unicode_print_quoted (e
, vs
->value
, -1);
3329 fprintf (e
, " END\n");
3331 fprintf (e
, " END\n");
3337 const rc_ver_varinfo
*vv
;
3339 fprintf (e
, " BLOCK \"VarFileInfo\"\n");
3340 fprintf (e
, " BEGIN\n");
3341 fprintf (e
, " VALUE ");
3342 unicode_print_quoted (e
, vi
->u
.var
.key
, -1);
3344 for (vv
= vi
->u
.var
.var
; vv
!= NULL
; vv
= vv
->next
)
3345 fprintf (e
, ", 0x%x, %d", (unsigned int) vv
->language
,
3348 fprintf (e
, "\n END\n");
3355 fprintf (e
, "END\n");
3359 rcdata_copy (const rc_rcdata_item
*src
, bfd_byte
*dst
)
3367 windres_put_16 (&wrtarget
, dst
, (rc_uint_type
) src
->u
.word
);
3371 windres_put_32 (&wrtarget
, dst
, (rc_uint_type
) src
->u
.dword
);
3374 if (dst
&& src
->u
.string
.length
)
3375 memcpy (dst
, src
->u
.string
.s
, src
->u
.string
.length
);
3376 return (rc_uint_type
) src
->u
.string
.length
;
3377 case RCDATA_WSTRING
:
3378 if (dst
&& src
->u
.wstring
.length
)
3379 memcpy (dst
, src
->u
.wstring
.w
, src
->u
.wstring
.length
* sizeof (unichar
));
3380 return (rc_uint_type
) (src
->u
.wstring
.length
* sizeof (unichar
));
3382 if (dst
&& src
->u
.buffer
.length
)
3383 memcpy (dst
, src
->u
.buffer
.data
, src
->u
.buffer
.length
);
3384 return (rc_uint_type
) src
->u
.buffer
.length
;
3388 /* Never reached. */