mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
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:
parent
f88e119c36
commit
383ae3d03b
3 changed files with 417 additions and 25 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue