1 /* resrc.c -- read and write Windows rc files.
2 Copyright (C) 1997-2023 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 strcpy (cmd
, prefix
);
388 sprintf (cmd
+ end_prefix
, "%s", 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 char *cmd_copy
= xmalloc (strlen (cmd
));
413 strcpy (cmd_copy
, cmd
);
414 sprintf (cmd
, "\"%s\"", cmd_copy
);
418 sprintf (cmd
+ strlen (cmd
), " %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 if (filename
[0] == '/'
445 || filename
[0] == '\\'
446 || filename
[1] == ':')
448 edit
= dir
= xstrdup (filename
);
452 edit
= dir
= xmalloc (strlen (filename
) + 3);
453 sprintf (dir
, "./%s", filename
);
456 /* Walk dir backwards stopping at the first directory separator. */
457 edit
+= strlen (dir
);
458 while (edit
> dir
&& (edit
[-1] != '\\' && edit
[-1] != '/'))
464 /* Cut off trailing slash. */
468 /* Convert all back slashes to forward slashes. */
469 while ((edit
= strchr (dir
, '\\')) != NULL
)
472 windres_add_include_dir (dir
);
475 istream_type
= (use_temp_file
) ? ISTREAM_FILE
: ISTREAM_PIPE
;
477 if (preprocargs
== NULL
)
482 cmd
= xmalloc (strlen (preprocessor
)
483 + strlen (preprocargs
)
485 + strlen (fnquotes
) * 2
487 sprintf (cmd
, "%s %s %s%s%s", preprocessor
, preprocargs
,
488 fnquotes
, filename
, fnquotes
);
490 cpp_pipe
= open_input_stream (cmd
);
494 char *dash
, *slash
, *cp
;
496 cmd
= xmalloc (strlen (program_name
)
497 + strlen (DEFAULT_PREPROCESSOR_CMD
)
498 + strlen (DEFAULT_PREPROCESSOR_ARGS
)
499 + strlen (preprocargs
)
501 + strlen (fnquotes
) * 2
502 #ifdef HAVE_EXECUTABLE_SUFFIX
503 + strlen (EXECUTABLE_SUFFIX
)
509 for (cp
= program_name
; *cp
; cp
++)
514 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
515 *cp
== ':' || *cp
== '\\' ||
528 /* First, try looking for a prefixed gcc in the windres
529 directory, with the same prefix as windres */
531 cpp_pipe
= look_for_default (cmd
, program_name
, dash
- program_name
+ 1,
532 preprocargs
, filename
);
535 if (slash
&& ! cpp_pipe
)
537 /* Next, try looking for a gcc in the same directory as
540 cpp_pipe
= look_for_default (cmd
, program_name
, slash
- program_name
+ 1,
541 preprocargs
, filename
);
546 /* Sigh, try the default */
548 cpp_pipe
= look_for_default (cmd
, "", 0, preprocargs
, filename
);
555 rc_filename
= xstrdup (filename
);
558 rcparse_set_language (language
);
560 rcparse_discard_strings ();
562 close_input_stream ();
564 if (fontdirs
!= NULL
)
573 /* Close the input stream if it is open. */
576 close_input_stream (void)
578 if (istream_type
== ISTREAM_FILE
)
580 if (cpp_pipe
!= NULL
)
583 if (cpp_temp_file
!= NULL
)
585 int errno_save
= errno
;
587 unlink (cpp_temp_file
);
589 free (cpp_temp_file
);
594 if (cpp_pipe
!= NULL
)
597 err
= pclose (cpp_pipe
);
598 /* We are reading from a pipe, therefore we don't
599 know if cpp failed or succeeded until pclose. */
600 if (err
!= 0 || errno
== ECHILD
)
602 /* Since this is also run via xatexit, safeguard. */
604 cpp_temp_file
= NULL
;
605 fatal (_("preprocessing failed."));
610 /* Since this is also run via xatexit, safeguard. */
612 cpp_temp_file
= NULL
;
615 /* Report an error while reading an rc file. */
618 yyerror (const char *msg
)
620 fatal ("%s:%d: %s", rc_filename
, rc_lineno
, msg
);
623 /* Issue a warning while reading an rc file. */
626 rcparse_warning (const char *msg
)
628 fprintf (stderr
, "%s:%d: %s\n", rc_filename
, rc_lineno
, msg
);
631 /* Die if we get an unexpected end of file. */
634 unexpected_eof (const char *msg
)
636 fatal (_("%s: unexpected EOF"), msg
);
639 /* Read a 16 bit word from a file. The data is assumed to be little
643 get_word (FILE *e
, const char *msg
)
650 unexpected_eof (msg
);
651 return ((b2
& 0xff) << 8) | (b1
& 0xff);
654 /* Read a 32 bit word from a file. The data is assumed to be little
658 get_long (FILE *e
, const char *msg
)
667 unexpected_eof (msg
);
668 return (((((((b4
& 0xff) << 8)
674 /* Read data from a file. This is a wrapper to do error checking. */
677 get_data (FILE *e
, bfd_byte
*p
, rc_uint_type c
, const char *msg
)
679 rc_uint_type got
; /* $$$d */
681 got
= (rc_uint_type
) fread (p
, 1, c
, e
);
685 fatal (_("%s: read of %lu returned %lu"),
686 msg
, (unsigned long) c
, (unsigned long) got
);
689 /* Define an accelerator resource. */
692 define_accelerator (rc_res_id id
, const rc_res_res_info
*resinfo
,
693 rc_accelerator
*data
)
697 r
= define_standard_resource (&resources
, RT_ACCELERATOR
, id
,
698 resinfo
->language
, 0);
699 r
->type
= RES_TYPE_ACCELERATOR
;
701 r
->res_info
= *resinfo
;
704 /* Define a bitmap resource. Bitmap data is stored in a file. The
705 first 14 bytes of the file are a standard header, which is not
706 included in the resource data. */
708 #define BITMAP_SKIP (14)
711 define_bitmap (rc_res_id id
, const rc_res_res_info
*resinfo
,
712 const char *filename
)
721 e
= open_file_search (filename
, FOPEN_RB
, "bitmap file", &real_filename
);
723 if (stat (real_filename
, &s
) < 0)
724 fatal (_("stat failed on bitmap file `%s': %s"), real_filename
,
727 data
= (bfd_byte
*) res_alloc (s
.st_size
- BITMAP_SKIP
);
729 for (i
= 0; i
< BITMAP_SKIP
; i
++)
732 get_data (e
, data
, s
.st_size
- BITMAP_SKIP
, real_filename
);
735 free (real_filename
);
737 r
= define_standard_resource (&resources
, RT_BITMAP
, id
,
738 resinfo
->language
, 0);
740 r
->type
= RES_TYPE_BITMAP
;
741 r
->u
.data
.length
= s
.st_size
- BITMAP_SKIP
;
742 r
->u
.data
.data
= data
;
743 r
->res_info
= *resinfo
;
746 /* Define a cursor resource. A cursor file may contain a set of
747 bitmaps, each representing the same cursor at various different
748 resolutions. They each get written out with a different ID. The
749 real cursor resource is then a group resource which can be used to
750 select one of the actual cursors. */
753 define_cursor (rc_res_id id
, const rc_res_res_info
*resinfo
,
754 const char *filename
)
759 struct icondir
*icondirs
;
762 rc_group_cursor
*first
, **pp
;
764 e
= open_file_search (filename
, FOPEN_RB
, "cursor file", &real_filename
);
766 /* A cursor file is basically an icon file. The start of the file
767 is a three word structure. The first word is ignored. The
768 second word is the type of data. The third word is the number of
771 get_word (e
, real_filename
);
772 type
= get_word (e
, real_filename
);
773 count
= get_word (e
, real_filename
);
775 fatal (_("cursor file `%s' does not contain cursor data"), real_filename
);
777 /* Read in the icon directory entries. */
779 icondirs
= (struct icondir
*) xmalloc (count
* sizeof *icondirs
);
781 for (i
= 0; i
< count
; i
++)
783 icondirs
[i
].width
= getc (e
);
784 icondirs
[i
].height
= getc (e
);
785 icondirs
[i
].colorcount
= getc (e
);
787 icondirs
[i
].u
.cursor
.xhotspot
= get_word (e
, real_filename
);
788 icondirs
[i
].u
.cursor
.yhotspot
= get_word (e
, real_filename
);
789 icondirs
[i
].bytes
= get_long (e
, real_filename
);
790 icondirs
[i
].offset
= get_long (e
, real_filename
);
793 unexpected_eof (real_filename
);
796 /* Define each cursor as a unique resource. */
798 first_cursor
= cursors
;
800 for (i
= 0; i
< count
; i
++)
806 if (fseek (e
, icondirs
[i
].offset
, SEEK_SET
) != 0)
807 fatal (_("%s: fseek to %lu failed: %s"), real_filename
,
808 icondirs
[i
].offset
, strerror (errno
));
810 data
= (bfd_byte
*) res_alloc (icondirs
[i
].bytes
);
812 get_data (e
, data
, icondirs
[i
].bytes
, real_filename
);
814 c
= (rc_cursor
*) res_alloc (sizeof (rc_cursor
));
815 c
->xhotspot
= icondirs
[i
].u
.cursor
.xhotspot
;
816 c
->yhotspot
= icondirs
[i
].u
.cursor
.yhotspot
;
817 c
->length
= icondirs
[i
].bytes
;
825 r
= define_standard_resource (&resources
, RT_CURSOR
, name
,
826 resinfo
->language
, 0);
827 r
->type
= RES_TYPE_CURSOR
;
829 r
->res_info
= *resinfo
;
833 free (real_filename
);
835 /* Define a cursor group resource. */
839 for (i
= 0; i
< count
; i
++)
843 cg
= (rc_group_cursor
*) res_alloc (sizeof (rc_group_cursor
));
845 cg
->width
= icondirs
[i
].width
;
846 cg
->height
= 2 * icondirs
[i
].height
;
848 /* FIXME: What should these be set to? */
852 cg
->bytes
= icondirs
[i
].bytes
+ 4;
853 cg
->index
= first_cursor
+ i
+ 1;
861 r
= define_standard_resource (&resources
, RT_GROUP_CURSOR
, id
,
862 resinfo
->language
, 0);
863 r
->type
= RES_TYPE_GROUP_CURSOR
;
864 r
->u
.group_cursor
= first
;
865 r
->res_info
= *resinfo
;
868 /* Define a dialog resource. */
871 define_dialog (rc_res_id id
, const rc_res_res_info
*resinfo
,
872 const rc_dialog
*dialog
)
877 copy
= (rc_dialog
*) res_alloc (sizeof *copy
);
880 r
= define_standard_resource (&resources
, RT_DIALOG
, id
,
881 resinfo
->language
, 0);
882 r
->type
= RES_TYPE_DIALOG
;
884 r
->res_info
= *resinfo
;
887 /* Define a dialog control. This does not define a resource, but
888 merely allocates and fills in a structure. */
891 define_control (const rc_res_id iid
, rc_uint_type id
, rc_uint_type x
,
892 rc_uint_type y
, rc_uint_type width
, rc_uint_type height
,
893 const rc_res_id
class, rc_uint_type style
,
894 rc_uint_type exstyle
)
896 rc_dialog_control
*n
;
898 n
= (rc_dialog_control
*) res_alloc (sizeof (rc_dialog_control
));
902 n
->exstyle
= exstyle
;
916 define_icon_control (rc_res_id iid
, rc_uint_type id
, rc_uint_type x
,
917 rc_uint_type y
, rc_uint_type style
,
918 rc_uint_type exstyle
, rc_uint_type help
,
919 rc_rcdata_item
*data
, rc_dialog_ex
*ex
)
921 rc_dialog_control
*n
;
926 style
= SS_ICON
| WS_CHILD
| WS_VISIBLE
;
927 res_string_to_id (&tid
, "");
929 cid
.u
.id
= CTL_STATIC
;
930 n
= define_control (tid
, id
, x
, y
, 0, 0, cid
, style
, exstyle
);
933 rcparse_warning (_("help ID requires DIALOGEX"));
935 rcparse_warning (_("control data requires DIALOGEX"));
942 /* Define a font resource. */
945 define_font (rc_res_id id
, const rc_res_res_info
*resinfo
,
946 const char *filename
)
957 const char *device
, *face
;
960 e
= open_file_search (filename
, FOPEN_RB
, "font file", &real_filename
);
962 if (stat (real_filename
, &s
) < 0)
963 fatal (_("stat failed on font file `%s': %s"), real_filename
,
966 data
= (bfd_byte
*) res_alloc (s
.st_size
);
968 get_data (e
, data
, s
.st_size
, real_filename
);
971 free (real_filename
);
973 r
= define_standard_resource (&resources
, RT_FONT
, id
,
974 resinfo
->language
, 0);
976 r
->type
= RES_TYPE_FONT
;
977 r
->u
.data
.length
= s
.st_size
;
978 r
->u
.data
.data
= data
;
979 r
->res_info
= *resinfo
;
981 /* For each font resource, we must add an entry in the FONTDIR
982 resource. The FONTDIR resource includes some strings in the font
983 file. To find them, we have to do some magic on the data we have
986 offset
= ((((((data
[47] << 8)
990 if (offset
> 0 && offset
< s
.st_size
)
991 device
= (char *) data
+ offset
;
995 offset
= ((((((data
[51] << 8)
999 if (offset
> 0 && offset
< s
.st_size
)
1000 face
= (char *) data
+ offset
;
1006 fontdatalength
= 58 + strlen (device
) + strlen (face
);
1007 fontdata
= (bfd_byte
*) res_alloc (fontdatalength
);
1008 memcpy (fontdata
, data
, 56);
1009 strcpy ((char *) fontdata
+ 56, device
);
1010 strcpy ((char *) fontdata
+ 57 + strlen (device
), face
);
1012 fd
= (rc_fontdir
*) res_alloc (sizeof (rc_fontdir
));
1015 fd
->length
= fontdatalength
;
1016 fd
->data
= fontdata
;
1018 for (pp
= &fontdirs
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1022 /* For the single fontdirs resource, we always use the resource
1023 information of the last font. I don't know what else to do. */
1024 fontdirs_resinfo
= *resinfo
;
1028 define_font_rcdata (rc_res_id id
,const rc_res_res_info
*resinfo
,
1029 rc_rcdata_item
*data
)
1032 rc_uint_type len_data
;
1035 r
= define_standard_resource (&resources
, RT_FONT
, id
,
1036 resinfo
->language
, 0);
1038 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1040 r
->type
= RES_TYPE_FONT
;
1041 r
->u
.data
.length
= len_data
;
1042 r
->u
.data
.data
= pb_data
;
1043 r
->res_info
= *resinfo
;
1046 /* Define the fontdirs resource. This is called after the entire rc
1047 file has been parsed, if any font resources were seen. */
1050 define_fontdirs (void)
1058 r
= define_standard_resource (&resources
, RT_FONTDIR
, id
, 0x409, 0);
1060 r
->type
= RES_TYPE_FONTDIR
;
1061 r
->u
.fontdir
= fontdirs
;
1062 r
->res_info
= fontdirs_resinfo
;
1066 rcdata_render_as_buffer (const rc_rcdata_item
*data
, rc_uint_type
*plen
)
1068 const rc_rcdata_item
*d
;
1069 bfd_byte
*ret
= NULL
, *pret
;
1070 rc_uint_type len
= 0;
1072 for (d
= data
; d
!= NULL
; d
= d
->next
)
1073 len
+= rcdata_copy (d
, NULL
);
1076 ret
= pret
= (bfd_byte
*) res_alloc (len
);
1077 for (d
= data
; d
!= NULL
; d
= d
->next
)
1078 pret
+= rcdata_copy (d
, pret
);
1086 define_fontdir_rcdata (rc_res_id id
,const rc_res_res_info
*resinfo
,
1087 rc_rcdata_item
*data
)
1090 rc_fontdir
*fd
, *fd_first
, *fd_cur
;
1091 rc_uint_type len_data
;
1095 fd_cur
= fd_first
= NULL
;
1096 r
= define_standard_resource (&resources
, RT_FONTDIR
, id
, 0x409, 0);
1098 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1102 rc_uint_type off
= 2;
1103 c
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1107 rc_uint_type safe_pos
= off
;
1108 const struct bin_fontdir_item
*bfi
;
1110 bfi
= (const struct bin_fontdir_item
*) pb_data
+ off
;
1111 fd
= (rc_fontdir
*) res_alloc (sizeof (rc_fontdir
));
1112 fd
->index
= windres_get_16 (&wrtarget
, bfi
->index
, len_data
- off
);
1113 fd
->data
= pb_data
+ off
;
1115 len
= strlen ((char *) bfi
->device_name
) + 1;
1116 off
+= (rc_uint_type
) len
;
1117 off
+= (rc_uint_type
) strlen ((char *) bfi
->device_name
+ len
) + 1;
1118 fd
->length
= (off
- safe_pos
);
1120 if (fd_first
== NULL
)
1127 r
->type
= RES_TYPE_FONTDIR
;
1128 r
->u
.fontdir
= fd_first
;
1129 r
->res_info
= *resinfo
;
1132 static void define_messagetable_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1133 rc_rcdata_item
*data
)
1136 rc_uint_type len_data
;
1139 r
= define_standard_resource (&resources
, RT_MESSAGETABLE
, id
, resinfo
->language
, 0);
1141 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1142 r
->type
= RES_TYPE_MESSAGETABLE
;
1143 r
->u
.data
.length
= len_data
;
1144 r
->u
.data
.data
= pb_data
;
1145 r
->res_info
= *resinfo
;
1148 /* Define an icon resource. An icon file may contain a set of
1149 bitmaps, each representing the same icon at various different
1150 resolutions. They each get written out with a different ID. The
1151 real icon resource is then a group resource which can be used to
1152 select one of the actual icon bitmaps. */
1155 define_icon (rc_res_id id
, const rc_res_res_info
*resinfo
,
1156 const char *filename
)
1159 char *real_filename
;
1161 struct icondir
*icondirs
;
1164 rc_group_icon
*first
, **pp
;
1166 e
= open_file_search (filename
, FOPEN_RB
, "icon file", &real_filename
);
1168 /* The start of an icon file is a three word structure. The first
1169 word is ignored. The second word is the type of data. The third
1170 word is the number of entries. */
1172 get_word (e
, real_filename
);
1173 type
= get_word (e
, real_filename
);
1174 count
= get_word (e
, real_filename
);
1176 fatal (_("icon file `%s' does not contain icon data"), real_filename
);
1178 /* Read in the icon directory entries. */
1180 icondirs
= (struct icondir
*) xmalloc (count
* sizeof *icondirs
);
1182 for (i
= 0; i
< count
; i
++)
1184 icondirs
[i
].width
= getc (e
);
1185 icondirs
[i
].height
= getc (e
);
1186 icondirs
[i
].colorcount
= getc (e
);
1188 icondirs
[i
].u
.icon
.planes
= get_word (e
, real_filename
);
1189 icondirs
[i
].u
.icon
.bits
= get_word (e
, real_filename
);
1190 icondirs
[i
].bytes
= get_long (e
, real_filename
);
1191 icondirs
[i
].offset
= get_long (e
, real_filename
);
1194 unexpected_eof (real_filename
);
1197 /* Define each icon as a unique resource. */
1201 for (i
= 0; i
< count
; i
++)
1206 if (fseek (e
, icondirs
[i
].offset
, SEEK_SET
) != 0)
1207 fatal (_("%s: fseek to %lu failed: %s"), real_filename
,
1208 icondirs
[i
].offset
, strerror (errno
));
1210 data
= (bfd_byte
*) res_alloc (icondirs
[i
].bytes
);
1212 get_data (e
, data
, icondirs
[i
].bytes
, real_filename
);
1219 r
= define_standard_resource (&resources
, RT_ICON
, name
,
1220 resinfo
->language
, 0);
1221 r
->type
= RES_TYPE_ICON
;
1222 r
->u
.data
.length
= icondirs
[i
].bytes
;
1223 r
->u
.data
.data
= data
;
1224 r
->res_info
= *resinfo
;
1228 free (real_filename
);
1230 /* Define an icon group resource. */
1234 for (i
= 0; i
< count
; i
++)
1238 /* For some reason, at least in some files the planes and bits
1239 are zero. We instead set them from the color. This is
1242 cg
= (rc_group_icon
*) res_alloc (sizeof (rc_group_icon
));
1244 cg
->width
= icondirs
[i
].width
;
1245 cg
->height
= icondirs
[i
].height
;
1246 cg
->colors
= icondirs
[i
].colorcount
;
1248 if (icondirs
[i
].u
.icon
.planes
)
1249 cg
->planes
= icondirs
[i
].u
.icon
.planes
;
1253 if (icondirs
[i
].u
.icon
.bits
)
1254 cg
->bits
= icondirs
[i
].u
.icon
.bits
;
1259 while ((1L << cg
->bits
) < cg
->colors
)
1263 cg
->bytes
= icondirs
[i
].bytes
;
1264 cg
->index
= first_icon
+ i
+ 1;
1272 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1273 resinfo
->language
, 0);
1274 r
->type
= RES_TYPE_GROUP_ICON
;
1275 r
->u
.group_icon
= first
;
1276 r
->res_info
= *resinfo
;
1280 define_group_icon_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1281 rc_rcdata_item
*data
)
1284 rc_group_icon
*cg
, *first
, *cur
;
1285 rc_uint_type len_data
;
1288 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1293 while (len_data
>= 6)
1296 unsigned short type
;
1297 type
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1299 fatal (_("unexpected group icon type %d"), type
);
1300 c
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1304 for (i
= 0; i
< c
; i
++)
1307 fatal ("too small group icon rcdata");
1308 cg
= (rc_group_icon
*) res_alloc (sizeof (rc_group_icon
));
1310 cg
->width
= pb_data
[0];
1311 cg
->height
= pb_data
[1];
1312 cg
->colors
= pb_data
[2];
1313 cg
->planes
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1314 cg
->bits
= windres_get_16 (&wrtarget
, pb_data
+ 6, len_data
- 6);
1315 cg
->bytes
= windres_get_32 (&wrtarget
, pb_data
+ 8, len_data
- 8);
1316 cg
->index
= windres_get_16 (&wrtarget
, pb_data
+ 12, len_data
- 12);
1326 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1327 resinfo
->language
, 0);
1328 r
->type
= RES_TYPE_GROUP_ICON
;
1329 r
->u
.group_icon
= first
;
1330 r
->res_info
= *resinfo
;
1334 define_group_cursor_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1335 rc_rcdata_item
*data
)
1338 rc_group_cursor
*cg
, *first
, *cur
;
1339 rc_uint_type len_data
;
1342 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1346 while (len_data
>= 6)
1349 unsigned short type
;
1350 type
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1352 fatal (_("unexpected group cursor type %d"), type
);
1353 c
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1357 for (i
= 0; i
< c
; i
++)
1360 fatal ("too small group icon rcdata");
1361 cg
= (rc_group_cursor
*) res_alloc (sizeof (rc_group_cursor
));
1363 cg
->width
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1364 cg
->height
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1365 cg
->planes
= windres_get_16 (&wrtarget
, pb_data
+ 4, len_data
- 4);
1366 cg
->bits
= windres_get_16 (&wrtarget
, pb_data
+ 6, len_data
- 6);
1367 cg
->bytes
= windres_get_32 (&wrtarget
, pb_data
+ 8, len_data
- 8);
1368 cg
->index
= windres_get_16 (&wrtarget
, pb_data
+ 12, len_data
- 12);
1379 r
= define_standard_resource (&resources
, RT_GROUP_ICON
, id
,
1380 resinfo
->language
, 0);
1381 r
->type
= RES_TYPE_GROUP_CURSOR
;
1382 r
->u
.group_cursor
= first
;
1383 r
->res_info
= *resinfo
;
1387 define_cursor_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1388 rc_rcdata_item
*data
)
1392 rc_uint_type len_data
;
1395 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1397 c
= (rc_cursor
*) res_alloc (sizeof (rc_cursor
));
1398 c
->xhotspot
= windres_get_16 (&wrtarget
, pb_data
, len_data
);
1399 c
->yhotspot
= windres_get_16 (&wrtarget
, pb_data
+ 2, len_data
- 2);
1400 c
->length
= len_data
- BIN_CURSOR_SIZE
;
1401 c
->data
= (const bfd_byte
*) (data
+ BIN_CURSOR_SIZE
);
1403 r
= define_standard_resource (&resources
, RT_CURSOR
, id
, resinfo
->language
, 0);
1404 r
->type
= RES_TYPE_CURSOR
;
1406 r
->res_info
= *resinfo
;
1410 define_bitmap_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_BITMAP
, id
, resinfo
->language
, 0);
1420 r
->type
= RES_TYPE_BITMAP
;
1421 r
->u
.data
.length
= len_data
;
1422 r
->u
.data
.data
= pb_data
;
1423 r
->res_info
= *resinfo
;
1427 define_icon_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1428 rc_rcdata_item
*data
)
1431 rc_uint_type len_data
;
1434 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1436 r
= define_standard_resource (&resources
, RT_ICON
, id
, resinfo
->language
, 0);
1437 r
->type
= RES_TYPE_ICON
;
1438 r
->u
.data
.length
= len_data
;
1439 r
->u
.data
.data
= pb_data
;
1440 r
->res_info
= *resinfo
;
1443 /* Define a menu resource. */
1446 define_menu (rc_res_id id
, const rc_res_res_info
*resinfo
,
1447 rc_menuitem
*menuitems
)
1452 m
= (rc_menu
*) res_alloc (sizeof (rc_menu
));
1453 m
->items
= menuitems
;
1456 r
= define_standard_resource (&resources
, RT_MENU
, id
, resinfo
->language
, 0);
1457 r
->type
= RES_TYPE_MENU
;
1459 r
->res_info
= *resinfo
;
1462 /* Define a menu item. This does not define a resource, but merely
1463 allocates and fills in a structure. */
1466 define_menuitem (const unichar
*text
, rc_uint_type menuid
, rc_uint_type type
,
1467 rc_uint_type state
, rc_uint_type help
,
1468 rc_menuitem
*menuitems
)
1472 mi
= (rc_menuitem
*) res_alloc (sizeof (rc_menuitem
));
1477 mi
->text
= unichar_dup (text
);
1479 mi
->popup
= menuitems
;
1483 /* Define a messagetable resource. */
1486 define_messagetable (rc_res_id id
, const rc_res_res_info
*resinfo
,
1487 const char *filename
)
1490 char *real_filename
;
1495 e
= open_file_search (filename
, FOPEN_RB
, "messagetable file",
1498 if (stat (real_filename
, &s
) < 0)
1499 fatal (_("stat failed on bitmap file `%s': %s"), real_filename
,
1502 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1504 get_data (e
, data
, s
.st_size
, real_filename
);
1507 free (real_filename
);
1509 r
= define_standard_resource (&resources
, RT_MESSAGETABLE
, id
,
1510 resinfo
->language
, 0);
1512 r
->type
= RES_TYPE_MESSAGETABLE
;
1513 r
->u
.data
.length
= s
.st_size
;
1514 r
->u
.data
.data
= data
;
1515 r
->res_info
= *resinfo
;
1518 /* Define an rcdata resource. */
1521 define_rcdata (rc_res_id id
, const rc_res_res_info
*resinfo
,
1522 rc_rcdata_item
*data
)
1526 r
= define_standard_resource (&resources
, RT_RCDATA
, id
,
1527 resinfo
->language
, 0);
1528 r
->type
= RES_TYPE_RCDATA
;
1530 r
->res_info
= *resinfo
;
1533 /* Create an rcdata item holding a string. */
1536 define_rcdata_string (const char *string
, rc_uint_type len
)
1541 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1543 ri
->type
= RCDATA_STRING
;
1544 ri
->u
.string
.length
= len
;
1545 s
= (char *) res_alloc (len
);
1546 memcpy (s
, string
, len
);
1552 /* Create an rcdata item holding a unicode string. */
1555 define_rcdata_unistring (const unichar
*string
, rc_uint_type len
)
1560 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1562 ri
->type
= RCDATA_WSTRING
;
1563 ri
->u
.wstring
.length
= len
;
1564 s
= (unichar
*) res_alloc (len
* sizeof (unichar
));
1565 memcpy (s
, string
, len
* sizeof (unichar
));
1566 ri
->u
.wstring
.w
= s
;
1571 /* Create an rcdata item holding a number. */
1574 define_rcdata_number (rc_uint_type val
, int dword
)
1578 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1580 ri
->type
= dword
? RCDATA_DWORD
: RCDATA_WORD
;
1586 /* Define a stringtable resource. This is called for each string
1587 which appears in a STRINGTABLE statement. */
1590 define_stringtable (const rc_res_res_info
*resinfo
,
1591 rc_uint_type stringid
, const unichar
*string
, int len
)
1598 id
.u
.id
= (stringid
>> 4) + 1;
1599 r
= define_standard_resource (&resources
, RT_STRING
, id
,
1600 resinfo
->language
, 1);
1602 if (r
->type
== RES_TYPE_UNINITIALIZED
)
1606 r
->type
= RES_TYPE_STRINGTABLE
;
1607 r
->u
.stringtable
= ((rc_stringtable
*)
1608 res_alloc (sizeof (rc_stringtable
)));
1609 for (i
= 0; i
< 16; i
++)
1611 r
->u
.stringtable
->strings
[i
].length
= 0;
1612 r
->u
.stringtable
->strings
[i
].string
= NULL
;
1615 r
->res_info
= *resinfo
;
1617 h
= (unichar
*) res_alloc ((len
+ 1) * sizeof (unichar
));
1619 memcpy (h
, string
, len
* sizeof (unichar
));
1621 r
->u
.stringtable
->strings
[stringid
& 0xf].length
= (rc_uint_type
) len
;
1622 r
->u
.stringtable
->strings
[stringid
& 0xf].string
= h
;
1626 define_toolbar (rc_res_id id
, rc_res_res_info
*resinfo
, rc_uint_type width
, rc_uint_type height
,
1627 rc_toolbar_item
*items
)
1632 t
= (rc_toolbar
*) res_alloc (sizeof (rc_toolbar
));
1633 t
->button_width
= width
;
1634 t
->button_height
= height
;
1637 while (items
!= NULL
)
1640 items
= items
->next
;
1642 r
= define_standard_resource (&resources
, RT_TOOLBAR
, id
, resinfo
->language
, 0);
1643 r
->type
= RES_TYPE_TOOLBAR
;
1645 r
->res_info
= *resinfo
;
1648 /* Define a user data resource where the data is in the rc file. */
1651 define_user_data (rc_res_id id
, rc_res_id type
,
1652 const rc_res_res_info
*resinfo
,
1653 rc_rcdata_item
*data
)
1658 rc_uint_type len_data
;
1660 /* We have to check if the binary data is parsed specially. */
1661 if (type
.named
== 0)
1666 define_fontdir_rcdata (id
, resinfo
, data
);
1669 define_font_rcdata (id
, resinfo
, data
);
1672 define_icon_rcdata (id
, resinfo
, data
);
1675 define_bitmap_rcdata (id
, resinfo
, data
);
1678 define_cursor_rcdata (id
, resinfo
, data
);
1681 define_group_icon_rcdata (id
, resinfo
, data
);
1683 case RT_GROUP_CURSOR
:
1684 define_group_cursor_rcdata (id
, resinfo
, data
);
1686 case RT_MESSAGETABLE
:
1687 define_messagetable_rcdata (id
, resinfo
, data
);
1690 /* Treat as normal user-data. */
1697 ids
[2].u
.id
= resinfo
->language
;
1699 r
= define_resource (& resources
, 3, ids
, 0);
1700 r
->type
= RES_TYPE_USERDATA
;
1701 r
->u
.userdata
= ((rc_rcdata_item
*)
1702 res_alloc (sizeof (rc_rcdata_item
)));
1703 r
->u
.userdata
->next
= NULL
;
1704 r
->u
.userdata
->type
= RCDATA_BUFFER
;
1705 pb_data
= rcdata_render_as_buffer (data
, &len_data
);
1706 r
->u
.userdata
->u
.buffer
.length
= len_data
;
1707 r
->u
.userdata
->u
.buffer
.data
= pb_data
;
1708 r
->res_info
= *resinfo
;
1712 define_rcdata_file (rc_res_id id
, const rc_res_res_info
*resinfo
,
1713 const char *filename
)
1717 char *real_filename
;
1721 e
= open_file_search (filename
, FOPEN_RB
, "file", &real_filename
);
1724 if (stat (real_filename
, &s
) < 0)
1725 fatal (_("stat failed on file `%s': %s"), real_filename
,
1728 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1730 get_data (e
, data
, s
.st_size
, real_filename
);
1733 free (real_filename
);
1735 ri
= (rc_rcdata_item
*) res_alloc (sizeof (rc_rcdata_item
));
1737 ri
->type
= RCDATA_BUFFER
;
1738 ri
->u
.buffer
.length
= s
.st_size
;
1739 ri
->u
.buffer
.data
= data
;
1741 define_rcdata (id
, resinfo
, ri
);
1744 /* Define a user data resource where the data is in a file. */
1747 define_user_file (rc_res_id id
, rc_res_id type
,
1748 const rc_res_res_info
*resinfo
, const char *filename
)
1751 char *real_filename
;
1757 e
= open_file_search (filename
, FOPEN_RB
, "file", &real_filename
);
1759 if (stat (real_filename
, &s
) < 0)
1760 fatal (_("stat failed on file `%s': %s"), real_filename
,
1763 data
= (bfd_byte
*) res_alloc (s
.st_size
);
1765 get_data (e
, data
, s
.st_size
, real_filename
);
1768 free (real_filename
);
1773 ids
[2].u
.id
= resinfo
->language
;
1775 r
= define_resource (&resources
, 3, ids
, 0);
1776 r
->type
= RES_TYPE_USERDATA
;
1777 r
->u
.userdata
= ((rc_rcdata_item
*)
1778 res_alloc (sizeof (rc_rcdata_item
)));
1779 r
->u
.userdata
->next
= NULL
;
1780 r
->u
.userdata
->type
= RCDATA_BUFFER
;
1781 r
->u
.userdata
->u
.buffer
.length
= s
.st_size
;
1782 r
->u
.userdata
->u
.buffer
.data
= data
;
1783 r
->res_info
= *resinfo
;
1786 /* Define a versioninfo resource. */
1789 define_versioninfo (rc_res_id id
, rc_uint_type language
,
1790 rc_fixed_versioninfo
*fixedverinfo
,
1791 rc_ver_info
*verinfo
)
1795 r
= define_standard_resource (&resources
, RT_VERSION
, id
, language
, 0);
1796 r
->type
= RES_TYPE_VERSIONINFO
;
1797 r
->u
.versioninfo
= ((rc_versioninfo
*)
1798 res_alloc (sizeof (rc_versioninfo
)));
1799 r
->u
.versioninfo
->fixed
= fixedverinfo
;
1800 r
->u
.versioninfo
->var
= verinfo
;
1801 r
->res_info
.language
= language
;
1804 /* Add string version info to a list of version information. */
1807 append_ver_stringfileinfo (rc_ver_info
*verinfo
,
1808 rc_ver_stringtable
*stringtables
)
1810 rc_ver_info
*vi
, **pp
;
1812 vi
= (rc_ver_info
*) res_alloc (sizeof (rc_ver_info
));
1814 vi
->type
= VERINFO_STRING
;
1815 vi
->u
.string
.stringtables
= stringtables
;
1817 for (pp
= &verinfo
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1824 rc_ver_stringtable
*
1825 append_ver_stringtable (rc_ver_stringtable
*stringtable
,
1826 const char *language
,
1827 rc_ver_stringinfo
*strings
)
1829 rc_ver_stringtable
*vst
, **pp
;
1831 vst
= (rc_ver_stringtable
*) res_alloc (sizeof (rc_ver_stringtable
));
1833 unicode_from_ascii ((rc_uint_type
*) NULL
, &vst
->language
, language
);
1834 vst
->strings
= strings
;
1836 for (pp
= &stringtable
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1843 /* Add variable version info to a list of version information. */
1846 append_ver_varfileinfo (rc_ver_info
*verinfo
, const unichar
*key
,
1847 rc_ver_varinfo
*var
)
1849 rc_ver_info
*vi
, **pp
;
1851 vi
= (rc_ver_info
*) res_alloc (sizeof *vi
);
1853 vi
->type
= VERINFO_VAR
;
1854 vi
->u
.var
.key
= unichar_dup (key
);
1855 vi
->u
.var
.var
= var
;
1857 for (pp
= &verinfo
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1864 /* Append version string information to a list. */
1867 append_verval (rc_ver_stringinfo
*strings
, const unichar
*key
,
1868 const unichar
*value
)
1870 rc_ver_stringinfo
*vs
, **pp
;
1872 vs
= (rc_ver_stringinfo
*) res_alloc (sizeof (rc_ver_stringinfo
));
1874 vs
->key
= unichar_dup (key
);
1875 vs
->value
= unichar_dup (value
);
1877 for (pp
= &strings
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1884 /* Append version variable information to a list. */
1887 append_vertrans (rc_ver_varinfo
*var
, rc_uint_type language
,
1888 rc_uint_type charset
)
1890 rc_ver_varinfo
*vv
, **pp
;
1892 vv
= (rc_ver_varinfo
*) res_alloc (sizeof (rc_ver_varinfo
));
1894 vv
->language
= language
;
1895 vv
->charset
= charset
;
1897 for (pp
= &var
; *pp
!= NULL
; pp
= &(*pp
)->next
)
1904 /* Local functions used to write out an rc file. */
1906 static void indent (FILE *, int);
1907 static void write_rc_directory (FILE *, const rc_res_directory
*, const rc_res_id
*,
1908 const rc_res_id
*, rc_uint_type
*, int);
1909 static void write_rc_subdir (FILE *, const rc_res_entry
*, const rc_res_id
*,
1910 const rc_res_id
*, rc_uint_type
*, int);
1911 static void write_rc_resource (FILE *, const rc_res_id
*, const rc_res_id
*,
1912 const rc_res_resource
*, rc_uint_type
*);
1913 static void write_rc_accelerators (FILE *, const rc_accelerator
*);
1914 static void write_rc_cursor (FILE *, const rc_cursor
*);
1915 static void write_rc_group_cursor (FILE *, const rc_group_cursor
*);
1916 static void write_rc_dialog (FILE *, const rc_dialog
*);
1917 static void write_rc_dialog_control (FILE *, const rc_dialog_control
*);
1918 static void write_rc_fontdir (FILE *, const rc_fontdir
*);
1919 static void write_rc_group_icon (FILE *, const rc_group_icon
*);
1920 static void write_rc_menu (FILE *, const rc_menu
*, int);
1921 static void write_rc_toolbar (FILE *, const rc_toolbar
*);
1922 static void write_rc_menuitems (FILE *, const rc_menuitem
*, int, int);
1923 static void write_rc_messagetable (FILE *, rc_uint_type
, const bfd_byte
*);
1925 static void write_rc_datablock (FILE *, rc_uint_type
, const bfd_byte
*, int, int, int);
1926 static void write_rc_rcdata (FILE *, const rc_rcdata_item
*, int);
1927 static void write_rc_stringtable (FILE *, const rc_res_id
*, const rc_stringtable
*);
1928 static void write_rc_versioninfo (FILE *, const rc_versioninfo
*);
1930 /* Indent a given number of spaces. */
1933 indent (FILE *e
, int c
)
1937 for (i
= 0; i
< c
; i
++)
1941 /* Dump the resources we have read in the format of an rc file.
1943 Reasoned by the fact, that some resources need to be stored into file and
1944 refer to that file, we use the user-data model for that to express it binary
1945 without the need to store it somewhere externally. */
1948 write_rc_file (const char *filename
, const rc_res_directory
*res_dir
)
1951 rc_uint_type language
;
1953 if (filename
== NULL
)
1957 e
= fopen (filename
, FOPEN_WT
);
1959 fatal (_("can't open `%s' for output: %s"), filename
, strerror (errno
));
1962 language
= (rc_uint_type
) ((bfd_signed_vma
) -1);
1963 write_rc_directory (e
, res_dir
, (const rc_res_id
*) NULL
,
1964 (const rc_res_id
*) NULL
, &language
, 1);
1967 /* Write out a directory. E is the file to write to. RD is the
1968 directory. TYPE is a pointer to the level 1 ID which serves as the
1969 resource type. NAME is a pointer to the level 2 ID which serves as
1970 an individual resource name. LANGUAGE is a pointer to the current
1971 language. LEVEL is the level in the tree. */
1974 write_rc_directory (FILE *e
, const rc_res_directory
*rd
,
1975 const rc_res_id
*type
, const rc_res_id
*name
,
1976 rc_uint_type
*language
, int level
)
1978 const rc_res_entry
*re
;
1980 /* Print out some COFF information that rc files can't represent. */
1981 if (rd
->time
!= 0 || rd
->characteristics
!= 0 || rd
->major
!= 0 || rd
->minor
!= 0)
1983 wr_printcomment (e
, "COFF information not part of RC");
1985 wr_printcomment (e
, "Time stamp: %u", rd
->time
);
1986 if (rd
->characteristics
!= 0)
1987 wr_printcomment (e
, "Characteristics: %u", rd
->characteristics
);
1988 if (rd
->major
!= 0 || rd
->minor
!= 0)
1989 wr_printcomment (e
, "Version major:%d minor:%d", rd
->major
, rd
->minor
);
1992 for (re
= rd
->entries
; re
!= NULL
; re
= re
->next
)
1997 /* If we're at level 1, the key of this resource is the
1998 type. This normally duplicates the information we have
1999 stored with the resource itself, but we need to remember
2000 the type if this is a user define resource type. */
2005 /* If we're at level 2, the key of this resource is the name
2006 we are going to use in the rc printout. */
2011 /* If we're at level 3, then this key represents a language.
2012 Use it to update the current language. */
2014 && re
->id
.u
.id
!= (unsigned long) (unsigned int) *language
2015 && (re
->id
.u
.id
& 0xffff) == re
->id
.u
.id
)
2017 wr_print (e
, "LANGUAGE %u, %u\n",
2018 re
->id
.u
.id
& ((1 << SUBLANG_SHIFT
) - 1),
2019 (re
->id
.u
.id
>> SUBLANG_SHIFT
) & 0xff);
2020 *language
= re
->id
.u
.id
;
2029 write_rc_subdir (e
, re
, type
, name
, language
, level
);
2034 /* This is the normal case: the three levels are
2035 TYPE/NAME/LANGUAGE. NAME will have been set at level
2036 2, and represents the name to use. We probably just
2037 set LANGUAGE, and it will probably match what the
2038 resource itself records if anything. */
2039 write_rc_resource (e
, type
, name
, re
->u
.res
, language
);
2043 wr_printcomment (e
, "Resource at unexpected level %d", level
);
2044 write_rc_resource (e
, type
, (rc_res_id
*) NULL
, re
->u
.res
,
2049 if (rd
->entries
== NULL
)
2055 /* Write out a subdirectory entry. E is the file to write to. RE is
2056 the subdirectory entry. TYPE and NAME are pointers to higher level
2057 IDs, or NULL. LANGUAGE is a pointer to the current language.
2058 LEVEL is the level in the tree. */
2061 write_rc_subdir (FILE *e
, const rc_res_entry
*re
,
2062 const rc_res_id
*type
, const rc_res_id
*name
,
2063 rc_uint_type
*language
, int level
)
2069 wr_printcomment (e
, "Type: ");
2071 res_id_print (e
, re
->id
, 1);
2076 switch (re
->id
.u
.id
)
2078 case RT_CURSOR
: s
= "cursor"; break;
2079 case RT_BITMAP
: s
= "bitmap"; break;
2080 case RT_ICON
: s
= "icon"; break;
2081 case RT_MENU
: s
= "menu"; break;
2082 case RT_DIALOG
: s
= "dialog"; break;
2083 case RT_STRING
: s
= "stringtable"; break;
2084 case RT_FONTDIR
: s
= "fontdir"; break;
2085 case RT_FONT
: s
= "font"; break;
2086 case RT_ACCELERATOR
: s
= "accelerators"; break;
2087 case RT_RCDATA
: s
= "rcdata"; break;
2088 case RT_MESSAGETABLE
: s
= "messagetable"; break;
2089 case RT_GROUP_CURSOR
: s
= "group cursor"; break;
2090 case RT_GROUP_ICON
: s
= "group icon"; break;
2091 case RT_VERSION
: s
= "version"; break;
2092 case RT_DLGINCLUDE
: s
= "dlginclude"; break;
2093 case RT_PLUGPLAY
: s
= "plugplay"; break;
2094 case RT_VXD
: s
= "vxd"; break;
2095 case RT_ANICURSOR
: s
= "anicursor"; break;
2096 case RT_ANIICON
: s
= "aniicon"; break;
2097 case RT_TOOLBAR
: s
= "toolbar"; break;
2098 case RT_HTML
: s
= "html"; break;
2099 default: s
= NULL
; break;
2103 fprintf (e
, "%s", s
);
2105 res_id_print (e
, re
->id
, 1);
2110 wr_printcomment (e
, "Name: ");
2111 res_id_print (e
, re
->id
, 1);
2115 wr_printcomment (e
, "Language: ");
2116 res_id_print (e
, re
->id
, 1);
2120 wr_printcomment (e
, "Level %d: ", level
);
2121 res_id_print (e
, re
->id
, 1);
2124 write_rc_directory (e
, re
->u
.dir
, type
, name
, language
, level
+ 1);
2127 /* Write out a single resource. E is the file to write to. TYPE is a
2128 pointer to the type of the resource. NAME is a pointer to the name
2129 of the resource; it will be NULL if there is a level mismatch. RES
2130 is the resource data. LANGUAGE is a pointer to the current
2134 write_rc_resource (FILE *e
, const rc_res_id
*type
,
2135 const rc_res_id
*name
, const rc_res_resource
*res
,
2136 rc_uint_type
*language
)
2147 case RES_TYPE_ACCELERATOR
:
2149 rt
= RT_ACCELERATOR
;
2152 case RES_TYPE_BITMAP
:
2153 s
= "2 /* RT_BITMAP */";
2157 case RES_TYPE_CURSOR
:
2158 s
= "1 /* RT_CURSOR */";
2162 case RES_TYPE_GROUP_CURSOR
:
2163 s
= "12 /* RT_GROUP_CURSOR */";
2164 rt
= RT_GROUP_CURSOR
;
2167 case RES_TYPE_DIALOG
:
2168 if (extended_dialog (res
->u
.dialog
))
2176 s
= "8 /* RT_FONT */";
2180 case RES_TYPE_FONTDIR
:
2181 s
= "7 /* RT_FONTDIR */";
2186 s
= "3 /* RT_ICON */";
2190 case RES_TYPE_GROUP_ICON
:
2191 s
= "14 /* RT_GROUP_ICON */";
2196 if (extended_menu (res
->u
.menu
))
2209 case RES_TYPE_MESSAGETABLE
:
2210 s
= "11 /* RT_MESSAGETABLE */";
2211 rt
= RT_MESSAGETABLE
;
2214 case RES_TYPE_RCDATA
:
2219 case RES_TYPE_STRINGTABLE
:
2224 case RES_TYPE_USERDATA
:
2229 case RES_TYPE_VERSIONINFO
:
2234 case RES_TYPE_TOOLBAR
:
2242 && (type
->named
|| type
->u
.id
!= (unsigned long) rt
))
2244 wr_printcomment (e
, "Unexpected resource type mismatch: ");
2245 res_id_print (e
, *type
, 1);
2246 fprintf (e
, " != %d", rt
);
2249 if (res
->coff_info
.codepage
!= 0)
2250 wr_printcomment (e
, "Code page: %u", res
->coff_info
.codepage
);
2251 if (res
->coff_info
.reserved
!= 0)
2252 wr_printcomment (e
, "COFF reserved value: %u", res
->coff_info
.reserved
);
2255 if (rt
== RT_STRING
)
2260 res_id_print (e
, *name
, 1);
2262 fprintf (e
, "??Unknown-Name??");
2267 fprintf (e
, "%s", s
);
2268 else if (type
!= NULL
)
2270 if (type
->named
== 0)
2272 #define PRINT_RT_NAME(NAME) case NAME: \
2273 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2279 res_id_print (e
, *type
, 0);
2282 PRINT_RT_NAME(RT_MANIFEST
);
2283 PRINT_RT_NAME(RT_ANICURSOR
);
2284 PRINT_RT_NAME(RT_ANIICON
);
2285 PRINT_RT_NAME(RT_RCDATA
);
2286 PRINT_RT_NAME(RT_ICON
);
2287 PRINT_RT_NAME(RT_CURSOR
);
2288 PRINT_RT_NAME(RT_BITMAP
);
2289 PRINT_RT_NAME(RT_PLUGPLAY
);
2290 PRINT_RT_NAME(RT_VXD
);
2291 PRINT_RT_NAME(RT_FONT
);
2292 PRINT_RT_NAME(RT_FONTDIR
);
2293 PRINT_RT_NAME(RT_HTML
);
2294 PRINT_RT_NAME(RT_MESSAGETABLE
);
2295 PRINT_RT_NAME(RT_DLGINCLUDE
);
2296 PRINT_RT_NAME(RT_DLGINIT
);
2298 #undef PRINT_RT_NAME
2301 res_id_print (e
, *type
, 1);
2304 fprintf (e
, "??Unknown-Type??");
2306 if (res
->res_info
.memflags
!= 0)
2308 if ((res
->res_info
.memflags
& MEMFLAG_MOVEABLE
) != 0)
2309 fprintf (e
, " MOVEABLE");
2310 if ((res
->res_info
.memflags
& MEMFLAG_PURE
) != 0)
2311 fprintf (e
, " PURE");
2312 if ((res
->res_info
.memflags
& MEMFLAG_PRELOAD
) != 0)
2313 fprintf (e
, " PRELOAD");
2314 if ((res
->res_info
.memflags
& MEMFLAG_DISCARDABLE
) != 0)
2315 fprintf (e
, " DISCARDABLE");
2318 if (res
->type
== RES_TYPE_DIALOG
)
2320 fprintf (e
, " %d, %d, %d, %d",
2321 (int) res
->u
.dialog
->x
, (int) res
->u
.dialog
->y
,
2322 (int) res
->u
.dialog
->width
, (int) res
->u
.dialog
->height
);
2323 if (res
->u
.dialog
->ex
!= NULL
2324 && res
->u
.dialog
->ex
->help
!= 0)
2325 fprintf (e
, ", %u", (unsigned int) res
->u
.dialog
->ex
->help
);
2327 else if (res
->type
== RES_TYPE_TOOLBAR
)
2329 fprintf (e
, " %d, %d", (int) res
->u
.toolbar
->button_width
,
2330 (int) res
->u
.toolbar
->button_height
);
2335 if ((res
->res_info
.language
!= 0 && res
->res_info
.language
!= *language
)
2336 || res
->res_info
.characteristics
!= 0
2337 || res
->res_info
.version
!= 0)
2343 case RES_TYPE_ACCELERATOR
:
2344 case RES_TYPE_DIALOG
:
2346 case RES_TYPE_RCDATA
:
2347 case RES_TYPE_STRINGTABLE
:
2356 if (res
->res_info
.language
!= 0 && res
->res_info
.language
!= *language
)
2357 fprintf (e
, "%sLANGUAGE %d, %d\n",
2358 modifiers
? "// " : "",
2359 (int) res
->res_info
.language
& ((1<<SUBLANG_SHIFT
)-1),
2360 (int) (res
->res_info
.language
>> SUBLANG_SHIFT
) & 0xff);
2361 if (res
->res_info
.characteristics
!= 0)
2362 fprintf (e
, "%sCHARACTERISTICS %u\n",
2363 modifiers
? "// " : "",
2364 (unsigned int) res
->res_info
.characteristics
);
2365 if (res
->res_info
.version
!= 0)
2366 fprintf (e
, "%sVERSION %u\n",
2367 modifiers
? "// " : "",
2368 (unsigned int) res
->res_info
.version
);
2376 case RES_TYPE_ACCELERATOR
:
2377 write_rc_accelerators (e
, res
->u
.acc
);
2380 case RES_TYPE_CURSOR
:
2381 write_rc_cursor (e
, res
->u
.cursor
);
2384 case RES_TYPE_GROUP_CURSOR
:
2385 write_rc_group_cursor (e
, res
->u
.group_cursor
);
2388 case RES_TYPE_DIALOG
:
2389 write_rc_dialog (e
, res
->u
.dialog
);
2392 case RES_TYPE_FONTDIR
:
2393 write_rc_fontdir (e
, res
->u
.fontdir
);
2396 case RES_TYPE_GROUP_ICON
:
2397 write_rc_group_icon (e
, res
->u
.group_icon
);
2401 write_rc_menu (e
, res
->u
.menu
, menuex
);
2404 case RES_TYPE_RCDATA
:
2405 write_rc_rcdata (e
, res
->u
.rcdata
, 0);
2408 case RES_TYPE_STRINGTABLE
:
2409 write_rc_stringtable (e
, name
, res
->u
.stringtable
);
2412 case RES_TYPE_USERDATA
:
2413 write_rc_rcdata (e
, res
->u
.userdata
, 0);
2416 case RES_TYPE_TOOLBAR
:
2417 write_rc_toolbar (e
, res
->u
.toolbar
);
2420 case RES_TYPE_VERSIONINFO
:
2421 write_rc_versioninfo (e
, res
->u
.versioninfo
);
2424 case RES_TYPE_BITMAP
:
2427 write_rc_datablock (e
, res
->u
.data
.length
, res
->u
.data
.data
, 0, 1, 0);
2429 case RES_TYPE_MESSAGETABLE
:
2430 write_rc_messagetable (e
, res
->u
.data
.length
, res
->u
.data
.data
);
2435 /* Write out accelerator information. */
2438 write_rc_accelerators (FILE *e
, const rc_accelerator
*accelerators
)
2440 const rc_accelerator
*acc
;
2442 fprintf (e
, "BEGIN\n");
2443 for (acc
= accelerators
; acc
!= NULL
; acc
= acc
->next
)
2449 if ((acc
->key
& 0x7f) == acc
->key
2450 && ISPRINT (acc
->key
)
2451 && (acc
->flags
& ACC_VIRTKEY
) == 0)
2453 fprintf (e
, "\"%c\"", (char) acc
->key
);
2458 fprintf (e
, "%d", (int) acc
->key
);
2462 fprintf (e
, ", %d", (int) acc
->id
);
2466 if ((acc
->flags
& ACC_VIRTKEY
) != 0)
2467 fprintf (e
, ", VIRTKEY");
2469 fprintf (e
, ", ASCII");
2472 if ((acc
->flags
& ACC_SHIFT
) != 0)
2473 fprintf (e
, ", SHIFT");
2474 if ((acc
->flags
& ACC_CONTROL
) != 0)
2475 fprintf (e
, ", CONTROL");
2476 if ((acc
->flags
& ACC_ALT
) != 0)
2477 fprintf (e
, ", ALT");
2482 fprintf (e
, "END\n");
2485 /* Write out cursor information. This would normally be in a separate
2486 file, which the rc file would include. */
2489 write_rc_cursor (FILE *e
, const rc_cursor
*cursor
)
2491 fprintf (e
, "BEGIN\n");
2493 fprintf (e
, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2494 (unsigned int) cursor
->xhotspot
, (unsigned int) cursor
->yhotspot
,
2495 (int) cursor
->xhotspot
, (int) cursor
->yhotspot
);
2496 write_rc_datablock (e
, (rc_uint_type
) cursor
->length
, (const bfd_byte
*) cursor
->data
,
2498 fprintf (e
, "END\n");
2501 /* Write out group cursor data. This would normally be built from the
2505 write_rc_group_cursor (FILE *e
, const rc_group_cursor
*group_cursor
)
2507 const rc_group_cursor
*gc
;
2510 for (c
= 0, gc
= group_cursor
; gc
!= NULL
; gc
= gc
->next
, c
++)
2512 fprintf (e
, "BEGIN\n");
2515 fprintf (e
, "0, 2, %d%s\t /* Having %d items. */\n", c
, (c
!= 0 ? "," : ""), c
);
2517 fprintf (e
, "/* width, height, planes, bits, bytes, index. */\n");
2519 for (c
= 1, gc
= group_cursor
; gc
!= NULL
; gc
= gc
->next
, c
++)
2522 fprintf (e
, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2523 (int) gc
->width
, (int) gc
->height
, (int) gc
->planes
, (int) gc
->bits
,
2524 (unsigned int) gc
->bytes
, (int) gc
->index
, (gc
->next
!= NULL
? "," : ""), c
);
2525 fprintf (e
, "/* width: %d; height %d; planes %d; bits %d. */\n",
2526 (int) gc
->width
, (int) gc
->height
, (int) gc
->planes
,
2529 fprintf (e
, "END\n");
2532 /* Write dialog data. */
2535 write_rc_dialog (FILE *e
, const rc_dialog
*dialog
)
2537 const rc_dialog_control
*control
;
2539 fprintf (e
, "STYLE 0x%x\n", dialog
->style
);
2541 if (dialog
->exstyle
!= 0)
2542 fprintf (e
, "EXSTYLE 0x%x\n", (unsigned int) dialog
->exstyle
);
2544 if ((dialog
->class.named
&& dialog
->class.u
.n
.length
> 0)
2545 || dialog
->class.u
.id
!= 0)
2547 fprintf (e
, "CLASS ");
2548 res_id_print (e
, dialog
->class, 1);
2552 if (dialog
->caption
!= NULL
)
2554 fprintf (e
, "CAPTION ");
2555 unicode_print_quoted (e
, dialog
->caption
, -1);
2559 if ((dialog
->menu
.named
&& dialog
->menu
.u
.n
.length
> 0)
2560 || dialog
->menu
.u
.id
!= 0)
2562 fprintf (e
, "MENU ");
2563 res_id_print (e
, dialog
->menu
, 0);
2567 if (dialog
->font
!= NULL
)
2569 fprintf (e
, "FONT %d, ", (int) dialog
->pointsize
);
2570 unicode_print_quoted (e
, dialog
->font
, -1);
2571 if (dialog
->ex
!= NULL
2572 && (dialog
->ex
->weight
!= 0
2573 || dialog
->ex
->italic
!= 0
2574 || dialog
->ex
->charset
!= 1))
2575 fprintf (e
, ", %d, %d, %d",
2576 (int) dialog
->ex
->weight
,
2577 (int) dialog
->ex
->italic
,
2578 (int) dialog
->ex
->charset
);
2582 fprintf (e
, "BEGIN\n");
2584 for (control
= dialog
->controls
; control
!= NULL
; control
= control
->next
)
2585 write_rc_dialog_control (e
, control
);
2587 fprintf (e
, "END\n");
2590 /* For each predefined control keyword, this table provides the class
2596 unsigned short class;
2597 unsigned long style
;
2600 static const struct control_info control_info
[] =
2602 { "AUTO3STATE", CTL_BUTTON
, BS_AUTO3STATE
},
2603 { "AUTOCHECKBOX", CTL_BUTTON
, BS_AUTOCHECKBOX
},
2604 { "AUTORADIOBUTTON", CTL_BUTTON
, BS_AUTORADIOBUTTON
},
2605 { "CHECKBOX", CTL_BUTTON
, BS_CHECKBOX
},
2606 { "COMBOBOX", CTL_COMBOBOX
, (unsigned long) -1 },
2607 { "CTEXT", CTL_STATIC
, SS_CENTER
},
2608 { "DEFPUSHBUTTON", CTL_BUTTON
, BS_DEFPUSHBUTTON
},
2609 { "EDITTEXT", CTL_EDIT
, (unsigned long) -1 },
2610 { "GROUPBOX", CTL_BUTTON
, BS_GROUPBOX
},
2611 { "ICON", CTL_STATIC
, SS_ICON
},
2612 { "LISTBOX", CTL_LISTBOX
, (unsigned long) -1 },
2613 { "LTEXT", CTL_STATIC
, SS_LEFT
},
2614 { "PUSHBOX", CTL_BUTTON
, BS_PUSHBOX
},
2615 { "PUSHBUTTON", CTL_BUTTON
, BS_PUSHBUTTON
},
2616 { "RADIOBUTTON", CTL_BUTTON
, BS_RADIOBUTTON
},
2617 { "RTEXT", CTL_STATIC
, SS_RIGHT
},
2618 { "SCROLLBAR", CTL_SCROLLBAR
, (unsigned long) -1 },
2619 { "STATE3", CTL_BUTTON
, BS_3STATE
},
2620 /* It's important that USERBUTTON come after all the other button
2621 types, so that it won't be matched too early. */
2622 { "USERBUTTON", CTL_BUTTON
, (unsigned long) -1 },
2626 /* Write a dialog control. */
2629 write_rc_dialog_control (FILE *e
, const rc_dialog_control
*control
)
2631 const struct control_info
*ci
;
2635 if (control
->class.named
)
2639 for (ci
= control_info
; ci
->name
!= NULL
; ++ci
)
2640 if (ci
->class == control
->class.u
.id
2641 && (ci
->style
== (unsigned long) -1
2642 || ci
->style
== (control
->style
& 0xff)))
2646 fprintf (e
, "CONTROL");
2647 else if (ci
->name
!= NULL
)
2648 fprintf (e
, "%s", ci
->name
);
2651 fprintf (e
, "CONTROL");
2655 /* For EDITTEXT, COMBOBOX, LISTBOX, and SCROLLBAR don't dump text. */
2656 if ((control
->text
.named
|| control
->text
.u
.id
!= 0)
2658 || (ci
->class != CTL_EDIT
2659 && ci
->class != CTL_COMBOBOX
2660 && ci
->class != CTL_LISTBOX
2661 && ci
->class != CTL_SCROLLBAR
)))
2664 res_id_print (e
, control
->text
, 1);
2668 fprintf (e
, " %d, ", (int) control
->id
);
2672 if (control
->class.named
)
2674 res_id_print (e
, control
->class, 0);
2675 if (control
->class.named
)
2677 fprintf (e
, ", 0x%x, ", (unsigned int) control
->style
);
2680 fprintf (e
, "%d, %d", (int) control
->x
, (int) control
->y
);
2682 if (control
->style
!= SS_ICON
2683 || control
->exstyle
!= 0
2684 || control
->width
!= 0
2685 || control
->height
!= 0
2686 || control
->help
!= 0)
2688 fprintf (e
, ", %d, %d", (int) control
->width
, (int) control
->height
);
2690 /* FIXME: We don't need to print the style if it is the default.
2691 More importantly, in certain cases we actually need to turn
2692 off parts of the forced style, by using NOT. */
2694 fprintf (e
, ", 0x%x", (unsigned int) control
->style
);
2696 if (control
->exstyle
!= 0 || control
->help
!= 0)
2697 fprintf (e
, ", 0x%x, %u", (unsigned int) control
->exstyle
,
2698 (unsigned int) control
->help
);
2703 if (control
->data
!= NULL
)
2704 write_rc_rcdata (e
, control
->data
, 2);
2707 /* Write out font directory data. This would normally be built from
2711 write_rc_fontdir (FILE *e
, const rc_fontdir
*fontdir
)
2713 const rc_fontdir
*fc
;
2716 for (c
= 0, fc
= fontdir
; fc
!= NULL
; fc
= fc
->next
, c
++)
2718 fprintf (e
, "BEGIN\n");
2720 fprintf (e
, "%d%s\t /* Has %d elements. */\n", c
, (c
!= 0 ? "," : ""), c
);
2721 for (c
= 1, fc
= fontdir
; fc
!= NULL
; fc
= fc
->next
, c
++)
2724 fprintf (e
, "%d,\t/* Font no %d with index %d. */\n",
2725 (int) fc
->index
, c
, (int) fc
->index
);
2726 write_rc_datablock (e
, (rc_uint_type
) fc
->length
- 2,
2727 (const bfd_byte
*) fc
->data
+ 4,fc
->next
!= NULL
,
2730 fprintf (e
, "END\n");
2733 /* Write out group icon data. This would normally be built from the
2737 write_rc_group_icon (FILE *e
, const rc_group_icon
*group_icon
)
2739 const rc_group_icon
*gi
;
2742 for (c
= 0, gi
= group_icon
; gi
!= NULL
; gi
= gi
->next
, c
++)
2745 fprintf (e
, "BEGIN\n");
2747 fprintf (e
, " 0, 1, %d%s\t /* Has %d elements. */\n", c
, (c
!= 0 ? "," : ""), c
);
2750 fprintf (e
, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2751 for (c
= 1, gi
= group_icon
; gi
!= NULL
; gi
= gi
->next
, c
++)
2754 fprintf (e
, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2755 gi
->width
, gi
->height
, gi
->colors
, 0, (int) gi
->planes
, (int) gi
->bits
,
2756 (unsigned int) gi
->bytes
, (int) gi
->index
, (gi
->next
!= NULL
? "," : ""), c
);
2758 fprintf (e
, "END\n");
2761 /* Write out a menu resource. */
2764 write_rc_menu (FILE *e
, const rc_menu
*menu
, int menuex
)
2766 if (menu
->help
!= 0)
2767 fprintf (e
, "// Help ID: %u\n", (unsigned int) menu
->help
);
2768 write_rc_menuitems (e
, menu
->items
, menuex
, 0);
2772 write_rc_toolbar (FILE *e
, const rc_toolbar
*tb
)
2774 rc_toolbar_item
*it
;
2776 fprintf (e
, "BEGIN\n");
2781 if (it
->id
.u
.id
== 0)
2782 fprintf (e
, "SEPARATOR\n");
2784 fprintf (e
, "BUTTON %d\n", (int) it
->id
.u
.id
);
2788 fprintf (e
, "END\n");
2791 /* Write out menuitems. */
2794 write_rc_menuitems (FILE *e
, const rc_menuitem
*menuitems
, int menuex
,
2797 const rc_menuitem
*mi
;
2800 fprintf (e
, "BEGIN\n");
2802 for (mi
= menuitems
; mi
!= NULL
; mi
= mi
->next
)
2804 indent (e
, ind
+ 2);
2806 if (mi
->popup
== NULL
)
2807 fprintf (e
, "MENUITEM");
2809 fprintf (e
, "POPUP");
2812 && mi
->popup
== NULL
2817 fprintf (e
, " SEPARATOR\n");
2821 if (mi
->text
== NULL
)
2822 fprintf (e
, " \"\"");
2826 unicode_print_quoted (e
, mi
->text
, -1);
2831 if (mi
->popup
== NULL
)
2832 fprintf (e
, ", %d", (int) mi
->id
);
2834 if ((mi
->type
& MENUITEM_CHECKED
) != 0)
2835 fprintf (e
, ", CHECKED");
2836 if ((mi
->type
& MENUITEM_GRAYED
) != 0)
2837 fprintf (e
, ", GRAYED");
2838 if ((mi
->type
& MENUITEM_HELP
) != 0)
2839 fprintf (e
, ", HELP");
2840 if ((mi
->type
& MENUITEM_INACTIVE
) != 0)
2841 fprintf (e
, ", INACTIVE");
2842 if ((mi
->type
& MENUITEM_MENUBARBREAK
) != 0)
2843 fprintf (e
, ", MENUBARBREAK");
2844 if ((mi
->type
& MENUITEM_MENUBREAK
) != 0)
2845 fprintf (e
, ", MENUBREAK");
2846 if ((mi
->type
& MENUITEM_OWNERDRAW
) != 0)
2847 fprintf (e
, ", OWNERDRAW");
2848 if ((mi
->type
& MENUITEM_BITMAP
) != 0)
2849 fprintf (e
, ", BITMAP");
2853 if (mi
->id
!= 0 || mi
->type
!= 0 || mi
->state
!= 0 || mi
->help
!= 0)
2855 fprintf (e
, ", %d", (int) mi
->id
);
2856 if (mi
->type
!= 0 || mi
->state
!= 0 || mi
->help
!= 0)
2858 fprintf (e
, ", %u", (unsigned int) mi
->type
);
2859 if (mi
->state
!= 0 || mi
->help
!= 0)
2861 fprintf (e
, ", %u", (unsigned int) mi
->state
);
2863 fprintf (e
, ", %u", (unsigned int) mi
->help
);
2871 if (mi
->popup
!= NULL
)
2872 write_rc_menuitems (e
, mi
->popup
, menuex
, ind
+ 2);
2876 fprintf (e
, "END\n");
2880 test_rc_datablock_unicode (rc_uint_type length
, const bfd_byte
*data
)
2883 if ((length
& 1) != 0)
2886 for (i
= 0; i
< length
; i
+= 2)
2888 if (data
[i
] == 0 && data
[i
+ 1] == 0 && (i
+ 2) < length
)
2890 if (data
[i
] == 0xff && data
[i
+ 1] == 0xff)
2897 test_rc_datablock_text (rc_uint_type length
, const bfd_byte
*data
)
2907 for (i
= 0, c
= 0; i
< length
; i
++)
2909 if (! ISPRINT (data
[i
]) && data
[i
] != '\n'
2910 && ! (data
[i
] == '\r' && (i
+ 1) < length
&& data
[i
+ 1] == '\n')
2912 && ! (data
[i
] == 0 && (i
+ 1) != length
))
2918 else if (data
[i
] == '\n') has_nl
++;
2920 if (length
> 80 && ! has_nl
)
2922 c
= (((c
* 10000) + (i
/ 100) - 1)) / i
;
2929 write_rc_messagetable (FILE *e
, rc_uint_type length
, const bfd_byte
*data
)
2932 const struct bin_messagetable
*mt
;
2934 fprintf (e
, "BEGIN\n");
2936 write_rc_datablock (e
, length
, data
, 0, 0, 0);
2939 wr_printcomment (e
, "MC syntax dump");
2940 if (length
< BIN_MESSAGETABLE_SIZE
)
2947 mt
= (const struct bin_messagetable
*) data
;
2948 m
= windres_get_32 (&wrtarget
, mt
->cblocks
, length
);
2950 if (length
< (BIN_MESSAGETABLE_SIZE
+ m
* BIN_MESSAGETABLE_BLOCK_SIZE
))
2955 for (i
= 0; i
< m
; i
++)
2957 rc_uint_type low
, high
, offset
;
2958 const struct bin_messagetable_item
*mti
;
2960 low
= windres_get_32 (&wrtarget
, mt
->items
[i
].lowid
, 4);
2961 high
= windres_get_32 (&wrtarget
, mt
->items
[i
].highid
, 4);
2962 offset
= windres_get_32 (&wrtarget
, mt
->items
[i
].offset
, 4);
2966 rc_uint_type elen
, flags
;
2967 if ((offset
+ BIN_MESSAGETABLE_ITEM_SIZE
) > length
)
2972 mti
= (const struct bin_messagetable_item
*) &data
[offset
];
2973 elen
= windres_get_16 (&wrtarget
, mti
->length
, 2);
2974 flags
= windres_get_16 (&wrtarget
, mti
->flags
, 2);
2975 if ((offset
+ elen
) > length
)
2980 wr_printcomment (e
, "MessageId = 0x%x", low
);
2981 wr_printcomment (e
, "");
2983 if ((flags
& MESSAGE_RESOURCE_UNICODE
) == MESSAGE_RESOURCE_UNICODE
)
2985 /* PR 17512: file: 5c3232dc. */
2986 if (elen
> BIN_MESSAGETABLE_ITEM_SIZE
* 2)
2987 unicode_print (e
, (const unichar
*) mti
->data
,
2988 (elen
- BIN_MESSAGETABLE_ITEM_SIZE
) / 2);
2992 if (elen
> BIN_MESSAGETABLE_ITEM_SIZE
)
2993 ascii_print (e
, (const char *) mti
->data
,
2994 (elen
- BIN_MESSAGETABLE_ITEM_SIZE
));
2997 wr_printcomment (e
,"");
3006 wr_printcomment (e
, "Illegal data");
3008 fprintf (e
, "END\n");
3012 write_rc_datablock (FILE *e
, rc_uint_type length
, const bfd_byte
*data
, int has_next
,
3013 int hasblock
, int show_comment
)
3018 fprintf (e
, "BEGIN\n");
3020 if (show_comment
== -1)
3022 if (test_rc_datablock_text(length
, data
))
3025 for (i
= 0; i
< length
;)
3030 for (c
= 0; i
< length
&& c
< 160 && data
[i
] != '\n'; c
++, i
++)
3032 if (i
< length
&& data
[i
] == '\n')
3034 ascii_print(e
, (const char *) &data
[i
- c
], c
);
3043 fprintf (e
, "\"\"");
3049 fprintf (e
, "END\n");
3052 if (test_rc_datablock_unicode (length
, data
))
3055 for (i
= 0; i
< length
;)
3059 u
= (const unichar
*) &data
[i
];
3063 for (c
= 0; i
< length
&& c
< 160 && u
[c
] != '\n'; c
++, i
+= 2)
3065 if (i
< length
&& u
[c
] == '\n')
3067 unicode_print (e
, u
, c
);
3076 fprintf (e
, "L\"\"");
3082 fprintf (e
, "END\n");
3091 rc_uint_type i
, max_row
;
3094 max_row
= (show_comment
? 4 : 8);
3096 for (i
= 0; i
+ 3 < length
;)
3099 rc_uint_type comment_start
;
3106 for (k
= 0; k
< max_row
&& i
+ 3 < length
; k
++, i
+= 4)
3109 plen
= fprintf (e
, "0x%lxL",
3110 (unsigned long) windres_get_32 (&wrtarget
, data
+ i
, length
- i
));
3112 plen
= fprintf (e
, " 0x%lxL",
3113 (unsigned long) windres_get_32 (&wrtarget
, data
+ i
, length
- i
)) - 1;
3114 if (has_next
|| (i
+ 4) < length
)
3116 if (plen
>0 && plen
< 11)
3117 indent (e
, 11 - plen
);
3123 fprintf (e
, "\t/* ");
3124 ascii_print (e
, (const char *) &data
[comment_start
], i
- comment_start
);
3125 fprintf (e
, ". */");
3135 plen
= fprintf (e
, "0x%x",
3136 (int) windres_get_16 (&wrtarget
, data
+ i
, length
- i
));
3137 if (has_next
|| i
+ 2 < length
)
3139 if (plen
> 0 && plen
< 11)
3140 indent (e
, 11 - plen
);
3145 fprintf (e
, "\t/* ");
3146 ascii_print (e
, (const char *) &data
[i
], 2);
3147 fprintf (e
, ". */");
3159 ascii_print (e
, (const char *) &data
[i
], 1);
3168 fprintf (e
, "END\n");
3171 /* Write out an rcdata resource. This is also used for other types of
3172 resources that need to print arbitrary data. */
3175 write_rc_rcdata (FILE *e
, const rc_rcdata_item
*rcdata
, int ind
)
3177 const rc_rcdata_item
*ri
;
3180 fprintf (e
, "BEGIN\n");
3182 for (ri
= rcdata
; ri
!= NULL
; ri
= ri
->next
)
3184 if (ri
->type
== RCDATA_BUFFER
&& ri
->u
.buffer
.length
== 0)
3193 indent (e
, ind
+ 2);
3194 fprintf (e
, "%ld", (long) (ri
->u
.word
& 0xffff));
3198 indent (e
, ind
+ 2);
3199 fprintf (e
, "%luL", (unsigned long) ri
->u
.dword
);
3203 indent (e
, ind
+ 2);
3205 ascii_print (e
, ri
->u
.string
.s
, ri
->u
.string
.length
);
3209 case RCDATA_WSTRING
:
3210 indent (e
, ind
+ 2);
3212 unicode_print (e
, ri
->u
.wstring
.w
, ri
->u
.wstring
.length
);
3217 write_rc_datablock (e
, (rc_uint_type
) ri
->u
.buffer
.length
,
3218 (const bfd_byte
*) ri
->u
.buffer
.data
,
3219 ri
->next
!= NULL
, 0, -1);
3223 if (ri
->type
!= RCDATA_BUFFER
)
3225 if (ri
->next
!= NULL
)
3232 fprintf (e
, "END\n");
3235 /* Write out a stringtable resource. */
3238 write_rc_stringtable (FILE *e
, const rc_res_id
*name
,
3239 const rc_stringtable
*stringtable
)
3241 rc_uint_type offset
;
3244 if (name
!= NULL
&& ! name
->named
)
3245 offset
= (name
->u
.id
- 1) << 4;
3248 fprintf (e
, "/* %s string table name. */\n",
3249 name
== NULL
? "Missing" : "Invalid");
3253 fprintf (e
, "BEGIN\n");
3255 for (i
= 0; i
< 16; i
++)
3257 if (stringtable
->strings
[i
].length
!= 0)
3259 fprintf (e
, " %lu, ", (unsigned long) offset
+ i
);
3260 unicode_print_quoted (e
, stringtable
->strings
[i
].string
,
3261 stringtable
->strings
[i
].length
);
3266 fprintf (e
, "END\n");
3269 /* Write out a versioninfo resource. */
3272 write_rc_versioninfo (FILE *e
, const rc_versioninfo
*versioninfo
)
3274 const rc_fixed_versioninfo
*f
;
3275 const rc_ver_info
*vi
;
3277 f
= versioninfo
->fixed
;
3278 if (f
->file_version_ms
!= 0 || f
->file_version_ls
!= 0)
3279 fprintf (e
, " FILEVERSION %u, %u, %u, %u\n",
3280 (unsigned int) ((f
->file_version_ms
>> 16) & 0xffff),
3281 (unsigned int) (f
->file_version_ms
& 0xffff),
3282 (unsigned int) ((f
->file_version_ls
>> 16) & 0xffff),
3283 (unsigned int) (f
->file_version_ls
& 0xffff));
3284 if (f
->product_version_ms
!= 0 || f
->product_version_ls
!= 0)
3285 fprintf (e
, " PRODUCTVERSION %u, %u, %u, %u\n",
3286 (unsigned int) ((f
->product_version_ms
>> 16) & 0xffff),
3287 (unsigned int) (f
->product_version_ms
& 0xffff),
3288 (unsigned int) ((f
->product_version_ls
>> 16) & 0xffff),
3289 (unsigned int) (f
->product_version_ls
& 0xffff));
3290 if (f
->file_flags_mask
!= 0)
3291 fprintf (e
, " FILEFLAGSMASK 0x%x\n", (unsigned int) f
->file_flags_mask
);
3292 if (f
->file_flags
!= 0)
3293 fprintf (e
, " FILEFLAGS 0x%x\n", (unsigned int) f
->file_flags
);
3294 if (f
->file_os
!= 0)
3295 fprintf (e
, " FILEOS 0x%x\n", (unsigned int) f
->file_os
);
3296 if (f
->file_type
!= 0)
3297 fprintf (e
, " FILETYPE 0x%x\n", (unsigned int) f
->file_type
);
3298 if (f
->file_subtype
!= 0)
3299 fprintf (e
, " FILESUBTYPE 0x%x\n", (unsigned int) f
->file_subtype
);
3300 if (f
->file_date_ms
!= 0 || f
->file_date_ls
!= 0)
3301 fprintf (e
, "/* Date: %u, %u. */\n",
3302 (unsigned int) f
->file_date_ms
, (unsigned int) f
->file_date_ls
);
3304 fprintf (e
, "BEGIN\n");
3306 for (vi
= versioninfo
->var
; vi
!= NULL
; vi
= vi
->next
)
3310 case VERINFO_STRING
:
3312 const rc_ver_stringtable
*vst
;
3313 const rc_ver_stringinfo
*vs
;
3315 fprintf (e
, " BLOCK \"StringFileInfo\"\n");
3316 fprintf (e
, " BEGIN\n");
3318 for (vst
= vi
->u
.string
.stringtables
; vst
!= NULL
; vst
= vst
->next
)
3320 fprintf (e
, " BLOCK ");
3321 unicode_print_quoted (e
, vst
->language
, -1);
3324 fprintf (e
, " BEGIN\n");
3326 for (vs
= vst
->strings
; vs
!= NULL
; vs
= vs
->next
)
3328 fprintf (e
, " VALUE ");
3329 unicode_print_quoted (e
, vs
->key
, -1);
3331 unicode_print_quoted (e
, vs
->value
, -1);
3335 fprintf (e
, " END\n");
3337 fprintf (e
, " END\n");
3343 const rc_ver_varinfo
*vv
;
3345 fprintf (e
, " BLOCK \"VarFileInfo\"\n");
3346 fprintf (e
, " BEGIN\n");
3347 fprintf (e
, " VALUE ");
3348 unicode_print_quoted (e
, vi
->u
.var
.key
, -1);
3350 for (vv
= vi
->u
.var
.var
; vv
!= NULL
; vv
= vv
->next
)
3351 fprintf (e
, ", 0x%x, %d", (unsigned int) vv
->language
,
3354 fprintf (e
, "\n END\n");
3361 fprintf (e
, "END\n");
3365 rcdata_copy (const rc_rcdata_item
*src
, bfd_byte
*dst
)
3373 windres_put_16 (&wrtarget
, dst
, (rc_uint_type
) src
->u
.word
);
3377 windres_put_32 (&wrtarget
, dst
, (rc_uint_type
) src
->u
.dword
);
3380 if (dst
&& src
->u
.string
.length
)
3381 memcpy (dst
, src
->u
.string
.s
, src
->u
.string
.length
);
3382 return (rc_uint_type
) src
->u
.string
.length
;
3383 case RCDATA_WSTRING
:
3384 if (dst
&& src
->u
.wstring
.length
)
3385 memcpy (dst
, src
->u
.wstring
.w
, src
->u
.wstring
.length
* sizeof (unichar
));
3386 return (rc_uint_type
) (src
->u
.wstring
.length
* sizeof (unichar
));
3388 if (dst
&& src
->u
.buffer
.length
)
3389 memcpy (dst
, src
->u
.buffer
.data
, src
->u
.buffer
.length
);
3390 return (rc_uint_type
) src
->u
.buffer
.length
;
3394 /* Never reached. */