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 300

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

powered by: WebSVN 2.1.0

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