2007-06-04 Olivier Hainque <hainque@adacore.com>
[binutils.git] / binutils / resrc.c
blob24b423d93e98f82056ba1912073c89d712dad74f
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 2 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
22 02110-1301, USA. */
24 /* This file contains functions that read and write Windows rc files.
25 These are text files that represent resources. */
27 #include "sysdep.h"
28 #include "bfd.h"
29 #include "bucomm.h"
30 #include "libiberty.h"
31 #include "safe-ctype.h"
32 #include "windres.h"
34 #include <assert.h>
35 #include <errno.h>
36 #include <sys/stat.h>
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
41 #ifdef HAVE_SYS_WAIT_H
42 #include <sys/wait.h>
43 #else /* ! HAVE_SYS_WAIT_H */
44 #if ! defined (_WIN32) || defined (__CYGWIN__)
45 #ifndef WIFEXITED
46 #define WIFEXITED(w) (((w)&0377) == 0)
47 #endif
48 #ifndef WIFSIGNALED
49 #define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
50 #endif
51 #ifndef WTERMSIG
52 #define WTERMSIG(w) ((w) & 0177)
53 #endif
54 #ifndef WEXITSTATUS
55 #define WEXITSTATUS(w) (((w) >> 8) & 0377)
56 #endif
57 #else /* defined (_WIN32) && ! defined (__CYGWIN__) */
58 #ifndef WIFEXITED
59 #define WIFEXITED(w) (((w) & 0xff) == 0)
60 #endif
61 #ifndef WIFSIGNALED
62 #define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
63 #endif
64 #ifndef WTERMSIG
65 #define WTERMSIG(w) ((w) & 0x7f)
66 #endif
67 #ifndef WEXITSTATUS
68 #define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
69 #endif
70 #endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
71 #endif /* ! HAVE_SYS_WAIT_H */
73 #ifndef STDOUT_FILENO
74 #define STDOUT_FILENO 1
75 #endif
77 #if defined (_WIN32) && ! defined (__CYGWIN__)
78 #define popen _popen
79 #define pclose _pclose
80 #endif
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. */
89 struct icondir
91 /* Width of image. */
92 bfd_byte width;
93 /* Height of image. */
94 bfd_byte height;
95 /* Number of colors in image. */
96 bfd_byte colorcount;
97 union
99 struct
101 /* Color planes. */
102 unsigned short planes;
103 /* Bits per pixel. */
104 unsigned short bits;
105 } icon;
106 struct
108 /* X coordinate of hotspot. */
109 unsigned short xhotspot;
110 /* Y coordinate of hotspot. */
111 unsigned short yhotspot;
112 } cursor;
113 } u;
114 /* Bytes in image. */
115 unsigned long bytes;
116 /* File offset of image. */
117 unsigned long offset;
120 /* The name of the rc file we are reading. */
122 char *rc_filename;
124 /* The line number in the rc file. */
126 int rc_lineno;
128 /* The pipe we are reading from, so that we can close it if we exit. */
130 FILE *cpp_pipe;
132 /* The temporary file used if we're not using popen, so we can delete it
133 if we exit. */
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. */
147 static int cursors;
149 /* The number of font resources we have written out. */
151 static int fonts;
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. */
163 static int icons;
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 *,
175 rc_rcdata_item *);
176 static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
177 rc_rcdata_item *);
178 static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
179 rc_rcdata_item *);
180 static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
181 rc_rcdata_item *);
182 static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
183 rc_rcdata_item *);
184 static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
185 rc_rcdata_item *);
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'. */
202 static int
203 run_cmd (char *cmd, const char *redir)
205 char *s;
206 int pid, wait_status, retcode;
207 int i;
208 const char **argv;
209 char *errmsg_fmt, *errmsg_arg;
210 char *temp_base = choose_temp_base ();
211 int in_quote;
212 char sep;
213 int redir_handle = -1;
214 int stdout_save = -1;
216 /* Count the args. */
217 i = 0;
219 for (s = cmd; *s; s++)
220 if (*s == ' ')
221 i++;
223 i++;
224 argv = alloca (sizeof (char *) * (i + 3));
225 i = 0;
226 s = cmd;
228 while (1)
230 while (*s == ' ' && *s != 0)
231 s++;
233 if (*s == 0)
234 break;
236 in_quote = (*s == '\'' || *s == '"');
237 sep = (in_quote) ? *s++ : ' ';
238 argv[i++] = s;
240 while (*s != sep && *s != 0)
241 s++;
243 if (*s == 0)
244 break;
246 *s++ = 0;
248 if (in_quote)
249 s++;
251 argv[i++] = NULL;
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. */
256 fflush (stdout);
257 fflush (stderr);
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,
263 strerror (errno));
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);
282 if (pid == -1)
284 fatal (_("%s %s: %s"), errmsg_fmt, errmsg_arg, strerror (errno));
285 return 1;
288 retcode = 0;
289 pid = pwait (pid, &wait_status, 0);
291 if (pid == -1)
293 fatal (_("wait: %s"), strerror (errno));
294 retcode = 1;
296 else if (WIFSIGNALED (wait_status))
298 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
299 retcode = 1;
301 else if (WIFEXITED (wait_status))
303 if (WEXITSTATUS (wait_status) != 0)
305 fatal (_("%s exited with status %d"), cmd,
306 WEXITSTATUS (wait_status));
307 retcode = 1;
310 else
311 retcode = 1;
313 return retcode;
316 static FILE *
317 open_input_stream (char *cmd)
319 if (istream_type == ISTREAM_FILE)
321 char *fileprefix;
323 fileprefix = choose_temp_base ();
324 cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
325 sprintf (cpp_temp_file, "%s.irc", fileprefix);
326 free (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));
336 if (verbose)
337 fprintf (stderr,
338 _("Using temporary file `%s' to read preprocessor output\n"),
339 cpp_temp_file);
341 else
343 cpp_pipe = popen (cmd, FOPEN_RT);
344 if (cpp_pipe == NULL)
345 fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
346 if (verbose)
347 fprintf (stderr, _("Using popen to read preprocessor output\n"));
350 xatexit (close_input_stream);
351 return cpp_pipe;
354 /* look for the preprocessor program */
356 static FILE *
357 look_for_default (char *cmd, const char *prefix, int end_prefix,
358 const char *preprocargs, const char *filename)
360 char *space;
361 int found;
362 struct stat s;
364 strcpy (cmd, prefix);
366 sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
367 space = strchr (cmd + end_prefix, ' ');
368 if (space)
369 *space = 0;
371 if (
372 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
373 strchr (cmd, '\\') ||
374 #endif
375 strchr (cmd, '/'))
377 found = (stat (cmd, &s) == 0
378 #ifdef HAVE_EXECUTABLE_SUFFIX
379 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
380 #endif
383 if (! found)
385 if (verbose)
386 fprintf (stderr, _("Tried `%s'\n"), cmd);
387 return NULL;
391 strcpy (cmd, prefix);
393 sprintf (cmd + end_prefix, "%s %s %s",
394 DEFAULT_PREPROCESSOR, preprocargs, filename);
396 if (verbose)
397 fprintf (stderr, _("Using `%s'\n"), cmd);
399 cpp_pipe = open_input_stream (cmd);
400 return cpp_pipe;
403 /* Read an rc file. */
405 rc_res_directory *
406 read_rc_file (const char *filename, const char *preprocessor,
407 const char *preprocargs, int language, int use_temp_file)
409 char *cmd;
411 istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
413 if (preprocargs == NULL)
414 preprocargs = "";
415 if (filename == NULL)
416 filename = "-";
418 if (preprocessor)
420 cmd = xmalloc (strlen (preprocessor)
421 + strlen (preprocargs)
422 + strlen (filename)
423 + 10);
424 sprintf (cmd, "%s %s %s", preprocessor, preprocargs, filename);
426 cpp_pipe = open_input_stream (cmd);
428 else
430 char *dash, *slash, *cp;
432 preprocessor = DEFAULT_PREPROCESSOR;
434 cmd = xmalloc (strlen (program_name)
435 + strlen (preprocessor)
436 + strlen (preprocargs)
437 + strlen (filename)
438 #ifdef HAVE_EXECUTABLE_SUFFIX
439 + strlen (EXECUTABLE_SUFFIX)
440 #endif
441 + 10);
444 dash = slash = 0;
445 for (cp = program_name; *cp; cp++)
447 if (*cp == '-')
448 dash = cp;
449 if (
450 #if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
451 *cp == ':' || *cp == '\\' ||
452 #endif
453 *cp == '/')
455 slash = cp;
456 dash = 0;
460 cpp_pipe = 0;
462 if (dash)
464 /* First, try looking for a prefixed gcc in the windres
465 directory, with the same prefix as windres */
467 cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
468 preprocargs, filename);
471 if (slash && ! cpp_pipe)
473 /* Next, try looking for a gcc in the same directory as
474 that windres */
476 cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
477 preprocargs, filename);
480 if (! cpp_pipe)
482 /* Sigh, try the default */
484 cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
489 free (cmd);
491 rc_filename = xstrdup (filename);
492 rc_lineno = 1;
493 if (language != -1)
494 rcparse_set_language (language);
495 yyparse ();
496 rcparse_discard_strings ();
498 close_input_stream ();
500 if (fontdirs != NULL)
501 define_fontdirs ();
503 free (rc_filename);
504 rc_filename = NULL;
506 return resources;
509 /* Close the input stream if it is open. */
511 static void
512 close_input_stream (void)
514 if (istream_type == ISTREAM_FILE)
516 if (cpp_pipe != NULL)
517 fclose (cpp_pipe);
519 if (cpp_temp_file != NULL)
521 int errno_save = errno;
523 unlink (cpp_temp_file);
524 errno = errno_save;
525 free (cpp_temp_file);
528 else
530 if (cpp_pipe != NULL)
531 pclose (cpp_pipe);
534 /* Since this is also run via xatexit, safeguard. */
535 cpp_pipe = NULL;
536 cpp_temp_file = NULL;
539 /* Report an error while reading an rc file. */
541 void
542 yyerror (const char *msg)
544 fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
547 /* Issue a warning while reading an rc file. */
549 void
550 rcparse_warning (const char *msg)
552 fprintf (stderr, _("%s:%d: %s\n"), rc_filename, rc_lineno, msg);
555 /* Die if we get an unexpected end of file. */
557 static void
558 unexpected_eof (const char *msg)
560 fatal (_("%s: unexpected EOF"), msg);
563 /* Read a 16 bit word from a file. The data is assumed to be little
564 endian. */
566 static int
567 get_word (FILE *e, const char *msg)
569 int b1, b2;
571 b1 = getc (e);
572 b2 = getc (e);
573 if (feof (e))
574 unexpected_eof (msg);
575 return ((b2 & 0xff) << 8) | (b1 & 0xff);
578 /* Read a 32 bit word from a file. The data is assumed to be little
579 endian. */
581 static unsigned long
582 get_long (FILE *e, const char *msg)
584 int b1, b2, b3, b4;
586 b1 = getc (e);
587 b2 = getc (e);
588 b3 = getc (e);
589 b4 = getc (e);
590 if (feof (e))
591 unexpected_eof (msg);
592 return (((((((b4 & 0xff) << 8)
593 | (b3 & 0xff)) << 8)
594 | (b2 & 0xff)) << 8)
595 | (b1 & 0xff));
598 /* Read data from a file. This is a wrapper to do error checking. */
600 static void
601 get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
603 rc_uint_type got; // $$$d
605 got = (rc_uint_type) fread (p, 1, c, e);
606 if (got == c)
607 return;
609 fatal (_("%s: read of %lu returned %lu"), msg, (long) c, (long) got);
612 /* Define an accelerator resource. */
614 void
615 define_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
616 rc_accelerator *data)
618 rc_res_resource *r;
620 r = define_standard_resource (&resources, RT_ACCELERATOR, id,
621 resinfo->language, 0);
622 r->type = RES_TYPE_ACCELERATOR;
623 r->u.acc = data;
624 r->res_info = *resinfo;
627 /* Define a bitmap resource. Bitmap data is stored in a file. The
628 first 14 bytes of the file are a standard header, which is not
629 included in the resource data. */
631 #define BITMAP_SKIP (14)
633 void
634 define_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
635 const char *filename)
637 FILE *e;
638 char *real_filename;
639 struct stat s;
640 bfd_byte *data;
641 rc_uint_type i;
642 rc_res_resource *r;
644 e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
646 if (stat (real_filename, &s) < 0)
647 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
648 strerror (errno));
650 data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
652 for (i = 0; i < BITMAP_SKIP; i++)
653 getc (e);
655 get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
657 fclose (e);
658 free (real_filename);
660 r = define_standard_resource (&resources, RT_BITMAP, id,
661 resinfo->language, 0);
663 r->type = RES_TYPE_BITMAP;
664 r->u.data.length = s.st_size - BITMAP_SKIP;
665 r->u.data.data = data;
666 r->res_info = *resinfo;
669 /* Define a cursor resource. A cursor file may contain a set of
670 bitmaps, each representing the same cursor at various different
671 resolutions. They each get written out with a different ID. The
672 real cursor resource is then a group resource which can be used to
673 select one of the actual cursors. */
675 void
676 define_cursor (rc_res_id id, const rc_res_res_info *resinfo,
677 const char *filename)
679 FILE *e;
680 char *real_filename;
681 int type, count, i;
682 struct icondir *icondirs;
683 int first_cursor;
684 rc_res_resource *r;
685 rc_group_cursor *first, **pp;
687 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
689 /* A cursor file is basically an icon file. The start of the file
690 is a three word structure. The first word is ignored. The
691 second word is the type of data. The third word is the number of
692 entries. */
694 get_word (e, real_filename);
695 type = get_word (e, real_filename);
696 count = get_word (e, real_filename);
697 if (type != 2)
698 fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
700 /* Read in the icon directory entries. */
702 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
704 for (i = 0; i < count; i++)
706 icondirs[i].width = getc (e);
707 icondirs[i].height = getc (e);
708 icondirs[i].colorcount = getc (e);
709 getc (e);
710 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
711 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
712 icondirs[i].bytes = get_long (e, real_filename);
713 icondirs[i].offset = get_long (e, real_filename);
715 if (feof (e))
716 unexpected_eof (real_filename);
719 /* Define each cursor as a unique resource. */
721 first_cursor = cursors;
723 for (i = 0; i < count; i++)
725 bfd_byte *data;
726 rc_res_id name;
727 rc_cursor *c;
729 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
730 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
731 icondirs[i].offset, strerror (errno));
733 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
735 get_data (e, data, icondirs[i].bytes, real_filename);
737 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
738 c->xhotspot = icondirs[i].u.cursor.xhotspot;
739 c->yhotspot = icondirs[i].u.cursor.yhotspot;
740 c->length = icondirs[i].bytes;
741 c->data = data;
743 ++cursors;
745 name.named = 0;
746 name.u.id = cursors;
748 r = define_standard_resource (&resources, RT_CURSOR, name,
749 resinfo->language, 0);
750 r->type = RES_TYPE_CURSOR;
751 r->u.cursor = c;
752 r->res_info = *resinfo;
755 fclose (e);
756 free (real_filename);
758 /* Define a cursor group resource. */
760 first = NULL;
761 pp = &first;
762 for (i = 0; i < count; i++)
764 rc_group_cursor *cg;
766 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
767 cg->next = NULL;
768 cg->width = icondirs[i].width;
769 cg->height = 2 * icondirs[i].height;
771 /* FIXME: What should these be set to? */
772 cg->planes = 1;
773 cg->bits = 1;
775 cg->bytes = icondirs[i].bytes + 4;
776 cg->index = first_cursor + i + 1;
778 *pp = cg;
779 pp = &(*pp)->next;
782 free (icondirs);
784 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
785 resinfo->language, 0);
786 r->type = RES_TYPE_GROUP_CURSOR;
787 r->u.group_cursor = first;
788 r->res_info = *resinfo;
791 /* Define a dialog resource. */
793 void
794 define_dialog (rc_res_id id, const rc_res_res_info *resinfo,
795 const rc_dialog *dialog)
797 rc_dialog *copy;
798 rc_res_resource *r;
800 copy = (rc_dialog *) res_alloc (sizeof *copy);
801 *copy = *dialog;
803 r = define_standard_resource (&resources, RT_DIALOG, id,
804 resinfo->language, 0);
805 r->type = RES_TYPE_DIALOG;
806 r->u.dialog = copy;
807 r->res_info = *resinfo;
810 /* Define a dialog control. This does not define a resource, but
811 merely allocates and fills in a structure. */
813 rc_dialog_control *
814 define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
815 rc_uint_type y, rc_uint_type width, rc_uint_type height,
816 const rc_res_id class, rc_uint_type style,
817 rc_uint_type exstyle)
819 rc_dialog_control *n;
821 n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
822 n->next = NULL;
823 n->id = id;
824 n->style = style;
825 n->exstyle = exstyle;
826 n->x = x;
827 n->y = y;
828 n->width = width;
829 n->height = height;
830 n->class = class;
831 n->text = iid;
832 n->data = NULL;
833 n->help = 0;
835 return n;
838 rc_dialog_control *
839 define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
840 rc_uint_type y, rc_uint_type style,
841 rc_uint_type exstyle, rc_uint_type help,
842 rc_rcdata_item *data, rc_dialog_ex *ex)
844 rc_dialog_control *n;
845 rc_res_id tid;
846 rc_res_id cid;
848 if (style == 0)
849 style = SS_ICON | WS_CHILD | WS_VISIBLE;
850 res_string_to_id (&tid, "");
851 cid.named = 0;
852 cid.u.id = CTL_STATIC;
853 n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
854 n->text = iid;
855 if (help && ! ex)
856 rcparse_warning (_("help ID requires DIALOGEX"));
857 if (data && ! ex)
858 rcparse_warning (_("control data requires DIALOGEX"));
859 n->help = help;
860 n->data = data;
862 return n;
865 /* Define a font resource. */
867 void
868 define_font (rc_res_id id, const rc_res_res_info *resinfo,
869 const char *filename)
871 FILE *e;
872 char *real_filename;
873 struct stat s;
874 bfd_byte *data;
875 rc_res_resource *r;
876 long offset;
877 long fontdatalength;
878 bfd_byte *fontdata;
879 rc_fontdir *fd;
880 const char *device, *face;
881 rc_fontdir **pp;
883 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
885 if (stat (real_filename, &s) < 0)
886 fatal (_("stat failed on font file `%s': %s"), real_filename,
887 strerror (errno));
889 data = (bfd_byte *) res_alloc (s.st_size);
891 get_data (e, data, s.st_size, real_filename);
893 fclose (e);
894 free (real_filename);
896 r = define_standard_resource (&resources, RT_FONT, id,
897 resinfo->language, 0);
899 r->type = RES_TYPE_FONT;
900 r->u.data.length = s.st_size;
901 r->u.data.data = data;
902 r->res_info = *resinfo;
904 /* For each font resource, we must add an entry in the FONTDIR
905 resource. The FONTDIR resource includes some strings in the font
906 file. To find them, we have to do some magic on the data we have
907 read. */
909 offset = ((((((data[47] << 8)
910 | data[46]) << 8)
911 | data[45]) << 8)
912 | data[44]);
913 if (offset > 0 && offset < s.st_size)
914 device = (char *) data + offset;
915 else
916 device = "";
918 offset = ((((((data[51] << 8)
919 | data[50]) << 8)
920 | data[49]) << 8)
921 | data[48]);
922 if (offset > 0 && offset < s.st_size)
923 face = (char *) data + offset;
924 else
925 face = "";
927 ++fonts;
929 fontdatalength = 58 + strlen (device) + strlen (face);
930 fontdata = (bfd_byte *) res_alloc (fontdatalength);
931 memcpy (fontdata, data, 56);
932 strcpy ((char *) fontdata + 56, device);
933 strcpy ((char *) fontdata + 57 + strlen (device), face);
935 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
936 fd->next = NULL;
937 fd->index = fonts;
938 fd->length = fontdatalength;
939 fd->data = fontdata;
941 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
943 *pp = fd;
945 /* For the single fontdirs resource, we always use the resource
946 information of the last font. I don't know what else to do. */
947 fontdirs_resinfo = *resinfo;
950 static void
951 define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
952 rc_rcdata_item *data)
954 rc_res_resource *r;
955 rc_uint_type len_data;
956 bfd_byte *pb_data;
958 r = define_standard_resource (&resources, RT_FONT, id,
959 resinfo->language, 0);
961 pb_data = rcdata_render_as_buffer (data, &len_data);
963 r->type = RES_TYPE_FONT;
964 r->u.data.length = len_data;
965 r->u.data.data = pb_data;
966 r->res_info = *resinfo;
969 /* Define the fontdirs resource. This is called after the entire rc
970 file has been parsed, if any font resources were seen. */
972 static void
973 define_fontdirs (void)
975 rc_res_resource *r;
976 rc_res_id id;
978 id.named = 0;
979 id.u.id = 1;
981 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
983 r->type = RES_TYPE_FONTDIR;
984 r->u.fontdir = fontdirs;
985 r->res_info = fontdirs_resinfo;
988 static bfd_byte *
989 rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
991 const rc_rcdata_item *d;
992 bfd_byte *ret = NULL, *pret;
993 rc_uint_type len = 0;
995 for (d = data; d != NULL; d = d->next)
996 len += rcdata_copy (d, NULL);
997 if (len != 0)
999 ret = pret = (bfd_byte *) res_alloc (len);
1000 for (d = data; d != NULL; d = d->next)
1001 pret += rcdata_copy (d, pret);
1003 if (plen)
1004 *plen = len;
1005 return ret;
1008 static void
1009 define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1010 rc_rcdata_item *data)
1012 rc_res_resource *r;
1013 rc_fontdir *fd, *fd_first, *fd_cur;
1014 rc_uint_type len_data;
1015 bfd_byte *pb_data;
1016 rc_uint_type c;
1018 fd_cur = fd_first = NULL;
1019 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1021 pb_data = rcdata_render_as_buffer (data, &len_data);
1023 if (pb_data)
1025 rc_uint_type off = 2;
1026 c = windres_get_16 (&wrtarget, pb_data, len_data);
1027 for (; c > 0; c--)
1029 size_t len;
1030 rc_uint_type safe_pos = off;
1031 const struct bin_fontdir_item *bfi;
1033 bfi = (const struct bin_fontdir_item *) pb_data + off;
1034 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1035 fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
1036 fd->data = pb_data + off;
1037 off += 56;
1038 len = strlen ((char *) bfi->device_name) + 1;
1039 off += (rc_uint_type) len;
1040 off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
1041 fd->length = (off - safe_pos);
1042 fd->next = NULL;
1043 if (fd_first == NULL)
1044 fd_first = fd;
1045 else
1046 fd_cur->next = fd;
1047 fd_cur = fd;
1050 r->type = RES_TYPE_FONTDIR;
1051 r->u.fontdir = fd_first;
1052 r->res_info = *resinfo;
1055 static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1056 rc_rcdata_item *data)
1058 rc_res_resource *r;
1059 rc_uint_type len_data;
1060 bfd_byte *pb_data;
1062 r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
1064 pb_data = rcdata_render_as_buffer (data, &len_data);
1065 r->type = RES_TYPE_MESSAGETABLE;
1066 r->u.data.length = len_data;
1067 r->u.data.data = pb_data;
1068 r->res_info = *resinfo;
1071 /* Define an icon resource. An icon file may contain a set of
1072 bitmaps, each representing the same icon at various different
1073 resolutions. They each get written out with a different ID. The
1074 real icon resource is then a group resource which can be used to
1075 select one of the actual icon bitmaps. */
1077 void
1078 define_icon (rc_res_id id, const rc_res_res_info *resinfo,
1079 const char *filename)
1081 FILE *e;
1082 char *real_filename;
1083 int type, count, i;
1084 struct icondir *icondirs;
1085 int first_icon;
1086 rc_res_resource *r;
1087 rc_group_icon *first, **pp;
1089 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1091 /* The start of an icon file is a three word structure. The first
1092 word is ignored. The second word is the type of data. The third
1093 word is the number of entries. */
1095 get_word (e, real_filename);
1096 type = get_word (e, real_filename);
1097 count = get_word (e, real_filename);
1098 if (type != 1)
1099 fatal (_("icon file `%s' does not contain icon data"), real_filename);
1101 /* Read in the icon directory entries. */
1103 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1105 for (i = 0; i < count; i++)
1107 icondirs[i].width = getc (e);
1108 icondirs[i].height = getc (e);
1109 icondirs[i].colorcount = getc (e);
1110 getc (e);
1111 icondirs[i].u.icon.planes = get_word (e, real_filename);
1112 icondirs[i].u.icon.bits = get_word (e, real_filename);
1113 icondirs[i].bytes = get_long (e, real_filename);
1114 icondirs[i].offset = get_long (e, real_filename);
1116 if (feof (e))
1117 unexpected_eof (real_filename);
1120 /* Define each icon as a unique resource. */
1122 first_icon = icons;
1124 for (i = 0; i < count; i++)
1126 bfd_byte *data;
1127 rc_res_id name;
1129 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1130 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1131 icondirs[i].offset, strerror (errno));
1133 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
1135 get_data (e, data, icondirs[i].bytes, real_filename);
1137 ++icons;
1139 name.named = 0;
1140 name.u.id = icons;
1142 r = define_standard_resource (&resources, RT_ICON, name,
1143 resinfo->language, 0);
1144 r->type = RES_TYPE_ICON;
1145 r->u.data.length = icondirs[i].bytes;
1146 r->u.data.data = data;
1147 r->res_info = *resinfo;
1150 fclose (e);
1151 free (real_filename);
1153 /* Define an icon group resource. */
1155 first = NULL;
1156 pp = &first;
1157 for (i = 0; i < count; i++)
1159 rc_group_icon *cg;
1161 /* For some reason, at least in some files the planes and bits
1162 are zero. We instead set them from the color. This is
1163 copied from rcl. */
1165 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1166 cg->next = NULL;
1167 cg->width = icondirs[i].width;
1168 cg->height = icondirs[i].height;
1169 cg->colors = icondirs[i].colorcount;
1171 if (icondirs[i].u.icon.planes)
1172 cg->planes = icondirs[i].u.icon.planes;
1173 else
1174 cg->planes = 1;
1176 if (icondirs[i].u.icon.bits)
1177 cg->bits = icondirs[i].u.icon.bits;
1178 else
1180 cg->bits = 0;
1182 while ((1L << cg->bits) < cg->colors)
1183 ++cg->bits;
1186 cg->bytes = icondirs[i].bytes;
1187 cg->index = first_icon + i + 1;
1189 *pp = cg;
1190 pp = &(*pp)->next;
1193 free (icondirs);
1195 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1196 resinfo->language, 0);
1197 r->type = RES_TYPE_GROUP_ICON;
1198 r->u.group_icon = first;
1199 r->res_info = *resinfo;
1202 static void
1203 define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1204 rc_rcdata_item *data)
1206 rc_res_resource *r;
1207 rc_group_icon *cg, *first, *cur;
1208 rc_uint_type len_data;
1209 bfd_byte *pb_data;
1211 pb_data = rcdata_render_as_buffer (data, &len_data);
1213 cur = NULL;
1214 first = NULL;
1216 while (len_data >= 6)
1218 int c, i;
1219 unsigned short type;
1220 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1221 if (type != 1)
1222 fatal (_("unexpected group icon type %d"), type);
1223 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1224 len_data -= 6;
1225 pb_data += 6;
1227 for (i = 0; i < c; i++)
1229 if (len_data < 14)
1230 fatal ("too small group icon rcdata");
1231 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1232 cg->next = NULL;
1233 cg->width = pb_data[0];
1234 cg->height = pb_data[1];
1235 cg->colors = pb_data[2];
1236 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1237 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1238 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1239 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1240 if (! first)
1241 first = cg;
1242 else
1243 cur->next = cg;
1244 cur = cg;
1245 pb_data += 14;
1246 len_data -= 14;
1249 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1250 resinfo->language, 0);
1251 r->type = RES_TYPE_GROUP_ICON;
1252 r->u.group_icon = first;
1253 r->res_info = *resinfo;
1256 static void
1257 define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1258 rc_rcdata_item *data)
1260 rc_res_resource *r;
1261 rc_group_cursor *cg, *first, *cur;
1262 rc_uint_type len_data;
1263 bfd_byte *pb_data;
1265 pb_data = rcdata_render_as_buffer (data, &len_data);
1267 first = cur = NULL;
1269 while (len_data >= 6)
1271 int c, i;
1272 unsigned short type;
1273 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1274 if (type != 2)
1275 fatal (_("unexpected group cursor type %d"), type);
1276 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1277 len_data -= 6;
1278 pb_data += 6;
1280 for (i = 0; i < c; i++)
1282 if (len_data < 14)
1283 fatal ("too small group icon rcdata");
1284 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
1285 cg->next = NULL;
1286 cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
1287 cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1288 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1289 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1290 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1291 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1292 if (! first)
1293 first = cg;
1294 else
1295 cur->next = cg;
1296 cur = cg;
1297 pb_data += 14;
1298 len_data -= 14;
1302 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1303 resinfo->language, 0);
1304 r->type = RES_TYPE_GROUP_CURSOR;
1305 r->u.group_cursor = first;
1306 r->res_info = *resinfo;
1309 static void
1310 define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1311 rc_rcdata_item *data)
1313 rc_cursor *c;
1314 rc_res_resource *r;
1315 rc_uint_type len_data;
1316 bfd_byte *pb_data;
1318 pb_data = rcdata_render_as_buffer (data, &len_data);
1320 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
1321 c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
1322 c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1323 c->length = len_data - BIN_CURSOR_SIZE;
1324 c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
1326 r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
1327 r->type = RES_TYPE_CURSOR;
1328 r->u.cursor = c;
1329 r->res_info = *resinfo;
1332 static void
1333 define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1334 rc_rcdata_item *data)
1336 rc_res_resource *r;
1337 rc_uint_type len_data;
1338 bfd_byte *pb_data;
1340 pb_data = rcdata_render_as_buffer (data, &len_data);
1342 r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
1343 r->type = RES_TYPE_BITMAP;
1344 r->u.data.length = len_data;
1345 r->u.data.data = pb_data;
1346 r->res_info = *resinfo;
1349 static void
1350 define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1351 rc_rcdata_item *data)
1353 rc_res_resource *r;
1354 rc_uint_type len_data;
1355 bfd_byte *pb_data;
1357 pb_data = rcdata_render_as_buffer (data, &len_data);
1359 r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
1360 r->type = RES_TYPE_ICON;
1361 r->u.data.length = len_data;
1362 r->u.data.data = pb_data;
1363 r->res_info = *resinfo;
1366 /* Define a menu resource. */
1368 void
1369 define_menu (rc_res_id id, const rc_res_res_info *resinfo,
1370 rc_menuitem *menuitems)
1372 rc_menu *m;
1373 rc_res_resource *r;
1375 m = (rc_menu *) res_alloc (sizeof (rc_menu));
1376 m->items = menuitems;
1377 m->help = 0;
1379 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1380 r->type = RES_TYPE_MENU;
1381 r->u.menu = m;
1382 r->res_info = *resinfo;
1385 /* Define a menu item. This does not define a resource, but merely
1386 allocates and fills in a structure. */
1388 rc_menuitem *
1389 define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
1390 rc_uint_type state, rc_uint_type help,
1391 rc_menuitem *menuitems)
1393 rc_menuitem *mi;
1395 mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
1396 mi->next = NULL;
1397 mi->type = type;
1398 mi->state = state;
1399 mi->id = menuid;
1400 mi->text = unichar_dup (text);
1401 mi->help = help;
1402 mi->popup = menuitems;
1403 return mi;
1406 /* Define a messagetable resource. */
1408 void
1409 define_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
1410 const char *filename)
1412 FILE *e;
1413 char *real_filename;
1414 struct stat s;
1415 bfd_byte *data;
1416 rc_res_resource *r;
1418 e = open_file_search (filename, FOPEN_RB, "messagetable file",
1419 &real_filename);
1421 if (stat (real_filename, &s) < 0)
1422 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1423 strerror (errno));
1425 data = (bfd_byte *) res_alloc (s.st_size);
1427 get_data (e, data, s.st_size, real_filename);
1429 fclose (e);
1430 free (real_filename);
1432 r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1433 resinfo->language, 0);
1435 r->type = RES_TYPE_MESSAGETABLE;
1436 r->u.data.length = s.st_size;
1437 r->u.data.data = data;
1438 r->res_info = *resinfo;
1441 /* Define an rcdata resource. */
1443 void
1444 define_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1445 rc_rcdata_item *data)
1447 rc_res_resource *r;
1449 r = define_standard_resource (&resources, RT_RCDATA, id,
1450 resinfo->language, 0);
1451 r->type = RES_TYPE_RCDATA;
1452 r->u.rcdata = data;
1453 r->res_info = *resinfo;
1456 /* Create an rcdata item holding a string. */
1458 rc_rcdata_item *
1459 define_rcdata_string (const char *string, rc_uint_type len)
1461 rc_rcdata_item *ri;
1462 char *s;
1464 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1465 ri->next = NULL;
1466 ri->type = RCDATA_STRING;
1467 ri->u.string.length = len;
1468 s = (char *) res_alloc (len);
1469 memcpy (s, string, len);
1470 ri->u.string.s = s;
1472 return ri;
1475 /* Create an rcdata item holding a unicode string. */
1477 rc_rcdata_item *
1478 define_rcdata_unistring (const unichar *string, rc_uint_type len)
1480 rc_rcdata_item *ri;
1481 unichar *s;
1483 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1484 ri->next = NULL;
1485 ri->type = RCDATA_WSTRING;
1486 ri->u.wstring.length = len;
1487 s = (unichar *) res_alloc (len * sizeof (unichar));
1488 memcpy (s, string, len * sizeof (unichar));
1489 ri->u.wstring.w = s;
1491 return ri;
1494 /* Create an rcdata item holding a number. */
1496 rc_rcdata_item *
1497 define_rcdata_number (rc_uint_type val, int dword)
1499 rc_rcdata_item *ri;
1501 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1502 ri->next = NULL;
1503 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1504 ri->u.word = val;
1506 return ri;
1509 /* Define a stringtable resource. This is called for each string
1510 which appears in a STRINGTABLE statement. */
1512 void
1513 define_stringtable (const rc_res_res_info *resinfo,
1514 rc_uint_type stringid, const unichar *string)
1516 rc_res_id id;
1517 rc_res_resource *r;
1519 id.named = 0;
1520 id.u.id = (stringid >> 4) + 1;
1521 r = define_standard_resource (&resources, RT_STRING, id,
1522 resinfo->language, 1);
1524 if (r->type == RES_TYPE_UNINITIALIZED)
1526 int i;
1528 r->type = RES_TYPE_STRINGTABLE;
1529 r->u.stringtable = ((rc_stringtable *)
1530 res_alloc (sizeof (rc_stringtable)));
1531 for (i = 0; i < 16; i++)
1533 r->u.stringtable->strings[i].length = 0;
1534 r->u.stringtable->strings[i].string = NULL;
1537 r->res_info = *resinfo;
1540 r->u.stringtable->strings[stringid & 0xf].length = unichar_len (string);
1541 r->u.stringtable->strings[stringid & 0xf].string = unichar_dup (string);
1544 void
1545 define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
1546 rc_toolbar_item *items)
1548 rc_toolbar *t;
1549 rc_res_resource *r;
1551 t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1552 t->button_width = width;
1553 t->button_height = height;
1554 t->nitems = 0;
1555 t->items = items;
1556 while (items != NULL)
1558 t->nitems+=1;
1559 items = items->next;
1561 r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
1562 r->type = RES_TYPE_TOOLBAR;
1563 r->u.toolbar = t;
1564 r->res_info = *resinfo;
1567 /* Define a user data resource where the data is in the rc file. */
1569 void
1570 define_user_data (rc_res_id id, rc_res_id type,
1571 const rc_res_res_info *resinfo,
1572 rc_rcdata_item *data)
1574 rc_res_id ids[3];
1575 rc_res_resource *r;
1576 bfd_byte *pb_data;
1577 rc_uint_type len_data;
1579 /* We have to check if the binary data is parsed specially. */
1580 if (type.named == 0)
1582 switch (type.u.id)
1584 case RT_FONTDIR:
1585 define_fontdir_rcdata (id, resinfo, data);
1586 return;
1587 case RT_FONT:
1588 define_font_rcdata (id, resinfo, data);
1589 return;
1590 case RT_ICON:
1591 define_icon_rcdata (id, resinfo, data);
1592 return;
1593 case RT_BITMAP:
1594 define_bitmap_rcdata (id, resinfo, data);
1595 return;
1596 case RT_CURSOR:
1597 define_cursor_rcdata (id, resinfo, data);
1598 return;
1599 case RT_GROUP_ICON:
1600 define_group_icon_rcdata (id, resinfo, data);
1601 return;
1602 case RT_GROUP_CURSOR:
1603 define_group_cursor_rcdata (id, resinfo, data);
1604 return;
1605 case RT_MESSAGETABLE:
1606 define_messagetable_rcdata (id, resinfo, data);
1607 return;
1608 default:
1609 /* Treat as normal user-data. */
1610 break;
1613 ids[0] = type;
1614 ids[1] = id;
1615 ids[2].named = 0;
1616 ids[2].u.id = resinfo->language;
1618 r = define_resource (& resources, 3, ids, 0);
1619 r->type = RES_TYPE_USERDATA;
1620 r->u.userdata = ((rc_rcdata_item *)
1621 res_alloc (sizeof (rc_rcdata_item)));
1622 r->u.userdata->next = NULL;
1623 r->u.userdata->type = RCDATA_BUFFER;
1624 pb_data = rcdata_render_as_buffer (data, &len_data);
1625 r->u.userdata->u.buffer.length = len_data;
1626 r->u.userdata->u.buffer.data = pb_data;
1627 r->res_info = *resinfo;
1630 void
1631 define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
1632 const char *filename)
1634 rc_rcdata_item *ri;
1635 FILE *e;
1636 char *real_filename;
1637 struct stat s;
1638 bfd_byte *data;
1640 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1643 if (stat (real_filename, &s) < 0)
1644 fatal (_("stat failed on file `%s': %s"), real_filename,
1645 strerror (errno));
1647 data = (bfd_byte *) res_alloc (s.st_size);
1649 get_data (e, data, s.st_size, real_filename);
1651 fclose (e);
1652 free (real_filename);
1654 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1655 ri->next = NULL;
1656 ri->type = RCDATA_BUFFER;
1657 ri->u.buffer.length = s.st_size;
1658 ri->u.buffer.data = data;
1660 define_rcdata (id, resinfo, ri);
1663 /* Define a user data resource where the data is in a file. */
1665 void
1666 define_user_file (rc_res_id id, rc_res_id type,
1667 const rc_res_res_info *resinfo, const char *filename)
1669 FILE *e;
1670 char *real_filename;
1671 struct stat s;
1672 bfd_byte *data;
1673 rc_res_id ids[3];
1674 rc_res_resource *r;
1676 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1678 if (stat (real_filename, &s) < 0)
1679 fatal (_("stat failed on file `%s': %s"), real_filename,
1680 strerror (errno));
1682 data = (bfd_byte *) res_alloc (s.st_size);
1684 get_data (e, data, s.st_size, real_filename);
1686 fclose (e);
1687 free (real_filename);
1689 ids[0] = type;
1690 ids[1] = id;
1691 ids[2].named = 0;
1692 ids[2].u.id = resinfo->language;
1694 r = define_resource (&resources, 3, ids, 0);
1695 r->type = RES_TYPE_USERDATA;
1696 r->u.userdata = ((rc_rcdata_item *)
1697 res_alloc (sizeof (rc_rcdata_item)));
1698 r->u.userdata->next = NULL;
1699 r->u.userdata->type = RCDATA_BUFFER;
1700 r->u.userdata->u.buffer.length = s.st_size;
1701 r->u.userdata->u.buffer.data = data;
1702 r->res_info = *resinfo;
1705 /* Define a versioninfo resource. */
1707 void
1708 define_versioninfo (rc_res_id id, rc_uint_type language,
1709 rc_fixed_versioninfo *fixedverinfo,
1710 rc_ver_info *verinfo)
1712 rc_res_resource *r;
1714 r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1715 r->type = RES_TYPE_VERSIONINFO;
1716 r->u.versioninfo = ((rc_versioninfo *)
1717 res_alloc (sizeof (rc_versioninfo)));
1718 r->u.versioninfo->fixed = fixedverinfo;
1719 r->u.versioninfo->var = verinfo;
1720 r->res_info.language = language;
1723 /* Add string version info to a list of version information. */
1725 rc_ver_info *
1726 append_ver_stringfileinfo (rc_ver_info *verinfo, const char *language,
1727 rc_ver_stringinfo *strings)
1729 rc_ver_info *vi, **pp;
1731 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
1732 vi->next = NULL;
1733 vi->type = VERINFO_STRING;
1734 unicode_from_ascii ((rc_uint_type *) NULL, &vi->u.string.language, language);
1735 vi->u.string.strings = strings;
1737 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1739 *pp = vi;
1741 return verinfo;
1744 /* Add variable version info to a list of version information. */
1746 rc_ver_info *
1747 append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
1748 rc_ver_varinfo *var)
1750 rc_ver_info *vi, **pp;
1752 vi = (rc_ver_info *) res_alloc (sizeof *vi);
1753 vi->next = NULL;
1754 vi->type = VERINFO_VAR;
1755 vi->u.var.key = unichar_dup (key);
1756 vi->u.var.var = var;
1758 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1760 *pp = vi;
1762 return verinfo;
1765 /* Append version string information to a list. */
1767 rc_ver_stringinfo *
1768 append_verval (rc_ver_stringinfo *strings, const unichar *key,
1769 const unichar *value)
1771 rc_ver_stringinfo *vs, **pp;
1773 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
1774 vs->next = NULL;
1775 vs->key = unichar_dup (key);
1776 vs->value = unichar_dup (value);
1778 for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1780 *pp = vs;
1782 return strings;
1785 /* Append version variable information to a list. */
1787 rc_ver_varinfo *
1788 append_vertrans (rc_ver_varinfo *var, rc_uint_type language,
1789 rc_uint_type charset)
1791 rc_ver_varinfo *vv, **pp;
1793 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
1794 vv->next = NULL;
1795 vv->language = language;
1796 vv->charset = charset;
1798 for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1800 *pp = vv;
1802 return var;
1805 /* Local functions used to write out an rc file. */
1807 static void indent (FILE *, int);
1808 static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
1809 const rc_res_id *, rc_uint_type *, int);
1810 static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
1811 const rc_res_id *, rc_uint_type *, int);
1812 static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
1813 const rc_res_resource *, rc_uint_type *);
1814 static void write_rc_accelerators (FILE *, const rc_accelerator *);
1815 static void write_rc_cursor (FILE *, const rc_cursor *);
1816 static void write_rc_group_cursor (FILE *, const rc_group_cursor *);
1817 static void write_rc_dialog (FILE *, const rc_dialog *);
1818 static void write_rc_dialog_control (FILE *, const rc_dialog_control *);
1819 static void write_rc_fontdir (FILE *, const rc_fontdir *);
1820 static void write_rc_group_icon (FILE *, const rc_group_icon *);
1821 static void write_rc_menu (FILE *, const rc_menu *, int);
1822 static void write_rc_toolbar (FILE *, const rc_toolbar *);
1823 static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
1824 static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
1826 static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
1827 static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
1828 static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
1829 static void write_rc_versioninfo (FILE *, const rc_versioninfo *);
1831 /* Indent a given number of spaces. */
1833 static void
1834 indent (FILE *e, int c)
1836 int i;
1838 for (i = 0; i < c; i++)
1839 putc (' ', e);
1842 /* Dump the resources we have read in the format of an rc file.
1844 Reasoned by the fact, that some resources need to be stored into file and
1845 refer to that file, we use the user-data model for that to express it binary
1846 without the need to store it somewhere externally. */
1848 void
1849 write_rc_file (const char *filename, const rc_res_directory *resources)
1851 FILE *e;
1852 rc_uint_type language;
1854 if (filename == NULL)
1855 e = stdout;
1856 else
1858 e = fopen (filename, FOPEN_WT);
1859 if (e == NULL)
1860 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1863 language = (rc_uint_type) ((bfd_signed_vma) -1);
1864 write_rc_directory (e, resources, (const rc_res_id *) NULL,
1865 (const rc_res_id *) NULL, &language, 1);
1868 /* Write out a directory. E is the file to write to. RD is the
1869 directory. TYPE is a pointer to the level 1 ID which serves as the
1870 resource type. NAME is a pointer to the level 2 ID which serves as
1871 an individual resource name. LANGUAGE is a pointer to the current
1872 language. LEVEL is the level in the tree. */
1874 static void
1875 write_rc_directory (FILE *e, const rc_res_directory *rd,
1876 const rc_res_id *type, const rc_res_id *name,
1877 rc_uint_type *language, int level)
1879 const rc_res_entry *re;
1881 /* Print out some COFF information that rc files can't represent. */
1882 if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
1884 wr_printcomment (e, "COFF information not part of RC");
1885 if (rd->time != 0)
1886 wr_printcomment (e, "Time stamp: %u", rd->time);
1887 if (rd->characteristics != 0)
1888 wr_printcomment (e, "Characteristics: %u", rd->characteristics);
1889 if (rd->major != 0 || rd->minor != 0)
1890 wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
1893 for (re = rd->entries; re != NULL; re = re->next)
1895 switch (level)
1897 case 1:
1898 /* If we're at level 1, the key of this resource is the
1899 type. This normally duplicates the information we have
1900 stored with the resource itself, but we need to remember
1901 the type if this is a user define resource type. */
1902 type = &re->id;
1903 break;
1905 case 2:
1906 /* If we're at level 2, the key of this resource is the name
1907 we are going to use in the rc printout. */
1908 name = &re->id;
1909 break;
1911 case 3:
1912 /* If we're at level 3, then this key represents a language.
1913 Use it to update the current language. */
1914 if (! re->id.named
1915 && re->id.u.id != (unsigned long) (unsigned int) *language
1916 && (re->id.u.id & 0xffff) == re->id.u.id)
1918 wr_print (e, "LANGUAGE %u, %u\n",
1919 re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
1920 (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
1921 *language = re->id.u.id;
1923 break;
1925 default:
1926 break;
1929 if (re->subdir)
1930 write_rc_subdir (e, re, type, name, language, level);
1931 else
1933 if (level == 3)
1935 /* This is the normal case: the three levels are
1936 TYPE/NAME/LANGUAGE. NAME will have been set at level
1937 2, and represents the name to use. We probably just
1938 set LANGUAGE, and it will probably match what the
1939 resource itself records if anything. */
1940 write_rc_resource (e, type, name, re->u.res, language);
1942 else
1944 wr_printcomment (e, "Resource at unexpected level %d", level);
1945 write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
1946 language);
1950 if (rd->entries == NULL)
1952 wr_print_flush (e);
1956 /* Write out a subdirectory entry. E is the file to write to. RE is
1957 the subdirectory entry. TYPE and NAME are pointers to higher level
1958 IDs, or NULL. LANGUAGE is a pointer to the current language.
1959 LEVEL is the level in the tree. */
1961 static void
1962 write_rc_subdir (FILE *e, const rc_res_entry *re,
1963 const rc_res_id *type, const rc_res_id *name,
1964 rc_uint_type *language, int level)
1966 fprintf (e, "\n");
1967 switch (level)
1969 case 1:
1970 wr_printcomment (e, "Type: ");
1971 if (re->id.named)
1972 res_id_print (e, re->id, 1);
1973 else
1975 const char *s;
1977 switch (re->id.u.id)
1979 case RT_CURSOR: s = "cursor"; break;
1980 case RT_BITMAP: s = "bitmap"; break;
1981 case RT_ICON: s = "icon"; break;
1982 case RT_MENU: s = "menu"; break;
1983 case RT_DIALOG: s = "dialog"; break;
1984 case RT_STRING: s = "stringtable"; break;
1985 case RT_FONTDIR: s = "fontdir"; break;
1986 case RT_FONT: s = "font"; break;
1987 case RT_ACCELERATOR: s = "accelerators"; break;
1988 case RT_RCDATA: s = "rcdata"; break;
1989 case RT_MESSAGETABLE: s = "messagetable"; break;
1990 case RT_GROUP_CURSOR: s = "group cursor"; break;
1991 case RT_GROUP_ICON: s = "group icon"; break;
1992 case RT_VERSION: s = "version"; break;
1993 case RT_DLGINCLUDE: s = "dlginclude"; break;
1994 case RT_PLUGPLAY: s = "plugplay"; break;
1995 case RT_VXD: s = "vxd"; break;
1996 case RT_ANICURSOR: s = "anicursor"; break;
1997 case RT_ANIICON: s = "aniicon"; break;
1998 case RT_TOOLBAR: s = "toolbar"; break;
1999 case RT_HTML: s = "html"; break;
2000 default: s = NULL; break;
2003 if (s != NULL)
2004 fprintf (e, "%s", s);
2005 else
2006 res_id_print (e, re->id, 1);
2008 break;
2010 case 2:
2011 wr_printcomment (e, "Name: ");
2012 res_id_print (e, re->id, 1);
2013 break;
2015 case 3:
2016 wr_printcomment (e, "Language: ");
2017 res_id_print (e, re->id, 1);
2018 break;
2020 default:
2021 wr_printcomment (e, "Level %d: ", level);
2022 res_id_print (e, re->id, 1);
2025 write_rc_directory (e, re->u.dir, type, name, language, level + 1);
2028 /* Write out a single resource. E is the file to write to. TYPE is a
2029 pointer to the type of the resource. NAME is a pointer to the name
2030 of the resource; it will be NULL if there is a level mismatch. RES
2031 is the resource data. LANGUAGE is a pointer to the current
2032 language. */
2034 static void
2035 write_rc_resource (FILE *e, const rc_res_id *type,
2036 const rc_res_id *name, const rc_res_resource *res,
2037 rc_uint_type *language)
2039 const char *s;
2040 int rt;
2041 int menuex = 0;
2043 switch (res->type)
2045 default:
2046 abort ();
2048 case RES_TYPE_ACCELERATOR:
2049 s = "ACCELERATORS";
2050 rt = RT_ACCELERATOR;
2051 break;
2053 case RES_TYPE_BITMAP:
2054 s = "2 /* RT_BITMAP */";
2055 rt = RT_BITMAP;
2056 break;
2058 case RES_TYPE_CURSOR:
2059 s = "1 /* RT_CURSOR */";
2060 rt = RT_CURSOR;
2061 break;
2063 case RES_TYPE_GROUP_CURSOR:
2064 s = "12 /* RT_GROUP_CURSOR */";
2065 rt = RT_GROUP_CURSOR;
2066 break;
2068 case RES_TYPE_DIALOG:
2069 if (extended_dialog (res->u.dialog))
2070 s = "DIALOGEX";
2071 else
2072 s = "DIALOG";
2073 rt = RT_DIALOG;
2074 break;
2076 case RES_TYPE_FONT:
2077 s = "8 /* RT_FONT */";
2078 rt = RT_FONT;
2079 break;
2081 case RES_TYPE_FONTDIR:
2082 s = "7 /* RT_FONTDIR */";
2083 rt = RT_FONTDIR;
2084 break;
2086 case RES_TYPE_ICON:
2087 s = "3 /* RT_ICON */";
2088 rt = RT_ICON;
2089 break;
2091 case RES_TYPE_GROUP_ICON:
2092 s = "14 /* RT_GROUP_ICON */";
2093 rt = RT_GROUP_ICON;
2094 break;
2096 case RES_TYPE_MENU:
2097 if (extended_menu (res->u.menu))
2099 s = "MENUEX";
2100 menuex = 1;
2102 else
2104 s = "MENU";
2105 menuex = 0;
2107 rt = RT_MENU;
2108 break;
2110 case RES_TYPE_MESSAGETABLE:
2111 s = "11 /* RT_MESSAGETABLE */";
2112 rt = RT_MESSAGETABLE;
2113 break;
2115 case RES_TYPE_RCDATA:
2116 s = "RCDATA";
2117 rt = RT_RCDATA;
2118 break;
2120 case RES_TYPE_STRINGTABLE:
2121 s = "STRINGTABLE";
2122 rt = RT_STRING;
2123 break;
2125 case RES_TYPE_USERDATA:
2126 s = NULL;
2127 rt = 0;
2128 break;
2130 case RES_TYPE_VERSIONINFO:
2131 s = "VERSIONINFO";
2132 rt = RT_VERSION;
2133 break;
2135 case RES_TYPE_TOOLBAR:
2136 s = "TOOLBAR";
2137 rt = RT_TOOLBAR;
2138 break;
2141 if (rt != 0
2142 && type != NULL
2143 && (type->named || type->u.id != (unsigned long) rt))
2145 wr_printcomment (e, "Unexpected resource type mismatch: ");
2146 res_id_print (e, *type, 1);
2147 fprintf (e, " != %d", rt);
2150 if (res->coff_info.codepage != 0)
2151 wr_printcomment (e, "Code page: %u", res->coff_info.codepage);
2152 if (res->coff_info.reserved != 0)
2153 wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved);
2155 wr_print (e, "\n");
2156 if (rt == RT_STRING)
2158 else
2160 if (name != NULL)
2161 res_id_print (e, *name, 1);
2162 else
2163 fprintf (e, "??Unknown-Name??");
2164 fprintf (e, " ");
2167 if (s != NULL)
2168 fprintf (e, "%s", s);
2169 else if (type != NULL)
2171 if (type->named == 0)
2173 #define PRINT_RT_NAME(NAME) case NAME: \
2174 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2175 break
2177 switch (type->u.id)
2179 default:
2180 res_id_print (e, *type, 0);
2181 break;
2183 PRINT_RT_NAME(RT_MANIFEST);
2184 PRINT_RT_NAME(RT_ANICURSOR);
2185 PRINT_RT_NAME(RT_ANIICON);
2186 PRINT_RT_NAME(RT_RCDATA);
2187 PRINT_RT_NAME(RT_ICON);
2188 PRINT_RT_NAME(RT_CURSOR);
2189 PRINT_RT_NAME(RT_BITMAP);
2190 PRINT_RT_NAME(RT_PLUGPLAY);
2191 PRINT_RT_NAME(RT_VXD);
2192 PRINT_RT_NAME(RT_FONT);
2193 PRINT_RT_NAME(RT_FONTDIR);
2194 PRINT_RT_NAME(RT_HTML);
2195 PRINT_RT_NAME(RT_MESSAGETABLE);
2196 PRINT_RT_NAME(RT_DLGINCLUDE);
2197 PRINT_RT_NAME(RT_DLGINIT);
2199 #undef PRINT_RT_NAME
2201 else
2202 res_id_print (e, *type, 1);
2204 else
2205 fprintf (e, "??Unknown-Type??");
2207 if (res->res_info.memflags != 0)
2209 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
2210 fprintf (e, " MOVEABLE");
2211 if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
2212 fprintf (e, " PURE");
2213 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
2214 fprintf (e, " PRELOAD");
2215 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
2216 fprintf (e, " DISCARDABLE");
2219 if (res->type == RES_TYPE_DIALOG)
2221 fprintf (e, " %d, %d, %d, %d",
2222 (int) res->u.dialog->x, (int) res->u.dialog->y,
2223 (int) res->u.dialog->width, (int) res->u.dialog->height);
2224 if (res->u.dialog->ex != NULL
2225 && res->u.dialog->ex->help != 0)
2226 fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help);
2228 else if (res->type == RES_TYPE_TOOLBAR)
2230 fprintf (e, " %d, %d", (int) res->u.toolbar->button_width,
2231 (int) res->u.toolbar->button_height);
2234 fprintf (e, "\n");
2236 if ((res->res_info.language != 0 && res->res_info.language != *language)
2237 || res->res_info.characteristics != 0
2238 || res->res_info.version != 0)
2240 int modifiers;
2242 switch (res->type)
2244 case RES_TYPE_ACCELERATOR:
2245 case RES_TYPE_DIALOG:
2246 case RES_TYPE_MENU:
2247 case RES_TYPE_RCDATA:
2248 case RES_TYPE_STRINGTABLE:
2249 modifiers = 1;
2250 break;
2252 default:
2253 modifiers = 0;
2254 break;
2257 if (res->res_info.language != 0 && res->res_info.language != *language)
2258 fprintf (e, "%sLANGUAGE %d, %d\n",
2259 modifiers ? "// " : "",
2260 (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
2261 (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
2262 if (res->res_info.characteristics != 0)
2263 fprintf (e, "%sCHARACTERISTICS %u\n",
2264 modifiers ? "// " : "",
2265 (unsigned int) res->res_info.characteristics);
2266 if (res->res_info.version != 0)
2267 fprintf (e, "%sVERSION %u\n",
2268 modifiers ? "// " : "",
2269 (unsigned int) res->res_info.version);
2272 switch (res->type)
2274 default:
2275 abort ();
2277 case RES_TYPE_ACCELERATOR:
2278 write_rc_accelerators (e, res->u.acc);
2279 break;
2281 case RES_TYPE_CURSOR:
2282 write_rc_cursor (e, res->u.cursor);
2283 break;
2285 case RES_TYPE_GROUP_CURSOR:
2286 write_rc_group_cursor (e, res->u.group_cursor);
2287 break;
2289 case RES_TYPE_DIALOG:
2290 write_rc_dialog (e, res->u.dialog);
2291 break;
2293 case RES_TYPE_FONTDIR:
2294 write_rc_fontdir (e, res->u.fontdir);
2295 break;
2297 case RES_TYPE_GROUP_ICON:
2298 write_rc_group_icon (e, res->u.group_icon);
2299 break;
2301 case RES_TYPE_MENU:
2302 write_rc_menu (e, res->u.menu, menuex);
2303 break;
2305 case RES_TYPE_RCDATA:
2306 write_rc_rcdata (e, res->u.rcdata, 0);
2307 break;
2309 case RES_TYPE_STRINGTABLE:
2310 write_rc_stringtable (e, name, res->u.stringtable);
2311 break;
2313 case RES_TYPE_USERDATA:
2314 write_rc_rcdata (e, res->u.userdata, 0);
2315 break;
2317 case RES_TYPE_TOOLBAR:
2318 write_rc_toolbar (e, res->u.toolbar);
2319 break;
2321 case RES_TYPE_VERSIONINFO:
2322 write_rc_versioninfo (e, res->u.versioninfo);
2323 break;
2325 case RES_TYPE_BITMAP:
2326 case RES_TYPE_FONT:
2327 case RES_TYPE_ICON:
2328 write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0);
2329 break;
2330 case RES_TYPE_MESSAGETABLE:
2331 write_rc_messagetable (e, res->u.data.length, res->u.data.data);
2332 break;
2336 /* Write out accelerator information. */
2338 static void
2339 write_rc_accelerators (FILE *e, const rc_accelerator *accelerators)
2341 const rc_accelerator *acc;
2343 fprintf (e, "BEGIN\n");
2344 for (acc = accelerators; acc != NULL; acc = acc->next)
2346 int printable;
2348 fprintf (e, " ");
2350 if ((acc->key & 0x7f) == acc->key
2351 && ISPRINT (acc->key)
2352 && (acc->flags & ACC_VIRTKEY) == 0)
2354 fprintf (e, "\"%c\"", (char) acc->key);
2355 printable = 1;
2357 else
2359 fprintf (e, "%d", (int) acc->key);
2360 printable = 0;
2363 fprintf (e, ", %d", (int) acc->id);
2365 if (! printable)
2367 if ((acc->flags & ACC_VIRTKEY) != 0)
2368 fprintf (e, ", VIRTKEY");
2369 else
2370 fprintf (e, ", ASCII");
2373 if ((acc->flags & ACC_SHIFT) != 0)
2374 fprintf (e, ", SHIFT");
2375 if ((acc->flags & ACC_CONTROL) != 0)
2376 fprintf (e, ", CONTROL");
2377 if ((acc->flags & ACC_ALT) != 0)
2378 fprintf (e, ", ALT");
2380 fprintf (e, "\n");
2383 fprintf (e, "END\n");
2386 /* Write out cursor information. This would normally be in a separate
2387 file, which the rc file would include. */
2389 static void
2390 write_rc_cursor (FILE *e, const rc_cursor *cursor)
2392 fprintf (e, "BEGIN\n");
2393 indent (e, 2);
2394 fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2395 (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot,
2396 (int) cursor->xhotspot, (int) cursor->yhotspot);
2397 write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data,
2398 0, 0, 0);
2399 fprintf (e, "END\n");
2402 /* Write out group cursor data. This would normally be built from the
2403 cursor data. */
2405 static void
2406 write_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor)
2408 const rc_group_cursor *gc;
2409 int c;
2411 for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2413 fprintf (e, "BEGIN\n");
2415 indent (e, 2);
2416 fprintf (e, "0, 2, %d%s\t /* Having %d items. */\n", c, (c != 0 ? "," : ""), c);
2417 indent (e, 4);
2418 fprintf (e, "/* width, height, planes, bits, bytes, index. */\n");
2420 for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2422 indent (e, 4);
2423 fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2424 (int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits,
2425 (unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c);
2426 fprintf (e, "/* width: %d; height %d; planes %d; bits %d. */\n",
2427 (int) gc->width, (int) gc->height, (int) gc->planes,
2428 (int) gc->bits);
2430 fprintf (e, "END\n");
2433 /* Write dialog data. */
2435 static void
2436 write_rc_dialog (FILE *e, const rc_dialog *dialog)
2438 const rc_dialog_control *control;
2440 fprintf (e, "STYLE 0x%x\n", dialog->style);
2442 if (dialog->exstyle != 0)
2443 fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle);
2445 if ((dialog->class.named && dialog->class.u.n.length > 0)
2446 || dialog->class.u.id != 0)
2448 fprintf (e, "CLASS ");
2449 res_id_print (e, dialog->class, 1);
2450 fprintf (e, "\n");
2453 if (dialog->caption != NULL)
2455 fprintf (e, "CAPTION ");
2456 unicode_print_quoted (e, dialog->caption, -1);
2457 fprintf (e, "\n");
2460 if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2461 || dialog->menu.u.id != 0)
2463 fprintf (e, "MENU ");
2464 res_id_print (e, dialog->menu, 0);
2465 fprintf (e, "\n");
2468 if (dialog->font != NULL)
2470 fprintf (e, "FONT %d, ", (int) dialog->pointsize);
2471 unicode_print_quoted (e, dialog->font, -1);
2472 if (dialog->ex != NULL
2473 && (dialog->ex->weight != 0
2474 || dialog->ex->italic != 0
2475 || dialog->ex->charset != 1))
2476 fprintf (e, ", %d, %d, %d",
2477 (int) dialog->ex->weight,
2478 (int) dialog->ex->italic,
2479 (int) dialog->ex->charset);
2480 fprintf (e, "\n");
2483 fprintf (e, "BEGIN\n");
2485 for (control = dialog->controls; control != NULL; control = control->next)
2486 write_rc_dialog_control (e, control);
2488 fprintf (e, "END\n");
2491 /* For each predefined control keyword, this table provides the class
2492 and the style. */
2494 struct control_info
2496 const char *name;
2497 unsigned short class;
2498 unsigned long style;
2501 static const struct control_info control_info[] =
2503 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2504 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2505 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2506 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2507 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2508 { "CTEXT", CTL_STATIC, SS_CENTER },
2509 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2510 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2511 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2512 { "ICON", CTL_STATIC, SS_ICON },
2513 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2514 { "LTEXT", CTL_STATIC, SS_LEFT },
2515 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2516 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2517 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2518 { "RTEXT", CTL_STATIC, SS_RIGHT },
2519 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2520 { "STATE3", CTL_BUTTON, BS_3STATE },
2521 /* It's important that USERBUTTON come after all the other button
2522 types, so that it won't be matched too early. */
2523 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2524 { NULL, 0, 0 }
2527 /* Write a dialog control. */
2529 static void
2530 write_rc_dialog_control (FILE *e, const rc_dialog_control *control)
2532 const struct control_info *ci;
2534 fprintf (e, " ");
2536 if (control->class.named)
2537 ci = NULL;
2538 else
2540 for (ci = control_info; ci->name != NULL; ++ci)
2541 if (ci->class == control->class.u.id
2542 && (ci->style == (unsigned long) -1
2543 || ci->style == (control->style & 0xff)))
2544 break;
2546 if (ci == NULL)
2547 fprintf (e, "CONTROL");
2548 else if (ci->name != NULL)
2549 fprintf (e, "%s", ci->name);
2550 else
2552 fprintf (e, "CONTROL");
2553 ci = NULL;
2556 if (control->text.named || control->text.u.id != 0)
2558 fprintf (e, " ");
2559 res_id_print (e, control->text, 1);
2560 fprintf (e, ",");
2563 fprintf (e, " %d, ", (int) control->id);
2565 if (ci == NULL)
2567 if (control->class.named)
2568 fprintf (e, "\"");
2569 res_id_print (e, control->class, 0);
2570 if (control->class.named)
2571 fprintf (e, "\"");
2572 fprintf (e, ", 0x%x, ", (unsigned int) control->style);
2575 fprintf (e, "%d, %d", (int) control->x, (int) control->y);
2577 if (control->style != SS_ICON
2578 || control->exstyle != 0
2579 || control->width != 0
2580 || control->height != 0
2581 || control->help != 0)
2583 fprintf (e, ", %d, %d", (int) control->width, (int) control->height);
2585 /* FIXME: We don't need to print the style if it is the default.
2586 More importantly, in certain cases we actually need to turn
2587 off parts of the forced style, by using NOT. */
2588 if (ci != NULL)
2589 fprintf (e, ", 0x%x", (unsigned int) control->style);
2591 if (control->exstyle != 0 || control->help != 0)
2592 fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle,
2593 (unsigned int) control->help);
2596 fprintf (e, "\n");
2598 if (control->data != NULL)
2599 write_rc_rcdata (e, control->data, 2);
2602 /* Write out font directory data. This would normally be built from
2603 the font data. */
2605 static void
2606 write_rc_fontdir (FILE *e, const rc_fontdir *fontdir)
2608 const rc_fontdir *fc;
2609 int c;
2611 for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++)
2613 fprintf (e, "BEGIN\n");
2614 indent (e, 2);
2615 fprintf (e, "%d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2616 for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++)
2618 indent (e, 4);
2619 fprintf (e, "%d,\t/* Font no %d with index %d. */\n",
2620 (int) fc->index, c, (int) fc->index);
2621 write_rc_datablock (e, (rc_uint_type) fc->length - 2,
2622 (const bfd_byte *) fc->data + 4,fc->next != NULL,
2623 0, 0);
2625 fprintf (e, "END\n");
2628 /* Write out group icon data. This would normally be built from the
2629 icon data. */
2631 static void
2632 write_rc_group_icon (FILE *e, const rc_group_icon *group_icon)
2634 const rc_group_icon *gi;
2635 int c;
2637 for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++)
2640 fprintf (e, "BEGIN\n");
2641 indent (e, 2);
2642 fprintf (e, " 0, 1, %d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2644 indent (e, 4);
2645 fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2646 for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++)
2648 indent (e, 4);
2649 fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2650 gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits,
2651 (unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c);
2653 fprintf (e, "END\n");
2656 /* Write out a menu resource. */
2658 static void
2659 write_rc_menu (FILE *e, const rc_menu *menu, int menuex)
2661 if (menu->help != 0)
2662 fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help);
2663 write_rc_menuitems (e, menu->items, menuex, 0);
2666 static void
2667 write_rc_toolbar (FILE *e, const rc_toolbar *tb)
2669 rc_toolbar_item *it;
2670 indent (e, 0);
2671 fprintf (e, "BEGIN\n");
2672 it = tb->items;
2673 while(it != NULL)
2675 indent (e, 2);
2676 if (it->id.u.id == 0)
2677 fprintf (e, "SEPARATOR\n");
2678 else
2679 fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
2680 it = it->next;
2682 indent (e, 0);
2683 fprintf (e, "END\n");
2686 /* Write out menuitems. */
2688 static void
2689 write_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex,
2690 int ind)
2692 const rc_menuitem *mi;
2694 indent (e, ind);
2695 fprintf (e, "BEGIN\n");
2697 for (mi = menuitems; mi != NULL; mi = mi->next)
2699 indent (e, ind + 2);
2701 if (mi->popup == NULL)
2702 fprintf (e, "MENUITEM");
2703 else
2704 fprintf (e, "POPUP");
2706 if (! menuex
2707 && mi->popup == NULL
2708 && mi->text == NULL
2709 && mi->type == 0
2710 && mi->id == 0)
2712 fprintf (e, " SEPARATOR\n");
2713 continue;
2716 if (mi->text == NULL)
2717 fprintf (e, " \"\"");
2718 else
2720 fprintf (e, " ");
2721 unicode_print_quoted (e, mi->text, -1);
2724 if (! menuex)
2726 if (mi->popup == NULL)
2727 fprintf (e, ", %d", (int) mi->id);
2729 if ((mi->type & MENUITEM_CHECKED) != 0)
2730 fprintf (e, ", CHECKED");
2731 if ((mi->type & MENUITEM_GRAYED) != 0)
2732 fprintf (e, ", GRAYED");
2733 if ((mi->type & MENUITEM_HELP) != 0)
2734 fprintf (e, ", HELP");
2735 if ((mi->type & MENUITEM_INACTIVE) != 0)
2736 fprintf (e, ", INACTIVE");
2737 if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2738 fprintf (e, ", MENUBARBREAK");
2739 if ((mi->type & MENUITEM_MENUBREAK) != 0)
2740 fprintf (e, ", MENUBREAK");
2742 else
2744 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2746 fprintf (e, ", %d", (int) mi->id);
2747 if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2749 fprintf (e, ", %u", (unsigned int) mi->type);
2750 if (mi->state != 0 || mi->help != 0)
2752 fprintf (e, ", %u", (unsigned int) mi->state);
2753 if (mi->help != 0)
2754 fprintf (e, ", %u", (unsigned int) mi->help);
2760 fprintf (e, "\n");
2762 if (mi->popup != NULL)
2763 write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2766 indent (e, ind);
2767 fprintf (e, "END\n");
2770 static int
2771 test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
2773 rc_uint_type i;
2774 if ((length & 1) != 0)
2775 return 0;
2777 for (i = 0; i < length; i += 2)
2779 if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2780 return 0;
2781 if (data[i] == 0xff && data[i + 1] == 0xff)
2782 return 0;
2784 return 1;
2787 static int
2788 test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2790 int has_nl;
2791 rc_uint_type c;
2792 rc_uint_type i;
2794 if (length <= 1)
2795 return 0;
2797 has_nl = 0;
2798 for (i = 0, c = 0; i < length; i++)
2800 if (! ISPRINT (data[i]) && data[i] != '\n'
2801 && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2802 && data[i] != '\t'
2803 && ! (data[i] == 0 && (i + 1) != length))
2805 if (data[i] <= 7)
2806 return 0;
2807 c++;
2809 else if (data[i] == '\n') has_nl++;
2811 if (length > 80 && ! has_nl)
2812 return 0;
2813 c = (((c * 10000) + (i / 100) - 1)) / i;
2814 if (c >= 150)
2815 return 0;
2816 return 1;
2819 static void
2820 write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
2822 int has_error = 0;
2823 const struct bin_messagetable *mt;
2824 fprintf (e, "BEGIN\n");
2826 write_rc_datablock (e, length, data, 0, 0, 0);
2828 fprintf (e, "\n");
2829 wr_printcomment (e, "MC syntax dump");
2830 if (length < BIN_MESSAGETABLE_SIZE)
2831 has_error = 1;
2832 else
2833 do {
2834 rc_uint_type m, i;
2835 mt = (const struct bin_messagetable *) data;
2836 m = windres_get_32 (&wrtarget, mt->cblocks, length);
2837 if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2839 has_error = 1;
2840 break;
2842 for (i = 0; i < m; i++)
2844 rc_uint_type low, high, offset;
2845 const struct bin_messagetable_item *mti;
2847 low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2848 high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2849 offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2850 while (low <= high)
2852 rc_uint_type elen, flags;
2853 if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2855 has_error = 1;
2856 break;
2858 mti = (const struct bin_messagetable_item *) &data[offset];
2859 elen = windres_get_16 (&wrtarget, mti->length, 2);
2860 flags = windres_get_16 (&wrtarget, mti->flags, 2);
2861 if ((offset + elen) > length)
2863 has_error = 1;
2864 break;
2866 wr_printcomment (e, "MessageId = 0x%x", low);
2867 wr_printcomment (e, "");
2868 if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2869 unicode_print (e, (const unichar *) mti->data,
2870 (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2871 else
2872 ascii_print (e, (const char *) mti->data,
2873 (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2874 wr_printcomment (e,"");
2875 ++low;
2876 offset += elen;
2879 } while (0);
2880 if (has_error)
2881 wr_printcomment (e, "Illegal data");
2882 wr_print_flush (e);
2883 fprintf (e, "END\n");
2886 static void
2887 write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
2888 int hasblock, int show_comment)
2890 int plen;
2892 if (hasblock)
2893 fprintf (e, "BEGIN\n");
2895 if (show_comment == -1)
2897 if (test_rc_datablock_text(length, data))
2899 rc_uint_type i, c;
2900 for (i = 0; i < length;)
2902 indent (e, 2);
2903 fprintf (e, "\"");
2905 for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
2907 if (i < length && data[i] == '\n')
2908 ++i, ++c;
2909 ascii_print (e, (const char *) &data[i - c], c);
2910 fprintf (e, "\"");
2911 if (i < length)
2912 fprintf (e, "\n");
2915 if (i == 0)
2917 indent (e, 2);
2918 fprintf (e, "\"\"");
2920 if (has_next)
2921 fprintf (e, ",");
2922 fprintf (e, "\n");
2923 if (hasblock)
2924 fprintf (e, "END\n");
2925 return;
2927 if (test_rc_datablock_unicode (length, data))
2929 rc_uint_type i, c;
2930 for (i = 0; i < length;)
2932 const unichar *u;
2934 u = (const unichar *) &data[i];
2935 indent (e, 2);
2936 fprintf (e, "L\"");
2938 for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
2940 if (i < length && u[c] == '\n')
2941 i += 2, ++c;
2942 unicode_print (e, u, c);
2943 fprintf (e, "\"");
2944 if (i < length)
2945 fprintf (e, "\n");
2948 if (i == 0)
2950 indent (e, 2);
2951 fprintf (e, "L\"\"");
2953 if (has_next)
2954 fprintf (e, ",");
2955 fprintf (e, "\n");
2956 if (hasblock)
2957 fprintf (e, "END\n");
2958 return;
2961 show_comment = 0;
2964 if (length != 0)
2966 rc_uint_type i, max_row;
2967 int first = 1;
2969 max_row = (show_comment ? 4 : 8);
2970 indent (e, 2);
2971 for (i = 0; i + 3 < length;)
2973 rc_uint_type k;
2974 rc_uint_type comment_start;
2976 comment_start = i;
2978 if (! first)
2979 indent (e, 2);
2981 for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
2983 if (k == 0)
2984 plen = fprintf (e, "0x%lxL",
2985 (long) windres_get_32 (&wrtarget, data + i, length - i));
2986 else
2987 plen = fprintf (e, " 0x%lxL",
2988 (long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
2989 if (has_next || (i + 4) < length)
2991 if (plen>0 && plen < 11)
2992 indent (e, 11 - plen);
2993 fprintf (e, ",");
2996 if (show_comment)
2998 fprintf (e, "\t/* ");
2999 ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3000 fprintf (e, ". */");
3002 fprintf (e, "\n");
3003 first = 0;
3006 if (i + 1 < length)
3008 if (! first)
3009 indent (e, 2);
3010 plen = fprintf (e, "0x%x",
3011 (int) windres_get_16 (&wrtarget, data + i, length - i));
3012 if (has_next || i + 2 < length)
3014 if (plen > 0 && plen < 11)
3015 indent (e, 11 - plen);
3016 fprintf (e, ",");
3018 if (show_comment)
3020 fprintf (e, "\t/* ");
3021 ascii_print (e, (const char *) &data[i], 2);
3022 fprintf (e, ". */");
3024 fprintf (e, "\n");
3025 i += 2;
3026 first = 0;
3029 if (i < length)
3031 if (! first)
3032 indent (e, 2);
3033 fprintf (e, "\"");
3034 ascii_print (e, (const char *) &data[i], 1);
3035 fprintf (e, "\"");
3036 if (has_next)
3037 fprintf (e, ",");
3038 fprintf (e, "\n");
3039 first = 0;
3042 if (hasblock)
3043 fprintf (e, "END\n");
3046 /* Write out an rcdata resource. This is also used for other types of
3047 resources that need to print arbitrary data. */
3049 static void
3050 write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3052 const rc_rcdata_item *ri;
3054 indent (e, ind);
3055 fprintf (e, "BEGIN\n");
3057 for (ri = rcdata; ri != NULL; ri = ri->next)
3059 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3060 continue;
3062 switch (ri->type)
3064 default:
3065 abort ();
3067 case RCDATA_WORD:
3068 indent (e, ind + 2);
3069 fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3070 break;
3072 case RCDATA_DWORD:
3073 indent (e, ind + 2);
3074 fprintf (e, "%luL", (unsigned long) ri->u.dword);
3075 break;
3077 case RCDATA_STRING:
3078 indent (e, ind + 2);
3079 fprintf (e, "\"");
3080 ascii_print (e, ri->u.string.s, ri->u.string.length);
3081 fprintf (e, "\"");
3082 break;
3084 case RCDATA_WSTRING:
3085 indent (e, ind + 2);
3086 fprintf (e, "L\"");
3087 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3088 fprintf (e, "\"");
3089 break;
3091 case RCDATA_BUFFER:
3092 write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3093 (const bfd_byte *) ri->u.buffer.data,
3094 ri->next != NULL, 0, -1);
3095 break;
3098 if (ri->type != RCDATA_BUFFER)
3100 if (ri->next != NULL)
3101 fprintf (e, ",");
3102 fprintf (e, "\n");
3106 indent (e, ind);
3107 fprintf (e, "END\n");
3110 /* Write out a stringtable resource. */
3112 static void
3113 write_rc_stringtable (FILE *e, const rc_res_id *name,
3114 const rc_stringtable *stringtable)
3116 rc_uint_type offset;
3117 int i;
3119 if (name != NULL && ! name->named)
3120 offset = (name->u.id - 1) << 4;
3121 else
3123 fprintf (e, "/* %s string table name. */\n",
3124 name == NULL ? "Missing" : "Invalid");
3125 offset = 0;
3128 fprintf (e, "BEGIN\n");
3130 for (i = 0; i < 16; i++)
3132 if (stringtable->strings[i].length != 0)
3134 fprintf (e, " %lu, ", (long) offset + i);
3135 unicode_print_quoted (e, stringtable->strings[i].string,
3136 stringtable->strings[i].length);
3137 fprintf (e, "\n");
3141 fprintf (e, "END\n");
3144 /* Write out a versioninfo resource. */
3146 static void
3147 write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
3149 const rc_fixed_versioninfo *f;
3150 const rc_ver_info *vi;
3152 f = versioninfo->fixed;
3153 if (f->file_version_ms != 0 || f->file_version_ls != 0)
3154 fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3155 (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3156 (unsigned int) (f->file_version_ms & 0xffff),
3157 (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3158 (unsigned int) (f->file_version_ls & 0xffff));
3159 if (f->product_version_ms != 0 || f->product_version_ls != 0)
3160 fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3161 (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3162 (unsigned int) (f->product_version_ms & 0xffff),
3163 (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3164 (unsigned int) (f->product_version_ls & 0xffff));
3165 if (f->file_flags_mask != 0)
3166 fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
3167 if (f->file_flags != 0)
3168 fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
3169 if (f->file_os != 0)
3170 fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
3171 if (f->file_type != 0)
3172 fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
3173 if (f->file_subtype != 0)
3174 fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
3175 if (f->file_date_ms != 0 || f->file_date_ls != 0)
3176 fprintf (e, "/* Date: %u, %u. */\n",
3177 (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
3179 fprintf (e, "BEGIN\n");
3181 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3183 switch (vi->type)
3185 case VERINFO_STRING:
3187 const rc_ver_stringinfo *vs;
3189 fprintf (e, " BLOCK \"StringFileInfo\"\n");
3190 fprintf (e, " BEGIN\n");
3191 fprintf (e, " BLOCK ");
3192 unicode_print_quoted (e, vi->u.string.language, -1);
3193 fprintf (e, "\n");
3194 fprintf (e, " BEGIN\n");
3196 for (vs = vi->u.string.strings; vs != NULL; vs = vs->next)
3198 fprintf (e, " VALUE ");
3199 unicode_print_quoted (e, vs->key, -1);
3200 fprintf (e, ", ");
3201 unicode_print_quoted (e, vs->value, -1);
3202 fprintf (e, "\n");
3205 fprintf (e, " END\n");
3206 fprintf (e, " END\n");
3207 break;
3210 case VERINFO_VAR:
3212 const rc_ver_varinfo *vv;
3214 fprintf (e, " BLOCK \"VarFileInfo\"\n");
3215 fprintf (e, " BEGIN\n");
3216 fprintf (e, " VALUE ");
3217 unicode_print_quoted (e, vi->u.var.key, -1);
3219 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3220 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
3221 (int) vv->charset);
3223 fprintf (e, "\n END\n");
3225 break;
3230 fprintf (e, "END\n");
3233 static rc_uint_type
3234 rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
3236 if (! src)
3237 return 0;
3238 switch (src->type)
3240 case RCDATA_WORD:
3241 if (dst)
3242 windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3243 return 2;
3244 case RCDATA_DWORD:
3245 if (dst)
3246 windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3247 return 4;
3248 case RCDATA_STRING:
3249 if (dst && src->u.string.length)
3250 memcpy (dst, src->u.string.s, src->u.string.length);
3251 return (rc_uint_type) src->u.string.length;
3252 case RCDATA_WSTRING:
3253 if (dst && src->u.wstring.length)
3254 memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3255 return (rc_uint_type) (src->u.wstring.length * sizeof (unichar));
3256 case RCDATA_BUFFER:
3257 if (dst && src->u.buffer.length)
3258 memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3259 return (rc_uint_type) src->u.buffer.length;
3260 default:
3261 abort ();
3263 /* Never reached. */
3264 return 0;