1/* GNU Objective C Runtime archiving 2 Copyright (C) 1993, 1995, 1996, 1997 Free Software Foundation, Inc. 3 Contributed by Kresten Krab Thorup 4 5This file is part of GNU CC. 6 7GNU CC is free software; you can redistribute it and/or modify it under the 8terms of the GNU General Public License as published by the Free Software 9Foundation; either version 2, or (at your option) any later version. 10 11GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14details. 15 16You should have received a copy of the GNU General Public License along with 17GNU CC; see the file COPYING. If not, write to the Free Software 18Foundation, 59 Temple Place - Suite 330, 19Boston, MA 02111-1307, USA. */ 20 21/* As a special exception, if you link this library with files compiled with 22 GCC to produce an executable, this does not cause the resulting executable 23 to be covered by the GNU General Public License. This exception does not 24 however invalidate any other reasons why the executable file might be 25 covered by the GNU General Public License. */ 26 27#include "tconfig.h" 28#include "runtime.h" 29#include "typedstream.h" 30#include "encoding.h" 31 32#ifdef HAVE_STDLIB_H 33#include <stdlib.h> 34#endif 35 36extern int fflush(FILE*); 37 38#define ROUND(V, A) \ 39 ({ typeof(V) __v=(V); typeof(A) __a=(A); \ 40 __a*((__v+__a-1)/__a); }) 41 42#define PTR2LONG(P) (((char*)(P))-(char*)0) 43#define LONG2PTR(L) (((char*)0)+(L)) 44 45/* Declare some functions... */ 46 47static int 48objc_read_class (struct objc_typed_stream* stream, Class* class); 49 50int objc_sizeof_type(const char* type); 51 52static int 53objc_write_use_common (struct objc_typed_stream* stream, unsigned long key); 54 55static int 56objc_write_register_common (struct objc_typed_stream* stream, 57 unsigned long key); 58 59static int 60objc_write_class (struct objc_typed_stream* stream, 61 struct objc_class* class); 62 63const char* objc_skip_type (const char* type); 64 65static void __objc_finish_write_root_object(struct objc_typed_stream*); 66static void __objc_finish_read_root_object(struct objc_typed_stream*); 67 68static __inline__ int 69__objc_code_unsigned_char (unsigned char* buf, unsigned char val) 70{ 71 if ((val&_B_VALUE) == val) 72 { 73 buf[0] = val|_B_SINT; 74 return 1; 75 } 76 else 77 { 78 buf[0] = _B_NINT|0x01; 79 buf[1] = val; 80 return 2; 81 } 82} 83 84int 85objc_write_unsigned_char (struct objc_typed_stream* stream, 86 unsigned char value) 87{ 88 unsigned char buf[sizeof (unsigned char)+1]; 89 int len = __objc_code_unsigned_char (buf, value); 90 return (*stream->write)(stream->physical, buf, len); 91} 92 93static __inline__ int 94__objc_code_char (unsigned char* buf, signed char val) 95{ 96 if (val >= 0) 97 return __objc_code_unsigned_char (buf, val); 98 else 99 { 100 buf[0] = _B_NINT|_B_SIGN|0x01; 101 buf[1] = -val; 102 return 2; 103 } 104} 105 106int 107objc_write_char (struct objc_typed_stream* stream, signed char value) 108{ 109 unsigned char buf[sizeof (char)+1]; 110 int len = __objc_code_char (buf, value); 111 return (*stream->write)(stream->physical, buf, len); 112} 113 114static __inline__ int 115__objc_code_unsigned_short (unsigned char* buf, unsigned short val) 116{ 117 if ((val&_B_VALUE) == val) 118 { 119 buf[0] = val|_B_SINT; 120 return 1; 121 } 122 else 123 { 124 int c, b; 125 126 buf[0] = _B_NINT; 127 128 for (c= sizeof(short); c != 0; c -= 1) 129 if (((val>>(8*(c-1)))%0x100) != 0) 130 break; 131 132 buf[0] |= c; 133 134 for (b = 1; c != 0; c--, b++) 135 { 136 buf[b] = (val >> (8*(c-1)))%0x100; 137 } 138 139 return b; 140 } 141} 142 143int 144objc_write_unsigned_short (struct objc_typed_stream* stream, 145 unsigned short value) 146{ 147 unsigned char buf[sizeof (unsigned short)+1]; 148 int len = __objc_code_unsigned_short (buf, value); 149 return (*stream->write)(stream->physical, buf, len); 150} 151 152static __inline__ int 153__objc_code_short (unsigned char* buf, short val) 154{ 155 int sign = (val < 0); 156 int size = __objc_code_unsigned_short (buf, sign ? -val : val); 157 if (sign) 158 buf[0] |= _B_SIGN; 159 return size; 160} 161 162int 163objc_write_short (struct objc_typed_stream* stream, short value) 164{ 165 unsigned char buf[sizeof (short)+1]; 166 int len = __objc_code_short (buf, value); 167 return (*stream->write)(stream->physical, buf, len); 168} 169 170 171static __inline__ int 172__objc_code_unsigned_int (unsigned char* buf, unsigned int val) 173{ 174 if ((val&_B_VALUE) == val) 175 { 176 buf[0] = val|_B_SINT; 177 return 1; 178 } 179 else 180 { 181 int c, b; 182 183 buf[0] = _B_NINT; 184 185 for (c= sizeof(int); c != 0; c -= 1) 186 if (((val>>(8*(c-1)))%0x100) != 0) 187 break; 188 189 buf[0] |= c; 190 191 for (b = 1; c != 0; c--, b++) 192 { 193 buf[b] = (val >> (8*(c-1)))%0x100; 194 } 195 196 return b; 197 } 198} 199 200int 201objc_write_unsigned_int (struct objc_typed_stream* stream, unsigned int value) 202{ 203 unsigned char buf[sizeof(unsigned int)+1]; 204 int len = __objc_code_unsigned_int (buf, value); 205 return (*stream->write)(stream->physical, buf, len); 206} 207 208static __inline__ int 209__objc_code_int (unsigned char* buf, int val) 210{ 211 int sign = (val < 0); 212 int size = __objc_code_unsigned_int (buf, sign ? -val : val); 213 if (sign) 214 buf[0] |= _B_SIGN; 215 return size; 216} 217 218int 219objc_write_int (struct objc_typed_stream* stream, int value) 220{ 221 unsigned char buf[sizeof(int)+1]; 222 int len = __objc_code_int (buf, value); 223 return (*stream->write)(stream->physical, buf, len); 224} 225 226static __inline__ int 227__objc_code_unsigned_long (unsigned char* buf, unsigned long val) 228{ 229 if ((val&_B_VALUE) == val) 230 { 231 buf[0] = val|_B_SINT; 232 return 1; 233 } 234 else 235 { 236 int c, b; 237 238 buf[0] = _B_NINT; 239 240 for (c= sizeof(long); c != 0; c -= 1) 241 if (((val>>(8*(c-1)))%0x100) != 0) 242 break; 243 244 buf[0] |= c; 245 246 for (b = 1; c != 0; c--, b++) 247 { 248 buf[b] = (val >> (8*(c-1)))%0x100; 249 } 250 251 return b; 252 } 253} 254 255int 256objc_write_unsigned_long (struct objc_typed_stream* stream, 257 unsigned long value) 258{ 259 unsigned char buf[sizeof(unsigned long)+1]; 260 int len = __objc_code_unsigned_long (buf, value); 261 return (*stream->write)(stream->physical, buf, len); 262} 263 264static __inline__ int 265__objc_code_long (unsigned char* buf, long val) 266{ 267 int sign = (val < 0); 268 int size = __objc_code_unsigned_long (buf, sign ? -val : val); 269 if (sign) 270 buf[0] |= _B_SIGN; 271 return size; 272} 273 274int 275objc_write_long (struct objc_typed_stream* stream, long value) 276{ 277 unsigned char buf[sizeof(long)+1]; 278 int len = __objc_code_long (buf, value); 279 return (*stream->write)(stream->physical, buf, len); 280} 281 282 283int 284objc_write_string (struct objc_typed_stream* stream, 285 const unsigned char* string, unsigned int nbytes) 286{ 287 unsigned char buf[sizeof(unsigned int)+1]; 288 int len = __objc_code_unsigned_int (buf, nbytes); 289 290 if ((buf[0]&_B_CODE) == _B_SINT) 291 buf[0] = (buf[0]&_B_VALUE)|_B_SSTR; 292 293 else /* _B_NINT */ 294 buf[0] = (buf[0]&_B_VALUE)|_B_NSTR; 295 296 if ((*stream->write)(stream->physical, buf, len) != 0) 297 return (*stream->write)(stream->physical, string, nbytes); 298 else 299 return 0; 300} 301 302int 303objc_write_string_atomic (struct objc_typed_stream* stream, 304 unsigned char* string, unsigned int nbytes) 305{ 306 unsigned long key; 307 if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, string)))) 308 return objc_write_use_common (stream, key); 309 else 310 { 311 int length; 312 hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(string)), string); 313 if ((length = objc_write_register_common (stream, key))) 314 return objc_write_string (stream, string, nbytes); 315 return length; 316 } 317} 318 319static int 320objc_write_register_common (struct objc_typed_stream* stream, 321 unsigned long key) 322{ 323 unsigned char buf[sizeof (unsigned long)+2]; 324 int len = __objc_code_unsigned_long (buf+1, key); 325 if (len == 1) 326 { 327 buf[0] = _B_RCOMM|0x01; 328 buf[1] &= _B_VALUE; 329 return (*stream->write)(stream->physical, buf, len+1); 330 } 331 else 332 { 333 buf[1] = (buf[1]&_B_VALUE)|_B_RCOMM; 334 return (*stream->write)(stream->physical, buf+1, len); 335 } 336} 337 338static int 339objc_write_use_common (struct objc_typed_stream* stream, unsigned long key) 340{ 341 unsigned char buf[sizeof (unsigned long)+2]; 342 int len = __objc_code_unsigned_long (buf+1, key); 343 if (len == 1) 344 { 345 buf[0] = _B_UCOMM|0x01; 346 buf[1] &= _B_VALUE; 347 return (*stream->write)(stream->physical, buf, 2); 348 } 349 else 350 { 351 buf[1] = (buf[1]&_B_VALUE)|_B_UCOMM; 352 return (*stream->write)(stream->physical, buf+1, len); 353 } 354} 355 356static __inline__ int 357__objc_write_extension (struct objc_typed_stream* stream, unsigned char code) 358{ 359 if (code <= _B_VALUE) 360 { 361 unsigned char buf = code|_B_EXT; 362 return (*stream->write)(stream->physical, &buf, 1); 363 } 364 else 365 { 366 objc_error(nil, OBJC_ERR_BAD_OPCODE, 367 "__objc_write_extension: bad opcode %c\n", code); 368 return -1; 369 } 370} 371 372__inline__ int 373__objc_write_object (struct objc_typed_stream* stream, id object) 374{ 375 unsigned char buf = '\0'; 376 SEL write_sel = sel_get_any_uid ("write:"); 377 if (object) 378 { 379 __objc_write_extension (stream, _BX_OBJECT); 380 objc_write_class (stream, object->class_pointer); 381 (*objc_msg_lookup(object, write_sel))(object, write_sel, stream); 382 return (*stream->write)(stream->physical, &buf, 1); 383 } 384 else 385 return objc_write_use_common(stream, 0); 386} 387 388int 389objc_write_object_reference (struct objc_typed_stream* stream, id object) 390{ 391 unsigned long key; 392 if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object)))) 393 return objc_write_use_common (stream, key); 394 395 __objc_write_extension (stream, _BX_OBJREF); 396 return objc_write_unsigned_long (stream, PTR2LONG (object)); 397} 398 399int 400objc_write_root_object (struct objc_typed_stream* stream, id object) 401{ 402 int len = 0; 403 if (stream->writing_root_p) 404 objc_error (nil, OBJC_ERR_RECURSE_ROOT, 405 "objc_write_root_object called recursively"); 406 else 407 { 408 stream->writing_root_p = 1; 409 __objc_write_extension (stream, _BX_OBJROOT); 410 if((len = objc_write_object (stream, object))) 411 __objc_finish_write_root_object(stream); 412 stream->writing_root_p = 0; 413 } 414 return len; 415} 416 417int 418objc_write_object (struct objc_typed_stream* stream, id object) 419{ 420 unsigned long key; 421 if ((key = PTR2LONG(hash_value_for_key (stream->object_table, object)))) 422 return objc_write_use_common (stream, key); 423 424 else if (object == nil) 425 return objc_write_use_common(stream, 0); 426 427 else 428 { 429 int length; 430 hash_add (&stream->object_table, LONG2PTR(key=PTR2LONG(object)), object); 431 if ((length = objc_write_register_common (stream, key))) 432 return __objc_write_object (stream, object); 433 return length; 434 } 435} 436 437__inline__ int 438__objc_write_class (struct objc_typed_stream* stream, struct objc_class* class) 439{ 440 __objc_write_extension (stream, _BX_CLASS); 441 objc_write_string_atomic(stream, (char*)class->name, 442 strlen((char*)class->name)); 443 return objc_write_unsigned_long (stream, class->version); 444} 445 446 447static int 448objc_write_class (struct objc_typed_stream* stream, 449 struct objc_class* class) 450{ 451 unsigned long key; 452 if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, class)))) 453 return objc_write_use_common (stream, key); 454 else 455 { 456 int length; 457 hash_add (&stream->stream_table, LONG2PTR(key=PTR2LONG(class)), class); 458 if ((length = objc_write_register_common (stream, key))) 459 return __objc_write_class (stream, class); 460 return length; 461 } 462} 463 464 465__inline__ int 466__objc_write_selector (struct objc_typed_stream* stream, SEL selector) 467{ 468 const char* sel_name; 469 __objc_write_extension (stream, _BX_SEL); 470 /* to handle NULL selectors */ 471 if ((SEL)0 == selector) 472 return objc_write_string (stream, "", 0); 473 sel_name = sel_get_name (selector); 474 return objc_write_string (stream, sel_name, strlen ((char*)sel_name)); 475} 476 477int 478objc_write_selector (struct objc_typed_stream* stream, SEL selector) 479{ 480 const char* sel_name; 481 unsigned long key; 482 483 /* to handle NULL selectors */ 484 if ((SEL)0 == selector) 485 return __objc_write_selector (stream, selector); 486 487 sel_name = sel_get_name (selector); 488 if ((key = PTR2LONG(hash_value_for_key (stream->stream_table, sel_name)))) 489 return objc_write_use_common (stream, key); 490 else 491 { 492 int length; 493 hash_add (&stream->stream_table, 494 LONG2PTR(key=PTR2LONG(sel_name)), (char*)sel_name); 495 if ((length = objc_write_register_common (stream, key))) 496 return __objc_write_selector (stream, selector); 497 return length; 498 } 499} 500 501 502 503/* 504** Read operations 505*/ 506 507__inline__ int 508objc_read_char (struct objc_typed_stream* stream, char* val) 509{ 510 unsigned char buf; 511 int len; 512 len = (*stream->read)(stream->physical, &buf, 1); 513 if (len != 0) 514 { 515 if ((buf & _B_CODE) == _B_SINT) 516 (*val) = (buf & _B_VALUE); 517 518 else if ((buf & _B_NUMBER) == 1) 519 { 520 len = (*stream->read)(stream->physical, val, 1); 521 if (buf&_B_SIGN) 522 (*val) = -1*(*val); 523 } 524 525 else 526 objc_error(nil, OBJC_ERR_BAD_DATA, 527 "expected 8bit signed int, got %dbit int", 528 (int)(buf&_B_NUMBER)*8); 529 } 530 return len; 531} 532 533 534__inline__ int 535objc_read_unsigned_char (struct objc_typed_stream* stream, unsigned char* val) 536{ 537 unsigned char buf; 538 int len; 539 if ((len = (*stream->read)(stream->physical, &buf, 1))) 540 { 541 if ((buf & _B_CODE) == _B_SINT) 542 (*val) = (buf & _B_VALUE); 543 544 else if ((buf & _B_NUMBER) == 1) 545 len = (*stream->read)(stream->physical, val, 1); 546 547 else 548 objc_error(nil, OBJC_ERR_BAD_DATA, 549 "expected 8bit unsigned int, got %dbit int", 550 (int)(buf&_B_NUMBER)*8); 551 } 552 return len; 553} 554 555__inline__ int 556objc_read_short (struct objc_typed_stream* stream, short* value) 557{ 558 unsigned char buf[sizeof(short)+1]; 559 int len; 560 if ((len = (*stream->read)(stream->physical, buf, 1))) 561 { 562 if ((buf[0] & _B_CODE) == _B_SINT) 563 (*value) = (buf[0] & _B_VALUE); 564 565 else 566 { 567 int pos = 1; 568 int nbytes = buf[0] & _B_NUMBER; 569 if (nbytes > sizeof (short)) 570 objc_error(nil, OBJC_ERR_BAD_DATA, 571 "expected short, got bigger (%dbits)", nbytes*8); 572 len = (*stream->read)(stream->physical, buf+1, nbytes); 573 (*value) = 0; 574 while (pos <= nbytes) 575 (*value) = ((*value)*0x100) + buf[pos++]; 576 if (buf[0] & _B_SIGN) 577 (*value) = -(*value); 578 } 579 } 580 return len; 581} 582 583__inline__ int 584objc_read_unsigned_short (struct objc_typed_stream* stream, 585 unsigned short* value) 586{ 587 unsigned char buf[sizeof(unsigned short)+1]; 588 int len; 589 if ((len = (*stream->read)(stream->physical, buf, 1))) 590 { 591 if ((buf[0] & _B_CODE) == _B_SINT) 592 (*value) = (buf[0] & _B_VALUE); 593 594 else 595 { 596 int pos = 1; 597 int nbytes = buf[0] & _B_NUMBER; 598 if (nbytes > sizeof (short)) 599 objc_error(nil, OBJC_ERR_BAD_DATA, 600 "expected short, got int or bigger"); 601 len = (*stream->read)(stream->physical, buf+1, nbytes); 602 (*value) = 0; 603 while (pos <= nbytes) 604 (*value) = ((*value)*0x100) + buf[pos++]; 605 } 606 } 607 return len; 608} 609 610 611__inline__ int 612objc_read_int (struct objc_typed_stream* stream, int* value) 613{ 614 unsigned char buf[sizeof(int)+1]; 615 int len; 616 if ((len = (*stream->read)(stream->physical, buf, 1))) 617 { 618 if ((buf[0] & _B_CODE) == _B_SINT) 619 (*value) = (buf[0] & _B_VALUE); 620 621 else 622 { 623 int pos = 1; 624 int nbytes = buf[0] & _B_NUMBER; 625 if (nbytes > sizeof (int)) 626 objc_error(nil, OBJC_ERR_BAD_DATA, "expected int, got bigger"); 627 len = (*stream->read)(stream->physical, buf+1, nbytes); 628 (*value) = 0; 629 while (pos <= nbytes) 630 (*value) = ((*value)*0x100) + buf[pos++]; 631 if (buf[0] & _B_SIGN) 632 (*value) = -(*value); 633 } 634 } 635 return len; 636} 637 638__inline__ int 639objc_read_long (struct objc_typed_stream* stream, long* value) 640{ 641 unsigned char buf[sizeof(long)+1]; 642 int len; 643 if ((len = (*stream->read)(stream->physical, buf, 1))) 644 { 645 if ((buf[0] & _B_CODE) == _B_SINT) 646 (*value) = (buf[0] & _B_VALUE); 647 648 else 649 { 650 int pos = 1; 651 int nbytes = buf[0] & _B_NUMBER; 652 if (nbytes > sizeof (long)) 653 objc_error(nil, OBJC_ERR_BAD_DATA, "expected long, got bigger"); 654 len = (*stream->read)(stream->physical, buf+1, nbytes); 655 (*value) = 0; 656 while (pos <= nbytes) 657 (*value) = ((*value)*0x100) + buf[pos++]; 658 if (buf[0] & _B_SIGN) 659 (*value) = -(*value); 660 } 661 } 662 return len; 663} 664 665__inline__ int 666__objc_read_nbyte_uint (struct objc_typed_stream* stream, 667 unsigned int nbytes, unsigned int* val) 668{ 669 int len, pos = 0; 670 unsigned char buf[sizeof(unsigned int)+1]; 671 672 if (nbytes > sizeof (int)) 673 objc_error(nil, OBJC_ERR_BAD_DATA, "expected int, got bigger"); 674 675 len = (*stream->read)(stream->physical, buf, nbytes); 676 (*val) = 0; 677 while (pos < nbytes) 678 (*val) = ((*val)*0x100) + buf[pos++]; 679 return len; 680} 681 682 683__inline__ int 684objc_read_unsigned_int (struct objc_typed_stream* stream, 685 unsigned int* value) 686{ 687 unsigned char buf[sizeof(unsigned int)+1]; 688 int len; 689 if ((len = (*stream->read)(stream->physical, buf, 1))) 690 { 691 if ((buf[0] & _B_CODE) == _B_SINT) 692 (*value) = (buf[0] & _B_VALUE); 693 694 else 695 len = __objc_read_nbyte_uint (stream, (buf[0] & _B_VALUE), value); 696 697 } 698 return len; 699} 700 701int 702__objc_read_nbyte_ulong (struct objc_typed_stream* stream, 703 unsigned int nbytes, unsigned long* val) 704{ 705 int len, pos = 0; 706 unsigned char buf[sizeof(unsigned long)+1]; 707 708 if (nbytes > sizeof (long)) 709 objc_error(nil, OBJC_ERR_BAD_DATA, "expected long, got bigger"); 710 711 len = (*stream->read)(stream->physical, buf, nbytes); 712 (*val) = 0; 713 while (pos < nbytes) 714 (*val) = ((*val)*0x100) + buf[pos++]; 715 return len; 716} 717 718 719__inline__ int 720objc_read_unsigned_long (struct objc_typed_stream* stream, 721 unsigned long* value) 722{ 723 unsigned char buf[sizeof(unsigned long)+1]; 724 int len; 725 if ((len = (*stream->read)(stream->physical, buf, 1))) 726 { 727 if ((buf[0] & _B_CODE) == _B_SINT) 728 (*value) = (buf[0] & _B_VALUE); 729 730 else 731 len = __objc_read_nbyte_ulong (stream, (buf[0] & _B_VALUE), value); 732 733 } 734 return len; 735} 736 737__inline__ int 738objc_read_string (struct objc_typed_stream* stream, 739 char** string) 740{ 741 unsigned char buf[sizeof(unsigned int)+1]; 742 int len; 743 if ((len = (*stream->read)(stream->physical, buf, 1))) 744 { 745 unsigned long key = 0; 746 747 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ 748 { 749 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); 750 len = (*stream->read)(stream->physical, buf, 1); 751 } 752 753 switch (buf[0]&_B_CODE) { 754 case _B_SSTR: 755 { 756 int length = buf[0]&_B_VALUE; 757 (*string) = (char*)objc_malloc(length+1); 758 if (key) 759 hash_add (&stream->stream_table, LONG2PTR(key), *string); 760 len = (*stream->read)(stream->physical, *string, length); 761 (*string)[length] = '\0'; 762 } 763 break; 764 765 case _B_UCOMM: 766 { 767 char *tmp; 768 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); 769 tmp = hash_value_for_key (stream->stream_table, LONG2PTR (key)); 770 *string = objc_malloc (strlen(tmp) + 1); 771 strcpy (*string, tmp); 772 } 773 break; 774 775 case _B_NSTR: 776 { 777 unsigned int nbytes = buf[0]&_B_VALUE; 778 len = __objc_read_nbyte_uint(stream, nbytes, &nbytes); 779 if (len) { 780 (*string) = (char*)objc_malloc(nbytes+1); 781 if (key) 782 hash_add (&stream->stream_table, LONG2PTR(key), *string); 783 len = (*stream->read)(stream->physical, *string, nbytes); 784 (*string)[nbytes] = '\0'; 785 } 786 } 787 break; 788 789 default: 790 objc_error(nil, OBJC_ERR_BAD_DATA, 791 "expected string, got opcode %c\n", (buf[0]&_B_CODE)); 792 } 793 } 794 795 return len; 796} 797 798 799int 800objc_read_object (struct objc_typed_stream* stream, id* object) 801{ 802 unsigned char buf[sizeof (unsigned int)]; 803 int len; 804 if ((len = (*stream->read)(stream->physical, buf, 1))) 805 { 806 SEL read_sel = sel_get_any_uid ("read:"); 807 unsigned long key = 0; 808 809 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register common */ 810 { 811 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); 812 len = (*stream->read)(stream->physical, buf, 1); 813 } 814 815 if (buf[0] == (_B_EXT | _BX_OBJECT)) 816 { 817 Class class; 818 819 /* get class */ 820 len = objc_read_class (stream, &class); 821 822 /* create instance */ 823 (*object) = class_create_instance(class); 824 825 /* register? */ 826 if (key) 827 hash_add (&stream->object_table, LONG2PTR(key), *object); 828 829 /* send -read: */ 830 if (__objc_responds_to (*object, read_sel)) 831 (*get_imp(class, read_sel))(*object, read_sel, stream); 832 833 /* check null-byte */ 834 len = (*stream->read)(stream->physical, buf, 1); 835 if (buf[0] != '\0') 836 objc_error(nil, OBJC_ERR_BAD_DATA, 837 "expected null-byte, got opcode %c", buf[0]); 838 } 839 840 else if ((buf[0]&_B_CODE) == _B_UCOMM) 841 { 842 if (key) 843 objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); 844 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); 845 (*object) = hash_value_for_key (stream->object_table, LONG2PTR(key)); 846 } 847 848 else if (buf[0] == (_B_EXT | _BX_OBJREF)) /* a forward reference */ 849 { 850 struct objc_list* other; 851 len = objc_read_unsigned_long (stream, &key); 852 other = (struct objc_list*)hash_value_for_key (stream->object_refs, 853 LONG2PTR(key)); 854 hash_add (&stream->object_refs, LONG2PTR(key), 855 (void*)list_cons(object, other)); 856 } 857 858 else if (buf[0] == (_B_EXT | _BX_OBJROOT)) /* a root object */ 859 { 860 if (key) 861 objc_error(nil, OBJC_ERR_BAD_KEY, 862 "cannot register root object..."); 863 len = objc_read_object (stream, object); 864 __objc_finish_read_root_object (stream); 865 } 866 867 else 868 objc_error(nil, OBJC_ERR_BAD_DATA, 869 "expected object, got opcode %c", buf[0]); 870 } 871 return len; 872} 873 874static int 875objc_read_class (struct objc_typed_stream* stream, Class* class) 876{ 877 unsigned char buf[sizeof (unsigned int)]; 878 int len; 879 if ((len = (*stream->read)(stream->physical, buf, 1))) 880 { 881 unsigned long key = 0; 882 883 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ 884 { 885 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); 886 len = (*stream->read)(stream->physical, buf, 1); 887 } 888 889 if (buf[0] == (_B_EXT | _BX_CLASS)) 890 { 891 char* class_name; 892 unsigned long version; 893 894 /* get class */ 895 len = objc_read_string (stream, &class_name); 896 (*class) = objc_get_class(class_name); 897 objc_free(class_name); 898 899 /* register */ 900 if (key) 901 hash_add (&stream->stream_table, LONG2PTR(key), *class); 902 903 objc_read_unsigned_long(stream, &version); 904 hash_add (&stream->class_table, (*class)->name, (void*)version); 905 } 906 907 else if ((buf[0]&_B_CODE) == _B_UCOMM) 908 { 909 if (key) 910 objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); 911 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); 912 (*class) = hash_value_for_key (stream->stream_table, LONG2PTR(key)); 913 if (!*class) 914 objc_error(nil, OBJC_ERR_BAD_CLASS, 915 "cannot find class for key %lu", key); 916 } 917 918 else 919 objc_error(nil, OBJC_ERR_BAD_DATA, 920 "expected class, got opcode %c", buf[0]); 921 } 922 return len; 923} 924 925int 926objc_read_selector (struct objc_typed_stream* stream, SEL* selector) 927{ 928 unsigned char buf[sizeof (unsigned int)]; 929 int len; 930 if ((len = (*stream->read)(stream->physical, buf, 1))) 931 { 932 unsigned long key = 0; 933 934 if ((buf[0]&_B_CODE) == _B_RCOMM) /* register following */ 935 { 936 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); 937 len = (*stream->read)(stream->physical, buf, 1); 938 } 939 940 if (buf[0] == (_B_EXT|_BX_SEL)) /* selector! */ 941 { 942 char* selector_name; 943 944 /* get selector */ 945 len = objc_read_string (stream, &selector_name); 946 /* To handle NULL selectors */ 947 if (0 == strlen(selector_name)) 948 { 949 (*selector) = (SEL)0; 950 return 0; 951 } 952 else 953 (*selector) = sel_get_any_uid(selector_name); 954 objc_free(selector_name); 955 956 /* register */ 957 if (key) 958 hash_add (&stream->stream_table, LONG2PTR(key), (void*)*selector); 959 } 960 961 else if ((buf[0]&_B_CODE) == _B_UCOMM) 962 { 963 if (key) 964 objc_error(nil, OBJC_ERR_BAD_KEY, "cannot register use upcode..."); 965 len = __objc_read_nbyte_ulong(stream, (buf[0] & _B_VALUE), &key); 966 (*selector) = hash_value_for_key (stream->stream_table, 967 LONG2PTR(key)); 968 } 969 970 else 971 objc_error(nil, OBJC_ERR_BAD_DATA, 972 "expected selector, got opcode %c", buf[0]); 973 } 974 return len; 975} 976 977/* 978** USER LEVEL FUNCTIONS 979*/ 980 981/* 982** Write one object, encoded in TYPE and pointed to by DATA to the 983** typed stream STREAM. 984*/ 985 986int 987objc_write_type(TypedStream* stream, const char* type, const void* data) 988{ 989 switch(*type) { 990 case _C_ID: 991 return objc_write_object (stream, *(id*)data); 992 break; 993 994 case _C_CLASS: 995 return objc_write_class (stream, *(Class*)data); 996 break; 997 998 case _C_SEL: 999 return objc_write_selector (stream, *(SEL*)data); 1000 break; 1001 1002 case _C_CHR: 1003 return objc_write_char(stream, *(signed char*)data); 1004 break; 1005 1006 case _C_UCHR: 1007 return objc_write_unsigned_char(stream, *(unsigned char*)data); 1008 break; 1009 1010 case _C_SHT: 1011 return objc_write_short(stream, *(short*)data); 1012 break; 1013 1014 case _C_USHT: 1015 return objc_write_unsigned_short(stream, *(unsigned short*)data); 1016 break; 1017 1018 case _C_INT: 1019 return objc_write_int(stream, *(int*)data); 1020 break; 1021 1022 case _C_UINT: 1023 return objc_write_unsigned_int(stream, *(unsigned int*)data); 1024 break; 1025 1026 case _C_LNG: 1027 return objc_write_long(stream, *(long*)data); 1028 break; 1029 1030 case _C_ULNG: 1031 return objc_write_unsigned_long(stream, *(unsigned long*)data); 1032 break; 1033 1034 case _C_CHARPTR: 1035 return objc_write_string (stream, *(char**)data, strlen(*(char**)data)); 1036 break; 1037 1038 case _C_ATOM: 1039 return objc_write_string_atomic (stream, *(char**)data, 1040 strlen(*(char**)data)); 1041 break; 1042 1043 case _C_ARY_B: 1044 { 1045 int len = atoi(type+1); 1046 while (isdigit(*++type)) 1047 ; 1048 return objc_write_array (stream, type, len, data); 1049 } 1050 break; 1051 1052 case _C_STRUCT_B: 1053 { 1054 int acc_size = 0; 1055 int align; 1056 while (*type != _C_STRUCT_E && *type++ != '=') 1057 ; /* skip "<name>=" */ 1058 while (*type != _C_STRUCT_E) 1059 { 1060 align = objc_alignof_type (type); /* padd to alignment */ 1061 acc_size += ROUND (acc_size, align); 1062 objc_write_type (stream, type, ((char*)data)+acc_size); 1063 acc_size += objc_sizeof_type (type); /* add component size */ 1064 type = objc_skip_typespec (type); /* skip component */ 1065 } 1066 return 1; 1067 } 1068 1069 default: 1070 { 1071 objc_error(nil, OBJC_ERR_BAD_TYPE, 1072 "objc_write_type: cannot parse typespec: %s\n", type); 1073 return 0; 1074 } 1075 } 1076} 1077 1078/* 1079** Read one object, encoded in TYPE and pointed to by DATA to the 1080** typed stream STREAM. DATA specifies the address of the types to 1081** read. Expected type is checked against the type actually present 1082** on the stream. 1083*/ 1084 1085int 1086objc_read_type(TypedStream* stream, const char* type, void* data) 1087{ 1088 char c; 1089 switch(c = *type) { 1090 case _C_ID: 1091 return objc_read_object (stream, (id*)data); 1092 break; 1093 1094 case _C_CLASS: 1095 return objc_read_class (stream, (Class*)data); 1096 break; 1097 1098 case _C_SEL: 1099 return objc_read_selector (stream, (SEL*)data); 1100 break; 1101 1102 case _C_CHR: 1103 return objc_read_char (stream, (char*)data); 1104 break; 1105 1106 case _C_UCHR: 1107 return objc_read_unsigned_char (stream, (unsigned char*)data); 1108 break; 1109 1110 case _C_SHT: 1111 return objc_read_short (stream, (short*)data); 1112 break; 1113 1114 case _C_USHT: 1115 return objc_read_unsigned_short (stream, (unsigned short*)data); 1116 break; 1117 1118 case _C_INT: 1119 return objc_read_int (stream, (int*)data); 1120 break; 1121 1122 case _C_UINT: 1123 return objc_read_unsigned_int (stream, (unsigned int*)data); 1124 break; 1125 1126 case _C_LNG: 1127 return objc_read_long (stream, (long*)data); 1128 break; 1129 1130 case _C_ULNG: 1131 return objc_read_unsigned_long (stream, (unsigned long*)data); 1132 break; 1133 1134 case _C_CHARPTR: 1135 case _C_ATOM: 1136 return objc_read_string (stream, (char**)data); 1137 break; 1138 1139 case _C_ARY_B: 1140 { 1141 int len = atoi(type+1); 1142 while (isdigit(*++type)) 1143 ; 1144 return objc_read_array (stream, type, len, data); 1145 } 1146 break; 1147 1148 case _C_STRUCT_B: 1149 { 1150 int acc_size = 0; 1151 int align; 1152 while (*type != _C_STRUCT_E && *type++ != '=') 1153 ; /* skip "<name>=" */ 1154 while (*type != _C_STRUCT_E) 1155 { 1156 align = objc_alignof_type (type); /* padd to alignment */ 1157 acc_size += ROUND (acc_size, align); 1158 objc_read_type (stream, type, ((char*)data)+acc_size); 1159 acc_size += objc_sizeof_type (type); /* add component size */ 1160 type = objc_skip_typespec (type); /* skip component */ 1161 } 1162 return 1; 1163 } 1164 1165 default: 1166 { 1167 objc_error(nil, OBJC_ERR_BAD_TYPE, 1168 "objc_read_type: cannot parse typespec: %s\n", type); 1169 return 0; 1170 } 1171 } 1172} 1173 1174/* 1175** Write the object specified by the template TYPE to STREAM. Last 1176** arguments specify addresses of values to be written. It might 1177** seem surprising to specify values by address, but this is extremely 1178** convenient for copy-paste with objc_read_types calls. A more 1179** down-to-the-earth cause for this passing of addresses is that values 1180** of arbitrary size is not well supported in ANSI C for functions with 1181** variable number of arguments. 1182*/ 1183 1184int 1185objc_write_types (TypedStream* stream, const char* type, ...) 1186{ 1187 va_list args; 1188 const char *c; 1189 int res = 0; 1190 1191 va_start(args, type); 1192 1193 for (c = type; *c; c = objc_skip_typespec (c)) 1194 { 1195 switch(*c) { 1196 case _C_ID: 1197 res = objc_write_object (stream, *va_arg (args, id*)); 1198 break; 1199 1200 case _C_CLASS: 1201 res = objc_write_class (stream, *va_arg(args, Class*)); 1202 break; 1203 1204 case _C_SEL: 1205 res = objc_write_selector (stream, *va_arg(args, SEL*)); 1206 break; 1207 1208 case _C_CHR: 1209 res = objc_write_char (stream, *va_arg (args, char*)); 1210 break; 1211 1212 case _C_UCHR: 1213 res = objc_write_unsigned_char (stream, 1214 *va_arg (args, unsigned char*)); 1215 break; 1216 1217 case _C_SHT: 1218 res = objc_write_short (stream, *va_arg(args, short*)); 1219 break; 1220 1221 case _C_USHT: 1222 res = objc_write_unsigned_short (stream, 1223 *va_arg(args, unsigned short*)); 1224 break; 1225 1226 case _C_INT: 1227 res = objc_write_int(stream, *va_arg(args, int*)); 1228 break; 1229 1230 case _C_UINT: 1231 res = objc_write_unsigned_int(stream, *va_arg(args, unsigned int*)); 1232 break; 1233 1234 case _C_LNG: 1235 res = objc_write_long(stream, *va_arg(args, long*)); 1236 break; 1237 1238 case _C_ULNG: 1239 res = objc_write_unsigned_long(stream, *va_arg(args, unsigned long*)); 1240 break; 1241 1242 case _C_CHARPTR: 1243 { 1244 char** str = va_arg(args, char**); 1245 res = objc_write_string (stream, *str, strlen(*str)); 1246 } 1247 break; 1248 1249 case _C_ATOM: 1250 { 1251 char** str = va_arg(args, char**); 1252 res = objc_write_string_atomic (stream, *str, strlen(*str)); 1253 } 1254 break; 1255 1256 case _C_ARY_B: 1257 { 1258 int len = atoi(c+1); 1259 const char* t = c; 1260 while (isdigit(*++t)) 1261 ; 1262 res = objc_write_array (stream, t, len, va_arg(args, void*)); 1263 t = objc_skip_typespec (t); 1264 if (*t != _C_ARY_E) 1265 objc_error(nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t); 1266 } 1267 break; 1268 1269 default: 1270 objc_error(nil, OBJC_ERR_BAD_TYPE, 1271 "objc_write_types: cannot parse typespec: %s\n", type); 1272 } 1273 } 1274 va_end(args); 1275 return res; 1276} 1277 1278 1279/* 1280** Last arguments specify addresses of values to be read. Expected 1281** type is checked against the type actually present on the stream. 1282*/ 1283 1284int 1285objc_read_types(TypedStream* stream, const char* type, ...) 1286{ 1287 va_list args; 1288 const char *c; 1289 int res = 0; 1290 1291 va_start(args, type); 1292 1293 for (c = type; *c; c = objc_skip_typespec(c)) 1294 { 1295 switch(*c) { 1296 case _C_ID: 1297 res = objc_read_object(stream, va_arg(args, id*)); 1298 break; 1299 1300 case _C_CLASS: 1301 res = objc_read_class(stream, va_arg(args, Class*)); 1302 break; 1303 1304 case _C_SEL: 1305 res = objc_read_selector(stream, va_arg(args, SEL*)); 1306 break; 1307 1308 case _C_CHR: 1309 res = objc_read_char(stream, va_arg(args, char*)); 1310 break; 1311 1312 case _C_UCHR: 1313 res = objc_read_unsigned_char(stream, va_arg(args, unsigned char*)); 1314 break; 1315 1316 case _C_SHT: 1317 res = objc_read_short(stream, va_arg(args, short*)); 1318 break; 1319 1320 case _C_USHT: 1321 res = objc_read_unsigned_short(stream, va_arg(args, unsigned short*)); 1322 break; 1323 1324 case _C_INT: 1325 res = objc_read_int(stream, va_arg(args, int*)); 1326 break; 1327 1328 case _C_UINT: 1329 res = objc_read_unsigned_int(stream, va_arg(args, unsigned int*)); 1330 break; 1331 1332 case _C_LNG: 1333 res = objc_read_long(stream, va_arg(args, long*)); 1334 break; 1335 1336 case _C_ULNG: 1337 res = objc_read_unsigned_long(stream, va_arg(args, unsigned long*)); 1338 break; 1339 1340 case _C_CHARPTR: 1341 case _C_ATOM: 1342 { 1343 char** str = va_arg(args, char**); 1344 res = objc_read_string (stream, str); 1345 } 1346 break; 1347 1348 case _C_ARY_B: 1349 { 1350 int len = atoi(c+1); 1351 const char* t = c; 1352 while (isdigit(*++t)) 1353 ; 1354 res = objc_read_array (stream, t, len, va_arg(args, void*)); 1355 t = objc_skip_typespec (t); 1356 if (*t != _C_ARY_E) 1357 objc_error(nil, OBJC_ERR_BAD_TYPE, "expected `]', got: %s", t); 1358 } 1359 break; 1360 1361 default: 1362 objc_error(nil, OBJC_ERR_BAD_TYPE, 1363 "objc_read_types: cannot parse typespec: %s\n", type); 1364 } 1365 } 1366 va_end(args); 1367 return res; 1368} 1369 1370/* 1371** Write an array of COUNT elements of TYPE from the memory address DATA. 1372** This is equivalent of objc_write_type (stream, "[N<type>]", data) 1373*/ 1374 1375int 1376objc_write_array (TypedStream* stream, const char* type, 1377 int count, const void* data) 1378{ 1379 int off = objc_sizeof_type(type); 1380 const char* where = data; 1381 1382 while (count-- > 0) 1383 { 1384 objc_write_type(stream, type, where); 1385 where += off; 1386 } 1387 return 1; 1388} 1389 1390/* 1391** Read an array of COUNT elements of TYPE into the memory address 1392** DATA. The memory pointed to by data is supposed to be allocated 1393** by the callee. This is equivalent of 1394** objc_read_type (stream, "[N<type>]", data) 1395*/ 1396 1397int 1398objc_read_array (TypedStream* stream, const char* type, 1399 int count, void* data) 1400{ 1401 int off = objc_sizeof_type(type); 1402 char* where = (char*)data; 1403 1404 while (count-- > 0) 1405 { 1406 objc_read_type(stream, type, where); 1407 where += off; 1408 } 1409 return 1; 1410} 1411 1412static int 1413__objc_fread(FILE* file, char* data, int len) 1414{ 1415 return fread(data, len, 1, file); 1416} 1417 1418static int 1419__objc_fwrite(FILE* file, char* data, int len) 1420{ 1421 return fwrite(data, len, 1, file); 1422} 1423 1424static int 1425__objc_feof(FILE* file) 1426{ 1427 return feof(file); 1428} 1429 1430static int 1431__objc_no_write(FILE* file, char* data, int len) 1432{ 1433 objc_error (nil, OBJC_ERR_NO_WRITE, "TypedStream not open for writing"); 1434 return 0; 1435} 1436 1437static int 1438__objc_no_read(FILE* file, char* data, int len) 1439{ 1440 objc_error (nil, OBJC_ERR_NO_READ, "TypedStream not open for reading"); 1441 return 0; 1442} 1443 1444static int 1445__objc_read_typed_stream_signature (TypedStream* stream) 1446{ 1447 char buffer[80]; 1448 int pos = 0; 1449 do 1450 (*stream->read)(stream->physical, buffer+pos, 1); 1451 while (buffer[pos++] != '\0') 1452 ; 1453 sscanf (buffer, "GNU TypedStream %d", &stream->version); 1454 if (stream->version != OBJC_TYPED_STREAM_VERSION) 1455 objc_error (nil, OBJC_ERR_STREAM_VERSION, 1456 "cannot handle TypedStream version %d", stream->version); 1457 return 1; 1458} 1459 1460static int 1461__objc_write_typed_stream_signature (TypedStream* stream) 1462{ 1463 char buffer[80]; 1464 sprintf(buffer, "GNU TypedStream %d", OBJC_TYPED_STREAM_VERSION); 1465 stream->version = OBJC_TYPED_STREAM_VERSION; 1466 (*stream->write)(stream->physical, buffer, strlen(buffer)+1); 1467 return 1; 1468} 1469 1470static void __objc_finish_write_root_object(struct objc_typed_stream* stream) 1471{ 1472 hash_delete (stream->object_table); 1473 stream->object_table = hash_new(64, 1474 (hash_func_type)hash_ptr, 1475 (compare_func_type)compare_ptrs); 1476} 1477 1478static void __objc_finish_read_root_object(struct objc_typed_stream* stream) 1479{ 1480 node_ptr node; 1481 SEL awake_sel = sel_get_any_uid ("awake"); 1482 cache_ptr free_list = hash_new (64, 1483 (hash_func_type) hash_ptr, 1484 (compare_func_type) compare_ptrs); 1485 1486 /* resolve object forward references */ 1487 for (node = hash_next (stream->object_refs, NULL); node; 1488 node = hash_next (stream->object_refs, node)) 1489 { 1490 struct objc_list* reflist = node->value; 1491 const void* key = node->key; 1492 id object = hash_value_for_key (stream->object_table, key); 1493 while(reflist) 1494 { 1495 *((id*)reflist->head) = object; 1496 if (hash_value_for_key (free_list,reflist) == NULL) 1497 hash_add (&free_list,reflist,reflist); 1498 1499 reflist = reflist->tail; 1500 } 1501 } 1502 1503 /* apply __objc_free to all objects stored in free_list */ 1504 for (node = hash_next (free_list, NULL); node; 1505 node = hash_next (free_list, node)) 1506 objc_free ((void *) node->key); 1507 1508 hash_delete (free_list); 1509 1510 /* empty object reference table */ 1511 hash_delete (stream->object_refs); 1512 stream->object_refs = hash_new(8, (hash_func_type)hash_ptr, 1513 (compare_func_type)compare_ptrs); 1514 1515 /* call -awake for all objects read */ 1516 if (awake_sel) 1517 { 1518 for (node = hash_next (stream->object_table, NULL); node; 1519 node = hash_next (stream->object_table, node)) 1520 { 1521 id object = node->value; 1522 if (__objc_responds_to (object, awake_sel)) 1523 (*objc_msg_lookup(object, awake_sel))(object, awake_sel); 1524 } 1525 } 1526 1527 /* empty object table */ 1528 hash_delete (stream->object_table); 1529 stream->object_table = hash_new(64, 1530 (hash_func_type)hash_ptr, 1531 (compare_func_type)compare_ptrs); 1532} 1533 1534/* 1535** Open the stream PHYSICAL in MODE 1536*/ 1537 1538TypedStream* 1539objc_open_typed_stream (FILE* physical, int mode) 1540{ 1541 TypedStream* s = (TypedStream*)objc_malloc(sizeof(TypedStream)); 1542 1543 s->mode = mode; 1544 s->physical = physical; 1545 s->stream_table = hash_new(64, 1546 (hash_func_type)hash_ptr, 1547 (compare_func_type)compare_ptrs); 1548 s->object_table = hash_new(64, 1549 (hash_func_type)hash_ptr, 1550 (compare_func_type)compare_ptrs); 1551 s->eof = (objc_typed_eof_func)__objc_feof; 1552 s->flush = (objc_typed_flush_func)fflush; 1553 s->writing_root_p = 0; 1554 if (mode == OBJC_READONLY) 1555 { 1556 s->class_table = hash_new(8, (hash_func_type)hash_string, 1557 (compare_func_type)compare_strings); 1558 s->object_refs = hash_new(8, (hash_func_type)hash_ptr, 1559 (compare_func_type)compare_ptrs); 1560 s->read = (objc_typed_read_func)__objc_fread; 1561 s->write = (objc_typed_write_func)__objc_no_write; 1562 __objc_read_typed_stream_signature (s); 1563 } 1564 else if (mode == OBJC_WRITEONLY) 1565 { 1566 s->class_table = 0; 1567 s->object_refs = 0; 1568 s->read = (objc_typed_read_func)__objc_no_read; 1569 s->write = (objc_typed_write_func)__objc_fwrite; 1570 __objc_write_typed_stream_signature (s); 1571 } 1572 else 1573 { 1574 objc_close_typed_stream (s); 1575 return NULL; 1576 } 1577 s->type = OBJC_FILE_STREAM; 1578 return s; 1579} 1580 1581/* 1582** Open the file named by FILE_NAME in MODE 1583*/ 1584 1585TypedStream* 1586objc_open_typed_stream_for_file (const char* file_name, int mode) 1587{ 1588 FILE* file = NULL; 1589 TypedStream* s; 1590 1591 if (mode == OBJC_READONLY) 1592 file = fopen (file_name, "r"); 1593 else 1594 file = fopen (file_name, "w"); 1595 1596 if (file) 1597 { 1598 s = objc_open_typed_stream (file, mode); 1599 if (s) 1600 s->type |= OBJC_MANAGED_STREAM; 1601 return s; 1602 } 1603 else 1604 return NULL; 1605} 1606 1607/* 1608** Close STREAM freeing the structure it self. If it was opened with 1609** objc_open_typed_stream_for_file, the file will also be closed. 1610*/ 1611 1612void 1613objc_close_typed_stream (TypedStream* stream) 1614{ 1615 if (stream->mode == OBJC_READONLY) 1616 { 1617 __objc_finish_read_root_object (stream); /* Just in case... */ 1618 hash_delete (stream->class_table); 1619 hash_delete (stream->object_refs); 1620 } 1621 1622 hash_delete (stream->stream_table); 1623 hash_delete (stream->object_table); 1624 1625 if (stream->type == (OBJC_MANAGED_STREAM | OBJC_FILE_STREAM)) 1626 fclose ((FILE*)stream->physical); 1627 1628 objc_free(stream); 1629} 1630 1631BOOL 1632objc_end_of_typed_stream (TypedStream* stream) 1633{ 1634 return (*stream->eof)(stream->physical); 1635} 1636 1637void 1638objc_flush_typed_stream (TypedStream* stream) 1639{ 1640 (*stream->flush)(stream->physical); 1641} 1642 1643long 1644objc_get_stream_class_version (TypedStream* stream, Class class) 1645{ 1646 if (stream->class_table) 1647 return PTR2LONG(hash_value_for_key (stream->class_table, class->name)); 1648 else 1649 return class_get_version (class); 1650} 1651 1652