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