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