1/** Implementation of NSUnarchiver for GNUstep 2 Copyright (C) 1998 Free Software Foundation, Inc. 3 4 Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk> 5 Created: October 1998 6 7 This file is part of the GNUstep Base Library. 8 9 This library is free software; you can redistribute it and/or 10 modify it under the terms of the GNU Lesser General Public 11 License as published by the Free Software Foundation; either 12 version 2 of the License, or (at your option) any later version. 13 14 This library is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 Lesser General Public License for more details. 18 19 You should have received a copy of the GNU Lesser General Public 20 License along with this library; if not, write to the Free 21 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 22 Boston, MA 02110 USA. 23 24 <title>NSUnarchiver class reference</title> 25 $Date$ $Revision$ 26 */ 27 28#import "common.h" 29 30#if !defined (__GNU_LIBOBJC__) 31# include <objc/encoding.h> 32#endif 33 34#define EXPOSE_NSUnarchiver_IVARS 1 35#import "Foundation/NSDictionary.h" 36#import "Foundation/NSException.h" 37#import "Foundation/NSByteOrder.h" 38 39/* 40 * Setup for inline operation of arrays. 41 */ 42#define GSI_ARRAY_NO_RETAIN 1 43#define GSI_ARRAY_NO_RELEASE 1 44#define GSI_ARRAY_TYPES GSUNION_OBJ|GSUNION_SEL|GSUNION_PTR 45 46#include "GNUstepBase/GSIArray.h" 47 48#define _IN_NSUNARCHIVER_M 49#import "Foundation/NSArchiver.h" 50#undef _IN_NSUNARCHIVER_M 51 52#import "Foundation/NSAutoreleasePool.h" 53#import "Foundation/NSCoder.h" 54#import "Foundation/NSData.h" 55#import "Foundation/NSArray.h" 56 57@class NSDataMalloc; 58@interface NSDataMalloc : NSObject // Help the compiler 59@end 60 61static const char* 62typeToName1(char type) 63{ 64 switch (type) 65 { 66 case _C_CLASS: return "class"; 67 case _C_ID: return "object"; 68 case _C_SEL: return "selector"; 69 case _C_CHR: return "char"; 70 case _C_UCHR: return "unsigned char"; 71 case _C_SHT: return "short"; 72 case _C_USHT: return "unsigned short"; 73 case _C_INT: return "int"; 74 case _C_UINT: return "unsigned int"; 75 case _C_LNG: return "long"; 76 case _C_ULNG: return "unsigned long"; 77 case _C_LNG_LNG: return "long long"; 78 case _C_ULNG_LNG: return "unsigned long long"; 79 case _C_FLT: return "float"; 80 case _C_DBL: return "double"; 81#if __GNUC__ > 2 && defined(_C_BOOL) 82 case _C_BOOL: return "_Bool"; 83#endif 84 case _C_PTR: return "pointer"; 85 case _C_CHARPTR: return "cstring"; 86 case _C_ARY_B: return "array"; 87 case _C_STRUCT_B: return "struct"; 88 default: 89 { 90 static char buf1[32]; 91 static char buf2[32]; 92 static char *bufptr = buf1; 93 94 if (bufptr == buf1) 95 { 96 bufptr = buf2; 97 } 98 else 99 { 100 bufptr = buf1; 101 } 102 snprintf(bufptr, 32, "unknown type info - 0x%x", type); 103 return bufptr; 104 } 105 } 106} 107 108static const char* 109typeToName2(char type) 110{ 111 switch (type & _GSC_MASK) 112 { 113 case _GSC_CID: return "class (encoded as id)"; 114 case _GSC_CLASS: return "class"; 115 case _GSC_ID: return "object"; 116 case _GSC_SEL: return "selector"; 117 case _GSC_CHR: return "char"; 118 case _GSC_UCHR: return "unsigned char"; 119 case _GSC_SHT: return "short"; 120 case _GSC_USHT: return "unsigned short"; 121 case _GSC_INT: return "int"; 122 case _GSC_UINT: return "unsigned int"; 123 case _GSC_LNG: return "long"; 124 case _GSC_ULNG: return "unsigned long"; 125 case _GSC_LNG_LNG: return "long long"; 126 case _GSC_ULNG_LNG: return "unsigned long long"; 127 case _GSC_FLT: return "float"; 128 case _GSC_DBL: return "double"; 129 case _GSC_BOOL: return "_Bool"; 130 case _GSC_PTR: return "pointer"; 131 case _GSC_CHARPTR: return "cstring"; 132 case _GSC_ARY_B: return "array"; 133 case _GSC_STRUCT_B: return "struct"; 134 default: 135 { 136 static char buf1[32]; 137 static char buf2[32]; 138 static char *bufptr = buf1; 139 140 if (bufptr == buf1) 141 { 142 bufptr = buf2; 143 } 144 else 145 { 146 bufptr = buf1; 147 } 148 snprintf(bufptr, 32, "unknown type info - 0x%x", type); 149 return bufptr; 150 } 151 } 152} 153 154/* 155 * There are thirtyone possible basic types. We reserve a type of zero 156 * to mean that no information is specified. The slots in this array 157 * MUST correspond to the definitions in NSData.h 158 */ 159static char type_map[32] = { 160 0, 161 _C_CHR, 162 _C_UCHR, 163 _C_SHT, 164 _C_USHT, 165 _C_INT, 166 _C_UINT, 167 _C_LNG, 168 _C_ULNG, 169 _C_LNG_LNG, 170 _C_ULNG_LNG, 171 _C_FLT, 172 _C_DBL, 173#if __GNUC__ > 2 && defined(_C_BOOL) 174 _C_BOOL, 175#else 176 0, 177#endif 178 0, 179 0, 180 _C_ID, 181 _C_CLASS, 182 _C_SEL, 183 _C_PTR, 184 _C_CHARPTR, 185 _C_ARY_B, 186 _C_STRUCT_B, 187 0, 188 0, 189 0, 190 0, 191 0, 192 0, 193 0, 194 0, 195 0 196}; 197 198 199static inline BOOL 200typeCheck(char t1, char t2) 201{ 202 if (type_map[(t2 & _GSC_MASK)] != t1) 203 { 204/* 205 * HACK ... allow int/long/longlong types to be used interchangably 206 * as the ObjC compiler currently uses quadword (q/Q) encoding for 207 * integer types on some 64bit systems, so the i/l/q/I/L/Q encodings 208 * can vary. 209 */ 210 char c = type_map[(t2 & _GSC_MASK)]; 211 char s1; 212 char s2; 213 214 switch (t1) 215 { 216 case _C_SHT: s1 = _GSC_S_SHT; break; 217 case _C_USHT: s1 = _GSC_S_SHT; break; 218 case _C_INT: s1 = _GSC_S_INT; break; 219 case _C_UINT: s1 = _GSC_S_INT; break; 220 case _C_LNG: s1 = _GSC_S_LNG; break; 221 case _C_ULNG: s1 = _GSC_S_LNG; break; 222 case _C_LNG_LNG: s1 = _GSC_S_LNG_LNG; break; 223 case _C_ULNG_LNG: s1 = _GSC_S_LNG_LNG; break; 224 default: s1 = 0; 225 } 226 227 switch (t2) 228 { 229 case _C_SHT: s2 = _GSC_S_SHT; break; 230 case _C_USHT: s2 = _GSC_S_SHT; break; 231 case _C_INT: s2 = _GSC_S_INT; break; 232 case _C_UINT: s2 = _GSC_S_INT; break; 233 case _C_LNG: s2 = _GSC_S_LNG; break; 234 case _C_ULNG: s2 = _GSC_S_LNG; break; 235 case _C_LNG_LNG: s2 = _GSC_S_LNG_LNG; break; 236 case _C_ULNG_LNG: s2 = _GSC_S_LNG_LNG; break; 237 default: s2 = 0; 238 } 239 240 if ((c == _C_INT || c == _C_LNG || c == _C_LNG_LNG) 241 && (t1 == _C_INT || t1 == _C_LNG || t1 == _C_LNG_LNG)) 242 return s1 == s2 ? YES : NO; 243 244 if ((c == _C_UINT || c == _C_ULNG || c == _C_ULNG_LNG) 245 && (t1 == _C_UINT || t1 == _C_ULNG || t1 == _C_ULNG_LNG)) 246 return s1 == s2 ? YES : NO; 247 248/* HACK also allow float and double to be used interchangably as MacOS-X 249 * intorduced CGFloat, which may be aither a float or a double. 250 */ 251 if ((c == _C_FLT || c == _C_DBL) && (t1 == _C_FLT || t1 == _C_DBL)) 252 return NO; 253 254 [NSException raise: NSInternalInconsistencyException 255 format: @"expected %s and got %s", 256 typeToName1(t1), typeToName2(t2)]; 257 } 258 return YES; 259} 260 261#define PREFIX "GNUstep archive" 262 263static SEL desSel; 264static SEL tagSel; 265static SEL dValSel; 266 267@interface NSUnarchiverClassInfo : NSObject 268{ 269@public 270 NSString *original; 271 NSString *name; 272 Class class; 273} 274+ (id) newWithName: (NSString*)n; 275- (void) mapToClass: (Class)c withName: (NSString*)name; 276@end 277 278@implementation NSUnarchiverClassInfo 279+ (id) newWithName: (NSString*)n 280{ 281 NSUnarchiverClassInfo *info; 282 283 info = (NSUnarchiverClassInfo*)NSAllocateObject(self,0,NSDefaultMallocZone()); 284 if (info) 285 { 286 info->original = [n copyWithZone: NSDefaultMallocZone()]; 287 } 288 return info; 289} 290- (void) dealloc 291{ 292 RELEASE(original); 293 if (name) 294 { 295 RELEASE(name); 296 } 297 NSDeallocateObject(self); 298 GSNOSUPERDEALLOC; 299} 300- (void) mapToClass: (Class)c withName: (NSString*)n 301{ 302 ASSIGN(name, n); 303 class = c; 304} 305@end 306 307/* 308 * Dictionary used by NSUnarchiver class to keep track of 309 * NSUnarchiverClassInfo objects used to map classes by name when 310 * unarchiving. 311 */ 312static NSMutableDictionary *clsDict; /* Class information */ 313 314@interface NSUnarchiverObjectInfo : NSUnarchiverClassInfo 315{ 316@public 317 NSInteger version; 318 NSUnarchiverClassInfo *overrides; 319} 320@end 321 322static inline Class 323mapClassObject(NSUnarchiverObjectInfo *info) 324{ 325 if (info->overrides == nil) 326 { 327 info->overrides = [clsDict objectForKey: info->original]; 328 } 329 if (info->overrides) 330 { 331 return info->overrides->class; 332 } 333 else 334 { 335 return info->class; 336 } 337} 338 339static inline NSString* 340mapClassName(NSUnarchiverObjectInfo *info) 341{ 342 if (info->overrides == nil) 343 { 344 info->overrides = [clsDict objectForKey: info->original]; 345 } 346 if (info->overrides) 347 { 348 return info->overrides->name; 349 } 350 else 351 { 352 return info->name; 353 } 354} 355 356@implementation NSUnarchiverObjectInfo 357@end 358 359/** 360 * <p>This class reconstructs objects from an archive.</p><br /> 361 * <strong>Re-using the archiver</strong> 362 * <p> 363 * The -resetUnarchiverWithData:atIndex: method lets you re-use 364 * the archive to decode a new data object or, in conjunction 365 * with the 'cursor' method (which reports the current decoding 366 * position in the archive), decode a second archive that exists 367 * in the data object after the first one. 368 * </p> 369 * <strong>Subclassing with different input format.</strong><br /><br /> 370 * <code>NSUnarchiver</code> normally reads directly from an [NSData] 371 * object using the methods - 372 * <deflist> 373 * <term>-deserializeTypeTag:andCrossRef:atCursor:</term> 374 * <desc> 375 * to decode type tags for data items, the tag is the 376 * first byte of the character encoding string for the 377 * data type (as provided by '@encode(xxx)'), possibly 378 * with the top bit set to indicate that what follows is 379 * a crossreference to an item already encoded.<br /> 380 * Also decode a crossreference number either to identify the 381 * following item, or to refer to a previously encoded item. 382 * Objects, Classes, Selectors, CStrings and Pointer items 383 * have crossreference encoding, other types do not.<br /> 384 * </desc> 385 * <term>[NSData-deserializeDataAt:ofObjCType:atCursor:context:]</term> 386 * <desc> 387 * to decode all other information. 388 * </desc> 389 * </deflist> 390 * <p> 391 * <code>NSUnarchiver</code> normally uses other [NSData] methods to read 392 * the archive header information from within the method: 393 * [-deserializeHeaderAt:version:classes:objects:pointers:] 394 * to read a fixed size header including archiver version 395 * (obtained by <code>[self systemVersion]</code>) and crossreference 396 * table sizes. 397 * </p> 398 * <p> 399 * To subclass <code>NSUnarchiver</code>, you must implement your own 400 * versions of the four methods above, and override the 'directDataAccess' 401 * method to return NO so that the archiver knows to use your serialization 402 * methods rather than those in the [NSData] object. 403 * </p> 404 */ 405@implementation NSUnarchiver 406 407static Class NSDataMallocClass; 408static unsigned encodingVersion; 409 410+ (void) initialize 411{ 412 if ([self class] == [NSUnarchiver class]) 413 { 414 NSArchiver *archiver = [NSArchiver new]; 415 416 encodingVersion = [archiver systemVersion]; 417 [archiver release]; 418 desSel = @selector(deserializeDataAt:ofObjCType:atCursor:context:); 419 tagSel = @selector(deserializeTypeTag:andCrossRef:atCursor:); 420 dValSel = @selector(decodeValueOfObjCType:at:); 421 clsDict = [[NSMutableDictionary alloc] initWithCapacity: 200]; 422 NSDataMallocClass = [NSDataMalloc class]; 423 424 } 425} 426 427/** 428 * Creates an NSUnarchiver to read from anObject and returns result of sending 429 * [NSCoder -decodeObject] to it. 430 */ 431+ (id) unarchiveObjectWithData: (NSData*)anObject 432{ 433 NSUnarchiver *unarchiver; 434 id obj; 435 436 unarchiver = [[self alloc] initForReadingWithData: anObject]; 437 NS_DURING 438 { 439 obj = [unarchiver decodeObject]; 440 } 441 NS_HANDLER 442 { 443 obj = nil; 444 RELEASE(unarchiver); 445 [localException raise]; 446 } 447 NS_ENDHANDLER 448 RELEASE(unarchiver); 449 450 return obj; 451} 452 453/** 454 * Creates an NSUnarchiver to read from path and returns result of sending 455 * [NSCoder -decodeObject] to it. 456 */ 457+ (id) unarchiveObjectWithFile: (NSString*)path 458{ 459 NSData *d = [NSDataMallocClass dataWithContentsOfFile: path]; 460 461 if (d != nil) 462 { 463 return [self unarchiveObjectWithData: d]; 464 } 465 return nil; 466} 467 468- (void) dealloc 469{ 470 RELEASE(data); 471 RELEASE(objSave); 472 RELEASE(objDict); 473 if (clsMap) 474 { 475 NSZone *z = clsMap->zone; 476 477 GSIArrayClear(clsMap); 478 GSIArrayClear(objMap); 479 GSIArrayClear(ptrMap); 480 NSZoneFree(z, (void*)clsMap); 481 } 482 [super dealloc]; 483} 484 485/** 486 * Set up to read objects from data buffer anObject. 487 */ 488- (id) initForReadingWithData: (NSData*)anObject 489{ 490 if (anObject == nil) 491 { 492 [NSException raise: NSInvalidArgumentException 493 format: @"nil data passed to initForReadingWithData:"]; 494 } 495 496 self = [super init]; 497 if (self) 498 { 499 dValImp = [self methodForSelector: dValSel]; 500 zone = [self zone]; 501 /* 502 * If we are not deserializing directly from the data object 503 * then we cache our own deserialisation methods. 504 */ 505 if ([self directDataAccess] == NO) 506 { 507 src = self; /* Default object to handle serialisation */ 508 desImp = [src methodForSelector: desSel]; 509 tagImp = (void (*)(id, SEL, unsigned char*, unsigned*, unsigned*)) 510 [src methodForSelector: tagSel]; 511 } 512 /* 513 * objDict is a dictionary of objects for mapping classes of 514 * one name to be those of another name! It also handles 515 * keeping track of the version numbers that the classes were 516 * encoded with. 517 */ 518 objDict = [[NSMutableDictionary allocWithZone: zone] 519 initWithCapacity: 200]; 520 /* 521 * objSave is an array used purely to ensure that objects 522 * we decode persist until the end of the decoding. 523 */ 524 objSave = [[NSMutableArray allocWithZone: zone] 525 initWithCapacity: 200]; 526 527 NS_DURING 528 { 529 [self resetUnarchiverWithData: anObject atIndex: 0]; 530 } 531 NS_HANDLER 532 { 533 DESTROY(self); 534 [localException raise]; 535 } 536 NS_ENDHANDLER 537 } 538 return self; 539} 540 541- (void) decodeArrayOfObjCType: (const char*)type 542 count: (NSUInteger)expected 543 at: (void*)buf 544{ 545 NSUInteger i; 546 NSUInteger offset = 0; 547 unsigned int size = (unsigned int)objc_sizeof_type(type); 548 unsigned char info; 549 unsigned char ainfo; 550 unsigned char amask; 551 NSUInteger count; 552 553 (*tagImp)(src, tagSel, &info, 0, &cursor); 554 if ([self systemVersion] == 12402) 555 { 556 uint8_t c; 557 558 /* Unpack variable length count. 559 */ 560 count = 0; 561 for (;;) 562 { 563 if (count * 128 < count) 564 { 565 [NSException raise: NSInternalInconsistencyException 566 format: @"overflow in array count"]; 567 } 568 count *= 128; 569 (*desImp)(src, desSel, &c, @encode(uint8_t), &cursor, nil); 570 if (c & 128) 571 { 572 count += (c & 127); 573 } 574 else 575 { 576 count += c; 577 break; 578 } 579 } 580 } 581 else 582 { 583 uint32_t c; 584 585 (*desImp)(src, desSel, &c, @encode(uint32_t), &cursor, nil); 586 count = c; 587 if (0xffffffff == c) 588 { 589 (*desImp)(src, desSel, &count, @encode(NSUInteger), &cursor, nil); 590 } 591 } 592 if (info != _GSC_ARY_B) 593 { 594 [NSException raise: NSInternalInconsistencyException 595 format: @"expected array and got %s", typeToName2(info)]; 596 } 597 if (count != expected) 598 { 599 [NSException raise: NSInternalInconsistencyException 600 format: @"expected array count %"PRIuPTR" and got %"PRIuPTR"", 601 expected, count]; 602 } 603 604 switch (*type) 605 { 606 case _C_ID: info = _GSC_NONE; break; 607 case _C_CHR: info = _GSC_CHR; break; 608 case _C_UCHR: info = _GSC_UCHR; break; 609 case _C_SHT: info = _GSC_SHT; break; 610 case _C_USHT: info = _GSC_USHT; break; 611 case _C_INT: info = _GSC_INT; break; 612 case _C_UINT: info = _GSC_UINT; break; 613 case _C_LNG: info = _GSC_LNG; break; 614 case _C_ULNG: info = _GSC_ULNG; break; 615 case _C_LNG_LNG: info = _GSC_LNG_LNG; break; 616 case _C_ULNG_LNG: info = _GSC_ULNG_LNG; break; 617 case _C_FLT: info = _GSC_FLT; break; 618 case _C_DBL: info = _GSC_DBL; break; 619#if __GNUC__ > 2 && defined(_C_BOOL) 620 case _C_BOOL: info = _GSC_BOOL; break; 621#endif 622 default: info = _GSC_NONE; break; 623 } 624 625 if (info == _GSC_NONE) 626 { 627 for (i = 0; i < count; i++) 628 { 629 (*dValImp)(self, dValSel, type, (char*)buf + offset); 630 offset += size; 631 } 632 return; 633 } 634 635 (*tagImp)(src, tagSel, &ainfo, 0, &cursor); 636 amask = (ainfo & _GSC_MASK); 637 638 /* If we have a perfect type match or we are coding a class as an ID, 639 * we can just decode the array simply. 640 */ 641 if (info == amask) 642 { 643 for (i = 0; i < count; i++) 644 { 645 (*desImp)(src, desSel, (char*)buf + offset, type, &cursor, nil); 646 offset += size; 647 } 648 return; 649 } 650 651 /* This will raise an exception if the types don't match at all. 652 */ 653 typeCheck(*type, ainfo); 654 655 /* We fall through to here only when we have to decode a value 656 * whose natural size on this system is not the same as on the 657 * machine on which the archive was created. 658 */ 659 660 if (*type == _C_FLT) 661 { 662 for (i = 0; i < count; i++) 663 { 664 double d; 665 666 (*desImp)(src, desSel, &d, @encode(double), &cursor, nil); 667 *(float*)(buf + offset) = (float)d; 668 offset += size; 669 } 670 } 671 else if (*type == _C_DBL) 672 { 673 for (i = 0; i < count; i++) 674 { 675 float f; 676 677 (*desImp)(src, desSel, &f, @encode(float), &cursor, nil); 678 *(double*)(buf + offset) = (double)f; 679 offset += size; 680 } 681 } 682 else if (*type == _C_SHT 683 || *type == _C_INT 684 || *type == _C_LNG 685 || *type == _C_LNG_LNG) 686 { 687 int64_t big; 688 int64_t max; 689 int64_t min; 690 691 switch (size) 692 { 693 case 1: 694 max = INT8_MAX; 695 min = INT8_MIN; 696 break; 697 case 2: 698 max = INT16_MAX; 699 min = INT16_MAX; 700 break; 701 case 4: 702 max = INT32_MAX; 703 min = INT32_MIN; 704 break; 705 default: 706 max = INT64_MAX; 707 min = INT64_MIN; 708 } 709 710 for (i = 0; i < count; i++) 711 { 712 void *address = (void*)buf + offset; 713 714 switch (ainfo & _GSC_SIZE) 715 { 716 case _GSC_I16: /* Encoded as 16-bit */ 717 { 718 int16_t val; 719 720 (*desImp)(src, desSel, &val, @encode(int16_t), &cursor, nil); 721 big = val; 722 break; 723 } 724 725 case _GSC_I32: /* Encoded as 32-bit */ 726 { 727 int32_t val; 728 729 (*desImp)(src, desSel, &val, @encode(int32_t), &cursor, nil); 730 big = val; 731 break; 732 } 733 734 case _GSC_I64: /* Encoded as 64-bit */ 735 { 736 (*desImp)(src, desSel, &big, @encode(int64_t), &cursor, nil); 737 break; 738 } 739 740 default: 741 [NSException raise: NSGenericException 742 format: @"invalid size in archive"]; 743 } 744 /* 745 * Now we copy from the big value to the destination location. 746 */ 747 switch (size) 748 { 749 case 1: 750 *(int8_t*)address = (int8_t)big; 751 break; 752 case 2: 753 *(int16_t*)address = (int16_t)big; 754 break; 755 case 4: 756 *(int32_t*)address = (int32_t)big; 757 break; 758 default: 759 *(int64_t*)address = big; 760 } 761 if (big < min || big > max) 762 { 763 NSLog(@"Lost information converting large decoded value"); 764 } 765 offset += size; 766 } 767 } 768 else 769 { 770 uint64_t big; 771 uint64_t max; 772 773 switch (size) 774 { 775 case 1: 776 max = UINT8_MAX; 777 break; 778 case 2: 779 max = UINT16_MAX; 780 break; 781 case 4: 782 max = UINT32_MAX; 783 break; 784 default: 785 max = UINT64_MAX; 786 } 787 788 for (i = 0; i < count; i++) 789 { 790 void *address = (void*)buf + offset; 791 792 switch (info & _GSC_SIZE) 793 { 794 case _GSC_I16: /* Encoded as 16-bit */ 795 { 796 uint16_t val; 797 798 (*desImp)(src, desSel, &val, @encode(uint16_t), &cursor, nil); 799 big = val; 800 break; 801 } 802 803 case _GSC_I32: /* Encoded as 32-bit */ 804 { 805 uint32_t val; 806 807 (*desImp)(src, desSel, &val, @encode(uint32_t), &cursor, nil); 808 big = val; 809 break; 810 } 811 812 case _GSC_I64: /* Encoded as 64-bit */ 813 { 814 (*desImp)(src, desSel, &big, @encode(uint64_t), &cursor, nil); 815 break; 816 } 817 818 default: 819 [NSException raise: NSGenericException 820 format: @"invalid size in archive"]; 821 } 822 /* 823 * Now we copy from the big value to the destination location. 824 */ 825 switch (size) 826 { 827 case 1: 828 *(uint8_t*)address = (uint8_t)big; 829 break; 830 case 2: 831 *(uint16_t*)address = (uint16_t)big; 832 break; 833 case 4: 834 *(uint32_t*)address = (uint32_t)big; 835 break; 836 case 8: 837 *(uint64_t*)address = big; 838 } 839 if (big > max) 840 { 841 NSLog(@"Lost information converting large decoded value"); 842 } 843 offset += size; 844 } 845 } 846} 847 848static inline int 849scalarSize(char type) 850{ 851 switch (type) 852 { 853 case _C_SHT: 854 case _C_USHT: return _GSC_S_SHT; 855 case _C_INT: 856 case _C_UINT: return _GSC_S_INT; 857 case _C_LNG: 858 case _C_ULNG: return _GSC_S_LNG; 859 case _C_LNG_LNG: 860 case _C_ULNG_LNG: return _GSC_S_LNG_LNG; 861 default: 862 [NSException raise: NSInvalidArgumentException 863 format: @"scalarSize() called with non-scalar type"]; 864 } 865 return -1; 866} 867 868- (void) decodeValueOfObjCType: (const char*)type 869 at: (void*)address 870{ 871 unsigned xref; 872 unsigned char info; 873 874 (*tagImp)(src, tagSel, &info, &xref, &cursor); 875 876 switch (info & _GSC_MASK) 877 { 878 case _GSC_ID: 879 { 880 id obj; 881 882 typeCheck(*type, _GSC_ID); 883 /* 884 * Special case - a zero crossref value size is a nil pointer. 885 */ 886 if ((info & _GSC_SIZE) == 0) 887 { 888 obj = nil; 889 } 890 else 891 { 892 if (info & _GSC_XREF) 893 { 894 if (xref >= GSIArrayCount(objMap)) 895 { 896 [NSException raise: NSInternalInconsistencyException 897 format: @"object crossref missing - %d", 898 xref]; 899 } 900 obj = GSIArrayItemAtIndex(objMap, xref).obj; 901 /* 902 * If it's a cross-reference, we need to retain it in 903 * order to give the appearance that it's actually a 904 * new object. 905 */ 906 IF_NO_GC(RETAIN(obj)); 907 } 908 else 909 { 910 Class c; 911 id rep; 912 913 if (xref != GSIArrayCount(objMap)) 914 { 915 [NSException raise: NSInternalInconsistencyException 916 format: @"extra object crossref - %d", 917 xref]; 918 } 919 (*dValImp)(self, dValSel, @encode(Class), &c); 920 921 if (c == 0) 922 { 923 [NSException raise: NSInternalInconsistencyException 924 format: @"decoded nil class"]; 925 } 926 obj = [c allocWithZone: zone]; 927 GSIArrayAddItem(objMap, (GSIArrayItem)obj); 928 929 rep = [obj initWithCoder: self]; 930 if (rep != obj) 931 { 932 obj = rep; 933 GSIArraySetItemAtIndex(objMap, (GSIArrayItem)obj, xref); 934 } 935 936 rep = [obj awakeAfterUsingCoder: self]; 937 if (rep != obj) 938 { 939 obj = rep; 940 GSIArraySetItemAtIndex(objMap, (GSIArrayItem)obj, xref); 941 } 942 /* 943 * The objMap does not retain objects, so in order to 944 * be sure that a decoded object is not deallocated by 945 * anything before it is needed (because it is decoded 946 * later as a cross reference) we store it in objSave. 947 */ 948 if (obj != nil) 949 { 950 [objSave addObject: obj]; 951 } 952 } 953 } 954 *(id*)address = obj; 955 return; 956 } 957 958 case _GSC_CLASS: 959 { 960 Class c; 961 NSUnarchiverObjectInfo *classInfo; 962 Class dummy; 963 964 if (*type != _C_ID) 965 { 966 typeCheck(*type, _GSC_CLASS); 967 } 968 /* 969 * Special case - a zero crossref value size is a nil pointer. 970 */ 971 if ((info & _GSC_SIZE) == 0) 972 { 973 *(SEL*)address = 0; 974 return; 975 } 976 if (info & _GSC_XREF) 977 { 978 if (xref >= GSIArrayCount(clsMap)) 979 { 980 [NSException raise: NSInternalInconsistencyException 981 format: @"class crossref missing - %d", xref]; 982 } 983 classInfo = (NSUnarchiverObjectInfo*) 984 GSIArrayItemAtIndex(clsMap, xref).obj; 985 *(Class*)address = mapClassObject(classInfo); 986 return; 987 } 988 while ((info & _GSC_MASK) == _GSC_CLASS) 989 { 990 unsigned cver; 991 NSString *className; 992 uint16_t nameLength; 993 994 if (xref != GSIArrayCount(clsMap)) 995 { 996 [NSException raise: NSInternalInconsistencyException 997 format: @"extra class crossref - %d", xref]; 998 } 999 1000 /* 1001 * A class is encoded as a 16-bit length, a sequence of 1002 * characters providing its name, then a version number. 1003 */ 1004 (*desImp)(src, desSel, &nameLength, @encode(uint16_t), 1005 &cursor, nil); 1006 if (nameLength == 0) 1007 { 1008 className = nil; 1009 } 1010 else 1011 { 1012 char name[nameLength+1]; 1013 1014 [src deserializeBytes: name 1015 length: nameLength 1016 atCursor: &cursor]; 1017 name[nameLength] = '\0'; 1018 className = [[NSString alloc] initWithUTF8String: name]; 1019 } 1020 (*desImp)(src, desSel, &cver, @encode(unsigned), &cursor, nil); 1021 if (className == 0) 1022 { 1023 NSLog(@"[%s %s] decoded nil class name", 1024 class_getName([self class]), sel_getName(_cmd)); 1025 className = @"_NSUnarchiverUnknownClass"; 1026 } 1027 classInfo = [objDict objectForKey: className]; 1028 if (nil == classInfo) 1029 { 1030 classInfo = [NSUnarchiverObjectInfo newWithName: className]; 1031 c = NSClassFromString(className); 1032 /* 1033 * Show a warning, if the class name that's being used to 1034 * build the class causes NSClassFromString to return nil. 1035 * This means that the class is unknown to the runtime. 1036 */ 1037 if (c == nil) 1038 { 1039 NSLog(@"Unable to find class named '%@'", className); 1040 } 1041 [classInfo mapToClass: c withName: className]; 1042 [objDict setObject: classInfo forKey: className]; 1043 RELEASE(classInfo); 1044 } 1045 RELEASE(className); 1046 classInfo->version = (NSInteger)cver; 1047 GSIArrayAddItem(clsMap, (GSIArrayItem)((id)classInfo)); 1048 *(Class*)address = mapClassObject(classInfo); 1049 /* 1050 * Point the address to a dummy location and read the 1051 * next tag - if it is another class, loop to get it. 1052 */ 1053 address = &dummy; 1054 (*tagImp)(src, tagSel, &info, &xref, &cursor); 1055 } 1056 if (info != _GSC_NONE) 1057 { 1058 [NSException raise: NSInternalInconsistencyException 1059 format: @"class list improperly terminated"]; 1060 } 1061 return; 1062 } 1063 1064 case _GSC_SEL: 1065 { 1066 SEL sel; 1067 1068 typeCheck(*type, _GSC_SEL); 1069 /* 1070 * Special case - a zero crossref value size is a nil pointer. 1071 */ 1072 if ((info & _GSC_SIZE) == 0) 1073 { 1074 *(SEL*)address = 0; 1075 return; 1076 } 1077 if (info & _GSC_XREF) 1078 { 1079 if (xref >= GSIArrayCount(ptrMap)) 1080 { 1081 [NSException raise: NSInternalInconsistencyException 1082 format: @"sel crossref missing - %d", xref]; 1083 } 1084 sel = GSIArrayItemAtIndex(ptrMap, xref).sel; 1085 } 1086 else 1087 { 1088 if (xref != GSIArrayCount(ptrMap)) 1089 { 1090 [NSException raise: NSInternalInconsistencyException 1091 format: @"extra sel crossref - %d", xref]; 1092 } 1093 (*desImp)(src, desSel, &sel, @encode(SEL), &cursor, nil); 1094 GSIArrayAddItem(ptrMap, (GSIArrayItem)sel); 1095 } 1096 *(SEL*)address = sel; 1097 return; 1098 } 1099 1100 case _GSC_ARY_B: 1101 { 1102 int count; 1103 1104 typeCheck(*type, _GSC_ARY_B); 1105 count = atoi(++type); 1106 while (isdigit(*type)) 1107 { 1108 type++; 1109 } 1110 [self decodeArrayOfObjCType: type count: count at: address]; 1111 return; 1112 } 1113 1114 case _GSC_STRUCT_B: 1115 { 1116 struct objc_struct_layout layout; 1117 1118 typeCheck(*type, _GSC_STRUCT_B); 1119 objc_layout_structure (type, &layout); 1120 while (objc_layout_structure_next_member (&layout)) 1121 { 1122 unsigned offset; 1123 unsigned align; 1124 const char *ftype; 1125 1126 objc_layout_structure_get_info (&layout, &offset, &align, &ftype); 1127 1128 (*dValImp)(self, dValSel, ftype, (char*)address + offset); 1129 } 1130 return; 1131 } 1132 1133 case _GSC_PTR: 1134 { 1135 typeCheck(*type, _GSC_PTR); 1136 /* 1137 * Special case - a zero crossref value size is a nil pointer. 1138 */ 1139 if ((info & _GSC_SIZE) == 0) 1140 { 1141 *(void**)address = 0; 1142 return; 1143 } 1144 if (info & _GSC_XREF) 1145 { 1146 if (xref >= GSIArrayCount(ptrMap)) 1147 { 1148 [NSException raise: NSInternalInconsistencyException 1149 format: @"ptr crossref missing - %d", xref]; 1150 } 1151 *(void**)address = GSIArrayItemAtIndex(ptrMap, xref).ptr; 1152 } 1153 else 1154 { 1155 unsigned size; 1156 1157 if (GSIArrayCount(ptrMap) != xref) 1158 { 1159 [NSException raise: NSInternalInconsistencyException 1160 format: @"extra ptr crossref - %d", xref]; 1161 } 1162 1163 /* 1164 * Allocate memory for object to be decoded into and 1165 * add it to the crossref map. 1166 */ 1167 size = objc_sizeof_type(++type); 1168 *(void**)address = GSAutoreleasedBuffer(size); 1169 GSIArrayAddItem(ptrMap, (GSIArrayItem)*(void**)address); 1170 1171 /* 1172 * Decode value and add memory to map for crossrefs. 1173 */ 1174 (*dValImp)(self, dValSel, type, *(void**)address); 1175 } 1176 return; 1177 } 1178 1179 case _GSC_CHARPTR: 1180 { 1181 typeCheck(*type, _GSC_CHARPTR); 1182 /* 1183 * Special case - a zero crossref value size is a nil pointer. 1184 */ 1185 if ((info & _GSC_SIZE) == 0) 1186 { 1187 *(char**)address = 0; 1188 return; 1189 } 1190 if (info & _GSC_XREF) 1191 { 1192 if (xref >= GSIArrayCount(ptrMap)) 1193 { 1194 [NSException raise: NSInternalInconsistencyException 1195 format: @"string crossref missing - %d", xref]; 1196 } 1197 *(char**)address = GSIArrayItemAtIndex(ptrMap, xref).str; 1198 } 1199 else 1200 { 1201 if (xref != GSIArrayCount(ptrMap)) 1202 { 1203 [NSException raise: NSInternalInconsistencyException 1204 format: @"extra string crossref - %d", xref]; 1205 } 1206 (*desImp)(src, desSel, address, @encode(char*), &cursor, nil); 1207 GSIArrayAddItem(ptrMap, (GSIArrayItem)*(void**)address); 1208 } 1209 return; 1210 } 1211 1212 case _GSC_CHR: 1213 case _GSC_UCHR: 1214 /* Encoding of chars is not consistant across platforms, so we 1215 loosen the type checking a little */ 1216 if (*type != type_map[_GSC_CHR] && *type != type_map[_GSC_UCHR]) 1217 { 1218 [NSException raise: NSInternalInconsistencyException 1219 format: @"expected %s and got %s", 1220 typeToName1(*type), typeToName2(info)]; 1221 } 1222 (*desImp)(src, desSel, address, type, &cursor, nil); 1223 return; 1224 1225 case _GSC_SHT: 1226 case _GSC_USHT: 1227 if (YES == typeCheck(*type, info & _GSC_MASK) 1228 && (info & _GSC_SIZE) == scalarSize(*type)) 1229 { 1230 (*desImp)(src, desSel, address, type, &cursor, nil); 1231 return; 1232 } 1233 break; 1234 1235 case _GSC_INT: 1236 case _GSC_UINT: 1237 if (YES == typeCheck(*type, info & _GSC_MASK) 1238 && (info & _GSC_SIZE) == scalarSize(*type)) 1239 { 1240 (*desImp)(src, desSel, address, type, &cursor, nil); 1241 return; 1242 } 1243 break; 1244 1245 case _GSC_LNG: 1246 case _GSC_ULNG: 1247 if (YES == typeCheck(*type, info & _GSC_MASK) 1248 && (info & _GSC_SIZE) == scalarSize(*type)) 1249 { 1250 (*desImp)(src, desSel, address, type, &cursor, nil); 1251 return; 1252 } 1253 break; 1254 1255 case _GSC_LNG_LNG: 1256 case _GSC_ULNG_LNG: 1257 if (YES == typeCheck(*type, info & _GSC_MASK) 1258 && (info & _GSC_SIZE) == scalarSize(*type)) 1259 { 1260 (*desImp)(src, desSel, address, type, &cursor, nil); 1261 return; 1262 } 1263 break; 1264 1265 case _GSC_FLT: 1266 if (YES == typeCheck(*type, _GSC_FLT) 1267 && *type == _C_FLT) 1268 { 1269 (*desImp)(src, desSel, address, type, &cursor, nil); 1270 } 1271 else 1272 { 1273 float val; 1274 1275 /* We found a float when expecting a double ... handle it. 1276 */ 1277 (*desImp)(src, desSel, &val, @encode(float), &cursor, nil); 1278 *(double*)address = (double)val; 1279 } 1280 return; 1281 1282 case _GSC_DBL: 1283 if (YES == typeCheck(*type, _GSC_DBL) 1284 && *type == _C_DBL) 1285 { 1286 (*desImp)(src, desSel, address, type, &cursor, nil); 1287 } 1288 else 1289 { 1290 double val; 1291 1292 /* We found a double when expecting a float ... handle it. 1293 */ 1294 (*desImp)(src, desSel, &val, @encode(double), &cursor, nil); 1295 *(float*)address = (float)val; 1296 } 1297 return; 1298 1299 case _GSC_BOOL: 1300 if (*type != type_map[_GSC_BOOL]) 1301 { 1302 [NSException raise: NSInternalInconsistencyException 1303 format: @"expected %s and got %s", 1304 typeToName1(*type), typeToName2(info)]; 1305 } 1306 (*desImp)(src, desSel, address, type, &cursor, nil); 1307 return; 1308 1309 default: 1310 [NSException raise: NSInternalInconsistencyException 1311 format: @"read unknown type info - %d", info]; 1312 } 1313 1314{ 1315 uint8_t size; 1316 1317 /* 1318 * We fall through to here only when we have to decode a value 1319 * whose natural size on this system is not the same as on the 1320 * machine on which the archive was created. 1321 */ 1322 1323 switch (*type) 1324 { 1325 case _C_SHT: 1326 case _C_USHT: size = sizeof(short); break; 1327 case _C_INT: 1328 case _C_UINT: size = sizeof(int); break; 1329 case _C_LNG: 1330 case _C_ULNG: size = sizeof(long); break; 1331 case _C_LNG_LNG: 1332 case _C_ULNG_LNG: size = sizeof(long long); break; 1333 default: size = 1; 1334 } 1335 1336 /* 1337 * First, we read the data and convert it to the largest size 1338 * this system can support. 1339 */ 1340 if (*type == _C_SHT 1341 || *type == _C_INT 1342 || *type == _C_LNG 1343 || *type == _C_LNG_LNG) 1344 { 1345 int64_t big; 1346 1347 switch (info & _GSC_SIZE) 1348 { 1349 case _GSC_I16: /* Encoded as 16-bit */ 1350 { 1351 int16_t val; 1352 1353 (*desImp)(src, desSel, &val, @encode(int16_t), &cursor, nil); 1354 big = val; 1355 break; 1356 } 1357 1358 case _GSC_I32: /* Encoded as 32-bit */ 1359 { 1360 int32_t val; 1361 1362 (*desImp)(src, desSel, &val, @encode(int32_t), &cursor, nil); 1363 big = val; 1364 break; 1365 } 1366 1367 case _GSC_I64: /* Encoded as 64-bit */ 1368 { 1369 (*desImp)(src, desSel, &big, @encode(int64_t), &cursor, nil); 1370 break; 1371 } 1372 1373 default: /* A 128-bit value */ 1374 { 1375 big = 0; 1376 [NSException raise: NSInternalInconsistencyException 1377 format: @"Archiving of 128bit integer not allowed"]; 1378 } 1379 } 1380 /* 1381 * Now we copy from the big value to the destination location. 1382 */ 1383 switch (size) 1384 { 1385 case 1: 1386 *(int8_t*)address = (int8_t)big; 1387 if (big > 127 || big < -128) 1388 { 1389 NSLog(@"Lost information converting decoded value to int8_t"); 1390 } 1391 return; 1392 case 2: 1393 *(int16_t*)address = (int16_t)big; 1394 if (big > 32767 || big < -32768) 1395 { 1396 NSLog(@"Lost information converting decoded value to int16_t"); 1397 } 1398 return; 1399 case 4: 1400 *(int32_t*)address = (int32_t)big; 1401 if (big > 2147483647 || big < -2147483648) 1402 { 1403 NSLog(@"Lost information converting decoded value to int32_t"); 1404 } 1405 return; 1406 case 8: 1407 *(int64_t*)address = big; 1408 return; 1409 default: 1410 [NSException raise: NSInternalInconsistencyException 1411 format: @"type/size information error"]; 1412 } 1413 } 1414 else 1415 { 1416 uint64_t big; 1417 1418 switch (info & _GSC_SIZE) 1419 { 1420 case _GSC_I16: /* Encoded as 16-bit */ 1421 { 1422 uint16_t val; 1423 1424 (*desImp)(src, desSel, &val, @encode(uint16_t), &cursor, nil); 1425 big = val; 1426 break; 1427 } 1428 1429 case _GSC_I32: /* Encoded as 32-bit */ 1430 { 1431 uint32_t val; 1432 1433 (*desImp)(src, desSel, &val, @encode(uint32_t), &cursor, nil); 1434 big = val; 1435 break; 1436 } 1437 1438 case _GSC_I64: /* Encoded as 64-bit */ 1439 { 1440 (*desImp)(src, desSel, &big, @encode(uint64_t), &cursor, nil); 1441 break; 1442 } 1443 1444 default: /* A 128-bit value */ 1445 { 1446 big = 0; 1447 [NSException raise: NSInternalInconsistencyException 1448 format: @"Archiving of 128bit integer not allowed"]; 1449 } 1450 } 1451 /* 1452 * Now we copy from the big value to the destination location. 1453 */ 1454 switch (size) 1455 { 1456 case 1: 1457 if (big & ~0xffLL) 1458 { 1459 NSLog(@"Lost information converting decoded value to uint8_t"); 1460 } 1461 *(uint8_t*)address = (uint8_t)big; 1462 return; 1463 case 2: 1464 if (big & ~0xffffLL) 1465 { 1466 NSLog(@"Lost information converting decoded value to uint16_t"); 1467 } 1468 *(uint16_t*)address = (uint16_t)big; 1469 return; 1470 case 4: 1471 if (big & ~0xffffffffLL) 1472 { 1473 NSLog(@"Lost information converting decoded value to uint32_t"); 1474 } 1475 *(uint32_t*)address = (uint32_t)big; 1476 return; 1477 case 8: 1478 *(uint64_t*)address = big; 1479 return; 1480 default: 1481 [NSException raise: NSInternalInconsistencyException 1482 format: @"type/size information error"]; 1483 } 1484 } 1485} 1486} 1487 1488- (NSData*) decodeDataObject 1489{ 1490 unsigned l; 1491 1492 (*dValImp)(self, dValSel, @encode(unsigned int), &l); 1493 if (l) 1494 { 1495 unsigned char c; 1496 1497 (*dValImp)(self, dValSel, @encode(unsigned char), &c); 1498 if (c == 0) 1499 { 1500 void *b; 1501 NSData *d; 1502 1503 b = NSZoneMalloc(zone, l); 1504 [self decodeArrayOfObjCType: @encode(unsigned char) 1505 count: l 1506 at: b]; 1507 d = [[NSData allocWithZone: zone] initWithBytesNoCopy: b 1508 length: l]; 1509 IF_NO_GC(AUTORELEASE(d)); 1510 return d; 1511 } 1512 else 1513 { 1514 [NSException raise: NSInternalInconsistencyException 1515 format: @"Decoding data object with unknown type"]; 1516 } 1517 } 1518 return [NSData data]; 1519} 1520 1521/** 1522 * Returns whether have currently read through all of data buffer or file 1523 * this unarchiver was initialized with. 1524 */ 1525- (BOOL) isAtEnd 1526{ 1527 return (cursor >= [data length]); 1528} 1529 1530/** 1531 * Returns zone unarchived objects will be allocated from. 1532 */ 1533- (NSZone*) objectZone 1534{ 1535 return zone; 1536} 1537 1538/** 1539 * Sets zone unarchived objects will be allocated from. 1540 */ 1541- (void) setObjectZone: (NSZone*)aZone 1542{ 1543 zone = aZone; 1544} 1545 1546/** 1547 * Returns system version archive was encoded by. 1548 */ 1549- (unsigned) systemVersion 1550{ 1551 return version; 1552} 1553 1554/** 1555 * Returns class name unarchivers will use to instantiate encoded objects 1556 * when they report their class name as nameInArchive. 1557 */ 1558+ (NSString*) classNameDecodedForArchiveClassName: (NSString*)nameInArchive 1559{ 1560 NSUnarchiverClassInfo *info = [clsDict objectForKey: nameInArchive]; 1561 NSString *alias; 1562 1563 if (info == nil) 1564 { 1565 return nil; 1566 } 1567 alias = info->name; 1568 if (alias) 1569 { 1570 return alias; 1571 } 1572 return nameInArchive; 1573} 1574 1575/** 1576 * Sets class name unarchivers will use to instantiate encoded objects 1577 * when they report their class name as nameInArchive. This can be used 1578 * to support backwards compatibility across class name changes. 1579 */ 1580+ (void) decodeClassName: (NSString*)nameInArchive 1581 asClassName: (NSString*)trueName 1582{ 1583 Class c; 1584 1585 c = objc_lookUpClass([trueName cString]); 1586 if (c == 0) 1587 { 1588 [NSException raise: NSInvalidArgumentException 1589 format: @"can't find class %@", trueName]; 1590 } 1591 else 1592 { 1593 NSUnarchiverClassInfo *info = [clsDict objectForKey: nameInArchive]; 1594 1595 if (info == nil) 1596 { 1597 info = [NSUnarchiverClassInfo newWithName: nameInArchive]; 1598 [clsDict setObject: info forKey: nameInArchive]; 1599 RELEASE(info); 1600 } 1601 [info mapToClass: c withName: trueName]; 1602 } 1603} 1604 1605/** 1606 * Returns class name this unarchiver uses to instantiate encoded objects 1607 * when they report their class name as nameInArchive. 1608 */ 1609- (NSString*) classNameDecodedForArchiveClassName: (NSString*)nameInArchive 1610{ 1611 NSUnarchiverObjectInfo *info = [objDict objectForKey: nameInArchive]; 1612 NSString *alias; 1613 1614 if (info == nil) 1615 { 1616 return nil; 1617 } 1618 alias = mapClassName(info); 1619 if (alias) 1620 { 1621 return alias; 1622 } 1623 return nameInArchive; 1624} 1625 1626 1627/** 1628 * Set class name this unarchiver uses to instantiate encoded objects 1629 * when they report their class name as nameInArchive. This can be used 1630 * to provide backward compatibility across class name changes. 1631 */ 1632- (void) decodeClassName: (NSString*)nameInArchive 1633 asClassName: (NSString*)trueName 1634{ 1635 Class c; 1636 1637 c = objc_lookUpClass([trueName cString]); 1638 if (c == 0) 1639 { 1640 [NSException raise: NSInvalidArgumentException 1641 format: @"can't find class %@", trueName]; 1642 } 1643 else 1644 { 1645 NSUnarchiverObjectInfo *info = [objDict objectForKey: nameInArchive]; 1646 1647 if (info == nil) 1648 { 1649 info = [NSUnarchiverObjectInfo newWithName: nameInArchive]; 1650 [objDict setObject: info forKey: nameInArchive]; 1651 RELEASE(info); 1652 } 1653 [info mapToClass: c withName: trueName]; 1654 } 1655} 1656 1657/** 1658 * Set unarchiver to replace anObject with replacement whenever it is 1659 * found decoded from the archive. 1660 */ 1661- (void) replaceObject: (id)anObject withObject: (id)replacement 1662{ 1663 unsigned i; 1664 1665 if (replacement == anObject) 1666 return; 1667 for (i = GSIArrayCount(objMap) - 1; i > 0; i--) 1668 { 1669 if (GSIArrayItemAtIndex(objMap, i).obj == anObject) 1670 { 1671 GSIArraySetItemAtIndex(objMap, (GSIArrayItem)replacement, i); 1672 return; 1673 } 1674 } 1675 [NSException raise: NSInvalidArgumentException 1676 format: @"object to be replaced does not exist"]; 1677} 1678 1679- (NSInteger) versionForClassName: (NSString*)className 1680{ 1681 NSUnarchiverObjectInfo *info; 1682 1683 info = [objDict objectForKey: className]; 1684 if (info == nil) 1685 { 1686 return (NSInteger)NSNotFound; 1687 } 1688 return info->version; 1689} 1690 1691@end 1692 1693 1694 1695 1696/** 1697 * Category for compatibility with old GNUstep encoding. 1698 */ 1699@implementation NSUnarchiver (GNUstep) 1700 1701/** 1702 * Return current position within archive byte array. 1703 */ 1704- (unsigned) cursor 1705{ 1706 return cursor; 1707} 1708 1709 1710/** 1711 * Prepare for reuse of the unarchiver to unpack a new archive, specified in 1712 * anObject, starting at pos. Reads archive header. 1713 */ 1714- (void) resetUnarchiverWithData: (NSData*)anObject 1715 atIndex: (unsigned)pos 1716{ 1717 unsigned sizeC; 1718 unsigned sizeO; 1719 unsigned sizeP; 1720 1721 if (anObject == nil) 1722 { 1723 [NSException raise: NSInvalidArgumentException 1724 format: @"nil passed to resetUnarchiverWithData:atIndex:"]; 1725 } 1726 if (data != anObject) 1727 { 1728 Class c; 1729 1730 TEST_RELEASE(data); 1731 data = RETAIN(anObject); 1732 c = object_getClass(data); 1733 if (src != self) 1734 { 1735 src = data; 1736 if (c != dataClass) 1737 { 1738 /* 1739 * Cache methods for deserialising from the data object. 1740 */ 1741 desImp = [src methodForSelector: desSel]; 1742 tagImp = (void (*)(id, SEL, unsigned char*, unsigned*, unsigned*)) 1743 [src methodForSelector: tagSel]; 1744 } 1745 } 1746 dataClass = c; 1747 } 1748 1749 /* 1750 * Read header including version and crossref table sizes. 1751 */ 1752 cursor = pos; 1753 [self deserializeHeaderAt: &cursor 1754 version: &version 1755 classes: &sizeC 1756 objects: &sizeO 1757 pointers: &sizeP]; 1758 if (version > encodingVersion) 1759 { 1760 [NSException raise: NSInvalidArgumentException 1761 format: @"Archive systemVersion (%u) not recognised", version]; 1762 } 1763 1764 if (clsMap == 0) 1765 { 1766 /* 1767 * Allocate and initialise arrays to build crossref maps in. 1768 */ 1769 clsMap = NSZoneMalloc(zone, sizeof(GSIArray_t)*3); 1770 GSIArrayInitWithZoneAndCapacity(clsMap, zone, sizeC); 1771 GSIArrayAddItem(clsMap, (GSIArrayItem)(void*)0); 1772 1773 objMap = &clsMap[1]; 1774 GSIArrayInitWithZoneAndCapacity(objMap, zone, sizeO); 1775 GSIArrayAddItem(objMap, (GSIArrayItem)(void*)0); 1776 1777 ptrMap = &clsMap[2]; 1778 GSIArrayInitWithZoneAndCapacity(ptrMap, zone, sizeP); 1779 GSIArrayAddItem(ptrMap, (GSIArrayItem)(void*)0); 1780 } 1781 else 1782 { 1783 clsMap->count = 1; 1784 objMap->count = 1; 1785 ptrMap->count = 1; 1786 } 1787 1788 [objDict removeAllObjects]; 1789 [objSave removeAllObjects]; 1790} 1791 1792/** 1793 * Reads in header for GNUstep archive format. 1794 */ 1795- (void) deserializeHeaderAt: (unsigned*)pos 1796 version: (unsigned*)v 1797 classes: (unsigned*)c 1798 objects: (unsigned*)o 1799 pointers: (unsigned*)p 1800{ 1801 unsigned plen = strlen(PREFIX); 1802 unsigned size = plen+36; 1803 char header[size+1]; 1804 1805 [data getBytes: header range: NSMakeRange(*pos, size)]; 1806 *pos += size; 1807 header[size] = '\0'; 1808 if (strncmp(header, PREFIX, plen) != 0) 1809 { 1810 [NSException raise: NSInternalInconsistencyException 1811 format: @"Archive has wrong prefix"]; 1812 } 1813 if (sscanf(&header[plen], "%x:%x:%x:%x:", v, c, o, p) != 4) 1814 { 1815 [NSException raise: NSInternalInconsistencyException 1816 format: @"Archive has wrong prefix"]; 1817 } 1818} 1819 1820/** 1821 * Returns YES. 1822 */ 1823- (BOOL) directDataAccess 1824{ 1825 return YES; 1826} 1827 1828@end 1829 1830