Updated keyed coding to a (hopefully) useable state

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@18480 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2004-01-25 18:39:20 +00:00
parent cb36d86fb7
commit c8b5bed53f
6 changed files with 295 additions and 53 deletions

View file

@ -1,6 +1,22 @@
2004-01-25 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSPropertyList.m: Fix bug in encoding integers as xml.
* Source/GSPrivate.h: Added internal class for handling old style
arrays of items within keyed coding ... should this go elsewhere?
* Source/NSCoder.m: Added internal class for keyed coding of
arrays of items.
* Source/NSKeyedArchiver.m: Added support for
([encodeArrayOfobjCType:count:at:]) and the private
([_encodeArrayOfObjects:forKey:]) method. This completes (afaik) the
implementation for archiving ... and it's somewhat tested for xml
coding. Time to start using and debugging.
* Source/NSKeyedUnarchiver.m: All methods now implemented, but no
proper type checking/coercion done, and minimal testing done.
No attempt to handle OpenStep style property lists either, just xml!
2004-01-24 Richard Frith-Macdonald <rfm@gnu.org> 2004-01-24 Richard Frith-Macdonald <rfm@gnu.org>
* wHeaders/Foundation/NSKeyedArchiver.h: * Headers/Foundation/NSKeyedArchiver.h:
* Source/NSKeyedArchiver.m: * Source/NSKeyedArchiver.m:
Add keyed version of geometry encoding methods as pointed out by Add keyed version of geometry encoding methods as pointed out by
Fred Kiefer. Fred Kiefer.

View file

@ -134,5 +134,28 @@ BOOL GSUserDefaultsFlag(GSUserDefaultFlagType type);
*/ */
BOOL GSEnvironmentFlag(const char *name, BOOL def); BOOL GSEnvironmentFlag(const char *name, BOOL def);
/**
* This class exists simply as a mechanism for encapsulating arrays
* encoded using [NSKeyedArchiver-encodeArrayOfObjCType:count:at:]
*/
@interface _NSKeyedCoderOldStyleArray : NSObject <NSCoding>
{
char _t[2];
unsigned _c;
unsigned _s;
const void *_a;
NSData *_d; // Only valid after initWithCoder:
}
- (const void*) bytes;
- (unsigned) count;
- (void) encodeWithCoder: (NSCoder*)aCoder;
- (id) initWithCoder: (NSCoder*)aCoder;
- (id) initWithObjCType: (const char*)t count: (int)c at: (const void*)a;
- (unsigned) size;
- (const char*) type;
@end
#endif /* __GSPrivate_h_ */ #endif /* __GSPrivate_h_ */

View file

@ -489,5 +489,85 @@
[self encodeValueOfObjCType: @encode(id) at: anObject withName: name]; [self encodeValueOfObjCType: @encode(id) at: anObject withName: name];
} }
@end @end
#include "GSPrivate.h"
@implementation _NSKeyedCoderOldStyleArray
- (const void*) bytes
{
return _a;
}
- (unsigned) count
{
return _c;
}
- (void) dealloc
{
DESTROY(_d);
[super dealloc];
}
- (id) initWithCoder: (NSCoder*)aCoder
{
id o;
void *address;
unsigned i;
_c = [aCoder decodeIntForKey: @"NS.count"];
_t[0] = (char)[aCoder decodeIntForKey: @"NS.type"];
_t[1] = '\0';
/*
* We decode the size from the remote end, but discard it as we
* are probably safer to use the local size of the datatype involved.
*/
_s = [aCoder decodeIntForKey: @"NS.size"];
_s = objc_sizeof_type(_t);
_d = o = [[NSMutableData alloc] initWithLength: _c * _s];
_a = address = [o mutableBytes];
for (i = 0; i < _c; i++)
{
[aCoder decodeValueOfObjCType: _t at: address];
address += _s;
}
return self;
}
- (id) initWithObjCType: (const char*)t count: (int)c at: (const void*)a
{
_t[0] = *t;
_t[1] = '\0';
_s = objc_sizeof_type(_t);
_c = c;
_a = a;
return self;
}
- (void) encodeWithCoder: (NSCoder*)aCoder
{
int i;
[aCoder encodeInt: _c forKey: @"NS.count"];
[aCoder encodeInt: *_t forKey: @"NS.type"];
[aCoder encodeInt: _s forKey: @"NS.size"];
for (i = 0; i < _c; i++)
{
[aCoder encodeValueOfObjCType: _t at: _a];
_a += _s;
}
}
- (unsigned) size
{
return _s;
}
- (const char*) type
{
return _t;
}
@end

View file

@ -28,16 +28,20 @@
#include <Foundation/NSException.h> #include <Foundation/NSException.h>
#include <Foundation/NSValue.h> #include <Foundation/NSValue.h>
#include "GSPrivate.h"
@class GSString;
/* /*
* Setup for inline operation of pointer map tables. * Setup for inline operation of pointer map tables.
*/ */
#define GSI_MAP_RETAIN_KEY(M, X) #define GSI_MAP_RETAIN_KEY(M, X) RETAIN(X.obj)
#define GSI_MAP_RELEASE_KEY(M, X) #define GSI_MAP_RELEASE_KEY(M, X) RELEASE(X.obj)
#define GSI_MAP_RETAIN_VAL(M, X) #define GSI_MAP_RETAIN_VAL(M, X)
#define GSI_MAP_RELEASE_VAL(M, X) #define GSI_MAP_RELEASE_VAL(M, X)
#define GSI_MAP_HASH(M, X) ((X).uint) #define GSI_MAP_HASH(M, X) ((X).uint)
#define GSI_MAP_EQUAL(M, X,Y) ((X).uint == (Y).uint) #define GSI_MAP_EQUAL(M, X,Y) ((X).uint == (Y).uint)
#define GSI_MAP_NOCLEAN 1 #undef GSI_MAP_NOCLEAN
#include <GNUstepBase/GSIMap.h> #include <GNUstepBase/GSIMap.h>
@ -70,45 +74,70 @@ static NSMapTable *globalClassMap = 0;
NSStringFromClass([self class]), aKey, NSStringFromSelector(_cmd)]; \ NSStringFromClass([self class]), aKey, NSStringFromSelector(_cmd)]; \
} }
/*
* Make a dictionary referring to the object at ref in the array of all objects.
*/
static NSDictionary *makeReference(unsigned ref)
{
NSNumber *n;
NSDictionary *d;
n = [NSNumber numberWithUnsignedInt: ref];
d = [NSDictionary dictionaryWithObject: n forKey: @"CF$UID"];
return d;
}
@interface NSKeyedArchiver (Private) @interface NSKeyedArchiver (Private)
- (NSDictionary*) _buildObjectReference: (id)anObject; - (void) _encodeArrayOfObjects: (NSArray*)anArray forKey: (NSString*)aKey;
- (void) _encodeObject: (id)anObject - (id) _encodeObject: (id)anObject conditional: (BOOL)conditional;
forKey: (NSString*)aKey
conditional: (BOOL)conditional;
@end @end
@implementation NSKeyedArchiver (Private) @implementation NSKeyedArchiver (Private)
/*
* Add an object to the table off all encoded objects, and return a reference.
*/
- (NSDictionary*) _buildObjectReference: (id)anObject
{
unsigned ref = 0;
if (anObject != nil) /**
* Internal method used to encode an array relatively efficiently.<br />
* Some MacOS-X library classes seem to use this.
*/
- (void) _encodeArrayOfObjects: (NSArray*)anArray forKey: (NSString*)aKey
{
id o;
CHECKKEY
if (anArray == nil)
{ {
ref = [_obj count]; o = makeReference(0);
[_obj addObject: anObject];
} }
return [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: ref] else
forKey: @"CF$UID"]; {
NSMutableArray *m;
unsigned c;
unsigned i;
c = [anArray count];
m = [NSMutableArray arrayWithCapacity: c];
for (i = 0; i < c; i++)
{
o = [self _encodeObject: [anArray objectAtIndex: i] conditional: NO];
[m addObject: o];
}
o = m;
}
[_enc setObject: o forKey: aKey];
} }
/* /*
* The real workhorse of the archiving process ... this deals with all * The real workhorse of the archiving process ... this deals with all
* archiving of objects. * archiving of objects. It returns the object to be stored in the
* mapping dictionary (_enc).
*/ */
- (void) _encodeObject: (id)anObject - (id) _encodeObject: (id)anObject conditional: (BOOL)conditional
forKey: (NSString*)aKey
conditional: (BOOL)conditional
{ {
id original = anObject; id original = anObject;
GSIMapNode node; GSIMapNode node;
id objectInfo = nil; // Encoded object id objectInfo = nil; // Encoded object
NSMutableDictionary *m = nil; NSMutableDictionary *m = nil;
NSNumber *refNum; NSDictionary *refObject;
NSDictionary *keyDict; unsigned ref = 0; // Reference to nil
unsigned ref = 0;
if (anObject != nil) if (anObject != nil)
{ {
@ -166,8 +195,11 @@ static NSMapTable *globalClassMap = 0;
} }
else else
{ {
Class c = [anObject class];
// FIXME ... exactly what classes are stored directly??? // FIXME ... exactly what classes are stored directly???
if ([anObject isKindOfClass: [NSString class]] == YES) if ([anObject isKindOfClass: [GSString class]] == YES
|| c == [@"literal" class])
{ {
// We will store the string object directly. // We will store the string object directly.
objectInfo = anObject; objectInfo = anObject;
@ -209,12 +241,9 @@ static NSMapTable *globalClassMap = 0;
} }
/* /*
* Store the mapping from aKey to the appropriate entry in _obj * Build an object to reference the encoded value of anObject
*/ */
refNum = [[NSNumber alloc] initWithInt: ref]; refObject = makeReference(ref);
keyDict = [NSDictionary dictionaryWithObject: refNum forKey: @"CF$UID"];
[_enc setObject: keyDict forKey: aKey];
RELEASE(refNum);
/* /*
* objectInfo is a dictionary describing the object. * objectInfo is a dictionary describing the object.
@ -317,10 +346,7 @@ static NSMapTable *globalClassMap = 0;
* Now create a reference to the class information and store it * Now create a reference to the class information and store it
* in the object description dictionary for the object we just encoded. * in the object description dictionary for the object we just encoded.
*/ */
refNum = [[NSNumber alloc] initWithInt: ref]; [m setObject: makeReference(ref) forKey: @"$class"];
keyDict = [NSDictionary dictionaryWithObject: refNum forKey: @"CF$UID"];
[m setObject: keyDict forKey: @"$class"];
RELEASE(refNum);
} }
/* /*
@ -330,6 +356,11 @@ static NSMapTable *globalClassMap = 0;
{ {
[_delegate archiver: self didEncodeObject: anObject]; [_delegate archiver: self didEncodeObject: anObject];
} }
/*
* Return the dictionary identifying the encoded object.
*/
return refObject;
} }
@end @end
@ -445,6 +476,19 @@ static NSMapTable *globalClassMap = 0;
return _delegate; return _delegate;
} }
- (void) encodeArrayOfObjCType: (const char*)aType
count: (unsigned)aCount
at: (const void*)address
{
id o;
o = [[_NSKeyedCoderOldStyleArray alloc] initWithObjCType: aType
count: aCount
at: address];
[self encodeObject: o];
RELEASE(o);
}
- (void) encodeBool: (BOOL)aBool forKey: (NSString*)aKey - (void) encodeBool: (BOOL)aBool forKey: (NSString*)aKey
{ {
CHECKKEY CHECKKEY
@ -462,16 +506,18 @@ static NSMapTable *globalClassMap = 0;
- (void) encodeConditionalObject: (id)anObject - (void) encodeConditionalObject: (id)anObject
{ {
[self _encodeObject: anObject NSString *aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
forKey: [NSString stringWithFormat: @"$%u", _keyNum++]
conditional: YES]; anObject = [self _encodeObject: anObject conditional: YES];
[_enc setObject: anObject forKey: aKey];
} }
- (void) encodeConditionalObject: (id)anObject forKey: (NSString*)aKey - (void) encodeConditionalObject: (id)anObject forKey: (NSString*)aKey
{ {
CHECKKEY CHECKKEY
[self _encodeObject: anObject forKey: aKey conditional: YES]; anObject = [self _encodeObject: anObject conditional: YES];
[_enc setObject: anObject forKey: aKey];
} }
- (void) encodeDouble: (double)aDouble forKey: (NSString*)aKey - (void) encodeDouble: (double)aDouble forKey: (NSString*)aKey
@ -511,16 +557,18 @@ static NSMapTable *globalClassMap = 0;
- (void) encodeObject: (id)anObject - (void) encodeObject: (id)anObject
{ {
[self _encodeObject: anObject NSString *aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
forKey: [NSString stringWithFormat: @"$%u", _keyNum++]
conditional: NO]; anObject = [self _encodeObject: anObject conditional: NO];
[_enc setObject: anObject forKey: aKey];
} }
- (void) encodeObject: (id)anObject forKey: (NSString*)aKey - (void) encodeObject: (id)anObject forKey: (NSString*)aKey
{ {
CHECKKEY CHECKKEY
[self _encodeObject: anObject forKey: aKey conditional: NO]; anObject = [self _encodeObject: anObject conditional: NO];
[_enc setObject: anObject forKey: aKey];
} }
- (void) encodePoint: (NSPoint)p - (void) encodePoint: (NSPoint)p

View file

@ -29,6 +29,8 @@
#include <Foundation/NSNull.h> #include <Foundation/NSNull.h>
#include <Foundation/NSValue.h> #include <Foundation/NSValue.h>
#include "GSPrivate.h"
/* /*
* Setup for inline operation of arrays. * Setup for inline operation of arrays.
*/ */
@ -49,7 +51,6 @@ NSString * const NSInvalidUnarchiveOperationException
static NSMapTable globalClassMap = 0; static NSMapTable globalClassMap = 0;
#define GETVAL \ #define GETVAL \
NSString *oldKey = aKey; \
id o; \ id o; \
\ \
if ([aKey isKindOfClass: [NSString class]] == NO) \ if ([aKey isKindOfClass: [NSString class]] == NO) \
@ -62,21 +63,60 @@ static NSMapTable globalClassMap = 0;
{ \ { \
aKey = [@"$" stringByAppendingString: aKey]; \ 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]; o = [_keyMap objectForKey: aKey];
@interface NSKeyedUnarchiver (Private) @interface NSKeyedUnarchiver (Private)
- (id) _decodeArrayOfObjectsForKey: (NSString*)aKey;
- (id) _decodeObject: (unsigned)index; - (id) _decodeObject: (unsigned)index;
@end @end
@implementation NSKeyedUnarchiver (Private) @implementation NSKeyedUnarchiver (Private)
/**
* Internal method used to decode an array relatively efficiently.<br />
* Some MacOS-X library classes seem to use this.
*/
- (id) _decodeArrayOfObjectsForKey: (NSString*)aKey
{
id o = [_keyMap objectForKey: aKey];
if (o != nil)
{
if ([o isKindOfClass: [NSArray class]] == YES)
{
unsigned c = [o count];
NSMutableArray *m = [NSMutableArray arrayWithCapacity: c];
unsigned i;
for (i = 0; i < c; i++)
{
unsigned ref;
id val;
ref = [[[o objectAtIndex: i] objectForKey: @"CF$UID"]
unsignedIntValue];
val = [self _decodeObject: ref];
if (val == nil)
{
[NSException raise:
NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: decoded nil in array",
NSStringFromClass([self class]),
NSStringFromSelector(_cmd)];
}
[m addObject: val];
}
o = m;
}
else
{
o = nil;
}
}
return o;
}
- (id) _decodeObject: (unsigned)index - (id) _decodeObject: (unsigned)index
{ {
id o; id o;
@ -308,8 +348,36 @@ static NSMapTable globalClassMap = 0;
[super dealloc]; [super dealloc];
} }
- (void) decodeArrayOfObjCType: (const char*)type
count: (unsigned)expected
at: (void*)buf
{
id o = [self decodeObject];
if ([o isKindOfClass: [_NSKeyedCoderOldStyleArray class]] == NO)
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: value is '%@'",
NSStringFromClass([self class]), NSStringFromSelector(_cmd), o];
}
if (strcmp([o type], type) != 0)
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: type missmatch",
NSStringFromClass([self class]), NSStringFromSelector(_cmd), o];
}
if ([o count] != expected)
{
[NSException raise: NSInvalidUnarchiveOperationException
format: @"[%@ +%@]: count missmatch",
NSStringFromClass([self class]), NSStringFromSelector(_cmd), o];
}
memcpy(buf, [o bytes], expected * objc_sizeof_type(type));
}
- (BOOL) decodeBoolForKey: (NSString*)aKey - (BOOL) decodeBoolForKey: (NSString*)aKey
{ {
NSString *oldKey = aKey;
GETVAL GETVAL
if (o != nil) if (o != nil)
{ {
@ -331,6 +399,7 @@ static NSMapTable globalClassMap = 0;
- (const uint8_t*) decodeBytesForKey: (NSString*)aKey - (const uint8_t*) decodeBytesForKey: (NSString*)aKey
returnedLength: (unsigned*)length returnedLength: (unsigned*)length
{ {
NSString *oldKey = aKey;
GETVAL GETVAL
if (o != nil) if (o != nil)
{ {
@ -353,6 +422,7 @@ static NSMapTable globalClassMap = 0;
- (double) decodeDoubleForKey: (NSString*)aKey - (double) decodeDoubleForKey: (NSString*)aKey
{ {
NSString *oldKey = aKey;
GETVAL GETVAL
if (o != nil) if (o != nil)
{ {
@ -373,6 +443,7 @@ static NSMapTable globalClassMap = 0;
- (float) decodeFloatForKey: (NSString*)aKey - (float) decodeFloatForKey: (NSString*)aKey
{ {
NSString *oldKey = aKey;
GETVAL GETVAL
if (o != nil) if (o != nil)
{ {
@ -393,6 +464,7 @@ static NSMapTable globalClassMap = 0;
- (int) decodeIntForKey: (NSString*)aKey - (int) decodeIntForKey: (NSString*)aKey
{ {
NSString *oldKey = aKey;
GETVAL GETVAL
if (o != nil) if (o != nil)
{ {
@ -415,6 +487,7 @@ static NSMapTable globalClassMap = 0;
- (int32_t) decodeInt32ForKey: (NSString*)aKey - (int32_t) decodeInt32ForKey: (NSString*)aKey
{ {
NSString *oldKey = aKey;
GETVAL GETVAL
if (o != nil) if (o != nil)
{ {
@ -437,6 +510,7 @@ static NSMapTable globalClassMap = 0;
- (int64_t) decodeInt64ForKey: (NSString*)aKey - (int64_t) decodeInt64ForKey: (NSString*)aKey
{ {
NSString *oldKey = aKey;
GETVAL GETVAL
if (o != nil) if (o != nil)
{ {
@ -485,6 +559,7 @@ static NSMapTable globalClassMap = 0;
- (id) decodeObjectForKey: (NSString*)aKey - (id) decodeObjectForKey: (NSString*)aKey
{ {
NSString *oldKey = aKey;
GETVAL GETVAL
if (o != nil) if (o != nil)
{ {

View file

@ -1531,7 +1531,7 @@ OAppend(id obj, NSDictionary *loc, unsigned lev, unsigned step,
{ {
if (x == NSPropertyListXMLFormat_v1_0) if (x == NSPropertyListXMLFormat_v1_0)
{ {
[dest appendBytes: "<integer>" length: 8]; [dest appendBytes: "<integer>" length: 9];
XString([obj stringValue], dest); XString([obj stringValue], dest);
[dest appendBytes: "</integer>\n" length: 11]; [dest appendBytes: "</integer>\n" length: 11];
} }