OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [binutils-2.18.50/] [binutils/] [windres.c] - Blame information for rev 517

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.