Updated windres tool
[deliverable/binutils-gdb.git] / binutils / windres.c
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.
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 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.
28
29 It is based on information taken from the following sources:
30
31 * Microsoft documentation.
32
33 * The rcl program, written by Gunther Ebert
34 <gunther.ebert@ixos-leipzig.de>.
35
36 * The res2coff program, written by Pedro A. Aranda <paag@tid.es>. */
37
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"
48
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;
53
54 /* Used by resrc.c at least. */
55
56 int verbose = 0;
57
58 int target_is_bigendian = 0;
59 const char *def_target_arch;
60
61 static void set_endianess (bfd *, const char *);
62
63 /* An enumeration of format types. */
64
65 enum res_format
66 {
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
75 };
76
77 /* A structure used to map between format types and strings. */
78
79 struct format_map
80 {
81 const char *name;
82 enum res_format format;
83 };
84
85 /* A mapping between names and format types. */
86
87 static const struct format_map format_names[] =
88 {
89 { "rc", RES_FORMAT_RC },
90 { "res", RES_FORMAT_RES },
91 { "coff", RES_FORMAT_COFF },
92 { NULL, RES_FORMAT_UNKNOWN }
93 };
94
95 /* A mapping from file extensions to format types. */
96
97 static const struct format_map format_fileexts[] =
98 {
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 }
105 };
106
107 /* A list of include directories. */
108
109 struct include_dir
110 {
111 struct include_dir *next;
112 char *dir;
113 };
114
115 static struct include_dir *include_dirs;
116
117 /* Static functions. */
118
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 *);
128 \f
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);
135
136 \f
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. */
139
140 #define obstack_chunk_alloc xmalloc
141 #define obstack_chunk_free free
142
143 /* The resource building obstack. */
144
145 static struct obstack res_obstack;
146
147 /* Initialize the resource building obstack. */
148
149 static void
150 res_init (void)
151 {
152 obstack_init (&res_obstack);
153 }
154
155 /* Allocate space on the resource building obstack. */
156
157 void *
158 res_alloc (rc_uint_type bytes)
159 {
160 return (void *) obstack_alloc (&res_obstack, (size_t) bytes);
161 }
162
163 /* We also use an obstack to save memory used while writing out a set
164 of resources. */
165
166 static struct obstack reswr_obstack;
167
168 /* Initialize the resource writing obstack. */
169
170 static void
171 reswr_init (void)
172 {
173 obstack_init (&reswr_obstack);
174 }
175
176 /* Allocate space on the resource writing obstack. */
177
178 void *
179 reswr_alloc (rc_uint_type bytes)
180 {
181 return (void *) obstack_alloc (&reswr_obstack, (size_t) bytes);
182 }
183 \f
184 /* Open a file using the include directory search list. */
185
186 FILE *
187 open_file_search (const char *filename, const char *mode, const char *errmsg,
188 char **real_filename)
189 {
190 FILE *e;
191 struct include_dir *d;
192
193 e = fopen (filename, mode);
194 if (e != NULL)
195 {
196 *real_filename = xstrdup (filename);
197 return e;
198 }
199
200 if (errno == ENOENT)
201 {
202 for (d = include_dirs; d != NULL; d = d->next)
203 {
204 char *n;
205
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)
210 {
211 *real_filename = n;
212 return e;
213 }
214
215 if (errno != ENOENT)
216 break;
217 }
218 }
219
220 fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
221
222 /* Return a value to avoid a compiler warning. */
223 return NULL;
224 }
225 \f
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. */
229
230 int
231 res_id_cmp (rc_res_id a, rc_res_id b)
232 {
233 if (! a.named)
234 {
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;
243 }
244 else
245 {
246 unichar *as, *ase, *bs, *bse;
247
248 if (! b.named)
249 return -1;
250
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;
255
256 while (as < ase)
257 {
258 int i;
259
260 if (bs >= bse)
261 return 1;
262 i = (int) *as - (int) *bs;
263 if (i != 0)
264 return i;
265 ++as;
266 ++bs;
267 }
268
269 if (bs < bse)
270 return -1;
271
272 return 0;
273 }
274 }
275
276 /* Print a resource ID. */
277
278 void
279 res_id_print (FILE *stream, rc_res_id id, int quote)
280 {
281 if (! id.named)
282 fprintf (stream, "%u", (int) id.u.id);
283 else
284 {
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);
289 }
290 }
291
292 /* Print a list of resource ID's. */
293
294 void
295 res_ids_print (FILE *stream, int cids, const rc_res_id *ids)
296 {
297 int i;
298
299 for (i = 0; i < cids; i++)
300 {
301 res_id_print (stream, ids[i], 1);
302 if (i + 1 < cids)
303 fprintf (stream, ": ");
304 }
305 }
306
307 /* Convert an ASCII string to a resource ID. */
308
309 void
310 res_string_to_id (rc_res_id *res_id, const char *string)
311 {
312 res_id->named = 1;
313 unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
314 }
315
316 /* Convert an unicode string to a resource ID. */
317 void
318 res_unistring_to_id (rc_res_id *res_id, const unichar *u)
319 {
320 res_id->named = 1;
321 res_id->u.n.length = unichar_len (u);
322 res_id->u.n.name = unichar_dup_uppercase (u);
323 }
324
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. */
332
333 rc_res_resource *
334 define_resource (rc_res_directory **resources, int cids,
335 const rc_res_id *ids, int dupok)
336 {
337 rc_res_entry *re = NULL;
338 int i;
339
340 assert (cids > 0);
341 for (i = 0; i < cids; i++)
342 {
343 rc_res_entry **pp;
344
345 if (*resources == NULL)
346 {
347 static unsigned int timeval;
348
349 /* Use the same timestamp for every resource created in a
350 single run. */
351 if (timeval == 0)
352 timeval = time (NULL);
353
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;
361 }
362
363 for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
364 if (res_id_cmp ((*pp)->id, ids[i]) == 0)
365 break;
366
367 if (*pp != NULL)
368 re = *pp;
369 else
370 {
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)
375 {
376 re->subdir = 1;
377 re->u.dir = NULL;
378 }
379 else
380 {
381 re->subdir = 0;
382 re->u.res = NULL;
383 }
384
385 *pp = re;
386 }
387
388 if ((i + 1) < cids)
389 {
390 if (! re->subdir)
391 {
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);
396 }
397
398 resources = &re->u.dir;
399 }
400 }
401
402 if (re->subdir)
403 {
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);
408 }
409
410 if (re->u.res != NULL)
411 {
412 if (dupok)
413 return re->u.res;
414
415 fprintf (stderr, _("%s: warning: "), program_name);
416 res_ids_print (stderr, cids, ids);
417 fprintf (stderr, _(": duplicate value\n"));
418 }
419
420 re->u.res = ((rc_res_resource *)
421 res_alloc (sizeof (rc_res_resource)));
422 memset (re->u.res, 0, sizeof (rc_res_resource));
423
424 re->u.res->type = RES_TYPE_UNINITIALIZED;
425 return re->u.res;
426 }
427
428 /* Define a standard resource. This is a version of define_resource
429 that just takes type, name, and language arguments. */
430
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)
434 {
435 rc_res_id a[3];
436
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);
443 }
444
445 /* Comparison routine for resource sorting. */
446
447 static int
448 cmp_res_entry (const void *p1, const void *p2)
449 {
450 const rc_res_entry **re1, **re2;
451
452 re1 = (const rc_res_entry **) p1;
453 re2 = (const rc_res_entry **) p2;
454 return res_id_cmp ((*re1)->id, (*re2)->id);
455 }
456
457 /* Sort the resources. */
458
459 static rc_res_directory *
460 sort_resources (rc_res_directory *resdir)
461 {
462 int c, i;
463 rc_res_entry *re;
464 rc_res_entry **a;
465
466 if (resdir->entries == NULL)
467 return resdir;
468
469 c = 0;
470 for (re = resdir->entries; re != NULL; re = re->next)
471 ++c;
472
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 *));
476
477 for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
478 a[i] = re;
479
480 qsort (a, c, sizeof (rc_res_entry *), cmp_res_entry);
481
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;
486
487 free (a);
488
489 /* Now sort the subdirectories. */
490
491 for (re = resdir->entries; re != NULL; re = re->next)
492 if (re->subdir)
493 re->u.dir = sort_resources (re->u.dir);
494
495 return resdir;
496 }
497 \f
498 /* Return whether the dialog resource DIALOG is a DIALOG or a
499 DIALOGEX. */
500
501 int
502 extended_dialog (const rc_dialog *dialog)
503 {
504 const rc_dialog_control *c;
505
506 if (dialog->ex != NULL)
507 return 1;
508
509 for (c = dialog->controls; c != NULL; c = c->next)
510 if (c->data != NULL || c->help != 0)
511 return 1;
512
513 return 0;
514 }
515
516 /* Return whether MENUITEMS are a MENU or a MENUEX. */
517
518 int
519 extended_menu (const rc_menu *menu)
520 {
521 return extended_menuitems (menu->items);
522 }
523
524 static int
525 extended_menuitems (const rc_menuitem *menuitems)
526 {
527 const rc_menuitem *mi;
528
529 for (mi = menuitems; mi != NULL; mi = mi->next)
530 {
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)
545 {
546 if (extended_menuitems (mi->popup))
547 return 1;
548 }
549 }
550
551 return 0;
552 }
553 \f
554 /* Convert a string to a format type, or exit if it can't be done. */
555
556 static enum res_format
557 format_from_name (const char *name, int exit_on_error)
558 {
559 const struct format_map *m;
560
561 for (m = format_names; m->name != NULL; m++)
562 if (strcasecmp (m->name, name) == 0)
563 break;
564
565 if (m->name == NULL && exit_on_error)
566 {
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);
573 }
574
575 return m->format;
576 }
577
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. */
580
581 static enum res_format
582 format_from_filename (const char *filename, int input)
583 {
584 const char *ext;
585 FILE *e;
586 bfd_byte b1, b2, b3, b4, b5;
587 int magic;
588
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)
593 {
594 const struct format_map *m;
595
596 ++ext;
597 for (m = format_fileexts; m->name != NULL; m++)
598 if (strcasecmp (m->name, ext) == 0)
599 return m->format;
600 }
601
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;
606
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));
612
613 b1 = getc (e);
614 b2 = getc (e);
615 b3 = getc (e);
616 b4 = getc (e);
617 b5 = getc (e);
618
619 fclose (e);
620
621 /* A PE executable starts with 0x4d 0x5a. */
622 if (b1 == 0x4d && b2 == 0x5a)
623 return RES_FORMAT_COFF;
624
625 /* A COFF .o file starts with a COFF magic number. */
626 magic = (b2 << 8) | b1;
627 switch (magic)
628 {
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;
636 }
637
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;
641
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;
649
650 /* Otherwise, we give up. */
651 fatal (_("can not determine type of file `%s'; use the -J option"),
652 filename);
653
654 /* Return something to silence the compiler warning. */
655 return RES_FORMAT_UNKNOWN;
656 }
657
658 /* Print a usage message and exit. */
659
660 static void
661 usage (FILE *stream, int status)
662 {
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"));
693
694 list_supported_targets (program_name, stream);
695
696 if (REPORT_BUGS_TO[0] && status == 0)
697 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
698
699 exit (status);
700 }
701
702 /* Quote characters that will confuse the shell when we run the preprocessor. */
703
704 static const char *
705 quot (const char *string)
706 {
707 static char *buf = 0;
708 static int buflen = 0;
709 int slen = strlen (string);
710 const char *src;
711 char *dest;
712
713 if ((buflen < slen * 2 + 2) || ! buf)
714 {
715 buflen = slen * 2 + 2;
716 if (buf)
717 free (buf);
718 buf = (char *) xmalloc (buflen);
719 }
720
721 for (src=string, dest=buf; *src; src++, dest++)
722 {
723 if (*src == '(' || *src == ')' || *src == ' ')
724 *dest++ = '\\';
725 *dest = *src;
726 }
727 *dest = 0;
728 return buf;
729 }
730
731 /* Long options. */
732
733 /* 150 isn't special; it's just an arbitrary non-ASCII char value. */
734
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)
739
740 static const struct option long_options[] =
741 {
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}
759 };
760
761 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes. */
762 int main (int, char **);
763
764 /* The main function. */
765
766 int
767 main (int argc, char **argv)
768 {
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;
782
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);
791
792 program_name = argv[0];
793 xmalloc_set_program_name (program_name);
794
795 expandargv (&argc, &argv);
796
797 bfd_init ();
798 set_default_bfd_target ();
799
800 res_init ();
801
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;
811
812 while ((c = getopt_long (argc, argv, "f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
813 (int *) 0)) != EOF)
814 {
815 switch (c)
816 {
817 case 'i':
818 input_filename = optarg;
819 break;
820
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)
830 {
831 if (optind == argc)
832 fatal (_("No filename following the -fo option.\n"));
833 optarg = argv [optind++];
834 }
835 /* Fall through. */
836
837 case 'o':
838 output_filename = optarg;
839 break;
840
841 case 'J':
842 input_format = format_from_name (optarg, 1);
843 break;
844
845 case 'O':
846 output_format = format_from_name (optarg, 1);
847 break;
848
849 case 'F':
850 target = optarg;
851 break;
852
853 case OPTION_PREPROCESSOR:
854 preprocessor = optarg;
855 break;
856
857 case 'D':
858 case 'U':
859 if (preprocargs == NULL)
860 {
861 quotedarg = quot (optarg);
862 preprocargs = xmalloc (strlen (quotedarg) + 3);
863 sprintf (preprocargs, "-%c%s", c, quotedarg);
864 }
865 else
866 {
867 char *n;
868
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;
874 }
875 break;
876
877 case 'r':
878 /* Ignored for compatibility with rc. */
879 break;
880
881 case 'v':
882 verbose ++;
883 break;
884
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)
889 {
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;
894 }
895
896 if (preprocargs == NULL)
897 {
898 quotedarg = quot (optarg);
899 preprocargs = xmalloc (strlen (quotedarg) + 3);
900 sprintf (preprocargs, "-I%s", quotedarg);
901 }
902 else
903 {
904 char *n;
905
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;
911 }
912
913 {
914 struct include_dir *n, **pp;
915
916 n = (struct include_dir *) xmalloc (sizeof *n);
917 n->next = NULL;
918 n->dir = optarg;
919
920 for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
921 ;
922 *pp = n;
923 }
924
925 break;
926
927 case 'l':
928 language = strtol (optarg, (char **) NULL, 16);
929 break;
930
931 case OPTION_USE_TEMP_FILE:
932 use_temp_file = 1;
933 break;
934
935 case OPTION_NO_USE_TEMP_FILE:
936 use_temp_file = 0;
937 break;
938
939 #ifdef YYDEBUG
940 case OPTION_YYDEBUG:
941 yydebug = 1;
942 break;
943 #endif
944
945 case 'h':
946 case 'H':
947 usage (stdout, 0);
948 break;
949
950 case 'V':
951 print_version ("windres");
952 break;
953
954 default:
955 usage (stderr, 1);
956 break;
957 }
958 }
959
960 if (input_filename == NULL && optind < argc)
961 {
962 input_filename = argv[optind];
963 ++optind;
964 }
965
966 if (output_filename == NULL && optind < argc)
967 {
968 output_filename = argv[optind];
969 ++optind;
970 }
971
972 if (argc != optind)
973 usage (stderr, 1);
974
975 if (input_format == RES_FORMAT_UNKNOWN)
976 {
977 if (input_filename == NULL)
978 input_format = RES_FORMAT_RC;
979 else
980 input_format = format_from_filename (input_filename, 1);
981 }
982
983 if (output_format == RES_FORMAT_UNKNOWN)
984 {
985 if (output_filename == NULL)
986 output_format = RES_FORMAT_RC;
987 else
988 output_format = format_from_filename (output_filename, 0);
989 }
990
991 set_endianess (NULL, target);
992
993 /* Read the input file. */
994 switch (input_format)
995 {
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;
1008 }
1009
1010 if (resources == NULL)
1011 fatal (_("no resources"));
1012
1013 /* Sort the resources. This is required for COFF, convenient for
1014 rc, and unimportant for res. */
1015 resources = sort_resources (resources);
1016
1017 /* Write the output file. */
1018 reswr_init ();
1019
1020 switch (output_format)
1021 {
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;
1033 }
1034
1035 xexit (0);
1036 return 0;
1037 }
1038
1039 static void set_endianess (bfd *abfd, const char *target)
1040 {
1041 const bfd_target *target_vec;
1042
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);
1048 {
1049 const char *tname = target_vec->name;
1050 const char **arch = bfd_arch_list();
1051 if (arch && tname)
1052 {
1053 if (strchr (tname, '-') != NULL)
1054 tname = strchr (tname, '-') + 1;
1055 while (*arch != NULL)
1056 {
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)
1061 {
1062 def_target_arch = *arch;
1063 break;
1064 }
1065 arch++;
1066 }
1067 }
1068 if (! def_target_arch)
1069 fatal ("Can't detect architecture.");
1070 }
1071 }
1072
1073 bfd *
1074 windres_open_as_binary (const char *filename, int rdmode)
1075 {
1076 bfd *abfd;
1077
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"));
1081
1082 if (rdmode && ! bfd_check_format (abfd, bfd_object))
1083 fatal ("can't open `%s' for input.", filename);
1084
1085 return abfd;
1086 }
1087
1088 void
1089 set_windres_bfd_endianess (windres_bfd *wrbfd, int is_bigendian)
1090 {
1091 assert (!! wrbfd);
1092 switch (WR_KIND(wrbfd))
1093 {
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 ();
1105 }
1106 }
1107
1108 void
1109 set_windres_bfd (windres_bfd *wrbfd, bfd *abfd, asection *sec, rc_uint_type kind)
1110 {
1111 assert (!! wrbfd);
1112 switch (kind)
1113 {
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 ();
1126 }
1127 WR_KIND(wrbfd) = kind;
1128 WR_BFD(wrbfd) = abfd;
1129 WR_SECTION(wrbfd) = sec;
1130 }
1131
1132 void
1133 set_windres_bfd_content(windres_bfd *wrbfd, const void *data, rc_uint_type off,
1134 rc_uint_type length)
1135 {
1136 if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1137 {
1138 if (! bfd_set_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1139 bfd_fatal ("bfd_set_section_contents");
1140 }
1141 else
1142 abort ();
1143 }
1144
1145 void
1146 get_windres_bfd_content(windres_bfd *wrbfd, void *data, rc_uint_type off,
1147 rc_uint_type length)
1148 {
1149 if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1150 {
1151 if (! bfd_get_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1152 bfd_fatal ("bfd_get_section_contents");
1153 }
1154 else
1155 abort ();
1156 }
1157
1158 void
1159 windres_put_8 (windres_bfd *wrbfd, void *p, rc_uint_type value)
1160 {
1161 switch (WR_KIND(wrbfd))
1162 {
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 ();
1173 }
1174 }
1175
1176 void
1177 windres_put_16 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1178 {
1179 switch (WR_KIND(wrbfd))
1180 {
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 ();
1193 }
1194 }
1195
1196 void
1197 windres_put_32 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1198 {
1199 switch (WR_KIND(wrbfd))
1200 {
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 ();
1213 }
1214 }
1215
1216 rc_uint_type
1217 windres_get_8 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1218 {
1219 if (length < 1)
1220 fatal ("windres_get_8: unexpected eob.");
1221 switch (WR_KIND(wrbfd))
1222 {
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 ();
1231 }
1232 return 0;
1233 }
1234
1235 rc_uint_type
1236 windres_get_16 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1237 {
1238 if (length < 2)
1239 fatal ("windres_get_16: unexpected eob.");
1240 switch (WR_KIND(wrbfd))
1241 {
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 ();
1251 }
1252 return 0;
1253 }
1254
1255 rc_uint_type
1256 windres_get_32 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1257 {
1258 if (length < 4)
1259 fatal ("windres_get_32: unexpected eob.");
1260 switch (WR_KIND(wrbfd))
1261 {
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 ();
1271 }
1272 return 0;
1273 }
1274
1275 static rc_uint_type
1276 target_get_8 (const void *p, rc_uint_type length)
1277 {
1278 rc_uint_type ret;
1279
1280 if (length < 1)
1281 fatal ("Resource too small for getting 8-bit value.");
1282
1283 ret = (rc_uint_type) *((const bfd_byte *) p);
1284 return ret & 0xff;
1285 }
1286
1287 static rc_uint_type
1288 target_get_16 (const void *p, rc_uint_type length)
1289 {
1290 if (length < 2)
1291 fatal ("Resource too small for getting 16-bit value.");
1292
1293 if (target_is_bigendian)
1294 return bfd_getb16 (p);
1295 else
1296 return bfd_getl16 (p);
1297 }
1298
1299 static rc_uint_type
1300 target_get_32 (const void *p, rc_uint_type length)
1301 {
1302 if (length < 4)
1303 fatal ("Resource too small for getting 32-bit value.");
1304
1305 if (target_is_bigendian)
1306 return bfd_getb32 (p);
1307 else
1308 return bfd_getl32 (p);
1309 }
1310
1311 static void
1312 target_put_8 (void *p, rc_uint_type value)
1313 {
1314 assert (!! p);
1315 *((bfd_byte *) p)=(bfd_byte) value;
1316 }
1317
1318 static void
1319 target_put_16 (void *p, rc_uint_type value)
1320 {
1321 assert (!! p);
1322
1323 if (target_is_bigendian)
1324 bfd_putb16 (value, p);
1325 else
1326 bfd_putl16 (value, p);
1327 }
1328
1329 static void
1330 target_put_32 (void *p, rc_uint_type value)
1331 {
1332 assert (!! p);
1333
1334 if (target_is_bigendian)
1335 bfd_putb32 (value, p);
1336 else
1337 bfd_putl32 (value, p);
1338 }
1339
1340 static int isInComment = 0;
1341
1342 int wr_printcomment (FILE *e, const char *fmt, ...)
1343 {
1344 va_list arg;
1345 int r = 0;
1346
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;
1358 }
1359
1360 int wr_print (FILE *e, const char *fmt, ...)
1361 {
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;
1373 }
This page took 0.05934 seconds and 5 git commands to generate.