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