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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [binutils/] [windres.c] - Blame information for rev 165

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

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

powered by: WebSVN 2.1.0

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