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