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