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