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