1 /* windres.c -- a program to manipulate Windows resources
2    Copyright (C) 1997-2018 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 	  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 
224 int
res_id_cmp(rc_res_id a,rc_res_id b)225 res_id_cmp (rc_res_id a, rc_res_id b)
226 {
227   if (! a.named)
228     {
229       if (b.named)
230 	return 1;
231       if (a.u.id > b.u.id)
232 	return 1;
233       else if (a.u.id < b.u.id)
234 	return -1;
235       else
236 	return 0;
237     }
238   else
239     {
240       unichar *as, *ase, *bs, *bse;
241 
242       if (! b.named)
243 	return -1;
244 
245       as = a.u.n.name;
246       ase = as + a.u.n.length;
247       bs = b.u.n.name;
248       bse = bs + b.u.n.length;
249 
250       while (as < ase)
251 	{
252 	  int i;
253 
254 	  if (bs >= bse)
255 	    return 1;
256 	  i = (int) *as - (int) *bs;
257 	  if (i != 0)
258 	    return i;
259 	  ++as;
260 	  ++bs;
261 	}
262 
263       if (bs < bse)
264 	return -1;
265 
266       return 0;
267     }
268 }
269 
270 /* Print a resource ID.  */
271 
272 void
res_id_print(FILE * stream,rc_res_id id,int quote)273 res_id_print (FILE *stream, rc_res_id id, int quote)
274 {
275   if (! id.named)
276     fprintf (stream, "%u", (int) id.u.id);
277   else
278     {
279       if (quote)
280 	unicode_print_quoted (stream, id.u.n.name, id.u.n.length);
281       else
282       unicode_print (stream, id.u.n.name, id.u.n.length);
283     }
284 }
285 
286 /* Print a list of resource ID's.  */
287 
288 void
res_ids_print(FILE * stream,int cids,const rc_res_id * ids)289 res_ids_print (FILE *stream, int cids, const rc_res_id *ids)
290 {
291   int i;
292 
293   for (i = 0; i < cids; i++)
294     {
295       res_id_print (stream, ids[i], 1);
296       if (i + 1 < cids)
297 	fprintf (stream, ": ");
298     }
299 }
300 
301 /* Convert an ASCII string to a resource ID.  */
302 
303 void
res_string_to_id(rc_res_id * res_id,const char * string)304 res_string_to_id (rc_res_id *res_id, const char *string)
305 {
306   res_id->named = 1;
307   unicode_from_ascii (&res_id->u.n.length, &res_id->u.n.name, string);
308 }
309 
310 /* Convert an unicode string to a resource ID.  */
311 void
res_unistring_to_id(rc_res_id * res_id,const unichar * u)312 res_unistring_to_id (rc_res_id *res_id, const unichar *u)
313 {
314   res_id->named = 1;
315   res_id->u.n.length = unichar_len (u);
316   res_id->u.n.name = unichar_dup_uppercase (u);
317 }
318 
319 /* Define a resource.  The arguments are the resource tree, RESOURCES,
320    and the location at which to put it in the tree, CIDS and IDS.
321    This returns a newly allocated rc_res_resource structure, which the
322    caller is expected to initialize.  If DUPOK is non-zero, then if a
323    resource with this ID exists, it is returned.  Otherwise, a warning
324    is issued, and a new resource is created replacing the existing
325    one.  */
326 
327 rc_res_resource *
define_resource(rc_res_directory ** resources,int cids,const rc_res_id * ids,int dupok)328 define_resource (rc_res_directory **resources, int cids,
329 		 const rc_res_id *ids, int dupok)
330 {
331   rc_res_entry *re = NULL;
332   int i;
333 
334   assert (cids > 0);
335   for (i = 0; i < cids; i++)
336     {
337       rc_res_entry **pp;
338 
339       if (*resources == NULL)
340 	{
341 	  *resources = ((rc_res_directory *)
342 			res_alloc (sizeof (rc_res_directory)));
343 	  (*resources)->characteristics = 0;
344 	  /* Using a real timestamp only serves to create non-deterministic
345 	     results.  Use zero instead.  */
346 	  (*resources)->time = 0;
347 	  (*resources)->major = 0;
348 	  (*resources)->minor = 0;
349 	  (*resources)->entries = NULL;
350 	}
351 
352       for (pp = &(*resources)->entries; *pp != NULL; pp = &(*pp)->next)
353 	if (res_id_cmp ((*pp)->id, ids[i]) == 0)
354 	  break;
355 
356       if (*pp != NULL)
357 	re = *pp;
358       else
359 	{
360 	  re = (rc_res_entry *) res_alloc (sizeof (rc_res_entry));
361 	  re->next = NULL;
362 	  re->id = ids[i];
363 	  if ((i + 1) < cids)
364 	    {
365 	      re->subdir = 1;
366 	      re->u.dir = NULL;
367 	    }
368 	  else
369 	    {
370 	      re->subdir = 0;
371 	      re->u.res = NULL;
372 	    }
373 
374 	  *pp = re;
375 	}
376 
377       if ((i + 1) < cids)
378 	{
379 	  if (! re->subdir)
380 	    {
381 	      fprintf (stderr, "%s: ", program_name);
382 	      res_ids_print (stderr, i, ids);
383 	      fprintf (stderr, _(": expected to be a directory\n"));
384 	      xexit (1);
385 	    }
386 
387 	  resources = &re->u.dir;
388 	}
389     }
390 
391   if (re->subdir)
392     {
393       fprintf (stderr, "%s: ", program_name);
394       res_ids_print (stderr, cids, ids);
395       fprintf (stderr, _(": expected to be a leaf\n"));
396       xexit (1);
397     }
398 
399   if (re->u.res != NULL)
400     {
401       if (dupok)
402 	return re->u.res;
403 
404       fprintf (stderr, _("%s: warning: "), program_name);
405       res_ids_print (stderr, cids, ids);
406       fprintf (stderr, _(": duplicate value\n"));
407     }
408 
409   re->u.res = ((rc_res_resource *)
410 	       res_alloc (sizeof (rc_res_resource)));
411   memset (re->u.res, 0, sizeof (rc_res_resource));
412 
413   re->u.res->type = RES_TYPE_UNINITIALIZED;
414   return re->u.res;
415 }
416 
417 /* Define a standard resource.  This is a version of define_resource
418    that just takes type, name, and language arguments.  */
419 
420 rc_res_resource *
define_standard_resource(rc_res_directory ** resources,int type,rc_res_id name,rc_uint_type language,int dupok)421 define_standard_resource (rc_res_directory **resources, int type,
422 			  rc_res_id name, rc_uint_type language, int dupok)
423 {
424   rc_res_id a[3];
425 
426   a[0].named = 0;
427   a[0].u.id = type;
428   a[1] = name;
429   a[2].named = 0;
430   a[2].u.id = language;
431   return define_resource (resources, 3, a, dupok);
432 }
433 
434 /* Comparison routine for resource sorting.  */
435 
436 static int
cmp_res_entry(const void * p1,const void * p2)437 cmp_res_entry (const void *p1, const void *p2)
438 {
439   const rc_res_entry **re1, **re2;
440 
441   re1 = (const rc_res_entry **) p1;
442   re2 = (const rc_res_entry **) p2;
443   return res_id_cmp ((*re1)->id, (*re2)->id);
444 }
445 
446 /* Sort the resources.  */
447 
448 static rc_res_directory *
sort_resources(rc_res_directory * resdir)449 sort_resources (rc_res_directory *resdir)
450 {
451   int c, i;
452   rc_res_entry *re;
453   rc_res_entry **a;
454 
455   if (resdir->entries == NULL)
456     return resdir;
457 
458   c = 0;
459   for (re = resdir->entries; re != NULL; re = re->next)
460     ++c;
461 
462   /* This is a recursive routine, so using xmalloc is probably better
463      than alloca.  */
464   a = (rc_res_entry **) xmalloc (c * sizeof (rc_res_entry *));
465 
466   for (i = 0, re = resdir->entries; re != NULL; re = re->next, i++)
467     a[i] = re;
468 
469   qsort (a, c, sizeof (rc_res_entry *), cmp_res_entry);
470 
471   resdir->entries = a[0];
472   for (i = 0; i < c - 1; i++)
473     a[i]->next = a[i + 1];
474   a[i]->next = NULL;
475 
476   free (a);
477 
478   /* Now sort the subdirectories.  */
479 
480   for (re = resdir->entries; re != NULL; re = re->next)
481     if (re->subdir)
482       re->u.dir = sort_resources (re->u.dir);
483 
484   return resdir;
485 }
486 
487 /* Return whether the dialog resource DIALOG is a DIALOG or a
488    DIALOGEX.  */
489 
490 int
extended_dialog(const rc_dialog * dialog)491 extended_dialog (const rc_dialog *dialog)
492 {
493   const rc_dialog_control *c;
494 
495   if (dialog->ex != NULL)
496     return 1;
497 
498   for (c = dialog->controls; c != NULL; c = c->next)
499     if (c->data != NULL || c->help != 0)
500       return 1;
501 
502   return 0;
503 }
504 
505 /* Return whether MENUITEMS are a MENU or a MENUEX.  */
506 
507 int
extended_menu(const rc_menu * menu)508 extended_menu (const rc_menu *menu)
509 {
510   return extended_menuitems (menu->items);
511 }
512 
513 static int
extended_menuitems(const rc_menuitem * menuitems)514 extended_menuitems (const rc_menuitem *menuitems)
515 {
516   const rc_menuitem *mi;
517 
518   for (mi = menuitems; mi != NULL; mi = mi->next)
519     {
520       if (mi->help != 0 || mi->state != 0)
521 	return 1;
522       if (mi->popup != NULL && mi->id != 0)
523 	return 1;
524       if ((mi->type
525 	   & ~ (MENUITEM_CHECKED
526 		| MENUITEM_GRAYED
527 		| MENUITEM_HELP
528 		| MENUITEM_INACTIVE
529 		| MENUITEM_MENUBARBREAK
530 		| MENUITEM_MENUBREAK))
531 	  != 0)
532 	return 1;
533       if (mi->popup != NULL)
534 	{
535 	  if (extended_menuitems (mi->popup))
536 	    return 1;
537 	}
538     }
539 
540   return 0;
541 }
542 
543 /* Convert a string to a format type, or exit if it can't be done.  */
544 
545 static enum res_format
format_from_name(const char * name,int exit_on_error)546 format_from_name (const char *name, int exit_on_error)
547 {
548   const struct format_map *m;
549 
550   for (m = format_names; m->name != NULL; m++)
551     if (strcasecmp (m->name, name) == 0)
552       break;
553 
554   if (m->name == NULL && exit_on_error)
555     {
556       non_fatal (_("unknown format type `%s'"), name);
557       fprintf (stderr, _("%s: supported formats:"), program_name);
558       for (m = format_names; m->name != NULL; m++)
559 	fprintf (stderr, " %s", m->name);
560       fprintf (stderr, "\n");
561       xexit (1);
562     }
563 
564   return m->format;
565 }
566 
567 /* Work out a format type given a file name.  If INPUT is non-zero,
568    it's OK to look at the file itself.  */
569 
570 static enum res_format
format_from_filename(const char * filename,int input)571 format_from_filename (const char *filename, int input)
572 {
573   const char *ext;
574   FILE *e;
575   bfd_byte b1, b2, b3, b4, b5;
576   int magic;
577 
578   /* If we have an extension, see if we recognize it as implying a
579      particular format.  */
580   ext = strrchr (filename, '.');
581   if (ext != NULL)
582     {
583       const struct format_map *m;
584 
585       ++ext;
586       for (m = format_fileexts; m->name != NULL; m++)
587 	if (strcasecmp (m->name, ext) == 0)
588 	  return m->format;
589     }
590 
591   /* If we don't recognize the name of an output file, assume it's a
592      COFF file.  */
593   if (! input)
594     return RES_FORMAT_COFF;
595 
596   /* Read the first few bytes of the file to see if we can guess what
597      it is.  */
598   e = fopen (filename, FOPEN_RB);
599   if (e == NULL)
600     fatal ("%s: %s", filename, strerror (errno));
601 
602   b1 = getc (e);
603   b2 = getc (e);
604   b3 = getc (e);
605   b4 = getc (e);
606   b5 = getc (e);
607 
608   fclose (e);
609 
610   /* A PE executable starts with 0x4d 0x5a.  */
611   if (b1 == 0x4d && b2 == 0x5a)
612     return RES_FORMAT_COFF;
613 
614   /* A COFF .o file starts with a COFF magic number.  */
615   magic = (b2 << 8) | b1;
616   switch (magic)
617     {
618     case 0x14c: /* i386 */
619     case 0x166: /* MIPS */
620     case 0x184: /* Alpha */
621     case 0x268: /* 68k */
622     case 0x1f0: /* PowerPC */
623     case 0x290: /* PA */
624       return RES_FORMAT_COFF;
625     }
626 
627   /* A RES file starts with 0x0 0x0 0x0 0x0 0x20 0x0 0x0 0x0.  */
628   if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0 && b5 == 0x20)
629     return RES_FORMAT_RES;
630 
631   /* If every character is printable or space, assume it's an RC file.  */
632   if ((ISPRINT (b1) || ISSPACE (b1))
633       && (ISPRINT (b2) || ISSPACE (b2))
634       && (ISPRINT (b3) || ISSPACE (b3))
635       && (ISPRINT (b4) || ISSPACE (b4))
636       && (ISPRINT (b5) || ISSPACE (b5)))
637     return RES_FORMAT_RC;
638 
639   /* Otherwise, we give up.  */
640   fatal (_("can not determine type of file `%s'; use the -J option"),
641 	 filename);
642 
643   /* Return something to silence the compiler warning.  */
644   return RES_FORMAT_UNKNOWN;
645 }
646 
647 /* Print a usage message and exit.  */
648 
649 static void
usage(FILE * stream,int status)650 usage (FILE *stream, int status)
651 {
652   fprintf (stream, _("Usage: %s [option(s)] [input-file] [output-file]\n"),
653 	   program_name);
654   fprintf (stream, _(" The options are:\n\
655   -i --input=<file>            Name input file\n\
656   -o --output=<file>           Name output file\n\
657   -J --input-format=<format>   Specify input format\n\
658   -O --output-format=<format>  Specify output format\n\
659   -F --target=<target>         Specify COFF target\n\
660      --preprocessor=<program>  Program to use to preprocess rc file\n\
661      --preprocessor-arg=<arg>  Additional preprocessor argument\n\
662   -I --include-dir=<dir>       Include directory when preprocessing rc file\n\
663   -D --define <sym>[=<val>]    Define SYM when preprocessing rc file\n\
664   -U --undefine <sym>          Undefine SYM when preprocessing rc file\n\
665   -v --verbose                 Verbose - tells you what it's doing\n\
666   -c --codepage=<codepage>     Specify default codepage\n\
667   -l --language=<val>          Set language when reading rc file\n\
668      --use-temp-file           Use a temporary file instead of popen to read\n\
669                                the preprocessor output\n\
670      --no-use-temp-file        Use popen (default)\n"));
671 #ifdef YYDEBUG
672   fprintf (stream, _("\
673      --yydebug                 Turn on parser debugging\n"));
674 #endif
675   fprintf (stream, _("\
676   -r                           Ignored for compatibility with rc\n\
677   @<file>                      Read options from <file>\n\
678   -h --help                    Print this help message\n\
679   -V --version                 Print version information\n"));
680   fprintf (stream, _("\
681 FORMAT is one of rc, res, or coff, and is deduced from the file name\n\
682 extension if not specified.  A single file name is an input file.\n\
683 No input-file is stdin, default rc.  No output-file is stdout, default rc.\n"));
684 
685   list_supported_targets (program_name, stream);
686 
687   if (REPORT_BUGS_TO[0] && status == 0)
688     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
689 
690   exit (status);
691 }
692 
693 /* Quote characters that will confuse the shell when we run the preprocessor.  */
694 
695 static const char *
quot(const char * string)696 quot (const char *string)
697 {
698   static char *buf = 0;
699   static int buflen = 0;
700   int slen = strlen (string);
701   const char *src;
702   char *dest;
703 
704   if ((buflen < slen * 2 + 2) || ! buf)
705     {
706       buflen = slen * 2 + 2;
707       if (buf)
708 	free (buf);
709       buf = (char *) xmalloc (buflen);
710     }
711 
712   for (src=string, dest=buf; *src; src++, dest++)
713     {
714       if (*src == '(' || *src == ')' || *src == ' ')
715 	*dest++ = '\\';
716       *dest = *src;
717     }
718   *dest = 0;
719   return buf;
720 }
721 
722 /* Long options.  */
723 
724 enum option_values
725 {
726   /* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
727   OPTION_PREPROCESSOR	= 150,
728   OPTION_USE_TEMP_FILE,
729   OPTION_NO_USE_TEMP_FILE,
730   OPTION_YYDEBUG,
731   OPTION_INCLUDE_DIR,
732   OPTION_PREPROCESSOR_ARG
733 };
734 
735 static const struct option long_options[] =
736 {
737   {"input", required_argument, 0, 'i'},
738   {"output", required_argument, 0, 'o'},
739   {"input-format", required_argument, 0, 'J'},
740   {"output-format", required_argument, 0, 'O'},
741   {"target", required_argument, 0, 'F'},
742   {"preprocessor", required_argument, 0, OPTION_PREPROCESSOR},
743   {"preprocessor-arg", required_argument, 0, OPTION_PREPROCESSOR_ARG},
744   {"include-dir", required_argument, 0, OPTION_INCLUDE_DIR},
745   {"define", required_argument, 0, 'D'},
746   {"undefine", required_argument, 0, 'U'},
747   {"verbose", no_argument, 0, 'v'},
748   {"codepage", required_argument, 0, 'c'},
749   {"language", required_argument, 0, 'l'},
750   {"use-temp-file", no_argument, 0, OPTION_USE_TEMP_FILE},
751   {"no-use-temp-file", no_argument, 0, OPTION_NO_USE_TEMP_FILE},
752   {"yydebug", no_argument, 0, OPTION_YYDEBUG},
753   {"version", no_argument, 0, 'V'},
754   {"help", no_argument, 0, 'h'},
755   {0, no_argument, 0, 0}
756 };
757 
758 void
windres_add_include_dir(const char * p)759 windres_add_include_dir (const char *p)
760 {
761   struct include_dir *n, **pp;
762 
763   /* Computing paths is often complicated and error prone.
764      The easiest way to check for mistakes is at the time
765      we add them to include_dirs.  */
766   assert (p != NULL);
767   assert (*p != '\0');
768 
769   n = xmalloc (sizeof *n);
770   n->next = NULL;
771   n->dir = (char * ) p;
772 
773   for (pp = &include_dirs; *pp != NULL; pp = &(*pp)->next)
774     ;
775   *pp = n;
776 }
777 
778 /* This keeps gcc happy when using -Wmissing-prototypes -Wstrict-prototypes.  */
779 int main (int, char **);
780 
781 /* The main function.  */
782 
783 int
main(int argc,char ** argv)784 main (int argc, char **argv)
785 {
786   int c;
787   char *input_filename;
788   char *output_filename;
789   enum res_format input_format;
790   enum res_format input_format_tmp;
791   enum res_format output_format;
792   char *target;
793   char *preprocessor;
794   char *preprocargs;
795   const char *quotedarg;
796   int language;
797   rc_res_directory *resources;
798   int use_temp_file;
799 
800 #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
801   setlocale (LC_MESSAGES, "");
802 #endif
803 #if defined (HAVE_SETLOCALE)
804   setlocale (LC_CTYPE, "");
805 #endif
806   bindtextdomain (PACKAGE, LOCALEDIR);
807   textdomain (PACKAGE);
808 
809   program_name = argv[0];
810   xmalloc_set_program_name (program_name);
811   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 
1094 static void
set_endianness(bfd * abfd,const char * target)1095 set_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 
1108 bfd *
windres_open_as_binary(const char * filename,int rdmode)1109 windres_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 
1123 void
set_windres_bfd_endianness(windres_bfd * wrbfd,int is_bigendian)1124 set_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 
1143 void
set_windres_bfd(windres_bfd * wrbfd,bfd * abfd,asection * sec,rc_uint_type kind)1144 set_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 
1167 void
set_windres_bfd_content(windres_bfd * wrbfd,const void * data,rc_uint_type off,rc_uint_type length)1168 set_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 
1180 void
get_windres_bfd_content(windres_bfd * wrbfd,void * data,rc_uint_type off,rc_uint_type length)1181 get_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 
1193 void
windres_put_8(windres_bfd * wrbfd,void * p,rc_uint_type value)1194 windres_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 
1211 void
windres_put_16(windres_bfd * wrbfd,void * data,rc_uint_type value)1212 windres_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 
1231 void
windres_put_32(windres_bfd * wrbfd,void * data,rc_uint_type value)1232 windres_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 
1251 rc_uint_type
windres_get_8(windres_bfd * wrbfd,const void * data,rc_uint_type length)1252 windres_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 
1270 rc_uint_type
windres_get_16(windres_bfd * wrbfd,const void * data,rc_uint_type length)1271 windres_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 
1290 rc_uint_type
windres_get_32(windres_bfd * wrbfd,const void * data,rc_uint_type length)1291 windres_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 
1310 static rc_uint_type
target_get_8(const void * p,rc_uint_type length)1311 target_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 
1322 static rc_uint_type
target_get_16(const void * p,rc_uint_type length)1323 target_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 
1334 static rc_uint_type
target_get_32(const void * p,rc_uint_type length)1335 target_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 
1346 static void
target_put_8(void * p,rc_uint_type value)1347 target_put_8 (void *p, rc_uint_type value)
1348 {
1349   assert (!! p);
1350   *((bfd_byte *) p)=(bfd_byte) value;
1351 }
1352 
1353 static void
target_put_16(void * p,rc_uint_type value)1354 target_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 
1364 static void
target_put_32(void * p,rc_uint_type value)1365 target_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 
1375 static int isInComment = 0;
1376 
wr_printcomment(FILE * e,const char * fmt,...)1377 int 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 
wr_print(FILE * e,const char * fmt,...)1395 int 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