2007-06-04 Olivier Hainque <hainque@adacore.com>
[binutils.git] / binutils / windres.c
blob90918a6e90563686f6038203a068e98d4534ea9f
1 /* windres.c -- a program to manipulate Windows resources
2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007
3 Free Software Foundation, Inc.
4 Written by Ian Lance Taylor, Cygnus Support.
5 Rewritten by Kai Tietz, Onevision.
7 This file is part of GNU Binutils.
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.
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.
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. */
24 /* This program can read and write Windows resources in various
25 formats. In particular, it can act like the rc resource compiler
26 program, and it can act like the cvtres res to COFF conversion
27 program.
29 It is based on information taken from the following sources:
31 * Microsoft documentation.
33 * The rcl program, written by Gunther Ebert
34 <gunther.ebert@ixos-leipzig.de>.
36 * The res2coff program, written by Pedro A. Aranda <paag@tid.es>. */
38 #include "sysdep.h"
39 #include <assert.h>
40 #include <time.h>
41 #include "bfd.h"
42 #include "getopt.h"
43 #include "bucomm.h"
44 #include "libiberty.h"
45 #include "safe-ctype.h"
46 #include "obstack.h"
47 #include "windres.h"
49 /* Defined in bfd/binary.c. Used to set architecture and machine of input
50 binary files. */
51 extern enum bfd_architecture bfd_external_binary_architecture;
52 extern unsigned long bfd_external_machine;
54 /* Used by resrc.c at least. */
56 int verbose = 0;
58 int target_is_bigendian = 0;
59 const char *def_target_arch;
61 static void set_endianess (bfd *, const char *);
63 /* An enumeration of format types. */
65 enum res_format
67 /* Unknown format. */
68 RES_FORMAT_UNKNOWN,
69 /* Textual RC file. */
70 RES_FORMAT_RC,
71 /* Binary RES file. */
72 RES_FORMAT_RES,
73 /* COFF file. */
74 RES_FORMAT_COFF
77 /* A structure used to map between format types and strings. */
79 struct format_map
81 const char *name;
82 enum res_format format;
85 /* A mapping between names and format types. */
87 static const struct format_map format_names[] =
89 { "rc", RES_FORMAT_RC },
90 { "res", RES_FORMAT_RES },
91 { "coff", RES_FORMAT_COFF },
92 { NULL, RES_FORMAT_UNKNOWN }
95 /* A mapping from file extensions to format types. */
97 static const struct format_map format_fileexts[] =
99 { "rc", RES_FORMAT_RC },
100 { "res", RES_FORMAT_RES },
101 { "exe", RES_FORMAT_COFF },
102 { "obj", RES_FORMAT_COFF },
103 { "o", RES_FORMAT_COFF },
104 { NULL, RES_FORMAT_UNKNOWN }
107 /* A list of include directories. */
109 struct include_dir
111 struct include_dir *next;
112 char *dir;
115 static struct include_dir *include_dirs;
117 /* Static functions. */
119 static void res_init (void);
120 static int extended_menuitems (const rc_menuitem *);
121 static enum res_format format_from_name (const char *, int);
122 static enum res_format format_from_filename (const char *, int);
123 static void usage (FILE *, int);
124 static int cmp_res_entry (const void *, const void *);
125 static rc_res_directory *sort_resources (rc_res_directory *);
126 static void reswr_init (void);
127 static const char * quot (const char *);
129 static rc_uint_type target_get_8 (const void *, rc_uint_type);
130 static void target_put_8 (void *, rc_uint_type);
131 static rc_uint_type target_get_16 (const void *, rc_uint_type);
132 static void target_put_16 (void *, rc_uint_type);
133 static rc_uint_type target_get_32 (const void *, rc_uint_type);
134 static void target_put_32 (void *, rc_uint_type);
137 /* When we are building a resource tree, we allocate everything onto
138 an obstack, so that we can free it all at once if we want. */
140 #define obstack_chunk_alloc xmalloc
141 #define obstack_chunk_free free
143 /* The resource building obstack. */
145 static struct obstack res_obstack;
147 /* Initialize the resource building obstack. */
149 static void
150 res_init (void)
152 obstack_init (&res_obstack);
155 /* Allocate space on the resource building obstack. */
157 void *
158 res_alloc (rc_uint_type bytes)
160 return (void *) obstack_alloc (&res_obstack, (size_t) bytes);
163 /* We also use an obstack to save memory used while writing out a set
164 of resources. */
166 static struct obstack reswr_obstack;
168 /* Initialize the resource writing obstack. */
170 static void
171 reswr_init (void)
173 obstack_init (&reswr_obstack);
176 /* Allocate space on the resource writing obstack. */
178 void *
179 reswr_alloc (rc_uint_type bytes)
181 return (void *) obstack_alloc (&reswr_obstack, (size_t) bytes);
184 /* Open a file using the include directory search list. */
186 FILE *
187 open_file_search (const char *filename, const char *mode, const char *errmsg,
188 char **real_filename)
190 FILE *e;
191 struct include_dir *d;
193 e = fopen (filename, mode);
194 if (e != NULL)
196 *real_filename = xstrdup (filename);
197 return e;
200 if (errno == ENOENT)
202 for (d = include_dirs; d != NULL; d = d->next)
204 char *n;
206 n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
207 sprintf (n, "%s/%s", d->dir, filename);
208 e = fopen (n, mode);
209 if (e != NULL)
211 *real_filename = n;
212 return e;
215 if (errno != ENOENT)
216 break;
220 fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
222 /* Return a value to avoid a compiler warning. */
223 return NULL;
226 /* Compare two resource ID's. We consider name entries to come before
227 numeric entries, because that is how they appear in the COFF .rsrc
228 section. */
231 res_id_cmp (rc_res_id a, rc_res_id b)
233 if (! a.named)
235 if (b.named)
236 return 1;
237 if (a.u.id > b.u.id)
238 return 1;
239 else if (a.u.id < b.u.id)
240 return -1;
241 else
242 return 0;
244 else
246 unichar *as, *ase, *bs, *bse;
248 if (! b.named)
249 return -1;
251 as = a.u.n.name;
252 ase = as + a.u.n.length;
253 bs = b.u.n.name;
254 bse = bs + b.u.n.length;
256 while (as < ase)
258 int i;
260 if (bs >= bse)
261 return 1;
262 i = (int) *as - (int) *bs;
263 if (i != 0)
264 return i;
265 ++as;
266 ++bs;
269 if (bs < bse)
270 return -1;
272 return 0;
276 /* Print a resource ID. */
278 void
279 res_id_print (FILE *stream, rc_res_id id, int quote)
281 if (! id.named)
282 fprintf (stream, "%u", (int) id.u.id);
283 else
285 if (quote)
286 unicode_print_quoted (stream, id.u.n.name, id.u.n.length);
287 else
288 unicode_print (stream, id.u.n.name, id.u.n.length);
292 /* Print a list of resource ID's. */
294 void
295 res_ids_print (FILE *stream, int cids, const rc_res_id *ids)
297 int i;
299 for (i = 0; i < cids; i++)
301 res_id_print (stream, ids[i], 1);
302 if (i + 1 < cids)
303 fprintf (stream, ": ");
307 /* Convert an ASCII string to a resource ID. */
309 void
310 res_string_to_id (rc_res_id *res_id, const char *string)
312 res_id->named = 1;
313 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
316 /* Convert an unicode string to a resource ID. */
317 void
318 res_unistring_to_id (rc_res_id *res_id, const unichar *u)
320 res_id->named = 1;
321 res_id->u.n.length = unichar_len (u);
322 res_id->u.n.name = unichar_dup_uppercase (u);
325 /* Define a resource. The arguments are the resource tree, RESOURCES,
326 and the location at which to put it in the tree, CIDS and IDS.
327 This returns a newly allocated rc_res_resource structure, which the
328 caller is expected to initialize. If DUPOK is non-zero, then if a
329 resource with this ID exists, it is returned. Otherwise, a warning
330 is issued, and a new resource is created replacing the existing
331 one. */
333 rc_res_resource *
334 define_resource (rc_res_directory **resources, int cids,
335 const rc_res_id *ids, int dupok)
337 rc_res_entry *re = NULL;
338 int i;
340 assert (cids > 0);
341 for (i = 0; i < cids; i++)
343 rc_res_entry **pp;
345 if (*resources == NULL)
347 static unsigned int timeval;
349 /* Use the same timestamp for every resource created in a
350 single run. */
351 if (timeval == 0)
352 timeval = time (NULL);
354 *resources = ((rc_res_directory *)
355 res_alloc (sizeof (rc_res_directory)));
356 (*resources)->characteristics = 0;
357 (*resources)->time = timeval;
358 (*resources)->major = 0;
359 (*resources)->minor = 0;
360 (*resources)->entries = NULL;
363 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
364 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
365 break;
367 if (*pp != NULL)
368 re = *pp;
369 else
371 re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
372 re->next = NULL;
373 re->id = ids[i];
374 if ((i + 1) < cids)
376 re->subdir = 1;
377 re->u.dir = NULL;
379 else
381 re->subdir = 0;
382 re->u.res = NULL;
385 *pp = re;
388 if ((i + 1) < cids)
390 if (! re->subdir)
392 fprintf (stderr, "%s: ", program_name);
393 res_ids_print (stderr, i, ids);
394 fprintf (stderr, _(": expected to be a directory\n"));
395 xexit (1);
398 resources = &re->u.dir;
402 if (re->subdir)
404 fprintf (stderr, "%s: ", program_name);
405 res_ids_print (stderr, cids, ids);
406 fprintf (stderr, _(": expected to be a leaf\n"));
407 xexit (1);
410 if (re->u.res != NULL)
412 if (dupok)
413 return re->u.res;
415 fprintf (stderr, _("%s: warning: "), program_name);
416 res_ids_print (stderr, cids, ids);
417 fprintf (stderr, _(": duplicate value\n"));
420 re->u.res = ((rc_res_resource *)
421 res_alloc (sizeof (rc_res_resource)));
422 memset (re->u.res, 0, sizeof (rc_res_resource));
424 re->u.res->type = RES_TYPE_UNINITIALIZED;
425 return re->u.res;
428 /* Define a standard resource. This is a version of define_resource
429 that just takes type, name, and language arguments. */
431 rc_res_resource *
432 define_standard_resource (rc_res_directory **resources, int type,
433 rc_res_id name, rc_uint_type language, int dupok)
435 rc_res_id a[3];
437 a[0].named = 0;
438 a[0].u.id = type;
439 a[1] = name;
440 a[2].named = 0;
441 a[2].u.id = language;
442 return define_resource (resources, 3, a, dupok);
445 /* Comparison routine for resource sorting. */
447 static int
448 cmp_res_entry (const void *p1, const void *p2)
450 const rc_res_entry **re1, **re2;
452 re1 = (const rc_res_entry **) p1;
453 re2 = (const rc_res_entry **) p2;
454 return res_id_cmp ((*re1)->id, (*re2)->id);
457 /* Sort the resources. */
459 static rc_res_directory *
460 sort_resources (rc_res_directory *resdir)
462 int c, i;
463 rc_res_entry *re;
464 rc_res_entry **a;
466 if (resdir->entries == NULL)
467 return resdir;
469 c = 0;
470 for (re = resdir->entries; re != NULL; re = re->next)
471 ++c;
473 /* This is a recursive routine, so using xmalloc is probably better
474 than alloca. */
475 a = (rc_res_entry **) xmalloc (c * sizeof (rc_res_entry *));
477 for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
478 a[i] = re;
480 qsort (a, c, sizeof (rc_res_entry *), cmp_res_entry);
482 resdir->entries = a[0];
483 for (i = 0; i < c - 1; i++)
484 a[i]->next = a[i + 1];
485 a[i]->next = NULL;
487 free (a);
489 /* Now sort the subdirectories. */
491 for (re = resdir->entries; re != NULL; re = re->next)
492 if (re->subdir)
493 re->u.dir = sort_resources (re->u.dir);
495 return resdir;
498 /* Return whether the dialog resource DIALOG is a DIALOG or a
499 DIALOGEX. */
502 extended_dialog (const rc_dialog *dialog)
504 const rc_dialog_control *c;
506 if (dialog->ex != NULL)
507 return 1;
509 for (c = dialog->controls; c != NULL; c = c->next)
510 if (c->data != NULL || c->help != 0)
511 return 1;
513 return 0;
516 /* Return whether MENUITEMS are a MENU or a MENUEX. */
519 extended_menu (const rc_menu *menu)
521 return extended_menuitems (menu->items);
524 static int
525 extended_menuitems (const rc_menuitem *menuitems)
527 const rc_menuitem *mi;
529 for (mi = menuitems; mi != NULL; mi = mi->next)
531 if (mi->help != 0 || mi->state != 0)
532 return 1;
533 if (mi->popup != NULL && mi->id != 0)
534 return 1;
535 if ((mi->type
536 & ~ (MENUITEM_CHECKED
537 | MENUITEM_GRAYED
538 | MENUITEM_HELP
539 | MENUITEM_INACTIVE
540 | MENUITEM_MENUBARBREAK
541 | MENUITEM_MENUBREAK))
542 != 0)
543 return 1;
544 if (mi->popup != NULL)
546 if (extended_menuitems (mi->popup))
547 return 1;
551 return 0;
554 /* Convert a string to a format type, or exit if it can't be done. */
556 static enum res_format
557 format_from_name (const char *name, int exit_on_error)
559 const struct format_map *m;
561 for (m = format_names; m->name != NULL; m++)
562 if (strcasecmp (m->name, name) == 0)
563 break;
565 if (m->name == NULL && exit_on_error)
567 non_fatal (_("unknown format type `%s'"), name);
568 fprintf (stderr, _("%s: supported formats:"), program_name);
569 for (m = format_names; m->name != NULL; m++)
570 fprintf (stderr, " %s", m->name);
571 fprintf (stderr, "\n");
572 xexit (1);
575 return m->format;
578 /* Work out a format type given a file name. If INPUT is non-zero,
579 it's OK to look at the file itself. */
581 static enum res_format
582 format_from_filename (const char *filename, int input)
584 const char *ext;
585 FILE *e;
586 bfd_byte b1, b2, b3, b4, b5;
587 int magic;
589 /* If we have an extension, see if we recognize it as implying a
590 particular format. */
591 ext = strrchr (filename, '.');
592 if (ext != NULL)
594 const struct format_map *m;
596 ++ext;
597 for (m = format_fileexts; m->name != NULL; m++)
598 if (strcasecmp (m->name, ext) == 0)
599 return m->format;
602 /* If we don't recognize the name of an output file, assume it's a
603 COFF file. */
604 if (! input)
605 return RES_FORMAT_COFF;
607 /* Read the first few bytes of the file to see if we can guess what
608 it is. */
609 e = fopen (filename, FOPEN_RB);
610 if (e == NULL)
611 fatal ("%s: %s", filename, strerror (errno));
613 b1 = getc (e);
614 b2 = getc (e);
615 b3 = getc (e);
616 b4 = getc (e);
617 b5 = getc (e);
619 fclose (e);
621 /* A PE executable starts with 0x4d 0x5a. */
622 if (b1 == 0x4d && b2 == 0x5a)
623 return RES_FORMAT_COFF;
625 /* A COFF .o file starts with a COFF magic number. */
626 magic = (b2 << 8) | b1;
627 switch (magic)
629 case 0x14c: /* i386 */
630 case 0x166: /* MIPS */
631 case 0x184: /* Alpha */
632 case 0x268: /* 68k */
633 case 0x1f0: /* PowerPC */
634 case 0x290: /* PA */
635 return RES_FORMAT_COFF;
638 /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */
639 if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
640 return RES_FORMAT_RES;
642 /* If every character is printable or space, assume it's an RC file. */
643 if ((ISPRINT (b1) || ISSPACE (b1))
644 && (ISPRINT (b2) || ISSPACE (b2))
645 && (ISPRINT (b3) || ISSPACE (b3))
646 && (ISPRINT (b4) || ISSPACE (b4))
647 && (ISPRINT (b5) || ISSPACE (b5)))
648 return RES_FORMAT_RC;
650 /* Otherwise, we give up. */
651 fatal (_("can not determine type of file `%s'; use the -J option"),
652 filename);
654 /* Return something to silence the compiler warning. */
655 return RES_FORMAT_UNKNOWN;
658 /* Print a usage message and exit. */
660 static void
661 usage (FILE *stream, int status)
663 fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
664 program_name);
665 fprintf (stream, _(" The options are:\n\
666 -i --input=<file> Name input file\n\
667 -o --output=<file> Name output file\n\
668 -J --input-format=<format> Specify input format\n\
669 -O --output-format=<format> Specify output format\n\
670 -F --target=<target> Specify COFF target\n\
671 --preprocessor=<program> Program to use to preprocess rc file\n\
672 -I --include-dir=<dir> Include directory when preprocessing rc file\n\
673 -D --define <sym>[=<val>] Define SYM when preprocessing rc file\n\
674 -U --undefine <sym> Undefine SYM when preprocessing rc file\n\
675 -v --verbose Verbose - tells you what it's doing\n\
676 -l --language=<val> Set language when reading rc file\n\
677 --use-temp-file Use a temporary file instead of popen to read\n\
678 the preprocessor output\n\
679 --no-use-temp-file Use popen (default)\n"));
680 #ifdef YYDEBUG
681 fprintf (stream, _("\
682 --yydebug Turn on parser debugging\n"));
683 #endif
684 fprintf (stream, _("\
685 -r Ignored for compatibility with rc\n\
686 @<file> Read options from <file>\n\
687 -h --help Print this help message\n\
688 -V --version Print version information\n"));
689 fprintf (stream, _("\
690 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
691 extension if not specified. A single file name is an input file.\n\
692 No input-file is stdin, default rc. No output-file is stdout, default rc.\n"));
694 list_supported_targets (program_name, stream);
696 if (REPORT_BUGS_TO[0] && status == 0)
697 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
699 exit (status);
702 /* Quote characters that will confuse the shell when we run the preprocessor. */
704 static const char *
705 quot (const char *string)
707 static char *buf = 0;
708 static int buflen = 0;
709 int slen = strlen (string);
710 const char *src;
711 char *dest;
713 if ((buflen < slen * 2 + 2) || ! buf)
715 buflen = slen * 2 + 2;
716 if (buf)
717 free (buf);
718 buf = (char *) xmalloc (buflen);
721 for (src=string, dest=buf; *src; src++, dest++)
723 if (*src == '(' || *src == ')' || *src == ' ')
724 *dest++ = '\\';
725 *dest = *src;
727 *dest = 0;
728 return buf;
731 /* Long options. */
733 /* 150 isn't special; it's just an arbitrary non-ASCII char value. */
735 #define OPTION_PREPROCESSOR 150
736 #define OPTION_USE_TEMP_FILE (OPTION_PREPROCESSOR + 1)
737 #define OPTION_NO_USE_TEMP_FILE (OPTION_USE_TEMP_FILE + 1)
738 #define OPTION_YYDEBUG (OPTION_NO_USE_TEMP_FILE + 1)
740 static const struct option long_options[] =
742 {"input", required_argument, 0, 'i'},
743 {"output", required_argument, 0, 'o'},
744 {"input-format", required_argument, 0, 'J'},
745 {"output-format", required_argument, 0, 'O'},
746 {"target", required_argument, 0, 'F'},
747 {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
748 {"include-dir", required_argument, 0, 'I'},
749 {"define", required_argument, 0, 'D'},
750 {"undefine", required_argument, 0, 'U'},
751 {"verbose", no_argument, 0, 'v'},
752 {"language", required_argument, 0, 'l'},
753 {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
754 {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
755 {"yydebug", no_argument, 0, OPTION_YYDEBUG},
756 {"version", no_argument, 0, 'V'},
757 {"help", no_argument, 0, 'h'},
758 {0, no_argument, 0, 0}
761 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes. */
762 int main (int, char **);
764 /* The main function. */
767 main (int argc, char **argv)
769 int c;
770 char *input_filename;
771 char *output_filename;
772 enum res_format input_format;
773 enum res_format input_format_tmp;
774 enum res_format output_format;
775 char *target;
776 char *preprocessor;
777 char *preprocargs;
778 const char *quotedarg;
779 int language;
780 rc_res_directory *resources;
781 int use_temp_file;
783 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
784 setlocale (LC_MESSAGES, "");
785 #endif
786 #if defined (HAVE_SETLOCALE)
787 setlocale (LC_CTYPE, "");
788 #endif
789 bindtextdomain (PACKAGE, LOCALEDIR);
790 textdomain (PACKAGE);
792 program_name = argv[0];
793 xmalloc_set_program_name (program_name);
795 expandargv (&argc, &argv);
797 bfd_init ();
798 set_default_bfd_target ();
800 res_init ();
802 input_filename = NULL;
803 output_filename = NULL;
804 input_format = RES_FORMAT_UNKNOWN;
805 output_format = RES_FORMAT_UNKNOWN;
806 target = NULL;
807 preprocessor = NULL;
808 preprocargs = NULL;
809 language = 0x409; /* LANG_ENGLISH, SUBLANG_ENGLISH_US. */
810 use_temp_file = 0;
812 while ((c = getopt_long (argc, argv, "f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
813 (int *) 0)) != EOF)
815 switch (c)
817 case 'i':
818 input_filename = optarg;
819 break;
821 case 'f':
822 /* For compatibility with rc we accept "-fo <name>" as being the
823 equivalent of "-o <name>". We do not advertise this fact
824 though, as we do not want users to use non-GNU like command
825 line switches. */
826 if (*optarg != 'o')
827 fatal (_("invalid option -f\n"));
828 optarg++;
829 if (* optarg == 0)
831 if (optind == argc)
832 fatal (_("No filename following the -fo option.\n"));
833 optarg = argv [optind++];
835 /* Fall through. */
837 case 'o':
838 output_filename = optarg;
839 break;
841 case 'J':
842 input_format = format_from_name (optarg, 1);
843 break;
845 case 'O':
846 output_format = format_from_name (optarg, 1);
847 break;
849 case 'F':
850 target = optarg;
851 break;
853 case OPTION_PREPROCESSOR:
854 preprocessor = optarg;
855 break;
857 case 'D':
858 case 'U':
859 if (preprocargs == NULL)
861 quotedarg = quot (optarg);
862 preprocargs = xmalloc (strlen (quotedarg) + 3);
863 sprintf (preprocargs, "-%c%s", c, quotedarg);
865 else
867 char *n;
869 quotedarg = quot (optarg);
870 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
871 sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
872 free (preprocargs);
873 preprocargs = n;
875 break;
877 case 'r':
878 /* Ignored for compatibility with rc. */
879 break;
881 case 'v':
882 verbose ++;
883 break;
885 case 'I':
886 /* For backward compatibility, should be removed in the future. */
887 input_format_tmp = format_from_name (optarg, 0);
888 if (input_format_tmp != RES_FORMAT_UNKNOWN)
890 fprintf (stderr,
891 _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
892 input_format = input_format_tmp;
893 break;
896 if (preprocargs == NULL)
898 quotedarg = quot (optarg);
899 preprocargs = xmalloc (strlen (quotedarg) + 3);
900 sprintf (preprocargs, "-I%s", quotedarg);
902 else
904 char *n;
906 quotedarg = quot (optarg);
907 n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
908 sprintf (n, "%s -I%s", preprocargs, quotedarg);
909 free (preprocargs);
910 preprocargs = n;
914 struct include_dir *n, **pp;
916 n = (struct include_dir *) xmalloc (sizeof *n);
917 n->next = NULL;
918 n->dir = optarg;
920 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
922 *pp = n;
925 break;
927 case 'l':
928 language = strtol (optarg, (char **) NULL, 16);
929 break;
931 case OPTION_USE_TEMP_FILE:
932 use_temp_file = 1;
933 break;
935 case OPTION_NO_USE_TEMP_FILE:
936 use_temp_file = 0;
937 break;
939 #ifdef YYDEBUG
940 case OPTION_YYDEBUG:
941 yydebug = 1;
942 break;
943 #endif
945 case 'h':
946 case 'H':
947 usage (stdout, 0);
948 break;
950 case 'V':
951 print_version ("windres");
952 break;
954 default:
955 usage (stderr, 1);
956 break;
960 if (input_filename == NULL && optind < argc)
962 input_filename = argv[optind];
963 ++optind;
966 if (output_filename == NULL && optind < argc)
968 output_filename = argv[optind];
969 ++optind;
972 if (argc != optind)
973 usage (stderr, 1);
975 if (input_format == RES_FORMAT_UNKNOWN)
977 if (input_filename == NULL)
978 input_format = RES_FORMAT_RC;
979 else
980 input_format = format_from_filename (input_filename, 1);
983 if (output_format == RES_FORMAT_UNKNOWN)
985 if (output_filename == NULL)
986 output_format = RES_FORMAT_RC;
987 else
988 output_format = format_from_filename (output_filename, 0);
991 set_endianess (NULL, target);
993 /* Read the input file. */
994 switch (input_format)
996 default:
997 abort ();
998 case RES_FORMAT_RC:
999 resources = read_rc_file (input_filename, preprocessor, preprocargs,
1000 language, use_temp_file);
1001 break;
1002 case RES_FORMAT_RES:
1003 resources = read_res_file (input_filename);
1004 break;
1005 case RES_FORMAT_COFF:
1006 resources = read_coff_rsrc (input_filename, target);
1007 break;
1010 if (resources == NULL)
1011 fatal (_("no resources"));
1013 /* Sort the resources. This is required for COFF, convenient for
1014 rc, and unimportant for res. */
1015 resources = sort_resources (resources);
1017 /* Write the output file. */
1018 reswr_init ();
1020 switch (output_format)
1022 default:
1023 abort ();
1024 case RES_FORMAT_RC:
1025 write_rc_file (output_filename, resources);
1026 break;
1027 case RES_FORMAT_RES:
1028 write_res_file (output_filename, resources);
1029 break;
1030 case RES_FORMAT_COFF:
1031 write_coff_file (output_filename, target, resources);
1032 break;
1035 xexit (0);
1036 return 0;
1039 static void set_endianess (bfd *abfd, const char *target)
1041 const bfd_target *target_vec;
1043 def_target_arch = NULL;
1044 target_vec = bfd_find_target (target, abfd);
1045 if (! target_vec)
1046 fatal ("Can't detect target endianess and architecture.");
1047 target_is_bigendian = ((target_vec->byteorder == BFD_ENDIAN_BIG) ? 1 : 0);
1049 const char *tname = target_vec->name;
1050 const char **arch = bfd_arch_list();
1051 if (arch && tname)
1053 if (strchr (tname, '-') != NULL)
1054 tname = strchr (tname, '-') + 1;
1055 while (*arch != NULL)
1057 const char *in_a = strstr (*arch, tname);
1058 char end_ch = (in_a ? in_a[strlen(tname)] : 0);
1059 if (in_a && (in_a == *arch || in_a[-1] == ':')
1060 && end_ch == 0)
1062 def_target_arch = *arch;
1063 break;
1065 arch++;
1068 if (! def_target_arch)
1069 fatal ("Can't detect architecture.");
1073 bfd *
1074 windres_open_as_binary (const char *filename, int rdmode)
1076 bfd *abfd;
1078 abfd = (rdmode ? bfd_openr (filename, "binary") : bfd_openw (filename, "binary"));
1079 if (! abfd)
1080 fatal ("can't open `%s' for %s", filename, (rdmode ? "input" : "output"));
1082 if (rdmode && ! bfd_check_format (abfd, bfd_object))
1083 fatal ("can't open `%s' for input.", filename);
1085 return abfd;
1088 void
1089 set_windres_bfd_endianess (windres_bfd *wrbfd, int is_bigendian)
1091 assert (!! wrbfd);
1092 switch (WR_KIND(wrbfd))
1094 case WR_KIND_BFD_BIN_L:
1095 if (is_bigendian)
1096 WR_KIND(wrbfd) = WR_KIND_BFD_BIN_B;
1097 break;
1098 case WR_KIND_BFD_BIN_B:
1099 if (! is_bigendian)
1100 WR_KIND(wrbfd) = WR_KIND_BFD_BIN_L;
1101 break;
1102 default:
1103 /* only binary bfd can be overriden. */
1104 abort ();
1108 void
1109 set_windres_bfd (windres_bfd *wrbfd, bfd *abfd, asection *sec, rc_uint_type kind)
1111 assert (!! wrbfd);
1112 switch (kind)
1114 case WR_KIND_TARGET:
1115 abfd = NULL;
1116 sec = NULL;
1117 break;
1118 case WR_KIND_BFD:
1119 case WR_KIND_BFD_BIN_L:
1120 case WR_KIND_BFD_BIN_B:
1121 assert (!! abfd);
1122 assert (!!sec);
1123 break;
1124 default:
1125 abort ();
1127 WR_KIND(wrbfd) = kind;
1128 WR_BFD(wrbfd) = abfd;
1129 WR_SECTION(wrbfd) = sec;
1132 void
1133 set_windres_bfd_content(windres_bfd *wrbfd, const void *data, rc_uint_type off,
1134 rc_uint_type length)
1136 if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1138 if (! bfd_set_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1139 bfd_fatal ("bfd_set_section_contents");
1141 else
1142 abort ();
1145 void
1146 get_windres_bfd_content(windres_bfd *wrbfd, void *data, rc_uint_type off,
1147 rc_uint_type length)
1149 if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1151 if (! bfd_get_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1152 bfd_fatal ("bfd_get_section_contents");
1154 else
1155 abort ();
1158 void
1159 windres_put_8 (windres_bfd *wrbfd, void *p, rc_uint_type value)
1161 switch (WR_KIND(wrbfd))
1163 case WR_KIND_TARGET:
1164 target_put_8 (p, value);
1165 break;
1166 case WR_KIND_BFD:
1167 case WR_KIND_BFD_BIN_L:
1168 case WR_KIND_BFD_BIN_B:
1169 bfd_put_8 (WR_BFD(wrbfd), value, p);
1170 break;
1171 default:
1172 abort ();
1176 void
1177 windres_put_16 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1179 switch (WR_KIND(wrbfd))
1181 case WR_KIND_TARGET:
1182 target_put_16 (data, value);
1183 break;
1184 case WR_KIND_BFD:
1185 case WR_KIND_BFD_BIN_B:
1186 bfd_put_16 (WR_BFD(wrbfd), value, data);
1187 break;
1188 case WR_KIND_BFD_BIN_L:
1189 bfd_putl16 (value, data);
1190 break;
1191 default:
1192 abort ();
1196 void
1197 windres_put_32 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1199 switch (WR_KIND(wrbfd))
1201 case WR_KIND_TARGET:
1202 target_put_32 (data, value);
1203 break;
1204 case WR_KIND_BFD:
1205 case WR_KIND_BFD_BIN_B:
1206 bfd_put_32 (WR_BFD(wrbfd), value, data);
1207 break;
1208 case WR_KIND_BFD_BIN_L:
1209 bfd_putl32 (value, data);
1210 break;
1211 default:
1212 abort ();
1216 rc_uint_type
1217 windres_get_8 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1219 if (length < 1)
1220 fatal ("windres_get_8: unexpected eob.");
1221 switch (WR_KIND(wrbfd))
1223 case WR_KIND_TARGET:
1224 return target_get_8 (data, length);
1225 case WR_KIND_BFD:
1226 case WR_KIND_BFD_BIN_B:
1227 case WR_KIND_BFD_BIN_L:
1228 return bfd_get_8 (WR_BFD(wrbfd), data);
1229 default:
1230 abort ();
1232 return 0;
1235 rc_uint_type
1236 windres_get_16 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1238 if (length < 2)
1239 fatal ("windres_get_16: unexpected eob.");
1240 switch (WR_KIND(wrbfd))
1242 case WR_KIND_TARGET:
1243 return target_get_16 (data, length);
1244 case WR_KIND_BFD:
1245 case WR_KIND_BFD_BIN_B:
1246 return bfd_get_16 (WR_BFD(wrbfd), data);
1247 case WR_KIND_BFD_BIN_L:
1248 return bfd_getl16 (data);
1249 default:
1250 abort ();
1252 return 0;
1255 rc_uint_type
1256 windres_get_32 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1258 if (length < 4)
1259 fatal ("windres_get_32: unexpected eob.");
1260 switch (WR_KIND(wrbfd))
1262 case WR_KIND_TARGET:
1263 return target_get_32 (data, length);
1264 case WR_KIND_BFD:
1265 case WR_KIND_BFD_BIN_B:
1266 return bfd_get_32 (WR_BFD(wrbfd), data);
1267 case WR_KIND_BFD_BIN_L:
1268 return bfd_getl32 (data);
1269 default:
1270 abort ();
1272 return 0;
1275 static rc_uint_type
1276 target_get_8 (const void *p, rc_uint_type length)
1278 rc_uint_type ret;
1280 if (length < 1)
1281 fatal ("Resource too small for getting 8-bit value.");
1283 ret = (rc_uint_type) *((const bfd_byte *) p);
1284 return ret & 0xff;
1287 static rc_uint_type
1288 target_get_16 (const void *p, rc_uint_type length)
1290 if (length < 2)
1291 fatal ("Resource too small for getting 16-bit value.");
1293 if (target_is_bigendian)
1294 return bfd_getb16 (p);
1295 else
1296 return bfd_getl16 (p);
1299 static rc_uint_type
1300 target_get_32 (const void *p, rc_uint_type length)
1302 if (length < 4)
1303 fatal ("Resource too small for getting 32-bit value.");
1305 if (target_is_bigendian)
1306 return bfd_getb32 (p);
1307 else
1308 return bfd_getl32 (p);
1311 static void
1312 target_put_8 (void *p, rc_uint_type value)
1314 assert (!! p);
1315 *((bfd_byte *) p)=(bfd_byte) value;
1318 static void
1319 target_put_16 (void *p, rc_uint_type value)
1321 assert (!! p);
1323 if (target_is_bigendian)
1324 bfd_putb16 (value, p);
1325 else
1326 bfd_putl16 (value, p);
1329 static void
1330 target_put_32 (void *p, rc_uint_type value)
1332 assert (!! p);
1334 if (target_is_bigendian)
1335 bfd_putb32 (value, p);
1336 else
1337 bfd_putl32 (value, p);
1340 static int isInComment = 0;
1342 int wr_printcomment (FILE *e, const char *fmt, ...)
1344 va_list arg;
1345 int r = 0;
1347 if (isInComment)
1348 r += fprintf (e, "\n ");
1349 else
1350 fprintf (e, "/* ");
1351 isInComment = 1;
1352 if (fmt == NULL)
1353 return r;
1354 va_start (arg, fmt);
1355 r += vfprintf (e, fmt, arg);
1356 va_end (arg);
1357 return r;
1360 int wr_print (FILE *e, const char *fmt, ...)
1362 va_list arg;
1363 int r = 0;
1364 if (isInComment)
1365 r += fprintf (e, ". */\n");
1366 isInComment = 0;
1367 if (! fmt)
1368 return r;
1369 va_start (arg, fmt);
1370 r += vfprintf (e, fmt, arg);
1371 va_end (arg);
1372 return r;