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>
* wHeaders/Foundation/NSKeyedArchiver.h:
* Headers/Foundation/NSKeyedArchiver.h:
* Source/NSKeyedArchiver.m:
Add keyed version of geometry encoding methods as pointed out by
Fred Kiefer.

View file

@ -134,5 +134,28 @@ BOOL GSUserDefaultsFlag(GSUserDefaultFlagType type);
*/
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_ */

View file

@ -489,5 +489,85 @@
[self encodeValueOfObjCType: @encode(id) at: anObject withName: name];
}
@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/NSValue.h>
#include "GSPrivate.h"
@class GSString;
/*
* Setup for inline operation of pointer map tables.
*/
#define GSI_MAP_RETAIN_KEY(M, X)
#define GSI_MAP_RELEASE_KEY(M, X)
#define GSI_MAP_RETAIN_KEY(M, X) RETAIN(X.obj)
#define GSI_MAP_RELEASE_KEY(M, X) RELEASE(X.obj)
#define GSI_MAP_RETAIN_VAL(M, X)
#define GSI_MAP_RELEASE_VAL(M, X)
#define GSI_MAP_HASH(M, X) ((X).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>
@ -70,45 +74,70 @@ static NSMapTable *globalClassMap = 0;
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)
- (NSDictionary*) _buildObjectReference: (id)anObject;
- (void) _encodeObject: (id)anObject
forKey: (NSString*)aKey
conditional: (BOOL)conditional;
- (void) _encodeArrayOfObjects: (NSArray*)anArray forKey: (NSString*)aKey;
- (id) _encodeObject: (id)anObject conditional: (BOOL)conditional;
@end
@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];
[_obj addObject: anObject];
o = makeReference(0);
}
return [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: ref]
forKey: @"CF$UID"];
else
{
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
* archiving of objects.
* archiving of objects. It returns the object to be stored in the
* mapping dictionary (_enc).
*/
- (void) _encodeObject: (id)anObject
forKey: (NSString*)aKey
conditional: (BOOL)conditional
- (id) _encodeObject: (id)anObject conditional: (BOOL)conditional
{
id original = anObject;
GSIMapNode node;
id objectInfo = nil; // Encoded object
NSMutableDictionary *m = nil;
NSNumber *refNum;
NSDictionary *keyDict;
unsigned ref = 0;
NSDictionary *refObject;
unsigned ref = 0; // Reference to nil
if (anObject != nil)
{
@ -166,8 +195,11 @@ static NSMapTable *globalClassMap = 0;
}
else
{
Class c = [anObject class];
// 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.
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];
keyDict = [NSDictionary dictionaryWithObject: refNum forKey: @"CF$UID"];
[_enc setObject: keyDict forKey: aKey];
RELEASE(refNum);
refObject = makeReference(ref);
/*
* 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
* in the object description dictionary for the object we just encoded.
*/
refNum = [[NSNumber alloc] initWithInt: ref];
keyDict = [NSDictionary dictionaryWithObject: refNum forKey: @"CF$UID"];
[m setObject: keyDict forKey: @"$class"];
RELEASE(refNum);
[m setObject: makeReference(ref) forKey: @"$class"];
}
/*
@ -330,6 +356,11 @@ static NSMapTable *globalClassMap = 0;
{
[_delegate archiver: self didEncodeObject: anObject];
}
/*
* Return the dictionary identifying the encoded object.
*/
return refObject;
}
@end
@ -445,6 +476,19 @@ static NSMapTable *globalClassMap = 0;
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
{
CHECKKEY
@ -462,16 +506,18 @@ static NSMapTable *globalClassMap = 0;
- (void) encodeConditionalObject: (id)anObject
{
[self _encodeObject: anObject
forKey: [NSString stringWithFormat: @"$%u", _keyNum++]
conditional: YES];
NSString *aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
anObject = [self _encodeObject: anObject conditional: YES];
[_enc setObject: anObject forKey: aKey];
}
- (void) encodeConditionalObject: (id)anObject forKey: (NSString*)aKey
{
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
@ -511,16 +557,18 @@ static NSMapTable *globalClassMap = 0;
- (void) encodeObject: (id)anObject
{
[self _encodeObject: anObject
forKey: [NSString stringWithFormat: @"$%u", _keyNum++]
conditional: NO];
NSString *aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
anObject = [self _encodeObject: anObject conditional: NO];
[_enc setObject: anObject forKey: aKey];
}
- (void) encodeObject: (id)anObject forKey: (NSString*)aKey
{
CHECKKEY
[self _encodeObject: anObject forKey: aKey conditional: NO];
anObject = [self _encodeObject: anObject conditional: NO];
[_enc setObject: anObject forKey: aKey];
}
- (void) encodePoint: (NSPoint)p

View file

@ -29,6 +29,8 @@
#include <Foundation/NSNull.h>
#include <Foundation/NSValue.h>
#include "GSPrivate.h"
/*
* Setup for inline operation of arrays.
*/
@ -49,7 +51,6 @@ NSString * const NSInvalidUnarchiveOperationException
static NSMapTable globalClassMap = 0;
#define GETVAL \
NSString *oldKey = aKey; \
id o; \
\
if ([aKey isKindOfClass: [NSString class]] == NO) \
@ -62,21 +63,60 @@ static NSMapTable globalClassMap = 0;
{ \
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) _decodeArrayOfObjectsForKey: (NSString*)aKey;
- (id) _decodeObject: (unsigned)index;
@end
@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 o;
@ -308,8 +348,36 @@ static NSMapTable globalClassMap = 0;
[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
{
NSString *oldKey = aKey;
GETVAL
if (o != nil)
{
@ -331,6 +399,7 @@ static NSMapTable globalClassMap = 0;
- (const uint8_t*) decodeBytesForKey: (NSString*)aKey
returnedLength: (unsigned*)length
{
NSString *oldKey = aKey;
GETVAL
if (o != nil)
{
@ -353,6 +422,7 @@ static NSMapTable globalClassMap = 0;
- (double) decodeDoubleForKey: (NSString*)aKey
{
NSString *oldKey = aKey;
GETVAL
if (o != nil)
{
@ -373,6 +443,7 @@ static NSMapTable globalClassMap = 0;
- (float) decodeFloatForKey: (NSString*)aKey
{
NSString *oldKey = aKey;
GETVAL
if (o != nil)
{
@ -393,6 +464,7 @@ static NSMapTable globalClassMap = 0;
- (int) decodeIntForKey: (NSString*)aKey
{
NSString *oldKey = aKey;
GETVAL
if (o != nil)
{
@ -415,6 +487,7 @@ static NSMapTable globalClassMap = 0;
- (int32_t) decodeInt32ForKey: (NSString*)aKey
{
NSString *oldKey = aKey;
GETVAL
if (o != nil)
{
@ -437,6 +510,7 @@ static NSMapTable globalClassMap = 0;
- (int64_t) decodeInt64ForKey: (NSString*)aKey
{
NSString *oldKey = aKey;
GETVAL
if (o != nil)
{
@ -485,6 +559,7 @@ static NSMapTable globalClassMap = 0;
- (id) decodeObjectForKey: (NSString*)aKey
{
NSString *oldKey = aKey;
GETVAL
if (o != nil)
{

View file

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