1/* resrc.c -- read and write Windows rc files. 2 Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2007, 2008 3 Free Software Foundation, Inc. 4 Written by Ian Lance Taylor, Cygnus Support. 5 Rewritten by Kai Tietz, Onevision. 6 7 This file is part of GNU Binutils. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 22 02110-1301, USA. */ 23 24/* This file contains functions that read and write Windows rc files. 25 These are text files that represent resources. */ 26 27#include "sysdep.h" 28#include "bfd.h" 29#include "bucomm.h" 30#include "libiberty.h" 31#include "safe-ctype.h" 32#include "windres.h" 33 34#include <assert.h> 35#include <errno.h> 36#include <sys/stat.h> 37#ifdef HAVE_UNISTD_H 38#include <unistd.h> 39#endif 40 41#ifdef HAVE_SYS_WAIT_H 42#include <sys/wait.h> 43#else /* ! HAVE_SYS_WAIT_H */ 44#if ! defined (_WIN32) || defined (__CYGWIN__) 45#ifndef WIFEXITED 46#define WIFEXITED(w) (((w)&0377) == 0) 47#endif 48#ifndef WIFSIGNALED 49#define WIFSIGNALED(w) (((w)&0377) != 0177 && ((w)&~0377) == 0) 50#endif 51#ifndef WTERMSIG 52#define WTERMSIG(w) ((w) & 0177) 53#endif 54#ifndef WEXITSTATUS 55#define WEXITSTATUS(w) (((w) >> 8) & 0377) 56#endif 57#else /* defined (_WIN32) && ! defined (__CYGWIN__) */ 58#ifndef WIFEXITED 59#define WIFEXITED(w) (((w) & 0xff) == 0) 60#endif 61#ifndef WIFSIGNALED 62#define WIFSIGNALED(w) (((w) & 0xff) != 0 && ((w) & 0xff) != 0x7f) 63#endif 64#ifndef WTERMSIG 65#define WTERMSIG(w) ((w) & 0x7f) 66#endif 67#ifndef WEXITSTATUS 68#define WEXITSTATUS(w) (((w) & 0xff00) >> 8) 69#endif 70#endif /* defined (_WIN32) && ! defined (__CYGWIN__) */ 71#endif /* ! HAVE_SYS_WAIT_H */ 72 73#ifndef STDOUT_FILENO 74#define STDOUT_FILENO 1 75#endif 76 77#if defined (_WIN32) && ! defined (__CYGWIN__) 78#define popen _popen 79#define pclose _pclose 80#endif 81 82/* The default preprocessor. */ 83 84#define DEFAULT_PREPROCESSOR "gcc -E -xc -DRC_INVOKED" 85 86/* We read the directory entries in a cursor or icon file into 87 instances of this structure. */ 88 89struct icondir 90{ 91 /* Width of image. */ 92 bfd_byte width; 93 /* Height of image. */ 94 bfd_byte height; 95 /* Number of colors in image. */ 96 bfd_byte colorcount; 97 union 98 { 99 struct 100 { 101 /* Color planes. */ 102 unsigned short planes; 103 /* Bits per pixel. */ 104 unsigned short bits; 105 } icon; 106 struct 107 { 108 /* X coordinate of hotspot. */ 109 unsigned short xhotspot; 110 /* Y coordinate of hotspot. */ 111 unsigned short yhotspot; 112 } cursor; 113 } u; 114 /* Bytes in image. */ 115 unsigned long bytes; 116 /* File offset of image. */ 117 unsigned long offset; 118}; 119 120/* The name of the rc file we are reading. */ 121 122char *rc_filename; 123 124/* The line number in the rc file. */ 125 126int rc_lineno; 127 128/* The pipe we are reading from, so that we can close it if we exit. */ 129 130FILE *cpp_pipe; 131 132/* The temporary file used if we're not using popen, so we can delete it 133 if we exit. */ 134 135static char *cpp_temp_file; 136 137/* Input stream is either a file or a pipe. */ 138 139static enum {ISTREAM_PIPE, ISTREAM_FILE} istream_type; 140 141/* As we read the rc file, we attach information to this structure. */ 142 143static rc_res_directory *resources; 144 145/* The number of cursor resources we have written out. */ 146 147static int cursors; 148 149/* The number of font resources we have written out. */ 150 151static int fonts; 152 153/* Font directory information. */ 154 155rc_fontdir *fontdirs; 156 157/* Resource info to use for fontdirs. */ 158 159rc_res_res_info fontdirs_resinfo; 160 161/* The number of icon resources we have written out. */ 162 163static int icons; 164 165/* The windres target bfd . */ 166 167static windres_bfd wrtarget = 168{ 169 (bfd *) NULL, (asection *) NULL, WR_KIND_TARGET 170}; 171 172/* Local functions for rcdata based resource definitions. */ 173 174static void define_font_rcdata (rc_res_id, const rc_res_res_info *, 175 rc_rcdata_item *); 176static void define_icon_rcdata (rc_res_id, const rc_res_res_info *, 177 rc_rcdata_item *); 178static void define_bitmap_rcdata (rc_res_id, const rc_res_res_info *, 179 rc_rcdata_item *); 180static void define_cursor_rcdata (rc_res_id, const rc_res_res_info *, 181 rc_rcdata_item *); 182static void define_fontdir_rcdata (rc_res_id, const rc_res_res_info *, 183 rc_rcdata_item *); 184static void define_messagetable_rcdata (rc_res_id, const rc_res_res_info *, 185 rc_rcdata_item *); 186static rc_uint_type rcdata_copy (const rc_rcdata_item *, bfd_byte *); 187static bfd_byte *rcdata_render_as_buffer (const rc_rcdata_item *, rc_uint_type *); 188 189static int run_cmd (char *, const char *); 190static FILE *open_input_stream (char *); 191static FILE *look_for_default 192 (char *, const char *, int, const char *, const char *); 193static void close_input_stream (void); 194static void unexpected_eof (const char *); 195static int get_word (FILE *, const char *); 196static unsigned long get_long (FILE *, const char *); 197static void get_data (FILE *, bfd_byte *, rc_uint_type, const char *); 198static void define_fontdirs (void); 199 200/* Run `cmd' and redirect the output to `redir'. */ 201 202static int 203run_cmd (char *cmd, const char *redir) 204{ 205 char *s; 206 int pid, wait_status, retcode; 207 int i; 208 const char **argv; 209 char *errmsg_fmt, *errmsg_arg; 210 char *temp_base = choose_temp_base (); 211 int in_quote; 212 char sep; 213 int redir_handle = -1; 214 int stdout_save = -1; 215 216 /* Count the args. */ 217 i = 0; 218 219 for (s = cmd; *s; s++) 220 if (*s == ' ') 221 i++; 222 223 i++; 224 argv = alloca (sizeof (char *) * (i + 3)); 225 i = 0; 226 s = cmd; 227 228 while (1) 229 { 230 while (*s == ' ' && *s != 0) 231 s++; 232 233 if (*s == 0) 234 break; 235 236 in_quote = (*s == '\'' || *s == '"'); 237 sep = (in_quote) ? *s++ : ' '; 238 argv[i++] = s; 239 240 while (*s != sep && *s != 0) 241 s++; 242 243 if (*s == 0) 244 break; 245 246 *s++ = 0; 247 248 if (in_quote) 249 s++; 250 } 251 argv[i++] = NULL; 252 253 /* Setup the redirection. We can't use the usual fork/exec and redirect 254 since we may be running on non-POSIX Windows host. */ 255 256 fflush (stdout); 257 fflush (stderr); 258 259 /* Open temporary output file. */ 260 redir_handle = open (redir, O_WRONLY | O_TRUNC | O_CREAT, 0666); 261 if (redir_handle == -1) 262 fatal (_("can't open temporary file `%s': %s"), redir, 263 strerror (errno)); 264 265 /* Duplicate the stdout file handle so it can be restored later. */ 266 stdout_save = dup (STDOUT_FILENO); 267 if (stdout_save == -1) 268 fatal (_("can't redirect stdout: `%s': %s"), redir, strerror (errno)); 269 270 /* Redirect stdout to our output file. */ 271 dup2 (redir_handle, STDOUT_FILENO); 272 273 pid = pexecute (argv[0], (char * const *) argv, program_name, temp_base, 274 &errmsg_fmt, &errmsg_arg, PEXECUTE_ONE | PEXECUTE_SEARCH); 275 276 /* Restore stdout to its previous setting. */ 277 dup2 (stdout_save, STDOUT_FILENO); 278 279 /* Close response file. */ 280 close (redir_handle); 281 282 if (pid == -1) 283 { 284 fatal ("%s %s: %s", errmsg_fmt, errmsg_arg, strerror (errno)); 285 return 1; 286 } 287 288 retcode = 0; 289 pid = pwait (pid, &wait_status, 0); 290 291 if (pid == -1) 292 { 293 fatal (_("wait: %s"), strerror (errno)); 294 retcode = 1; 295 } 296 else if (WIFSIGNALED (wait_status)) 297 { 298 fatal (_("subprocess got fatal signal %d"), WTERMSIG (wait_status)); 299 retcode = 1; 300 } 301 else if (WIFEXITED (wait_status)) 302 { 303 if (WEXITSTATUS (wait_status) != 0) 304 { 305 fatal (_("%s exited with status %d"), cmd, 306 WEXITSTATUS (wait_status)); 307 retcode = 1; 308 } 309 } 310 else 311 retcode = 1; 312 313 return retcode; 314} 315 316static FILE * 317open_input_stream (char *cmd) 318{ 319 if (istream_type == ISTREAM_FILE) 320 { 321 char *fileprefix; 322 323 fileprefix = choose_temp_base (); 324 cpp_temp_file = (char *) xmalloc (strlen (fileprefix) + 5); 325 sprintf (cpp_temp_file, "%s.irc", fileprefix); 326 free (fileprefix); 327 328 if (run_cmd (cmd, cpp_temp_file)) 329 fatal (_("can't execute `%s': %s"), cmd, strerror (errno)); 330 331 cpp_pipe = fopen (cpp_temp_file, FOPEN_RT);; 332 if (cpp_pipe == NULL) 333 fatal (_("can't open temporary file `%s': %s"), 334 cpp_temp_file, strerror (errno)); 335 336 if (verbose) 337 fprintf (stderr, 338 _("Using temporary file `%s' to read preprocessor output\n"), 339 cpp_temp_file); 340 } 341 else 342 { 343 cpp_pipe = popen (cmd, FOPEN_RT); 344 if (cpp_pipe == NULL) 345 fatal (_("can't popen `%s': %s"), cmd, strerror (errno)); 346 if (verbose) 347 fprintf (stderr, _("Using popen to read preprocessor output\n")); 348 } 349 350 xatexit (close_input_stream); 351 return cpp_pipe; 352} 353 354/* Determine if FILENAME contains special characters that 355 can cause problems unless the entire filename is quoted. */ 356 357static int 358filename_need_quotes (const char *filename) 359{ 360 if (filename == NULL || (filename[0] == '-' && filename[1] == 0)) 361 return 0; 362 363 while (*filename != 0) 364 { 365 switch (*filename) 366 { 367 case '&': 368 case ' ': 369 case '<': 370 case '>': 371 case '|': 372 case '%': 373 return 1; 374 } 375 ++filename; 376 } 377 return 0; 378} 379 380/* Look for the preprocessor program. */ 381 382static FILE * 383look_for_default (char *cmd, const char *prefix, int end_prefix, 384 const char *preprocargs, const char *filename) 385{ 386 char *space; 387 int found; 388 struct stat s; 389 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : ""); 390 391 strcpy (cmd, prefix); 392 393 sprintf (cmd + end_prefix, "%s", DEFAULT_PREPROCESSOR); 394 space = strchr (cmd + end_prefix, ' '); 395 if (space) 396 *space = 0; 397 398 if ( 399#if defined (__DJGPP__) || defined (__CYGWIN__) || defined (_WIN32) 400 strchr (cmd, '\\') || 401#endif 402 strchr (cmd, '/')) 403 { 404 found = (stat (cmd, &s) == 0 405#ifdef HAVE_EXECUTABLE_SUFFIX 406 || stat (strcat (cmd, EXECUTABLE_SUFFIX), &s) == 0 407#endif 408 ); 409 410 if (! found) 411 { 412 if (verbose) 413 fprintf (stderr, _("Tried `%s'\n"), cmd); 414 return NULL; 415 } 416 } 417 418 strcpy (cmd, prefix); 419 420 sprintf (cmd + end_prefix, "%s %s %s%s%s", 421 DEFAULT_PREPROCESSOR, preprocargs, fnquotes, filename, fnquotes); 422 423 if (verbose) 424 fprintf (stderr, _("Using `%s'\n"), cmd); 425 426 cpp_pipe = open_input_stream (cmd); 427 return cpp_pipe; 428} 429 430/* Read an rc file. */ 431 432rc_res_directory * 433read_rc_file (const char *filename, const char *preprocessor, 434 const char *preprocargs, int language, int use_temp_file) 435{ 436 char *cmd; 437 const char *fnquotes = (filename_need_quotes (filename) ? "\"" : ""); 438 439 if (filename == NULL) 440 filename = "-"; 441 /* Setup the default resource import path taken from input file. */ 442 else if (strchr (filename, '/') != NULL || strchr (filename, '\\') != NULL) 443 { 444 char *edit, *dir; 445 446 if (filename[0] == '/' 447 || filename[0] == '\\' 448 || filename[1] == ':') 449 /* Absolute path. */ 450 edit = dir = xstrdup (filename); 451 else 452 { 453 /* Relative path. */ 454 edit = dir = xmalloc (strlen (filename) + 3); 455 sprintf (dir, "./%s", filename); 456 } 457 458 /* Walk dir backwards stopping at the first directory separator. */ 459 edit += strlen (dir); 460 while (edit > dir && (edit[-1] != '\\' && edit[-1] != '/')) 461 { 462 --edit; 463 edit[0] = 0; 464 } 465 466 /* Cut off trailing slash. */ 467 --edit; 468 edit[0] = 0; 469 470 /* Convert all back slashes to forward slashes. */ 471 while ((edit = strchr (dir, '\\')) != NULL) 472 *edit = '/'; 473 474 windres_add_include_dir (dir); 475 } 476 477 istream_type = (use_temp_file) ? ISTREAM_FILE : ISTREAM_PIPE; 478 479 if (preprocargs == NULL) 480 preprocargs = ""; 481 482 if (preprocessor) 483 { 484 cmd = xmalloc (strlen (preprocessor) 485 + strlen (preprocargs) 486 + strlen (filename) 487 + strlen (fnquotes) * 2 488 + 10); 489 sprintf (cmd, "%s %s %s%s%s", preprocessor, preprocargs, 490 fnquotes, filename, fnquotes); 491 492 cpp_pipe = open_input_stream (cmd); 493 } 494 else 495 { 496 char *dash, *slash, *cp; 497 498 preprocessor = DEFAULT_PREPROCESSOR; 499 500 cmd = xmalloc (strlen (program_name) 501 + strlen (preprocessor) 502 + strlen (preprocargs) 503 + strlen (filename) 504 + strlen (fnquotes) * 2 505#ifdef HAVE_EXECUTABLE_SUFFIX 506 + strlen (EXECUTABLE_SUFFIX) 507#endif 508 + 10); 509 510 511 dash = slash = 0; 512 for (cp = program_name; *cp; cp++) 513 { 514 if (*cp == '-') 515 dash = cp; 516 if ( 517#if defined (__DJGPP__) || defined (__CYGWIN__) || defined(_WIN32) 518 *cp == ':' || *cp == '\\' || 519#endif 520 *cp == '/') 521 { 522 slash = cp; 523 dash = 0; 524 } 525 } 526 527 cpp_pipe = 0; 528 529 if (dash) 530 { 531 /* First, try looking for a prefixed gcc in the windres 532 directory, with the same prefix as windres */ 533 534 cpp_pipe = look_for_default (cmd, program_name, dash - program_name + 1, 535 preprocargs, filename); 536 } 537 538 if (slash && ! cpp_pipe) 539 { 540 /* Next, try looking for a gcc in the same directory as 541 that windres */ 542 543 cpp_pipe = look_for_default (cmd, program_name, slash - program_name + 1, 544 preprocargs, filename); 545 } 546 547 if (! cpp_pipe) 548 { 549 /* Sigh, try the default */ 550 551 cpp_pipe = look_for_default (cmd, "", 0, preprocargs, filename); 552 } 553 554 } 555 556 free (cmd); 557 558 rc_filename = xstrdup (filename); 559 rc_lineno = 1; 560 if (language != -1) 561 rcparse_set_language (language); 562 yyparse (); 563 rcparse_discard_strings (); 564 565 close_input_stream (); 566 567 if (fontdirs != NULL) 568 define_fontdirs (); 569 570 free (rc_filename); 571 rc_filename = NULL; 572 573 return resources; 574} 575 576/* Close the input stream if it is open. */ 577 578static void 579close_input_stream (void) 580{ 581 if (istream_type == ISTREAM_FILE) 582 { 583 if (cpp_pipe != NULL) 584 fclose (cpp_pipe); 585 586 if (cpp_temp_file != NULL) 587 { 588 int errno_save = errno; 589 590 unlink (cpp_temp_file); 591 errno = errno_save; 592 free (cpp_temp_file); 593 } 594 } 595 else 596 { 597 if (cpp_pipe != NULL) 598 { 599 int err; 600 err = pclose (cpp_pipe); 601 /* We are reading from a pipe, therefore we don't 602 know if cpp failed or succeeded until pclose. */ 603 if (err != 0 || errno == ECHILD) 604 { 605 /* Since this is also run via xatexit, safeguard. */ 606 cpp_pipe = NULL; 607 cpp_temp_file = NULL; 608 fatal (_("preprocessing failed.")); 609 } 610 } 611 } 612 613 /* Since this is also run via xatexit, safeguard. */ 614 cpp_pipe = NULL; 615 cpp_temp_file = NULL; 616} 617 618/* Report an error while reading an rc file. */ 619 620void 621yyerror (const char *msg) 622{ 623 fatal ("%s:%d: %s", rc_filename, rc_lineno, msg); 624} 625 626/* Issue a warning while reading an rc file. */ 627 628void 629rcparse_warning (const char *msg) 630{ 631 fprintf (stderr, "%s:%d: %s\n", rc_filename, rc_lineno, msg); 632} 633 634/* Die if we get an unexpected end of file. */ 635 636static void 637unexpected_eof (const char *msg) 638{ 639 fatal (_("%s: unexpected EOF"), msg); 640} 641 642/* Read a 16 bit word from a file. The data is assumed to be little 643 endian. */ 644 645static int 646get_word (FILE *e, const char *msg) 647{ 648 int b1, b2; 649 650 b1 = getc (e); 651 b2 = getc (e); 652 if (feof (e)) 653 unexpected_eof (msg); 654 return ((b2 & 0xff) << 8) | (b1 & 0xff); 655} 656 657/* Read a 32 bit word from a file. The data is assumed to be little 658 endian. */ 659 660static unsigned long 661get_long (FILE *e, const char *msg) 662{ 663 int b1, b2, b3, b4; 664 665 b1 = getc (e); 666 b2 = getc (e); 667 b3 = getc (e); 668 b4 = getc (e); 669 if (feof (e)) 670 unexpected_eof (msg); 671 return (((((((b4 & 0xff) << 8) 672 | (b3 & 0xff)) << 8) 673 | (b2 & 0xff)) << 8) 674 | (b1 & 0xff)); 675} 676 677/* Read data from a file. This is a wrapper to do error checking. */ 678 679static void 680get_data (FILE *e, bfd_byte *p, rc_uint_type c, const char *msg) 681{ 682 rc_uint_type got; // $$$d 683 684 got = (rc_uint_type) fread (p, 1, c, e); 685 if (got == c) 686 return; 687 688 fatal (_("%s: read of %lu returned %lu"), 689 msg, (unsigned long) c, (unsigned long) got); 690} 691 692/* Define an accelerator resource. */ 693 694void 695define_accelerator (rc_res_id id, const rc_res_res_info *resinfo, 696 rc_accelerator *data) 697{ 698 rc_res_resource *r; 699 700 r = define_standard_resource (&resources, RT_ACCELERATOR, id, 701 resinfo->language, 0); 702 r->type = RES_TYPE_ACCELERATOR; 703 r->u.acc = data; 704 r->res_info = *resinfo; 705} 706 707/* Define a bitmap resource. Bitmap data is stored in a file. The 708 first 14 bytes of the file are a standard header, which is not 709 included in the resource data. */ 710 711#define BITMAP_SKIP (14) 712 713void 714define_bitmap (rc_res_id id, const rc_res_res_info *resinfo, 715 const char *filename) 716{ 717 FILE *e; 718 char *real_filename; 719 struct stat s; 720 bfd_byte *data; 721 rc_uint_type i; 722 rc_res_resource *r; 723 724 e = open_file_search (filename, FOPEN_RB, "bitmap file", &real_filename); 725 726 if (stat (real_filename, &s) < 0) 727 fatal (_("stat failed on bitmap file `%s': %s"), real_filename, 728 strerror (errno)); 729 730 data = (bfd_byte *) res_alloc (s.st_size - BITMAP_SKIP); 731 732 for (i = 0; i < BITMAP_SKIP; i++) 733 getc (e); 734 735 get_data (e, data, s.st_size - BITMAP_SKIP, real_filename); 736 737 fclose (e); 738 free (real_filename); 739 740 r = define_standard_resource (&resources, RT_BITMAP, id, 741 resinfo->language, 0); 742 743 r->type = RES_TYPE_BITMAP; 744 r->u.data.length = s.st_size - BITMAP_SKIP; 745 r->u.data.data = data; 746 r->res_info = *resinfo; 747} 748 749/* Define a cursor resource. A cursor file may contain a set of 750 bitmaps, each representing the same cursor at various different 751 resolutions. They each get written out with a different ID. The 752 real cursor resource is then a group resource which can be used to 753 select one of the actual cursors. */ 754 755void 756define_cursor (rc_res_id id, const rc_res_res_info *resinfo, 757 const char *filename) 758{ 759 FILE *e; 760 char *real_filename; 761 int type, count, i; 762 struct icondir *icondirs; 763 int first_cursor; 764 rc_res_resource *r; 765 rc_group_cursor *first, **pp; 766 767 e = open_file_search (filename, FOPEN_RB, "cursor file", &real_filename); 768 769 /* A cursor file is basically an icon file. The start of the file 770 is a three word structure. The first word is ignored. The 771 second word is the type of data. The third word is the number of 772 entries. */ 773 774 get_word (e, real_filename); 775 type = get_word (e, real_filename); 776 count = get_word (e, real_filename); 777 if (type != 2) 778 fatal (_("cursor file `%s' does not contain cursor data"), real_filename); 779 780 /* Read in the icon directory entries. */ 781 782 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs); 783 784 for (i = 0; i < count; i++) 785 { 786 icondirs[i].width = getc (e); 787 icondirs[i].height = getc (e); 788 icondirs[i].colorcount = getc (e); 789 getc (e); 790 icondirs[i].u.cursor.xhotspot = get_word (e, real_filename); 791 icondirs[i].u.cursor.yhotspot = get_word (e, real_filename); 792 icondirs[i].bytes = get_long (e, real_filename); 793 icondirs[i].offset = get_long (e, real_filename); 794 795 if (feof (e)) 796 unexpected_eof (real_filename); 797 } 798 799 /* Define each cursor as a unique resource. */ 800 801 first_cursor = cursors; 802 803 for (i = 0; i < count; i++) 804 { 805 bfd_byte *data; 806 rc_res_id name; 807 rc_cursor *c; 808 809 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0) 810 fatal (_("%s: fseek to %lu failed: %s"), real_filename, 811 icondirs[i].offset, strerror (errno)); 812 813 data = (bfd_byte *) res_alloc (icondirs[i].bytes); 814 815 get_data (e, data, icondirs[i].bytes, real_filename); 816 817 c = (rc_cursor *) res_alloc (sizeof (rc_cursor)); 818 c->xhotspot = icondirs[i].u.cursor.xhotspot; 819 c->yhotspot = icondirs[i].u.cursor.yhotspot; 820 c->length = icondirs[i].bytes; 821 c->data = data; 822 823 ++cursors; 824 825 name.named = 0; 826 name.u.id = cursors; 827 828 r = define_standard_resource (&resources, RT_CURSOR, name, 829 resinfo->language, 0); 830 r->type = RES_TYPE_CURSOR; 831 r->u.cursor = c; 832 r->res_info = *resinfo; 833 } 834 835 fclose (e); 836 free (real_filename); 837 838 /* Define a cursor group resource. */ 839 840 first = NULL; 841 pp = &first; 842 for (i = 0; i < count; i++) 843 { 844 rc_group_cursor *cg; 845 846 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor)); 847 cg->next = NULL; 848 cg->width = icondirs[i].width; 849 cg->height = 2 * icondirs[i].height; 850 851 /* FIXME: What should these be set to? */ 852 cg->planes = 1; 853 cg->bits = 1; 854 855 cg->bytes = icondirs[i].bytes + 4; 856 cg->index = first_cursor + i + 1; 857 858 *pp = cg; 859 pp = &(*pp)->next; 860 } 861 862 free (icondirs); 863 864 r = define_standard_resource (&resources, RT_GROUP_CURSOR, id, 865 resinfo->language, 0); 866 r->type = RES_TYPE_GROUP_CURSOR; 867 r->u.group_cursor = first; 868 r->res_info = *resinfo; 869} 870 871/* Define a dialog resource. */ 872 873void 874define_dialog (rc_res_id id, const rc_res_res_info *resinfo, 875 const rc_dialog *dialog) 876{ 877 rc_dialog *copy; 878 rc_res_resource *r; 879 880 copy = (rc_dialog *) res_alloc (sizeof *copy); 881 *copy = *dialog; 882 883 r = define_standard_resource (&resources, RT_DIALOG, id, 884 resinfo->language, 0); 885 r->type = RES_TYPE_DIALOG; 886 r->u.dialog = copy; 887 r->res_info = *resinfo; 888} 889 890/* Define a dialog control. This does not define a resource, but 891 merely allocates and fills in a structure. */ 892 893rc_dialog_control * 894define_control (const rc_res_id iid, rc_uint_type id, rc_uint_type x, 895 rc_uint_type y, rc_uint_type width, rc_uint_type height, 896 const rc_res_id class, rc_uint_type style, 897 rc_uint_type exstyle) 898{ 899 rc_dialog_control *n; 900 901 n = (rc_dialog_control *) res_alloc (sizeof (rc_dialog_control)); 902 n->next = NULL; 903 n->id = id; 904 n->style = style; 905 n->exstyle = exstyle; 906 n->x = x; 907 n->y = y; 908 n->width = width; 909 n->height = height; 910 n->class = class; 911 n->text = iid; 912 n->data = NULL; 913 n->help = 0; 914 915 return n; 916} 917 918rc_dialog_control * 919define_icon_control (rc_res_id iid, rc_uint_type id, rc_uint_type x, 920 rc_uint_type y, rc_uint_type style, 921 rc_uint_type exstyle, rc_uint_type help, 922 rc_rcdata_item *data, rc_dialog_ex *ex) 923{ 924 rc_dialog_control *n; 925 rc_res_id tid; 926 rc_res_id cid; 927 928 if (style == 0) 929 style = SS_ICON | WS_CHILD | WS_VISIBLE; 930 res_string_to_id (&tid, ""); 931 cid.named = 0; 932 cid.u.id = CTL_STATIC; 933 n = define_control (tid, id, x, y, 0, 0, cid, style, exstyle); 934 n->text = iid; 935 if (help && ! ex) 936 rcparse_warning (_("help ID requires DIALOGEX")); 937 if (data && ! ex) 938 rcparse_warning (_("control data requires DIALOGEX")); 939 n->help = help; 940 n->data = data; 941 942 return n; 943} 944 945/* Define a font resource. */ 946 947void 948define_font (rc_res_id id, const rc_res_res_info *resinfo, 949 const char *filename) 950{ 951 FILE *e; 952 char *real_filename; 953 struct stat s; 954 bfd_byte *data; 955 rc_res_resource *r; 956 long offset; 957 long fontdatalength; 958 bfd_byte *fontdata; 959 rc_fontdir *fd; 960 const char *device, *face; 961 rc_fontdir **pp; 962 963 e = open_file_search (filename, FOPEN_RB, "font file", &real_filename); 964 965 if (stat (real_filename, &s) < 0) 966 fatal (_("stat failed on font file `%s': %s"), real_filename, 967 strerror (errno)); 968 969 data = (bfd_byte *) res_alloc (s.st_size); 970 971 get_data (e, data, s.st_size, real_filename); 972 973 fclose (e); 974 free (real_filename); 975 976 r = define_standard_resource (&resources, RT_FONT, id, 977 resinfo->language, 0); 978 979 r->type = RES_TYPE_FONT; 980 r->u.data.length = s.st_size; 981 r->u.data.data = data; 982 r->res_info = *resinfo; 983 984 /* For each font resource, we must add an entry in the FONTDIR 985 resource. The FONTDIR resource includes some strings in the font 986 file. To find them, we have to do some magic on the data we have 987 read. */ 988 989 offset = ((((((data[47] << 8) 990 | data[46]) << 8) 991 | data[45]) << 8) 992 | data[44]); 993 if (offset > 0 && offset < s.st_size) 994 device = (char *) data + offset; 995 else 996 device = ""; 997 998 offset = ((((((data[51] << 8) 999 | data[50]) << 8) 1000 | data[49]) << 8) 1001 | data[48]); 1002 if (offset > 0 && offset < s.st_size) 1003 face = (char *) data + offset; 1004 else 1005 face = ""; 1006 1007 ++fonts; 1008 1009 fontdatalength = 58 + strlen (device) + strlen (face); 1010 fontdata = (bfd_byte *) res_alloc (fontdatalength); 1011 memcpy (fontdata, data, 56); 1012 strcpy ((char *) fontdata + 56, device); 1013 strcpy ((char *) fontdata + 57 + strlen (device), face); 1014 1015 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir)); 1016 fd->next = NULL; 1017 fd->index = fonts; 1018 fd->length = fontdatalength; 1019 fd->data = fontdata; 1020 1021 for (pp = &fontdirs; *pp != NULL; pp = &(*pp)->next) 1022 ; 1023 *pp = fd; 1024 1025 /* For the single fontdirs resource, we always use the resource 1026 information of the last font. I don't know what else to do. */ 1027 fontdirs_resinfo = *resinfo; 1028} 1029 1030static void 1031define_font_rcdata (rc_res_id id,const rc_res_res_info *resinfo, 1032 rc_rcdata_item *data) 1033{ 1034 rc_res_resource *r; 1035 rc_uint_type len_data; 1036 bfd_byte *pb_data; 1037 1038 r = define_standard_resource (&resources, RT_FONT, id, 1039 resinfo->language, 0); 1040 1041 pb_data = rcdata_render_as_buffer (data, &len_data); 1042 1043 r->type = RES_TYPE_FONT; 1044 r->u.data.length = len_data; 1045 r->u.data.data = pb_data; 1046 r->res_info = *resinfo; 1047} 1048 1049/* Define the fontdirs resource. This is called after the entire rc 1050 file has been parsed, if any font resources were seen. */ 1051 1052static void 1053define_fontdirs (void) 1054{ 1055 rc_res_resource *r; 1056 rc_res_id id; 1057 1058 id.named = 0; 1059 id.u.id = 1; 1060 1061 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0); 1062 1063 r->type = RES_TYPE_FONTDIR; 1064 r->u.fontdir = fontdirs; 1065 r->res_info = fontdirs_resinfo; 1066} 1067 1068static bfd_byte * 1069rcdata_render_as_buffer (const rc_rcdata_item *data, rc_uint_type *plen) 1070{ 1071 const rc_rcdata_item *d; 1072 bfd_byte *ret = NULL, *pret; 1073 rc_uint_type len = 0; 1074 1075 for (d = data; d != NULL; d = d->next) 1076 len += rcdata_copy (d, NULL); 1077 if (len != 0) 1078 { 1079 ret = pret = (bfd_byte *) res_alloc (len); 1080 for (d = data; d != NULL; d = d->next) 1081 pret += rcdata_copy (d, pret); 1082 } 1083 if (plen) 1084 *plen = len; 1085 return ret; 1086} 1087 1088static void 1089define_fontdir_rcdata (rc_res_id id,const rc_res_res_info *resinfo, 1090 rc_rcdata_item *data) 1091{ 1092 rc_res_resource *r; 1093 rc_fontdir *fd, *fd_first, *fd_cur; 1094 rc_uint_type len_data; 1095 bfd_byte *pb_data; 1096 rc_uint_type c; 1097 1098 fd_cur = fd_first = NULL; 1099 r = define_standard_resource (&resources, RT_FONTDIR, id, 0x409, 0); 1100 1101 pb_data = rcdata_render_as_buffer (data, &len_data); 1102 1103 if (pb_data) 1104 { 1105 rc_uint_type off = 2; 1106 c = windres_get_16 (&wrtarget, pb_data, len_data); 1107 for (; c > 0; c--) 1108 { 1109 size_t len; 1110 rc_uint_type safe_pos = off; 1111 const struct bin_fontdir_item *bfi; 1112 1113 bfi = (const struct bin_fontdir_item *) pb_data + off; 1114 fd = (rc_fontdir *) res_alloc (sizeof (rc_fontdir)); 1115 fd->index = windres_get_16 (&wrtarget, bfi->index, len_data - off); 1116 fd->data = pb_data + off; 1117 off += 56; 1118 len = strlen ((char *) bfi->device_name) + 1; 1119 off += (rc_uint_type) len; 1120 off += (rc_uint_type) strlen ((char *) bfi->device_name + len) + 1; 1121 fd->length = (off - safe_pos); 1122 fd->next = NULL; 1123 if (fd_first == NULL) 1124 fd_first = fd; 1125 else 1126 fd_cur->next = fd; 1127 fd_cur = fd; 1128 } 1129 } 1130 r->type = RES_TYPE_FONTDIR; 1131 r->u.fontdir = fd_first; 1132 r->res_info = *resinfo; 1133} 1134 1135static void define_messagetable_rcdata (rc_res_id id, const rc_res_res_info *resinfo, 1136 rc_rcdata_item *data) 1137{ 1138 rc_res_resource *r; 1139 rc_uint_type len_data; 1140 bfd_byte *pb_data; 1141 1142 r = define_standard_resource (&resources, RT_MESSAGETABLE, id, resinfo->language, 0); 1143 1144 pb_data = rcdata_render_as_buffer (data, &len_data); 1145 r->type = RES_TYPE_MESSAGETABLE; 1146 r->u.data.length = len_data; 1147 r->u.data.data = pb_data; 1148 r->res_info = *resinfo; 1149} 1150 1151/* Define an icon resource. An icon file may contain a set of 1152 bitmaps, each representing the same icon at various different 1153 resolutions. They each get written out with a different ID. The 1154 real icon resource is then a group resource which can be used to 1155 select one of the actual icon bitmaps. */ 1156 1157void 1158define_icon (rc_res_id id, const rc_res_res_info *resinfo, 1159 const char *filename) 1160{ 1161 FILE *e; 1162 char *real_filename; 1163 int type, count, i; 1164 struct icondir *icondirs; 1165 int first_icon; 1166 rc_res_resource *r; 1167 rc_group_icon *first, **pp; 1168 1169 e = open_file_search (filename, FOPEN_RB, "icon file", &real_filename); 1170 1171 /* The start of an icon file is a three word structure. The first 1172 word is ignored. The second word is the type of data. The third 1173 word is the number of entries. */ 1174 1175 get_word (e, real_filename); 1176 type = get_word (e, real_filename); 1177 count = get_word (e, real_filename); 1178 if (type != 1) 1179 fatal (_("icon file `%s' does not contain icon data"), real_filename); 1180 1181 /* Read in the icon directory entries. */ 1182 1183 icondirs = (struct icondir *) xmalloc (count * sizeof *icondirs); 1184 1185 for (i = 0; i < count; i++) 1186 { 1187 icondirs[i].width = getc (e); 1188 icondirs[i].height = getc (e); 1189 icondirs[i].colorcount = getc (e); 1190 getc (e); 1191 icondirs[i].u.icon.planes = get_word (e, real_filename); 1192 icondirs[i].u.icon.bits = get_word (e, real_filename); 1193 icondirs[i].bytes = get_long (e, real_filename); 1194 icondirs[i].offset = get_long (e, real_filename); 1195 1196 if (feof (e)) 1197 unexpected_eof (real_filename); 1198 } 1199 1200 /* Define each icon as a unique resource. */ 1201 1202 first_icon = icons; 1203 1204 for (i = 0; i < count; i++) 1205 { 1206 bfd_byte *data; 1207 rc_res_id name; 1208 1209 if (fseek (e, icondirs[i].offset, SEEK_SET) != 0) 1210 fatal (_("%s: fseek to %lu failed: %s"), real_filename, 1211 icondirs[i].offset, strerror (errno)); 1212 1213 data = (bfd_byte *) res_alloc (icondirs[i].bytes); 1214 1215 get_data (e, data, icondirs[i].bytes, real_filename); 1216 1217 ++icons; 1218 1219 name.named = 0; 1220 name.u.id = icons; 1221 1222 r = define_standard_resource (&resources, RT_ICON, name, 1223 resinfo->language, 0); 1224 r->type = RES_TYPE_ICON; 1225 r->u.data.length = icondirs[i].bytes; 1226 r->u.data.data = data; 1227 r->res_info = *resinfo; 1228 } 1229 1230 fclose (e); 1231 free (real_filename); 1232 1233 /* Define an icon group resource. */ 1234 1235 first = NULL; 1236 pp = &first; 1237 for (i = 0; i < count; i++) 1238 { 1239 rc_group_icon *cg; 1240 1241 /* For some reason, at least in some files the planes and bits 1242 are zero. We instead set them from the color. This is 1243 copied from rcl. */ 1244 1245 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon)); 1246 cg->next = NULL; 1247 cg->width = icondirs[i].width; 1248 cg->height = icondirs[i].height; 1249 cg->colors = icondirs[i].colorcount; 1250 1251 if (icondirs[i].u.icon.planes) 1252 cg->planes = icondirs[i].u.icon.planes; 1253 else 1254 cg->planes = 1; 1255 1256 if (icondirs[i].u.icon.bits) 1257 cg->bits = icondirs[i].u.icon.bits; 1258 else 1259 { 1260 cg->bits = 0; 1261 1262 while ((1L << cg->bits) < cg->colors) 1263 ++cg->bits; 1264 } 1265 1266 cg->bytes = icondirs[i].bytes; 1267 cg->index = first_icon + i + 1; 1268 1269 *pp = cg; 1270 pp = &(*pp)->next; 1271 } 1272 1273 free (icondirs); 1274 1275 r = define_standard_resource (&resources, RT_GROUP_ICON, id, 1276 resinfo->language, 0); 1277 r->type = RES_TYPE_GROUP_ICON; 1278 r->u.group_icon = first; 1279 r->res_info = *resinfo; 1280} 1281 1282static void 1283define_group_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo, 1284 rc_rcdata_item *data) 1285{ 1286 rc_res_resource *r; 1287 rc_group_icon *cg, *first, *cur; 1288 rc_uint_type len_data; 1289 bfd_byte *pb_data; 1290 1291 pb_data = rcdata_render_as_buffer (data, &len_data); 1292 1293 cur = NULL; 1294 first = NULL; 1295 1296 while (len_data >= 6) 1297 { 1298 int c, i; 1299 unsigned short type; 1300 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2); 1301 if (type != 1) 1302 fatal (_("unexpected group icon type %d"), type); 1303 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4); 1304 len_data -= 6; 1305 pb_data += 6; 1306 1307 for (i = 0; i < c; i++) 1308 { 1309 if (len_data < 14) 1310 fatal ("too small group icon rcdata"); 1311 cg = (rc_group_icon *) res_alloc (sizeof (rc_group_icon)); 1312 cg->next = NULL; 1313 cg->width = pb_data[0]; 1314 cg->height = pb_data[1]; 1315 cg->colors = pb_data[2]; 1316 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4); 1317 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6); 1318 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8); 1319 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12); 1320 if (! first) 1321 first = cg; 1322 else 1323 cur->next = cg; 1324 cur = cg; 1325 pb_data += 14; 1326 len_data -= 14; 1327 } 1328 } 1329 r = define_standard_resource (&resources, RT_GROUP_ICON, id, 1330 resinfo->language, 0); 1331 r->type = RES_TYPE_GROUP_ICON; 1332 r->u.group_icon = first; 1333 r->res_info = *resinfo; 1334} 1335 1336static void 1337define_group_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo, 1338 rc_rcdata_item *data) 1339{ 1340 rc_res_resource *r; 1341 rc_group_cursor *cg, *first, *cur; 1342 rc_uint_type len_data; 1343 bfd_byte *pb_data; 1344 1345 pb_data = rcdata_render_as_buffer (data, &len_data); 1346 1347 first = cur = NULL; 1348 1349 while (len_data >= 6) 1350 { 1351 int c, i; 1352 unsigned short type; 1353 type = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2); 1354 if (type != 2) 1355 fatal (_("unexpected group cursor type %d"), type); 1356 c = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4); 1357 len_data -= 6; 1358 pb_data += 6; 1359 1360 for (i = 0; i < c; i++) 1361 { 1362 if (len_data < 14) 1363 fatal ("too small group icon rcdata"); 1364 cg = (rc_group_cursor *) res_alloc (sizeof (rc_group_cursor)); 1365 cg->next = NULL; 1366 cg->width = windres_get_16 (&wrtarget, pb_data, len_data); 1367 cg->height = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2); 1368 cg->planes = windres_get_16 (&wrtarget, pb_data + 4, len_data - 4); 1369 cg->bits = windres_get_16 (&wrtarget, pb_data + 6, len_data - 6); 1370 cg->bytes = windres_get_32 (&wrtarget, pb_data + 8, len_data - 8); 1371 cg->index = windres_get_16 (&wrtarget, pb_data + 12, len_data - 12); 1372 if (! first) 1373 first = cg; 1374 else 1375 cur->next = cg; 1376 cur = cg; 1377 pb_data += 14; 1378 len_data -= 14; 1379 } 1380 } 1381 1382 r = define_standard_resource (&resources, RT_GROUP_ICON, id, 1383 resinfo->language, 0); 1384 r->type = RES_TYPE_GROUP_CURSOR; 1385 r->u.group_cursor = first; 1386 r->res_info = *resinfo; 1387} 1388 1389static void 1390define_cursor_rcdata (rc_res_id id, const rc_res_res_info *resinfo, 1391 rc_rcdata_item *data) 1392{ 1393 rc_cursor *c; 1394 rc_res_resource *r; 1395 rc_uint_type len_data; 1396 bfd_byte *pb_data; 1397 1398 pb_data = rcdata_render_as_buffer (data, &len_data); 1399 1400 c = (rc_cursor *) res_alloc (sizeof (rc_cursor)); 1401 c->xhotspot = windres_get_16 (&wrtarget, pb_data, len_data); 1402 c->yhotspot = windres_get_16 (&wrtarget, pb_data + 2, len_data - 2); 1403 c->length = len_data - BIN_CURSOR_SIZE; 1404 c->data = (const bfd_byte *) (data + BIN_CURSOR_SIZE); 1405 1406 r = define_standard_resource (&resources, RT_CURSOR, id, resinfo->language, 0); 1407 r->type = RES_TYPE_CURSOR; 1408 r->u.cursor = c; 1409 r->res_info = *resinfo; 1410} 1411 1412static void 1413define_bitmap_rcdata (rc_res_id id, const rc_res_res_info *resinfo, 1414 rc_rcdata_item *data) 1415{ 1416 rc_res_resource *r; 1417 rc_uint_type len_data; 1418 bfd_byte *pb_data; 1419 1420 pb_data = rcdata_render_as_buffer (data, &len_data); 1421 1422 r = define_standard_resource (&resources, RT_BITMAP, id, resinfo->language, 0); 1423 r->type = RES_TYPE_BITMAP; 1424 r->u.data.length = len_data; 1425 r->u.data.data = pb_data; 1426 r->res_info = *resinfo; 1427} 1428 1429static void 1430define_icon_rcdata (rc_res_id id, const rc_res_res_info *resinfo, 1431 rc_rcdata_item *data) 1432{ 1433 rc_res_resource *r; 1434 rc_uint_type len_data; 1435 bfd_byte *pb_data; 1436 1437 pb_data = rcdata_render_as_buffer (data, &len_data); 1438 1439 r = define_standard_resource (&resources, RT_ICON, id, resinfo->language, 0); 1440 r->type = RES_TYPE_ICON; 1441 r->u.data.length = len_data; 1442 r->u.data.data = pb_data; 1443 r->res_info = *resinfo; 1444} 1445 1446/* Define a menu resource. */ 1447 1448void 1449define_menu (rc_res_id id, const rc_res_res_info *resinfo, 1450 rc_menuitem *menuitems) 1451{ 1452 rc_menu *m; 1453 rc_res_resource *r; 1454 1455 m = (rc_menu *) res_alloc (sizeof (rc_menu)); 1456 m->items = menuitems; 1457 m->help = 0; 1458 1459 r = define_standard_resource (&resources, RT_MENU, id, resinfo->language, 0); 1460 r->type = RES_TYPE_MENU; 1461 r->u.menu = m; 1462 r->res_info = *resinfo; 1463} 1464 1465/* Define a menu item. This does not define a resource, but merely 1466 allocates and fills in a structure. */ 1467 1468rc_menuitem * 1469define_menuitem (const unichar *text, rc_uint_type menuid, rc_uint_type type, 1470 rc_uint_type state, rc_uint_type help, 1471 rc_menuitem *menuitems) 1472{ 1473 rc_menuitem *mi; 1474 1475 mi = (rc_menuitem *) res_alloc (sizeof (rc_menuitem)); 1476 mi->next = NULL; 1477 mi->type = type; 1478 mi->state = state; 1479 mi->id = menuid; 1480 mi->text = unichar_dup (text); 1481 mi->help = help; 1482 mi->popup = menuitems; 1483 return mi; 1484} 1485 1486/* Define a messagetable resource. */ 1487 1488void 1489define_messagetable (rc_res_id id, const rc_res_res_info *resinfo, 1490 const char *filename) 1491{ 1492 FILE *e; 1493 char *real_filename; 1494 struct stat s; 1495 bfd_byte *data; 1496 rc_res_resource *r; 1497 1498 e = open_file_search (filename, FOPEN_RB, "messagetable file", 1499 &real_filename); 1500 1501 if (stat (real_filename, &s) < 0) 1502 fatal (_("stat failed on bitmap file `%s': %s"), real_filename, 1503 strerror (errno)); 1504 1505 data = (bfd_byte *) res_alloc (s.st_size); 1506 1507 get_data (e, data, s.st_size, real_filename); 1508 1509 fclose (e); 1510 free (real_filename); 1511 1512 r = define_standard_resource (&resources, RT_MESSAGETABLE, id, 1513 resinfo->language, 0); 1514 1515 r->type = RES_TYPE_MESSAGETABLE; 1516 r->u.data.length = s.st_size; 1517 r->u.data.data = data; 1518 r->res_info = *resinfo; 1519} 1520 1521/* Define an rcdata resource. */ 1522 1523void 1524define_rcdata (rc_res_id id, const rc_res_res_info *resinfo, 1525 rc_rcdata_item *data) 1526{ 1527 rc_res_resource *r; 1528 1529 r = define_standard_resource (&resources, RT_RCDATA, id, 1530 resinfo->language, 0); 1531 r->type = RES_TYPE_RCDATA; 1532 r->u.rcdata = data; 1533 r->res_info = *resinfo; 1534} 1535 1536/* Create an rcdata item holding a string. */ 1537 1538rc_rcdata_item * 1539define_rcdata_string (const char *string, rc_uint_type len) 1540{ 1541 rc_rcdata_item *ri; 1542 char *s; 1543 1544 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item)); 1545 ri->next = NULL; 1546 ri->type = RCDATA_STRING; 1547 ri->u.string.length = len; 1548 s = (char *) res_alloc (len); 1549 memcpy (s, string, len); 1550 ri->u.string.s = s; 1551 1552 return ri; 1553} 1554 1555/* Create an rcdata item holding a unicode string. */ 1556 1557rc_rcdata_item * 1558define_rcdata_unistring (const unichar *string, rc_uint_type len) 1559{ 1560 rc_rcdata_item *ri; 1561 unichar *s; 1562 1563 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item)); 1564 ri->next = NULL; 1565 ri->type = RCDATA_WSTRING; 1566 ri->u.wstring.length = len; 1567 s = (unichar *) res_alloc (len * sizeof (unichar)); 1568 memcpy (s, string, len * sizeof (unichar)); 1569 ri->u.wstring.w = s; 1570 1571 return ri; 1572} 1573 1574/* Create an rcdata item holding a number. */ 1575 1576rc_rcdata_item * 1577define_rcdata_number (rc_uint_type val, int dword) 1578{ 1579 rc_rcdata_item *ri; 1580 1581 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item)); 1582 ri->next = NULL; 1583 ri->type = dword ? RCDATA_DWORD : RCDATA_WORD; 1584 ri->u.word = val; 1585 1586 return ri; 1587} 1588 1589/* Define a stringtable resource. This is called for each string 1590 which appears in a STRINGTABLE statement. */ 1591 1592void 1593define_stringtable (const rc_res_res_info *resinfo, 1594 rc_uint_type stringid, const unichar *string) 1595{ 1596 rc_res_id id; 1597 rc_res_resource *r; 1598 1599 id.named = 0; 1600 id.u.id = (stringid >> 4) + 1; 1601 r = define_standard_resource (&resources, RT_STRING, id, 1602 resinfo->language, 1); 1603 1604 if (r->type == RES_TYPE_UNINITIALIZED) 1605 { 1606 int i; 1607 1608 r->type = RES_TYPE_STRINGTABLE; 1609 r->u.stringtable = ((rc_stringtable *) 1610 res_alloc (sizeof (rc_stringtable))); 1611 for (i = 0; i < 16; i++) 1612 { 1613 r->u.stringtable->strings[i].length = 0; 1614 r->u.stringtable->strings[i].string = NULL; 1615 } 1616 1617 r->res_info = *resinfo; 1618 } 1619 1620 r->u.stringtable->strings[stringid & 0xf].length = unichar_len (string); 1621 r->u.stringtable->strings[stringid & 0xf].string = unichar_dup (string); 1622} 1623 1624void 1625define_toolbar (rc_res_id id, rc_res_res_info *resinfo, rc_uint_type width, rc_uint_type height, 1626 rc_toolbar_item *items) 1627{ 1628 rc_toolbar *t; 1629 rc_res_resource *r; 1630 1631 t = (rc_toolbar *) res_alloc (sizeof (rc_toolbar)); 1632 t->button_width = width; 1633 t->button_height = height; 1634 t->nitems = 0; 1635 t->items = items; 1636 while (items != NULL) 1637 { 1638 t->nitems+=1; 1639 items = items->next; 1640 } 1641 r = define_standard_resource (&resources, RT_TOOLBAR, id, resinfo->language, 0); 1642 r->type = RES_TYPE_TOOLBAR; 1643 r->u.toolbar = t; 1644 r->res_info = *resinfo; 1645} 1646 1647/* Define a user data resource where the data is in the rc file. */ 1648 1649void 1650define_user_data (rc_res_id id, rc_res_id type, 1651 const rc_res_res_info *resinfo, 1652 rc_rcdata_item *data) 1653{ 1654 rc_res_id ids[3]; 1655 rc_res_resource *r; 1656 bfd_byte *pb_data; 1657 rc_uint_type len_data; 1658 1659 /* We have to check if the binary data is parsed specially. */ 1660 if (type.named == 0) 1661 { 1662 switch (type.u.id) 1663 { 1664 case RT_FONTDIR: 1665 define_fontdir_rcdata (id, resinfo, data); 1666 return; 1667 case RT_FONT: 1668 define_font_rcdata (id, resinfo, data); 1669 return; 1670 case RT_ICON: 1671 define_icon_rcdata (id, resinfo, data); 1672 return; 1673 case RT_BITMAP: 1674 define_bitmap_rcdata (id, resinfo, data); 1675 return; 1676 case RT_CURSOR: 1677 define_cursor_rcdata (id, resinfo, data); 1678 return; 1679 case RT_GROUP_ICON: 1680 define_group_icon_rcdata (id, resinfo, data); 1681 return; 1682 case RT_GROUP_CURSOR: 1683 define_group_cursor_rcdata (id, resinfo, data); 1684 return; 1685 case RT_MESSAGETABLE: 1686 define_messagetable_rcdata (id, resinfo, data); 1687 return; 1688 default: 1689 /* Treat as normal user-data. */ 1690 break; 1691 } 1692 } 1693 ids[0] = type; 1694 ids[1] = id; 1695 ids[2].named = 0; 1696 ids[2].u.id = resinfo->language; 1697 1698 r = define_resource (& resources, 3, ids, 0); 1699 r->type = RES_TYPE_USERDATA; 1700 r->u.userdata = ((rc_rcdata_item *) 1701 res_alloc (sizeof (rc_rcdata_item))); 1702 r->u.userdata->next = NULL; 1703 r->u.userdata->type = RCDATA_BUFFER; 1704 pb_data = rcdata_render_as_buffer (data, &len_data); 1705 r->u.userdata->u.buffer.length = len_data; 1706 r->u.userdata->u.buffer.data = pb_data; 1707 r->res_info = *resinfo; 1708} 1709 1710void 1711define_rcdata_file (rc_res_id id, const rc_res_res_info *resinfo, 1712 const char *filename) 1713{ 1714 rc_rcdata_item *ri; 1715 FILE *e; 1716 char *real_filename; 1717 struct stat s; 1718 bfd_byte *data; 1719 1720 e = open_file_search (filename, FOPEN_RB, "file", &real_filename); 1721 1722 1723 if (stat (real_filename, &s) < 0) 1724 fatal (_("stat failed on file `%s': %s"), real_filename, 1725 strerror (errno)); 1726 1727 data = (bfd_byte *) res_alloc (s.st_size); 1728 1729 get_data (e, data, s.st_size, real_filename); 1730 1731 fclose (e); 1732 free (real_filename); 1733 1734 ri = (rc_rcdata_item *) res_alloc (sizeof (rc_rcdata_item)); 1735 ri->next = NULL; 1736 ri->type = RCDATA_BUFFER; 1737 ri->u.buffer.length = s.st_size; 1738 ri->u.buffer.data = data; 1739 1740 define_rcdata (id, resinfo, ri); 1741} 1742 1743/* Define a user data resource where the data is in a file. */ 1744 1745void 1746define_user_file (rc_res_id id, rc_res_id type, 1747 const rc_res_res_info *resinfo, const char *filename) 1748{ 1749 FILE *e; 1750 char *real_filename; 1751 struct stat s; 1752 bfd_byte *data; 1753 rc_res_id ids[3]; 1754 rc_res_resource *r; 1755 1756 e = open_file_search (filename, FOPEN_RB, "file", &real_filename); 1757 1758 if (stat (real_filename, &s) < 0) 1759 fatal (_("stat failed on file `%s': %s"), real_filename, 1760 strerror (errno)); 1761 1762 data = (bfd_byte *) res_alloc (s.st_size); 1763 1764 get_data (e, data, s.st_size, real_filename); 1765 1766 fclose (e); 1767 free (real_filename); 1768 1769 ids[0] = type; 1770 ids[1] = id; 1771 ids[2].named = 0; 1772 ids[2].u.id = resinfo->language; 1773 1774 r = define_resource (&resources, 3, ids, 0); 1775 r->type = RES_TYPE_USERDATA; 1776 r->u.userdata = ((rc_rcdata_item *) 1777 res_alloc (sizeof (rc_rcdata_item))); 1778 r->u.userdata->next = NULL; 1779 r->u.userdata->type = RCDATA_BUFFER; 1780 r->u.userdata->u.buffer.length = s.st_size; 1781 r->u.userdata->u.buffer.data = data; 1782 r->res_info = *resinfo; 1783} 1784 1785/* Define a versioninfo resource. */ 1786 1787void 1788define_versioninfo (rc_res_id id, rc_uint_type language, 1789 rc_fixed_versioninfo *fixedverinfo, 1790 rc_ver_info *verinfo) 1791{ 1792 rc_res_resource *r; 1793 1794 r = define_standard_resource (&resources, RT_VERSION, id, language, 0); 1795 r->type = RES_TYPE_VERSIONINFO; 1796 r->u.versioninfo = ((rc_versioninfo *) 1797 res_alloc (sizeof (rc_versioninfo))); 1798 r->u.versioninfo->fixed = fixedverinfo; 1799 r->u.versioninfo->var = verinfo; 1800 r->res_info.language = language; 1801} 1802 1803/* Add string version info to a list of version information. */ 1804 1805rc_ver_info * 1806append_ver_stringfileinfo (rc_ver_info *verinfo, const char *language, 1807 rc_ver_stringinfo *strings) 1808{ 1809 rc_ver_info *vi, **pp; 1810 1811 vi = (rc_ver_info *) res_alloc (sizeof (rc_ver_info)); 1812 vi->next = NULL; 1813 vi->type = VERINFO_STRING; 1814 unicode_from_ascii ((rc_uint_type *) NULL, &vi->u.string.language, language); 1815 vi->u.string.strings = strings; 1816 1817 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next) 1818 ; 1819 *pp = vi; 1820 1821 return verinfo; 1822} 1823 1824/* Add variable version info to a list of version information. */ 1825 1826rc_ver_info * 1827append_ver_varfileinfo (rc_ver_info *verinfo, const unichar *key, 1828 rc_ver_varinfo *var) 1829{ 1830 rc_ver_info *vi, **pp; 1831 1832 vi = (rc_ver_info *) res_alloc (sizeof *vi); 1833 vi->next = NULL; 1834 vi->type = VERINFO_VAR; 1835 vi->u.var.key = unichar_dup (key); 1836 vi->u.var.var = var; 1837 1838 for (pp = &verinfo; *pp != NULL; pp = &(*pp)->next) 1839 ; 1840 *pp = vi; 1841 1842 return verinfo; 1843} 1844 1845/* Append version string information to a list. */ 1846 1847rc_ver_stringinfo * 1848append_verval (rc_ver_stringinfo *strings, const unichar *key, 1849 const unichar *value) 1850{ 1851 rc_ver_stringinfo *vs, **pp; 1852 1853 vs = (rc_ver_stringinfo *) res_alloc (sizeof (rc_ver_stringinfo)); 1854 vs->next = NULL; 1855 vs->key = unichar_dup (key); 1856 vs->value = unichar_dup (value); 1857 1858 for (pp = &strings; *pp != NULL; pp = &(*pp)->next) 1859 ; 1860 *pp = vs; 1861 1862 return strings; 1863} 1864 1865/* Append version variable information to a list. */ 1866 1867rc_ver_varinfo * 1868append_vertrans (rc_ver_varinfo *var, rc_uint_type language, 1869 rc_uint_type charset) 1870{ 1871 rc_ver_varinfo *vv, **pp; 1872 1873 vv = (rc_ver_varinfo *) res_alloc (sizeof (rc_ver_varinfo)); 1874 vv->next = NULL; 1875 vv->language = language; 1876 vv->charset = charset; 1877 1878 for (pp = &var; *pp != NULL; pp = &(*pp)->next) 1879 ; 1880 *pp = vv; 1881 1882 return var; 1883} 1884 1885/* Local functions used to write out an rc file. */ 1886 1887static void indent (FILE *, int); 1888static void write_rc_directory (FILE *, const rc_res_directory *, const rc_res_id *, 1889 const rc_res_id *, rc_uint_type *, int); 1890static void write_rc_subdir (FILE *, const rc_res_entry *, const rc_res_id *, 1891 const rc_res_id *, rc_uint_type *, int); 1892static void write_rc_resource (FILE *, const rc_res_id *, const rc_res_id *, 1893 const rc_res_resource *, rc_uint_type *); 1894static void write_rc_accelerators (FILE *, const rc_accelerator *); 1895static void write_rc_cursor (FILE *, const rc_cursor *); 1896static void write_rc_group_cursor (FILE *, const rc_group_cursor *); 1897static void write_rc_dialog (FILE *, const rc_dialog *); 1898static void write_rc_dialog_control (FILE *, const rc_dialog_control *); 1899static void write_rc_fontdir (FILE *, const rc_fontdir *); 1900static void write_rc_group_icon (FILE *, const rc_group_icon *); 1901static void write_rc_menu (FILE *, const rc_menu *, int); 1902static void write_rc_toolbar (FILE *, const rc_toolbar *); 1903static void write_rc_menuitems (FILE *, const rc_menuitem *, int, int); 1904static void write_rc_messagetable (FILE *, rc_uint_type , const bfd_byte *); 1905 1906static void write_rc_datablock (FILE *, rc_uint_type , const bfd_byte *, int, int, int); 1907static void write_rc_rcdata (FILE *, const rc_rcdata_item *, int); 1908static void write_rc_stringtable (FILE *, const rc_res_id *, const rc_stringtable *); 1909static void write_rc_versioninfo (FILE *, const rc_versioninfo *); 1910 1911/* Indent a given number of spaces. */ 1912 1913static void 1914indent (FILE *e, int c) 1915{ 1916 int i; 1917 1918 for (i = 0; i < c; i++) 1919 putc (' ', e); 1920} 1921 1922/* Dump the resources we have read in the format of an rc file. 1923 1924 Reasoned by the fact, that some resources need to be stored into file and 1925 refer to that file, we use the user-data model for that to express it binary 1926 without the need to store it somewhere externally. */ 1927 1928void 1929write_rc_file (const char *filename, const rc_res_directory *res_dir) 1930{ 1931 FILE *e; 1932 rc_uint_type language; 1933 1934 if (filename == NULL) 1935 e = stdout; 1936 else 1937 { 1938 e = fopen (filename, FOPEN_WT); 1939 if (e == NULL) 1940 fatal (_("can't open `%s' for output: %s"), filename, strerror (errno)); 1941 } 1942 1943 language = (rc_uint_type) ((bfd_signed_vma) -1); 1944 write_rc_directory (e, res_dir, (const rc_res_id *) NULL, 1945 (const rc_res_id *) NULL, &language, 1); 1946} 1947 1948/* Write out a directory. E is the file to write to. RD is the 1949 directory. TYPE is a pointer to the level 1 ID which serves as the 1950 resource type. NAME is a pointer to the level 2 ID which serves as 1951 an individual resource name. LANGUAGE is a pointer to the current 1952 language. LEVEL is the level in the tree. */ 1953 1954static void 1955write_rc_directory (FILE *e, const rc_res_directory *rd, 1956 const rc_res_id *type, const rc_res_id *name, 1957 rc_uint_type *language, int level) 1958{ 1959 const rc_res_entry *re; 1960 1961 /* Print out some COFF information that rc files can't represent. */ 1962 if (rd->time != 0 || rd->characteristics != 0 || rd->major != 0 || rd->minor != 0) 1963 { 1964 wr_printcomment (e, "COFF information not part of RC"); 1965 if (rd->time != 0) 1966 wr_printcomment (e, "Time stamp: %u", rd->time); 1967 if (rd->characteristics != 0) 1968 wr_printcomment (e, "Characteristics: %u", rd->characteristics); 1969 if (rd->major != 0 || rd->minor != 0) 1970 wr_printcomment (e, "Version major:%d minor:%d", rd->major, rd->minor); 1971 } 1972 1973 for (re = rd->entries; re != NULL; re = re->next) 1974 { 1975 switch (level) 1976 { 1977 case 1: 1978 /* If we're at level 1, the key of this resource is the 1979 type. This normally duplicates the information we have 1980 stored with the resource itself, but we need to remember 1981 the type if this is a user define resource type. */ 1982 type = &re->id; 1983 break; 1984 1985 case 2: 1986 /* If we're at level 2, the key of this resource is the name 1987 we are going to use in the rc printout. */ 1988 name = &re->id; 1989 break; 1990 1991 case 3: 1992 /* If we're at level 3, then this key represents a language. 1993 Use it to update the current language. */ 1994 if (! re->id.named 1995 && re->id.u.id != (unsigned long) (unsigned int) *language 1996 && (re->id.u.id & 0xffff) == re->id.u.id) 1997 { 1998 wr_print (e, "LANGUAGE %u, %u\n", 1999 re->id.u.id & ((1 << SUBLANG_SHIFT) - 1), 2000 (re->id.u.id >> SUBLANG_SHIFT) & 0xff); 2001 *language = re->id.u.id; 2002 } 2003 break; 2004 2005 default: 2006 break; 2007 } 2008 2009 if (re->subdir) 2010 write_rc_subdir (e, re, type, name, language, level); 2011 else 2012 { 2013 if (level == 3) 2014 { 2015 /* This is the normal case: the three levels are 2016 TYPE/NAME/LANGUAGE. NAME will have been set at level 2017 2, and represents the name to use. We probably just 2018 set LANGUAGE, and it will probably match what the 2019 resource itself records if anything. */ 2020 write_rc_resource (e, type, name, re->u.res, language); 2021 } 2022 else 2023 { 2024 wr_printcomment (e, "Resource at unexpected level %d", level); 2025 write_rc_resource (e, type, (rc_res_id *) NULL, re->u.res, 2026 language); 2027 } 2028 } 2029 } 2030 if (rd->entries == NULL) 2031 { 2032 wr_print_flush (e); 2033 } 2034} 2035 2036/* Write out a subdirectory entry. E is the file to write to. RE is 2037 the subdirectory entry. TYPE and NAME are pointers to higher level 2038 IDs, or NULL. LANGUAGE is a pointer to the current language. 2039 LEVEL is the level in the tree. */ 2040 2041static void 2042write_rc_subdir (FILE *e, const rc_res_entry *re, 2043 const rc_res_id *type, const rc_res_id *name, 2044 rc_uint_type *language, int level) 2045{ 2046 fprintf (e, "\n"); 2047 switch (level) 2048 { 2049 case 1: 2050 wr_printcomment (e, "Type: "); 2051 if (re->id.named) 2052 res_id_print (e, re->id, 1); 2053 else 2054 { 2055 const char *s; 2056 2057 switch (re->id.u.id) 2058 { 2059 case RT_CURSOR: s = "cursor"; break; 2060 case RT_BITMAP: s = "bitmap"; break; 2061 case RT_ICON: s = "icon"; break; 2062 case RT_MENU: s = "menu"; break; 2063 case RT_DIALOG: s = "dialog"; break; 2064 case RT_STRING: s = "stringtable"; break; 2065 case RT_FONTDIR: s = "fontdir"; break; 2066 case RT_FONT: s = "font"; break; 2067 case RT_ACCELERATOR: s = "accelerators"; break; 2068 case RT_RCDATA: s = "rcdata"; break; 2069 case RT_MESSAGETABLE: s = "messagetable"; break; 2070 case RT_GROUP_CURSOR: s = "group cursor"; break; 2071 case RT_GROUP_ICON: s = "group icon"; break; 2072 case RT_VERSION: s = "version"; break; 2073 case RT_DLGINCLUDE: s = "dlginclude"; break; 2074 case RT_PLUGPLAY: s = "plugplay"; break; 2075 case RT_VXD: s = "vxd"; break; 2076 case RT_ANICURSOR: s = "anicursor"; break; 2077 case RT_ANIICON: s = "aniicon"; break; 2078 case RT_TOOLBAR: s = "toolbar"; break; 2079 case RT_HTML: s = "html"; break; 2080 default: s = NULL; break; 2081 } 2082 2083 if (s != NULL) 2084 fprintf (e, "%s", s); 2085 else 2086 res_id_print (e, re->id, 1); 2087 } 2088 break; 2089 2090 case 2: 2091 wr_printcomment (e, "Name: "); 2092 res_id_print (e, re->id, 1); 2093 break; 2094 2095 case 3: 2096 wr_printcomment (e, "Language: "); 2097 res_id_print (e, re->id, 1); 2098 break; 2099 2100 default: 2101 wr_printcomment (e, "Level %d: ", level); 2102 res_id_print (e, re->id, 1); 2103 } 2104 2105 write_rc_directory (e, re->u.dir, type, name, language, level + 1); 2106} 2107 2108/* Write out a single resource. E is the file to write to. TYPE is a 2109 pointer to the type of the resource. NAME is a pointer to the name 2110 of the resource; it will be NULL if there is a level mismatch. RES 2111 is the resource data. LANGUAGE is a pointer to the current 2112 language. */ 2113 2114static void 2115write_rc_resource (FILE *e, const rc_res_id *type, 2116 const rc_res_id *name, const rc_res_resource *res, 2117 rc_uint_type *language) 2118{ 2119 const char *s; 2120 int rt; 2121 int menuex = 0; 2122 2123 switch (res->type) 2124 { 2125 default: 2126 abort (); 2127 2128 case RES_TYPE_ACCELERATOR: 2129 s = "ACCELERATORS"; 2130 rt = RT_ACCELERATOR; 2131 break; 2132 2133 case RES_TYPE_BITMAP: 2134 s = "2 /* RT_BITMAP */"; 2135 rt = RT_BITMAP; 2136 break; 2137 2138 case RES_TYPE_CURSOR: 2139 s = "1 /* RT_CURSOR */"; 2140 rt = RT_CURSOR; 2141 break; 2142 2143 case RES_TYPE_GROUP_CURSOR: 2144 s = "12 /* RT_GROUP_CURSOR */"; 2145 rt = RT_GROUP_CURSOR; 2146 break; 2147 2148 case RES_TYPE_DIALOG: 2149 if (extended_dialog (res->u.dialog)) 2150 s = "DIALOGEX"; 2151 else 2152 s = "DIALOG"; 2153 rt = RT_DIALOG; 2154 break; 2155 2156 case RES_TYPE_FONT: 2157 s = "8 /* RT_FONT */"; 2158 rt = RT_FONT; 2159 break; 2160 2161 case RES_TYPE_FONTDIR: 2162 s = "7 /* RT_FONTDIR */"; 2163 rt = RT_FONTDIR; 2164 break; 2165 2166 case RES_TYPE_ICON: 2167 s = "3 /* RT_ICON */"; 2168 rt = RT_ICON; 2169 break; 2170 2171 case RES_TYPE_GROUP_ICON: 2172 s = "14 /* RT_GROUP_ICON */"; 2173 rt = RT_GROUP_ICON; 2174 break; 2175 2176 case RES_TYPE_MENU: 2177 if (extended_menu (res->u.menu)) 2178 { 2179 s = "MENUEX"; 2180 menuex = 1; 2181 } 2182 else 2183 { 2184 s = "MENU"; 2185 menuex = 0; 2186 } 2187 rt = RT_MENU; 2188 break; 2189 2190 case RES_TYPE_MESSAGETABLE: 2191 s = "11 /* RT_MESSAGETABLE */"; 2192 rt = RT_MESSAGETABLE; 2193 break; 2194 2195 case RES_TYPE_RCDATA: 2196 s = "RCDATA"; 2197 rt = RT_RCDATA; 2198 break; 2199 2200 case RES_TYPE_STRINGTABLE: 2201 s = "STRINGTABLE"; 2202 rt = RT_STRING; 2203 break; 2204 2205 case RES_TYPE_USERDATA: 2206 s = NULL; 2207 rt = 0; 2208 break; 2209 2210 case RES_TYPE_VERSIONINFO: 2211 s = "VERSIONINFO"; 2212 rt = RT_VERSION; 2213 break; 2214 2215 case RES_TYPE_TOOLBAR: 2216 s = "TOOLBAR"; 2217 rt = RT_TOOLBAR; 2218 break; 2219 } 2220 2221 if (rt != 0 2222 && type != NULL 2223 && (type->named || type->u.id != (unsigned long) rt)) 2224 { 2225 wr_printcomment (e, "Unexpected resource type mismatch: "); 2226 res_id_print (e, *type, 1); 2227 fprintf (e, " != %d", rt); 2228 } 2229 2230 if (res->coff_info.codepage != 0) 2231 wr_printcomment (e, "Code page: %u", res->coff_info.codepage); 2232 if (res->coff_info.reserved != 0) 2233 wr_printcomment (e, "COFF reserved value: %u", res->coff_info.reserved); 2234 2235 wr_print (e, "\n"); 2236 if (rt == RT_STRING) 2237 ; 2238 else 2239 { 2240 if (name != NULL) 2241 res_id_print (e, *name, 1); 2242 else 2243 fprintf (e, "??Unknown-Name??"); 2244 fprintf (e, " "); 2245 } 2246 2247 if (s != NULL) 2248 fprintf (e, "%s", s); 2249 else if (type != NULL) 2250 { 2251 if (type->named == 0) 2252 { 2253#define PRINT_RT_NAME(NAME) case NAME: \ 2254 fprintf (e, "%u /* %s */", (unsigned int) NAME, #NAME); \ 2255 break 2256 2257 switch (type->u.id) 2258 { 2259 default: 2260 res_id_print (e, *type, 0); 2261 break; 2262 2263 PRINT_RT_NAME(RT_MANIFEST); 2264 PRINT_RT_NAME(RT_ANICURSOR); 2265 PRINT_RT_NAME(RT_ANIICON); 2266 PRINT_RT_NAME(RT_RCDATA); 2267 PRINT_RT_NAME(RT_ICON); 2268 PRINT_RT_NAME(RT_CURSOR); 2269 PRINT_RT_NAME(RT_BITMAP); 2270 PRINT_RT_NAME(RT_PLUGPLAY); 2271 PRINT_RT_NAME(RT_VXD); 2272 PRINT_RT_NAME(RT_FONT); 2273 PRINT_RT_NAME(RT_FONTDIR); 2274 PRINT_RT_NAME(RT_HTML); 2275 PRINT_RT_NAME(RT_MESSAGETABLE); 2276 PRINT_RT_NAME(RT_DLGINCLUDE); 2277 PRINT_RT_NAME(RT_DLGINIT); 2278 } 2279#undef PRINT_RT_NAME 2280 } 2281 else 2282 res_id_print (e, *type, 1); 2283 } 2284 else 2285 fprintf (e, "??Unknown-Type??"); 2286 2287 if (res->res_info.memflags != 0) 2288 { 2289 if ((res->res_info.memflags & MEMFLAG_MOVEABLE) != 0) 2290 fprintf (e, " MOVEABLE"); 2291 if ((res->res_info.memflags & MEMFLAG_PURE) != 0) 2292 fprintf (e, " PURE"); 2293 if ((res->res_info.memflags & MEMFLAG_PRELOAD) != 0) 2294 fprintf (e, " PRELOAD"); 2295 if ((res->res_info.memflags & MEMFLAG_DISCARDABLE) != 0) 2296 fprintf (e, " DISCARDABLE"); 2297 } 2298 2299 if (res->type == RES_TYPE_DIALOG) 2300 { 2301 fprintf (e, " %d, %d, %d, %d", 2302 (int) res->u.dialog->x, (int) res->u.dialog->y, 2303 (int) res->u.dialog->width, (int) res->u.dialog->height); 2304 if (res->u.dialog->ex != NULL 2305 && res->u.dialog->ex->help != 0) 2306 fprintf (e, ", %u", (unsigned int) res->u.dialog->ex->help); 2307 } 2308 else if (res->type == RES_TYPE_TOOLBAR) 2309 { 2310 fprintf (e, " %d, %d", (int) res->u.toolbar->button_width, 2311 (int) res->u.toolbar->button_height); 2312 } 2313 2314 fprintf (e, "\n"); 2315 2316 if ((res->res_info.language != 0 && res->res_info.language != *language) 2317 || res->res_info.characteristics != 0 2318 || res->res_info.version != 0) 2319 { 2320 int modifiers; 2321 2322 switch (res->type) 2323 { 2324 case RES_TYPE_ACCELERATOR: 2325 case RES_TYPE_DIALOG: 2326 case RES_TYPE_MENU: 2327 case RES_TYPE_RCDATA: 2328 case RES_TYPE_STRINGTABLE: 2329 modifiers = 1; 2330 break; 2331 2332 default: 2333 modifiers = 0; 2334 break; 2335 } 2336 2337 if (res->res_info.language != 0 && res->res_info.language != *language) 2338 fprintf (e, "%sLANGUAGE %d, %d\n", 2339 modifiers ? "// " : "", 2340 (int) res->res_info.language & ((1<<SUBLANG_SHIFT)-1), 2341 (int) (res->res_info.language >> SUBLANG_SHIFT) & 0xff); 2342 if (res->res_info.characteristics != 0) 2343 fprintf (e, "%sCHARACTERISTICS %u\n", 2344 modifiers ? "// " : "", 2345 (unsigned int) res->res_info.characteristics); 2346 if (res->res_info.version != 0) 2347 fprintf (e, "%sVERSION %u\n", 2348 modifiers ? "// " : "", 2349 (unsigned int) res->res_info.version); 2350 } 2351 2352 switch (res->type) 2353 { 2354 default: 2355 abort (); 2356 2357 case RES_TYPE_ACCELERATOR: 2358 write_rc_accelerators (e, res->u.acc); 2359 break; 2360 2361 case RES_TYPE_CURSOR: 2362 write_rc_cursor (e, res->u.cursor); 2363 break; 2364 2365 case RES_TYPE_GROUP_CURSOR: 2366 write_rc_group_cursor (e, res->u.group_cursor); 2367 break; 2368 2369 case RES_TYPE_DIALOG: 2370 write_rc_dialog (e, res->u.dialog); 2371 break; 2372 2373 case RES_TYPE_FONTDIR: 2374 write_rc_fontdir (e, res->u.fontdir); 2375 break; 2376 2377 case RES_TYPE_GROUP_ICON: 2378 write_rc_group_icon (e, res->u.group_icon); 2379 break; 2380 2381 case RES_TYPE_MENU: 2382 write_rc_menu (e, res->u.menu, menuex); 2383 break; 2384 2385 case RES_TYPE_RCDATA: 2386 write_rc_rcdata (e, res->u.rcdata, 0); 2387 break; 2388 2389 case RES_TYPE_STRINGTABLE: 2390 write_rc_stringtable (e, name, res->u.stringtable); 2391 break; 2392 2393 case RES_TYPE_USERDATA: 2394 write_rc_rcdata (e, res->u.userdata, 0); 2395 break; 2396 2397 case RES_TYPE_TOOLBAR: 2398 write_rc_toolbar (e, res->u.toolbar); 2399 break; 2400 2401 case RES_TYPE_VERSIONINFO: 2402 write_rc_versioninfo (e, res->u.versioninfo); 2403 break; 2404 2405 case RES_TYPE_BITMAP: 2406 case RES_TYPE_FONT: 2407 case RES_TYPE_ICON: 2408 write_rc_datablock (e, res->u.data.length, res->u.data.data, 0, 1, 0); 2409 break; 2410 case RES_TYPE_MESSAGETABLE: 2411 write_rc_messagetable (e, res->u.data.length, res->u.data.data); 2412 break; 2413 } 2414} 2415 2416/* Write out accelerator information. */ 2417 2418static void 2419write_rc_accelerators (FILE *e, const rc_accelerator *accelerators) 2420{ 2421 const rc_accelerator *acc; 2422 2423 fprintf (e, "BEGIN\n"); 2424 for (acc = accelerators; acc != NULL; acc = acc->next) 2425 { 2426 int printable; 2427 2428 fprintf (e, " "); 2429 2430 if ((acc->key & 0x7f) == acc->key 2431 && ISPRINT (acc->key) 2432 && (acc->flags & ACC_VIRTKEY) == 0) 2433 { 2434 fprintf (e, "\"%c\"", (char) acc->key); 2435 printable = 1; 2436 } 2437 else 2438 { 2439 fprintf (e, "%d", (int) acc->key); 2440 printable = 0; 2441 } 2442 2443 fprintf (e, ", %d", (int) acc->id); 2444 2445 if (! printable) 2446 { 2447 if ((acc->flags & ACC_VIRTKEY) != 0) 2448 fprintf (e, ", VIRTKEY"); 2449 else 2450 fprintf (e, ", ASCII"); 2451 } 2452 2453 if ((acc->flags & ACC_SHIFT) != 0) 2454 fprintf (e, ", SHIFT"); 2455 if ((acc->flags & ACC_CONTROL) != 0) 2456 fprintf (e, ", CONTROL"); 2457 if ((acc->flags & ACC_ALT) != 0) 2458 fprintf (e, ", ALT"); 2459 2460 fprintf (e, "\n"); 2461 } 2462 2463 fprintf (e, "END\n"); 2464} 2465 2466/* Write out cursor information. This would normally be in a separate 2467 file, which the rc file would include. */ 2468 2469static void 2470write_rc_cursor (FILE *e, const rc_cursor *cursor) 2471{ 2472 fprintf (e, "BEGIN\n"); 2473 indent (e, 2); 2474 fprintf (e, " 0x%x, 0x%x,\t/* Hotspot x: %d, y: %d. */\n", 2475 (unsigned int) cursor->xhotspot, (unsigned int) cursor->yhotspot, 2476 (int) cursor->xhotspot, (int) cursor->yhotspot); 2477 write_rc_datablock (e, (rc_uint_type) cursor->length, (const bfd_byte *) cursor->data, 2478 0, 0, 0); 2479 fprintf (e, "END\n"); 2480} 2481 2482/* Write out group cursor data. This would normally be built from the 2483 cursor data. */ 2484 2485static void 2486write_rc_group_cursor (FILE *e, const rc_group_cursor *group_cursor) 2487{ 2488 const rc_group_cursor *gc; 2489 int c; 2490 2491 for (c = 0, gc = group_cursor; gc != NULL; gc = gc->next, c++) 2492 ; 2493 fprintf (e, "BEGIN\n"); 2494 2495 indent (e, 2); 2496 fprintf (e, "0, 2, %d%s\t /* Having %d items. */\n", c, (c != 0 ? "," : ""), c); 2497 indent (e, 4); 2498 fprintf (e, "/* width, height, planes, bits, bytes, index. */\n"); 2499 2500 for (c = 1, gc = group_cursor; gc != NULL; gc = gc->next, c++) 2501 { 2502 indent (e, 4); 2503 fprintf (e, "%d, %d, %d, %d, 0x%xL, %d%s /* Element %d. */\n", 2504 (int) gc->width, (int) gc->height, (int) gc->planes, (int) gc->bits, 2505 (unsigned int) gc->bytes, (int) gc->index, (gc->next != NULL ? "," : ""), c); 2506 fprintf (e, "/* width: %d; height %d; planes %d; bits %d. */\n", 2507 (int) gc->width, (int) gc->height, (int) gc->planes, 2508 (int) gc->bits); 2509 } 2510 fprintf (e, "END\n"); 2511} 2512 2513/* Write dialog data. */ 2514 2515static void 2516write_rc_dialog (FILE *e, const rc_dialog *dialog) 2517{ 2518 const rc_dialog_control *control; 2519 2520 fprintf (e, "STYLE 0x%x\n", dialog->style); 2521 2522 if (dialog->exstyle != 0) 2523 fprintf (e, "EXSTYLE 0x%x\n", (unsigned int) dialog->exstyle); 2524 2525 if ((dialog->class.named && dialog->class.u.n.length > 0) 2526 || dialog->class.u.id != 0) 2527 { 2528 fprintf (e, "CLASS "); 2529 res_id_print (e, dialog->class, 1); 2530 fprintf (e, "\n"); 2531 } 2532 2533 if (dialog->caption != NULL) 2534 { 2535 fprintf (e, "CAPTION "); 2536 unicode_print_quoted (e, dialog->caption, -1); 2537 fprintf (e, "\n"); 2538 } 2539 2540 if ((dialog->menu.named && dialog->menu.u.n.length > 0) 2541 || dialog->menu.u.id != 0) 2542 { 2543 fprintf (e, "MENU "); 2544 res_id_print (e, dialog->menu, 0); 2545 fprintf (e, "\n"); 2546 } 2547 2548 if (dialog->font != NULL) 2549 { 2550 fprintf (e, "FONT %d, ", (int) dialog->pointsize); 2551 unicode_print_quoted (e, dialog->font, -1); 2552 if (dialog->ex != NULL 2553 && (dialog->ex->weight != 0 2554 || dialog->ex->italic != 0 2555 || dialog->ex->charset != 1)) 2556 fprintf (e, ", %d, %d, %d", 2557 (int) dialog->ex->weight, 2558 (int) dialog->ex->italic, 2559 (int) dialog->ex->charset); 2560 fprintf (e, "\n"); 2561 } 2562 2563 fprintf (e, "BEGIN\n"); 2564 2565 for (control = dialog->controls; control != NULL; control = control->next) 2566 write_rc_dialog_control (e, control); 2567 2568 fprintf (e, "END\n"); 2569} 2570 2571/* For each predefined control keyword, this table provides the class 2572 and the style. */ 2573 2574struct control_info 2575{ 2576 const char *name; 2577 unsigned short class; 2578 unsigned long style; 2579}; 2580 2581static const struct control_info control_info[] = 2582{ 2583 { "AUTO3STATE", CTL_BUTTON, BS_AUTO3STATE }, 2584 { "AUTOCHECKBOX", CTL_BUTTON, BS_AUTOCHECKBOX }, 2585 { "AUTORADIOBUTTON", CTL_BUTTON, BS_AUTORADIOBUTTON }, 2586 { "CHECKBOX", CTL_BUTTON, BS_CHECKBOX }, 2587 { "COMBOBOX", CTL_COMBOBOX, (unsigned long) -1 }, 2588 { "CTEXT", CTL_STATIC, SS_CENTER }, 2589 { "DEFPUSHBUTTON", CTL_BUTTON, BS_DEFPUSHBUTTON }, 2590 { "EDITTEXT", CTL_EDIT, (unsigned long) -1 }, 2591 { "GROUPBOX", CTL_BUTTON, BS_GROUPBOX }, 2592 { "ICON", CTL_STATIC, SS_ICON }, 2593 { "LISTBOX", CTL_LISTBOX, (unsigned long) -1 }, 2594 { "LTEXT", CTL_STATIC, SS_LEFT }, 2595 { "PUSHBOX", CTL_BUTTON, BS_PUSHBOX }, 2596 { "PUSHBUTTON", CTL_BUTTON, BS_PUSHBUTTON }, 2597 { "RADIOBUTTON", CTL_BUTTON, BS_RADIOBUTTON }, 2598 { "RTEXT", CTL_STATIC, SS_RIGHT }, 2599 { "SCROLLBAR", CTL_SCROLLBAR, (unsigned long) -1 }, 2600 { "STATE3", CTL_BUTTON, BS_3STATE }, 2601 /* It's important that USERBUTTON come after all the other button 2602 types, so that it won't be matched too early. */ 2603 { "USERBUTTON", CTL_BUTTON, (unsigned long) -1 }, 2604 { NULL, 0, 0 } 2605}; 2606 2607/* Write a dialog control. */ 2608 2609static void 2610write_rc_dialog_control (FILE *e, const rc_dialog_control *control) 2611{ 2612 const struct control_info *ci; 2613 2614 fprintf (e, " "); 2615 2616 if (control->class.named) 2617 ci = NULL; 2618 else 2619 { 2620 for (ci = control_info; ci->name != NULL; ++ci) 2621 if (ci->class == control->class.u.id 2622 && (ci->style == (unsigned long) -1 2623 || ci->style == (control->style & 0xff))) 2624 break; 2625 } 2626 if (ci == NULL) 2627 fprintf (e, "CONTROL"); 2628 else if (ci->name != NULL) 2629 fprintf (e, "%s", ci->name); 2630 else 2631 { 2632 fprintf (e, "CONTROL"); 2633 ci = NULL; 2634 } 2635 2636 if (control->text.named || control->text.u.id != 0) 2637 { 2638 fprintf (e, " "); 2639 res_id_print (e, control->text, 1); 2640 fprintf (e, ","); 2641 } 2642 2643 fprintf (e, " %d, ", (int) control->id); 2644 2645 if (ci == NULL) 2646 { 2647 if (control->class.named) 2648 fprintf (e, "\""); 2649 res_id_print (e, control->class, 0); 2650 if (control->class.named) 2651 fprintf (e, "\""); 2652 fprintf (e, ", 0x%x, ", (unsigned int) control->style); 2653 } 2654 2655 fprintf (e, "%d, %d", (int) control->x, (int) control->y); 2656 2657 if (control->style != SS_ICON 2658 || control->exstyle != 0 2659 || control->width != 0 2660 || control->height != 0 2661 || control->help != 0) 2662 { 2663 fprintf (e, ", %d, %d", (int) control->width, (int) control->height); 2664 2665 /* FIXME: We don't need to print the style if it is the default. 2666 More importantly, in certain cases we actually need to turn 2667 off parts of the forced style, by using NOT. */ 2668 if (ci != NULL) 2669 fprintf (e, ", 0x%x", (unsigned int) control->style); 2670 2671 if (control->exstyle != 0 || control->help != 0) 2672 fprintf (e, ", 0x%x, %u", (unsigned int) control->exstyle, 2673 (unsigned int) control->help); 2674 } 2675 2676 fprintf (e, "\n"); 2677 2678 if (control->data != NULL) 2679 write_rc_rcdata (e, control->data, 2); 2680} 2681 2682/* Write out font directory data. This would normally be built from 2683 the font data. */ 2684 2685static void 2686write_rc_fontdir (FILE *e, const rc_fontdir *fontdir) 2687{ 2688 const rc_fontdir *fc; 2689 int c; 2690 2691 for (c = 0, fc = fontdir; fc != NULL; fc = fc->next, c++) 2692 ; 2693 fprintf (e, "BEGIN\n"); 2694 indent (e, 2); 2695 fprintf (e, "%d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c); 2696 for (c = 1, fc = fontdir; fc != NULL; fc = fc->next, c++) 2697 { 2698 indent (e, 4); 2699 fprintf (e, "%d,\t/* Font no %d with index %d. */\n", 2700 (int) fc->index, c, (int) fc->index); 2701 write_rc_datablock (e, (rc_uint_type) fc->length - 2, 2702 (const bfd_byte *) fc->data + 4,fc->next != NULL, 2703 0, 0); 2704 } 2705 fprintf (e, "END\n"); 2706} 2707 2708/* Write out group icon data. This would normally be built from the 2709 icon data. */ 2710 2711static void 2712write_rc_group_icon (FILE *e, const rc_group_icon *group_icon) 2713{ 2714 const rc_group_icon *gi; 2715 int c; 2716 2717 for (c = 0, gi = group_icon; gi != NULL; gi = gi->next, c++) 2718 ; 2719 2720 fprintf (e, "BEGIN\n"); 2721 indent (e, 2); 2722 fprintf (e, " 0, 1, %d%s\t /* Has %d elements. */\n", c, (c != 0 ? "," : ""), c); 2723 2724 indent (e, 4); 2725 fprintf (e, "/* \"width height colors pad\", planes, bits, bytes, index. */\n"); 2726 for (c = 1, gi = group_icon; gi != NULL; gi = gi->next, c++) 2727 { 2728 indent (e, 4); 2729 fprintf (e, "\"\\%03o\\%03o\\%03o\\%03o\", %d, %d, 0x%xL, %d%s\t/* Element no %d. */\n", 2730 gi->width, gi->height, gi->colors, 0, (int) gi->planes, (int) gi->bits, 2731 (unsigned int) gi->bytes, (int) gi->index, (gi->next != NULL ? "," : ""), c); 2732 } 2733 fprintf (e, "END\n"); 2734} 2735 2736/* Write out a menu resource. */ 2737 2738static void 2739write_rc_menu (FILE *e, const rc_menu *menu, int menuex) 2740{ 2741 if (menu->help != 0) 2742 fprintf (e, "// Help ID: %u\n", (unsigned int) menu->help); 2743 write_rc_menuitems (e, menu->items, menuex, 0); 2744} 2745 2746static void 2747write_rc_toolbar (FILE *e, const rc_toolbar *tb) 2748{ 2749 rc_toolbar_item *it; 2750 indent (e, 0); 2751 fprintf (e, "BEGIN\n"); 2752 it = tb->items; 2753 while(it != NULL) 2754 { 2755 indent (e, 2); 2756 if (it->id.u.id == 0) 2757 fprintf (e, "SEPARATOR\n"); 2758 else 2759 fprintf (e, "BUTTON %d\n", (int) it->id.u.id); 2760 it = it->next; 2761 } 2762 indent (e, 0); 2763 fprintf (e, "END\n"); 2764} 2765 2766/* Write out menuitems. */ 2767 2768static void 2769write_rc_menuitems (FILE *e, const rc_menuitem *menuitems, int menuex, 2770 int ind) 2771{ 2772 const rc_menuitem *mi; 2773 2774 indent (e, ind); 2775 fprintf (e, "BEGIN\n"); 2776 2777 for (mi = menuitems; mi != NULL; mi = mi->next) 2778 { 2779 indent (e, ind + 2); 2780 2781 if (mi->popup == NULL) 2782 fprintf (e, "MENUITEM"); 2783 else 2784 fprintf (e, "POPUP"); 2785 2786 if (! menuex 2787 && mi->popup == NULL 2788 && mi->text == NULL 2789 && mi->type == 0 2790 && mi->id == 0) 2791 { 2792 fprintf (e, " SEPARATOR\n"); 2793 continue; 2794 } 2795 2796 if (mi->text == NULL) 2797 fprintf (e, " \"\""); 2798 else 2799 { 2800 fprintf (e, " "); 2801 unicode_print_quoted (e, mi->text, -1); 2802 } 2803 2804 if (! menuex) 2805 { 2806 if (mi->popup == NULL) 2807 fprintf (e, ", %d", (int) mi->id); 2808 2809 if ((mi->type & MENUITEM_CHECKED) != 0) 2810 fprintf (e, ", CHECKED"); 2811 if ((mi->type & MENUITEM_GRAYED) != 0) 2812 fprintf (e, ", GRAYED"); 2813 if ((mi->type & MENUITEM_HELP) != 0) 2814 fprintf (e, ", HELP"); 2815 if ((mi->type & MENUITEM_INACTIVE) != 0) 2816 fprintf (e, ", INACTIVE"); 2817 if ((mi->type & MENUITEM_MENUBARBREAK) != 0) 2818 fprintf (e, ", MENUBARBREAK"); 2819 if ((mi->type & MENUITEM_MENUBREAK) != 0) 2820 fprintf (e, ", MENUBREAK"); 2821 } 2822 else 2823 { 2824 if (mi->id != 0 || mi->type != 0 || mi->state != 0 || mi->help != 0) 2825 { 2826 fprintf (e, ", %d", (int) mi->id); 2827 if (mi->type != 0 || mi->state != 0 || mi->help != 0) 2828 { 2829 fprintf (e, ", %u", (unsigned int) mi->type); 2830 if (mi->state != 0 || mi->help != 0) 2831 { 2832 fprintf (e, ", %u", (unsigned int) mi->state); 2833 if (mi->help != 0) 2834 fprintf (e, ", %u", (unsigned int) mi->help); 2835 } 2836 } 2837 } 2838 } 2839 2840 fprintf (e, "\n"); 2841 2842 if (mi->popup != NULL) 2843 write_rc_menuitems (e, mi->popup, menuex, ind + 2); 2844 } 2845 2846 indent (e, ind); 2847 fprintf (e, "END\n"); 2848} 2849 2850static int 2851test_rc_datablock_unicode (rc_uint_type length, const bfd_byte *data) 2852{ 2853 rc_uint_type i; 2854 if ((length & 1) != 0) 2855 return 0; 2856 2857 for (i = 0; i < length; i += 2) 2858 { 2859 if (data[i] == 0 && data[i + 1] == 0 && (i + 2) < length) 2860 return 0; 2861 if (data[i] == 0xff && data[i + 1] == 0xff) 2862 return 0; 2863 } 2864 return 1; 2865} 2866 2867static int 2868test_rc_datablock_text (rc_uint_type length, const bfd_byte *data) 2869{ 2870 int has_nl; 2871 rc_uint_type c; 2872 rc_uint_type i; 2873 2874 if (length <= 1) 2875 return 0; 2876 2877 has_nl = 0; 2878 for (i = 0, c = 0; i < length; i++) 2879 { 2880 if (! ISPRINT (data[i]) && data[i] != '\n' 2881 && ! (data[i] == '\r' && (i + 1) < length && data[i + 1] == '\n') 2882 && data[i] != '\t' 2883 && ! (data[i] == 0 && (i + 1) != length)) 2884 { 2885 if (data[i] <= 7) 2886 return 0; 2887 c++; 2888 } 2889 else if (data[i] == '\n') has_nl++; 2890 } 2891 if (length > 80 && ! has_nl) 2892 return 0; 2893 c = (((c * 10000) + (i / 100) - 1)) / i; 2894 if (c >= 150) 2895 return 0; 2896 return 1; 2897} 2898 2899static void 2900write_rc_messagetable (FILE *e, rc_uint_type length, const bfd_byte *data) 2901{ 2902 int has_error = 0; 2903 const struct bin_messagetable *mt; 2904 fprintf (e, "BEGIN\n"); 2905 2906 write_rc_datablock (e, length, data, 0, 0, 0); 2907 2908 fprintf (e, "\n"); 2909 wr_printcomment (e, "MC syntax dump"); 2910 if (length < BIN_MESSAGETABLE_SIZE) 2911 has_error = 1; 2912 else 2913 do { 2914 rc_uint_type m, i; 2915 mt = (const struct bin_messagetable *) data; 2916 m = windres_get_32 (&wrtarget, mt->cblocks, length); 2917 if (length < (BIN_MESSAGETABLE_SIZE + m * BIN_MESSAGETABLE_BLOCK_SIZE)) 2918 { 2919 has_error = 1; 2920 break; 2921 } 2922 for (i = 0; i < m; i++) 2923 { 2924 rc_uint_type low, high, offset; 2925 const struct bin_messagetable_item *mti; 2926 2927 low = windres_get_32 (&wrtarget, mt->items[i].lowid, 4); 2928 high = windres_get_32 (&wrtarget, mt->items[i].highid, 4); 2929 offset = windres_get_32 (&wrtarget, mt->items[i].offset, 4); 2930 while (low <= high) 2931 { 2932 rc_uint_type elen, flags; 2933 if ((offset + BIN_MESSAGETABLE_ITEM_SIZE) > length) 2934 { 2935 has_error = 1; 2936 break; 2937 } 2938 mti = (const struct bin_messagetable_item *) &data[offset]; 2939 elen = windres_get_16 (&wrtarget, mti->length, 2); 2940 flags = windres_get_16 (&wrtarget, mti->flags, 2); 2941 if ((offset + elen) > length) 2942 { 2943 has_error = 1; 2944 break; 2945 } 2946 wr_printcomment (e, "MessageId = 0x%x", low); 2947 wr_printcomment (e, ""); 2948 if ((flags & MESSAGE_RESOURCE_UNICODE) == MESSAGE_RESOURCE_UNICODE) 2949 unicode_print (e, (const unichar *) mti->data, 2950 (elen - BIN_MESSAGETABLE_ITEM_SIZE) / 2); 2951 else 2952 ascii_print (e, (const char *) mti->data, 2953 (elen - BIN_MESSAGETABLE_ITEM_SIZE)); 2954 wr_printcomment (e,""); 2955 ++low; 2956 offset += elen; 2957 } 2958 } 2959 } while (0); 2960 if (has_error) 2961 wr_printcomment (e, "Illegal data"); 2962 wr_print_flush (e); 2963 fprintf (e, "END\n"); 2964} 2965 2966static void 2967write_rc_datablock (FILE *e, rc_uint_type length, const bfd_byte *data, int has_next, 2968 int hasblock, int show_comment) 2969{ 2970 int plen; 2971 2972 if (hasblock) 2973 fprintf (e, "BEGIN\n"); 2974 2975 if (show_comment == -1) 2976 { 2977 if (test_rc_datablock_text(length, data)) 2978 { 2979 rc_uint_type i, c; 2980 for (i = 0; i < length;) 2981 { 2982 indent (e, 2); 2983 fprintf (e, "\""); 2984 2985 for (c = 0; i < length && c < 160 && data[i] != '\n'; c++, i++) 2986 ; 2987 if (i < length && data[i] == '\n') 2988 ++i, ++c; 2989 ascii_print (e, (const char *) &data[i - c], c); 2990 fprintf (e, "\""); 2991 if (i < length) 2992 fprintf (e, "\n"); 2993 } 2994 2995 if (i == 0) 2996 { 2997 indent (e, 2); 2998 fprintf (e, "\"\""); 2999 } 3000 if (has_next) 3001 fprintf (e, ","); 3002 fprintf (e, "\n"); 3003 if (hasblock) 3004 fprintf (e, "END\n"); 3005 return; 3006 } 3007 if (test_rc_datablock_unicode (length, data)) 3008 { 3009 rc_uint_type i, c; 3010 for (i = 0; i < length;) 3011 { 3012 const unichar *u; 3013 3014 u = (const unichar *) &data[i]; 3015 indent (e, 2); 3016 fprintf (e, "L\""); 3017 3018 for (c = 0; i < length && c < 160 && u[c] != '\n'; c++, i += 2) 3019 ; 3020 if (i < length && u[c] == '\n') 3021 i += 2, ++c; 3022 unicode_print (e, u, c); 3023 fprintf (e, "\""); 3024 if (i < length) 3025 fprintf (e, "\n"); 3026 } 3027 3028 if (i == 0) 3029 { 3030 indent (e, 2); 3031 fprintf (e, "L\"\""); 3032 } 3033 if (has_next) 3034 fprintf (e, ","); 3035 fprintf (e, "\n"); 3036 if (hasblock) 3037 fprintf (e, "END\n"); 3038 return; 3039 } 3040 3041 show_comment = 0; 3042 } 3043 3044 if (length != 0) 3045 { 3046 rc_uint_type i, max_row; 3047 int first = 1; 3048 3049 max_row = (show_comment ? 4 : 8); 3050 indent (e, 2); 3051 for (i = 0; i + 3 < length;) 3052 { 3053 rc_uint_type k; 3054 rc_uint_type comment_start; 3055 3056 comment_start = i; 3057 3058 if (! first) 3059 indent (e, 2); 3060 3061 for (k = 0; k < max_row && i + 3 < length; k++, i += 4) 3062 { 3063 if (k == 0) 3064 plen = fprintf (e, "0x%lxL", 3065 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)); 3066 else 3067 plen = fprintf (e, " 0x%lxL", 3068 (unsigned long) windres_get_32 (&wrtarget, data + i, length - i)) - 1; 3069 if (has_next || (i + 4) < length) 3070 { 3071 if (plen>0 && plen < 11) 3072 indent (e, 11 - plen); 3073 fprintf (e, ","); 3074 } 3075 } 3076 if (show_comment) 3077 { 3078 fprintf (e, "\t/* "); 3079 ascii_print (e, (const char *) &data[comment_start], i - comment_start); 3080 fprintf (e, ". */"); 3081 } 3082 fprintf (e, "\n"); 3083 first = 0; 3084 } 3085 3086 if (i + 1 < length) 3087 { 3088 if (! first) 3089 indent (e, 2); 3090 plen = fprintf (e, "0x%x", 3091 (int) windres_get_16 (&wrtarget, data + i, length - i)); 3092 if (has_next || i + 2 < length) 3093 { 3094 if (plen > 0 && plen < 11) 3095 indent (e, 11 - plen); 3096 fprintf (e, ","); 3097 } 3098 if (show_comment) 3099 { 3100 fprintf (e, "\t/* "); 3101 ascii_print (e, (const char *) &data[i], 2); 3102 fprintf (e, ". */"); 3103 } 3104 fprintf (e, "\n"); 3105 i += 2; 3106 first = 0; 3107 } 3108 3109 if (i < length) 3110 { 3111 if (! first) 3112 indent (e, 2); 3113 fprintf (e, "\""); 3114 ascii_print (e, (const char *) &data[i], 1); 3115 fprintf (e, "\""); 3116 if (has_next) 3117 fprintf (e, ","); 3118 fprintf (e, "\n"); 3119 first = 0; 3120 } 3121 } 3122 if (hasblock) 3123 fprintf (e, "END\n"); 3124} 3125 3126/* Write out an rcdata resource. This is also used for other types of 3127 resources that need to print arbitrary data. */ 3128 3129static void 3130write_rc_rcdata (FILE *e, const rc_rcdata_item *rcdata, int ind) 3131{ 3132 const rc_rcdata_item *ri; 3133 3134 indent (e, ind); 3135 fprintf (e, "BEGIN\n"); 3136 3137 for (ri = rcdata; ri != NULL; ri = ri->next) 3138 { 3139 if (ri->type == RCDATA_BUFFER && ri->u.buffer.length == 0) 3140 continue; 3141 3142 switch (ri->type) 3143 { 3144 default: 3145 abort (); 3146 3147 case RCDATA_WORD: 3148 indent (e, ind + 2); 3149 fprintf (e, "%ld", (long) (ri->u.word & 0xffff)); 3150 break; 3151 3152 case RCDATA_DWORD: 3153 indent (e, ind + 2); 3154 fprintf (e, "%luL", (unsigned long) ri->u.dword); 3155 break; 3156 3157 case RCDATA_STRING: 3158 indent (e, ind + 2); 3159 fprintf (e, "\""); 3160 ascii_print (e, ri->u.string.s, ri->u.string.length); 3161 fprintf (e, "\""); 3162 break; 3163 3164 case RCDATA_WSTRING: 3165 indent (e, ind + 2); 3166 fprintf (e, "L\""); 3167 unicode_print (e, ri->u.wstring.w, ri->u.wstring.length); 3168 fprintf (e, "\""); 3169 break; 3170 3171 case RCDATA_BUFFER: 3172 write_rc_datablock (e, (rc_uint_type) ri->u.buffer.length, 3173 (const bfd_byte *) ri->u.buffer.data, 3174 ri->next != NULL, 0, -1); 3175 break; 3176 } 3177 3178 if (ri->type != RCDATA_BUFFER) 3179 { 3180 if (ri->next != NULL) 3181 fprintf (e, ","); 3182 fprintf (e, "\n"); 3183 } 3184 } 3185 3186 indent (e, ind); 3187 fprintf (e, "END\n"); 3188} 3189 3190/* Write out a stringtable resource. */ 3191 3192static void 3193write_rc_stringtable (FILE *e, const rc_res_id *name, 3194 const rc_stringtable *stringtable) 3195{ 3196 rc_uint_type offset; 3197 int i; 3198 3199 if (name != NULL && ! name->named) 3200 offset = (name->u.id - 1) << 4; 3201 else 3202 { 3203 fprintf (e, "/* %s string table name. */\n", 3204 name == NULL ? "Missing" : "Invalid"); 3205 offset = 0; 3206 } 3207 3208 fprintf (e, "BEGIN\n"); 3209 3210 for (i = 0; i < 16; i++) 3211 { 3212 if (stringtable->strings[i].length != 0) 3213 { 3214 fprintf (e, " %lu, ", (unsigned long) offset + i); 3215 unicode_print_quoted (e, stringtable->strings[i].string, 3216 stringtable->strings[i].length); 3217 fprintf (e, "\n"); 3218 } 3219 } 3220 3221 fprintf (e, "END\n"); 3222} 3223 3224/* Write out a versioninfo resource. */ 3225 3226static void 3227write_rc_versioninfo (FILE *e, const rc_versioninfo *versioninfo) 3228{ 3229 const rc_fixed_versioninfo *f; 3230 const rc_ver_info *vi; 3231 3232 f = versioninfo->fixed; 3233 if (f->file_version_ms != 0 || f->file_version_ls != 0) 3234 fprintf (e, " FILEVERSION %u, %u, %u, %u\n", 3235 (unsigned int) ((f->file_version_ms >> 16) & 0xffff), 3236 (unsigned int) (f->file_version_ms & 0xffff), 3237 (unsigned int) ((f->file_version_ls >> 16) & 0xffff), 3238 (unsigned int) (f->file_version_ls & 0xffff)); 3239 if (f->product_version_ms != 0 || f->product_version_ls != 0) 3240 fprintf (e, " PRODUCTVERSION %u, %u, %u, %u\n", 3241 (unsigned int) ((f->product_version_ms >> 16) & 0xffff), 3242 (unsigned int) (f->product_version_ms & 0xffff), 3243 (unsigned int) ((f->product_version_ls >> 16) & 0xffff), 3244 (unsigned int) (f->product_version_ls & 0xffff)); 3245 if (f->file_flags_mask != 0) 3246 fprintf (e, " FILEFLAGSMASK 0x%x\n", (unsigned int) f->file_flags_mask); 3247 if (f->file_flags != 0) 3248 fprintf (e, " FILEFLAGS 0x%x\n", (unsigned int) f->file_flags); 3249 if (f->file_os != 0) 3250 fprintf (e, " FILEOS 0x%x\n", (unsigned int) f->file_os); 3251 if (f->file_type != 0) 3252 fprintf (e, " FILETYPE 0x%x\n", (unsigned int) f->file_type); 3253 if (f->file_subtype != 0) 3254 fprintf (e, " FILESUBTYPE 0x%x\n", (unsigned int) f->file_subtype); 3255 if (f->file_date_ms != 0 || f->file_date_ls != 0) 3256 fprintf (e, "/* Date: %u, %u. */\n", 3257 (unsigned int) f->file_date_ms, (unsigned int) f->file_date_ls); 3258 3259 fprintf (e, "BEGIN\n"); 3260 3261 for (vi = versioninfo->var; vi != NULL; vi = vi->next) 3262 { 3263 switch (vi->type) 3264 { 3265 case VERINFO_STRING: 3266 { 3267 const rc_ver_stringinfo *vs; 3268 3269 fprintf (e, " BLOCK \"StringFileInfo\"\n"); 3270 fprintf (e, " BEGIN\n"); 3271 fprintf (e, " BLOCK "); 3272 unicode_print_quoted (e, vi->u.string.language, -1); 3273 fprintf (e, "\n"); 3274 fprintf (e, " BEGIN\n"); 3275 3276 for (vs = vi->u.string.strings; vs != NULL; vs = vs->next) 3277 { 3278 fprintf (e, " VALUE "); 3279 unicode_print_quoted (e, vs->key, -1); 3280 fprintf (e, ", "); 3281 unicode_print_quoted (e, vs->value, -1); 3282 fprintf (e, "\n"); 3283 } 3284 3285 fprintf (e, " END\n"); 3286 fprintf (e, " END\n"); 3287 break; 3288 } 3289 3290 case VERINFO_VAR: 3291 { 3292 const rc_ver_varinfo *vv; 3293 3294 fprintf (e, " BLOCK \"VarFileInfo\"\n"); 3295 fprintf (e, " BEGIN\n"); 3296 fprintf (e, " VALUE "); 3297 unicode_print_quoted (e, vi->u.var.key, -1); 3298 3299 for (vv = vi->u.var.var; vv != NULL; vv = vv->next) 3300 fprintf (e, ", 0x%x, %d", (unsigned int) vv->language, 3301 (int) vv->charset); 3302 3303 fprintf (e, "\n END\n"); 3304 3305 break; 3306 } 3307 } 3308 } 3309 3310 fprintf (e, "END\n"); 3311} 3312 3313static rc_uint_type 3314rcdata_copy (const rc_rcdata_item *src, bfd_byte *dst) 3315{ 3316 if (! src) 3317 return 0; 3318 switch (src->type) 3319 { 3320 case RCDATA_WORD: 3321 if (dst) 3322 windres_put_16 (&wrtarget, dst, (rc_uint_type) src->u.word); 3323 return 2; 3324 case RCDATA_DWORD: 3325 if (dst) 3326 windres_put_32 (&wrtarget, dst, (rc_uint_type) src->u.dword); 3327 return 4; 3328 case RCDATA_STRING: 3329 if (dst && src->u.string.length) 3330 memcpy (dst, src->u.string.s, src->u.string.length); 3331 return (rc_uint_type) src->u.string.length; 3332 case RCDATA_WSTRING: 3333 if (dst && src->u.wstring.length) 3334 memcpy (dst, src->u.wstring.w, src->u.wstring.length * sizeof (unichar)); 3335 return (rc_uint_type) (src->u.wstring.length * sizeof (unichar)); 3336 case RCDATA_BUFFER: 3337 if (dst && src->u.buffer.length) 3338 memcpy (dst, src->u.buffer.data, src->u.buffer.length); 3339 return (rc_uint_type) src->u.buffer.length; 3340 default: 3341 abort (); 3342 } 3343 /* Never reached. */ 3344 return 0; 3345} 3346