2012-11-09 Yao Qi <yao@codesourcery.com>
[deliverable/binutils-gdb.git] / binutils / resrc.c
CommitLineData
252b5132 1/* resrc.c -- read and write Windows rc files.
bfb6c1ab 2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008, 2011
b09a7772 3 Free Software Foundation, Inc.
252b5132 4 Written by Ian Lance Taylor, Cygnus Support.
4a594fce 5 Rewritten by Kai Tietz, Onevision.
252b5132
RH
6
7 This file is part of GNU Binutils.
8
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
32866df7 11 the Free Software Foundation; either version 3 of the License, or
252b5132
RH
12 (at your option) any later version.
13
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.
18
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
b43b5d5f
NC
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
22 02110-1301, USA. */
252b5132
RH
23
24/* This file contains functions that read and write Windows rc files.
25 These are text files that represent resources. */
26
3db64b00 27#include "sysdep.h"
252b5132 28#include "bfd.h"
4a594fce 29#include "bucomm.h"
252b5132 30#include "libiberty.h"
3882b010 31#include "safe-ctype.h"
252b5132
RH
32#include "windres.h"
33
34#include <assert.h>
5a298d2d
NC
35
36#ifdef HAVE_SYS_WAIT_H
37#include <sys/wait.h>
38#else /* ! HAVE_SYS_WAIT_H */
39#if ! defined (_WIN32) || defined (__CYGWIN__)
40#ifndef WIFEXITED
41#define WIFEXITED(w) (((w)&0377) == 0)
42#endif
43#ifndef WIFSIGNALED
44#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0)
45#endif
46#ifndef WTERMSIG
47#define WTERMSIG(w) ((w) & 0177)
48#endif
49#ifndef WEXITSTATUS
50#define WEXITSTATUS(w) (((w) >> 8) & 0377)
51#endif
52#else /* defined (_WIN32) && ! defined (__CYGWIN__) */
53#ifndef WIFEXITED
54#define WIFEXITED(w) (((w) & 0xff) == 0)
55#endif
56#ifndef WIFSIGNALED
57#define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f)
58#endif
59#ifndef WTERMSIG
60#define WTERMSIG(w) ((w) & 0x7f)
61#endif
62#ifndef WEXITSTATUS
63#define WEXITSTATUS(w) (((w) & 0xff00) >> 8)
64#endif
65#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */
66#endif /* ! HAVE_SYS_WAIT_H */
252b5132 67
5a298d2d
NC
68#ifndef STDOUT_FILENO
69#define STDOUT_FILENO 1
70#endif
53c7db4b 71
5a298d2d 72#if defined (_WIN32) && ! defined (__CYGWIN__)
252b5132
RH
73#define popen _popen
74#define pclose _pclose
75#endif
76
77/* The default preprocessor. */
78
2efaf10b 79#define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED"
252b5132
RH
80
81/* We read the directory entries in a cursor or icon file into
82 instances of this structure. */
83
84struct icondir
85{
86 /* Width of image. */
4a594fce 87 bfd_byte width;
252b5132 88 /* Height of image. */
4a594fce 89 bfd_byte height;
252b5132 90 /* Number of colors in image. */
4a594fce 91 bfd_byte colorcount;
252b5132
RH
92 union
93 {
94 struct
95 {
96 /* Color planes. */
97 unsigned short planes;
98 /* Bits per pixel. */
99 unsigned short bits;
100 } icon;
101 struct
102 {
103 /* X coordinate of hotspot. */
104 unsigned short xhotspot;
105 /* Y coordinate of hotspot. */
106 unsigned short yhotspot;
107 } cursor;
108 } u;
109 /* Bytes in image. */
110 unsigned long bytes;
111 /* File offset of image. */
112 unsigned long offset;
113};
114
115/* The name of the rc file we are reading. */
116
117char *rc_filename;
118
119/* The line number in the rc file. */
120
121int rc_lineno;
122
123/* The pipe we are reading from, so that we can close it if we exit. */
124
4a594fce 125FILE *cpp_pipe;
252b5132 126
5a298d2d
NC
127/* The temporary file used if we're not using popen, so we can delete it
128 if we exit. */
129
130static char *cpp_temp_file;
131
91eafb40 132/* Input stream is either a file or a pipe. */
5a298d2d
NC
133
134static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type;
135
252b5132
RH
136/* As we read the rc file, we attach information to this structure. */
137
4a594fce 138static rc_res_directory *resources;
252b5132
RH
139
140/* The number of cursor resources we have written out. */
141
142static int cursors;
143
144/* The number of font resources we have written out. */
145
146static int fonts;
147
148/* Font directory information. */
149
4a594fce 150rc_fontdir *fontdirs;
252b5132
RH
151
152/* Resource info to use for fontdirs. */
153
4a594fce 154rc_res_res_info fontdirs_resinfo;
252b5132
RH
155
156/* The number of icon resources we have written out. */
157
158static int icons;
159
4a594fce
NC
160/* The windres target bfd . */
161
162static windres_bfd wrtarget =
163{
164 (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET
165};
166
167/* Local functions for rcdata based resource definitions. */
168
169static void define_font_rcdata (rc_res_id, const rc_res_res_info *,
170 rc_rcdata_item *);
171static void define_icon_rcdata (rc_res_id, const rc_res_res_info *,
172 rc_rcdata_item *);
173static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *,
174 rc_rcdata_item *);
175static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *,
176 rc_rcdata_item *);
177static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *,
178 rc_rcdata_item *);
179static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *,
180 rc_rcdata_item *);
181static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *);
182static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *);
252b5132 183
2da42df6
AJ
184static int run_cmd (char *, const char *);
185static FILE *open_input_stream (char *);
186static FILE *look_for_default
187 (char *, const char *, int, const char *, const char *);
188static void close_input_stream (void);
189static void unexpected_eof (const char *);
190static int get_word (FILE *, const char *);
191static unsigned long get_long (FILE *, const char *);
4a594fce 192static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *);
2da42df6 193static void define_fontdirs (void);
252b5132 194\f
df3baf66 195/* Run `cmd' and redirect the output to `redir'. */
5a298d2d
NC
196
197static int
2da42df6 198run_cmd (char *cmd, const char *redir)
5a298d2d
NC
199{
200 char *s;
201 int pid, wait_status, retcode;
202 int i;
203 const char **argv;
204 char *errmsg_fmt, *errmsg_arg;
205 char *temp_base = choose_temp_base ();
206 int in_quote;
207 char sep;
208 int redir_handle = -1;
209 int stdout_save = -1;
210
211 /* Count the args. */
212 i = 0;
53c7db4b 213
5a298d2d
NC
214 for (s = cmd; *s; s++)
215 if (*s == ' ')
216 i++;
53c7db4b 217
5a298d2d
NC
218 i++;
219 argv = alloca (sizeof (char *) * (i + 3));
220 i = 0;
221 s = cmd;
53c7db4b 222
5a298d2d
NC
223 while (1)
224 {
225 while (*s == ' ' && *s != 0)
226 s++;
53c7db4b 227
5a298d2d
NC
228 if (*s == 0)
229 break;
53c7db4b 230
5a298d2d
NC
231 in_quote = (*s == '\'' || *s == '"');
232 sep = (in_quote) ? *s++ : ' ';
233 argv[i++] = s;
53c7db4b 234
5a298d2d
NC
235 while (*s != sep && *s != 0)
236 s++;
53c7db4b 237
5a298d2d
NC
238 if (*s == 0)
239 break;
53c7db4b 240
5a298d2d 241 *s++ = 0;
53c7db4b 242
5a298d2d 243 if (in_quote)
53c7db4b 244 s++;
5a298d2d
NC
245 }
246 argv[i++] = NULL;
247
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. */
250
251 fflush (stdout);
252 fflush (stderr);
253
254 /* Open temporary output file. */
255 redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666);
256 if (redir_handle == -1)
53c7db4b
KH
257 fatal (_("can't open temporary file `%s': %s"), redir,
258 strerror (errno));
5a298d2d
NC
259
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));
264
265 /* Redirect stdout to our output file. */
266 dup2 (redir_handle, STDOUT_FILENO);
267
268 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base,
269 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH);
270
271 /* Restore stdout to its previous setting. */
272 dup2 (stdout_save, STDOUT_FILENO);
273
50c2245b 274 /* Close response file. */
5a298d2d
NC
275 close (redir_handle);
276
277 if (pid == -1)
278 {
cc5914eb 279 fatal ("%s %s: %s", errmsg_fmt, errmsg_arg, strerror (errno));
5a298d2d
NC
280 return 1;
281 }
282
283 retcode = 0;
284 pid = pwait (pid, &wait_status, 0);
53c7db4b 285
5a298d2d
NC
286 if (pid == -1)
287 {
288 fatal (_("wait: %s"), strerror (errno));
289 retcode = 1;
290 }
291 else if (WIFSIGNALED (wait_status))
292 {
293 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status));
294 retcode = 1;
295 }
296 else if (WIFEXITED (wait_status))
297 {
298 if (WEXITSTATUS (wait_status) != 0)
299 {
53c7db4b 300 fatal (_("%s exited with status %d"), cmd,
5a298d2d
NC
301 WEXITSTATUS (wait_status));
302 retcode = 1;
303 }
304 }
305 else
306 retcode = 1;
53c7db4b 307
5a298d2d
NC
308 return retcode;
309}
310
311static FILE *
2da42df6 312open_input_stream (char *cmd)
5a298d2d
NC
313{
314 if (istream_type == ISTREAM_FILE)
315 {
316 char *fileprefix;
317
318 fileprefix = choose_temp_base ();
319 cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5);
320 sprintf (cpp_temp_file, "%s.irc", fileprefix);
321 free (fileprefix);
322
323 if (run_cmd (cmd, cpp_temp_file))
324 fatal (_("can't execute `%s': %s"), cmd, strerror (errno));
325
326 cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);;
327 if (cpp_pipe == NULL)
53c7db4b 328 fatal (_("can't open temporary file `%s': %s"),
5a298d2d 329 cpp_temp_file, strerror (errno));
53c7db4b 330
5a298d2d 331 if (verbose)
53c7db4b 332 fprintf (stderr,
5a298d2d
NC
333 _("Using temporary file `%s' to read preprocessor output\n"),
334 cpp_temp_file);
335 }
336 else
337 {
338 cpp_pipe = popen (cmd, FOPEN_RT);
339 if (cpp_pipe == NULL)
53c7db4b 340 fatal (_("can't popen `%s': %s"), cmd, strerror (errno));
5a298d2d
NC
341 if (verbose)
342 fprintf (stderr, _("Using popen to read preprocessor output\n"));
343 }
344
345 xatexit (close_input_stream);
346 return cpp_pipe;
347}
348
4b2c5b4a
NC
349/* Determine if FILENAME contains special characters that
350 can cause problems unless the entire filename is quoted. */
351
352static int
353filename_need_quotes (const char *filename)
354{
355 if (filename == NULL || (filename[0] == '-' && filename[1] == 0))
356 return 0;
357
358 while (*filename != 0)
359 {
360 switch (*filename)
361 {
362 case '&':
363 case ' ':
364 case '<':
365 case '>':
366 case '|':
367 case '%':
368 return 1;
369 }
370 ++filename;
371 }
372 return 0;
373}
374
375/* Look for the preprocessor program. */
751d21b5 376
bb0cb4db 377static FILE *
2da42df6
AJ
378look_for_default (char *cmd, const char *prefix, int end_prefix,
379 const char *preprocargs, const char *filename)
751d21b5 380{
751d21b5
DD
381 char *space;
382 int found;
383 struct stat s;
4b2c5b4a 384 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
751d21b5
DD
385
386 strcpy (cmd, prefix);
387
bb0cb4db
ILT
388 sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR);
389 space = strchr (cmd + end_prefix, ' ');
751d21b5
DD
390 if (space)
391 *space = 0;
392
5a298d2d
NC
393 if (
394#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32)
395 strchr (cmd, '\\') ||
396#endif
397 strchr (cmd, '/'))
751d21b5 398 {
bb0cb4db 399 found = (stat (cmd, &s) == 0
2481e6a2 400#ifdef HAVE_EXECUTABLE_SUFFIX
bb0cb4db
ILT
401 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0
402#endif
403 );
751d21b5 404
bb0cb4db 405 if (! found)
751d21b5
DD
406 {
407 if (verbose)
5a298d2d 408 fprintf (stderr, _("Tried `%s'\n"), cmd);
bb0cb4db 409 return NULL;
751d21b5
DD
410 }
411 }
412
413 strcpy (cmd, prefix);
414
4b2c5b4a
NC
415 sprintf (cmd + end_prefix, "%s %s %s%s%s",
416 DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes);
751d21b5
DD
417
418 if (verbose)
5a298d2d 419 fprintf (stderr, _("Using `%s'\n"), cmd);
751d21b5 420
5a298d2d 421 cpp_pipe = open_input_stream (cmd);
751d21b5
DD
422 return cpp_pipe;
423}
424
252b5132
RH
425/* Read an rc file. */
426
4a594fce 427rc_res_directory *
2da42df6
AJ
428read_rc_file (const char *filename, const char *preprocessor,
429 const char *preprocargs, int language, int use_temp_file)
252b5132
RH
430{
431 char *cmd;
4b2c5b4a 432 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : "");
252b5132 433
a1039809
NC
434 if (filename == NULL)
435 filename = "-";
c6998d15 436 /* Setup the default resource import path taken from input file. */
a1039809 437 else if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL)
c6998d15 438 {
c7f0a8e0 439 char *edit, *dir;
c6998d15
NC
440
441 if (filename[0] == '/'
442 || filename[0] == '\\'
443 || filename[1] == ':')
c7f0a8e0
CD
444 /* Absolute path. */
445 edit = dir = xstrdup (filename);
c6998d15
NC
446 else
447 {
c7f0a8e0
CD
448 /* Relative path. */
449 edit = dir = xmalloc (strlen (filename) + 3);
450 sprintf (dir, "./%s", filename);
c6998d15 451 }
c7f0a8e0
CD
452
453 /* Walk dir backwards stopping at the first directory separator. */
454 edit += strlen (dir);
455 while (edit > dir && (edit[-1] != '\\' && edit[-1] != '/'))
c6998d15 456 {
c7f0a8e0
CD
457 --edit;
458 edit[0] = 0;
c6998d15 459 }
c7f0a8e0 460
c6998d15 461 /* Cut off trailing slash. */
c7f0a8e0
CD
462 --edit;
463 edit[0] = 0;
c6998d15 464
c7f0a8e0
CD
465 /* Convert all back slashes to forward slashes. */
466 while ((edit = strchr (dir, '\\')) != NULL)
467 *edit = '/';
468
469 windres_add_include_dir (dir);
c6998d15
NC
470 }
471
5a298d2d
NC
472 istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE;
473
252b5132
RH
474 if (preprocargs == NULL)
475 preprocargs = "";
252b5132 476
751d21b5
DD
477 if (preprocessor)
478 {
479 cmd = xmalloc (strlen (preprocessor)
480 + strlen (preprocargs)
481 + strlen (filename)
4b2c5b4a 482 + strlen (fnquotes) * 2
751d21b5 483 + 10);
4b2c5b4a
NC
484 sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs,
485 fnquotes, filename, fnquotes);
751d21b5 486
5a298d2d 487 cpp_pipe = open_input_stream (cmd);
751d21b5
DD
488 }
489 else
490 {
491 char *dash, *slash, *cp;
492
493 preprocessor = DEFAULT_PREPROCESSOR;
252b5132 494
751d21b5
DD
495 cmd = xmalloc (strlen (program_name)
496 + strlen (preprocessor)
497 + strlen (preprocargs)
498 + strlen (filename)
4b2c5b4a 499 + strlen (fnquotes) * 2
2481e6a2 500#ifdef HAVE_EXECUTABLE_SUFFIX
bb0cb4db
ILT
501 + strlen (EXECUTABLE_SUFFIX)
502#endif
751d21b5
DD
503 + 10);
504
505
506 dash = slash = 0;
bb0cb4db 507 for (cp = program_name; *cp; cp++)
751d21b5
DD
508 {
509 if (*cp == '-')
510 dash = cp;
511 if (
5a298d2d 512#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32)
751d21b5
DD
513 *cp == ':' || *cp == '\\' ||
514#endif
515 *cp == '/')
516 {
517 slash = cp;
518 dash = 0;
519 }
520 }
521
522 cpp_pipe = 0;
523
524 if (dash)
525 {
526 /* First, try looking for a prefixed gcc in the windres
527 directory, with the same prefix as windres */
528
4a594fce 529 cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1,
751d21b5
DD
530 preprocargs, filename);
531 }
532
4a594fce 533 if (slash && ! cpp_pipe)
751d21b5
DD
534 {
535 /* Next, try looking for a gcc in the same directory as
536 that windres */
537
4a594fce 538 cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1,
751d21b5
DD
539 preprocargs, filename);
540 }
541
4a594fce 542 if (! cpp_pipe)
751d21b5
DD
543 {
544 /* Sigh, try the default */
545
546 cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename);
547 }
548
549 }
53c7db4b 550
252b5132
RH
551 free (cmd);
552
252b5132
RH
553 rc_filename = xstrdup (filename);
554 rc_lineno = 1;
555 if (language != -1)
556 rcparse_set_language (language);
252b5132 557 yyparse ();
405c98a4 558 rcparse_discard_strings ();
252b5132 559
5a298d2d 560 close_input_stream ();
53c7db4b 561
252b5132
RH
562 if (fontdirs != NULL)
563 define_fontdirs ();
564
565 free (rc_filename);
566 rc_filename = NULL;
567
568 return resources;
569}
570
5a298d2d 571/* Close the input stream if it is open. */
252b5132 572
5a298d2d 573static void
2da42df6 574close_input_stream (void)
252b5132 575{
5a298d2d
NC
576 if (istream_type == ISTREAM_FILE)
577 {
578 if (cpp_pipe != NULL)
579 fclose (cpp_pipe);
580
581 if (cpp_temp_file != NULL)
582 {
583 int errno_save = errno;
53c7db4b 584
5a298d2d
NC
585 unlink (cpp_temp_file);
586 errno = errno_save;
587 free (cpp_temp_file);
588 }
589 }
590 else
591 {
592 if (cpp_pipe != NULL)
c7f0a8e0
CD
593 {
594 int err;
595 err = pclose (cpp_pipe);
596 /* We are reading from a pipe, therefore we don't
597 know if cpp failed or succeeded until pclose. */
598 if (err != 0 || errno == ECHILD)
599 {
600 /* Since this is also run via xatexit, safeguard. */
601 cpp_pipe = NULL;
602 cpp_temp_file = NULL;
603 fatal (_("preprocessing failed."));
604 }
605 }
5a298d2d
NC
606 }
607
df3baf66 608 /* Since this is also run via xatexit, safeguard. */
5a298d2d
NC
609 cpp_pipe = NULL;
610 cpp_temp_file = NULL;
252b5132
RH
611}
612
613/* Report an error while reading an rc file. */
614
615void
2da42df6 616yyerror (const char *msg)
252b5132
RH
617{
618 fatal ("%s:%d: %s", rc_filename, rc_lineno, msg);
619}
620
621/* Issue a warning while reading an rc file. */
622
623void
2da42df6 624rcparse_warning (const char *msg)
252b5132 625{
cc5914eb 626 fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg);
252b5132
RH
627}
628
629/* Die if we get an unexpected end of file. */
630
631static void
2da42df6 632unexpected_eof (const char *msg)
252b5132
RH
633{
634 fatal (_("%s: unexpected EOF"), msg);
635}
636
637/* Read a 16 bit word from a file. The data is assumed to be little
638 endian. */
639
640static int
2da42df6 641get_word (FILE *e, const char *msg)
252b5132
RH
642{
643 int b1, b2;
644
645 b1 = getc (e);
646 b2 = getc (e);
647 if (feof (e))
648 unexpected_eof (msg);
649 return ((b2 & 0xff) << 8) | (b1 & 0xff);
650}
651
652/* Read a 32 bit word from a file. The data is assumed to be little
653 endian. */
654
655static unsigned long
2da42df6 656get_long (FILE *e, const char *msg)
252b5132
RH
657{
658 int b1, b2, b3, b4;
659
660 b1 = getc (e);
661 b2 = getc (e);
662 b3 = getc (e);
663 b4 = getc (e);
664 if (feof (e))
665 unexpected_eof (msg);
666 return (((((((b4 & 0xff) << 8)
667 | (b3 & 0xff)) << 8)
668 | (b2 & 0xff)) << 8)
669 | (b1 & 0xff));
670}
671
672/* Read data from a file. This is a wrapper to do error checking. */
673
674static void
4a594fce 675get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg)
252b5132 676{
4a594fce 677 rc_uint_type got; // $$$d
252b5132 678
4a594fce 679 got = (rc_uint_type) fread (p, 1, c, e);
252b5132
RH
680 if (got == c)
681 return;
682
0af1713e
AM
683 fatal (_("%s: read of %lu returned %lu"),
684 msg, (unsigned long) c, (unsigned long) got);
252b5132
RH
685}
686\f
687/* Define an accelerator resource. */
688
689void
4a594fce
NC
690define_accelerator (rc_res_id id, const rc_res_res_info *resinfo,
691 rc_accelerator *data)
252b5132 692{
4a594fce 693 rc_res_resource *r;
252b5132
RH
694
695 r = define_standard_resource (&resources, RT_ACCELERATOR, id,
696 resinfo->language, 0);
697 r->type = RES_TYPE_ACCELERATOR;
698 r->u.acc = data;
699 r->res_info = *resinfo;
700}
701
702/* Define a bitmap resource. Bitmap data is stored in a file. The
703 first 14 bytes of the file are a standard header, which is not
704 included in the resource data. */
705
706#define BITMAP_SKIP (14)
707
708void
4a594fce 709define_bitmap (rc_res_id id, const rc_res_res_info *resinfo,
2da42df6 710 const char *filename)
252b5132
RH
711{
712 FILE *e;
713 char *real_filename;
714 struct stat s;
4a594fce
NC
715 bfd_byte *data;
716 rc_uint_type i;
717 rc_res_resource *r;
252b5132
RH
718
719 e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename);
720
721 if (stat (real_filename, &s) < 0)
722 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
723 strerror (errno));
724
4a594fce 725 data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP);
252b5132
RH
726
727 for (i = 0; i < BITMAP_SKIP; i++)
728 getc (e);
729
730 get_data (e, data, s.st_size - BITMAP_SKIP, real_filename);
731
732 fclose (e);
733 free (real_filename);
734
735 r = define_standard_resource (&resources, RT_BITMAP, id,
736 resinfo->language, 0);
737
738 r->type = RES_TYPE_BITMAP;
739 r->u.data.length = s.st_size - BITMAP_SKIP;
740 r->u.data.data = data;
741 r->res_info = *resinfo;
742}
743
744/* Define a cursor resource. A cursor file may contain a set of
745 bitmaps, each representing the same cursor at various different
746 resolutions. They each get written out with a different ID. The
747 real cursor resource is then a group resource which can be used to
748 select one of the actual cursors. */
749
750void
4a594fce 751define_cursor (rc_res_id id, const rc_res_res_info *resinfo,
2da42df6 752 const char *filename)
252b5132
RH
753{
754 FILE *e;
755 char *real_filename;
756 int type, count, i;
757 struct icondir *icondirs;
758 int first_cursor;
4a594fce
NC
759 rc_res_resource *r;
760 rc_group_cursor *first, **pp;
252b5132
RH
761
762 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename);
763
764 /* A cursor file is basically an icon file. The start of the file
765 is a three word structure. The first word is ignored. The
766 second word is the type of data. The third word is the number of
767 entries. */
768
769 get_word (e, real_filename);
770 type = get_word (e, real_filename);
771 count = get_word (e, real_filename);
772 if (type != 2)
773 fatal (_("cursor file `%s' does not contain cursor data"), real_filename);
774
775 /* Read in the icon directory entries. */
776
777 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
778
779 for (i = 0; i < count; i++)
780 {
781 icondirs[i].width = getc (e);
782 icondirs[i].height = getc (e);
783 icondirs[i].colorcount = getc (e);
784 getc (e);
785 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename);
786 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename);
787 icondirs[i].bytes = get_long (e, real_filename);
788 icondirs[i].offset = get_long (e, real_filename);
789
790 if (feof (e))
791 unexpected_eof (real_filename);
792 }
793
794 /* Define each cursor as a unique resource. */
795
796 first_cursor = cursors;
797
798 for (i = 0; i < count; i++)
799 {
4a594fce
NC
800 bfd_byte *data;
801 rc_res_id name;
802 rc_cursor *c;
252b5132
RH
803
804 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
805 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
806 icondirs[i].offset, strerror (errno));
807
4a594fce 808 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
252b5132
RH
809
810 get_data (e, data, icondirs[i].bytes, real_filename);
811
4a594fce 812 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
252b5132
RH
813 c->xhotspot = icondirs[i].u.cursor.xhotspot;
814 c->yhotspot = icondirs[i].u.cursor.yhotspot;
815 c->length = icondirs[i].bytes;
816 c->data = data;
817
818 ++cursors;
819
820 name.named = 0;
821 name.u.id = cursors;
822
823 r = define_standard_resource (&resources, RT_CURSOR, name,
824 resinfo->language, 0);
825 r->type = RES_TYPE_CURSOR;
826 r->u.cursor = c;
827 r->res_info = *resinfo;
828 }
829
830 fclose (e);
831 free (real_filename);
832
833 /* Define a cursor group resource. */
834
835 first = NULL;
836 pp = &first;
837 for (i = 0; i < count; i++)
838 {
4a594fce 839 rc_group_cursor *cg;
252b5132 840
4a594fce 841 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
252b5132
RH
842 cg->next = NULL;
843 cg->width = icondirs[i].width;
844 cg->height = 2 * icondirs[i].height;
845
846 /* FIXME: What should these be set to? */
847 cg->planes = 1;
848 cg->bits = 1;
849
850 cg->bytes = icondirs[i].bytes + 4;
851 cg->index = first_cursor + i + 1;
852
853 *pp = cg;
854 pp = &(*pp)->next;
855 }
856
857 free (icondirs);
858
859 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id,
860 resinfo->language, 0);
861 r->type = RES_TYPE_GROUP_CURSOR;
862 r->u.group_cursor = first;
863 r->res_info = *resinfo;
864}
865
866/* Define a dialog resource. */
867
868void
4a594fce
NC
869define_dialog (rc_res_id id, const rc_res_res_info *resinfo,
870 const rc_dialog *dialog)
252b5132 871{
4a594fce
NC
872 rc_dialog *copy;
873 rc_res_resource *r;
252b5132 874
4a594fce 875 copy = (rc_dialog *) res_alloc (sizeof *copy);
252b5132
RH
876 *copy = *dialog;
877
878 r = define_standard_resource (&resources, RT_DIALOG, id,
879 resinfo->language, 0);
880 r->type = RES_TYPE_DIALOG;
881 r->u.dialog = copy;
882 r->res_info = *resinfo;
883}
884
885/* Define a dialog control. This does not define a resource, but
886 merely allocates and fills in a structure. */
887
4a594fce
NC
888rc_dialog_control *
889define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x,
890 rc_uint_type y, rc_uint_type width, rc_uint_type height,
891 const rc_res_id class, rc_uint_type style,
892 rc_uint_type exstyle)
252b5132 893{
4a594fce 894 rc_dialog_control *n;
252b5132 895
4a594fce 896 n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control));
252b5132
RH
897 n->next = NULL;
898 n->id = id;
899 n->style = style;
900 n->exstyle = exstyle;
901 n->x = x;
902 n->y = y;
903 n->width = width;
904 n->height = height;
4a594fce 905 n->class = class;
7adbf450 906 n->text = iid;
252b5132
RH
907 n->data = NULL;
908 n->help = 0;
909
910 return n;
911}
912
4a594fce
NC
913rc_dialog_control *
914define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x,
915 rc_uint_type y, rc_uint_type style,
916 rc_uint_type exstyle, rc_uint_type help,
917 rc_rcdata_item *data, rc_dialog_ex *ex)
2104a50e 918{
4a594fce
NC
919 rc_dialog_control *n;
920 rc_res_id tid;
921 rc_res_id cid;
7adbf450 922
2104a50e
DD
923 if (style == 0)
924 style = SS_ICON | WS_CHILD | WS_VISIBLE;
7adbf450 925 res_string_to_id (&tid, "");
4a594fce
NC
926 cid.named = 0;
927 cid.u.id = CTL_STATIC;
928 n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle);
2104a50e 929 n->text = iid;
4a594fce 930 if (help && ! ex)
2104a50e 931 rcparse_warning (_("help ID requires DIALOGEX"));
4a594fce 932 if (data && ! ex)
2104a50e
DD
933 rcparse_warning (_("control data requires DIALOGEX"));
934 n->help = help;
935 n->data = data;
936
937 return n;
938}
939
252b5132
RH
940/* Define a font resource. */
941
942void
4a594fce 943define_font (rc_res_id id, const rc_res_res_info *resinfo,
2da42df6 944 const char *filename)
252b5132
RH
945{
946 FILE *e;
947 char *real_filename;
948 struct stat s;
4a594fce
NC
949 bfd_byte *data;
950 rc_res_resource *r;
252b5132
RH
951 long offset;
952 long fontdatalength;
4a594fce
NC
953 bfd_byte *fontdata;
954 rc_fontdir *fd;
252b5132 955 const char *device, *face;
4a594fce 956 rc_fontdir **pp;
252b5132
RH
957
958 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename);
959
960 if (stat (real_filename, &s) < 0)
b09a7772 961 fatal (_("stat failed on font file `%s': %s"), real_filename,
252b5132
RH
962 strerror (errno));
963
4a594fce 964 data = (bfd_byte *) res_alloc (s.st_size);
252b5132
RH
965
966 get_data (e, data, s.st_size, real_filename);
967
968 fclose (e);
969 free (real_filename);
970
971 r = define_standard_resource (&resources, RT_FONT, id,
972 resinfo->language, 0);
973
974 r->type = RES_TYPE_FONT;
975 r->u.data.length = s.st_size;
976 r->u.data.data = data;
977 r->res_info = *resinfo;
978
979 /* For each font resource, we must add an entry in the FONTDIR
980 resource. The FONTDIR resource includes some strings in the font
981 file. To find them, we have to do some magic on the data we have
982 read. */
983
984 offset = ((((((data[47] << 8)
985 | data[46]) << 8)
986 | data[45]) << 8)
987 | data[44]);
988 if (offset > 0 && offset < s.st_size)
989 device = (char *) data + offset;
990 else
991 device = "";
992
993 offset = ((((((data[51] << 8)
994 | data[50]) << 8)
995 | data[49]) << 8)
996 | data[48]);
997 if (offset > 0 && offset < s.st_size)
998 face = (char *) data + offset;
999 else
1000 face = "";
1001
1002 ++fonts;
1003
1004 fontdatalength = 58 + strlen (device) + strlen (face);
4a594fce 1005 fontdata = (bfd_byte *) res_alloc (fontdatalength);
252b5132
RH
1006 memcpy (fontdata, data, 56);
1007 strcpy ((char *) fontdata + 56, device);
1008 strcpy ((char *) fontdata + 57 + strlen (device), face);
1009
4a594fce 1010 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
252b5132
RH
1011 fd->next = NULL;
1012 fd->index = fonts;
1013 fd->length = fontdatalength;
1014 fd->data = fontdata;
1015
1016 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next)
1017 ;
1018 *pp = fd;
1019
1020 /* For the single fontdirs resource, we always use the resource
1021 information of the last font. I don't know what else to do. */
1022 fontdirs_resinfo = *resinfo;
1023}
1024
4a594fce
NC
1025static void
1026define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1027 rc_rcdata_item *data)
1028{
1029 rc_res_resource *r;
1030 rc_uint_type len_data;
1031 bfd_byte *pb_data;
1032
1033 r = define_standard_resource (&resources, RT_FONT, id,
1034 resinfo->language, 0);
1035
1036 pb_data = rcdata_render_as_buffer (data, &len_data);
1037
1038 r->type = RES_TYPE_FONT;
1039 r->u.data.length = len_data;
1040 r->u.data.data = pb_data;
1041 r->res_info = *resinfo;
1042}
1043
252b5132
RH
1044/* Define the fontdirs resource. This is called after the entire rc
1045 file has been parsed, if any font resources were seen. */
1046
1047static void
2da42df6 1048define_fontdirs (void)
252b5132 1049{
4a594fce
NC
1050 rc_res_resource *r;
1051 rc_res_id id;
252b5132
RH
1052
1053 id.named = 0;
1054 id.u.id = 1;
1055
1056 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1057
1058 r->type = RES_TYPE_FONTDIR;
1059 r->u.fontdir = fontdirs;
1060 r->res_info = fontdirs_resinfo;
1061}
1062
4a594fce
NC
1063static bfd_byte *
1064rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen)
1065{
1066 const rc_rcdata_item *d;
1067 bfd_byte *ret = NULL, *pret;
1068 rc_uint_type len = 0;
1069
1070 for (d = data; d != NULL; d = d->next)
1071 len += rcdata_copy (d, NULL);
1072 if (len != 0)
1073 {
1074 ret = pret = (bfd_byte *) res_alloc (len);
1075 for (d = data; d != NULL; d = d->next)
1076 pret += rcdata_copy (d, pret);
1077 }
1078 if (plen)
1079 *plen = len;
1080 return ret;
1081}
1082
1083static void
1084define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo,
1085 rc_rcdata_item *data)
1086{
1087 rc_res_resource *r;
1088 rc_fontdir *fd, *fd_first, *fd_cur;
1089 rc_uint_type len_data;
1090 bfd_byte *pb_data;
1091 rc_uint_type c;
1092
1093 fd_cur = fd_first = NULL;
1094 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0);
1095
1096 pb_data = rcdata_render_as_buffer (data, &len_data);
1097
1098 if (pb_data)
1099 {
1100 rc_uint_type off = 2;
1101 c = windres_get_16 (&wrtarget, pb_data, len_data);
1102 for (; c > 0; c--)
1103 {
1104 size_t len;
1105 rc_uint_type safe_pos = off;
1106 const struct bin_fontdir_item *bfi;
1107
1108 bfi = (const struct bin_fontdir_item *) pb_data + off;
1109 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir));
1110 fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off);
1111 fd->data = pb_data + off;
1112 off += 56;
1113 len = strlen ((char *) bfi->device_name) + 1;
1114 off += (rc_uint_type) len;
1115 off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1;
1116 fd->length = (off - safe_pos);
1117 fd->next = NULL;
1118 if (fd_first == NULL)
1119 fd_first = fd;
1120 else
1121 fd_cur->next = fd;
1122 fd_cur = fd;
1123 }
1124 }
1125 r->type = RES_TYPE_FONTDIR;
1126 r->u.fontdir = fd_first;
1127 r->res_info = *resinfo;
1128}
1129
1130static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1131 rc_rcdata_item *data)
1132{
1133 rc_res_resource *r;
1134 rc_uint_type len_data;
1135 bfd_byte *pb_data;
1136
1137 r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0);
1138
1139 pb_data = rcdata_render_as_buffer (data, &len_data);
1140 r->type = RES_TYPE_MESSAGETABLE;
1141 r->u.data.length = len_data;
1142 r->u.data.data = pb_data;
1143 r->res_info = *resinfo;
1144}
1145
252b5132
RH
1146/* Define an icon resource. An icon file may contain a set of
1147 bitmaps, each representing the same icon at various different
1148 resolutions. They each get written out with a different ID. The
1149 real icon resource is then a group resource which can be used to
1150 select one of the actual icon bitmaps. */
1151
1152void
4a594fce 1153define_icon (rc_res_id id, const rc_res_res_info *resinfo,
2da42df6 1154 const char *filename)
252b5132
RH
1155{
1156 FILE *e;
1157 char *real_filename;
1158 int type, count, i;
1159 struct icondir *icondirs;
1160 int first_icon;
4a594fce
NC
1161 rc_res_resource *r;
1162 rc_group_icon *first, **pp;
252b5132
RH
1163
1164 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename);
1165
1166 /* The start of an icon file is a three word structure. The first
1167 word is ignored. The second word is the type of data. The third
1168 word is the number of entries. */
1169
1170 get_word (e, real_filename);
1171 type = get_word (e, real_filename);
1172 count = get_word (e, real_filename);
1173 if (type != 1)
1174 fatal (_("icon file `%s' does not contain icon data"), real_filename);
1175
1176 /* Read in the icon directory entries. */
1177
1178 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs);
1179
1180 for (i = 0; i < count; i++)
1181 {
1182 icondirs[i].width = getc (e);
1183 icondirs[i].height = getc (e);
1184 icondirs[i].colorcount = getc (e);
1185 getc (e);
1186 icondirs[i].u.icon.planes = get_word (e, real_filename);
1187 icondirs[i].u.icon.bits = get_word (e, real_filename);
1188 icondirs[i].bytes = get_long (e, real_filename);
1189 icondirs[i].offset = get_long (e, real_filename);
1190
1191 if (feof (e))
1192 unexpected_eof (real_filename);
1193 }
1194
1195 /* Define each icon as a unique resource. */
1196
1197 first_icon = icons;
1198
1199 for (i = 0; i < count; i++)
1200 {
4a594fce
NC
1201 bfd_byte *data;
1202 rc_res_id name;
252b5132
RH
1203
1204 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0)
1205 fatal (_("%s: fseek to %lu failed: %s"), real_filename,
1206 icondirs[i].offset, strerror (errno));
1207
4a594fce 1208 data = (bfd_byte *) res_alloc (icondirs[i].bytes);
252b5132
RH
1209
1210 get_data (e, data, icondirs[i].bytes, real_filename);
1211
1212 ++icons;
1213
1214 name.named = 0;
1215 name.u.id = icons;
1216
1217 r = define_standard_resource (&resources, RT_ICON, name,
1218 resinfo->language, 0);
1219 r->type = RES_TYPE_ICON;
1220 r->u.data.length = icondirs[i].bytes;
1221 r->u.data.data = data;
1222 r->res_info = *resinfo;
1223 }
1224
1225 fclose (e);
1226 free (real_filename);
1227
1228 /* Define an icon group resource. */
1229
1230 first = NULL;
1231 pp = &first;
1232 for (i = 0; i < count; i++)
1233 {
4a594fce 1234 rc_group_icon *cg;
252b5132
RH
1235
1236 /* For some reason, at least in some files the planes and bits
1237 are zero. We instead set them from the color. This is
1238 copied from rcl. */
1239
4a594fce 1240 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
252b5132
RH
1241 cg->next = NULL;
1242 cg->width = icondirs[i].width;
1243 cg->height = icondirs[i].height;
1244 cg->colors = icondirs[i].colorcount;
1245
b95f6b0c
CF
1246 if (icondirs[i].u.icon.planes)
1247 cg->planes = icondirs[i].u.icon.planes;
1248 else
1249 cg->planes = 1;
1250
1251 if (icondirs[i].u.icon.bits)
1252 cg->bits = icondirs[i].u.icon.bits;
1253 else
1254 {
1255 cg->bits = 0;
1256
1257 while ((1L << cg->bits) < cg->colors)
1258 ++cg->bits;
1259 }
252b5132
RH
1260
1261 cg->bytes = icondirs[i].bytes;
1262 cg->index = first_icon + i + 1;
1263
1264 *pp = cg;
1265 pp = &(*pp)->next;
1266 }
1267
1268 free (icondirs);
1269
1270 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1271 resinfo->language, 0);
1272 r->type = RES_TYPE_GROUP_ICON;
1273 r->u.group_icon = first;
1274 r->res_info = *resinfo;
1275}
1276
4a594fce
NC
1277static void
1278define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1279 rc_rcdata_item *data)
1280{
1281 rc_res_resource *r;
1282 rc_group_icon *cg, *first, *cur;
1283 rc_uint_type len_data;
1284 bfd_byte *pb_data;
1285
1286 pb_data = rcdata_render_as_buffer (data, &len_data);
1287
1288 cur = NULL;
1289 first = NULL;
1290
1291 while (len_data >= 6)
1292 {
1293 int c, i;
1294 unsigned short type;
1295 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1296 if (type != 1)
1297 fatal (_("unexpected group icon type %d"), type);
1298 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1299 len_data -= 6;
1300 pb_data += 6;
1301
1302 for (i = 0; i < c; i++)
1303 {
1304 if (len_data < 14)
1305 fatal ("too small group icon rcdata");
1306 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon));
1307 cg->next = NULL;
1308 cg->width = pb_data[0];
1309 cg->height = pb_data[1];
1310 cg->colors = pb_data[2];
1311 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1312 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1313 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1314 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1315 if (! first)
1316 first = cg;
1317 else
1318 cur->next = cg;
1319 cur = cg;
1320 pb_data += 14;
1321 len_data -= 14;
1322 }
1323 }
1324 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1325 resinfo->language, 0);
1326 r->type = RES_TYPE_GROUP_ICON;
1327 r->u.group_icon = first;
1328 r->res_info = *resinfo;
1329}
1330
1331static void
1332define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1333 rc_rcdata_item *data)
1334{
1335 rc_res_resource *r;
1336 rc_group_cursor *cg, *first, *cur;
1337 rc_uint_type len_data;
1338 bfd_byte *pb_data;
1339
1340 pb_data = rcdata_render_as_buffer (data, &len_data);
1341
1342 first = cur = NULL;
1343
1344 while (len_data >= 6)
1345 {
1346 int c, i;
1347 unsigned short type;
1348 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1349 if (type != 2)
1350 fatal (_("unexpected group cursor type %d"), type);
1351 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1352 len_data -= 6;
1353 pb_data += 6;
1354
1355 for (i = 0; i < c; i++)
1356 {
1357 if (len_data < 14)
1358 fatal ("too small group icon rcdata");
1359 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor));
1360 cg->next = NULL;
1361 cg->width = windres_get_16 (&wrtarget, pb_data, len_data);
1362 cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1363 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4);
1364 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6);
1365 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8);
1366 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12);
1367 if (! first)
1368 first = cg;
1369 else
1370 cur->next = cg;
1371 cur = cg;
1372 pb_data += 14;
1373 len_data -= 14;
1374 }
1375 }
1376
1377 r = define_standard_resource (&resources, RT_GROUP_ICON, id,
1378 resinfo->language, 0);
1379 r->type = RES_TYPE_GROUP_CURSOR;
1380 r->u.group_cursor = first;
1381 r->res_info = *resinfo;
1382}
1383
1384static void
1385define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1386 rc_rcdata_item *data)
1387{
1388 rc_cursor *c;
1389 rc_res_resource *r;
1390 rc_uint_type len_data;
1391 bfd_byte *pb_data;
1392
1393 pb_data = rcdata_render_as_buffer (data, &len_data);
1394
1395 c = (rc_cursor *) res_alloc (sizeof (rc_cursor));
1396 c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data);
1397 c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2);
1398 c->length = len_data - BIN_CURSOR_SIZE;
1399 c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE);
1400
1401 r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0);
1402 r->type = RES_TYPE_CURSOR;
1403 r->u.cursor = c;
1404 r->res_info = *resinfo;
1405}
1406
1407static void
1408define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1409 rc_rcdata_item *data)
1410{
1411 rc_res_resource *r;
1412 rc_uint_type len_data;
1413 bfd_byte *pb_data;
1414
1415 pb_data = rcdata_render_as_buffer (data, &len_data);
1416
1417 r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0);
1418 r->type = RES_TYPE_BITMAP;
1419 r->u.data.length = len_data;
1420 r->u.data.data = pb_data;
1421 r->res_info = *resinfo;
1422}
1423
1424static void
1425define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1426 rc_rcdata_item *data)
1427{
1428 rc_res_resource *r;
1429 rc_uint_type len_data;
1430 bfd_byte *pb_data;
1431
1432 pb_data = rcdata_render_as_buffer (data, &len_data);
1433
1434 r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0);
1435 r->type = RES_TYPE_ICON;
1436 r->u.data.length = len_data;
1437 r->u.data.data = pb_data;
1438 r->res_info = *resinfo;
1439}
1440
252b5132
RH
1441/* Define a menu resource. */
1442
1443void
4a594fce
NC
1444define_menu (rc_res_id id, const rc_res_res_info *resinfo,
1445 rc_menuitem *menuitems)
252b5132 1446{
4a594fce
NC
1447 rc_menu *m;
1448 rc_res_resource *r;
252b5132 1449
4a594fce 1450 m = (rc_menu *) res_alloc (sizeof (rc_menu));
252b5132
RH
1451 m->items = menuitems;
1452 m->help = 0;
1453
1454 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0);
1455 r->type = RES_TYPE_MENU;
1456 r->u.menu = m;
1457 r->res_info = *resinfo;
1458}
1459
1460/* Define a menu item. This does not define a resource, but merely
1461 allocates and fills in a structure. */
1462
4a594fce
NC
1463rc_menuitem *
1464define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type,
1465 rc_uint_type state, rc_uint_type help,
1466 rc_menuitem *menuitems)
252b5132 1467{
4a594fce 1468 rc_menuitem *mi;
252b5132 1469
4a594fce 1470 mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem));
252b5132
RH
1471 mi->next = NULL;
1472 mi->type = type;
1473 mi->state = state;
1474 mi->id = menuid;
4a594fce 1475 mi->text = unichar_dup (text);
252b5132
RH
1476 mi->help = help;
1477 mi->popup = menuitems;
1478 return mi;
1479}
1480
1481/* Define a messagetable resource. */
1482
1483void
4a594fce 1484define_messagetable (rc_res_id id, const rc_res_res_info *resinfo,
2da42df6 1485 const char *filename)
252b5132
RH
1486{
1487 FILE *e;
1488 char *real_filename;
1489 struct stat s;
4a594fce
NC
1490 bfd_byte *data;
1491 rc_res_resource *r;
252b5132
RH
1492
1493 e = open_file_search (filename, FOPEN_RB, "messagetable file",
1494 &real_filename);
1495
1496 if (stat (real_filename, &s) < 0)
1497 fatal (_("stat failed on bitmap file `%s': %s"), real_filename,
1498 strerror (errno));
1499
4a594fce 1500 data = (bfd_byte *) res_alloc (s.st_size);
252b5132
RH
1501
1502 get_data (e, data, s.st_size, real_filename);
1503
1504 fclose (e);
1505 free (real_filename);
1506
1507 r = define_standard_resource (&resources, RT_MESSAGETABLE, id,
1508 resinfo->language, 0);
1509
1510 r->type = RES_TYPE_MESSAGETABLE;
1511 r->u.data.length = s.st_size;
1512 r->u.data.data = data;
1513 r->res_info = *resinfo;
1514}
1515
1516/* Define an rcdata resource. */
1517
1518void
4a594fce
NC
1519define_rcdata (rc_res_id id, const rc_res_res_info *resinfo,
1520 rc_rcdata_item *data)
252b5132 1521{
4a594fce 1522 rc_res_resource *r;
252b5132
RH
1523
1524 r = define_standard_resource (&resources, RT_RCDATA, id,
1525 resinfo->language, 0);
1526 r->type = RES_TYPE_RCDATA;
1527 r->u.rcdata = data;
1528 r->res_info = *resinfo;
1529}
1530
1531/* Create an rcdata item holding a string. */
1532
4a594fce
NC
1533rc_rcdata_item *
1534define_rcdata_string (const char *string, rc_uint_type len)
252b5132 1535{
4a594fce 1536 rc_rcdata_item *ri;
252b5132
RH
1537 char *s;
1538
4a594fce 1539 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
252b5132
RH
1540 ri->next = NULL;
1541 ri->type = RCDATA_STRING;
1542 ri->u.string.length = len;
1543 s = (char *) res_alloc (len);
1544 memcpy (s, string, len);
1545 ri->u.string.s = s;
1546
1547 return ri;
1548}
1549
4a594fce
NC
1550/* Create an rcdata item holding a unicode string. */
1551
1552rc_rcdata_item *
1553define_rcdata_unistring (const unichar *string, rc_uint_type len)
1554{
1555 rc_rcdata_item *ri;
1556 unichar *s;
1557
1558 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
1559 ri->next = NULL;
1560 ri->type = RCDATA_WSTRING;
1561 ri->u.wstring.length = len;
1562 s = (unichar *) res_alloc (len * sizeof (unichar));
1563 memcpy (s, string, len * sizeof (unichar));
1564 ri->u.wstring.w = s;
1565
1566 return ri;
1567}
1568
252b5132
RH
1569/* Create an rcdata item holding a number. */
1570
4a594fce
NC
1571rc_rcdata_item *
1572define_rcdata_number (rc_uint_type val, int dword)
252b5132 1573{
4a594fce 1574 rc_rcdata_item *ri;
252b5132 1575
4a594fce 1576 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
252b5132
RH
1577 ri->next = NULL;
1578 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD;
1579 ri->u.word = val;
1580
1581 return ri;
1582}
1583
1584/* Define a stringtable resource. This is called for each string
1585 which appears in a STRINGTABLE statement. */
1586
1587void
4a594fce 1588define_stringtable (const rc_res_res_info *resinfo,
81472056 1589 rc_uint_type stringid, const unichar *string, int len)
252b5132 1590{
81472056 1591 unichar *h;
4a594fce
NC
1592 rc_res_id id;
1593 rc_res_resource *r;
252b5132
RH
1594
1595 id.named = 0;
1596 id.u.id = (stringid >> 4) + 1;
1597 r = define_standard_resource (&resources, RT_STRING, id,
1598 resinfo->language, 1);
1599
1600 if (r->type == RES_TYPE_UNINITIALIZED)
1601 {
1602 int i;
1603
1604 r->type = RES_TYPE_STRINGTABLE;
4a594fce
NC
1605 r->u.stringtable = ((rc_stringtable *)
1606 res_alloc (sizeof (rc_stringtable)));
252b5132
RH
1607 for (i = 0; i < 16; i++)
1608 {
1609 r->u.stringtable->strings[i].length = 0;
1610 r->u.stringtable->strings[i].string = NULL;
1611 }
1612
1613 r->res_info = *resinfo;
1614 }
81472056
KT
1615 h = (unichar *) res_alloc ((len + 1) * sizeof (unichar));
1616 if (len)
1617 memcpy (h, string, len * sizeof (unichar));
1618 h[len] = 0;
1619 r->u.stringtable->strings[stringid & 0xf].length = (rc_uint_type) len;
1620 r->u.stringtable->strings[stringid & 0xf].string = h;
4a594fce
NC
1621}
1622
1623void
1624define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height,
1625 rc_toolbar_item *items)
1626{
1627 rc_toolbar *t;
1628 rc_res_resource *r;
1629
1630 t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar));
1631 t->button_width = width;
1632 t->button_height = height;
1633 t->nitems = 0;
1634 t->items = items;
1635 while (items != NULL)
1636 {
1637 t->nitems+=1;
1638 items = items->next;
1639 }
1640 r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0);
1641 r->type = RES_TYPE_TOOLBAR;
1642 r->u.toolbar = t;
1643 r->res_info = *resinfo;
252b5132
RH
1644}
1645
1646/* Define a user data resource where the data is in the rc file. */
1647
1648void
4a594fce
NC
1649define_user_data (rc_res_id id, rc_res_id type,
1650 const rc_res_res_info *resinfo,
1651 rc_rcdata_item *data)
252b5132 1652{
4a594fce
NC
1653 rc_res_id ids[3];
1654 rc_res_resource *r;
1655 bfd_byte *pb_data;
1656 rc_uint_type len_data;
252b5132 1657
4a594fce
NC
1658 /* We have to check if the binary data is parsed specially. */
1659 if (type.named == 0)
1660 {
1661 switch (type.u.id)
1662 {
1663 case RT_FONTDIR:
1664 define_fontdir_rcdata (id, resinfo, data);
1665 return;
1666 case RT_FONT:
1667 define_font_rcdata (id, resinfo, data);
1668 return;
1669 case RT_ICON:
1670 define_icon_rcdata (id, resinfo, data);
1671 return;
1672 case RT_BITMAP:
1673 define_bitmap_rcdata (id, resinfo, data);
1674 return;
1675 case RT_CURSOR:
1676 define_cursor_rcdata (id, resinfo, data);
1677 return;
1678 case RT_GROUP_ICON:
1679 define_group_icon_rcdata (id, resinfo, data);
1680 return;
1681 case RT_GROUP_CURSOR:
1682 define_group_cursor_rcdata (id, resinfo, data);
1683 return;
1684 case RT_MESSAGETABLE:
1685 define_messagetable_rcdata (id, resinfo, data);
1686 return;
1687 default:
1688 /* Treat as normal user-data. */
1689 break;
1690 }
1691 }
252b5132
RH
1692 ids[0] = type;
1693 ids[1] = id;
1694 ids[2].named = 0;
1695 ids[2].u.id = resinfo->language;
1696
b09a7772 1697 r = define_resource (& resources, 3, ids, 0);
252b5132 1698 r->type = RES_TYPE_USERDATA;
4a594fce
NC
1699 r->u.userdata = ((rc_rcdata_item *)
1700 res_alloc (sizeof (rc_rcdata_item)));
1701 r->u.userdata->next = NULL;
1702 r->u.userdata->type = RCDATA_BUFFER;
1703 pb_data = rcdata_render_as_buffer (data, &len_data);
1704 r->u.userdata->u.buffer.length = len_data;
1705 r->u.userdata->u.buffer.data = pb_data;
252b5132
RH
1706 r->res_info = *resinfo;
1707}
1708
b09a7772 1709void
4a594fce 1710define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo,
b09a7772
NC
1711 const char *filename)
1712{
4a594fce 1713 rc_rcdata_item *ri;
b09a7772
NC
1714 FILE *e;
1715 char *real_filename;
1716 struct stat s;
4a594fce 1717 bfd_byte *data;
b09a7772
NC
1718
1719 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
1720
1721
1722 if (stat (real_filename, &s) < 0)
1723 fatal (_("stat failed on file `%s': %s"), real_filename,
1724 strerror (errno));
1725
4a594fce 1726 data = (bfd_byte *) res_alloc (s.st_size);
b09a7772
NC
1727
1728 get_data (e, data, s.st_size, real_filename);
1729
1730 fclose (e);
1731 free (real_filename);
1732
4a594fce 1733 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item));
b09a7772
NC
1734 ri->next = NULL;
1735 ri->type = RCDATA_BUFFER;
1736 ri->u.buffer.length = s.st_size;
1737 ri->u.buffer.data = data;
1738
1739 define_rcdata (id, resinfo, ri);
1740}
1741
252b5132
RH
1742/* Define a user data resource where the data is in a file. */
1743
1744void
4a594fce
NC
1745define_user_file (rc_res_id id, rc_res_id type,
1746 const rc_res_res_info *resinfo, const char *filename)
252b5132
RH
1747{
1748 FILE *e;
1749 char *real_filename;
1750 struct stat s;
4a594fce
NC
1751 bfd_byte *data;
1752 rc_res_id ids[3];
1753 rc_res_resource *r;
252b5132 1754
b09a7772 1755 e = open_file_search (filename, FOPEN_RB, "file", &real_filename);
252b5132
RH
1756
1757 if (stat (real_filename, &s) < 0)
b09a7772 1758 fatal (_("stat failed on file `%s': %s"), real_filename,
252b5132
RH
1759 strerror (errno));
1760
4a594fce 1761 data = (bfd_byte *) res_alloc (s.st_size);
252b5132
RH
1762
1763 get_data (e, data, s.st_size, real_filename);
1764
1765 fclose (e);
1766 free (real_filename);
1767
1768 ids[0] = type;
1769 ids[1] = id;
1770 ids[2].named = 0;
1771 ids[2].u.id = resinfo->language;
1772
1773 r = define_resource (&resources, 3, ids, 0);
1774 r->type = RES_TYPE_USERDATA;
4a594fce
NC
1775 r->u.userdata = ((rc_rcdata_item *)
1776 res_alloc (sizeof (rc_rcdata_item)));
252b5132
RH
1777 r->u.userdata->next = NULL;
1778 r->u.userdata->type = RCDATA_BUFFER;
1779 r->u.userdata->u.buffer.length = s.st_size;
1780 r->u.userdata->u.buffer.data = data;
1781 r->res_info = *resinfo;
1782}
1783
1784/* Define a versioninfo resource. */
1785
1786void
4a594fce
NC
1787define_versioninfo (rc_res_id id, rc_uint_type language,
1788 rc_fixed_versioninfo *fixedverinfo,
1789 rc_ver_info *verinfo)
252b5132 1790{
4a594fce 1791 rc_res_resource *r;
252b5132
RH
1792
1793 r = define_standard_resource (&resources, RT_VERSION, id, language, 0);
1794 r->type = RES_TYPE_VERSIONINFO;
4a594fce
NC
1795 r->u.versioninfo = ((rc_versioninfo *)
1796 res_alloc (sizeof (rc_versioninfo)));
252b5132
RH
1797 r->u.versioninfo->fixed = fixedverinfo;
1798 r->u.versioninfo->var = verinfo;
1799 r->res_info.language = language;
1800}
1801
1802/* Add string version info to a list of version information. */
1803
4a594fce 1804rc_ver_info *
bfb6c1ab
NC
1805append_ver_stringfileinfo (rc_ver_info *verinfo,
1806 rc_ver_stringtable *stringtables)
252b5132 1807{
4a594fce 1808 rc_ver_info *vi, **pp;
252b5132 1809
4a594fce 1810 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info));
252b5132
RH
1811 vi->next = NULL;
1812 vi->type = VERINFO_STRING;
bfb6c1ab 1813 vi->u.string.stringtables = stringtables;
252b5132
RH
1814
1815 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1816 ;
1817 *pp = vi;
1818
1819 return verinfo;
1820}
1821
bfb6c1ab
NC
1822rc_ver_stringtable *
1823append_ver_stringtable (rc_ver_stringtable *stringtable,
1824 const char *language,
1825 rc_ver_stringinfo *strings)
1826{
1827 rc_ver_stringtable *vst, **pp;
1828
1829 vst = (rc_ver_stringtable *) res_alloc (sizeof (rc_ver_stringtable));
1830 vst->next = NULL;
1831 unicode_from_ascii ((rc_uint_type *) NULL, &vst->language, language);
1832 vst->strings = strings;
1833
1834 for (pp = &stringtable; *pp != NULL; pp = &(*pp)->next)
1835 ;
1836 *pp = vst;
1837
1838 return stringtable;
1839}
1840
252b5132
RH
1841/* Add variable version info to a list of version information. */
1842
4a594fce
NC
1843rc_ver_info *
1844append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key,
1845 rc_ver_varinfo *var)
252b5132 1846{
4a594fce 1847 rc_ver_info *vi, **pp;
252b5132 1848
4a594fce 1849 vi = (rc_ver_info *) res_alloc (sizeof *vi);
252b5132
RH
1850 vi->next = NULL;
1851 vi->type = VERINFO_VAR;
4a594fce 1852 vi->u.var.key = unichar_dup (key);
252b5132
RH
1853 vi->u.var.var = var;
1854
1855 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next)
1856 ;
1857 *pp = vi;
1858
1859 return verinfo;
1860}
1861
1862/* Append version string information to a list. */
1863
4a594fce
NC
1864rc_ver_stringinfo *
1865append_verval (rc_ver_stringinfo *strings, const unichar *key,
1866 const unichar *value)
252b5132 1867{
4a594fce 1868 rc_ver_stringinfo *vs, **pp;
252b5132 1869
4a594fce 1870 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo));
252b5132 1871 vs->next = NULL;
4a594fce
NC
1872 vs->key = unichar_dup (key);
1873 vs->value = unichar_dup (value);
252b5132
RH
1874
1875 for (pp = &strings; *pp != NULL; pp = &(*pp)->next)
1876 ;
1877 *pp = vs;
1878
1879 return strings;
1880}
1881
1882/* Append version variable information to a list. */
1883
4a594fce
NC
1884rc_ver_varinfo *
1885append_vertrans (rc_ver_varinfo *var, rc_uint_type language,
1886 rc_uint_type charset)
252b5132 1887{
4a594fce 1888 rc_ver_varinfo *vv, **pp;
252b5132 1889
4a594fce 1890 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo));
252b5132
RH
1891 vv->next = NULL;
1892 vv->language = language;
1893 vv->charset = charset;
1894
1895 for (pp = &var; *pp != NULL; pp = &(*pp)->next)
1896 ;
1897 *pp = vv;
1898
1899 return var;
1900}
1901\f
1902/* Local functions used to write out an rc file. */
1903
2da42df6 1904static void indent (FILE *, int);
4a594fce
NC
1905static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *,
1906 const rc_res_id *, rc_uint_type *, int);
1907static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *,
1908 const rc_res_id *, rc_uint_type *, int);
1909static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *,
1910 const rc_res_resource *, rc_uint_type *);
1911static void write_rc_accelerators (FILE *, const rc_accelerator *);
1912static void write_rc_cursor (FILE *, const rc_cursor *);
1913static void write_rc_group_cursor (FILE *, const rc_group_cursor *);
1914static void write_rc_dialog (FILE *, const rc_dialog *);
1915static void write_rc_dialog_control (FILE *, const rc_dialog_control *);
1916static void write_rc_fontdir (FILE *, const rc_fontdir *);
1917static void write_rc_group_icon (FILE *, const rc_group_icon *);
1918static void write_rc_menu (FILE *, const rc_menu *, int);
1919static void write_rc_toolbar (FILE *, const rc_toolbar *);
1920static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int);
1921static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *);
1922
1923static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int);
1924static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int);
1925static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *);
1926static void write_rc_versioninfo (FILE *, const rc_versioninfo *);
252b5132
RH
1927
1928/* Indent a given number of spaces. */
1929
1930static void
2da42df6 1931indent (FILE *e, int c)
252b5132
RH
1932{
1933 int i;
1934
1935 for (i = 0; i < c; i++)
1936 putc (' ', e);
1937}
1938
1939/* Dump the resources we have read in the format of an rc file.
1940
4a594fce
NC
1941 Reasoned by the fact, that some resources need to be stored into file and
1942 refer to that file, we use the user-data model for that to express it binary
1943 without the need to store it somewhere externally. */
252b5132
RH
1944
1945void
91d6fa6a 1946write_rc_file (const char *filename, const rc_res_directory *res_dir)
252b5132
RH
1947{
1948 FILE *e;
4a594fce 1949 rc_uint_type language;
252b5132
RH
1950
1951 if (filename == NULL)
1952 e = stdout;
1953 else
1954 {
1955 e = fopen (filename, FOPEN_WT);
1956 if (e == NULL)
1957 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno));
1958 }
1959
4a594fce 1960 language = (rc_uint_type) ((bfd_signed_vma) -1);
91d6fa6a 1961 write_rc_directory (e, res_dir, (const rc_res_id *) NULL,
4a594fce 1962 (const rc_res_id *) NULL, &language, 1);
252b5132
RH
1963}
1964
1965/* Write out a directory. E is the file to write to. RD is the
1966 directory. TYPE is a pointer to the level 1 ID which serves as the
1967 resource type. NAME is a pointer to the level 2 ID which serves as
1968 an individual resource name. LANGUAGE is a pointer to the current
1969 language. LEVEL is the level in the tree. */
1970
1971static void
4a594fce
NC
1972write_rc_directory (FILE *e, const rc_res_directory *rd,
1973 const rc_res_id *type, const rc_res_id *name,
1974 rc_uint_type *language, int level)
252b5132 1975{
4a594fce 1976 const rc_res_entry *re;
252b5132
RH
1977
1978 /* Print out some COFF information that rc files can't represent. */
4a594fce
NC
1979 if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0)
1980 {
1981 wr_printcomment (e, "COFF information not part of RC");
252b5132 1982 if (rd->time != 0)
4a594fce 1983 wr_printcomment (e, "Time stamp: %u", rd->time);
252b5132 1984 if (rd->characteristics != 0)
4a594fce 1985 wr_printcomment (e, "Characteristics: %u", rd->characteristics);
252b5132 1986 if (rd->major != 0 || rd->minor != 0)
4a594fce
NC
1987 wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor);
1988 }
252b5132
RH
1989
1990 for (re = rd->entries; re != NULL; re = re->next)
1991 {
1992 switch (level)
1993 {
1994 case 1:
1995 /* If we're at level 1, the key of this resource is the
1996 type. This normally duplicates the information we have
1997 stored with the resource itself, but we need to remember
1998 the type if this is a user define resource type. */
1999 type = &re->id;
2000 break;
2001
2002 case 2:
2003 /* If we're at level 2, the key of this resource is the name
df3baf66 2004 we are going to use in the rc printout. */
252b5132
RH
2005 name = &re->id;
2006 break;
2007
2008 case 3:
2009 /* If we're at level 3, then this key represents a language.
2010 Use it to update the current language. */
2011 if (! re->id.named
2012 && re->id.u.id != (unsigned long) (unsigned int) *language
2013 && (re->id.u.id & 0xffff) == re->id.u.id)
2014 {
4a594fce 2015 wr_print (e, "LANGUAGE %u, %u\n",
53c7db4b 2016 re->id.u.id & ((1 << SUBLANG_SHIFT) - 1),
b24eb5ac 2017 (re->id.u.id >> SUBLANG_SHIFT) & 0xff);
252b5132
RH
2018 *language = re->id.u.id;
2019 }
2020 break;
2021
2022 default:
2023 break;
2024 }
2025
2026 if (re->subdir)
2027 write_rc_subdir (e, re, type, name, language, level);
2028 else
2029 {
2030 if (level == 3)
2031 {
2032 /* This is the normal case: the three levels are
2033 TYPE/NAME/LANGUAGE. NAME will have been set at level
2034 2, and represents the name to use. We probably just
2035 set LANGUAGE, and it will probably match what the
2036 resource itself records if anything. */
2037 write_rc_resource (e, type, name, re->u.res, language);
2038 }
2039 else
2040 {
4a594fce
NC
2041 wr_printcomment (e, "Resource at unexpected level %d", level);
2042 write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res,
252b5132
RH
2043 language);
2044 }
2045 }
2046 }
4a594fce
NC
2047 if (rd->entries == NULL)
2048 {
2049 wr_print_flush (e);
2050 }
252b5132
RH
2051}
2052
2053/* Write out a subdirectory entry. E is the file to write to. RE is
2054 the subdirectory entry. TYPE and NAME are pointers to higher level
2055 IDs, or NULL. LANGUAGE is a pointer to the current language.
2056 LEVEL is the level in the tree. */
2057
2058static void
4a594fce
NC
2059write_rc_subdir (FILE *e, const rc_res_entry *re,
2060 const rc_res_id *type, const rc_res_id *name,
2061 rc_uint_type *language, int level)
252b5132
RH
2062{
2063 fprintf (e, "\n");
2064 switch (level)
2065 {
2066 case 1:
4a594fce 2067 wr_printcomment (e, "Type: ");
252b5132
RH
2068 if (re->id.named)
2069 res_id_print (e, re->id, 1);
2070 else
2071 {
2072 const char *s;
2073
2074 switch (re->id.u.id)
2075 {
2076 case RT_CURSOR: s = "cursor"; break;
2077 case RT_BITMAP: s = "bitmap"; break;
2078 case RT_ICON: s = "icon"; break;
2079 case RT_MENU: s = "menu"; break;
2080 case RT_DIALOG: s = "dialog"; break;
2081 case RT_STRING: s = "stringtable"; break;
2082 case RT_FONTDIR: s = "fontdir"; break;
2083 case RT_FONT: s = "font"; break;
2084 case RT_ACCELERATOR: s = "accelerators"; break;
2085 case RT_RCDATA: s = "rcdata"; break;
2086 case RT_MESSAGETABLE: s = "messagetable"; break;
2087 case RT_GROUP_CURSOR: s = "group cursor"; break;
2088 case RT_GROUP_ICON: s = "group icon"; break;
2089 case RT_VERSION: s = "version"; break;
2090 case RT_DLGINCLUDE: s = "dlginclude"; break;
2091 case RT_PLUGPLAY: s = "plugplay"; break;
2092 case RT_VXD: s = "vxd"; break;
2093 case RT_ANICURSOR: s = "anicursor"; break;
2094 case RT_ANIICON: s = "aniicon"; break;
4a594fce
NC
2095 case RT_TOOLBAR: s = "toolbar"; break;
2096 case RT_HTML: s = "html"; break;
252b5132
RH
2097 default: s = NULL; break;
2098 }
2099
2100 if (s != NULL)
2101 fprintf (e, "%s", s);
2102 else
2103 res_id_print (e, re->id, 1);
2104 }
252b5132
RH
2105 break;
2106
2107 case 2:
4a594fce 2108 wr_printcomment (e, "Name: ");
252b5132 2109 res_id_print (e, re->id, 1);
252b5132
RH
2110 break;
2111
2112 case 3:
4a594fce 2113 wr_printcomment (e, "Language: ");
252b5132 2114 res_id_print (e, re->id, 1);
252b5132
RH
2115 break;
2116
2117 default:
4a594fce 2118 wr_printcomment (e, "Level %d: ", level);
252b5132 2119 res_id_print (e, re->id, 1);
53c7db4b 2120 }
252b5132
RH
2121
2122 write_rc_directory (e, re->u.dir, type, name, language, level + 1);
2123}
2124
2125/* Write out a single resource. E is the file to write to. TYPE is a
2126 pointer to the type of the resource. NAME is a pointer to the name
2127 of the resource; it will be NULL if there is a level mismatch. RES
2128 is the resource data. LANGUAGE is a pointer to the current
2129 language. */
2130
2131static void
4a594fce
NC
2132write_rc_resource (FILE *e, const rc_res_id *type,
2133 const rc_res_id *name, const rc_res_resource *res,
2134 rc_uint_type *language)
252b5132
RH
2135{
2136 const char *s;
2137 int rt;
2138 int menuex = 0;
2139
252b5132
RH
2140 switch (res->type)
2141 {
2142 default:
2143 abort ();
2144
2145 case RES_TYPE_ACCELERATOR:
4a594fce 2146 s = "ACCELERATORS";
252b5132
RH
2147 rt = RT_ACCELERATOR;
2148 break;
2149
2150 case RES_TYPE_BITMAP:
4a594fce 2151 s = "2 /* RT_BITMAP */";
252b5132
RH
2152 rt = RT_BITMAP;
2153 break;
2154
2155 case RES_TYPE_CURSOR:
4a594fce 2156 s = "1 /* RT_CURSOR */";
252b5132
RH
2157 rt = RT_CURSOR;
2158 break;
2159
2160 case RES_TYPE_GROUP_CURSOR:
4a594fce 2161 s = "12 /* RT_GROUP_CURSOR */";
252b5132
RH
2162 rt = RT_GROUP_CURSOR;
2163 break;
2164
2165 case RES_TYPE_DIALOG:
2166 if (extended_dialog (res->u.dialog))
2167 s = "DIALOGEX";
2168 else
2169 s = "DIALOG";
2170 rt = RT_DIALOG;
2171 break;
2172
2173 case RES_TYPE_FONT:
4a594fce 2174 s = "8 /* RT_FONT */";
252b5132
RH
2175 rt = RT_FONT;
2176 break;
2177
2178 case RES_TYPE_FONTDIR:
4a594fce 2179 s = "7 /* RT_FONTDIR */";
252b5132
RH
2180 rt = RT_FONTDIR;
2181 break;
2182
2183 case RES_TYPE_ICON:
4a594fce 2184 s = "3 /* RT_ICON */";
252b5132
RH
2185 rt = RT_ICON;
2186 break;
2187
2188 case RES_TYPE_GROUP_ICON:
4a594fce 2189 s = "14 /* RT_GROUP_ICON */";
252b5132
RH
2190 rt = RT_GROUP_ICON;
2191 break;
2192
2193 case RES_TYPE_MENU:
2194 if (extended_menu (res->u.menu))
2195 {
2196 s = "MENUEX";
2197 menuex = 1;
2198 }
2199 else
2200 {
2201 s = "MENU";
2202 menuex = 0;
2203 }
2204 rt = RT_MENU;
2205 break;
2206
2207 case RES_TYPE_MESSAGETABLE:
4a594fce 2208 s = "11 /* RT_MESSAGETABLE */";
252b5132
RH
2209 rt = RT_MESSAGETABLE;
2210 break;
2211
2212 case RES_TYPE_RCDATA:
2213 s = "RCDATA";
2214 rt = RT_RCDATA;
2215 break;
2216
2217 case RES_TYPE_STRINGTABLE:
2218 s = "STRINGTABLE";
2219 rt = RT_STRING;
2220 break;
2221
2222 case RES_TYPE_USERDATA:
2223 s = NULL;
2224 rt = 0;
2225 break;
2226
2227 case RES_TYPE_VERSIONINFO:
2228 s = "VERSIONINFO";
2229 rt = RT_VERSION;
2230 break;
4a594fce
NC
2231
2232 case RES_TYPE_TOOLBAR:
2233 s = "TOOLBAR";
2234 rt = RT_TOOLBAR;
2235 break;
252b5132
RH
2236 }
2237
2238 if (rt != 0
2239 && type != NULL
2240 && (type->named || type->u.id != (unsigned long) rt))
2241 {
4a594fce 2242 wr_printcomment (e, "Unexpected resource type mismatch: ");
252b5132
RH
2243 res_id_print (e, *type, 1);
2244 fprintf (e, " != %d", rt);
2245 }
2246
2247 if (res->coff_info.codepage != 0)
4a594fce 2248 wr_printcomment (e, "Code page: %u", res->coff_info.codepage);
252b5132 2249 if (res->coff_info.reserved != 0)
4a594fce 2250 wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved);
252b5132 2251
4a594fce
NC
2252 wr_print (e, "\n");
2253 if (rt == RT_STRING)
2254 ;
2255 else
2256 {
252b5132 2257 if (name != NULL)
4a594fce 2258 res_id_print (e, *name, 1);
252b5132
RH
2259 else
2260 fprintf (e, "??Unknown-Name??");
252b5132 2261 fprintf (e, " ");
4a594fce
NC
2262 }
2263
252b5132
RH
2264 if (s != NULL)
2265 fprintf (e, "%s", s);
2266 else if (type != NULL)
4a594fce
NC
2267 {
2268 if (type->named == 0)
2269 {
2270#define PRINT_RT_NAME(NAME) case NAME: \
2271 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \
2272 break
2273
2274 switch (type->u.id)
2275 {
2276 default:
252b5132 2277 res_id_print (e, *type, 0);
4a594fce
NC
2278 break;
2279
2280 PRINT_RT_NAME(RT_MANIFEST);
2281 PRINT_RT_NAME(RT_ANICURSOR);
2282 PRINT_RT_NAME(RT_ANIICON);
2283 PRINT_RT_NAME(RT_RCDATA);
2284 PRINT_RT_NAME(RT_ICON);
2285 PRINT_RT_NAME(RT_CURSOR);
2286 PRINT_RT_NAME(RT_BITMAP);
2287 PRINT_RT_NAME(RT_PLUGPLAY);
2288 PRINT_RT_NAME(RT_VXD);
2289 PRINT_RT_NAME(RT_FONT);
2290 PRINT_RT_NAME(RT_FONTDIR);
2291 PRINT_RT_NAME(RT_HTML);
2292 PRINT_RT_NAME(RT_MESSAGETABLE);
2293 PRINT_RT_NAME(RT_DLGINCLUDE);
2294 PRINT_RT_NAME(RT_DLGINIT);
2295 }
2296#undef PRINT_RT_NAME
2297 }
2298 else
2299 res_id_print (e, *type, 1);
2300 }
252b5132
RH
2301 else
2302 fprintf (e, "??Unknown-Type??");
2303
2304 if (res->res_info.memflags != 0)
2305 {
2306 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0)
2307 fprintf (e, " MOVEABLE");
2308 if ((res->res_info.memflags & MEMFLAG_PURE) != 0)
2309 fprintf (e, " PURE");
2310 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0)
2311 fprintf (e, " PRELOAD");
2312 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0)
2313 fprintf (e, " DISCARDABLE");
2314 }
2315
2316 if (res->type == RES_TYPE_DIALOG)
2317 {
4a594fce
NC
2318 fprintf (e, " %d, %d, %d, %d",
2319 (int) res->u.dialog->x, (int) res->u.dialog->y,
2320 (int) res->u.dialog->width, (int) res->u.dialog->height);
252b5132
RH
2321 if (res->u.dialog->ex != NULL
2322 && res->u.dialog->ex->help != 0)
4a594fce
NC
2323 fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help);
2324 }
2325 else if (res->type == RES_TYPE_TOOLBAR)
2326 {
2327 fprintf (e, " %d, %d", (int) res->u.toolbar->button_width,
2328 (int) res->u.toolbar->button_height);
252b5132
RH
2329 }
2330
2331 fprintf (e, "\n");
2332
2333 if ((res->res_info.language != 0 && res->res_info.language != *language)
2334 || res->res_info.characteristics != 0
2335 || res->res_info.version != 0)
2336 {
2337 int modifiers;
2338
2339 switch (res->type)
2340 {
2341 case RES_TYPE_ACCELERATOR:
2342 case RES_TYPE_DIALOG:
2343 case RES_TYPE_MENU:
2344 case RES_TYPE_RCDATA:
2345 case RES_TYPE_STRINGTABLE:
2346 modifiers = 1;
2347 break;
2348
2349 default:
2350 modifiers = 0;
2351 break;
2352 }
2353
2354 if (res->res_info.language != 0 && res->res_info.language != *language)
2355 fprintf (e, "%sLANGUAGE %d, %d\n",
2356 modifiers ? "// " : "",
4a594fce
NC
2357 (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1),
2358 (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff);
252b5132 2359 if (res->res_info.characteristics != 0)
4a594fce 2360 fprintf (e, "%sCHARACTERISTICS %u\n",
252b5132 2361 modifiers ? "// " : "",
4a594fce 2362 (unsigned int) res->res_info.characteristics);
252b5132 2363 if (res->res_info.version != 0)
4a594fce 2364 fprintf (e, "%sVERSION %u\n",
252b5132 2365 modifiers ? "// " : "",
4a594fce 2366 (unsigned int) res->res_info.version);
252b5132
RH
2367 }
2368
2369 switch (res->type)
2370 {
2371 default:
2372 abort ();
2373
2374 case RES_TYPE_ACCELERATOR:
2375 write_rc_accelerators (e, res->u.acc);
2376 break;
2377
2378 case RES_TYPE_CURSOR:
2379 write_rc_cursor (e, res->u.cursor);
2380 break;
2381
2382 case RES_TYPE_GROUP_CURSOR:
2383 write_rc_group_cursor (e, res->u.group_cursor);
2384 break;
2385
2386 case RES_TYPE_DIALOG:
2387 write_rc_dialog (e, res->u.dialog);
2388 break;
2389
2390 case RES_TYPE_FONTDIR:
2391 write_rc_fontdir (e, res->u.fontdir);
2392 break;
2393
2394 case RES_TYPE_GROUP_ICON:
2395 write_rc_group_icon (e, res->u.group_icon);
2396 break;
2397
2398 case RES_TYPE_MENU:
2399 write_rc_menu (e, res->u.menu, menuex);
2400 break;
2401
2402 case RES_TYPE_RCDATA:
2403 write_rc_rcdata (e, res->u.rcdata, 0);
2404 break;
2405
2406 case RES_TYPE_STRINGTABLE:
2407 write_rc_stringtable (e, name, res->u.stringtable);
2408 break;
2409
2410 case RES_TYPE_USERDATA:
2411 write_rc_rcdata (e, res->u.userdata, 0);
2412 break;
2413
4a594fce
NC
2414 case RES_TYPE_TOOLBAR:
2415 write_rc_toolbar (e, res->u.toolbar);
2416 break;
2417
252b5132
RH
2418 case RES_TYPE_VERSIONINFO:
2419 write_rc_versioninfo (e, res->u.versioninfo);
2420 break;
2421
2422 case RES_TYPE_BITMAP:
2423 case RES_TYPE_FONT:
2424 case RES_TYPE_ICON:
4a594fce
NC
2425 write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0);
2426 break;
252b5132 2427 case RES_TYPE_MESSAGETABLE:
4a594fce 2428 write_rc_messagetable (e, res->u.data.length, res->u.data.data);
252b5132
RH
2429 break;
2430 }
2431}
2432
2433/* Write out accelerator information. */
2434
2435static void
4a594fce 2436write_rc_accelerators (FILE *e, const rc_accelerator *accelerators)
252b5132 2437{
4a594fce 2438 const rc_accelerator *acc;
252b5132
RH
2439
2440 fprintf (e, "BEGIN\n");
2441 for (acc = accelerators; acc != NULL; acc = acc->next)
2442 {
2443 int printable;
2444
2445 fprintf (e, " ");
2446
2447 if ((acc->key & 0x7f) == acc->key
3882b010 2448 && ISPRINT (acc->key)
252b5132
RH
2449 && (acc->flags & ACC_VIRTKEY) == 0)
2450 {
4a594fce 2451 fprintf (e, "\"%c\"", (char) acc->key);
252b5132
RH
2452 printable = 1;
2453 }
2454 else
2455 {
4a594fce 2456 fprintf (e, "%d", (int) acc->key);
252b5132
RH
2457 printable = 0;
2458 }
2459
4a594fce 2460 fprintf (e, ", %d", (int) acc->id);
252b5132
RH
2461
2462 if (! printable)
2463 {
2464 if ((acc->flags & ACC_VIRTKEY) != 0)
2465 fprintf (e, ", VIRTKEY");
2466 else
2467 fprintf (e, ", ASCII");
2468 }
2469
2470 if ((acc->flags & ACC_SHIFT) != 0)
2471 fprintf (e, ", SHIFT");
2472 if ((acc->flags & ACC_CONTROL) != 0)
2473 fprintf (e, ", CONTROL");
2474 if ((acc->flags & ACC_ALT) != 0)
2475 fprintf (e, ", ALT");
2476
2477 fprintf (e, "\n");
2478 }
2479
2480 fprintf (e, "END\n");
2481}
2482
2483/* Write out cursor information. This would normally be in a separate
2484 file, which the rc file would include. */
2485
2486static void
4a594fce 2487write_rc_cursor (FILE *e, const rc_cursor *cursor)
252b5132 2488{
4a594fce
NC
2489 fprintf (e, "BEGIN\n");
2490 indent (e, 2);
2491 fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n",
2492 (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot,
2493 (int) cursor->xhotspot, (int) cursor->yhotspot);
2494 write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data,
2495 0, 0, 0);
2496 fprintf (e, "END\n");
252b5132
RH
2497}
2498
2499/* Write out group cursor data. This would normally be built from the
2500 cursor data. */
2501
2502static void
4a594fce 2503write_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor)
252b5132 2504{
4a594fce
NC
2505 const rc_group_cursor *gc;
2506 int c;
2507
2508 for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++)
2509 ;
2510 fprintf (e, "BEGIN\n");
252b5132 2511
4a594fce
NC
2512 indent (e, 2);
2513 fprintf (e, "0, 2, %d%s\t /* Having %d items. */\n", c, (c != 0 ? "," : ""), c);
2514 indent (e, 4);
2515 fprintf (e, "/* width, height, planes, bits, bytes, index. */\n");
2516
2517 for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++)
252b5132 2518 {
4a594fce
NC
2519 indent (e, 4);
2520 fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n",
2521 (int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits,
2522 (unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c);
2523 fprintf (e, "/* width: %d; height %d; planes %d; bits %d. */\n",
2524 (int) gc->width, (int) gc->height, (int) gc->planes,
2525 (int) gc->bits);
252b5132 2526 }
4a594fce 2527 fprintf (e, "END\n");
252b5132
RH
2528}
2529
2530/* Write dialog data. */
2531
2532static void
4a594fce 2533write_rc_dialog (FILE *e, const rc_dialog *dialog)
252b5132 2534{
4a594fce 2535 const rc_dialog_control *control;
252b5132 2536
4a594fce 2537 fprintf (e, "STYLE 0x%x\n", dialog->style);
91eafb40 2538
252b5132 2539 if (dialog->exstyle != 0)
4a594fce 2540 fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle);
91eafb40 2541
252b5132
RH
2542 if ((dialog->class.named && dialog->class.u.n.length > 0)
2543 || dialog->class.u.id != 0)
2544 {
2545 fprintf (e, "CLASS ");
df3baf66 2546 res_id_print (e, dialog->class, 1);
252b5132
RH
2547 fprintf (e, "\n");
2548 }
91eafb40 2549
252b5132
RH
2550 if (dialog->caption != NULL)
2551 {
4a594fce
NC
2552 fprintf (e, "CAPTION ");
2553 unicode_print_quoted (e, dialog->caption, -1);
2554 fprintf (e, "\n");
252b5132 2555 }
91eafb40 2556
252b5132
RH
2557 if ((dialog->menu.named && dialog->menu.u.n.length > 0)
2558 || dialog->menu.u.id != 0)
2559 {
2560 fprintf (e, "MENU ");
2561 res_id_print (e, dialog->menu, 0);
2562 fprintf (e, "\n");
2563 }
91eafb40 2564
252b5132
RH
2565 if (dialog->font != NULL)
2566 {
4a594fce
NC
2567 fprintf (e, "FONT %d, ", (int) dialog->pointsize);
2568 unicode_print_quoted (e, dialog->font, -1);
252b5132 2569 if (dialog->ex != NULL
45b99827
NC
2570 && (dialog->ex->weight != 0
2571 || dialog->ex->italic != 0
2572 || dialog->ex->charset != 1))
2573 fprintf (e, ", %d, %d, %d",
4a594fce
NC
2574 (int) dialog->ex->weight,
2575 (int) dialog->ex->italic,
2576 (int) dialog->ex->charset);
252b5132
RH
2577 fprintf (e, "\n");
2578 }
2579
2580 fprintf (e, "BEGIN\n");
2581
2582 for (control = dialog->controls; control != NULL; control = control->next)
2583 write_rc_dialog_control (e, control);
2584
2585 fprintf (e, "END\n");
2586}
2587
2588/* For each predefined control keyword, this table provides the class
2589 and the style. */
2590
2591struct control_info
2592{
2593 const char *name;
2594 unsigned short class;
2595 unsigned long style;
2596};
2597
2598static const struct control_info control_info[] =
2599{
2600 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE },
2601 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX },
2602 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON },
2603 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX },
2604 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 },
2605 { "CTEXT", CTL_STATIC, SS_CENTER },
2606 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON },
2607 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 },
2608 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX },
2609 { "ICON", CTL_STATIC, SS_ICON },
2610 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 },
2611 { "LTEXT", CTL_STATIC, SS_LEFT },
2612 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX },
2613 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON },
2614 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON },
2615 { "RTEXT", CTL_STATIC, SS_RIGHT },
2616 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 },
2617 { "STATE3", CTL_BUTTON, BS_3STATE },
2618 /* It's important that USERBUTTON come after all the other button
2619 types, so that it won't be matched too early. */
2620 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 },
2621 { NULL, 0, 0 }
2622};
2623
2624/* Write a dialog control. */
2625
2626static void
4a594fce 2627write_rc_dialog_control (FILE *e, const rc_dialog_control *control)
252b5132
RH
2628{
2629 const struct control_info *ci;
2630
2631 fprintf (e, " ");
2632
2633 if (control->class.named)
2634 ci = NULL;
2635 else
2636 {
2637 for (ci = control_info; ci->name != NULL; ++ci)
2638 if (ci->class == control->class.u.id
2639 && (ci->style == (unsigned long) -1
2640 || ci->style == (control->style & 0xff)))
2641 break;
2642 }
2643 if (ci == NULL)
2644 fprintf (e, "CONTROL");
2645 else if (ci->name != NULL)
2646 fprintf (e, "%s", ci->name);
2647 else
4a594fce 2648 {
252b5132 2649 fprintf (e, "CONTROL");
4a594fce
NC
2650 ci = NULL;
2651 }
53c7db4b 2652
7afcdbb2
KT
2653 /* For EDITTEXT, COMBOBOX, LISTBOX, and SCROLLBAR don't dump text. */
2654 if ((control->text.named || control->text.u.id != 0)
2655 && (!ci
2656 || (ci->class != CTL_EDIT
2657 && ci->class != CTL_COMBOBOX
2658 && ci->class != CTL_LISTBOX
2659 && ci->class != CTL_SCROLLBAR)))
252b5132
RH
2660 {
2661 fprintf (e, " ");
2662 res_id_print (e, control->text, 1);
2663 fprintf (e, ",");
2664 }
2665
4a594fce 2666 fprintf (e, " %d, ", (int) control->id);
252b5132
RH
2667
2668 if (ci == NULL)
2669 {
2670 if (control->class.named)
2671 fprintf (e, "\"");
2672 res_id_print (e, control->class, 0);
2673 if (control->class.named)
2674 fprintf (e, "\"");
4a594fce 2675 fprintf (e, ", 0x%x, ", (unsigned int) control->style);
252b5132
RH
2676 }
2677
4a594fce 2678 fprintf (e, "%d, %d", (int) control->x, (int) control->y);
252b5132
RH
2679
2680 if (control->style != SS_ICON
2681 || control->exstyle != 0
2682 || control->width != 0
2683 || control->height != 0
2684 || control->help != 0)
2685 {
4a594fce 2686 fprintf (e, ", %d, %d", (int) control->width, (int) control->height);
252b5132
RH
2687
2688 /* FIXME: We don't need to print the style if it is the default.
2689 More importantly, in certain cases we actually need to turn
2690 off parts of the forced style, by using NOT. */
4a594fce
NC
2691 if (ci != NULL)
2692 fprintf (e, ", 0x%x", (unsigned int) control->style);
252b5132
RH
2693
2694 if (control->exstyle != 0 || control->help != 0)
4a594fce
NC
2695 fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle,
2696 (unsigned int) control->help);
252b5132
RH
2697 }
2698
2699 fprintf (e, "\n");
2700
2701 if (control->data != NULL)
2702 write_rc_rcdata (e, control->data, 2);
2703}
2704
2705/* Write out font directory data. This would normally be built from
2706 the font data. */
2707
2708static void
4a594fce 2709write_rc_fontdir (FILE *e, const rc_fontdir *fontdir)
252b5132 2710{
4a594fce
NC
2711 const rc_fontdir *fc;
2712 int c;
252b5132 2713
4a594fce
NC
2714 for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++)
2715 ;
2716 fprintf (e, "BEGIN\n");
2717 indent (e, 2);
2718 fprintf (e, "%d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2719 for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++)
252b5132 2720 {
4a594fce
NC
2721 indent (e, 4);
2722 fprintf (e, "%d,\t/* Font no %d with index %d. */\n",
2723 (int) fc->index, c, (int) fc->index);
2724 write_rc_datablock (e, (rc_uint_type) fc->length - 2,
2725 (const bfd_byte *) fc->data + 4,fc->next != NULL,
2726 0, 0);
252b5132 2727 }
4a594fce 2728 fprintf (e, "END\n");
252b5132
RH
2729}
2730
2731/* Write out group icon data. This would normally be built from the
2732 icon data. */
2733
2734static void
4a594fce 2735write_rc_group_icon (FILE *e, const rc_group_icon *group_icon)
252b5132 2736{
4a594fce
NC
2737 const rc_group_icon *gi;
2738 int c;
2739
2740 for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++)
2741 ;
252b5132 2742
4a594fce
NC
2743 fprintf (e, "BEGIN\n");
2744 indent (e, 2);
2745 fprintf (e, " 0, 1, %d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c);
2746
2747 indent (e, 4);
2748 fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index. */\n");
2749 for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++)
252b5132 2750 {
4a594fce
NC
2751 indent (e, 4);
2752 fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n",
2753 gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits,
2754 (unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c);
252b5132 2755 }
4a594fce 2756 fprintf (e, "END\n");
252b5132
RH
2757}
2758
2759/* Write out a menu resource. */
2760
2761static void
4a594fce 2762write_rc_menu (FILE *e, const rc_menu *menu, int menuex)
252b5132
RH
2763{
2764 if (menu->help != 0)
4a594fce 2765 fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help);
252b5132
RH
2766 write_rc_menuitems (e, menu->items, menuex, 0);
2767}
2768
4a594fce
NC
2769static void
2770write_rc_toolbar (FILE *e, const rc_toolbar *tb)
2771{
2772 rc_toolbar_item *it;
2773 indent (e, 0);
2774 fprintf (e, "BEGIN\n");
2775 it = tb->items;
2776 while(it != NULL)
2777 {
2778 indent (e, 2);
2779 if (it->id.u.id == 0)
2780 fprintf (e, "SEPARATOR\n");
2781 else
2782 fprintf (e, "BUTTON %d\n", (int) it->id.u.id);
2783 it = it->next;
2784 }
2785 indent (e, 0);
2786 fprintf (e, "END\n");
2787}
2788
252b5132
RH
2789/* Write out menuitems. */
2790
2791static void
4a594fce 2792write_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex,
2da42df6 2793 int ind)
252b5132 2794{
4a594fce 2795 const rc_menuitem *mi;
252b5132
RH
2796
2797 indent (e, ind);
2798 fprintf (e, "BEGIN\n");
2799
2800 for (mi = menuitems; mi != NULL; mi = mi->next)
2801 {
2802 indent (e, ind + 2);
2803
2804 if (mi->popup == NULL)
2805 fprintf (e, "MENUITEM");
2806 else
2807 fprintf (e, "POPUP");
2808
2809 if (! menuex
2810 && mi->popup == NULL
2811 && mi->text == NULL
2812 && mi->type == 0
2813 && mi->id == 0)
2814 {
2815 fprintf (e, " SEPARATOR\n");
2816 continue;
2817 }
2818
2819 if (mi->text == NULL)
2820 fprintf (e, " \"\"");
2821 else
2822 {
4a594fce
NC
2823 fprintf (e, " ");
2824 unicode_print_quoted (e, mi->text, -1);
252b5132
RH
2825 }
2826
2827 if (! menuex)
2828 {
2829 if (mi->popup == NULL)
4a594fce 2830 fprintf (e, ", %d", (int) mi->id);
252b5132
RH
2831
2832 if ((mi->type & MENUITEM_CHECKED) != 0)
2833 fprintf (e, ", CHECKED");
2834 if ((mi->type & MENUITEM_GRAYED) != 0)
2835 fprintf (e, ", GRAYED");
2836 if ((mi->type & MENUITEM_HELP) != 0)
2837 fprintf (e, ", HELP");
2838 if ((mi->type & MENUITEM_INACTIVE) != 0)
2839 fprintf (e, ", INACTIVE");
2840 if ((mi->type & MENUITEM_MENUBARBREAK) != 0)
2841 fprintf (e, ", MENUBARBREAK");
2842 if ((mi->type & MENUITEM_MENUBREAK) != 0)
2843 fprintf (e, ", MENUBREAK");
2844 }
2845 else
2846 {
2847 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0)
2848 {
4a594fce 2849 fprintf (e, ", %d", (int) mi->id);
252b5132
RH
2850 if (mi->type != 0 || mi->state != 0 || mi->help != 0)
2851 {
4a594fce 2852 fprintf (e, ", %u", (unsigned int) mi->type);
252b5132
RH
2853 if (mi->state != 0 || mi->help != 0)
2854 {
4a594fce 2855 fprintf (e, ", %u", (unsigned int) mi->state);
252b5132 2856 if (mi->help != 0)
4a594fce 2857 fprintf (e, ", %u", (unsigned int) mi->help);
252b5132
RH
2858 }
2859 }
2860 }
2861 }
2862
2863 fprintf (e, "\n");
2864
2865 if (mi->popup != NULL)
2866 write_rc_menuitems (e, mi->popup, menuex, ind + 2);
2867 }
2868
2869 indent (e, ind);
2870 fprintf (e, "END\n");
2871}
2872
4a594fce
NC
2873static int
2874test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data)
252b5132 2875{
4a594fce
NC
2876 rc_uint_type i;
2877 if ((length & 1) != 0)
2878 return 0;
252b5132 2879
4a594fce
NC
2880 for (i = 0; i < length; i += 2)
2881 {
2882 if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length)
2883 return 0;
2884 if (data[i] == 0xff && data[i + 1] == 0xff)
2885 return 0;
2886 }
2887 return 1;
2888}
252b5132 2889
4a594fce
NC
2890static int
2891test_rc_datablock_text (rc_uint_type length, const bfd_byte *data)
2892{
2893 int has_nl;
2894 rc_uint_type c;
2895 rc_uint_type i;
2896
2897 if (length <= 1)
2898 return 0;
2899
2900 has_nl = 0;
2901 for (i = 0, c = 0; i < length; i++)
252b5132 2902 {
4a594fce
NC
2903 if (! ISPRINT (data[i]) && data[i] != '\n'
2904 && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n')
2905 && data[i] != '\t'
2906 && ! (data[i] == 0 && (i + 1) != length))
2907 {
2908 if (data[i] <= 7)
2909 return 0;
2910 c++;
2911 }
2912 else if (data[i] == '\n') has_nl++;
2913 }
2914 if (length > 80 && ! has_nl)
2915 return 0;
2916 c = (((c * 10000) + (i / 100) - 1)) / i;
2917 if (c >= 150)
2918 return 0;
2919 return 1;
2920}
252b5132 2921
4a594fce
NC
2922static void
2923write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data)
2924{
2925 int has_error = 0;
2926 const struct bin_messagetable *mt;
2927 fprintf (e, "BEGIN\n");
252b5132 2928
4a594fce 2929 write_rc_datablock (e, length, data, 0, 0, 0);
252b5132 2930
4a594fce
NC
2931 fprintf (e, "\n");
2932 wr_printcomment (e, "MC syntax dump");
2933 if (length < BIN_MESSAGETABLE_SIZE)
2934 has_error = 1;
2935 else
2936 do {
2937 rc_uint_type m, i;
2938 mt = (const struct bin_messagetable *) data;
2939 m = windres_get_32 (&wrtarget, mt->cblocks, length);
2940 if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE))
2941 {
2942 has_error = 1;
252b5132 2943 break;
4a594fce
NC
2944 }
2945 for (i = 0; i < m; i++)
2946 {
2947 rc_uint_type low, high, offset;
2948 const struct bin_messagetable_item *mti;
252b5132 2949
4a594fce
NC
2950 low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4);
2951 high = windres_get_32 (&wrtarget, mt->items[i].highid, 4);
2952 offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4);
2953 while (low <= high)
2954 {
2955 rc_uint_type elen, flags;
2956 if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length)
2957 {
2958 has_error = 1;
252b5132 2959 break;
4a594fce
NC
2960 }
2961 mti = (const struct bin_messagetable_item *) &data[offset];
2962 elen = windres_get_16 (&wrtarget, mti->length, 2);
2963 flags = windres_get_16 (&wrtarget, mti->flags, 2);
2964 if ((offset + elen) > length)
2965 {
2966 has_error = 1;
2967 break;
2968 }
2969 wr_printcomment (e, "MessageId = 0x%x", low);
2970 wr_printcomment (e, "");
2971 if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE)
2972 unicode_print (e, (const unichar *) mti->data,
2973 (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2);
2974 else
2975 ascii_print (e, (const char *) mti->data,
2976 (elen - BIN_MESSAGETABLE_ITEM_SIZE));
2977 wr_printcomment (e,"");
2978 ++low;
2979 offset += elen;
2980 }
2981 }
2982 } while (0);
2983 if (has_error)
2984 wr_printcomment (e, "Illegal data");
2985 wr_print_flush (e);
2986 fprintf (e, "END\n");
2987}
252b5132 2988
4a594fce
NC
2989static void
2990write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next,
2991 int hasblock, int show_comment)
2992{
2993 int plen;
252b5132 2994
4a594fce
NC
2995 if (hasblock)
2996 fprintf (e, "BEGIN\n");
2997
2998 if (show_comment == -1)
2999 {
3000 if (test_rc_datablock_text(length, data))
3001 {
3002 rc_uint_type i, c;
3003 for (i = 0; i < length;)
3004 {
3005 indent (e, 2);
3006 fprintf (e, "\"");
3007
3008 for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++)
3009 ;
3010 if (i < length && data[i] == '\n')
3011 ++i, ++c;
3012 ascii_print (e, (const char *) &data[i - c], c);
252b5132 3013 fprintf (e, "\"");
4a594fce
NC
3014 if (i < length)
3015 fprintf (e, "\n");
3016 }
3017
3018 if (i == 0)
252b5132 3019 {
4a594fce
NC
3020 indent (e, 2);
3021 fprintf (e, "\"\"");
252b5132 3022 }
4a594fce
NC
3023 if (has_next)
3024 fprintf (e, ",");
3025 fprintf (e, "\n");
3026 if (hasblock)
3027 fprintf (e, "END\n");
3028 return;
252b5132 3029 }
4a594fce
NC
3030 if (test_rc_datablock_unicode (length, data))
3031 {
3032 rc_uint_type i, c;
3033 for (i = 0; i < length;)
3034 {
3035 const unichar *u;
252b5132 3036
4a594fce
NC
3037 u = (const unichar *) &data[i];
3038 indent (e, 2);
252b5132 3039 fprintf (e, "L\"");
4a594fce
NC
3040
3041 for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2)
3042 ;
3043 if (i < length && u[c] == '\n')
3044 i += 2, ++c;
3045 unicode_print (e, u, c);
252b5132 3046 fprintf (e, "\"");
4a594fce
NC
3047 if (i < length)
3048 fprintf (e, "\n");
3049 }
252b5132 3050
4a594fce 3051 if (i == 0)
252b5132 3052 {
4a594fce
NC
3053 indent (e, 2);
3054 fprintf (e, "L\"\"");
3055 }
3056 if (has_next)
3057 fprintf (e, ",");
3058 fprintf (e, "\n");
3059 if (hasblock)
3060 fprintf (e, "END\n");
3061 return;
3062 }
252b5132 3063
4a594fce
NC
3064 show_comment = 0;
3065 }
252b5132 3066
4a594fce 3067 if (length != 0)
252b5132 3068 {
4a594fce
NC
3069 rc_uint_type i, max_row;
3070 int first = 1;
252b5132 3071
4a594fce
NC
3072 max_row = (show_comment ? 4 : 8);
3073 indent (e, 2);
3074 for (i = 0; i + 3 < length;)
252b5132 3075 {
4a594fce
NC
3076 rc_uint_type k;
3077 rc_uint_type comment_start;
3078
3079 comment_start = i;
3080
3081 if (! first)
3082 indent (e, 2);
3083
3084 for (k = 0; k < max_row && i + 3 < length; k++, i += 4)
34ca6cf8 3085 {
4a594fce
NC
3086 if (k == 0)
3087 plen = fprintf (e, "0x%lxL",
0af1713e 3088 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i));
34ca6cf8 3089 else
4a594fce 3090 plen = fprintf (e, " 0x%lxL",
0af1713e 3091 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1;
4a594fce 3092 if (has_next || (i + 4) < length)
34ca6cf8 3093 {
4a594fce
NC
3094 if (plen>0 && plen < 11)
3095 indent (e, 11 - plen);
3096 fprintf (e, ",");
34ca6cf8
ILT
3097 }
3098 }
4a594fce
NC
3099 if (show_comment)
3100 {
3101 fprintf (e, "\t/* ");
3102 ascii_print (e, (const char *) &data[comment_start], i - comment_start);
3103 fprintf (e, ". */");
252b5132 3104 }
34ca6cf8
ILT
3105 fprintf (e, "\n");
3106 first = 0;
252b5132
RH
3107 }
3108
4a594fce 3109 if (i + 1 < length)
252b5132 3110 {
34ca6cf8 3111 if (! first)
4a594fce
NC
3112 indent (e, 2);
3113 plen = fprintf (e, "0x%x",
3114 (int) windres_get_16 (&wrtarget, data + i, length - i));
3115 if (has_next || i + 2 < length)
252b5132 3116 {
4a594fce
NC
3117 if (plen > 0 && plen < 11)
3118 indent (e, 11 - plen);
3119 fprintf (e, ",");
34ca6cf8 3120 }
4a594fce
NC
3121 if (show_comment)
3122 {
3123 fprintf (e, "\t/* ");
3124 ascii_print (e, (const char *) &data[i], 2);
3125 fprintf (e, ". */");
252b5132 3126 }
34ca6cf8 3127 fprintf (e, "\n");
252b5132 3128 i += 2;
34ca6cf8 3129 first = 0;
252b5132
RH
3130 }
3131
4a594fce 3132 if (i < length)
252b5132 3133 {
34ca6cf8 3134 if (! first)
4a594fce
NC
3135 indent (e, 2);
3136 fprintf (e, "\"");
3137 ascii_print (e, (const char *) &data[i], 1);
3138 fprintf (e, "\"");
3139 if (has_next)
34ca6cf8
ILT
3140 fprintf (e, ",");
3141 fprintf (e, "\n");
3142 first = 0;
252b5132 3143 }
4a594fce
NC
3144 }
3145 if (hasblock)
3146 fprintf (e, "END\n");
3147}
3148
3149/* Write out an rcdata resource. This is also used for other types of
3150 resources that need to print arbitrary data. */
3151
3152static void
3153write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind)
3154{
3155 const rc_rcdata_item *ri;
3156
3157 indent (e, ind);
3158 fprintf (e, "BEGIN\n");
3159
3160 for (ri = rcdata; ri != NULL; ri = ri->next)
3161 {
3162 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0)
3163 continue;
252b5132 3164
4a594fce
NC
3165 switch (ri->type)
3166 {
3167 default:
3168 abort ();
3169
3170 case RCDATA_WORD:
3171 indent (e, ind + 2);
3172 fprintf (e, "%ld", (long) (ri->u.word & 0xffff));
3173 break;
3174
3175 case RCDATA_DWORD:
3176 indent (e, ind + 2);
3177 fprintf (e, "%luL", (unsigned long) ri->u.dword);
3178 break;
3179
3180 case RCDATA_STRING:
3181 indent (e, ind + 2);
3182 fprintf (e, "\"");
3183 ascii_print (e, ri->u.string.s, ri->u.string.length);
3184 fprintf (e, "\"");
3185 break;
3186
3187 case RCDATA_WSTRING:
3188 indent (e, ind + 2);
3189 fprintf (e, "L\"");
3190 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length);
3191 fprintf (e, "\"");
3192 break;
3193
3194 case RCDATA_BUFFER:
3195 write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length,
3196 (const bfd_byte *) ri->u.buffer.data,
3197 ri->next != NULL, 0, -1);
252b5132 3198 break;
252b5132
RH
3199 }
3200
34ca6cf8
ILT
3201 if (ri->type != RCDATA_BUFFER)
3202 {
3203 if (ri->next != NULL)
3204 fprintf (e, ",");
3205 fprintf (e, "\n");
3206 }
252b5132
RH
3207 }
3208
3209 indent (e, ind);
3210 fprintf (e, "END\n");
3211}
3212
3213/* Write out a stringtable resource. */
3214
3215static void
4a594fce
NC
3216write_rc_stringtable (FILE *e, const rc_res_id *name,
3217 const rc_stringtable *stringtable)
252b5132 3218{
4a594fce 3219 rc_uint_type offset;
252b5132
RH
3220 int i;
3221
3222 if (name != NULL && ! name->named)
3223 offset = (name->u.id - 1) << 4;
3224 else
3225 {
4a594fce 3226 fprintf (e, "/* %s string table name. */\n",
252b5132
RH
3227 name == NULL ? "Missing" : "Invalid");
3228 offset = 0;
3229 }
3230
3231 fprintf (e, "BEGIN\n");
3232
3233 for (i = 0; i < 16; i++)
3234 {
3235 if (stringtable->strings[i].length != 0)
3236 {
0af1713e 3237 fprintf (e, " %lu, ", (unsigned long) offset + i);
4a594fce 3238 unicode_print_quoted (e, stringtable->strings[i].string,
252b5132 3239 stringtable->strings[i].length);
4a594fce 3240 fprintf (e, "\n");
252b5132
RH
3241 }
3242 }
3243
3244 fprintf (e, "END\n");
3245}
3246
3247/* Write out a versioninfo resource. */
3248
3249static void
4a594fce 3250write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo)
252b5132 3251{
4a594fce
NC
3252 const rc_fixed_versioninfo *f;
3253 const rc_ver_info *vi;
252b5132
RH
3254
3255 f = versioninfo->fixed;
3256 if (f->file_version_ms != 0 || f->file_version_ls != 0)
4a594fce
NC
3257 fprintf (e, " FILEVERSION %u, %u, %u, %u\n",
3258 (unsigned int) ((f->file_version_ms >> 16) & 0xffff),
3259 (unsigned int) (f->file_version_ms & 0xffff),
3260 (unsigned int) ((f->file_version_ls >> 16) & 0xffff),
3261 (unsigned int) (f->file_version_ls & 0xffff));
252b5132 3262 if (f->product_version_ms != 0 || f->product_version_ls != 0)
4a594fce
NC
3263 fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n",
3264 (unsigned int) ((f->product_version_ms >> 16) & 0xffff),
3265 (unsigned int) (f->product_version_ms & 0xffff),
3266 (unsigned int) ((f->product_version_ls >> 16) & 0xffff),
3267 (unsigned int) (f->product_version_ls & 0xffff));
252b5132 3268 if (f->file_flags_mask != 0)
4a594fce 3269 fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask);
252b5132 3270 if (f->file_flags != 0)
4a594fce 3271 fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags);
252b5132 3272 if (f->file_os != 0)
4a594fce 3273 fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os);
252b5132 3274 if (f->file_type != 0)
4a594fce 3275 fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type);
252b5132 3276 if (f->file_subtype != 0)
4a594fce 3277 fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype);
252b5132 3278 if (f->file_date_ms != 0 || f->file_date_ls != 0)
4a594fce
NC
3279 fprintf (e, "/* Date: %u, %u. */\n",
3280 (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls);
252b5132
RH
3281
3282 fprintf (e, "BEGIN\n");
3283
3284 for (vi = versioninfo->var; vi != NULL; vi = vi->next)
3285 {
3286 switch (vi->type)
3287 {
3288 case VERINFO_STRING:
3289 {
bfb6c1ab 3290 const rc_ver_stringtable *vst;
4a594fce 3291 const rc_ver_stringinfo *vs;
252b5132
RH
3292
3293 fprintf (e, " BLOCK \"StringFileInfo\"\n");
3294 fprintf (e, " BEGIN\n");
252b5132 3295
bfb6c1ab 3296 for (vst = vi->u.string.stringtables; vst != NULL; vst = vst->next)
252b5132 3297 {
bfb6c1ab
NC
3298 fprintf (e, " BLOCK ");
3299 unicode_print_quoted (e, vst->language, -1);
3300
4a594fce 3301 fprintf (e, "\n");
bfb6c1ab
NC
3302 fprintf (e, " BEGIN\n");
3303
3304 for (vs = vst->strings; vs != NULL; vs = vs->next)
3305 {
3306 fprintf (e, " VALUE ");
3307 unicode_print_quoted (e, vs->key, -1);
3308 fprintf (e, ", ");
3309 unicode_print_quoted (e, vs->value, -1);
3310 fprintf (e, "\n");
3311 }
252b5132 3312
bfb6c1ab
NC
3313 fprintf (e, " END\n");
3314 }
252b5132
RH
3315 fprintf (e, " END\n");
3316 break;
3317 }
3318
3319 case VERINFO_VAR:
3320 {
4a594fce 3321 const rc_ver_varinfo *vv;
252b5132
RH
3322
3323 fprintf (e, " BLOCK \"VarFileInfo\"\n");
3324 fprintf (e, " BEGIN\n");
4a594fce
NC
3325 fprintf (e, " VALUE ");
3326 unicode_print_quoted (e, vi->u.var.key, -1);
252b5132
RH
3327
3328 for (vv = vi->u.var.var; vv != NULL; vv = vv->next)
3329 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language,
4a594fce 3330 (int) vv->charset);
252b5132
RH
3331
3332 fprintf (e, "\n END\n");
3333
3334 break;
3335 }
3336 }
3337 }
3338
3339 fprintf (e, "END\n");
3340}
3341
4a594fce
NC
3342static rc_uint_type
3343rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst)
252b5132 3344{
4a594fce
NC
3345 if (! src)
3346 return 0;
3347 switch (src->type)
252b5132 3348 {
4a594fce
NC
3349 case RCDATA_WORD:
3350 if (dst)
3351 windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word);
3352 return 2;
3353 case RCDATA_DWORD:
3354 if (dst)
3355 windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword);
3356 return 4;
3357 case RCDATA_STRING:
3358 if (dst && src->u.string.length)
3359 memcpy (dst, src->u.string.s, src->u.string.length);
3360 return (rc_uint_type) src->u.string.length;
3361 case RCDATA_WSTRING:
3362 if (dst && src->u.wstring.length)
3363 memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar));
3364 return (rc_uint_type) (src->u.wstring.length * sizeof (unichar));
3365 case RCDATA_BUFFER:
3366 if (dst && src->u.buffer.length)
3367 memcpy (dst, src->u.buffer.data, src->u.buffer.length);
3368 return (rc_uint_type) src->u.buffer.length;
3369 default:
3370 abort ();
252b5132 3371 }
4a594fce
NC
3372 /* Never reached. */
3373 return 0;
252b5132 3374}
This page took 0.677684 seconds and 4 git commands to generate.