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