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