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