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