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