mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-10 16:20:42 +00:00
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:
parent
cb36d86fb7
commit
c8b5bed53f
6 changed files with 295 additions and 53 deletions
18
ChangeLog
18
ChangeLog
|
@ -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.
|
||||
|
|
|
@ -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_ */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue