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