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