1 /* resrc.c -- read and write Windows rc files.
2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007
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] == ':')
449 e
= c
= xstrdup (filename
);
452 e
= c
= xmalloc (strlen (filename
) + 3);
453 sprintf (c
, "./%s", filename
);
456 while (e
> c
&& (e
[-1] != '\\' && e
[-1] != '/'))
461 /* Cut off trailing slash. */
464 while ((e
= strchr (c
, '\\')) != NULL
)
467 windres_add_include_dir (e
);
470 istream_type
= (use_temp_file
) ? ISTREAM_FILE
: ISTREAM_PIPE
;
472 if (preprocargs
== NULL
)
477 cmd
= xmalloc (strlen (preprocessor
)
478 + strlen (preprocargs
)
480 + strlen (fnquotes
) * 2
482 sprintf (cmd
, "%s %s %s%s%s", preprocessor
, preprocargs
,
483 fnquotes
, filename
, fnquotes
);
485 cpp_pipe
= open_input_stream (cmd
);
489 char *dash
, *slash
, *cp
;
491 preprocessor
= DEFAULT_PREPROCESSOR
;
493 cmd
= xmalloc (strlen (program_name
)
494 + strlen (preprocessor
)
495 + strlen (preprocargs
)
497 + strlen (fnquotes
) * 2
498 #ifdef HAVE_EXECUTABLE_SUFFIX
499 + strlen (EXECUTABLE_SUFFIX
)
505 for (cp
= program_name
; *cp
; cp
++)
510 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
511 *cp
== ':' || *cp
== '\\' ||
524 /* First, try looking for a prefixed gcc in the windres
525 directory, with the same prefix as windres */
527 cpp_pipe
= look_for_default (cmd
, program_name
, dash
- program_name
+ 1,
528 preprocargs
, filename
);
531 if (slash
&& ! cpp_pipe
)
533 /* Next, try looking for a gcc in the same directory as
536 cpp_pipe
= look_for_default (cmd
, program_name
, slash
- program_name
+ 1,
537 preprocargs
, filename
);
542 /* Sigh, try the default */
544 cpp_pipe
= look_for_default (cmd
, "", 0, preprocargs
, filename
);
551 rc_filename
= xstrdup (filename
);
554 rcparse_set_language (language
);
556 rcparse_discard_strings ();
558 close_input_stream ();
560 if (fontdirs
!= NULL
)
569 /* Close the input stream if it is open. */
572 close_input_stream (void)
574 if (istream_type
== ISTREAM_FILE
)
576 if (cpp_pipe
!= NULL
)
579 if (cpp_temp_file
!= NULL
)
581 int errno_save
= errno
;
583 unlink (cpp_temp_file
);
585 free (cpp_temp_file
);
590 if (cpp_pipe
!= NULL
)
594 /* Since this is also run via xatexit, safeguard. */
596 cpp_temp_file
= NULL
;
599 /* Report an error while reading an rc file. */
602 yyerror (const char *msg
)
604 fatal ("%s:%d: %s", rc_filename
, rc_lineno
, msg
);
607 /* Issue a warning while reading an rc file. */
610 rcparse_warning (const char *msg
)
612 fprintf (stderr
, _("%s:%d: %s\n"), rc_filename
, rc_lineno
, msg
);
615 /* Die if we get an unexpected end of file. */
618 unexpected_eof (const char *msg
)
620 fatal (_("%s: unexpected EOF"), msg
);
623 /* Read a 16 bit word from a file. The data is assumed to be little
627 get_word (FILE *e
, const char *msg
)
634 unexpected_eof (msg
);
635 return ((b2
& 0xff) << 8) | (b1
& 0xff);
638 /* Read a 32 bit word from a file. The data is assumed to be little
642 get_long (FILE *e
, const char *msg
)
651 unexpected_eof (msg
);
652 return (((((((b4
& 0xff) << 8)
658 /* Read data from a file. This is a wrapper to do error checking. */
661 get_data (FILE *e
, bfd_byte
*p
, rc_uint_type c
, const char *msg
)
663 rc_uint_type got
; // $$$d
665 got
= (rc_uint_type
) fread (p
, 1, c
, e
);
669 fatal (_("%s: read of %lu returned %lu"), msg
, (long) c
, (long) got
);
672 /* Define an accelerator resource. */
675 define_accelerator (rc_res_id id
, const rc_res_res_info
*resinfo
,
676 rc_accelerator
*data
)
680 r
= define_standard_resource (&resources
, RT_ACCELERATOR
, id
,
681 resinfo
->language
, 0);
682 r
->type
= RES_TYPE_ACCELERATOR
;
684 r
->res_info
= *resinfo
;
687 /* Define a bitmap resource. Bitmap data is stored in a file. The
688 first 14 bytes of the file are a standard header, which is not
689 included in the resource data. */
691 #define BITMAP_SKIP (14)
694 define_bitmap (rc_res_id id
, const rc_res_res_info
*resinfo
,
695 const char *filename
)
704 e
= open_file_search (filename
, FOPEN_RB
, "bitmap file", &real_filename
);
706 if (stat (real_filename
, &s
) < 0)
707 fatal (_("stat failed on bitmap file `%s': %s"), real_filename
,
710 data
= (bfd_byte
*) res_alloc (s
.st_size
- BITMAP_SKIP
);
712 for (i
= 0; i
< BITMAP_SKIP
; i
++)
715 get_data (e
, data
, s
.st_size
- BITMAP_SKIP
, real_filename
);
718 free (real_filename
);
720 r
= define_standard_resource (&resources
, RT_BITMAP
, id
,
721 resinfo
->language
, 0);
723 r
->type
= RES_TYPE_BITMAP
;
724 r
->u
.data
.length
= s
.st_size
- BITMAP_SKIP
;
725 r
->u
.data
.data
= data
;
726 r
->res_info
= *resinfo
;
729 /* Define a cursor resource. A cursor file may contain a set of
730 bitmaps, each representing the same cursor at various different
731 resolutions. They each get written out with a different ID. The
732 real cursor resource is then a group resource which can be used to
733 select one of the actual cursors. */
736 define_cursor (rc_res_id id
, const rc_res_res_info
*resinfo
,
737 const char *filename
)
742 struct icondir
*icondirs
;
745 rc_group_cursor
*first
, **pp
;
747 e
= open_file_search (filename
, FOPEN_RB
, "cursor file", &real_filename
);
749 /* A cursor file is basically an icon file. The start of the file
750 is a three word structure. The first word is ignored. The
751 second word is the type of data. The third word is the number of
754 get_word (e
, real_filename
);
755 type
= get_word (e
, real_filename
);
756 count
= get_word (e
, real_filename
);
758 fatal (_("cursor file `%s' does not contain cursor data"), real_filename
);
760 /* Read in the icon directory entries. */
762 icondirs
= (struct icondir
*) xmalloc (count
* sizeof *icondirs
);
764 for (i
= 0; i
< count
; i
++)
766 icondirs
[i
].width
= getc (e
);
767 icondirs
[i
].height
= getc (e
);
768 icondirs
[i
].colorcount
= getc (e
);
770 icondirs
[i
].u
.cursor
.xhotspot
= get_word (e
, real_filename
);
771 icondirs
[i
].u
.cursor
.yhotspot
= get_word (e
, real_filename
);
772 icondirs
[i
].bytes
= get_long (e
, real_filename
);
773 icondirs
[i
].offset
= get_long (e
, real_filename
);
776 unexpected_eof (real_filename
);
779 /* Define each cursor as a unique resource. */
781 first_cursor
= cursors
;
783 for (i
= 0; i
< count
; i
++)
789 if (fseek (e
, icondirs
[i
].offset
, SEEK_SET
) != 0)
790 fatal (_("%s: fseek to %lu failed: %s"), real_filename
,
791 icondirs
[i
].offset
, strerror (errno
));
793 data
= (bfd_byte
*) res_alloc (icondirs
[i
].bytes
);
795 get_data (e
, data
, icondirs
[i
].bytes
, real_filename
);
797 c
= (rc_cursor
*) res_alloc (sizeof (rc_cursor
));
798 c
->xhotspot
= icondirs
[i
].u
.cursor
.xhotspot
;
799 c
->yhotspot
= icondirs
[i
].u
.cursor
.yhotspot
;
800 c
->length
= icondirs
[i
].bytes
;
808 r
= define_standard_resource (&resources
, RT_CURSOR
, name
,
809 resinfo
->language
, 0);
810 r
->type
= RES_TYPE_CURSOR
;
812 r
->res_info
= *resinfo
;
816 free (real_filename
);
818 /* Define a cursor group resource. */
822 for (i
= 0; i
< count
; i
++)
826 cg
= (rc_group_cursor
*) res_alloc (sizeof (rc_group_cursor
));
828 cg
->width
= icondirs
[i
].width
;
829 cg
->height
= 2 * icondirs
[i
].height
;
831 /* FIXME: What should these be set to? */
835 cg
->bytes
= icondirs
[i
].bytes
+ 4;
836 cg
->index
= first_cursor
+ i
+ 1;
844 r
= define_standard_resource (&resources
, RT_GROUP_CURSOR
, id
,
845 resinfo
->language
, 0);
846 r
->type
= RES_TYPE_GROUP_CURSOR
;
847 r
->u
.group_cursor
= first
;
848 r
->res_info
= *resinfo
;
851 /* Define a dialog resource. */
854 define_dialog (rc_res_id id
, const rc_res_res_info
*resinfo
,
855 const rc_dialog
*dialog
)
860 copy
= (rc_dialog
*) res_alloc (sizeof *copy
);
863 r
= define_standard_resource (&resources
, RT_DIALOG
, id
,
864 resinfo
->language
, 0);
865 r
->type
= RES_TYPE_DIALOG
;
867 r
->res_info
= *resinfo
;
870 /* Define a dialog control. This does not define a resource, but
871 merely allocates and fills in a structure. */
874 define_control (const rc_res_id iid
, rc_uint_type id
, rc_uint_type x
,
875 rc_uint_type y
, rc_uint_type width
, rc_uint_type height
,
876 const rc_res_id
class, rc_uint_type style
,
877 rc_uint_type exstyle
)
879 rc_dialog_control
*n
;
881 n
= (rc_dialog_control
*) res_alloc (sizeof (rc_dialog_control
));
885 n
->exstyle
= exstyle
;
899 define_icon_control (rc_res_id iid
, rc_uint_type id
, rc_uint_type x
,
900 rc_uint_type y
, rc_uint_type style
,
901 rc_uint_type exstyle
, rc_uint_type help
,
902 rc_rcdata_item
*data
, rc_dialog_ex
*ex
)
904 rc_dialog_control
*n
;
909 style
= SS_ICON
| WS_CHILD
| WS_VISIBLE
;
910 res_string_to_id (&tid
, "");
912 cid
.u
.id
= CTL_STATIC
;
913 n
= define_control (tid
, id
, x
, y
, 0, 0, cid
, style
, exstyle
);
916 rcparse_warning (_("help ID requires DIALOGEX"));
918 rcparse_warning (_("control data requires DIALOGEX"));
925 /* Define a font resource. */
928 define_font (rc_res_id id
, const rc_res_res_info
*resinfo
,
929 const char *filename
)
940 const char *device
, *face
;
943 e
= open_file_search (filename
, FOPEN_RB
, "font file", &real_filename
);
945 if (stat (real_filename
, &s
) < 0)
946 fatal (_("stat failed on font file `%s': %s"), real_filename
,
949 data
= (bfd_byte
*) res_alloc (s
.st_size
);
951 get_data (e
, data
, s
.st_size
, real_filename
);
954 free (real_filename
);
956 r
= define_standard_resource (&resources
, RT_FONT
, id
,
957 resinfo
->language
, 0);
959 r
->type
= RES_TYPE_FONT
;
960 r
->u
.data
.length
= s
.st_size
;
961 r
->u
.data
.data
= data
;
962 r
->res_info
= *resinfo
;
964 /* For each font resource, we must add an entry in the FONTDIR
965 resource. The FONTDIR resource includes some strings in the font
966 file. To find them, we have to do some magic on the data we have
969 offset
= ((((((data
[47] << 8)
973 if (offset
> 0 && offset
< s
.st_size
)
974 device
= (char *) data
+ offset
;
978 offset
= ((((((data
[51] << 8)
982 if (offset
> 0 && offset
< s
.st_size
)
983 face
= (char *) data
+ offset
;
989 fontdatalength
= 58 + strlen (device
) + strlen (face
);
990 fontdata
= (bfd_byte
*) res_alloc (fontdatalength
);
991 memcpy (fontdata
, data
, 56);
992 strcpy ((char *) fontdata
+ 56, device
);
993 strcpy ((char *) fontdata
+ 57 + strlen (device
), face
);
995 fd
= (rc_fontdir
*) res_alloc (sizeof (rc_fontdir
));
998 fd
->length
= fontdatalength
;
1001 for (pp
= &fontdirs
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1005 /* For the single fontdirs resource, we always use the resource
1006 information of the last font. I don't know what else to do. */
1007 fontdirs_resinfo
= *resinfo
;
1011 define_font_rcdata (rc_res_id id
,const rc_res_res_info
*resinfo
,
1012 rc_rcdata_item
*data
)
1015 rc_uint_type len_data
;
1018 r
= define_standard_resource (&resources
, RT_FONT
, id
,
1019 resinfo
->language
, 0);
1021 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1023 r
->type
= RES_TYPE_FONT
;
1024 r
->u
.data
.length
= len_data
;
1025 r
->u
.data
.data
= pb_data
;
1026 r
->res_info
= *resinfo
;
1029 /* Define the fontdirs resource. This is called after the entire rc
1030 file has been parsed, if any font resources were seen. */
1033 define_fontdirs (void)
1041 r
= define_standard_resource (&resources
, RT_FONTDIR
, id
, 0x409, 0);
1043 r
->type
= RES_TYPE_FONTDIR
;
1044 r
->u
.fontdir
= fontdirs
;
1045 r
->res_info
= fontdirs_resinfo
;
1049 rcdata_render_as_buffer (const rc_rcdata_item
*data
, rc_uint_type
*plen
)
1051 const rc_rcdata_item
*d
;
1052 bfd_byte
*ret
= NULL
, *pret
;
1053 rc_uint_type len
= 0;
1055 for (d
= data
; d
!= NULL
; d
= d
->next
)
1056 len
+= rcdata_copy (d
, NULL
);
1059 ret
= pret
= (bfd_byte
*) res_alloc (len
);
1060 for (d
= data
; d
!= NULL
; d
= d
->next
)
1061 pret
+= rcdata_copy (d
, pret
);
1069 define_fontdir_rcdata (rc_res_id id
,const rc_res_res_info
*resinfo
,
1070 rc_rcdata_item
*data
)
1073 rc_fontdir
*fd
, *fd_first
, *fd_cur
;
1074 rc_uint_type len_data
;
1078 fd_cur
= fd_first
= NULL
;
1079 r
= define_standard_resource (&resources
, RT_FONTDIR
, id
, 0x409, 0);
1081 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1085 rc_uint_type off
= 2;
1086 c
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1090 rc_uint_type safe_pos
= off
;
1091 const struct bin_fontdir_item
*bfi
;
1093 bfi
= (const struct bin_fontdir_item
*) pb_data
+ off
;
1094 fd
= (rc_fontdir
*) res_alloc (sizeof (rc_fontdir
));
1095 fd
->index
= windres_get_16 (&wrtarget
, bfi
->index
, len_data
- off
);
1096 fd
->data
= pb_data
+ off
;
1098 len
= strlen ((char *) bfi
->device_name
) + 1;
1099 off
+= (rc_uint_type
) len
;
1100 off
+= (rc_uint_type
) strlen ((char *) bfi
->device_name
+ len
) + 1;
1101 fd
->length
= (off
- safe_pos
);
1103 if (fd_first
== NULL
)
1110 r
->type
= RES_TYPE_FONTDIR
;
1111 r
->u
.fontdir
= fd_first
;
1112 r
->res_info
= *resinfo
;
1115 static void define_messagetable_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1116 rc_rcdata_item
*data
)
1119 rc_uint_type len_data
;
1122 r
= define_standard_resource (&resources
, RT_MESSAGETABLE
, id
, resinfo
->language
, 0);
1124 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1125 r
->type
= RES_TYPE_MESSAGETABLE
;
1126 r
->u
.data
.length
= len_data
;
1127 r
->u
.data
.data
= pb_data
;
1128 r
->res_info
= *resinfo
;
1131 /* Define an icon resource. An icon file may contain a set of
1132 bitmaps, each representing the same icon at various different
1133 resolutions. They each get written out with a different ID. The
1134 real icon resource is then a group resource which can be used to
1135 select one of the actual icon bitmaps. */
1138 define_icon (rc_res_id id
, const rc_res_res_info
*resinfo
,
1139 const char *filename
)
1142 char *real_filename
;
1144 struct icondir
*icondirs
;
1147 rc_group_icon
*first
, **pp
;
1149 e
= open_file_search (filename
, FOPEN_RB
, "icon file", &real_filename
);
1151 /* The start of an icon file is a three word structure. The first
1152 word is ignored. The second word is the type of data. The third
1153 word is the number of entries. */
1155 get_word (e
, real_filename
);
1156 type
= get_word (e
, real_filename
);
1157 count
= get_word (e
, real_filename
);
1159 fatal (_("icon file `%s' does not contain icon data"), real_filename
);
1161 /* Read in the icon directory entries. */
1163 icondirs
= (struct icondir
*) xmalloc (count
* sizeof *icondirs
);
1165 for (i
= 0; i
< count
; i
++)
1167 icondirs
[i
].width
= getc (e
);
1168 icondirs
[i
].height
= getc (e
);
1169 icondirs
[i
].colorcount
= getc (e
);
1171 icondirs
[i
].u
.icon
.planes
= get_word (e
, real_filename
);
1172 icondirs
[i
].u
.icon
.bits
= get_word (e
, real_filename
);
1173 icondirs
[i
].bytes
= get_long (e
, real_filename
);
1174 icondirs
[i
].offset
= get_long (e
, real_filename
);
1177 unexpected_eof (real_filename
);
1180 /* Define each icon as a unique resource. */
1184 for (i
= 0; i
< count
; i
++)
1189 if (fseek (e
, icondirs
[i
].offset
, SEEK_SET
) != 0)
1190 fatal (_("%s: fseek to %lu failed: %s"), real_filename
,
1191 icondirs
[i
].offset
, strerror (errno
));
1193 data
= (bfd_byte
*) res_alloc (icondirs
[i
].bytes
);
1195 get_data (e
, data
, icondirs
[i
].bytes
, real_filename
);
1202 r
= define_standard_resource (&resources
, RT_ICON
, name
,
1203 resinfo
->language
, 0);
1204 r
->type
= RES_TYPE_ICON
;
1205 r
->u
.data
.length
= icondirs
[i
].bytes
;
1206 r
->u
.data
.data
= data
;
1207 r
->res_info
= *resinfo
;
1211 free (real_filename
);
1213 /* Define an icon group resource. */
1217 for (i
= 0; i
< count
; i
++)
1221 /* For some reason, at least in some files the planes and bits
1222 are zero. We instead set them from the color. This is
1225 cg
= (rc_group_icon
*) res_alloc (sizeof (rc_group_icon
));
1227 cg
->width
= icondirs
[i
].width
;
1228 cg
->height
= icondirs
[i
].height
;
1229 cg
->colors
= icondirs
[i
].colorcount
;
1231 if (icondirs
[i
].u
.icon
.planes
)
1232 cg
->planes
= icondirs
[i
].u
.icon
.planes
;
1236 if (icondirs
[i
].u
.icon
.bits
)
1237 cg
->bits
= icondirs
[i
].u
.icon
.bits
;
1242 while ((1L << cg
->bits
) < cg
->colors
)
1246 cg
->bytes
= icondirs
[i
].bytes
;
1247 cg
->index
= first_icon
+ i
+ 1;
1255 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1256 resinfo
->language
, 0);
1257 r
->type
= RES_TYPE_GROUP_ICON
;
1258 r
->u
.group_icon
= first
;
1259 r
->res_info
= *resinfo
;
1263 define_group_icon_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1264 rc_rcdata_item
*data
)
1267 rc_group_icon
*cg
, *first
, *cur
;
1268 rc_uint_type len_data
;
1271 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1276 while (len_data
>= 6)
1279 unsigned short type
;
1280 type
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1282 fatal (_("unexpected group icon type %d"), type
);
1283 c
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1287 for (i
= 0; i
< c
; i
++)
1290 fatal ("too small group icon rcdata");
1291 cg
= (rc_group_icon
*) res_alloc (sizeof (rc_group_icon
));
1293 cg
->width
= pb_data
[0];
1294 cg
->height
= pb_data
[1];
1295 cg
->colors
= pb_data
[2];
1296 cg
->planes
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1297 cg
->bits
= windres_get_16 (&wrtarget
, pb_data
+ 6, len_data
- 6);
1298 cg
->bytes
= windres_get_32 (&wrtarget
, pb_data
+ 8, len_data
- 8);
1299 cg
->index
= windres_get_16 (&wrtarget
, pb_data
+ 12, len_data
- 12);
1309 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1310 resinfo
->language
, 0);
1311 r
->type
= RES_TYPE_GROUP_ICON
;
1312 r
->u
.group_icon
= first
;
1313 r
->res_info
= *resinfo
;
1317 define_group_cursor_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1318 rc_rcdata_item
*data
)
1321 rc_group_cursor
*cg
, *first
, *cur
;
1322 rc_uint_type len_data
;
1325 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1329 while (len_data
>= 6)
1332 unsigned short type
;
1333 type
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1335 fatal (_("unexpected group cursor type %d"), type
);
1336 c
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1340 for (i
= 0; i
< c
; i
++)
1343 fatal ("too small group icon rcdata");
1344 cg
= (rc_group_cursor
*) res_alloc (sizeof (rc_group_cursor
));
1346 cg
->width
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1347 cg
->height
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1348 cg
->planes
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1349 cg
->bits
= windres_get_16 (&wrtarget
, pb_data
+ 6, len_data
- 6);
1350 cg
->bytes
= windres_get_32 (&wrtarget
, pb_data
+ 8, len_data
- 8);
1351 cg
->index
= windres_get_16 (&wrtarget
, pb_data
+ 12, len_data
- 12);
1362 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1363 resinfo
->language
, 0);
1364 r
->type
= RES_TYPE_GROUP_CURSOR
;
1365 r
->u
.group_cursor
= first
;
1366 r
->res_info
= *resinfo
;
1370 define_cursor_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1371 rc_rcdata_item
*data
)
1375 rc_uint_type len_data
;
1378 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1380 c
= (rc_cursor
*) res_alloc (sizeof (rc_cursor
));
1381 c
->xhotspot
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1382 c
->yhotspot
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1383 c
->length
= len_data
- BIN_CURSOR_SIZE
;
1384 c
->data
= (const bfd_byte
*) (data
+ BIN_CURSOR_SIZE
);
1386 r
= define_standard_resource (&resources
, RT_CURSOR
, id
, resinfo
->language
, 0);
1387 r
->type
= RES_TYPE_CURSOR
;
1389 r
->res_info
= *resinfo
;
1393 define_bitmap_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1394 rc_rcdata_item
*data
)
1397 rc_uint_type len_data
;
1400 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1402 r
= define_standard_resource (&resources
, RT_BITMAP
, id
, resinfo
->language
, 0);
1403 r
->type
= RES_TYPE_BITMAP
;
1404 r
->u
.data
.length
= len_data
;
1405 r
->u
.data
.data
= pb_data
;
1406 r
->res_info
= *resinfo
;
1410 define_icon_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1411 rc_rcdata_item
*data
)
1414 rc_uint_type len_data
;
1417 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1419 r
= define_standard_resource (&resources
, RT_ICON
, id
, resinfo
->language
, 0);
1420 r
->type
= RES_TYPE_ICON
;
1421 r
->u
.data
.length
= len_data
;
1422 r
->u
.data
.data
= pb_data
;
1423 r
->res_info
= *resinfo
;
1426 /* Define a menu resource. */
1429 define_menu (rc_res_id id
, const rc_res_res_info
*resinfo
,
1430 rc_menuitem
*menuitems
)
1435 m
= (rc_menu
*) res_alloc (sizeof (rc_menu
));
1436 m
->items
= menuitems
;
1439 r
= define_standard_resource (&resources
, RT_MENU
, id
, resinfo
->language
, 0);
1440 r
->type
= RES_TYPE_MENU
;
1442 r
->res_info
= *resinfo
;
1445 /* Define a menu item. This does not define a resource, but merely
1446 allocates and fills in a structure. */
1449 define_menuitem (const unichar
*text
, rc_uint_type menuid
, rc_uint_type type
,
1450 rc_uint_type state
, rc_uint_type help
,
1451 rc_menuitem
*menuitems
)
1455 mi
= (rc_menuitem
*) res_alloc (sizeof (rc_menuitem
));
1460 mi
->text
= unichar_dup (text
);
1462 mi
->popup
= menuitems
;
1466 /* Define a messagetable resource. */
1469 define_messagetable (rc_res_id id
, const rc_res_res_info
*resinfo
,
1470 const char *filename
)
1473 char *real_filename
;
1478 e
= open_file_search (filename
, FOPEN_RB
, "messagetable file",
1481 if (stat (real_filename
, &s
) < 0)
1482 fatal (_("stat failed on bitmap file `%s': %s"), real_filename
,
1485 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1487 get_data (e
, data
, s
.st_size
, real_filename
);
1490 free (real_filename
);
1492 r
= define_standard_resource (&resources
, RT_MESSAGETABLE
, id
,
1493 resinfo
->language
, 0);
1495 r
->type
= RES_TYPE_MESSAGETABLE
;
1496 r
->u
.data
.length
= s
.st_size
;
1497 r
->u
.data
.data
= data
;
1498 r
->res_info
= *resinfo
;
1501 /* Define an rcdata resource. */
1504 define_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1505 rc_rcdata_item
*data
)
1509 r
= define_standard_resource (&resources
, RT_RCDATA
, id
,
1510 resinfo
->language
, 0);
1511 r
->type
= RES_TYPE_RCDATA
;
1513 r
->res_info
= *resinfo
;
1516 /* Create an rcdata item holding a string. */
1519 define_rcdata_string (const char *string
, rc_uint_type len
)
1524 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1526 ri
->type
= RCDATA_STRING
;
1527 ri
->u
.string
.length
= len
;
1528 s
= (char *) res_alloc (len
);
1529 memcpy (s
, string
, len
);
1535 /* Create an rcdata item holding a unicode string. */
1538 define_rcdata_unistring (const unichar
*string
, rc_uint_type len
)
1543 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1545 ri
->type
= RCDATA_WSTRING
;
1546 ri
->u
.wstring
.length
= len
;
1547 s
= (unichar
*) res_alloc (len
* sizeof (unichar
));
1548 memcpy (s
, string
, len
* sizeof (unichar
));
1549 ri
->u
.wstring
.w
= s
;
1554 /* Create an rcdata item holding a number. */
1557 define_rcdata_number (rc_uint_type val
, int dword
)
1561 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1563 ri
->type
= dword
? RCDATA_DWORD
: RCDATA_WORD
;
1569 /* Define a stringtable resource. This is called for each string
1570 which appears in a STRINGTABLE statement. */
1573 define_stringtable (const rc_res_res_info
*resinfo
,
1574 rc_uint_type stringid
, const unichar
*string
)
1580 id
.u
.id
= (stringid
>> 4) + 1;
1581 r
= define_standard_resource (&resources
, RT_STRING
, id
,
1582 resinfo
->language
, 1);
1584 if (r
->type
== RES_TYPE_UNINITIALIZED
)
1588 r
->type
= RES_TYPE_STRINGTABLE
;
1589 r
->u
.stringtable
= ((rc_stringtable
*)
1590 res_alloc (sizeof (rc_stringtable
)));
1591 for (i
= 0; i
< 16; i
++)
1593 r
->u
.stringtable
->strings
[i
].length
= 0;
1594 r
->u
.stringtable
->strings
[i
].string
= NULL
;
1597 r
->res_info
= *resinfo
;
1600 r
->u
.stringtable
->strings
[stringid
& 0xf].length
= unichar_len (string
);
1601 r
->u
.stringtable
->strings
[stringid
& 0xf].string
= unichar_dup (string
);
1605 define_toolbar (rc_res_id id
, rc_res_res_info
*resinfo
, rc_uint_type width
, rc_uint_type height
,
1606 rc_toolbar_item
*items
)
1611 t
= (rc_toolbar
*) res_alloc (sizeof (rc_toolbar
));
1612 t
->button_width
= width
;
1613 t
->button_height
= height
;
1616 while (items
!= NULL
)
1619 items
= items
->next
;
1621 r
= define_standard_resource (&resources
, RT_TOOLBAR
, id
, resinfo
->language
, 0);
1622 r
->type
= RES_TYPE_TOOLBAR
;
1624 r
->res_info
= *resinfo
;
1627 /* Define a user data resource where the data is in the rc file. */
1630 define_user_data (rc_res_id id
, rc_res_id type
,
1631 const rc_res_res_info
*resinfo
,
1632 rc_rcdata_item
*data
)
1637 rc_uint_type len_data
;
1639 /* We have to check if the binary data is parsed specially. */
1640 if (type
.named
== 0)
1645 define_fontdir_rcdata (id
, resinfo
, data
);
1648 define_font_rcdata (id
, resinfo
, data
);
1651 define_icon_rcdata (id
, resinfo
, data
);
1654 define_bitmap_rcdata (id
, resinfo
, data
);
1657 define_cursor_rcdata (id
, resinfo
, data
);
1660 define_group_icon_rcdata (id
, resinfo
, data
);
1662 case RT_GROUP_CURSOR
:
1663 define_group_cursor_rcdata (id
, resinfo
, data
);
1665 case RT_MESSAGETABLE
:
1666 define_messagetable_rcdata (id
, resinfo
, data
);
1669 /* Treat as normal user-data. */
1676 ids
[2].u
.id
= resinfo
->language
;
1678 r
= define_resource (& resources
, 3, ids
, 0);
1679 r
->type
= RES_TYPE_USERDATA
;
1680 r
->u
.userdata
= ((rc_rcdata_item
*)
1681 res_alloc (sizeof (rc_rcdata_item
)));
1682 r
->u
.userdata
->next
= NULL
;
1683 r
->u
.userdata
->type
= RCDATA_BUFFER
;
1684 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1685 r
->u
.userdata
->u
.buffer
.length
= len_data
;
1686 r
->u
.userdata
->u
.buffer
.data
= pb_data
;
1687 r
->res_info
= *resinfo
;
1691 define_rcdata_file (rc_res_id id
, const rc_res_res_info
*resinfo
,
1692 const char *filename
)
1696 char *real_filename
;
1700 e
= open_file_search (filename
, FOPEN_RB
, "file", &real_filename
);
1703 if (stat (real_filename
, &s
) < 0)
1704 fatal (_("stat failed on file `%s': %s"), real_filename
,
1707 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1709 get_data (e
, data
, s
.st_size
, real_filename
);
1712 free (real_filename
);
1714 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1716 ri
->type
= RCDATA_BUFFER
;
1717 ri
->u
.buffer
.length
= s
.st_size
;
1718 ri
->u
.buffer
.data
= data
;
1720 define_rcdata (id
, resinfo
, ri
);
1723 /* Define a user data resource where the data is in a file. */
1726 define_user_file (rc_res_id id
, rc_res_id type
,
1727 const rc_res_res_info
*resinfo
, const char *filename
)
1730 char *real_filename
;
1736 e
= open_file_search (filename
, FOPEN_RB
, "file", &real_filename
);
1738 if (stat (real_filename
, &s
) < 0)
1739 fatal (_("stat failed on file `%s': %s"), real_filename
,
1742 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1744 get_data (e
, data
, s
.st_size
, real_filename
);
1747 free (real_filename
);
1752 ids
[2].u
.id
= resinfo
->language
;
1754 r
= define_resource (&resources
, 3, ids
, 0);
1755 r
->type
= RES_TYPE_USERDATA
;
1756 r
->u
.userdata
= ((rc_rcdata_item
*)
1757 res_alloc (sizeof (rc_rcdata_item
)));
1758 r
->u
.userdata
->next
= NULL
;
1759 r
->u
.userdata
->type
= RCDATA_BUFFER
;
1760 r
->u
.userdata
->u
.buffer
.length
= s
.st_size
;
1761 r
->u
.userdata
->u
.buffer
.data
= data
;
1762 r
->res_info
= *resinfo
;
1765 /* Define a versioninfo resource. */
1768 define_versioninfo (rc_res_id id
, rc_uint_type language
,
1769 rc_fixed_versioninfo
*fixedverinfo
,
1770 rc_ver_info
*verinfo
)
1774 r
= define_standard_resource (&resources
, RT_VERSION
, id
, language
, 0);
1775 r
->type
= RES_TYPE_VERSIONINFO
;
1776 r
->u
.versioninfo
= ((rc_versioninfo
*)
1777 res_alloc (sizeof (rc_versioninfo
)));
1778 r
->u
.versioninfo
->fixed
= fixedverinfo
;
1779 r
->u
.versioninfo
->var
= verinfo
;
1780 r
->res_info
.language
= language
;
1783 /* Add string version info to a list of version information. */
1786 append_ver_stringfileinfo (rc_ver_info
*verinfo
, const char *language
,
1787 rc_ver_stringinfo
*strings
)
1789 rc_ver_info
*vi
, **pp
;
1791 vi
= (rc_ver_info
*) res_alloc (sizeof (rc_ver_info
));
1793 vi
->type
= VERINFO_STRING
;
1794 unicode_from_ascii ((rc_uint_type
*) NULL
, &vi
->u
.string
.language
, language
);
1795 vi
->u
.string
.strings
= strings
;
1797 for (pp
= &verinfo
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1804 /* Add variable version info to a list of version information. */
1807 append_ver_varfileinfo (rc_ver_info
*verinfo
, const unichar
*key
,
1808 rc_ver_varinfo
*var
)
1810 rc_ver_info
*vi
, **pp
;
1812 vi
= (rc_ver_info
*) res_alloc (sizeof *vi
);
1814 vi
->type
= VERINFO_VAR
;
1815 vi
->u
.var
.key
= unichar_dup (key
);
1816 vi
->u
.var
.var
= var
;
1818 for (pp
= &verinfo
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1825 /* Append version string information to a list. */
1828 append_verval (rc_ver_stringinfo
*strings
, const unichar
*key
,
1829 const unichar
*value
)
1831 rc_ver_stringinfo
*vs
, **pp
;
1833 vs
= (rc_ver_stringinfo
*) res_alloc (sizeof (rc_ver_stringinfo
));
1835 vs
->key
= unichar_dup (key
);
1836 vs
->value
= unichar_dup (value
);
1838 for (pp
= &strings
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1845 /* Append version variable information to a list. */
1848 append_vertrans (rc_ver_varinfo
*var
, rc_uint_type language
,
1849 rc_uint_type charset
)
1851 rc_ver_varinfo
*vv
, **pp
;
1853 vv
= (rc_ver_varinfo
*) res_alloc (sizeof (rc_ver_varinfo
));
1855 vv
->language
= language
;
1856 vv
->charset
= charset
;
1858 for (pp
= &var
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1865 /* Local functions used to write out an rc file. */
1867 static void indent (FILE *, int);
1868 static void write_rc_directory (FILE *, const rc_res_directory
*, const rc_res_id
*,
1869 const rc_res_id
*, rc_uint_type
*, int);
1870 static void write_rc_subdir (FILE *, const rc_res_entry
*, const rc_res_id
*,
1871 const rc_res_id
*, rc_uint_type
*, int);
1872 static void write_rc_resource (FILE *, const rc_res_id
*, const rc_res_id
*,
1873 const rc_res_resource
*, rc_uint_type
*);
1874 static void write_rc_accelerators (FILE *, const rc_accelerator
*);
1875 static void write_rc_cursor (FILE *, const rc_cursor
*);
1876 static void write_rc_group_cursor (FILE *, const rc_group_cursor
*);
1877 static void write_rc_dialog (FILE *, const rc_dialog
*);
1878 static void write_rc_dialog_control (FILE *, const rc_dialog_control
*);
1879 static void write_rc_fontdir (FILE *, const rc_fontdir
*);
1880 static void write_rc_group_icon (FILE *, const rc_group_icon
*);
1881 static void write_rc_menu (FILE *, const rc_menu
*, int);
1882 static void write_rc_toolbar (FILE *, const rc_toolbar
*);
1883 static void write_rc_menuitems (FILE *, const rc_menuitem
*, int, int);
1884 static void write_rc_messagetable (FILE *, rc_uint_type
, const bfd_byte
*);
1886 static void write_rc_datablock (FILE *, rc_uint_type
, const bfd_byte
*, int, int, int);
1887 static void write_rc_rcdata (FILE *, const rc_rcdata_item
*, int);
1888 static void write_rc_stringtable (FILE *, const rc_res_id
*, const rc_stringtable
*);
1889 static void write_rc_versioninfo (FILE *, const rc_versioninfo
*);
1891 /* Indent a given number of spaces. */
1894 indent (FILE *e
, int c
)
1898 for (i
= 0; i
< c
; i
++)
1902 /* Dump the resources we have read in the format of an rc file.
1904 Reasoned by the fact, that some resources need to be stored into file and
1905 refer to that file, we use the user-data model for that to express it binary
1906 without the need to store it somewhere externally. */
1909 write_rc_file (const char *filename
, const rc_res_directory
*resources
)
1912 rc_uint_type language
;
1914 if (filename
== NULL
)
1918 e
= fopen (filename
, FOPEN_WT
);
1920 fatal (_("can't open `%s' for output: %s"), filename
, strerror (errno
));
1923 language
= (rc_uint_type
) ((bfd_signed_vma
) -1);
1924 write_rc_directory (e
, resources
, (const rc_res_id
*) NULL
,
1925 (const rc_res_id
*) NULL
, &language
, 1);
1928 /* Write out a directory. E is the file to write to. RD is the
1929 directory. TYPE is a pointer to the level 1 ID which serves as the
1930 resource type. NAME is a pointer to the level 2 ID which serves as
1931 an individual resource name. LANGUAGE is a pointer to the current
1932 language. LEVEL is the level in the tree. */
1935 write_rc_directory (FILE *e
, const rc_res_directory
*rd
,
1936 const rc_res_id
*type
, const rc_res_id
*name
,
1937 rc_uint_type
*language
, int level
)
1939 const rc_res_entry
*re
;
1941 /* Print out some COFF information that rc files can't represent. */
1942 if (rd
->time
!= 0 || rd
->characteristics
!= 0 || rd
->major
!= 0 || rd
->minor
!= 0)
1944 wr_printcomment (e
, "COFF information not part of RC");
1946 wr_printcomment (e
, "Time stamp: %u", rd
->time
);
1947 if (rd
->characteristics
!= 0)
1948 wr_printcomment (e
, "Characteristics: %u", rd
->characteristics
);
1949 if (rd
->major
!= 0 || rd
->minor
!= 0)
1950 wr_printcomment (e
, "Version major:%d minor:%d", rd
->major
, rd
->minor
);
1953 for (re
= rd
->entries
; re
!= NULL
; re
= re
->next
)
1958 /* If we're at level 1, the key of this resource is the
1959 type. This normally duplicates the information we have
1960 stored with the resource itself, but we need to remember
1961 the type if this is a user define resource type. */
1966 /* If we're at level 2, the key of this resource is the name
1967 we are going to use in the rc printout. */
1972 /* If we're at level 3, then this key represents a language.
1973 Use it to update the current language. */
1975 && re
->id
.u
.id
!= (unsigned long) (unsigned int) *language
1976 && (re
->id
.u
.id
& 0xffff) == re
->id
.u
.id
)
1978 wr_print (e
, "LANGUAGE %u, %u\n",
1979 re
->id
.u
.id
& ((1 << SUBLANG_SHIFT
) - 1),
1980 (re
->id
.u
.id
>> SUBLANG_SHIFT
) & 0xff);
1981 *language
= re
->id
.u
.id
;
1990 write_rc_subdir (e
, re
, type
, name
, language
, level
);
1995 /* This is the normal case: the three levels are
1996 TYPE/NAME/LANGUAGE. NAME will have been set at level
1997 2, and represents the name to use. We probably just
1998 set LANGUAGE, and it will probably match what the
1999 resource itself records if anything. */
2000 write_rc_resource (e
, type
, name
, re
->u
.res
, language
);
2004 wr_printcomment (e
, "Resource at unexpected level %d", level
);
2005 write_rc_resource (e
, type
, (rc_res_id
*) NULL
, re
->u
.res
,
2010 if (rd
->entries
== NULL
)
2016 /* Write out a subdirectory entry. E is the file to write to. RE is
2017 the subdirectory entry. TYPE and NAME are pointers to higher level
2018 IDs, or NULL. LANGUAGE is a pointer to the current language.
2019 LEVEL is the level in the tree. */
2022 write_rc_subdir (FILE *e
, const rc_res_entry
*re
,
2023 const rc_res_id
*type
, const rc_res_id
*name
,
2024 rc_uint_type
*language
, int level
)
2030 wr_printcomment (e
, "Type: ");
2032 res_id_print (e
, re
->id
, 1);
2037 switch (re
->id
.u
.id
)
2039 case RT_CURSOR
: s
= "cursor"; break;
2040 case RT_BITMAP
: s
= "bitmap"; break;
2041 case RT_ICON
: s
= "icon"; break;
2042 case RT_MENU
: s
= "menu"; break;
2043 case RT_DIALOG
: s
= "dialog"; break;
2044 case RT_STRING
: s
= "stringtable"; break;
2045 case RT_FONTDIR
: s
= "fontdir"; break;
2046 case RT_FONT
: s
= "font"; break;
2047 case RT_ACCELERATOR
: s
= "accelerators"; break;
2048 case RT_RCDATA
: s
= "rcdata"; break;
2049 case RT_MESSAGETABLE
: s
= "messagetable"; break;
2050 case RT_GROUP_CURSOR
: s
= "group cursor"; break;
2051 case RT_GROUP_ICON
: s
= "group icon"; break;
2052 case RT_VERSION
: s
= "version"; break;
2053 case RT_DLGINCLUDE
: s
= "dlginclude"; break;
2054 case RT_PLUGPLAY
: s
= "plugplay"; break;
2055 case RT_VXD
: s
= "vxd"; break;
2056 case RT_ANICURSOR
: s
= "anicursor"; break;
2057 case RT_ANIICON
: s
= "aniicon"; break;
2058 case RT_TOOLBAR
: s
= "toolbar"; break;
2059 case RT_HTML
: s
= "html"; break;
2060 default: s
= NULL
; break;
2064 fprintf (e
, "%s", s
);
2066 res_id_print (e
, re
->id
, 1);
2071 wr_printcomment (e
, "Name: ");
2072 res_id_print (e
, re
->id
, 1);
2076 wr_printcomment (e
, "Language: ");
2077 res_id_print (e
, re
->id
, 1);
2081 wr_printcomment (e
, "Level %d: ", level
);
2082 res_id_print (e
, re
->id
, 1);
2085 write_rc_directory (e
, re
->u
.dir
, type
, name
, language
, level
+ 1);
2088 /* Write out a single resource. E is the file to write to. TYPE is a
2089 pointer to the type of the resource. NAME is a pointer to the name
2090 of the resource; it will be NULL if there is a level mismatch. RES
2091 is the resource data. LANGUAGE is a pointer to the current
2095 write_rc_resource (FILE *e
, const rc_res_id
*type
,
2096 const rc_res_id
*name
, const rc_res_resource
*res
,
2097 rc_uint_type
*language
)
2108 case RES_TYPE_ACCELERATOR
:
2110 rt
= RT_ACCELERATOR
;
2113 case RES_TYPE_BITMAP
:
2114 s
= "2 /* RT_BITMAP */";
2118 case RES_TYPE_CURSOR
:
2119 s
= "1 /* RT_CURSOR */";
2123 case RES_TYPE_GROUP_CURSOR
:
2124 s
= "12 /* RT_GROUP_CURSOR */";
2125 rt
= RT_GROUP_CURSOR
;
2128 case RES_TYPE_DIALOG
:
2129 if (extended_dialog (res
->u
.dialog
))
2137 s
= "8 /* RT_FONT */";
2141 case RES_TYPE_FONTDIR
:
2142 s
= "7 /* RT_FONTDIR */";
2147 s
= "3 /* RT_ICON */";
2151 case RES_TYPE_GROUP_ICON
:
2152 s
= "14 /* RT_GROUP_ICON */";
2157 if (extended_menu (res
->u
.menu
))
2170 case RES_TYPE_MESSAGETABLE
:
2171 s
= "11 /* RT_MESSAGETABLE */";
2172 rt
= RT_MESSAGETABLE
;
2175 case RES_TYPE_RCDATA
:
2180 case RES_TYPE_STRINGTABLE
:
2185 case RES_TYPE_USERDATA
:
2190 case RES_TYPE_VERSIONINFO
:
2195 case RES_TYPE_TOOLBAR
:
2203 && (type
->named
|| type
->u
.id
!= (unsigned long) rt
))
2205 wr_printcomment (e
, "Unexpected resource type mismatch: ");
2206 res_id_print (e
, *type
, 1);
2207 fprintf (e
, " != %d", rt
);
2210 if (res
->coff_info
.codepage
!= 0)
2211 wr_printcomment (e
, "Code page: %u", res
->coff_info
.codepage
);
2212 if (res
->coff_info
.reserved
!= 0)
2213 wr_printcomment (e
, "COFF reserved value: %u", res
->coff_info
.reserved
);
2216 if (rt
== RT_STRING
)
2221 res_id_print (e
, *name
, 1);
2223 fprintf (e
, "??Unknown-Name??");
2228 fprintf (e
, "%s", s
);
2229 else if (type
!= NULL
)
2231 if (type
->named
== 0)
2233 #define PRINT_RT_NAME(NAME) case NAME: \
2234 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2240 res_id_print (e
, *type
, 0);
2243 PRINT_RT_NAME(RT_MANIFEST
);
2244 PRINT_RT_NAME(RT_ANICURSOR
);
2245 PRINT_RT_NAME(RT_ANIICON
);
2246 PRINT_RT_NAME(RT_RCDATA
);
2247 PRINT_RT_NAME(RT_ICON
);
2248 PRINT_RT_NAME(RT_CURSOR
);
2249 PRINT_RT_NAME(RT_BITMAP
);
2250 PRINT_RT_NAME(RT_PLUGPLAY
);
2251 PRINT_RT_NAME(RT_VXD
);
2252 PRINT_RT_NAME(RT_FONT
);
2253 PRINT_RT_NAME(RT_FONTDIR
);
2254 PRINT_RT_NAME(RT_HTML
);
2255 PRINT_RT_NAME(RT_MESSAGETABLE
);
2256 PRINT_RT_NAME(RT_DLGINCLUDE
);
2257 PRINT_RT_NAME(RT_DLGINIT
);
2259 #undef PRINT_RT_NAME
2262 res_id_print (e
, *type
, 1);
2265 fprintf (e
, "??Unknown-Type??");
2267 if (res
->res_info
.memflags
!= 0)
2269 if ((res
->res_info
.memflags
& MEMFLAG_MOVEABLE
) != 0)
2270 fprintf (e
, " MOVEABLE");
2271 if ((res
->res_info
.memflags
& MEMFLAG_PURE
) != 0)
2272 fprintf (e
, " PURE");
2273 if ((res
->res_info
.memflags
& MEMFLAG_PRELOAD
) != 0)
2274 fprintf (e
, " PRELOAD");
2275 if ((res
->res_info
.memflags
& MEMFLAG_DISCARDABLE
) != 0)
2276 fprintf (e
, " DISCARDABLE");
2279 if (res
->type
== RES_TYPE_DIALOG
)
2281 fprintf (e
, " %d, %d, %d, %d",
2282 (int) res
->u
.dialog
->x
, (int) res
->u
.dialog
->y
,
2283 (int) res
->u
.dialog
->width
, (int) res
->u
.dialog
->height
);
2284 if (res
->u
.dialog
->ex
!= NULL
2285 && res
->u
.dialog
->ex
->help
!= 0)
2286 fprintf (e
, ", %u", (unsigned int) res
->u
.dialog
->ex
->help
);
2288 else if (res
->type
== RES_TYPE_TOOLBAR
)
2290 fprintf (e
, " %d, %d", (int) res
->u
.toolbar
->button_width
,
2291 (int) res
->u
.toolbar
->button_height
);
2296 if ((res
->res_info
.language
!= 0 && res
->res_info
.language
!= *language
)
2297 || res
->res_info
.characteristics
!= 0
2298 || res
->res_info
.version
!= 0)
2304 case RES_TYPE_ACCELERATOR
:
2305 case RES_TYPE_DIALOG
:
2307 case RES_TYPE_RCDATA
:
2308 case RES_TYPE_STRINGTABLE
:
2317 if (res
->res_info
.language
!= 0 && res
->res_info
.language
!= *language
)
2318 fprintf (e
, "%sLANGUAGE %d, %d\n",
2319 modifiers
? "// " : "",
2320 (int) res
->res_info
.language
& ((1<<SUBLANG_SHIFT
)-1),
2321 (int) (res
->res_info
.language
>> SUBLANG_SHIFT
) & 0xff);
2322 if (res
->res_info
.characteristics
!= 0)
2323 fprintf (e
, "%sCHARACTERISTICS %u\n",
2324 modifiers
? "// " : "",
2325 (unsigned int) res
->res_info
.characteristics
);
2326 if (res
->res_info
.version
!= 0)
2327 fprintf (e
, "%sVERSION %u\n",
2328 modifiers
? "// " : "",
2329 (unsigned int) res
->res_info
.version
);
2337 case RES_TYPE_ACCELERATOR
:
2338 write_rc_accelerators (e
, res
->u
.acc
);
2341 case RES_TYPE_CURSOR
:
2342 write_rc_cursor (e
, res
->u
.cursor
);
2345 case RES_TYPE_GROUP_CURSOR
:
2346 write_rc_group_cursor (e
, res
->u
.group_cursor
);
2349 case RES_TYPE_DIALOG
:
2350 write_rc_dialog (e
, res
->u
.dialog
);
2353 case RES_TYPE_FONTDIR
:
2354 write_rc_fontdir (e
, res
->u
.fontdir
);
2357 case RES_TYPE_GROUP_ICON
:
2358 write_rc_group_icon (e
, res
->u
.group_icon
);
2362 write_rc_menu (e
, res
->u
.menu
, menuex
);
2365 case RES_TYPE_RCDATA
:
2366 write_rc_rcdata (e
, res
->u
.rcdata
, 0);
2369 case RES_TYPE_STRINGTABLE
:
2370 write_rc_stringtable (e
, name
, res
->u
.stringtable
);
2373 case RES_TYPE_USERDATA
:
2374 write_rc_rcdata (e
, res
->u
.userdata
, 0);
2377 case RES_TYPE_TOOLBAR
:
2378 write_rc_toolbar (e
, res
->u
.toolbar
);
2381 case RES_TYPE_VERSIONINFO
:
2382 write_rc_versioninfo (e
, res
->u
.versioninfo
);
2385 case RES_TYPE_BITMAP
:
2388 write_rc_datablock (e
, res
->u
.data
.length
, res
->u
.data
.data
, 0, 1, 0);
2390 case RES_TYPE_MESSAGETABLE
:
2391 write_rc_messagetable (e
, res
->u
.data
.length
, res
->u
.data
.data
);
2396 /* Write out accelerator information. */
2399 write_rc_accelerators (FILE *e
, const rc_accelerator
*accelerators
)
2401 const rc_accelerator
*acc
;
2403 fprintf (e
, "BEGIN\n");
2404 for (acc
= accelerators
; acc
!= NULL
; acc
= acc
->next
)
2410 if ((acc
->key
& 0x7f) == acc
->key
2411 && ISPRINT (acc
->key
)
2412 && (acc
->flags
& ACC_VIRTKEY
) == 0)
2414 fprintf (e
, "\"%c\"", (char) acc
->key
);
2419 fprintf (e
, "%d", (int) acc
->key
);
2423 fprintf (e
, ", %d", (int) acc
->id
);
2427 if ((acc
->flags
& ACC_VIRTKEY
) != 0)
2428 fprintf (e
, ", VIRTKEY");
2430 fprintf (e
, ", ASCII");
2433 if ((acc
->flags
& ACC_SHIFT
) != 0)
2434 fprintf (e
, ", SHIFT");
2435 if ((acc
->flags
& ACC_CONTROL
) != 0)
2436 fprintf (e
, ", CONTROL");
2437 if ((acc
->flags
& ACC_ALT
) != 0)
2438 fprintf (e
, ", ALT");
2443 fprintf (e
, "END\n");
2446 /* Write out cursor information. This would normally be in a separate
2447 file, which the rc file would include. */
2450 write_rc_cursor (FILE *e
, const rc_cursor
*cursor
)
2452 fprintf (e
, "BEGIN\n");
2454 fprintf (e
, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2455 (unsigned int) cursor
->xhotspot
, (unsigned int) cursor
->yhotspot
,
2456 (int) cursor
->xhotspot
, (int) cursor
->yhotspot
);
2457 write_rc_datablock (e
, (rc_uint_type
) cursor
->length
, (const bfd_byte
*) cursor
->data
,
2459 fprintf (e
, "END\n");
2462 /* Write out group cursor data. This would normally be built from the
2466 write_rc_group_cursor (FILE *e
, const rc_group_cursor
*group_cursor
)
2468 const rc_group_cursor
*gc
;
2471 for (c
= 0, gc
= group_cursor
; gc
!= NULL
; gc
= gc
->next
, c
++)
2473 fprintf (e
, "BEGIN\n");
2476 fprintf (e
, "0, 2, %d%s\t /* Having %d items. */\n", c
, (c
!= 0 ? "," : ""), c
);
2478 fprintf (e
, "/* width, height, planes, bits, bytes, index. */\n");
2480 for (c
= 1, gc
= group_cursor
; gc
!= NULL
; gc
= gc
->next
, c
++)
2483 fprintf (e
, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2484 (int) gc
->width
, (int) gc
->height
, (int) gc
->planes
, (int) gc
->bits
,
2485 (unsigned int) gc
->bytes
, (int) gc
->index
, (gc
->next
!= NULL
? "," : ""), c
);
2486 fprintf (e
, "/* width: %d; height %d; planes %d; bits %d. */\n",
2487 (int) gc
->width
, (int) gc
->height
, (int) gc
->planes
,
2490 fprintf (e
, "END\n");
2493 /* Write dialog data. */
2496 write_rc_dialog (FILE *e
, const rc_dialog
*dialog
)
2498 const rc_dialog_control
*control
;
2500 fprintf (e
, "STYLE 0x%x\n", dialog
->style
);
2502 if (dialog
->exstyle
!= 0)
2503 fprintf (e
, "EXSTYLE 0x%x\n", (unsigned int) dialog
->exstyle
);
2505 if ((dialog
->class.named
&& dialog
->class.u
.n
.length
> 0)
2506 || dialog
->class.u
.id
!= 0)
2508 fprintf (e
, "CLASS ");
2509 res_id_print (e
, dialog
->class, 1);
2513 if (dialog
->caption
!= NULL
)
2515 fprintf (e
, "CAPTION ");
2516 unicode_print_quoted (e
, dialog
->caption
, -1);
2520 if ((dialog
->menu
.named
&& dialog
->menu
.u
.n
.length
> 0)
2521 || dialog
->menu
.u
.id
!= 0)
2523 fprintf (e
, "MENU ");
2524 res_id_print (e
, dialog
->menu
, 0);
2528 if (dialog
->font
!= NULL
)
2530 fprintf (e
, "FONT %d, ", (int) dialog
->pointsize
);
2531 unicode_print_quoted (e
, dialog
->font
, -1);
2532 if (dialog
->ex
!= NULL
2533 && (dialog
->ex
->weight
!= 0
2534 || dialog
->ex
->italic
!= 0
2535 || dialog
->ex
->charset
!= 1))
2536 fprintf (e
, ", %d, %d, %d",
2537 (int) dialog
->ex
->weight
,
2538 (int) dialog
->ex
->italic
,
2539 (int) dialog
->ex
->charset
);
2543 fprintf (e
, "BEGIN\n");
2545 for (control
= dialog
->controls
; control
!= NULL
; control
= control
->next
)
2546 write_rc_dialog_control (e
, control
);
2548 fprintf (e
, "END\n");
2551 /* For each predefined control keyword, this table provides the class
2557 unsigned short class;
2558 unsigned long style
;
2561 static const struct control_info control_info
[] =
2563 { "AUTO3STATE", CTL_BUTTON
, BS_AUTO3STATE
},
2564 { "AUTOCHECKBOX", CTL_BUTTON
, BS_AUTOCHECKBOX
},
2565 { "AUTORADIOBUTTON", CTL_BUTTON
, BS_AUTORADIOBUTTON
},
2566 { "CHECKBOX", CTL_BUTTON
, BS_CHECKBOX
},
2567 { "COMBOBOX", CTL_COMBOBOX
, (unsigned long) -1 },
2568 { "CTEXT", CTL_STATIC
, SS_CENTER
},
2569 { "DEFPUSHBUTTON", CTL_BUTTON
, BS_DEFPUSHBUTTON
},
2570 { "EDITTEXT", CTL_EDIT
, (unsigned long) -1 },
2571 { "GROUPBOX", CTL_BUTTON
, BS_GROUPBOX
},
2572 { "ICON", CTL_STATIC
, SS_ICON
},
2573 { "LISTBOX", CTL_LISTBOX
, (unsigned long) -1 },
2574 { "LTEXT", CTL_STATIC
, SS_LEFT
},
2575 { "PUSHBOX", CTL_BUTTON
, BS_PUSHBOX
},
2576 { "PUSHBUTTON", CTL_BUTTON
, BS_PUSHBUTTON
},
2577 { "RADIOBUTTON", CTL_BUTTON
, BS_RADIOBUTTON
},
2578 { "RTEXT", CTL_STATIC
, SS_RIGHT
},
2579 { "SCROLLBAR", CTL_SCROLLBAR
, (unsigned long) -1 },
2580 { "STATE3", CTL_BUTTON
, BS_3STATE
},
2581 /* It's important that USERBUTTON come after all the other button
2582 types, so that it won't be matched too early. */
2583 { "USERBUTTON", CTL_BUTTON
, (unsigned long) -1 },
2587 /* Write a dialog control. */
2590 write_rc_dialog_control (FILE *e
, const rc_dialog_control
*control
)
2592 const struct control_info
*ci
;
2596 if (control
->class.named
)
2600 for (ci
= control_info
; ci
->name
!= NULL
; ++ci
)
2601 if (ci
->class == control
->class.u
.id
2602 && (ci
->style
== (unsigned long) -1
2603 || ci
->style
== (control
->style
& 0xff)))
2607 fprintf (e
, "CONTROL");
2608 else if (ci
->name
!= NULL
)
2609 fprintf (e
, "%s", ci
->name
);
2612 fprintf (e
, "CONTROL");
2616 if (control
->text
.named
|| control
->text
.u
.id
!= 0)
2619 res_id_print (e
, control
->text
, 1);
2623 fprintf (e
, " %d, ", (int) control
->id
);
2627 if (control
->class.named
)
2629 res_id_print (e
, control
->class, 0);
2630 if (control
->class.named
)
2632 fprintf (e
, ", 0x%x, ", (unsigned int) control
->style
);
2635 fprintf (e
, "%d, %d", (int) control
->x
, (int) control
->y
);
2637 if (control
->style
!= SS_ICON
2638 || control
->exstyle
!= 0
2639 || control
->width
!= 0
2640 || control
->height
!= 0
2641 || control
->help
!= 0)
2643 fprintf (e
, ", %d, %d", (int) control
->width
, (int) control
->height
);
2645 /* FIXME: We don't need to print the style if it is the default.
2646 More importantly, in certain cases we actually need to turn
2647 off parts of the forced style, by using NOT. */
2649 fprintf (e
, ", 0x%x", (unsigned int) control
->style
);
2651 if (control
->exstyle
!= 0 || control
->help
!= 0)
2652 fprintf (e
, ", 0x%x, %u", (unsigned int) control
->exstyle
,
2653 (unsigned int) control
->help
);
2658 if (control
->data
!= NULL
)
2659 write_rc_rcdata (e
, control
->data
, 2);
2662 /* Write out font directory data. This would normally be built from
2666 write_rc_fontdir (FILE *e
, const rc_fontdir
*fontdir
)
2668 const rc_fontdir
*fc
;
2671 for (c
= 0, fc
= fontdir
; fc
!= NULL
; fc
= fc
->next
, c
++)
2673 fprintf (e
, "BEGIN\n");
2675 fprintf (e
, "%d%s\t /* Has %d elements. */\n", c
, (c
!= 0 ? "," : ""), c
);
2676 for (c
= 1, fc
= fontdir
; fc
!= NULL
; fc
= fc
->next
, c
++)
2679 fprintf (e
, "%d,\t/* Font no %d with index %d. */\n",
2680 (int) fc
->index
, c
, (int) fc
->index
);
2681 write_rc_datablock (e
, (rc_uint_type
) fc
->length
- 2,
2682 (const bfd_byte
*) fc
->data
+ 4,fc
->next
!= NULL
,
2685 fprintf (e
, "END\n");
2688 /* Write out group icon data. This would normally be built from the
2692 write_rc_group_icon (FILE *e
, const rc_group_icon
*group_icon
)
2694 const rc_group_icon
*gi
;
2697 for (c
= 0, gi
= group_icon
; gi
!= NULL
; gi
= gi
->next
, c
++)
2700 fprintf (e
, "BEGIN\n");
2702 fprintf (e
, " 0, 1, %d%s\t /* Has %d elements. */\n", c
, (c
!= 0 ? "," : ""), c
);
2705 fprintf (e
, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2706 for (c
= 1, gi
= group_icon
; gi
!= NULL
; gi
= gi
->next
, c
++)
2709 fprintf (e
, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2710 gi
->width
, gi
->height
, gi
->colors
, 0, (int) gi
->planes
, (int) gi
->bits
,
2711 (unsigned int) gi
->bytes
, (int) gi
->index
, (gi
->next
!= NULL
? "," : ""), c
);
2713 fprintf (e
, "END\n");
2716 /* Write out a menu resource. */
2719 write_rc_menu (FILE *e
, const rc_menu
*menu
, int menuex
)
2721 if (menu
->help
!= 0)
2722 fprintf (e
, "// Help ID: %u\n", (unsigned int) menu
->help
);
2723 write_rc_menuitems (e
, menu
->items
, menuex
, 0);
2727 write_rc_toolbar (FILE *e
, const rc_toolbar
*tb
)
2729 rc_toolbar_item
*it
;
2731 fprintf (e
, "BEGIN\n");
2736 if (it
->id
.u
.id
== 0)
2737 fprintf (e
, "SEPARATOR\n");
2739 fprintf (e
, "BUTTON %d\n", (int) it
->id
.u
.id
);
2743 fprintf (e
, "END\n");
2746 /* Write out menuitems. */
2749 write_rc_menuitems (FILE *e
, const rc_menuitem
*menuitems
, int menuex
,
2752 const rc_menuitem
*mi
;
2755 fprintf (e
, "BEGIN\n");
2757 for (mi
= menuitems
; mi
!= NULL
; mi
= mi
->next
)
2759 indent (e
, ind
+ 2);
2761 if (mi
->popup
== NULL
)
2762 fprintf (e
, "MENUITEM");
2764 fprintf (e
, "POPUP");
2767 && mi
->popup
== NULL
2772 fprintf (e
, " SEPARATOR\n");
2776 if (mi
->text
== NULL
)
2777 fprintf (e
, " \"\"");
2781 unicode_print_quoted (e
, mi
->text
, -1);
2786 if (mi
->popup
== NULL
)
2787 fprintf (e
, ", %d", (int) mi
->id
);
2789 if ((mi
->type
& MENUITEM_CHECKED
) != 0)
2790 fprintf (e
, ", CHECKED");
2791 if ((mi
->type
& MENUITEM_GRAYED
) != 0)
2792 fprintf (e
, ", GRAYED");
2793 if ((mi
->type
& MENUITEM_HELP
) != 0)
2794 fprintf (e
, ", HELP");
2795 if ((mi
->type
& MENUITEM_INACTIVE
) != 0)
2796 fprintf (e
, ", INACTIVE");
2797 if ((mi
->type
& MENUITEM_MENUBARBREAK
) != 0)
2798 fprintf (e
, ", MENUBARBREAK");
2799 if ((mi
->type
& MENUITEM_MENUBREAK
) != 0)
2800 fprintf (e
, ", MENUBREAK");
2804 if (mi
->id
!= 0 || mi
->type
!= 0 || mi
->state
!= 0 || mi
->help
!= 0)
2806 fprintf (e
, ", %d", (int) mi
->id
);
2807 if (mi
->type
!= 0 || mi
->state
!= 0 || mi
->help
!= 0)
2809 fprintf (e
, ", %u", (unsigned int) mi
->type
);
2810 if (mi
->state
!= 0 || mi
->help
!= 0)
2812 fprintf (e
, ", %u", (unsigned int) mi
->state
);
2814 fprintf (e
, ", %u", (unsigned int) mi
->help
);
2822 if (mi
->popup
!= NULL
)
2823 write_rc_menuitems (e
, mi
->popup
, menuex
, ind
+ 2);
2827 fprintf (e
, "END\n");
2831 test_rc_datablock_unicode (rc_uint_type length
, const bfd_byte
*data
)
2834 if ((length
& 1) != 0)
2837 for (i
= 0; i
< length
; i
+= 2)
2839 if (data
[i
] == 0 && data
[i
+ 1] == 0 && (i
+ 2) < length
)
2841 if (data
[i
] == 0xff && data
[i
+ 1] == 0xff)
2848 test_rc_datablock_text (rc_uint_type length
, const bfd_byte
*data
)
2858 for (i
= 0, c
= 0; i
< length
; i
++)
2860 if (! ISPRINT (data
[i
]) && data
[i
] != '\n'
2861 && ! (data
[i
] == '\r' && (i
+ 1) < length
&& data
[i
+ 1] == '\n')
2863 && ! (data
[i
] == 0 && (i
+ 1) != length
))
2869 else if (data
[i
] == '\n') has_nl
++;
2871 if (length
> 80 && ! has_nl
)
2873 c
= (((c
* 10000) + (i
/ 100) - 1)) / i
;
2880 write_rc_messagetable (FILE *e
, rc_uint_type length
, const bfd_byte
*data
)
2883 const struct bin_messagetable
*mt
;
2884 fprintf (e
, "BEGIN\n");
2886 write_rc_datablock (e
, length
, data
, 0, 0, 0);
2889 wr_printcomment (e
, "MC syntax dump");
2890 if (length
< BIN_MESSAGETABLE_SIZE
)
2895 mt
= (const struct bin_messagetable
*) data
;
2896 m
= windres_get_32 (&wrtarget
, mt
->cblocks
, length
);
2897 if (length
< (BIN_MESSAGETABLE_SIZE
+ m
* BIN_MESSAGETABLE_BLOCK_SIZE
))
2902 for (i
= 0; i
< m
; i
++)
2904 rc_uint_type low
, high
, offset
;
2905 const struct bin_messagetable_item
*mti
;
2907 low
= windres_get_32 (&wrtarget
, mt
->items
[i
].lowid
, 4);
2908 high
= windres_get_32 (&wrtarget
, mt
->items
[i
].highid
, 4);
2909 offset
= windres_get_32 (&wrtarget
, mt
->items
[i
].offset
, 4);
2912 rc_uint_type elen
, flags
;
2913 if ((offset
+ BIN_MESSAGETABLE_ITEM_SIZE
) > length
)
2918 mti
= (const struct bin_messagetable_item
*) &data
[offset
];
2919 elen
= windres_get_16 (&wrtarget
, mti
->length
, 2);
2920 flags
= windres_get_16 (&wrtarget
, mti
->flags
, 2);
2921 if ((offset
+ elen
) > length
)
2926 wr_printcomment (e
, "MessageId = 0x%x", low
);
2927 wr_printcomment (e
, "");
2928 if ((flags
& MESSAGE_RESOURCE_UNICODE
) == MESSAGE_RESOURCE_UNICODE
)
2929 unicode_print (e
, (const unichar
*) mti
->data
,
2930 (elen
- BIN_MESSAGETABLE_ITEM_SIZE
) / 2);
2932 ascii_print (e
, (const char *) mti
->data
,
2933 (elen
- BIN_MESSAGETABLE_ITEM_SIZE
));
2934 wr_printcomment (e
,"");
2941 wr_printcomment (e
, "Illegal data");
2943 fprintf (e
, "END\n");
2947 write_rc_datablock (FILE *e
, rc_uint_type length
, const bfd_byte
*data
, int has_next
,
2948 int hasblock
, int show_comment
)
2953 fprintf (e
, "BEGIN\n");
2955 if (show_comment
== -1)
2957 if (test_rc_datablock_text(length
, data
))
2960 for (i
= 0; i
< length
;)
2965 for (c
= 0; i
< length
&& c
< 160 && data
[i
] != '\n'; c
++, i
++)
2967 if (i
< length
&& data
[i
] == '\n')
2969 ascii_print (e
, (const char *) &data
[i
- c
], c
);
2978 fprintf (e
, "\"\"");
2984 fprintf (e
, "END\n");
2987 if (test_rc_datablock_unicode (length
, data
))
2990 for (i
= 0; i
< length
;)
2994 u
= (const unichar
*) &data
[i
];
2998 for (c
= 0; i
< length
&& c
< 160 && u
[c
] != '\n'; c
++, i
+= 2)
3000 if (i
< length
&& u
[c
] == '\n')
3002 unicode_print (e
, u
, c
);
3011 fprintf (e
, "L\"\"");
3017 fprintf (e
, "END\n");
3026 rc_uint_type i
, max_row
;
3029 max_row
= (show_comment
? 4 : 8);
3031 for (i
= 0; i
+ 3 < length
;)
3034 rc_uint_type comment_start
;
3041 for (k
= 0; k
< max_row
&& i
+ 3 < length
; k
++, i
+= 4)
3044 plen
= fprintf (e
, "0x%lxL",
3045 (long) windres_get_32 (&wrtarget
, data
+ i
, length
- i
));
3047 plen
= fprintf (e
, " 0x%lxL",
3048 (long) windres_get_32 (&wrtarget
, data
+ i
, length
- i
)) - 1;
3049 if (has_next
|| (i
+ 4) < length
)
3051 if (plen
>0 && plen
< 11)
3052 indent (e
, 11 - plen
);
3058 fprintf (e
, "\t/* ");
3059 ascii_print (e
, (const char *) &data
[comment_start
], i
- comment_start
);
3060 fprintf (e
, ". */");
3070 plen
= fprintf (e
, "0x%x",
3071 (int) windres_get_16 (&wrtarget
, data
+ i
, length
- i
));
3072 if (has_next
|| i
+ 2 < length
)
3074 if (plen
> 0 && plen
< 11)
3075 indent (e
, 11 - plen
);
3080 fprintf (e
, "\t/* ");
3081 ascii_print (e
, (const char *) &data
[i
], 2);
3082 fprintf (e
, ". */");
3094 ascii_print (e
, (const char *) &data
[i
], 1);
3103 fprintf (e
, "END\n");
3106 /* Write out an rcdata resource. This is also used for other types of
3107 resources that need to print arbitrary data. */
3110 write_rc_rcdata (FILE *e
, const rc_rcdata_item
*rcdata
, int ind
)
3112 const rc_rcdata_item
*ri
;
3115 fprintf (e
, "BEGIN\n");
3117 for (ri
= rcdata
; ri
!= NULL
; ri
= ri
->next
)
3119 if (ri
->type
== RCDATA_BUFFER
&& ri
->u
.buffer
.length
== 0)
3128 indent (e
, ind
+ 2);
3129 fprintf (e
, "%ld", (long) (ri
->u
.word
& 0xffff));
3133 indent (e
, ind
+ 2);
3134 fprintf (e
, "%luL", (unsigned long) ri
->u
.dword
);
3138 indent (e
, ind
+ 2);
3140 ascii_print (e
, ri
->u
.string
.s
, ri
->u
.string
.length
);
3144 case RCDATA_WSTRING
:
3145 indent (e
, ind
+ 2);
3147 unicode_print (e
, ri
->u
.wstring
.w
, ri
->u
.wstring
.length
);
3152 write_rc_datablock (e
, (rc_uint_type
) ri
->u
.buffer
.length
,
3153 (const bfd_byte
*) ri
->u
.buffer
.data
,
3154 ri
->next
!= NULL
, 0, -1);
3158 if (ri
->type
!= RCDATA_BUFFER
)
3160 if (ri
->next
!= NULL
)
3167 fprintf (e
, "END\n");
3170 /* Write out a stringtable resource. */
3173 write_rc_stringtable (FILE *e
, const rc_res_id
*name
,
3174 const rc_stringtable
*stringtable
)
3176 rc_uint_type offset
;
3179 if (name
!= NULL
&& ! name
->named
)
3180 offset
= (name
->u
.id
- 1) << 4;
3183 fprintf (e
, "/* %s string table name. */\n",
3184 name
== NULL
? "Missing" : "Invalid");
3188 fprintf (e
, "BEGIN\n");
3190 for (i
= 0; i
< 16; i
++)
3192 if (stringtable
->strings
[i
].length
!= 0)
3194 fprintf (e
, " %lu, ", (long) offset
+ i
);
3195 unicode_print_quoted (e
, stringtable
->strings
[i
].string
,
3196 stringtable
->strings
[i
].length
);
3201 fprintf (e
, "END\n");
3204 /* Write out a versioninfo resource. */
3207 write_rc_versioninfo (FILE *e
, const rc_versioninfo
*versioninfo
)
3209 const rc_fixed_versioninfo
*f
;
3210 const rc_ver_info
*vi
;
3212 f
= versioninfo
->fixed
;
3213 if (f
->file_version_ms
!= 0 || f
->file_version_ls
!= 0)
3214 fprintf (e
, " FILEVERSION %u, %u, %u, %u\n",
3215 (unsigned int) ((f
->file_version_ms
>> 16) & 0xffff),
3216 (unsigned int) (f
->file_version_ms
& 0xffff),
3217 (unsigned int) ((f
->file_version_ls
>> 16) & 0xffff),
3218 (unsigned int) (f
->file_version_ls
& 0xffff));
3219 if (f
->product_version_ms
!= 0 || f
->product_version_ls
!= 0)
3220 fprintf (e
, " PRODUCTVERSION %u, %u, %u, %u\n",
3221 (unsigned int) ((f
->product_version_ms
>> 16) & 0xffff),
3222 (unsigned int) (f
->product_version_ms
& 0xffff),
3223 (unsigned int) ((f
->product_version_ls
>> 16) & 0xffff),
3224 (unsigned int) (f
->product_version_ls
& 0xffff));
3225 if (f
->file_flags_mask
!= 0)
3226 fprintf (e
, " FILEFLAGSMASK 0x%x\n", (unsigned int) f
->file_flags_mask
);
3227 if (f
->file_flags
!= 0)
3228 fprintf (e
, " FILEFLAGS 0x%x\n", (unsigned int) f
->file_flags
);
3229 if (f
->file_os
!= 0)
3230 fprintf (e
, " FILEOS 0x%x\n", (unsigned int) f
->file_os
);
3231 if (f
->file_type
!= 0)
3232 fprintf (e
, " FILETYPE 0x%x\n", (unsigned int) f
->file_type
);
3233 if (f
->file_subtype
!= 0)
3234 fprintf (e
, " FILESUBTYPE 0x%x\n", (unsigned int) f
->file_subtype
);
3235 if (f
->file_date_ms
!= 0 || f
->file_date_ls
!= 0)
3236 fprintf (e
, "/* Date: %u, %u. */\n",
3237 (unsigned int) f
->file_date_ms
, (unsigned int) f
->file_date_ls
);
3239 fprintf (e
, "BEGIN\n");
3241 for (vi
= versioninfo
->var
; vi
!= NULL
; vi
= vi
->next
)
3245 case VERINFO_STRING
:
3247 const rc_ver_stringinfo
*vs
;
3249 fprintf (e
, " BLOCK \"StringFileInfo\"\n");
3250 fprintf (e
, " BEGIN\n");
3251 fprintf (e
, " BLOCK ");
3252 unicode_print_quoted (e
, vi
->u
.string
.language
, -1);
3254 fprintf (e
, " BEGIN\n");
3256 for (vs
= vi
->u
.string
.strings
; vs
!= NULL
; vs
= vs
->next
)
3258 fprintf (e
, " VALUE ");
3259 unicode_print_quoted (e
, vs
->key
, -1);
3261 unicode_print_quoted (e
, vs
->value
, -1);
3265 fprintf (e
, " END\n");
3266 fprintf (e
, " END\n");
3272 const rc_ver_varinfo
*vv
;
3274 fprintf (e
, " BLOCK \"VarFileInfo\"\n");
3275 fprintf (e
, " BEGIN\n");
3276 fprintf (e
, " VALUE ");
3277 unicode_print_quoted (e
, vi
->u
.var
.key
, -1);
3279 for (vv
= vi
->u
.var
.var
; vv
!= NULL
; vv
= vv
->next
)
3280 fprintf (e
, ", 0x%x, %d", (unsigned int) vv
->language
,
3283 fprintf (e
, "\n END\n");
3290 fprintf (e
, "END\n");
3294 rcdata_copy (const rc_rcdata_item
*src
, bfd_byte
*dst
)
3302 windres_put_16 (&wrtarget
, dst
, (rc_uint_type
) src
->u
.word
);
3306 windres_put_32 (&wrtarget
, dst
, (rc_uint_type
) src
->u
.dword
);
3309 if (dst
&& src
->u
.string
.length
)
3310 memcpy (dst
, src
->u
.string
.s
, src
->u
.string
.length
);
3311 return (rc_uint_type
) src
->u
.string
.length
;
3312 case RCDATA_WSTRING
:
3313 if (dst
&& src
->u
.wstring
.length
)
3314 memcpy (dst
, src
->u
.wstring
.w
, src
->u
.wstring
.length
* sizeof (unichar
));
3315 return (rc_uint_type
) (src
->u
.wstring
.length
* sizeof (unichar
));
3317 if (dst
&& src
->u
.buffer
.length
)
3318 memcpy (dst
, src
->u
.buffer
.data
, src
->u
.buffer
.length
);
3319 return (rc_uint_type
) src
->u
.buffer
.length
;
3323 /* Never reached. */