Partial implementation of unarchiver code.

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@18458 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2004-01-22 20:38:24 +00:00
parent f88e119c36
commit 383ae3d03b
3 changed files with 417 additions and 25 deletions

View file

@ -1,4 +1,9 @@
2004-01-19 Richard Frith-Macdonald <rfm@gnu.org>
2004-01-22 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/NSKeyedArchiver.h: Update ivars for unarchiver.
* Source/NSKeyedUnarchiver.m: Partial implementation.
2004-01-21 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/Foundation/NSPropertyList.h: serialisation/deserialisation.
* Source/NSPropertyList.m: serialisation/deserialisation code partly

View file

@ -162,19 +162,22 @@
@interface NSKeyedUnarchiver : NSCoder
{
@private
id _delegate;
NSDictionary *_archive;
id _delegate; /* Delegate controls operation. */
NSMapTable *_clsMap; /* Map classes to names. */
NSArray *_objects; /* All encoded objects. */
NSDictionary *_keyMap; /* Local object name table. */
unsigned _cursor; /* Position in object. */
NSString *_archiverClass;
NSString *_version;
#ifndef _IN_NSKEYEDUNARCHIVER_M
#define GSIArray void*
#endif
GSIArray clsMap; /* Class crossreference map. */
GSIArray objMap; /* Object crossreference map. */
GSIArray ptrMap; /* Pointer crossreference map. */
GSIArray _objMap; /* Decoded objects. */
#ifndef _IN_NSKEYEDUNARCHIVER_M
#undef GSUnarchiverArray
#endif
unsigned cursor; /* Position in data buffer. */
NSZone *zone; /* Zone for allocating objs. */
NSMutableDictionary *objDict; /* Class information store. */
NSZone *_zone; /* Zone for allocating objs. */
}
+ (Class) classForClassName: (NSString*)aString;

View file

@ -26,19 +26,183 @@
#include <Foundation/NSData.h>
#include <Foundation/NSException.h>
#include <Foundation/NSMapTable.h>
#include <Foundation/NSNull.h>
#include <Foundation/NSValue.h>
/*
* Setup for inline operation of arrays.
*/
#define GSI_ARRAY_RETAIN(A, X)
#define GSI_ARRAY_RELEASE(A, X)
#define GSI_ARRAY_TYPES GSUNION_OBJ|GSUNION_SEL|GSUNION_PTR
#include <GNUstepBase/GSIArray.h>
#include <GNUstepBase/GSIMap.h>
#define _IN_NSKEYEDUNARCHIVER_M 1
#include <Foundation/NSKeyedArchiver.h>
#undef _IN_NSKEYEDUNARCHIVER_M
static NSMapTable globalClassMap = 0;
NSString * const NSInvalidUnarchiveOperationException
= @"NSInvalidUnarchiveOperationException";
static NSMapTable globalClassMap = 0;
#define GETVAL \
NSString *oldKey = aKey; \
id o; \
\
if ([aKey isKindOfClass: [NSString class]] == NO) \
{ \
[NSException raise: NSInvalidArgumentException \
format: @"%@, bad key '%@' in %@", \
NSStringFromClass([self class]), aKey, NSStringFromSelector(_cmd)]; \
} \
if ([aKey hasPrefix: @"$"] == YES) \
{ \
aKey = [@"$" stringByAppendingString: aKey]; \
} \
if ([_keyMap objectForKey: aKey] != nil) \
{ \
[NSException raise: NSInvalidArgumentException \
format: @"%@, duplicate key '%@' in %@", \
NSStringFromClass([self class]), aKey, NSStringFromSelector(_cmd)]; \
} \
o = [_keyMap objectForKey: aKey];
@interface NSKeyedUnarchiver (Private)
- (id) _decodeObject: (unsigned)index;
@end
@implementation NSKeyedUnarchiver (Private)
- (id) _decodeObject: (unsigned)index
{
id o;
id obj;
/*
* If the referenced object is already in _objMap
* we simply return it (the object at index 0 maps to nil)
*/
obj = GSIArrayItemAtIndex(_objMap, index).obj;
if (obj != nil)
{
if (obj == GSIArrayItemAtIndex(_objMap, 0).obj)
{
return nil;
}
return obj;
}
/*
* No mapped object, so we decode from the property list
* in _objects
*/
obj = [_objects objectAtIndex: index];
if ([obj isKindOfClass: [NSDictionary class]] == YES)
{
NSString *classname;
NSArray *classes;
Class c;
id r;
NSDictionary *savedKeyMap;
unsigned savedCursor;
/*
* Fetch the class information from the table.
*/
o = [obj objectForKey: @"$class"];
o = [o objectForKey: @"CF$UID"];
o = [_objects objectAtIndex: [o intValue]];
classname = [o objectForKey: @"$classname"];
classes = [o objectForKey: @"$classes"];
c = [self classForClassName: classname];
if (c == nil)
{
c = [[self class] classForClassName: classname];
if (c == nil)
{
c = NSClassFromString(classname);
if (c == nil)
{
c = [_delegate unarchiver: self
cannotDecodeObjectOfClassName: classname
originalClasses: classes];
if (c == nil)
{
[NSException raise:
NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: no class for name '%@'",
NSStringFromClass([self class]),
NSStringFromSelector(_cmd),
classname];
}
}
}
}
savedCursor = _cursor;
savedKeyMap = _keyMap;
_cursor = 0; // Starting object decode
_keyMap = obj; // Dictionary describing object
o = [c allocWithZone: _zone]; // Create instance.
r = [o initWithCoder: self];
if (r != o)
{
[_delegate unarchiver: self
willReplaceObject: o
withObject: r];
o = r;
}
r = [o awakeAfterUsingCoder: self];
if (r != o)
{
[_delegate unarchiver: self
willReplaceObject: o
withObject: r];
o = r;
}
if (_delegate != nil)
{
r = [_delegate unarchiver: self didDecodeObject: o];
if (r != o)
{
[_delegate unarchiver: self
willReplaceObject: o
withObject: r];
o = r;
}
}
if (o == nil)
{
obj = RETAIN(GSIArrayItemAtIndex(_objMap, 0).obj);
}
else
{
obj = o;
}
_keyMap = savedKeyMap;
_cursor = savedCursor;
}
else
{
RETAIN(obj); // Use the decoded object directly
}
GSIArraySetItemAtIndex(_objMap, (GSIArrayItem)obj, index);
return obj;
}
@end
@implementation NSKeyedUnarchiver
+ (Class) classForClassName: (NSString*)aString
@ -108,63 +272,234 @@ NSString * const NSInvalidUnarchiveOperationException
- (Class) classForClassName: (NSString*)aString
{
[self notImplemented: _cmd];
return nil;
return (Class)NSMapGet(_clsMap, (void*)aString);
}
- (BOOL) containsValueForKey: (NSString*)aKey
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
return YES;
}
return NO;
}
- (void) dealloc
{
DESTROY(_archive);
if (_clsMap != 0)
{
NSFreeMapTable(_clsMap);
_clsMap = 0;
}
if (_objMap != 0)
{
NSZone *z = _objMap->zone;
GSIArrayClear(_objMap);
NSZoneFree(z, (void*)_objMap);
}
[super dealloc];
}
- (BOOL) decodeBoolForKey: (NSString*)aKey
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
if ([o isKindOfClass: [NSNumber class]] == YES)
{
return [o boolValue];
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
oldKey, o];
}
}
return NO;
}
- (const uint8_t*) decodeBytesForKey: (NSString*)aKey
returnedLength: (unsigned*)length
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
if ([o isKindOfClass: [NSData class]] == YES)
{
*length = [o length];
return [o bytes];
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
oldKey, o];
}
}
*length = 0;
return 0;
}
- (double) decodeDoubleForKey: (NSString*)aKey
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
if ([o isKindOfClass: [NSNumber class]] == YES)
{
return [o doubleValue];
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
oldKey, o];
}
}
return 0.0;
}
- (float) decodeFloatForKey: (NSString*)aKey
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
if ([o isKindOfClass: [NSNumber class]] == YES)
{
return [o floatValue];
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
oldKey, o];
}
}
return 0.0;
}
- (int) decodeIntForKey: (NSString*)aKey
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
if ([o isKindOfClass: [NSNumber class]] == YES)
{
long long l = [o longLongValue];
return l;
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
oldKey, o];
}
}
return 0;
}
- (int32_t) decodeInt32ForKey: (NSString*)aKey
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
if ([o isKindOfClass: [NSNumber class]] == YES)
{
long long l = [o longLongValue];
return l;
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
oldKey, o];
}
}
return 0;
}
- (int64_t) decodeInt64ForKey: (NSString*)aKey
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
if ([o isKindOfClass: [NSNumber class]] == YES)
{
long long l = [o longLongValue];
return l;
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
oldKey, o];
}
}
return 0;
}
- (id) decodeObject
{
NSString *key = [NSString stringWithFormat: @"$%d", _cursor++];
NSNumber *pos;
id o = [_keyMap objectForKey: key];
if (o != nil)
{
if ([o isKindOfClass: [NSDictionary class]] == YES
&& (pos = [o objectForKey: @"CF$UID"]) != nil)
{
int index = [pos intValue];
return [self _decodeObject: index];
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
key, o];
}
}
return nil;
}
- (id) decodeObjectForKey: (NSString*)aKey
{
[self notImplemented: _cmd];
GETVAL
if (o != nil)
{
NSNumber *pos;
if ([o isKindOfClass: [NSDictionary class]] == YES
&& (pos = [o objectForKey: @"CF$UID"]) != nil)
{
int index = [pos intValue];
return [self _decodeObject: index];
}
else
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value for key(%@) is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
oldKey, o];
}
}
return nil;
}
@ -175,18 +510,67 @@ NSString * const NSInvalidUnarchiveOperationException
- (void) finishDecoding
{
[self notImplemented: _cmd];
[_delegate unarchiverWillFinish: self];
DESTROY(_archive);
[_delegate unarchiverDidFinish: self];
}
- (id) initForReadingWithData: (NSData*)data
{
[self notImplemented: _cmd];
self = [super init];
if (self)
{
NSPropertyListFormat format;
NSString *error;
_zone = [self zone];
_archive = [NSPropertyListSerialization propertyListFromData: data
mutabilityOption: NSPropertyListImmutable
format: &format
errorDescription: &error];
if (_archive == nil)
{
DESTROY(self);
}
else
{
unsigned count;
unsigned i;
RETAIN(_archive);
_archiverClass = [_archive objectForKey: @"$archiver"];
_version = [_archive objectForKey: @"$version"];
_objects = [_archive objectForKey: @"$objects"];
_keyMap = [_archive objectForKey: @"$top"];
_clsMap = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSNonOwnedPointerMapValueCallBacks, 0);
_objMap = NSZoneMalloc(_zone, sizeof(GSIArray_t));
count = [_objects count];
GSIArrayInitWithZoneAndCapacity(_objMap, _zone, count);
// Add marker for nil object
GSIArrayAddItem(_objMap, (GSIArrayItem)(void*)[NSNull null]);
// Add markers for unencoded objects.
for (i = 1; i < count; i++)
{
GSIArrayAddItem(_objMap, (GSIArrayItem)(void*)0);
}
}
}
return self;
}
- (void) setClass: (Class)aClass forClassName: (NSString*)aString
{
[self notImplemented: _cmd];
if (aString == nil)
{
NSMapRemove(_clsMap, (void*)aString);
}
else
{
NSMapInsert(_clsMap, (void*)aString, (void*)aClass);
}
}
- (void) setDelegate: (id)delegate