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