1 /* Copyright (c) 2006-2007 Christopher J. W. Lloyd
3 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8 #import <Foundation/NSUnarchiver.h>
9 #import <Foundation/NSRaise.h>
10 #import <Foundation/NSData.h>
11 #import <Foundation/NSMutableArray.h>
12 #import <Foundation/NSByteOrder.h>
15 @implementation NSUnarchiver
17 -(void)cannotDecodeType:(const char *)type {
18 [NSException raise:@"NSUnarchiverCannotDecodeException"
19 format:@"NSUnarchiver cannot decode type=%s",type];
22 -(void)_ensureLength:(NSUInteger)length {
23 if(_position+length>_length)
24 [NSException raise:@"NSUnarchiverBadArchiveException"
25 format:@"NSUnarchiver attempt to read beyond length"];
28 -(uint8_t)_extractWordOne {
29 [self _ensureLength:1];
30 return _bytes[_position++];
33 -(uint16_t)_extractWordTwo {
36 [self _ensureLength:2];
38 result=_bytes[_position++];
40 result|=_bytes[_position++];
45 -(unsigned int)_extractWordFour {
48 [self _ensureLength:4];
50 result=_bytes[_position++];
52 result|=_bytes[_position++];
54 result|=_bytes[_position++];
56 result|=_bytes[_position++];
61 -(unsigned long long)_extractWordEight {
62 unsigned long long result;
64 [self _ensureLength:8];
66 result=_bytes[_position++];
68 result|=_bytes[_position++];
70 result|=_bytes[_position++];
72 result|=_bytes[_position++];
74 result|=_bytes[_position++];
76 result|=_bytes[_position++];
78 result|=_bytes[_position++];
80 result|=_bytes[_position++];
85 -(float)_extractDataFloat {
86 NSSwappedFloat swapped;
88 swapped.floatWord=[self _extractWordFour];
90 return NSConvertSwappedFloatToHost(swapped);
93 -(double)_extractDataDouble {
94 NSSwappedDouble swapped;
96 swapped.doubleWord=[self _extractWordEight];
98 return NSConvertSwappedDoubleToHost(swapped);
101 -(NSString *)_extractCStringBytes {
105 while((_position+length)<_length && (_bytes[_position+length]!='\0'))
108 result=[NSString stringWithCString:(char *)(_bytes+_position) length:length];
114 -(NSUInteger)_extractReference {
115 return (NSUInteger)[self _extractWordFour];
118 -(NSString *)_extractCStringString {
119 NSUInteger ref=[self _extractReference];
120 NSString *result=NSMapGet(_cStrings,(void *)ref);
123 result=[self _extractCStringBytes];
124 NSMapInsert(_cStrings,(void *)ref,result);
130 -(const char *)_extractCString {
131 return [[self _extractCStringString] cString];
134 -(Class)_extractClass {
135 NSUInteger ref=[self _extractReference];
139 return [NSObject class];
140 else if((result=NSMapGet(_classes,(void *)ref))!=Nil)
143 NSString *className=[self _extractCStringString];
144 NSUInteger version=[self _extractWordFour];
146 result=NSClassFromString(className);
148 NSMapInsert(_classes,(void *)ref,result);
149 NSMapInsert(_classVersions,className,(void *)version);
151 [self _extractClass];
157 -(id)_extractObject {
158 NSUInteger ref=[self _extractReference];
163 else if((result=NSMapGet(_objects,(void *)ref))!=nil)
166 Class class=[self _extractClass];
168 result=[class allocWithZone:NULL];
169 NSMapInsert(_objects,(void *)ref,result);
170 result=[result initWithCoder:self];
171 result=[result awakeAfterUsingCoder:self];
173 NSMapInsert(_objects,(void *)ref,result);
175 [_allObjects addObject:result];
181 -(void)_extractArrayOfObjCType:(const char *)type length:(NSUInteger)length
187 unsigned char *values=addr;
190 for(i=0;i<length;i++)
191 values[i]=[self _extractWordOne];
197 unsigned short *values=addr;
200 for(i=0;i<length;i++)
201 values[i]=[self _extractWordTwo];
206 [self cannotDecodeType:type];
211 -(void)decodeValueOfObjCType:(const char *)type at:(void *)addr {
212 const char *checkType=[self _extractCString];
214 if(strcmp(checkType,type)!=0)
215 [NSException raise:@"NSUnarchiverTypeMismatchException"
216 format:@"NSUnarchiver type mismatch decoding %s, contains %s",type,checkType];
221 unsigned char *value=addr;
222 *value=[self _extractWordOne];
228 unsigned short *value=addr;
229 *value=[self _extractWordTwo];
235 unsigned int *value=addr;
236 *value=[self _extractWordFour];
242 unsigned long *value=addr;
243 *value=[self _extractWordFour];
249 unsigned long long *value=addr;
250 *value=[self _extractWordEight];
256 *value=[self _extractDataFloat];
262 *value=[self _extractDataDouble];
268 NSString *string=[self _extractCStringString];
270 *cString=NSZoneMalloc(NSDefaultMallocZone(),[string cStringLength]+1);
271 [string getCString:*cString];
278 *object=[self _extractObject];
283 [self cannotDecodeType:type];
288 NSString *string=[self _extractCStringString];
290 *value=NSSelectorFromString(string);
295 const char *tmp=type;
299 for(;*tmp>='0' && *tmp<='9';tmp++)
300 length=(length*10)+(*tmp-'0');
302 [self _extractArrayOfObjCType:tmp length:length at:addr];
307 if(strcmp(type,"{?=II}")==0){
310 value->location=[self _extractWordFour];
311 value->length=[self _extractWordFour];
314 if(strcmp(type,@encode(NSPoint))==0){
317 value->x=[self _extractDataFloat];
318 value->y=[self _extractDataFloat];
321 if(strcmp(type,@encode(NSSize))==0){
324 value->width=[self _extractDataFloat];
325 value->height=[self _extractDataFloat];
328 if(strcmp(type,@encode(NSRect))==0){
331 value->origin.x=[self _extractDataFloat];
332 value->origin.y=[self _extractDataFloat];
333 value->size.width=[self _extractDataFloat];
334 value->size.height=[self _extractDataFloat];
337 [self cannotDecodeType:type];
345 [self cannotDecodeType:type];
351 -(void *)decodeBytesWithReturnedLength:(NSUInteger *)lengthp {
353 unsigned length=[self _extractWordFour];
355 [self _ensureLength:length];
356 result=(void *)(_bytes+_position);
365 -(NSData *)decodeDataObject {
366 [self cannotDecodeType:"decodeDataObject"];
371 - (NSInteger)versionForClassName:(NSString *)className
375 if (!NSMapMember(_classVersions, className, &oKey, &oVal)) {
376 //NSLog(@"no version for %@",className);
379 return (NSInteger)NSMapGet(_classVersions, className);
383 -(BOOL)invalidHeader {
386 if(_length<strlen("~V1~")+1+4)
389 label=[self _extractCStringBytes];
390 if(![label isEqualToString:@"~V1~"])
393 _version=[self _extractWordFour];
395 [NSException raise:@"NSUnarchiverInvalidVersionException"
396 format:@"NSUnarchiver cannot unarchive version %d",_version];
401 -initForReadingWithData:(NSData *)data {
405 _length=[data length];
407 _objectZone=NSDefaultMallocZone();
409 _objects=NSCreateMapTable(NSIntMapKeyCallBacks,
410 NSNonRetainedObjectMapValueCallBacks,0);
411 _classes=NSCreateMapTable(NSIntMapKeyCallBacks,
412 NSNonRetainedObjectMapValueCallBacks,0);
413 _cStrings=NSCreateMapTable(NSIntMapKeyCallBacks,NSObjectMapValueCallBacks,0);
414 _classVersions=NSCreateMapTable(NSObjectMapKeyCallBacks,
415 NSIntMapValueCallBacks,0);
417 _allObjects=[NSMutableArray new];
419 if([self invalidHeader]){
428 NSFreeMapTable(_objects);
429 NSFreeMapTable(_classes);
430 NSFreeMapTable(_cStrings);
431 NSFreeMapTable(_classVersions);
432 [_allObjects release];
436 +(id)unarchiveObjectWithData:(NSData *)data {
437 NSUnarchiver *unarchiver=[[[NSUnarchiver allocWithZone:NULL] initForReadingWithData:data] autorelease];
439 return [unarchiver decodeObject];
442 +(id)unarchiveObjectWithFile:(NSString *)path {
443 NSData *data=[NSData dataWithContentsOfFile:path];
444 NSUnarchiver *unarchiver;
449 unarchiver=[[[NSUnarchiver allocWithZone:NULL] initForReadingWithData:data] autorelease];
451 return [unarchiver decodeObject];
455 return (_position<_length)?NO:YES;
458 -(NSZone *)objectZone {
462 -(void)setObjectZone:(NSZone *)zone {
466 -(void)decodeClassName:(NSString *)archiveName asClassName:(NSString *)runtimeName {
467 NSUnimplementedMethod();
470 -(NSString *)classNameDecodedForArchiveClassName:(NSString *)className {
471 NSUnimplementedMethod();
475 +(void)decodeClassName:(NSString *)archiveName asClassName:(NSString *)runtimeName {
476 NSUnimplementedMethod();
479 +(NSString *)classNameDecodedForArchiveClassName:(NSString *)className {
480 NSUnimplementedMethod();
484 -(void)replaceObject:original withObject:replacement {
485 NSUnimplementedMethod();