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