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