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