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