ChangeLog rotatation and copyright year update
[external/binutils.git] / binutils / windres.c
1 /* windres.c -- a program to manipulate Windows resources
2    Copyright (C) 1997-2015 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor, Cygnus Support.
4    Rewritten by Kai Tietz, Onevision.
5
6    This file is part of GNU Binutils.
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21    02110-1301, USA.  */
22
23 /* This program can read and write Windows resources in various
24    formats.  In particular, it can act like the rc resource compiler
25    program, and it can act like the cvtres res to COFF conversion
26    program.
27
28    It is based on information taken from the following sources:
29
30    * Microsoft documentation.
31
32    * The rcl program, written by Gunther Ebert
33      <gunther.ebert@ixos-leipzig.de>.
34
35    * The res2coff program, written by Pedro A. Aranda <paag@tid.es>.  */
36
37 #include "sysdep.h"
38 #include <assert.h>
39 #include "bfd.h"
40 #include "getopt.h"
41 #include "bucomm.h"
42 #include "libiberty.h"
43 #include "safe-ctype.h"
44 #include "obstack.h"
45 #include "windres.h"
46
47 /* Used by resrc.c at least.  */
48
49 int verbose = 0;
50
51 int target_is_bigendian = 0;
52 const char *def_target_arch;
53
54 static void set_endianness (bfd *, const char *);
55
56 /* An enumeration of format types.  */
57
58 enum res_format
59 {
60   /* Unknown format.  */
61   RES_FORMAT_UNKNOWN,
62   /* Textual RC file.  */
63   RES_FORMAT_RC,
64   /* Binary RES file.  */
65   RES_FORMAT_RES,
66   /* COFF file.  */
67   RES_FORMAT_COFF
68 };
69
70 /* A structure used to map between format types and strings.  */
71
72 struct format_map
73 {
74   const char *name;
75   enum res_format format;
76 };
77
78 /* A mapping between names and format types.  */
79
80 static const struct format_map format_names[] =
81 {
82   { "rc", RES_FORMAT_RC },
83   { "res", RES_FORMAT_RES },
84   { "coff", RES_FORMAT_COFF },
85   { NULL, RES_FORMAT_UNKNOWN }
86 };
87
88 /* A mapping from file extensions to format types.  */
89
90 static const struct format_map format_fileexts[] =
91 {
92   { "rc", RES_FORMAT_RC },
93   { "res", RES_FORMAT_RES },
94   { "exe", RES_FORMAT_COFF },
95   { "obj", RES_FORMAT_COFF },
96   { "o", RES_FORMAT_COFF },
97   { NULL, RES_FORMAT_UNKNOWN }
98 };
99
100 /* A list of include directories.  */
101
102 struct include_dir
103 {
104   struct include_dir *next;
105   char *dir;
106 };
107
108 static struct include_dir *include_dirs;
109
110 /* Static functions.  */
111
112 static void res_init (void);
113 static int extended_menuitems (const rc_menuitem *);
114 static enum res_format format_from_name (const char *, int);
115 static enum res_format format_from_filename (const char *, int);
116 static void usage (FILE *, int);
117 static int cmp_res_entry (const void *, const void *);
118 static rc_res_directory *sort_resources (rc_res_directory *);
119 static void reswr_init (void);
120 static const char * quot (const char *);
121 \f
122 static rc_uint_type target_get_8 (const void *, rc_uint_type);
123 static void target_put_8 (void *, rc_uint_type);
124 static rc_uint_type target_get_16 (const void *, rc_uint_type);
125 static void target_put_16 (void *, rc_uint_type);
126 static rc_uint_type target_get_32 (const void *, rc_uint_type);
127 static void target_put_32 (void *, rc_uint_type);
128
129 \f
130 /* When we are building a resource tree, we allocate everything onto
131    an obstack, so that we can free it all at once if we want.  */
132
133 #define obstack_chunk_alloc xmalloc
134 #define obstack_chunk_free free
135
136 /* The resource building obstack.  */
137
138 static struct obstack res_obstack;
139
140 /* Initialize the resource building obstack.  */
141
142 static void
143 res_init (void)
144 {
145   obstack_init (&res_obstack);
146 }
147
148 /* Allocate space on the resource building obstack.  */
149
150 void *
151 res_alloc (rc_uint_type bytes)
152 {
153   return obstack_alloc (&res_obstack, (size_t) bytes);
154 }
155
156 /* We also use an obstack to save memory used while writing out a set
157    of resources.  */
158
159 static struct obstack reswr_obstack;
160
161 /* Initialize the resource writing obstack.  */
162
163 static void
164 reswr_init (void)
165 {
166   obstack_init (&reswr_obstack);
167 }
168
169 /* Allocate space on the resource writing obstack.  */
170
171 void *
172 reswr_alloc (rc_uint_type bytes)
173 {
174   return obstack_alloc (&reswr_obstack, (size_t) bytes);
175 }
176 \f
177 /* Open a file using the include directory search list.  */
178
179 FILE *
180 open_file_search (const char *filename, const char *mode, const char *errmsg,
181                   char **real_filename)
182 {
183   FILE *e;
184   struct include_dir *d;
185
186   e = fopen (filename, mode);
187   if (e != NULL)
188     {
189       *real_filename = xstrdup (filename);
190       return e;
191     }
192
193   if (errno == ENOENT)
194     {
195       for (d = include_dirs; d != NULL; d = d->next)
196         {
197           char *n;
198
199           n = (char *) xmalloc (strlen (d->dir) + strlen (filename) + 2);
200           sprintf (n, "%s/%s", d->dir, filename);
201           e = fopen (n, mode);
202           if (e != NULL)
203             {
204               *real_filename = n;
205               return e;
206             }
207           free (n);
208
209           if (errno != ENOENT)
210             break;
211         }
212     }
213
214   fatal (_("can't open %s `%s': %s"), errmsg, filename, strerror (errno));
215
216   /* Return a value to avoid a compiler warning.  */
217   return NULL;
218 }
219 \f
220 /* Compare two resource ID's.  We consider name entries to come before
221    numeric entries, because that is how they appear in the COFF .rsrc
222    section.  */
223
224 int
225 res_id_cmp (rc_res_id a, rc_res_id b)
226 {
227   if (! a.named)
228     {
229       if (b.named)
230         return 1;
231       if (a.u.id > b.u.id)
232         return 1;
233       else if (a.u.id < b.u.id)
234         return -1;
235       else
236         return 0;
237     }
238   else
239     {
240       unichar *as, *ase, *bs, *bse;
241
242       if (! b.named)
243         return -1;
244
245       as = a.u.n.name;
246       ase = as + a.u.n.length;
247       bs = b.u.n.name;
248       bse = bs + b.u.n.length;
249
250       while (as < ase)
251         {
252           int i;
253
254           if (bs >= bse)
255             return 1;
256           i = (int) *as - (int) *bs;
257           if (i != 0)
258             return i;
259           ++as;
260           ++bs;
261         }
262
263       if (bs < bse)
264         return -1;
265
266       return 0;
267     }
268 }
269
270 /* Print a resource ID.  */
271
272 void
273 res_id_print (FILE *stream, rc_res_id id, int quote)
274 {
275   if (! id.named)
276     fprintf (stream, "%u", (int) id.u.id);
277   else
278     {
279       if (quote)
280         unicode_print_quoted (stream, id.u.n.name, id.u.n.length);
281       else
282       unicode_print (stream, id.u.n.name, id.u.n.length);
283     }
284 }
285
286 /* Print a list of resource ID's.  */
287
288 void
289 res_ids_print (FILE *stream, int cids, const rc_res_id *ids)
290 {
291   int i;
292
293   for (i = 0; i < cids; i++)
294     {
295       res_id_print (stream, ids[i], 1);
296       if (i + 1 < cids)
297         fprintf (stream, ": ");
298     }
299 }
300
301 /* Convert an ASCII string to a resource ID.  */
302
303 void
304 res_string_to_id (rc_res_id *res_id, const char *string)
305 {
306   res_id->named = 1;
307   unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
308 }
309
310 /* Convert an unicode string to a resource ID.  */
311 void
312 res_unistring_to_id (rc_res_id *res_id, const unichar *u)
313 {
314   res_id->named = 1;
315   res_id->u.n.length = unichar_len (u);
316   res_id->u.n.name = unichar_dup_uppercase (u);
317 }
318
319 /* Define a resource.  The arguments are the resource tree, RESOURCES,
320    and the location at which to put it in the tree, CIDS and IDS.
321    This returns a newly allocated rc_res_resource structure, which the
322    caller is expected to initialize.  If DUPOK is non-zero, then if a
323    resource with this ID exists, it is returned.  Otherwise, a warning
324    is issued, and a new resource is created replacing the existing
325    one.  */
326
327 rc_res_resource *
328 define_resource (rc_res_directory **resources, int cids,
329                  const rc_res_id *ids, int dupok)
330 {
331   rc_res_entry *re = NULL;
332   int i;
333
334   assert (cids > 0);
335   for (i = 0; i < cids; i++)
336     {
337       rc_res_entry **pp;
338
339       if (*resources == NULL)
340         {
341           *resources = ((rc_res_directory *)
342                         res_alloc (sizeof (rc_res_directory)));
343           (*resources)->characteristics = 0;
344           /* Using a real timestamp only serves to create non-deterministic
345              results.  Use zero instead.  */
346           (*resources)->time = 0;
347           (*resources)->major = 0;
348           (*resources)->minor = 0;
349           (*resources)->entries = NULL;
350         }
351
352       for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
353         if (res_id_cmp ((*pp)->id, ids[i]) == 0)
354           break;
355
356       if (*pp != NULL)
357         re = *pp;
358       else
359         {
360           re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
361           re->next = NULL;
362           re->id = ids[i];
363           if ((i + 1) < cids)
364             {
365               re->subdir = 1;
366               re->u.dir = NULL;
367             }
368           else
369             {
370               re->subdir = 0;
371               re->u.res = NULL;
372             }
373
374           *pp = re;
375         }
376
377       if ((i + 1) < cids)
378         {
379           if (! re->subdir)
380             {
381               fprintf (stderr, "%s: ", program_name);
382               res_ids_print (stderr, i, ids);
383               fprintf (stderr, _(": expected to be a directory\n"));
384               xexit (1);
385             }
386
387           resources = &re->u.dir;
388         }
389     }
390
391   if (re->subdir)
392     {
393       fprintf (stderr, "%s: ", program_name);
394       res_ids_print (stderr, cids, ids);
395       fprintf (stderr, _(": expected to be a leaf\n"));
396       xexit (1);
397     }
398
399   if (re->u.res != NULL)
400     {
401       if (dupok)
402         return re->u.res;
403
404       fprintf (stderr, _("%s: warning: "), program_name);
405       res_ids_print (stderr, cids, ids);
406       fprintf (stderr, _(": duplicate value\n"));
407     }
408
409   re->u.res = ((rc_res_resource *)
410                res_alloc (sizeof (rc_res_resource)));
411   memset (re->u.res, 0, sizeof (rc_res_resource));
412
413   re->u.res->type = RES_TYPE_UNINITIALIZED;
414   return re->u.res;
415 }
416
417 /* Define a standard resource.  This is a version of define_resource
418    that just takes type, name, and language arguments.  */
419
420 rc_res_resource *
421 define_standard_resource (rc_res_directory **resources, int type,
422                           rc_res_id name, rc_uint_type language, int dupok)
423 {
424   rc_res_id a[3];
425
426   a[0].named = 0;
427   a[0].u.id = type;
428   a[1] = name;
429   a[2].named = 0;
430   a[2].u.id = language;
431   return define_resource (resources, 3, a, dupok);
432 }
433
434 /* Comparison routine for resource sorting.  */
435
436 static int
437 cmp_res_entry (const void *p1, const void *p2)
438 {
439   const rc_res_entry **re1, **re2;
440
441   re1 = (const rc_res_entry **) p1;
442   re2 = (const rc_res_entry **) p2;
443   return res_id_cmp ((*re1)->id, (*re2)->id);
444 }
445
446 /* Sort the resources.  */
447
448 static rc_res_directory *
449 sort_resources (rc_res_directory *resdir)
450 {
451   int c, i;
452   rc_res_entry *re;
453   rc_res_entry **a;
454
455   if (resdir->entries == NULL)
456     return resdir;
457
458   c = 0;
459   for (re = resdir->entries; re != NULL; re = re->next)
460     ++c;
461
462   /* This is a recursive routine, so using xmalloc is probably better
463      than alloca.  */
464   a = (rc_res_entry **) xmalloc (c * sizeof (rc_res_entry *));
465
466   for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
467     a[i] = re;
468
469   qsort (a, c, sizeof (rc_res_entry *), cmp_res_entry);
470
471   resdir->entries = a[0];
472   for (i = 0; i < c - 1; i++)
473     a[i]->next = a[i + 1];
474   a[i]->next = NULL;
475
476   free (a);
477
478   /* Now sort the subdirectories.  */
479
480   for (re = resdir->entries; re != NULL; re = re->next)
481     if (re->subdir)
482       re->u.dir = sort_resources (re->u.dir);
483
484   return resdir;
485 }
486 \f
487 /* Return whether the dialog resource DIALOG is a DIALOG or a
488    DIALOGEX.  */
489
490 int
491 extended_dialog (const rc_dialog *dialog)
492 {
493   const rc_dialog_control *c;
494
495   if (dialog->ex != NULL)
496     return 1;
497
498   for (c = dialog->controls; c != NULL; c = c->next)
499     if (c->data != NULL || c->help != 0)
500       return 1;
501
502   return 0;
503 }
504
505 /* Return whether MENUITEMS are a MENU or a MENUEX.  */
506
507 int
508 extended_menu (const rc_menu *menu)
509 {
510   return extended_menuitems (menu->items);
511 }
512
513 static int
514 extended_menuitems (const rc_menuitem *menuitems)
515 {
516   const rc_menuitem *mi;
517
518   for (mi = menuitems; mi != NULL; mi = mi->next)
519     {
520       if (mi->help != 0 || mi->state != 0)
521         return 1;
522       if (mi->popup != NULL && mi->id != 0)
523         return 1;
524       if ((mi->type
525            & ~ (MENUITEM_CHECKED
526                 | MENUITEM_GRAYED
527                 | MENUITEM_HELP
528                 | MENUITEM_INACTIVE
529                 | MENUITEM_MENUBARBREAK
530                 | MENUITEM_MENUBREAK))
531           != 0)
532         return 1;
533       if (mi->popup != NULL)
534         {
535           if (extended_menuitems (mi->popup))
536             return 1;
537         }
538     }
539
540   return 0;
541 }
542 \f
543 /* Convert a string to a format type, or exit if it can't be done.  */
544
545 static enum res_format
546 format_from_name (const char *name, int exit_on_error)
547 {
548   const struct format_map *m;
549
550   for (m = format_names; m->name != NULL; m++)
551     if (strcasecmp (m->name, name) == 0)
552       break;
553
554   if (m->name == NULL && exit_on_error)
555     {
556       non_fatal (_("unknown format type `%s'"), name);
557       fprintf (stderr, _("%s: supported formats:"), program_name);
558       for (m = format_names; m->name != NULL; m++)
559         fprintf (stderr, " %s", m->name);
560       fprintf (stderr, "\n");
561       xexit (1);
562     }
563
564   return m->format;
565 }
566
567 /* Work out a format type given a file name.  If INPUT is non-zero,
568    it's OK to look at the file itself.  */
569
570 static enum res_format
571 format_from_filename (const char *filename, int input)
572 {
573   const char *ext;
574   FILE *e;
575   bfd_byte b1, b2, b3, b4, b5;
576   int magic;
577
578   /* If we have an extension, see if we recognize it as implying a
579      particular format.  */
580   ext = strrchr (filename, '.');
581   if (ext != NULL)
582     {
583       const struct format_map *m;
584
585       ++ext;
586       for (m = format_fileexts; m->name != NULL; m++)
587         if (strcasecmp (m->name, ext) == 0)
588           return m->format;
589     }
590
591   /* If we don't recognize the name of an output file, assume it's a
592      COFF file.  */
593   if (! input)
594     return RES_FORMAT_COFF;
595
596   /* Read the first few bytes of the file to see if we can guess what
597      it is.  */
598   e = fopen (filename, FOPEN_RB);
599   if (e == NULL)
600     fatal ("%s: %s", filename, strerror (errno));
601
602   b1 = getc (e);
603   b2 = getc (e);
604   b3 = getc (e);
605   b4 = getc (e);
606   b5 = getc (e);
607
608   fclose (e);
609
610   /* A PE executable starts with 0x4d 0x5a.  */
611   if (b1 == 0x4d && b2 == 0x5a)
612     return RES_FORMAT_COFF;
613
614   /* A COFF .o file starts with a COFF magic number.  */
615   magic = (b2 << 8) | b1;
616   switch (magic)
617     {
618     case 0x14c: /* i386 */
619     case 0x166: /* MIPS */
620     case 0x184: /* Alpha */
621     case 0x268: /* 68k */
622     case 0x1f0: /* PowerPC */
623     case 0x290: /* PA */
624       return RES_FORMAT_COFF;
625     }
626
627   /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0.  */
628   if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
629     return RES_FORMAT_RES;
630
631   /* If every character is printable or space, assume it's an RC file.  */
632   if ((ISPRINT (b1) || ISSPACE (b1))
633       && (ISPRINT (b2) || ISSPACE (b2))
634       && (ISPRINT (b3) || ISSPACE (b3))
635       && (ISPRINT (b4) || ISSPACE (b4))
636       && (ISPRINT (b5) || ISSPACE (b5)))
637     return RES_FORMAT_RC;
638
639   /* Otherwise, we give up.  */
640   fatal (_("can not determine type of file `%s'; use the -J option"),
641          filename);
642
643   /* Return something to silence the compiler warning.  */
644   return RES_FORMAT_UNKNOWN;
645 }
646
647 /* Print a usage message and exit.  */
648
649 static void
650 usage (FILE *stream, int status)
651 {
652   fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
653            program_name);
654   fprintf (stream, _(" The options are:\n\
655   -i --input=<file>            Name input file\n\
656   -o --output=<file>           Name output file\n\
657   -J --input-format=<format>   Specify input format\n\
658   -O --output-format=<format>  Specify output format\n\
659   -F --target=<target>         Specify COFF target\n\
660      --preprocessor=<program>  Program to use to preprocess rc file\n\
661      --preprocessor-arg=<arg>  Additional preprocessor argument\n\
662   -I --include-dir=<dir>       Include directory when preprocessing rc file\n\
663   -D --define <sym>[=<val>]    Define SYM when preprocessing rc file\n\
664   -U --undefine <sym>          Undefine SYM when preprocessing rc file\n\
665   -v --verbose                 Verbose - tells you what it's doing\n\
666   -c --codepage=<codepage>     Specify default codepage\n\
667   -l --language=<val>          Set language when reading rc file\n\
668      --use-temp-file           Use a temporary file instead of popen to read\n\
669                                the preprocessor output\n\
670      --no-use-temp-file        Use popen (default)\n"));
671 #ifdef YYDEBUG
672   fprintf (stream, _("\
673      --yydebug                 Turn on parser debugging\n"));
674 #endif
675   fprintf (stream, _("\
676   -r                           Ignored for compatibility with rc\n\
677   @<file>                      Read options from <file>\n\
678   -h --help                    Print this help message\n\
679   -V --version                 Print version information\n"));
680   fprintf (stream, _("\
681 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
682 extension if not specified.  A single file name is an input file.\n\
683 No input-file is stdin, default rc.  No output-file is stdout, default rc.\n"));
684
685   list_supported_targets (program_name, stream);
686
687   if (REPORT_BUGS_TO[0] && status == 0)
688     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
689
690   exit (status);
691 }
692
693 /* Quote characters that will confuse the shell when we run the preprocessor.  */
694
695 static const char *
696 quot (const char *string)
697 {
698   static char *buf = 0;
699   static int buflen = 0;
700   int slen = strlen (string);
701   const char *src;
702   char *dest;
703
704   if ((buflen < slen * 2 + 2) || ! buf)
705     {
706       buflen = slen * 2 + 2;
707       if (buf)
708         free (buf);
709       buf = (char *) xmalloc (buflen);
710     }
711
712   for (src=string, dest=buf; *src; src++, dest++)
713     {
714       if (*src == '(' || *src == ')' || *src == ' ')
715         *dest++ = '\\';
716       *dest = *src;
717     }
718   *dest = 0;
719   return buf;
720 }
721
722 /* Long options.  */
723
724 enum option_values
725 {
726   /* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
727   OPTION_PREPROCESSOR   = 150,
728   OPTION_USE_TEMP_FILE,
729   OPTION_NO_USE_TEMP_FILE,
730   OPTION_YYDEBUG,
731   OPTION_INCLUDE_DIR,
732   OPTION_PREPROCESSOR_ARG
733 };
734
735 static const struct option long_options[] =
736 {
737   {"input", required_argument, 0, 'i'},
738   {"output", required_argument, 0, 'o'},
739   {"input-format", required_argument, 0, 'J'},
740   {"output-format", required_argument, 0, 'O'},
741   {"target", required_argument, 0, 'F'},
742   {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
743   {"preprocessor-arg", required_argument, 0, OPTION_PREPROCESSOR_ARG},
744   {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
745   {"define", required_argument, 0, 'D'},
746   {"undefine", required_argument, 0, 'U'},
747   {"verbose", no_argument, 0, 'v'},
748   {"codepage", required_argument, 0, 'c'},
749   {"language", required_argument, 0, 'l'},
750   {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
751   {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
752   {"yydebug", no_argument, 0, OPTION_YYDEBUG},
753   {"version", no_argument, 0, 'V'},
754   {"help", no_argument, 0, 'h'},
755   {0, no_argument, 0, 0}
756 };
757
758 void
759 windres_add_include_dir (const char *p)
760 {
761   struct include_dir *n, **pp;
762
763   /* Computing paths is often complicated and error prone.
764      The easiest way to check for mistakes is at the time
765      we add them to include_dirs.  */
766   assert (p != NULL);
767   assert (*p != '\0');
768
769   n = xmalloc (sizeof *n);
770   n->next = NULL;
771   n->dir = (char * ) p;
772
773   for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
774     ;
775   *pp = n;
776 }
777
778 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes.  */
779 int main (int, char **);
780
781 /* The main function.  */
782
783 int
784 main (int argc, char **argv)
785 {
786   int c;
787   char *input_filename;
788   char *output_filename;
789   enum res_format input_format;
790   enum res_format input_format_tmp;
791   enum res_format output_format;
792   char *target;
793   char *preprocessor;
794   char *preprocargs;
795   const char *quotedarg;
796   int language;
797   rc_res_directory *resources;
798   int use_temp_file;
799
800 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
801   setlocale (LC_MESSAGES, "");
802 #endif
803 #if defined (HAVE_SETLOCALE)
804   setlocale (LC_CTYPE, "");
805 #endif
806   bindtextdomain (PACKAGE, LOCALEDIR);
807   textdomain (PACKAGE);
808
809   program_name = argv[0];
810   xmalloc_set_program_name (program_name);
811
812   expandargv (&argc, &argv);
813
814   bfd_init ();
815   set_default_bfd_target ();
816
817   res_init ();
818
819   input_filename = NULL;
820   output_filename = NULL;
821   input_format = RES_FORMAT_UNKNOWN;
822   output_format = RES_FORMAT_UNKNOWN;
823   target = NULL;
824   preprocessor = NULL;
825   preprocargs = NULL;
826   language = 0x409;   /* LANG_ENGLISH, SUBLANG_ENGLISH_US.  */
827   use_temp_file = 0;
828
829   while ((c = getopt_long (argc, argv, "c:f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
830                            (int *) 0)) != EOF)
831     {
832       switch (c)
833         {
834         case 'c':
835           {
836             rc_uint_type ncp;
837
838             if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X'))
839               ncp = (rc_uint_type) strtol (optarg + 2, NULL, 16);
840             else
841               ncp = (rc_uint_type) strtol (optarg, NULL, 10);
842             if (ncp == CP_UTF16 || ! unicode_is_valid_codepage (ncp))
843               fatal (_("invalid codepage specified.\n"));
844             wind_default_codepage = wind_current_codepage = ncp;
845           }
846           break;
847
848         case 'i':
849           input_filename = optarg;
850           break;
851
852         case 'f':
853           /* For compatibility with rc we accept "-fo <name>" as being the
854              equivalent of "-o <name>".  We do not advertise this fact
855              though, as we do not want users to use non-GNU like command
856              line switches.  */
857           if (*optarg != 'o')
858             fatal (_("invalid option -f\n"));
859           optarg++;
860           if (* optarg == 0)
861             {
862               if (optind == argc)
863                 fatal (_("No filename following the -fo option.\n"));
864               optarg = argv [optind++];
865             }
866           /* Fall through.  */
867
868         case 'o':
869           output_filename = optarg;
870           break;
871
872         case 'J':
873           input_format = format_from_name (optarg, 1);
874           break;
875
876         case 'O':
877           output_format = format_from_name (optarg, 1);
878           break;
879
880         case 'F':
881           target = optarg;
882           break;
883
884         case OPTION_PREPROCESSOR:
885           preprocessor = optarg;
886           break;
887
888         case OPTION_PREPROCESSOR_ARG:
889           if (preprocargs == NULL)
890             {
891               quotedarg = quot (optarg);
892               preprocargs = xstrdup (quotedarg);
893             }
894           else
895             {
896               char *n;
897
898               quotedarg = quot (optarg);
899               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 2);
900               sprintf (n, "%s %s", preprocargs, quotedarg);
901               free (preprocargs);
902               preprocargs = n;
903             }
904           break;
905
906         case 'D':
907         case 'U':
908           if (preprocargs == NULL)
909             {
910               quotedarg = quot (optarg);
911               preprocargs = xmalloc (strlen (quotedarg) + 3);
912               sprintf (preprocargs, "-%c%s", c, quotedarg);
913             }
914           else
915             {
916               char *n;
917
918               quotedarg = quot (optarg);
919               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
920               sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
921               free (preprocargs);
922               preprocargs = n;
923             }
924           break;
925
926         case 'r':
927           /* Ignored for compatibility with rc.  */
928           break;
929
930         case 'v':
931           verbose ++;
932           break;
933
934         case 'I':
935           /* For backward compatibility, should be removed in the future.  */
936           input_format_tmp = format_from_name (optarg, 0);
937           if (input_format_tmp != RES_FORMAT_UNKNOWN)
938             {
939               struct stat statbuf;
940               char modebuf[11];
941               
942               if (stat (optarg, & statbuf) == 0
943                   /* Coded this way to avoid importing knowledge of S_ISDIR into this file.  */
944                   && (mode_string (statbuf.st_mode, modebuf), modebuf[0] == 'd'))
945                 /* We have a -I option with a directory name that just happens
946                    to match a format name as well.  eg: -I res  Assume that the
947                    user knows what they are doing and do not complain.  */
948                 ;
949               else
950                 {
951                   fprintf (stderr,
952                            _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
953                   input_format = input_format_tmp;
954                   break;
955                 }
956             }
957           /* Fall through.  */
958
959         case OPTION_INCLUDE_DIR:
960           if (preprocargs == NULL)
961             {
962               quotedarg = quot (optarg);
963               preprocargs = xmalloc (strlen (quotedarg) + 3);
964               sprintf (preprocargs, "-I%s", quotedarg);
965             }
966           else
967             {
968               char *n;
969
970               quotedarg = quot (optarg);
971               n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
972               sprintf (n, "%s -I%s", preprocargs, quotedarg);
973               free (preprocargs);
974               preprocargs = n;
975             }
976
977           windres_add_include_dir (optarg);
978
979           break;
980
981         case 'l':
982           language = strtol (optarg, (char **) NULL, 16);
983           break;
984
985         case OPTION_USE_TEMP_FILE:
986           use_temp_file = 1;
987           break;
988
989         case OPTION_NO_USE_TEMP_FILE:
990           use_temp_file = 0;
991           break;
992
993 #ifdef YYDEBUG
994         case OPTION_YYDEBUG:
995           yydebug = 1;
996           break;
997 #endif
998
999         case 'h':
1000         case 'H':
1001           usage (stdout, 0);
1002           break;
1003
1004         case 'V':
1005           print_version ("windres");
1006           break;
1007
1008         default:
1009           usage (stderr, 1);
1010           break;
1011         }
1012     }
1013
1014   if (input_filename == NULL && optind < argc)
1015     {
1016       input_filename = argv[optind];
1017       ++optind;
1018     }
1019
1020   if (output_filename == NULL && optind < argc)
1021     {
1022       output_filename = argv[optind];
1023       ++optind;
1024     }
1025
1026   if (argc != optind)
1027     usage (stderr, 1);
1028
1029   if (input_format == RES_FORMAT_UNKNOWN)
1030     {
1031       if (input_filename == NULL)
1032         input_format = RES_FORMAT_RC;
1033       else
1034         input_format = format_from_filename (input_filename, 1);
1035     }
1036
1037   if (output_format == RES_FORMAT_UNKNOWN)
1038     {
1039       if (output_filename == NULL)
1040         output_format = RES_FORMAT_RC;
1041       else
1042         output_format = format_from_filename (output_filename, 0);
1043     }
1044
1045   set_endianness (NULL, target);
1046
1047   /* Read the input file.  */
1048   switch (input_format)
1049     {
1050     default:
1051       abort ();
1052     case RES_FORMAT_RC:
1053       resources = read_rc_file (input_filename, preprocessor, preprocargs,
1054                                 language, use_temp_file);
1055       break;
1056     case RES_FORMAT_RES:
1057       resources = read_res_file (input_filename);
1058       break;
1059     case RES_FORMAT_COFF:
1060       resources = read_coff_rsrc (input_filename, target);
1061       break;
1062     }
1063
1064   if (resources == NULL)
1065     fatal (_("no resources"));
1066
1067   /* Sort the resources.  This is required for COFF, convenient for
1068      rc, and unimportant for res.  */
1069   resources = sort_resources (resources);
1070
1071   /* Write the output file.  */
1072   reswr_init ();
1073
1074   switch (output_format)
1075     {
1076     default:
1077       abort ();
1078     case RES_FORMAT_RC:
1079       write_rc_file (output_filename, resources);
1080       break;
1081     case RES_FORMAT_RES:
1082       write_res_file (output_filename, resources);
1083       break;
1084     case RES_FORMAT_COFF:
1085       write_coff_file (output_filename, target, resources);
1086       break;
1087     }
1088
1089   xexit (0);
1090   return 0;
1091 }
1092
1093 static void
1094 set_endianness (bfd *abfd, const char *target)
1095 {
1096   const bfd_target *target_vec;
1097
1098   def_target_arch = NULL;
1099   target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL,
1100                                    &def_target_arch);
1101   if (! target_vec)
1102     fatal ("Can't detect target endianness and architecture.");
1103   if (! def_target_arch)
1104     fatal ("Can't detect architecture.");
1105 }
1106
1107 bfd *
1108 windres_open_as_binary (const char *filename, int rdmode)
1109 {
1110   bfd *abfd;
1111
1112   abfd = (rdmode ? bfd_openr (filename, "binary") : bfd_openw (filename, "binary"));
1113   if (! abfd)
1114     fatal ("can't open `%s' for %s", filename, (rdmode ? "input" : "output"));
1115
1116   if (rdmode && ! bfd_check_format (abfd, bfd_object))
1117     fatal ("can't open `%s' for input.", filename);
1118   
1119   return abfd;
1120 }
1121
1122 void
1123 set_windres_bfd_endianness (windres_bfd *wrbfd, int is_bigendian)
1124 {
1125   assert (!! wrbfd);
1126   switch (WR_KIND(wrbfd))
1127   {
1128   case WR_KIND_BFD_BIN_L:
1129     if (is_bigendian)
1130       WR_KIND(wrbfd) = WR_KIND_BFD_BIN_B;
1131     break;
1132   case WR_KIND_BFD_BIN_B:
1133     if (! is_bigendian)
1134       WR_KIND(wrbfd) = WR_KIND_BFD_BIN_L;
1135     break;
1136   default:
1137     /* only binary bfd can be overriden. */
1138     abort ();
1139   }
1140 }
1141
1142 void
1143 set_windres_bfd (windres_bfd *wrbfd, bfd *abfd, asection *sec, rc_uint_type kind)
1144 {
1145   assert (!! wrbfd);
1146   switch (kind)
1147   {
1148   case WR_KIND_TARGET:
1149     abfd = NULL;
1150     sec = NULL;
1151     break;
1152   case WR_KIND_BFD:
1153   case WR_KIND_BFD_BIN_L:
1154   case WR_KIND_BFD_BIN_B:
1155     assert (!! abfd);
1156     assert (!!sec);
1157     break;
1158   default:
1159     abort ();
1160   }
1161   WR_KIND(wrbfd) = kind;
1162   WR_BFD(wrbfd) = abfd;
1163   WR_SECTION(wrbfd) = sec;
1164 }
1165
1166 void
1167 set_windres_bfd_content (windres_bfd *wrbfd, const void *data, rc_uint_type off,
1168                          rc_uint_type length)
1169 {
1170   if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1171     {
1172       if (! bfd_set_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1173         bfd_fatal ("bfd_set_section_contents");
1174     }
1175   else
1176     abort ();
1177 }
1178
1179 void
1180 get_windres_bfd_content (windres_bfd *wrbfd, void *data, rc_uint_type off,
1181                          rc_uint_type length)
1182 {
1183   if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1184     {
1185       if (! bfd_get_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1186         bfd_fatal ("bfd_get_section_contents");
1187     }
1188   else
1189     abort ();
1190 }
1191
1192 void
1193 windres_put_8 (windres_bfd *wrbfd, void *p, rc_uint_type value)
1194 {
1195   switch (WR_KIND(wrbfd))
1196     {
1197     case WR_KIND_TARGET:
1198       target_put_8 (p, value);
1199       break;
1200     case WR_KIND_BFD:
1201     case WR_KIND_BFD_BIN_L:
1202     case WR_KIND_BFD_BIN_B:
1203       bfd_put_8 (WR_BFD(wrbfd), value, p);
1204       break;
1205     default:
1206       abort ();
1207     }
1208 }
1209
1210 void
1211 windres_put_16 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1212 {
1213   switch (WR_KIND(wrbfd))
1214     {
1215     case WR_KIND_TARGET:
1216       target_put_16 (data, value);
1217       break;
1218     case WR_KIND_BFD:
1219     case WR_KIND_BFD_BIN_B:
1220       bfd_put_16 (WR_BFD(wrbfd), value, data);
1221       break;
1222     case WR_KIND_BFD_BIN_L:
1223       bfd_putl16 (value, data);
1224       break;
1225     default:
1226       abort ();
1227     }
1228 }
1229
1230 void
1231 windres_put_32 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1232 {
1233   switch (WR_KIND(wrbfd))
1234     {
1235     case WR_KIND_TARGET:
1236       target_put_32 (data, value);
1237       break;
1238     case WR_KIND_BFD:
1239     case WR_KIND_BFD_BIN_B:
1240       bfd_put_32 (WR_BFD(wrbfd), value, data);
1241       break;
1242     case WR_KIND_BFD_BIN_L:
1243       bfd_putl32 (value, data);
1244       break;
1245     default:
1246       abort ();
1247     }
1248 }
1249
1250 rc_uint_type
1251 windres_get_8 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1252 {
1253   if (length < 1)
1254     fatal ("windres_get_8: unexpected eob.");
1255   switch (WR_KIND(wrbfd))
1256     {
1257     case WR_KIND_TARGET:
1258       return target_get_8 (data, length);
1259     case WR_KIND_BFD:
1260     case WR_KIND_BFD_BIN_B:
1261     case WR_KIND_BFD_BIN_L:
1262       return bfd_get_8 (WR_BFD(wrbfd), data);
1263     default:
1264       abort ();
1265     }
1266   return 0;
1267 }
1268
1269 rc_uint_type
1270 windres_get_16 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1271 {
1272   if (length < 2)
1273     fatal ("windres_get_16: unexpected eob.");
1274   switch (WR_KIND(wrbfd))
1275     {
1276     case WR_KIND_TARGET:
1277       return target_get_16 (data, length);
1278     case WR_KIND_BFD:
1279     case WR_KIND_BFD_BIN_B:
1280       return bfd_get_16 (WR_BFD(wrbfd), data);
1281     case WR_KIND_BFD_BIN_L:
1282       return bfd_getl16 (data);
1283     default:
1284       abort ();
1285     }
1286   return 0;
1287 }
1288
1289 rc_uint_type
1290 windres_get_32 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1291 {
1292   if (length < 4)
1293     fatal ("windres_get_32: unexpected eob.");
1294   switch (WR_KIND(wrbfd))
1295     {
1296     case WR_KIND_TARGET:
1297       return target_get_32 (data, length);
1298     case WR_KIND_BFD:
1299     case WR_KIND_BFD_BIN_B:
1300       return bfd_get_32 (WR_BFD(wrbfd), data);
1301     case WR_KIND_BFD_BIN_L:
1302       return bfd_getl32 (data);
1303     default:
1304       abort ();
1305     }
1306   return 0;
1307 }
1308
1309 static rc_uint_type
1310 target_get_8 (const void *p, rc_uint_type length)
1311 {
1312   rc_uint_type ret;
1313   
1314   if (length < 1)
1315     fatal ("Resource too small for getting 8-bit value.");
1316
1317   ret = (rc_uint_type) *((const bfd_byte *) p);
1318   return ret & 0xff;
1319 }
1320
1321 static rc_uint_type
1322 target_get_16 (const void *p, rc_uint_type length)
1323 {
1324   if (length < 2)
1325     fatal ("Resource too small for getting 16-bit value.");
1326   
1327   if (target_is_bigendian)
1328     return bfd_getb16 (p);
1329   else
1330     return bfd_getl16 (p);
1331 }
1332
1333 static rc_uint_type
1334 target_get_32 (const void *p, rc_uint_type length)
1335 {
1336   if (length < 4)
1337     fatal ("Resource too small for getting 32-bit value.");
1338   
1339   if (target_is_bigendian)
1340     return bfd_getb32 (p);
1341   else
1342     return bfd_getl32 (p);
1343 }
1344
1345 static void
1346 target_put_8 (void *p, rc_uint_type value)
1347 {
1348   assert (!! p);
1349   *((bfd_byte *) p)=(bfd_byte) value;
1350 }
1351
1352 static void
1353 target_put_16 (void *p, rc_uint_type value)
1354 {
1355   assert (!! p);
1356   
1357   if (target_is_bigendian)
1358     bfd_putb16 (value, p);
1359   else
1360     bfd_putl16 (value, p);
1361 }
1362
1363 static void
1364 target_put_32 (void *p, rc_uint_type value)
1365 {
1366   assert (!! p);
1367   
1368   if (target_is_bigendian)
1369     bfd_putb32 (value, p);
1370   else
1371     bfd_putl32 (value, p);
1372 }
1373
1374 static int isInComment = 0;
1375
1376 int wr_printcomment (FILE *e, const char *fmt, ...)
1377 {
1378   va_list arg;
1379   int r = 0;
1380
1381   if (isInComment)
1382     r += fprintf (e, "\n   ");
1383   else
1384     fprintf (e, "/* ");
1385   isInComment = 1;
1386   if (fmt == NULL)
1387     return r;
1388   va_start (arg, fmt);
1389   r += vfprintf (e, fmt, arg);
1390   va_end (arg);
1391   return r;
1392 }
1393
1394 int wr_print (FILE *e, const char *fmt, ...)
1395 {
1396   va_list arg;
1397   int r = 0;
1398   if (isInComment)
1399     r += fprintf (e, ".  */\n");
1400   isInComment = 0;
1401   if (! fmt)
1402     return r;
1403   va_start (arg, fmt);
1404   r += vfprintf (e, fmt, arg);
1405   va_end (arg);
1406   return r;    
1407 }