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