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