1/* windres.c -- a program to manipulate Windows resources
2   Copyright (C) 1997-2017 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
49int verbose = 0;
50
51int target_is_bigendian = 0;
52const char *def_target_arch;
53
54static void set_endianness (bfd *, const char *);
55
56/* An enumeration of format types.  */
57
58enum 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
72struct format_map
73{
74  const char *name;
75  enum res_format format;
76};
77
78/* A mapping between names and format types.  */
79
80static 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
90static 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
102struct include_dir
103{
104  struct include_dir *next;
105  char *dir;
106};
107
108static struct include_dir *include_dirs;
109
110/* Static functions.  */
111
112static void res_init (void);
113static int extended_menuitems (const rc_menuitem *);
114static enum res_format format_from_name (const char *, int);
115static enum res_format format_from_filename (const char *, int);
116static void usage (FILE *, int);
117static int cmp_res_entry (const void *, const void *);
118static rc_res_directory *sort_resources (rc_res_directory *);
119static void reswr_init (void);
120static const char * quot (const char *);
121
122static rc_uint_type target_get_8 (const void *, rc_uint_type);
123static void target_put_8 (void *, rc_uint_type);
124static rc_uint_type target_get_16 (const void *, rc_uint_type);
125static void target_put_16 (void *, rc_uint_type);
126static rc_uint_type target_get_32 (const void *, rc_uint_type);
127static void target_put_32 (void *, rc_uint_type);
128
129
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
138static struct obstack res_obstack;
139
140/* Initialize the resource building obstack.  */
141
142static void
143res_init (void)
144{
145  obstack_init (&res_obstack);
146}
147
148/* Allocate space on the resource building obstack.  */
149
150void *
151res_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
159static struct obstack reswr_obstack;
160
161/* Initialize the resource writing obstack.  */
162
163static void
164reswr_init (void)
165{
166  obstack_init (&reswr_obstack);
167}
168
169/* Allocate space on the resource writing obstack.  */
170
171void *
172reswr_alloc (rc_uint_type bytes)
173{
174  return obstack_alloc (&reswr_obstack, (size_t) bytes);
175}
176
177/* Open a file using the include directory search list.  */
178
179FILE *
180open_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
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
224int
225res_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
272void
273res_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
288void
289res_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
303void
304res_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.  */
311void
312res_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
327rc_res_resource *
328define_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
420rc_res_resource *
421define_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
436static int
437cmp_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
448static rc_res_directory *
449sort_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
487/* Return whether the dialog resource DIALOG is a DIALOG or a
488   DIALOGEX.  */
489
490int
491extended_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
507int
508extended_menu (const rc_menu *menu)
509{
510  return extended_menuitems (menu->items);
511}
512
513static int
514extended_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
543/* Convert a string to a format type, or exit if it can't be done.  */
544
545static enum res_format
546format_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
570static enum res_format
571format_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
649static void
650usage (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, _("\
681FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
682extension if not specified.  A single file name is an input file.\n\
683No 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
695static const char *
696quot (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
724enum 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
735static 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
758void
759windres_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.  */
779int main (int, char **);
780
781/* The main function.  */
782
783int
784main (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  bfd_set_error_program_name (program_name);
812
813  expandargv (&argc, &argv);
814
815  bfd_init ();
816  set_default_bfd_target ();
817
818  res_init ();
819
820  input_filename = NULL;
821  output_filename = NULL;
822  input_format = RES_FORMAT_UNKNOWN;
823  output_format = RES_FORMAT_UNKNOWN;
824  target = NULL;
825  preprocessor = NULL;
826  preprocargs = NULL;
827  language = 0x409;   /* LANG_ENGLISH, SUBLANG_ENGLISH_US.  */
828  use_temp_file = 0;
829
830  while ((c = getopt_long (argc, argv, "c:f:i:l:o:I:J:O:F:D:U:rhHvV", long_options,
831			   (int *) 0)) != EOF)
832    {
833      switch (c)
834	{
835	case 'c':
836	  {
837	    rc_uint_type ncp;
838
839	    if (optarg[0] == '0' && (optarg[1] == 'x' || optarg[1] == 'X'))
840	      ncp = (rc_uint_type) strtol (optarg + 2, NULL, 16);
841	    else
842	      ncp = (rc_uint_type) strtol (optarg, NULL, 10);
843	    if (ncp == CP_UTF16 || ! unicode_is_valid_codepage (ncp))
844	      fatal (_("invalid codepage specified.\n"));
845	    wind_default_codepage = wind_current_codepage = ncp;
846	  }
847	  break;
848
849	case 'i':
850	  input_filename = optarg;
851	  break;
852
853	case 'f':
854	  /* For compatibility with rc we accept "-fo <name>" as being the
855	     equivalent of "-o <name>".  We do not advertise this fact
856	     though, as we do not want users to use non-GNU like command
857	     line switches.  */
858	  if (*optarg != 'o')
859	    fatal (_("invalid option -f\n"));
860	  optarg++;
861	  if (* optarg == 0)
862	    {
863	      if (optind == argc)
864		fatal (_("No filename following the -fo option.\n"));
865	      optarg = argv [optind++];
866	    }
867	  /* Fall through.  */
868
869	case 'o':
870	  output_filename = optarg;
871	  break;
872
873	case 'J':
874	  input_format = format_from_name (optarg, 1);
875	  break;
876
877	case 'O':
878	  output_format = format_from_name (optarg, 1);
879	  break;
880
881	case 'F':
882	  target = optarg;
883	  break;
884
885	case OPTION_PREPROCESSOR:
886	  preprocessor = optarg;
887	  break;
888
889	case OPTION_PREPROCESSOR_ARG:
890	  if (preprocargs == NULL)
891	    {
892	      quotedarg = quot (optarg);
893	      preprocargs = xstrdup (quotedarg);
894	    }
895	  else
896	    {
897	      char *n;
898
899	      quotedarg = quot (optarg);
900	      n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 2);
901	      sprintf (n, "%s %s", preprocargs, quotedarg);
902	      free (preprocargs);
903	      preprocargs = n;
904	    }
905	  break;
906
907	case 'D':
908	case 'U':
909	  if (preprocargs == NULL)
910	    {
911	      quotedarg = quot (optarg);
912	      preprocargs = xmalloc (strlen (quotedarg) + 3);
913	      sprintf (preprocargs, "-%c%s", c, quotedarg);
914	    }
915	  else
916	    {
917	      char *n;
918
919	      quotedarg = quot (optarg);
920	      n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
921	      sprintf (n, "%s -%c%s", preprocargs, c, quotedarg);
922	      free (preprocargs);
923	      preprocargs = n;
924	    }
925	  break;
926
927	case 'r':
928	  /* Ignored for compatibility with rc.  */
929	  break;
930
931	case 'v':
932	  verbose ++;
933	  break;
934
935	case 'I':
936	  /* For backward compatibility, should be removed in the future.  */
937	  input_format_tmp = format_from_name (optarg, 0);
938	  if (input_format_tmp != RES_FORMAT_UNKNOWN)
939	    {
940	      struct stat statbuf;
941	      char modebuf[11];
942
943	      if (stat (optarg, & statbuf) == 0
944		  /* Coded this way to avoid importing knowledge of S_ISDIR into this file.  */
945		  && (mode_string (statbuf.st_mode, modebuf), modebuf[0] == 'd'))
946		/* We have a -I option with a directory name that just happens
947		   to match a format name as well.  eg: -I res  Assume that the
948		   user knows what they are doing and do not complain.  */
949		;
950	      else
951		{
952		  fprintf (stderr,
953			   _("Option -I is deprecated for setting the input format, please use -J instead.\n"));
954		  input_format = input_format_tmp;
955		  break;
956		}
957	    }
958	  /* Fall through.  */
959
960	case OPTION_INCLUDE_DIR:
961	  if (preprocargs == NULL)
962	    {
963	      quotedarg = quot (optarg);
964	      preprocargs = xmalloc (strlen (quotedarg) + 3);
965	      sprintf (preprocargs, "-I%s", quotedarg);
966	    }
967	  else
968	    {
969	      char *n;
970
971	      quotedarg = quot (optarg);
972	      n = xmalloc (strlen (preprocargs) + strlen (quotedarg) + 4);
973	      sprintf (n, "%s -I%s", preprocargs, quotedarg);
974	      free (preprocargs);
975	      preprocargs = n;
976	    }
977
978	  windres_add_include_dir (optarg);
979
980	  break;
981
982	case 'l':
983	  language = strtol (optarg, (char **) NULL, 16);
984	  break;
985
986	case OPTION_USE_TEMP_FILE:
987	  use_temp_file = 1;
988	  break;
989
990	case OPTION_NO_USE_TEMP_FILE:
991	  use_temp_file = 0;
992	  break;
993
994#ifdef YYDEBUG
995	case OPTION_YYDEBUG:
996	  yydebug = 1;
997	  break;
998#endif
999
1000	case 'h':
1001	case 'H':
1002	  usage (stdout, 0);
1003	  break;
1004
1005	case 'V':
1006	  print_version ("windres");
1007	  break;
1008
1009	default:
1010	  usage (stderr, 1);
1011	  break;
1012	}
1013    }
1014
1015  if (input_filename == NULL && optind < argc)
1016    {
1017      input_filename = argv[optind];
1018      ++optind;
1019    }
1020
1021  if (output_filename == NULL && optind < argc)
1022    {
1023      output_filename = argv[optind];
1024      ++optind;
1025    }
1026
1027  if (argc != optind)
1028    usage (stderr, 1);
1029
1030  if (input_format == RES_FORMAT_UNKNOWN)
1031    {
1032      if (input_filename == NULL)
1033	input_format = RES_FORMAT_RC;
1034      else
1035	input_format = format_from_filename (input_filename, 1);
1036    }
1037
1038  if (output_format == RES_FORMAT_UNKNOWN)
1039    {
1040      if (output_filename == NULL)
1041	output_format = RES_FORMAT_RC;
1042      else
1043	output_format = format_from_filename (output_filename, 0);
1044    }
1045
1046  set_endianness (NULL, target);
1047
1048  /* Read the input file.  */
1049  switch (input_format)
1050    {
1051    default:
1052      abort ();
1053    case RES_FORMAT_RC:
1054      resources = read_rc_file (input_filename, preprocessor, preprocargs,
1055				language, use_temp_file);
1056      break;
1057    case RES_FORMAT_RES:
1058      resources = read_res_file (input_filename);
1059      break;
1060    case RES_FORMAT_COFF:
1061      resources = read_coff_rsrc (input_filename, target);
1062      break;
1063    }
1064
1065  if (resources == NULL)
1066    fatal (_("no resources"));
1067
1068  /* Sort the resources.  This is required for COFF, convenient for
1069     rc, and unimportant for res.  */
1070  resources = sort_resources (resources);
1071
1072  /* Write the output file.  */
1073  reswr_init ();
1074
1075  switch (output_format)
1076    {
1077    default:
1078      abort ();
1079    case RES_FORMAT_RC:
1080      write_rc_file (output_filename, resources);
1081      break;
1082    case RES_FORMAT_RES:
1083      write_res_file (output_filename, resources);
1084      break;
1085    case RES_FORMAT_COFF:
1086      write_coff_file (output_filename, target, resources);
1087      break;
1088    }
1089
1090  xexit (0);
1091  return 0;
1092}
1093
1094static void
1095set_endianness (bfd *abfd, const char *target)
1096{
1097  const bfd_target *target_vec;
1098
1099  def_target_arch = NULL;
1100  target_vec = bfd_get_target_info (target, abfd, &target_is_bigendian, NULL,
1101                                   &def_target_arch);
1102  if (! target_vec)
1103    fatal ("Can't detect target endianness and architecture.");
1104  if (! def_target_arch)
1105    fatal ("Can't detect architecture.");
1106}
1107
1108bfd *
1109windres_open_as_binary (const char *filename, int rdmode)
1110{
1111  bfd *abfd;
1112
1113  abfd = (rdmode ? bfd_openr (filename, "binary") : bfd_openw (filename, "binary"));
1114  if (! abfd)
1115    fatal ("can't open `%s' for %s", filename, (rdmode ? "input" : "output"));
1116
1117  if (rdmode && ! bfd_check_format (abfd, bfd_object))
1118    fatal ("can't open `%s' for input.", filename);
1119
1120  return abfd;
1121}
1122
1123void
1124set_windres_bfd_endianness (windres_bfd *wrbfd, int is_bigendian)
1125{
1126  assert (!! wrbfd);
1127  switch (WR_KIND(wrbfd))
1128  {
1129  case WR_KIND_BFD_BIN_L:
1130    if (is_bigendian)
1131      WR_KIND(wrbfd) = WR_KIND_BFD_BIN_B;
1132    break;
1133  case WR_KIND_BFD_BIN_B:
1134    if (! is_bigendian)
1135      WR_KIND(wrbfd) = WR_KIND_BFD_BIN_L;
1136    break;
1137  default:
1138    /* only binary bfd can be overriden. */
1139    abort ();
1140  }
1141}
1142
1143void
1144set_windres_bfd (windres_bfd *wrbfd, bfd *abfd, asection *sec, rc_uint_type kind)
1145{
1146  assert (!! wrbfd);
1147  switch (kind)
1148  {
1149  case WR_KIND_TARGET:
1150    abfd = NULL;
1151    sec = NULL;
1152    break;
1153  case WR_KIND_BFD:
1154  case WR_KIND_BFD_BIN_L:
1155  case WR_KIND_BFD_BIN_B:
1156    assert (!! abfd);
1157    assert (!!sec);
1158    break;
1159  default:
1160    abort ();
1161  }
1162  WR_KIND(wrbfd) = kind;
1163  WR_BFD(wrbfd) = abfd;
1164  WR_SECTION(wrbfd) = sec;
1165}
1166
1167void
1168set_windres_bfd_content (windres_bfd *wrbfd, const void *data, rc_uint_type off,
1169			 rc_uint_type length)
1170{
1171  if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1172    {
1173      if (! bfd_set_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1174	bfd_fatal ("bfd_set_section_contents");
1175    }
1176  else
1177    abort ();
1178}
1179
1180void
1181get_windres_bfd_content (windres_bfd *wrbfd, void *data, rc_uint_type off,
1182			 rc_uint_type length)
1183{
1184  if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1185    {
1186      if (! bfd_get_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1187	bfd_fatal ("bfd_get_section_contents");
1188    }
1189  else
1190    abort ();
1191}
1192
1193void
1194windres_put_8 (windres_bfd *wrbfd, void *p, rc_uint_type value)
1195{
1196  switch (WR_KIND(wrbfd))
1197    {
1198    case WR_KIND_TARGET:
1199      target_put_8 (p, value);
1200      break;
1201    case WR_KIND_BFD:
1202    case WR_KIND_BFD_BIN_L:
1203    case WR_KIND_BFD_BIN_B:
1204      bfd_put_8 (WR_BFD(wrbfd), value, p);
1205      break;
1206    default:
1207      abort ();
1208    }
1209}
1210
1211void
1212windres_put_16 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1213{
1214  switch (WR_KIND(wrbfd))
1215    {
1216    case WR_KIND_TARGET:
1217      target_put_16 (data, value);
1218      break;
1219    case WR_KIND_BFD:
1220    case WR_KIND_BFD_BIN_B:
1221      bfd_put_16 (WR_BFD(wrbfd), value, data);
1222      break;
1223    case WR_KIND_BFD_BIN_L:
1224      bfd_putl16 (value, data);
1225      break;
1226    default:
1227      abort ();
1228    }
1229}
1230
1231void
1232windres_put_32 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1233{
1234  switch (WR_KIND(wrbfd))
1235    {
1236    case WR_KIND_TARGET:
1237      target_put_32 (data, value);
1238      break;
1239    case WR_KIND_BFD:
1240    case WR_KIND_BFD_BIN_B:
1241      bfd_put_32 (WR_BFD(wrbfd), value, data);
1242      break;
1243    case WR_KIND_BFD_BIN_L:
1244      bfd_putl32 (value, data);
1245      break;
1246    default:
1247      abort ();
1248    }
1249}
1250
1251rc_uint_type
1252windres_get_8 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1253{
1254  if (length < 1)
1255    fatal ("windres_get_8: unexpected eob.");
1256  switch (WR_KIND(wrbfd))
1257    {
1258    case WR_KIND_TARGET:
1259      return target_get_8 (data, length);
1260    case WR_KIND_BFD:
1261    case WR_KIND_BFD_BIN_B:
1262    case WR_KIND_BFD_BIN_L:
1263      return bfd_get_8 (WR_BFD(wrbfd), data);
1264    default:
1265      abort ();
1266    }
1267  return 0;
1268}
1269
1270rc_uint_type
1271windres_get_16 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1272{
1273  if (length < 2)
1274    fatal ("windres_get_16: unexpected eob.");
1275  switch (WR_KIND(wrbfd))
1276    {
1277    case WR_KIND_TARGET:
1278      return target_get_16 (data, length);
1279    case WR_KIND_BFD:
1280    case WR_KIND_BFD_BIN_B:
1281      return bfd_get_16 (WR_BFD(wrbfd), data);
1282    case WR_KIND_BFD_BIN_L:
1283      return bfd_getl16 (data);
1284    default:
1285      abort ();
1286    }
1287  return 0;
1288}
1289
1290rc_uint_type
1291windres_get_32 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1292{
1293  if (length < 4)
1294    fatal ("windres_get_32: unexpected eob.");
1295  switch (WR_KIND(wrbfd))
1296    {
1297    case WR_KIND_TARGET:
1298      return target_get_32 (data, length);
1299    case WR_KIND_BFD:
1300    case WR_KIND_BFD_BIN_B:
1301      return bfd_get_32 (WR_BFD(wrbfd), data);
1302    case WR_KIND_BFD_BIN_L:
1303      return bfd_getl32 (data);
1304    default:
1305      abort ();
1306    }
1307  return 0;
1308}
1309
1310static rc_uint_type
1311target_get_8 (const void *p, rc_uint_type length)
1312{
1313  rc_uint_type ret;
1314
1315  if (length < 1)
1316    fatal ("Resource too small for getting 8-bit value.");
1317
1318  ret = (rc_uint_type) *((const bfd_byte *) p);
1319  return ret & 0xff;
1320}
1321
1322static rc_uint_type
1323target_get_16 (const void *p, rc_uint_type length)
1324{
1325  if (length < 2)
1326    fatal ("Resource too small for getting 16-bit value.");
1327
1328  if (target_is_bigendian)
1329    return bfd_getb16 (p);
1330  else
1331    return bfd_getl16 (p);
1332}
1333
1334static rc_uint_type
1335target_get_32 (const void *p, rc_uint_type length)
1336{
1337  if (length < 4)
1338    fatal ("Resource too small for getting 32-bit value.");
1339
1340  if (target_is_bigendian)
1341    return bfd_getb32 (p);
1342  else
1343    return bfd_getl32 (p);
1344}
1345
1346static void
1347target_put_8 (void *p, rc_uint_type value)
1348{
1349  assert (!! p);
1350  *((bfd_byte *) p)=(bfd_byte) value;
1351}
1352
1353static void
1354target_put_16 (void *p, rc_uint_type value)
1355{
1356  assert (!! p);
1357
1358  if (target_is_bigendian)
1359    bfd_putb16 (value, p);
1360  else
1361    bfd_putl16 (value, p);
1362}
1363
1364static void
1365target_put_32 (void *p, rc_uint_type value)
1366{
1367  assert (!! p);
1368
1369  if (target_is_bigendian)
1370    bfd_putb32 (value, p);
1371  else
1372    bfd_putl32 (value, p);
1373}
1374
1375static int isInComment = 0;
1376
1377int wr_printcomment (FILE *e, const char *fmt, ...)
1378{
1379  va_list arg;
1380  int r = 0;
1381
1382  if (isInComment)
1383    r += fprintf (e, "\n   ");
1384  else
1385    fprintf (e, "/* ");
1386  isInComment = 1;
1387  if (fmt == NULL)
1388    return r;
1389  va_start (arg, fmt);
1390  r += vfprintf (e, fmt, arg);
1391  va_end (arg);
1392  return r;
1393}
1394
1395int wr_print (FILE *e, const char *fmt, ...)
1396{
1397  va_list arg;
1398  int r = 0;
1399  if (isInComment)
1400    r += fprintf (e, ".  */\n");
1401  isInComment = 0;
1402  if (! fmt)
1403    return r;
1404  va_start (arg, fmt);
1405  r += vfprintf (e, fmt, arg);
1406  va_end (arg);
1407  return r;
1408}
1409