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"
47 /* An enumeration of format types. */
53 /* Textual RC file. */
55 /* Binary RES file. */
61 /* A structure used to map between format types and strings. */
66 enum res_format format;
69 /* A mapping between names and format types. */
71 static const struct format_map format_names[] =
73 { "rc", RES_FORMAT_RC },
74 { "res", RES_FORMAT_RES },
75 { "coff", RES_FORMAT_COFF },
76 { NULL, RES_FORMAT_UNKNOWN }
79 /* A mapping from file extensions to format types. */
81 static const struct format_map format_fileexts[] =
83 { "rc", RES_FORMAT_RC },
84 { "res", RES_FORMAT_RES },
85 { "exe", RES_FORMAT_COFF },
86 { "obj", RES_FORMAT_COFF },
87 { "o", RES_FORMAT_COFF },
88 { NULL, RES_FORMAT_UNKNOWN }
91 /* A list of include directories. */
95 struct include_dir *next;
99 static struct include_dir *include_dirs;
103 /* 150 isn't special; it's just an arbitrary non-ASCII char value. */
105 #define OPTION_DEFINE 150
106 #define OPTION_HELP (OPTION_DEFINE + 1)
107 #define OPTION_INCLUDE_DIR (OPTION_HELP + 1)
108 #define OPTION_LANGUAGE (OPTION_INCLUDE_DIR + 1)
109 #define OPTION_PREPROCESSOR (OPTION_LANGUAGE + 1)
110 #define OPTION_VERSION (OPTION_PREPROCESSOR + 1)
111 #define OPTION_YYDEBUG (OPTION_VERSION + 1)
113 static const struct option long_options[] =
115 {"define", required_argument, 0, OPTION_DEFINE},
116 {"help", no_argument, 0, OPTION_HELP},
117 {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
118 {"input-format", required_argument, 0, 'I'},
119 {"language", required_argument, 0, OPTION_LANGUAGE},
120 {"output-format", required_argument, 0, 'O'},
121 {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
122 {"target", required_argument, 0, 'F'},
123 {"version", no_argument, 0, OPTION_VERSION},
124 {"yydebug", no_argument, 0, OPTION_YYDEBUG},
125 {0, no_argument, 0, 0}
128 /* Static functions. */
130 static enum res_format format_from_name PARAMS ((const char *));
131 static enum res_format format_from_filename PARAMS ((const char *, int));
132 static void usage PARAMS ((FILE *, int));
134 /* Open a file using the include directory search list. */
137 open_file_search (filename, mode, errmsg, real_filename)
138 const char *filename;
141 char **real_filename;
144 struct include_dir *d;
146 e = fopen (filename, mode);
149 *real_filename = xstrdup (filename);
155 for (d = include_dirs; d != NULL; d = d->next)
159 n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
160 sprintf (n, "%s/%s", d->dir, filename);
173 fatal ("can't open %s `%s': %s", errmsg, filename, strerror (errno));
175 /* Return a value to avoid a compiler warning. */
179 /* Unicode support. */
181 /* Convert an ASCII string to a unicode string. We just copy it,
182 expanding chars to shorts, rather than doing something intelligent. */
185 unicode_from_ascii (length, unicode, ascii)
186 unsigned short *length;
187 unsigned short **unicode;
194 len = strlen (ascii);
199 fatal ("string too long (%d chars > 0xffff)", len);
203 *unicode = (unsigned short *) xmalloc ((len + 1) * sizeof (unsigned short));
205 for (s = ascii, w = *unicode; *s != '\0'; s++, w++)
210 /* Print the unicode string UNICODE to the file E. LENGTH is the
211 number of characters to print, or -1 if we should print until the
212 end of the string. */
215 unicode_print (e, unicode, length)
217 const unsigned short *unicode;
236 if ((ch & 0x7f) == ch && isprint (ch))
238 else if ((ch & 0xff) == ch)
239 fprintf (e, "\\%03o", (unsigned int) ch);
241 fprintf (e, "\\x%x", (unsigned int) ch);
245 /* Compare two resource ID's. We consider name entries to come before
246 numeric entries, because that is how they appear in the COFF .rsrc
260 else if (a.u.id < b.u.id)
267 unsigned short *as, *ase, *bs, *bse;
273 ase = as + a.u.n.length;
275 bse = bs + b.u.n.length;
283 i = (int) *as - (int) *bs;
297 /* Print a resource ID. */
300 res_id_print (stream, id, quote)
306 fprintf (stream, "%lu", id.u.id);
309 unsigned short *s, *se;
314 se = s + id.u.n.length;
318 fprintf (stream, "\\\"");
319 else if ((*s & 0xff) == *s && isprint (*s))
322 fprintf (stream, "\\%03o", *s);
330 /* Print a list of resource ID's. */
333 res_ids_print (stream, cids, ids)
336 const struct res_id *ids;
340 for (i = 0; i < cids; i++)
342 res_id_print (stream, ids[i], 1);
344 fprintf (stream, ": ");
348 /* Convert an ASCII string to a resource ID. */
351 res_string_to_id (res_id, string)
352 struct res_id *res_id;
356 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
359 /* Define a resource. The arguments are the resource tree, RESOURCES,
360 and the location at which to put it in the tree, CIDS and IDS.
361 This returns a newly allocated res_resource structure, which the
362 caller is expected to initialize. If DUPOK is non-zero, then if a
363 resource with this ID exists, it is returned. Otherwise, a warning
364 is issued, and a new resource is created replacing the existing
367 struct res_resource *
368 define_resource (resources, cids, ids, dupok)
369 struct res_directory **resources;
371 const struct res_id *ids;
374 struct res_entry *re = NULL;
378 for (i = 0; i < cids; i++)
380 struct res_entry **pp;
382 if (*resources == NULL)
384 *resources = (struct res_directory *) xmalloc (sizeof **resources);
385 (*resources)->characteristics = 0;
386 (*resources)->time = 0;
387 (*resources)->major = 0;
388 (*resources)->minor = 0;
389 (*resources)->entries = NULL;
392 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
393 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
400 re = (struct res_entry *) xmalloc (sizeof *re);
421 fprintf (stderr, "%s: ", program_name);
422 res_ids_print (stderr, i, ids);
423 fprintf (stderr, ": expected to be a directory\n");
427 resources = &re->u.dir;
433 fprintf (stderr, "%s: ", program_name);
434 res_ids_print (stderr, cids, ids);
435 fprintf (stderr, ": expected to be a leaf\n");
439 if (re->u.res != NULL)
444 fprintf (stderr, "%s: warning: ", program_name);
445 res_ids_print (stderr, cids, ids);
446 fprintf (stderr, ": duplicate value\n");
449 re->u.res = (struct res_resource *) xmalloc (sizeof (struct res_resource));
451 re->u.res->type = RES_TYPE_UNINITIALIZED;
452 memset (&re->u.res->res_info, 0, sizeof (struct res_res_info));
453 memset (&re->u.res->coff_info, 0, sizeof (struct res_coff_info));
458 /* Define a standard resource. This is a version of define_resource
459 that just takes type, name, and language arguments. */
461 struct res_resource *
462 define_standard_resource (resources, type, name, language, dupok)
463 struct res_directory **resources;
475 a[2].u.id = language;
476 return define_resource (resources, 3, a, dupok);
479 /* Return whether the dialog resource DIALOG is a DIALOG or a
483 extended_dialog (dialog)
484 const struct dialog *dialog;
486 const struct dialog_control *c;
488 if (dialog->ex != NULL)
491 for (c = dialog->controls; c != NULL; c = c->next)
492 if (c->data != NULL || c->help != 0)
498 /* Return whether MENUITEMS are a MENU or a MENUEX. */
501 extended_menu (menuitems)
502 const struct menuitem *menuitems;
504 const struct menuitem *mi;
506 for (mi = menuitems; mi != NULL; mi = mi->next)
508 if (mi->help != 0 || mi->state != 0)
510 if (mi->popup != NULL && mi->id != 0)
513 & ~ (MENUITEM_CHECKED
517 | MENUITEM_MENUBARBREAK
518 | MENUITEM_MENUBREAK))
521 if (mi->popup != NULL)
523 if (extended_menu (mi->popup))
531 /* Convert a string to a format type, or exit if it can't be done. */
533 static enum res_format
534 format_from_name (name)
537 const struct format_map *m;
539 for (m = format_names; m->name != NULL; m++)
540 if (strcasecmp (m->name, name) == 0)
545 fprintf (stderr, "%s: unknown format type `%s'\n", program_name, name);
546 fprintf (stderr, "%s: supported formats:", program_name);
547 for (m = format_names; m->name != NULL; m++)
548 fprintf (stderr, " %s", m->name);
549 fprintf (stderr, "\n");
556 /* Work out a format type given a file name. If INPUT is non-zero,
557 it's OK to look at the file itself. */
559 static enum res_format
560 format_from_filename (filename, input)
561 const char *filename;
566 unsigned char b1, b2, b3, b4, b5;
569 /* If we have an extension, see if we recognize it as implying a
570 particular format. */
571 ext = strrchr (filename, '.');
574 const struct format_map *m;
577 for (m = format_fileexts; m->name != NULL; m++)
578 if (strcasecmp (m->name, ext) == 0)
582 /* If we don't recognize the name of an output file, assume it's a
586 return RES_FORMAT_COFF;
588 /* Read the first few bytes of the file to see if we can guess what
591 e = fopen (filename, FOPEN_RB);
593 fatal ("%s: %s", filename, strerror (errno));
603 /* A PE executable starts with 0x4d 0x5a 0x90 0x00. */
604 if (b1 == 0x4d && b2 == 0x5a && b3 == 0x90 && b4 == 0)
605 return RES_FORMAT_COFF;
607 /* A COFF .o file starts with a COFF magic number. */
608 magic = (b2 << 8) | b1;
611 case 0x14c: /* i386 */
612 case 0x166: /* MIPS */
613 case 0x184: /* Alpha */
614 case 0x268: /* 68k */
615 case 0x1f0: /* PowerPC */
617 return RES_FORMAT_COFF;
620 /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0. */
621 if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
622 return RES_FORMAT_RES;
624 /* If every character is printable or space, assume it's an RC file. */
625 if ((isprint (b1) || isspace (b1))
626 && (isprint (b2) || isspace (b2))
627 && (isprint (b3) || isspace (b3))
628 && (isprint (b4) || isspace (b4))
629 && (isprint (b5) || isspace (b5)))
630 return RES_FORMAT_RC;
632 /* Otherwise, we give up. */
633 fatal ("can not determine type of file `%s'; use the -I option",
636 /* Return something to silence the compiler warning. */
637 return RES_FORMAT_UNKNOWN;
640 /* Print a usage message and exit. */
643 usage (stream, status)
647 fprintf (stream, "Usage: %s [options] [input-file] [output-file]\n",
651 -i FILE, --input FILE Name input file\n\
652 -o FILE, --output FILE Name output file\n\
653 -I FORMAT, --input-format FORMAT\n\
654 Specify input format\n\
655 -O FORMAT, --output-format FORMAT\n\
656 Specify output format\n\
657 -F TARGET, --target TARGET Specify COFF target\n\
658 --preprocessor PROGRAM Program to use to preprocess rc file\n\
659 --include-dir DIR Include directory when preprocessing rc file\n\
660 --define SYM[=VAL] Define SYM when preprocessing rc file\n\
661 --language VAL Set language when reading rc file\n\
663 --yydebug Turn on parser debugging\n\
665 --help Print this help message\n\
666 --version Print version information\n");
668 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
669 extension if not specified. A single file name is an input file.\n\
670 No input-file is stdin, default rc. No output-file is stdout, default rc.\n");
671 list_supported_targets (program_name, stream);
673 fprintf (stream, "Report bugs to bug-gnu-utils@prep.ai.mit.edu\n");
677 /* The main function. */
685 char *input_filename;
686 char *output_filename;
687 enum res_format input_format;
688 enum res_format output_format;
693 struct res_directory *resources;
695 program_name = argv[0];
696 xmalloc_set_program_name (program_name);
699 set_default_bfd_target ();
701 input_filename = NULL;
702 output_filename = NULL;
703 input_format = RES_FORMAT_UNKNOWN;
704 output_format = RES_FORMAT_UNKNOWN;
710 while ((c = getopt_long (argc, argv, "i:o:I:O:F:", long_options,
716 input_filename = optarg;
720 output_filename = optarg;
724 input_format = format_from_name (optarg);
728 output_format = format_from_name (optarg);
735 case OPTION_PREPROCESSOR:
736 preprocessor = optarg;
740 if (preprocargs == NULL)
742 preprocargs = xmalloc (strlen (optarg) + 3);
743 sprintf (preprocargs, "-D%s", optarg);
749 n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
750 sprintf (n, "%s -D%s", preprocargs, optarg);
756 case OPTION_INCLUDE_DIR:
757 if (preprocargs == NULL)
759 preprocargs = xmalloc (strlen (optarg) + 3);
760 sprintf (preprocargs, "-I%s", optarg);
766 n = xmalloc (strlen (preprocargs) + strlen (optarg) + 4);
767 sprintf (n, "%s -I%s", preprocargs, optarg);
773 struct include_dir *n, **pp;
775 n = (struct include_dir *) xmalloc (sizeof *n);
779 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
786 case OPTION_LANGUAGE:
787 language = strtol (optarg, (char **) NULL, 16);
801 print_version ("windres");
810 if (input_filename == NULL && optind < argc)
812 input_filename = argv[optind];
816 if (output_filename == NULL && optind < argc)
818 output_filename = argv[optind];
825 if (input_format == RES_FORMAT_UNKNOWN)
827 if (input_filename == NULL)
828 input_format = RES_FORMAT_RC;
830 input_format = format_from_filename (input_filename, 1);
833 if (output_format == RES_FORMAT_UNKNOWN)
835 if (output_filename == NULL)
836 output_format = RES_FORMAT_RC;
838 output_format = format_from_filename (output_filename, 0);
841 /* Read the input file. */
843 switch (input_format)
848 resources = read_rc_file (input_filename, preprocessor, preprocargs,
852 resources = read_res_file (input_filename);
854 case RES_FORMAT_COFF:
855 resources = read_coff_rsrc (input_filename, target);
859 /* Write the output file. */
861 switch (output_format)
866 write_rc_file (output_filename, resources);
869 write_res_file (output_filename, resources);
871 case RES_FORMAT_COFF:
872 write_coff_file (output_filename, target, resources);
880 struct res_directory *
881 read_res_file (filename)
882 const char *filename;
884 fatal ("read_res_file unimplemented");
888 struct res_directory *
889 read_coff_rsrc (filename, target)
890 const char *filename;
893 fatal ("read_coff_rsrc unimplemented");
898 write_res_file (filename, resources)
899 const char *filename;
900 const struct res_directory *resources;
902 fatal ("write_res_file unimplemented");
906 write_coff_file (filename, target, resources)
907 const char *filename;
909 const struct res_directory *resources;
911 fatal ("write_coff_file unimplemented");