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