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