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 
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 
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
res_init(void)143 res_init (void)
144 {
145   obstack_init (&res_obstack);
146 }
147 
148 /* Allocate space on the resource building obstack.  */
149 
150 void *
res_alloc(rc_uint_type bytes)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
reswr_init(void)164 reswr_init (void)
165 {
166   obstack_init (&reswr_obstack);
167 }
168 
169 /* Allocate space on the resource writing obstack.  */
170 
171 void *
reswr_alloc(rc_uint_type bytes)172 reswr_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 
179 FILE *
open_file_search(const char * filename,const char * mode,const char * errmsg,char ** real_filename)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 
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
res_id_cmp(rc_res_id a,rc_res_id b)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
res_id_print(FILE * stream,rc_res_id id,int quote)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
res_ids_print(FILE * stream,int cids,const rc_res_id * ids)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
res_string_to_id(rc_res_id * res_id,const char * string)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
res_unistring_to_id(rc_res_id * res_id,const unichar * u)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 *
define_resource(rc_res_directory ** resources,int cids,const rc_res_id * ids,int dupok)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 *
define_standard_resource(rc_res_directory ** resources,int type,rc_res_id name,rc_uint_type language,int dupok)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
cmp_res_entry(const void * p1,const void * p2)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 *
sort_resources(rc_res_directory * resdir)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 
486 /* Return whether the dialog resource DIALOG is a DIALOG or a
487    DIALOGEX.  */
488 
489 int
extended_dialog(const rc_dialog * dialog)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
extended_menu(const rc_menu * menu)507 extended_menu (const rc_menu *menu)
508 {
509   return extended_menuitems (menu->items);
510 }
511 
512 static int
extended_menuitems(const rc_menuitem * menuitems)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 
542 /* Convert a string to a format type, or exit if it can't be done.  */
543 
544 static enum res_format
format_from_name(const char * name,int exit_on_error)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
format_from_filename(const char * filename,int input)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
usage(FILE * stream,int status)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 *
quot(const char * string)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
windres_add_include_dir(const char * p)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
main(int argc,char ** argv)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
set_endianness(bfd * abfd,const char * target)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 *
windres_open_as_binary(const char * filename,int rdmode)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
set_windres_bfd_endianness(windres_bfd * wrbfd,int is_bigendian)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
set_windres_bfd(windres_bfd * wrbfd,bfd * abfd,asection * sec,rc_uint_type kind)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
set_windres_bfd_content(windres_bfd * wrbfd,const void * data,rc_uint_type off,rc_uint_type length)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
get_windres_bfd_content(windres_bfd * wrbfd,void * data,rc_uint_type off,rc_uint_type length)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
windres_put_8(windres_bfd * wrbfd,void * p,rc_uint_type value)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
windres_put_16(windres_bfd * wrbfd,void * data,rc_uint_type value)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
windres_put_32(windres_bfd * wrbfd,void * data,rc_uint_type value)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
windres_get_8(windres_bfd * wrbfd,const void * data,rc_uint_type length)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
windres_get_16(windres_bfd * wrbfd,const void * data,rc_uint_type length)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
windres_get_32(windres_bfd * wrbfd,const void * data,rc_uint_type length)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
target_get_8(const void * p,rc_uint_type length)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
target_get_16(const void * p,rc_uint_type length)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
target_get_32(const void * p,rc_uint_type length)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
target_put_8(void * p,rc_uint_type value)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
target_put_16(void * p,rc_uint_type value)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
target_put_32(void * p,rc_uint_type value)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 
wr_printcomment(FILE * e,const char * fmt,...)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 
wr_print(FILE * e,const char * fmt,...)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 }
1407