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