OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [binutils-2.20.1/] [binutils/] [windres.c] - Blame information for rev 823

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

Line No. Rev Author Line
1 205 julius
/* windres.c -- a program to manipulate Windows resources
2
   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008,
3
   2009 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 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 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 int
1066
find_arch_match(const char *tname,const char **arch)
1067
{
1068
  while (*arch != NULL)
1069
    {
1070
      const char *in_a = strstr (*arch, tname);
1071
      char end_ch = (in_a ? in_a[strlen(tname)] : 0);
1072
 
1073
      if (in_a && (in_a == *arch || in_a[-1] == ':')
1074
          && end_ch == 0)
1075
        {
1076
          def_target_arch = *arch;
1077
          return 1;
1078
        }
1079
      arch++;
1080
    }
1081
  return 0;
1082
}
1083
 
1084
static void
1085
set_endianess (bfd *abfd, const char *target)
1086
{
1087
  const bfd_target *target_vec;
1088
 
1089
  def_target_arch = NULL;
1090
  target_vec = bfd_find_target (target, abfd);
1091
  if (! target_vec)
1092
    fatal ("Can't detect target endianess and architecture.");
1093
  target_is_bigendian = ((target_vec->byteorder == BFD_ENDIAN_BIG) ? 1 : 0);
1094
 
1095
  {
1096
    const char *  tname = target_vec->name;
1097
    const char ** arches = bfd_arch_list();
1098
 
1099
    if (arches && tname)
1100
      {
1101
        char *hyp = strchr (tname, '-');
1102
 
1103
        if (hyp != NULL)
1104
          {
1105
            tname = ++hyp;
1106
 
1107
            /* Make sure we dectect architecture names
1108
               for triplets like "pe-arm-wince-little".  */
1109
            if (!find_arch_match (tname, arches))
1110
              {
1111
                char *new_tname = (char *) alloca (strlen (hyp) + 1);
1112
                strcpy (new_tname, hyp);
1113
                while ((hyp = strrchr (new_tname, '-')) != NULL)
1114
                  {
1115
                    *hyp = 0;
1116
                    if (find_arch_match (new_tname, arches))
1117
                      break;
1118
                  }
1119
              }
1120
          }
1121
        else
1122
          find_arch_match (tname, arches);
1123
      }
1124
 
1125
    free (arches);
1126
 
1127
    if (! def_target_arch)
1128
      fatal ("Can't detect architecture.");
1129
  }
1130
}
1131
 
1132
bfd *
1133
windres_open_as_binary (const char *filename, int rdmode)
1134
{
1135
  bfd *abfd;
1136
 
1137
  abfd = (rdmode ? bfd_openr (filename, "binary") : bfd_openw (filename, "binary"));
1138
  if (! abfd)
1139
    fatal ("can't open `%s' for %s", filename, (rdmode ? "input" : "output"));
1140
 
1141
  if (rdmode && ! bfd_check_format (abfd, bfd_object))
1142
    fatal ("can't open `%s' for input.", filename);
1143
 
1144
  return abfd;
1145
}
1146
 
1147
void
1148
set_windres_bfd_endianess (windres_bfd *wrbfd, int is_bigendian)
1149
{
1150
  assert (!! wrbfd);
1151
  switch (WR_KIND(wrbfd))
1152
  {
1153
  case WR_KIND_BFD_BIN_L:
1154
    if (is_bigendian)
1155
      WR_KIND(wrbfd) = WR_KIND_BFD_BIN_B;
1156
    break;
1157
  case WR_KIND_BFD_BIN_B:
1158
    if (! is_bigendian)
1159
      WR_KIND(wrbfd) = WR_KIND_BFD_BIN_L;
1160
    break;
1161
  default:
1162
    /* only binary bfd can be overriden. */
1163
    abort ();
1164
  }
1165
}
1166
 
1167
void
1168
set_windres_bfd (windres_bfd *wrbfd, bfd *abfd, asection *sec, rc_uint_type kind)
1169
{
1170
  assert (!! wrbfd);
1171
  switch (kind)
1172
  {
1173
  case WR_KIND_TARGET:
1174
    abfd = NULL;
1175
    sec = NULL;
1176
    break;
1177
  case WR_KIND_BFD:
1178
  case WR_KIND_BFD_BIN_L:
1179
  case WR_KIND_BFD_BIN_B:
1180
    assert (!! abfd);
1181
    assert (!!sec);
1182
    break;
1183
  default:
1184
    abort ();
1185
  }
1186
  WR_KIND(wrbfd) = kind;
1187
  WR_BFD(wrbfd) = abfd;
1188
  WR_SECTION(wrbfd) = sec;
1189
}
1190
 
1191
void
1192
set_windres_bfd_content (windres_bfd *wrbfd, const void *data, rc_uint_type off,
1193
                         rc_uint_type length)
1194
{
1195
  if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1196
    {
1197
      if (! bfd_set_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1198
        bfd_fatal ("bfd_set_section_contents");
1199
    }
1200
  else
1201
    abort ();
1202
}
1203
 
1204
void
1205
get_windres_bfd_content (windres_bfd *wrbfd, void *data, rc_uint_type off,
1206
                         rc_uint_type length)
1207
{
1208
  if (WR_KIND(wrbfd) != WR_KIND_TARGET)
1209
    {
1210
      if (! bfd_get_section_contents (WR_BFD(wrbfd), WR_SECTION(wrbfd), data, off, length))
1211
        bfd_fatal ("bfd_get_section_contents");
1212
    }
1213
  else
1214
    abort ();
1215
}
1216
 
1217
void
1218
windres_put_8 (windres_bfd *wrbfd, void *p, rc_uint_type value)
1219
{
1220
  switch (WR_KIND(wrbfd))
1221
    {
1222
    case WR_KIND_TARGET:
1223
      target_put_8 (p, value);
1224
      break;
1225
    case WR_KIND_BFD:
1226
    case WR_KIND_BFD_BIN_L:
1227
    case WR_KIND_BFD_BIN_B:
1228
      bfd_put_8 (WR_BFD(wrbfd), value, p);
1229
      break;
1230
    default:
1231
      abort ();
1232
    }
1233
}
1234
 
1235
void
1236
windres_put_16 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1237
{
1238
  switch (WR_KIND(wrbfd))
1239
    {
1240
    case WR_KIND_TARGET:
1241
      target_put_16 (data, value);
1242
      break;
1243
    case WR_KIND_BFD:
1244
    case WR_KIND_BFD_BIN_B:
1245
      bfd_put_16 (WR_BFD(wrbfd), value, data);
1246
      break;
1247
    case WR_KIND_BFD_BIN_L:
1248
      bfd_putl16 (value, data);
1249
      break;
1250
    default:
1251
      abort ();
1252
    }
1253
}
1254
 
1255
void
1256
windres_put_32 (windres_bfd *wrbfd, void *data, rc_uint_type value)
1257
{
1258
  switch (WR_KIND(wrbfd))
1259
    {
1260
    case WR_KIND_TARGET:
1261
      target_put_32 (data, value);
1262
      break;
1263
    case WR_KIND_BFD:
1264
    case WR_KIND_BFD_BIN_B:
1265
      bfd_put_32 (WR_BFD(wrbfd), value, data);
1266
      break;
1267
    case WR_KIND_BFD_BIN_L:
1268
      bfd_putl32 (value, data);
1269
      break;
1270
    default:
1271
      abort ();
1272
    }
1273
}
1274
 
1275
rc_uint_type
1276
windres_get_8 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1277
{
1278
  if (length < 1)
1279
    fatal ("windres_get_8: unexpected eob.");
1280
  switch (WR_KIND(wrbfd))
1281
    {
1282
    case WR_KIND_TARGET:
1283
      return target_get_8 (data, length);
1284
    case WR_KIND_BFD:
1285
    case WR_KIND_BFD_BIN_B:
1286
    case WR_KIND_BFD_BIN_L:
1287
      return bfd_get_8 (WR_BFD(wrbfd), data);
1288
    default:
1289
      abort ();
1290
    }
1291
  return 0;
1292
}
1293
 
1294
rc_uint_type
1295
windres_get_16 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1296
{
1297
  if (length < 2)
1298
    fatal ("windres_get_16: unexpected eob.");
1299
  switch (WR_KIND(wrbfd))
1300
    {
1301
    case WR_KIND_TARGET:
1302
      return target_get_16 (data, length);
1303
    case WR_KIND_BFD:
1304
    case WR_KIND_BFD_BIN_B:
1305
      return bfd_get_16 (WR_BFD(wrbfd), data);
1306
    case WR_KIND_BFD_BIN_L:
1307
      return bfd_getl16 (data);
1308
    default:
1309
      abort ();
1310
    }
1311
  return 0;
1312
}
1313
 
1314
rc_uint_type
1315
windres_get_32 (windres_bfd *wrbfd, const void *data, rc_uint_type length)
1316
{
1317
  if (length < 4)
1318
    fatal ("windres_get_32: unexpected eob.");
1319
  switch (WR_KIND(wrbfd))
1320
    {
1321
    case WR_KIND_TARGET:
1322
      return target_get_32 (data, length);
1323
    case WR_KIND_BFD:
1324
    case WR_KIND_BFD_BIN_B:
1325
      return bfd_get_32 (WR_BFD(wrbfd), data);
1326
    case WR_KIND_BFD_BIN_L:
1327
      return bfd_getl32 (data);
1328
    default:
1329
      abort ();
1330
    }
1331
  return 0;
1332
}
1333
 
1334
static rc_uint_type
1335
target_get_8 (const void *p, rc_uint_type length)
1336
{
1337
  rc_uint_type ret;
1338
 
1339
  if (length < 1)
1340
    fatal ("Resource too small for getting 8-bit value.");
1341
 
1342
  ret = (rc_uint_type) *((const bfd_byte *) p);
1343
  return ret & 0xff;
1344
}
1345
 
1346
static rc_uint_type
1347
target_get_16 (const void *p, rc_uint_type length)
1348
{
1349
  if (length < 2)
1350
    fatal ("Resource too small for getting 16-bit value.");
1351
 
1352
  if (target_is_bigendian)
1353
    return bfd_getb16 (p);
1354
  else
1355
    return bfd_getl16 (p);
1356
}
1357
 
1358
static rc_uint_type
1359
target_get_32 (const void *p, rc_uint_type length)
1360
{
1361
  if (length < 4)
1362
    fatal ("Resource too small for getting 32-bit value.");
1363
 
1364
  if (target_is_bigendian)
1365
    return bfd_getb32 (p);
1366
  else
1367
    return bfd_getl32 (p);
1368
}
1369
 
1370
static void
1371
target_put_8 (void *p, rc_uint_type value)
1372
{
1373
  assert (!! p);
1374
  *((bfd_byte *) p)=(bfd_byte) value;
1375
}
1376
 
1377
static void
1378
target_put_16 (void *p, rc_uint_type value)
1379
{
1380
  assert (!! p);
1381
 
1382
  if (target_is_bigendian)
1383
    bfd_putb16 (value, p);
1384
  else
1385
    bfd_putl16 (value, p);
1386
}
1387
 
1388
static void
1389
target_put_32 (void *p, rc_uint_type value)
1390
{
1391
  assert (!! p);
1392
 
1393
  if (target_is_bigendian)
1394
    bfd_putb32 (value, p);
1395
  else
1396
    bfd_putl32 (value, p);
1397
}
1398
 
1399
static int isInComment = 0;
1400
 
1401
int wr_printcomment (FILE *e, const char *fmt, ...)
1402
{
1403
  va_list arg;
1404
  int r = 0;
1405
 
1406
  if (isInComment)
1407
    r += fprintf (e, "\n   ");
1408
  else
1409
    fprintf (e, "/* ");
1410
  isInComment = 1;
1411
  if (fmt == NULL)
1412
    return r;
1413
  va_start (arg, fmt);
1414
  r += vfprintf (e, fmt, arg);
1415
  va_end (arg);
1416
  return r;
1417
}
1418
 
1419
int wr_print (FILE *e, const char *fmt, ...)
1420
{
1421
  va_list arg;
1422
  int r = 0;
1423
  if (isInComment)
1424
    r += fprintf (e, ".  */\n");
1425
  isInComment = 0;
1426
  if (! fmt)
1427
    return r;
1428
  va_start (arg, fmt);
1429
  r += vfprintf (e, fmt, arg);
1430
  va_end (arg);
1431
  return r;
1432
}

powered by: WebSVN 2.1.0

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