1 /* windres.c -- a program to manipulate Windows resources
2 Copyright 1997 Free Software Foundation, Inc.
3 Written by Ian Lance Taylor, Cygnus Support.
5 This file is part of GNU Binutils.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 /* This program can read and write Windows resources in various
23 formats. In particular, it can act like the rc resource compiler
24 program, and it can act like the cvtres res to COFF conversion
27 It is based on information taken from the following sources:
29 * Microsoft documentation.
31 * The rcl program, written by Gunther Ebert
32 <gunther.ebert@ixos-leipzig.de>.
34 * The res2coff program, written by Pedro A. Aranda <paag@tid.es>.
41 #include "libiberty.h"
48 /* An enumeration of format types. */
54 /* Textual RC file. */
56 /* Binary RES file. */
62 /* A structure used to map between format types and strings. */
67 enum res_format format;
70 /* A mapping between names and format types. */
72 static const struct format_map format_names[] =
74 { "rc", RES_FORMAT_RC },
75 { "res", RES_FORMAT_RES },
76 { "coff", RES_FORMAT_COFF },
77 { NULL, RES_FORMAT_UNKNOWN }
80 /* A mapping from file extensions to format types. */
82 static const struct format_map format_fileexts[] =
84 { "rc", RES_FORMAT_RC },
85 { "res", RES_FORMAT_RES },
86 { "exe", RES_FORMAT_COFF },
87 { "obj", RES_FORMAT_COFF },
88 { "o", RES_FORMAT_COFF },
89 { NULL, RES_FORMAT_UNKNOWN }
92 /* A list of include directories. */
96 struct include_dir *next;
100 static struct include_dir *include_dirs;
104 /* 150 isn't special; it's just an arbitrary non-ASCII char value. */
106 #define OPTION_DEFINE 150
107 #define OPTION_HELP (OPTION_DEFINE + 1)
108 #define OPTION_INCLUDE_DIR (OPTION_HELP + 1)
109 #define OPTION_LANGUAGE (OPTION_INCLUDE_DIR + 1)
110 #define OPTION_PREPROCESSOR (OPTION_LANGUAGE + 1)
111 #define OPTION_VERSION (OPTION_PREPROCESSOR + 1)
112 #define OPTION_YYDEBUG (OPTION_VERSION + 1)
114 static const struct option long_options[] =
116 {"define", required_argument, 0, OPTION_DEFINE},
117 {"help", no_argument, 0, OPTION_HELP},
118 {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
119 {"input-format", required_argument, 0, 'I'},
120 {"language", required_argument, 0, OPTION_LANGUAGE},
121 {"output-format", required_argument, 0, 'O'},
122 {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
123 {"target", required_argument, 0, 'F'},
124 {"version", no_argument, 0, OPTION_VERSION},
125 {"yydebug", no_argument, 0, OPTION_YYDEBUG},
126 {0, no_argument, 0, 0}
129 /* Static functions. */
131 static void res_init PARAMS ((void));
132 static int extended_menuitems PARAMS ((const struct menuitem *));
133 static enum res_format format_from_name PARAMS ((const char *));
134 static enum res_format format_from_filename PARAMS ((const char *, int));
135 static void usage PARAMS ((FILE *, int));
136 static int cmp_res_entry PARAMS ((const PTR, const PTR));
137 static struct res_directory *sort_resources PARAMS ((struct res_directory *));
139 /* When we are building a resource tree, we allocate everything onto
140 an obstack, so that we can free it all at once if we want. */
142 #define obstack_chunk_alloc xmalloc
143 #define obstack_chunk_free free
145 /* The resource building obstack. */
147 static struct obstack res_obstack;
149 /* Initialize the resource building obstack. */
154 obstack_init (&res_obstack);
157 /* Allocate space on the resource building obstack. */
163 return (PTR) obstack_alloc (&res_obstack, bytes);
166 /* We also use an obstack to save memory used while writing out a set
169 static struct obstack reswr_obstack;
171 /* Initialize the resource writing obstack. */
176 obstack_init (&reswr_obstack);
179 /* Allocate space on the resource writing obstack. */
185 return (PTR) obstack_alloc (&reswr_obstack, bytes);
188 /* Open a file using the include directory search list. */
191 open_file_search (filename, mode, errmsg, real_filename)
192 const char *filename;
195 char **real_filename;
198 struct include_dir *d;
200 e = fopen (filename, mode);
203 *real_filename = xstrdup (filename);
209 for (d = include_dirs; d != NULL; d = d->next)
213 n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
214 sprintf (n, "%s/%s", d->dir, filename);
227 fatal ("can't open %s `%s': %s", errmsg, filename, strerror (errno));
229 /* Return a value to avoid a compiler warning. */
233 /* Unicode support. */
235 /* Convert an ASCII string to a unicode string. We just copy it,
236 expanding chars to shorts, rather than doing something intelligent. */
239 unicode_from_ascii (length, unicode, ascii)
248 len = strlen (ascii);
253 *unicode = ((unichar *) res_alloc ((len + 1) * sizeof (unichar)));
255 for (s = ascii, w = *unicode; *s != '\0'; s++, w++)
260 /* Print the unicode string UNICODE to the file E. LENGTH is the
261 number of characters to print, or -1 if we should print until the
262 end of the string. */
265 unicode_print (e, unicode, length)
267 const unichar *unicode;
281 if (ch == 0 && length < 0)
286 if ((ch & 0x7f) == ch && isprint (ch))
288 else if ((ch & 0xff) == ch)
289 fprintf (e, "\\%03o", (unsigned int) ch);
291 fprintf (e, "\\x%x", (unsigned int) ch);
295 /* Compare two resource ID's. We consider name entries to come before
296 numeric entries, because that is how they appear in the COFF .rsrc
310 else if (a.u.id < b.u.id)
317 unichar *as, *ase, *bs, *bse;
323 ase = as + a.u.n.length;
325 bse = bs + b.u.n.length;
333 i = (int) *as - (int) *bs;
347 /* Print a resource ID. */
350 res_id_print (stream, id, quote)
356 fprintf (stream, "%lu", id.u.id);
361 unicode_print (stream, id.u.n.name, id.u.n.length);
367 /* Print a list of resource ID's. */
370 res_ids_print (stream, cids, ids)
373 const struct res_id *ids;
377 for (i = 0; i < cids; i++)
379 res_id_print (stream, ids[i], 1);
381 fprintf (stream, ": ");
385 /* Convert an ASCII string to a resource ID. */
388 res_string_to_id (res_id, string)
389 struct res_id *res_id;
393 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
396 /* Define a resource. The arguments are the resource tree, RESOURCES,
397 and the location at which to put it in the tree, CIDS and IDS.
398 This returns a newly allocated res_resource structure, which the
399 caller is expected to initialize. If DUPOK is non-zero, then if a
400 resource with this ID exists, it is returned. Otherwise, a warning
401 is issued, and a new resource is created replacing the existing
404 struct res_resource *
405 define_resource (resources, cids, ids, dupok)
406 struct res_directory **resources;
408 const struct res_id *ids;
411 struct res_entry *re = NULL;
415 for (i = 0; i < cids; i++)
417 struct res_entry **pp;
419 if (*resources == NULL)
421 *resources = ((struct res_directory *)
422 res_alloc (sizeof **resources));
423 (*resources)->characteristics = 0;
424 (*resources)->time = 0;
425 (*resources)->major = 0;
426 (*resources)->minor = 0;
427 (*resources)->entries = NULL;
430 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
431 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
438 re = (struct res_entry *) res_alloc (sizeof *re);
459 fprintf (stderr, "%s: ", program_name);
460 res_ids_print (stderr, i, ids);
461 fprintf (stderr, ": expected to be a directory\n");
465 resources = &re->u.dir;
471 fprintf (stderr, "%s: ", program_name);
472 res_ids_print (stderr, cids, ids);
473 fprintf (stderr, ": expected to be a leaf\n");
477 if (re->u.res != NULL)
482 fprintf (stderr, "%s: warning: ", program_name);
483 res_ids_print (stderr, cids, ids);
484 fprintf (stderr, ": duplicate value\n");
487 re->u.res = ((struct res_resource *)
488 res_alloc (sizeof (struct res_resource)));
490 re->u.res->type = RES_TYPE_UNINITIALIZED;
491 memset (&re->u.res->res_info, 0, sizeof (struct res_res_info));
492 memset (&re->u.res->coff_info, 0, sizeof (struct res_coff_info));
497 /* Define a standard resource. This is a version of define_resource
498 that just takes type, name, and language arguments. */
500 struct res_resource *
501 define_standard_resource (resources, type, name, language, dupok)
502 struct res_directory **resources;
514 a[2].u.id = language;
515 return define_resource (resources, 3, a, dupok);
518 /* Comparison routine for resource sorting. */
521 cmp_res_entry (p1, p2)
525 const struct res_entry **re1, **re2;
527 re1 = (const struct res_entry **) p1;
528 re2 = (const struct res_entry **) p2;
529 return res_id_cmp ((*re1)->id, (*re2)->id);
532 /* Sort the resources. */
534 static struct res_directory *
535 sort_resources (resdir)
536 struct res_directory *resdir;
539 struct res_entry *re;
540 struct res_entry **a;
542 if (resdir->entries == NULL)
546 for (re = resdir->entries; re != NULL; re = re->next)
549 /* This is a recursive routine, so using xmalloc is probably better
551 a = (struct res_entry **) xmalloc (c * sizeof (struct res_entry *));
553 for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
556 qsort (a, c, sizeof (struct res_entry *), cmp_res_entry);
558 resdir->entries = a[0];
559 for (i = 0; i < c - 1; i++)
560 a[i]->next = a[i + 1];
565 /* Now sort the subdirectories. */
567 for (re = resdir->entries; re != NULL; re = re->next)
569 re->u.dir = sort_resources (re->u.dir);
574 /* Return whether the dialog resource DIALOG is a DIALOG or a
578 extended_dialog (dialog)
579 const struct dialog *dialog;
581 const struct dialog_control *c;
583 if (dialog->ex != NULL)
586 for (c = dialog->controls; c != NULL; c = c->next)
587 if (c->data != NULL || c->help != 0)
593 /* Return whether MENUITEMS are a MENU or a MENUEX. */
597 const struct menu *menu;
599 return extended_menuitems (menu->items);
603 extended_menuitems (menuitems)
604 const struct menuitem *menuitems;
606 const struct menuitem *mi;
608 for (mi = menuitems; mi != NULL; mi = mi->next)
610 if (mi->help != 0 || mi->state != 0)
612 if (mi->popup != NULL && mi->id != 0)
615 & ~ (MENUITEM_CHECKED
619 | MENUITEM_MENUBARBREAK
620 | MENUITEM_MENUBREAK))
623 if (mi->popup != NULL)
625 if (extended_menuitems (mi->popup))
633 /* Convert a string to a format type, or exit if it can't be done. */
635 static enum res_format
636 format_from_name (name)
639 const struct format_map *m;
641 for (m = format_names; m->name != NULL; m++)
642 if (strcasecmp (m->name, name) == 0)
647 fprintf (stderr, "%s: unknown format type `%s'\n", program_name, name);
648 fprintf (stderr, "%s: supported formats:", program_name);
649 for (m = format_names; m->name != NULL; m++)
650 fprintf (stderr, " %s", m->name);
651 fprintf (stderr, "\n");
658 /* Work out a format type given a file name. If INPUT is non-zero,
659 it's OK to look at the file itself. */
661 static enum res_format
662 format_from_filename (filename, input)
663 const char *filename;
668 unsigned char b1, b2, b3, b4, b5;
671 /* If we have an extension, see if we recognize it as implying a
672 particular format. */
673 ext = strrchr (filename, '.');
676 const struct format_map *m;
679 for (m = format_fileexts; m->name != NULL; m++)
680 if (strcasecmp (m->name, ext) == 0)
684 /* If we don't recognize the name of an output file, assume it's a
688 return RES_FORMAT_COFF;
690 /* Read the first few bytes of the file to see if we can guess what
693 e = fopen (filename, FOPEN_RB);
695 fatal ("%s: %s", filename, strerror (errno));
705 /* A PE executable starts with 0x4d 0x5a. */
706 if (b1 == 0x4d && b2 == 0x5a)
707 return RES_FORMAT_COFF;
709 /* A COFF .o file starts with a COFF magic number. */
710 magic = (b2 << 8) | b1;
713 case 0x14c: /* i386 */
714 case 0x166: /* MIPS */
715 case 0x184: /* Alpha */
716 case 0x268: /* 68k */
717 case 0x1f0: /* PowerPC */
719 return RES_FORMAT_COFF;
722 /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */
723 if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
724 return RES_FORMAT_RES;
726 /* If every character is printable or space, assume it's an RC file. */
727 if ((isprint (b1) || isspace (b1))
728 && (isprint (b2) || isspace (b2))
729 && (isprint (b3) || isspace (b3))
730 && (isprint (b4) || isspace (b4))
731 && (isprint (b5) || isspace (b5)))
732 return RES_FORMAT_RC;
734 /* Otherwise, we give up. */
735 fatal ("can not determine type of file `%s'; use the -I option",
738 /* Return something to silence the compiler warning. */
739 return RES_FORMAT_UNKNOWN;
742 /* Print a usage message and exit. */
745 usage (stream, status)
749 fprintf (stream, "Usage: %s [options] [input-file] [output-file]\n",
753 -i FILE, --input FILE Name input file\n\
754 -o FILE, --output FILE Name output file\n\
755 -I FORMAT, --input-format FORMAT\n\
756 Specify input format\n\
757 -O FORMAT, --output-format FORMAT\n\
758 Specify output format\n\
759 -F TARGET, --target TARGET Specify COFF target\n\
760 --preprocessor PROGRAM Program to use to preprocess rc file\n\
761 --include-dir DIR Include directory when preprocessing rc file\n\
762 --define SYM[=VAL] Define SYM when preprocessing rc file\n\
763 --language VAL Set language when reading rc file\n");
766 --yydebug Turn on parser debugging\n");
769 --help Print this help message\n\
770 --version Print version information\n");
772 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
773 extension if not specified. A single file name is an input file.\n\
774 No input-file is stdin, default rc. No output-file is stdout, default rc.\n");
775 list_supported_targets (program_name, stream);
777 fprintf (stream, "Report bugs to bug-gnu-utils@prep.ai.mit.edu\n");
781 /* The main function. */
789 char *input_filename;
790 char *output_filename;
791 enum res_format input_format;
792 enum res_format output_format;
797 struct res_directory *resources;
799 program_name = argv[0];
800 xmalloc_set_program_name (program_name);
803 set_default_bfd_target ();
807 input_filename = NULL;
808 output_filename = NULL;
809 input_format = RES_FORMAT_UNKNOWN;
810 output_format = RES_FORMAT_UNKNOWN;
816 while ((c = getopt_long (argc, argv, "i:o:I:O:F:", long_options,
822 input_filename = optarg;
826 output_filename = optarg;
830 input_format = format_from_name (optarg);
834 output_format = format_from_name (optarg);
841 case OPTION_PREPROCESSOR:
842 preprocessor = optarg;
846 if (preprocargs == NULL)
848 preprocargs = xmalloc (strlen (optarg) + 3);
849 sprintf (preprocargs, "-D%s", optarg);
855 n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
856 sprintf (n, "%s -D%s", preprocargs, optarg);
862 case OPTION_INCLUDE_DIR:
863 if (preprocargs == NULL)
865 preprocargs = xmalloc (strlen (optarg) + 3);
866 sprintf (preprocargs, "-I%s", optarg);
872 n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
873 sprintf (n, "%s -I%s", preprocargs, optarg);
879 struct include_dir *n, **pp;
881 n = (struct include_dir *) xmalloc (sizeof *n);
885 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
892 case OPTION_LANGUAGE:
893 language = strtol (optarg, (char **) NULL, 16);
907 print_version ("windres");
916 if (input_filename == NULL && optind < argc)
918 input_filename = argv[optind];
922 if (output_filename == NULL && optind < argc)
924 output_filename = argv[optind];
931 if (input_format == RES_FORMAT_UNKNOWN)
933 if (input_filename == NULL)
934 input_format = RES_FORMAT_RC;
936 input_format = format_from_filename (input_filename, 1);
939 if (output_format == RES_FORMAT_UNKNOWN)
941 if (output_filename == NULL)
942 output_format = RES_FORMAT_RC;
944 output_format = format_from_filename (output_filename, 0);
947 /* Read the input file. */
949 switch (input_format)
954 resources = read_rc_file (input_filename, preprocessor, preprocargs,
958 resources = read_res_file (input_filename);
960 case RES_FORMAT_COFF:
961 resources = read_coff_rsrc (input_filename, target);
965 if (resources == NULL)
966 fatal ("no resources");
968 /* Sort the resources. This is required for COFF, convenient for
969 rc, and unimportant for res. */
971 resources = sort_resources (resources);
973 /* Write the output file. */
977 switch (output_format)
982 write_rc_file (output_filename, resources);
985 write_res_file (output_filename, resources);
987 case RES_FORMAT_COFF:
988 write_coff_file (output_filename, target, resources);
996 struct res_directory *
997 read_res_file (filename)
998 const char *filename;
1000 fatal ("read_res_file unimplemented");
1005 write_res_file (filename, resources)
1006 const char *filename;
1007 const struct res_directory *resources;
1009 fatal ("write_res_file unimplemented");