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