mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-22 16:33:29 +00:00
NSSerialisation rewrite.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@3242 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
273e6d76d4
commit
71e18a67f4
4 changed files with 486 additions and 311 deletions
|
@ -1,3 +1,11 @@
|
|||
Thu Nov 19 16:00:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
|
||||
* src/include/NSSerializer.h: Removed erroneous protocol conformance
|
||||
for NSSerializer and NSDeserializer.
|
||||
* src/NSSerializer.m: Complete rewrite - full OpenStep compatibility
|
||||
and huge speed increase.
|
||||
* doc/todo.tmpl.texi: Update todo list.
|
||||
|
||||
Thu Nov 19 12:30:00 1998 Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
|
||||
* src/NSData.m: ([-encodeWithCoder:]) bugfix for case where data object
|
||||
|
|
|
@ -12,17 +12,12 @@
|
|||
|
||||
@item Implement Formatter classes (NSDateFormatter, etc) [5] (980722).
|
||||
|
||||
@item Implement NSDecimalNumber stuff [5] (981119).
|
||||
|
||||
@item Check that every class implements coding (correctly). [2, NSCoder] (980721).
|
||||
|
||||
@item Check that every class implements copying (correctly) - i.e. non-mutable classes should just retain, etc. [1, NSCopying] (980721).
|
||||
|
||||
@item Implement [NSDeserializer +deserializePropertyListLazilyFromData:atCursor:length:mutableContainers:]
|
||||
[3 NSProxy] (980712)
|
||||
|
||||
@item Implement [NSDeserialiser - deserializeObjectAt:ofObjCType:fromData:atCursor:] [1] (980712)
|
||||
|
||||
@item Implement [NSSerialiser - serializeObjectAt:ofObjCType:fromData:] [1] (980712)
|
||||
|
||||
@item Improve initWithFormat releated methods for NSString and find out how to implemente the locale stuff [4 OPENSTEP/Rhapsody] (980712)
|
||||
|
||||
@item Make gstep-base 64bit clean [5, 64bit machine] (980629)
|
||||
|
@ -41,7 +36,7 @@ an exception. [4, exceptions, threads] (980220)
|
|||
|
||||
@item Fix all the places marked FIXME or xxx. [3-9] (980629)
|
||||
|
||||
@item Write tests for various classes using the testsuite build
|
||||
@item Write tests for various classes using the testsuite built
|
||||
by Richard Frith-Macdonald @email{richard@@brainstorm.co.uk}. Contact
|
||||
him for details. [3, guile] (980629)
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Date: 1995
|
||||
Updated by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
||||
Date: 1997
|
||||
Date: 1998
|
||||
|
||||
This file is part of the GNUstep Base Library.
|
||||
|
||||
|
@ -38,27 +38,22 @@
|
|||
intoData: (NSMutableData*)data;
|
||||
@end
|
||||
|
||||
@interface NSSerializer: NSObject <NSObjCTypeSerializationCallBack>
|
||||
{
|
||||
}
|
||||
@interface NSSerializer: NSObject
|
||||
+ (NSData*) serializePropertyList: (id)propertyList;
|
||||
+ (void) serializePropertyList: (id)propertyList
|
||||
intoData: (NSMutableData*)d;
|
||||
@end
|
||||
|
||||
@interface NSDeserializer: NSObject <NSObjCTypeSerializationCallBack>
|
||||
{
|
||||
BOOL mutableContainer;
|
||||
}
|
||||
@interface NSDeserializer: NSObject
|
||||
+ (id) deserializePropertyListFromData: (NSData*)data
|
||||
atCursor: (unsigned int*)cursor
|
||||
mutableContainers: (BOOL)flag;
|
||||
+ (id) deserializePropertyListFromData: (NSData*)data
|
||||
mutableContainers: (BOOL)flag;
|
||||
+ (id) deserializePropertyListLazilyFromData: (NSData*)data
|
||||
atCursor: (unsigned*)cursor
|
||||
length: (unsigned)length
|
||||
mutableContainers: (BOOL)flag;
|
||||
atCursor: (unsigned*)cursor
|
||||
length: (unsigned)length
|
||||
mutableContainers: (BOOL)flag;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -23,342 +23,519 @@
|
|||
|
||||
#include <config.h>
|
||||
#include <gnustep/base/preface.h>
|
||||
#include <gnustep/base/fast.x>
|
||||
#include <gnustep/base/mframe.h>
|
||||
#include <Foundation/NSData.h>
|
||||
#include <Foundation/NSDictionary.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSProxy.h>
|
||||
|
||||
@class NSGMutableCString;
|
||||
@class NSGCString;
|
||||
#ifdef UNICODE
|
||||
@class NSGString;
|
||||
@class NSGMutableString;
|
||||
#endif
|
||||
@class NSGArray;
|
||||
@class NSGMutableArray;
|
||||
@class NSGDictionary;
|
||||
@class NSGMutableDictionary;
|
||||
@class NSDataMalloc;
|
||||
|
||||
typedef enum {
|
||||
ST_CSTRING,
|
||||
ST_MCSTRING,
|
||||
ST_STRING,
|
||||
ST_MSTRING,
|
||||
ST_DATA,
|
||||
ST_MDATA,
|
||||
ST_ARRAY,
|
||||
ST_MARRAY,
|
||||
ST_DICT,
|
||||
ST_MDICT
|
||||
} SerializerType;
|
||||
/*
|
||||
* Define constants for data types and variables to hold them.
|
||||
*/
|
||||
#define ST_CSTRING 0
|
||||
#define ST_STRING 1
|
||||
#define ST_ARRAY 2
|
||||
#define ST_MARRAY 3
|
||||
#define ST_DICT 4
|
||||
#define ST_MDICT 5
|
||||
#define ST_DATA 6
|
||||
|
||||
static char st_cstring = (char)ST_CSTRING;
|
||||
static char st_string = (char)ST_STRING;
|
||||
static char st_array = (char)ST_ARRAY;
|
||||
static char st_marray = (char)ST_MARRAY;
|
||||
static char st_dict = (char)ST_DICT;
|
||||
static char st_mdict = (char)ST_MDICT;
|
||||
static char st_data = (char)ST_DATA;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Variables to cache class information.
|
||||
*/
|
||||
static Class ArrayClass = 0;
|
||||
static Class MutableArrayClass = 0;
|
||||
static Class DataClass = 0;
|
||||
static Class DictionaryClass = 0;
|
||||
static Class MutableDictionaryClass = 0;
|
||||
|
||||
typedef struct {
|
||||
NSMutableData *data;
|
||||
void (*appImp)(); // Append to data.
|
||||
void* (*datImp)(); // Bytes pointer.
|
||||
unsigned int (*lenImp)(); // Length of data.
|
||||
void (*serImp)(); // Serialize integer.
|
||||
void (*setImp)(); // Set length of data.
|
||||
} _NSSerializerInfo;
|
||||
|
||||
static SEL appSel = @selector(appendBytes:length:);
|
||||
static SEL datSel = @selector(mutableBytes);
|
||||
static SEL lenSel = @selector(length);
|
||||
static SEL serSel = @selector(serializeInt:);
|
||||
static SEL setSel = @selector(setLength:);
|
||||
|
||||
static void
|
||||
initSerializerInfo(_NSSerializerInfo* info, NSMutableData *d)
|
||||
{
|
||||
Class c = fastClass(d);
|
||||
|
||||
info->data = d;
|
||||
info->appImp = (void (*)())get_imp(c, appSel);
|
||||
info->datImp = (void* (*)())get_imp(c, datSel);
|
||||
info->lenImp = (unsigned int (*)())get_imp(c, lenSel);
|
||||
info->serImp = (void (*)())get_imp(c, serSel);
|
||||
info->setImp = (void (*)())get_imp(c, setSel);
|
||||
}
|
||||
|
||||
static id
|
||||
serializeToInfo(id object, _NSSerializerInfo* info)
|
||||
{
|
||||
Class c = fastClass(object);
|
||||
|
||||
if (c == _fastCls._NSGCString || c == _fastCls._NSGMutableCString ||
|
||||
c == _fastCls._NXConstantString)
|
||||
{
|
||||
unsigned slen = [object cStringLength] + 1;
|
||||
unsigned dlen;
|
||||
|
||||
(*info->appImp)(info->data, appSel, &st_cstring, 1);
|
||||
(*info->serImp)(info->data, serSel, slen);
|
||||
dlen = (*info->lenImp)(info->data, lenSel);
|
||||
(*info->setImp)(info->data, setSel, dlen + slen);
|
||||
[object getCString: (*info->datImp)(info->data, datSel) + dlen];
|
||||
}
|
||||
else if (fastClassIsKindOfClass(c, _fastCls._NSString))
|
||||
{
|
||||
unsigned slen = [object length];
|
||||
unsigned dlen;
|
||||
|
||||
(*info->appImp)(info->data, appSel, &st_string, 1);
|
||||
(*info->serImp)(info->data, serSel, slen);
|
||||
dlen = (*info->lenImp)(info->data, lenSel);
|
||||
(*info->setImp)(info->data, setSel, dlen + slen*sizeof(unichar));
|
||||
[object getCharacters: (*info->datImp)(info->data, datSel) + dlen];
|
||||
}
|
||||
else if (fastClassIsKindOfClass(c, ArrayClass))
|
||||
{
|
||||
unsigned int count;
|
||||
|
||||
if ([object isKindOfClass: MutableArrayClass])
|
||||
(*info->appImp)(info->data, appSel, &st_marray, 1);
|
||||
else
|
||||
(*info->appImp)(info->data, appSel, &st_array, 1);
|
||||
|
||||
count = [object count];
|
||||
(*info->serImp)(info->data, serSel, count);
|
||||
|
||||
if (count)
|
||||
{
|
||||
id objects[count];
|
||||
unsigned int i;
|
||||
|
||||
[object getObjects: objects];
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
serializeToInfo(objects[i], info);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fastClassIsKindOfClass(c, DictionaryClass))
|
||||
{
|
||||
NSEnumerator *e = [object keyEnumerator];
|
||||
id k;
|
||||
IMP nxtImp;
|
||||
IMP objImp;
|
||||
|
||||
nxtImp = [e methodForSelector: @selector(nextObject)];
|
||||
objImp = [object methodForSelector: @selector(objectForKey:)];
|
||||
|
||||
if ([object isKindOfClass: MutableDictionaryClass])
|
||||
(*info->appImp)(info->data, appSel, &st_mdict, 1);
|
||||
else
|
||||
(*info->appImp)(info->data, appSel, &st_dict, 1);
|
||||
|
||||
(*info->serImp)(info->data, serSel, [object count]);
|
||||
while ((k = (*nxtImp)(e, @selector(nextObject))) != nil)
|
||||
{
|
||||
id o = (*objImp)(object, @selector(objectForKey:), k);
|
||||
|
||||
serializeToInfo(k, info);
|
||||
serializeToInfo(o, info);
|
||||
}
|
||||
}
|
||||
else if (fastClassIsKindOfClass(c, DataClass))
|
||||
{
|
||||
(*info->appImp)(info->data, appSel, &st_data, 1);
|
||||
(*info->serImp)(info->data, serSel, [object length]);
|
||||
(*info->appImp)(info->data, appSel, [object bytes], [object length]);
|
||||
}
|
||||
else
|
||||
{
|
||||
[NSException raise: NSInvalidArgumentException
|
||||
format: @"Unknown class in property list"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@implementation NSSerializer
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [NSSerializer class])
|
||||
{
|
||||
ArrayClass = [NSArray class];
|
||||
MutableArrayClass = [NSMutableArray class];
|
||||
DataClass = [NSData class];
|
||||
DictionaryClass = [NSDictionary class];
|
||||
MutableDictionaryClass = [NSMutableDictionary class];
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSData*) serializePropertyList: (id)propertyList
|
||||
{
|
||||
NSMutableData* d = [NSMutableData new];
|
||||
_NSSerializerInfo info;
|
||||
|
||||
[self serializePropertyList: propertyList intoData: d];
|
||||
return [d autorelease];
|
||||
NSAssert(propertyList != nil, NSInvalidArgumentException);
|
||||
initSerializerInfo(&info, [NSMutableData dataWithCapacity: 1024]);
|
||||
serializeToInfo(propertyList, &info);
|
||||
return info.data;
|
||||
}
|
||||
|
||||
+ (void) serializePropertyList: (id)propertyList
|
||||
intoData: (NSMutableData*)d
|
||||
{
|
||||
NSSerializer* s = [self new];
|
||||
_NSSerializerInfo info;
|
||||
|
||||
[d serializeDataAt: &propertyList
|
||||
ofObjCType: @encode(id)
|
||||
context: s];
|
||||
[s release];
|
||||
}
|
||||
|
||||
- (void) deserializeObjectAt: (id*)object
|
||||
ofObjCType: (const char *)type
|
||||
fromData: (NSData*)data
|
||||
atCursor: (unsigned*)cursor
|
||||
{
|
||||
[self shouldNotImplement: _cmd];
|
||||
}
|
||||
|
||||
- (void) serializeObjectAt: (id*)objPtr
|
||||
ofObjCType: (const char *)type
|
||||
intoData: (NSMutableData*)data
|
||||
{
|
||||
id object;
|
||||
|
||||
assert(objPtr != 0);
|
||||
assert(type == @encode(id));
|
||||
object = *objPtr;
|
||||
if ([object isKindOfClass: [NSMutableData class]]) {
|
||||
[data serializeInt: ST_MDATA];
|
||||
[data serializeInt: [object length]];
|
||||
[data appendBytes: [object bytes] length: [object length]];
|
||||
}
|
||||
else if ([object isKindOfClass: [NSData class]]) {
|
||||
[data serializeInt: ST_DATA];
|
||||
[data serializeInt: [object length]];
|
||||
[data appendBytes: [object bytes] length: [object length]];
|
||||
}
|
||||
else if ([object isKindOfClass: [NSGMutableCString class]]) {
|
||||
[data serializeInt: ST_MCSTRING];
|
||||
[data serializeInt: [object cStringLength]];
|
||||
[data appendBytes: [object cString] length: [object cStringLength]];
|
||||
}
|
||||
else if ([object isKindOfClass: [NSGCString class]]) {
|
||||
[data serializeInt: ST_CSTRING];
|
||||
[data serializeInt: [object cStringLength]];
|
||||
[data appendBytes: [object cString] length: [object cStringLength]];
|
||||
}
|
||||
#ifdef UNICODE
|
||||
else if ([object isKindOfClass: [NSMutableString class]] ||
|
||||
[object isKindOfClass: [NSGMutableString class]]) {
|
||||
[data serializeInt: ST_MSTRING];
|
||||
[data serializeInt: [object cStringLength]];
|
||||
[data appendBytes: [object cString] length: [object cStringLength]];
|
||||
}
|
||||
else if ([object isKindOfClass: [NSString class]] ||
|
||||
[object isKindOfClass: [NSGString class]]) {
|
||||
[data serializeInt: ST_STRING];
|
||||
[data serializeInt: [object cStringLength]];
|
||||
[data appendBytes: [object cString] length: [object cStringLength]];
|
||||
}
|
||||
#endif
|
||||
else if ([object isKindOfClass: [NSMutableArray class]] ||
|
||||
[object isKindOfClass: [NSGMutableArray class]]) {
|
||||
unsigned int i;
|
||||
|
||||
[data serializeInt: ST_MARRAY];
|
||||
[data serializeInt: [object count]];
|
||||
for (i = 0; i < [object count]; i++) {
|
||||
id o = [object objectAtIndex: i];
|
||||
|
||||
[data serializeDataAt: &o
|
||||
ofObjCType: @encode(id)
|
||||
context: self];
|
||||
}
|
||||
}
|
||||
else if ([object isKindOfClass: [NSArray class]] ||
|
||||
[object isKindOfClass: [NSGArray class]]) {
|
||||
unsigned int i;
|
||||
|
||||
[data serializeInt: ST_ARRAY];
|
||||
[data serializeInt: [object count]];
|
||||
for (i = 0; i < [object count]; i++) {
|
||||
id o = [object objectAtIndex: i];
|
||||
|
||||
[data serializeDataAt: &o
|
||||
ofObjCType: @encode(id)
|
||||
context: self];
|
||||
}
|
||||
}
|
||||
else if ([object isKindOfClass: [NSMutableDictionary class]] ||
|
||||
[object isKindOfClass: [NSGMutableDictionary class]]) {
|
||||
NSEnumerator* e = [object keyEnumerator];
|
||||
id k;
|
||||
|
||||
[data serializeInt: ST_MDICT];
|
||||
[data serializeInt: [object count]];
|
||||
while ((k = [e nextObject]) != nil) {
|
||||
id o = [object objectForKey:k];
|
||||
|
||||
[data serializeDataAt: &k
|
||||
ofObjCType: @encode(id)
|
||||
context: self];
|
||||
[data serializeDataAt: &o
|
||||
ofObjCType: @encode(id)
|
||||
context: self];
|
||||
}
|
||||
}
|
||||
else if ([object isKindOfClass: [NSDictionary class]] ||
|
||||
[object isKindOfClass: [NSGDictionary class]]) {
|
||||
NSEnumerator* e = [object keyEnumerator];
|
||||
id k;
|
||||
|
||||
[data serializeInt: ST_DICT];
|
||||
[data serializeInt: [object count]];
|
||||
while ((k = [e nextObject]) != nil) {
|
||||
id o = [object objectForKey:k];
|
||||
|
||||
[data serializeDataAt: &k
|
||||
ofObjCType: @encode(id)
|
||||
context: self];
|
||||
[data serializeDataAt: &o
|
||||
ofObjCType: @encode(id)
|
||||
context: self];
|
||||
}
|
||||
}
|
||||
else {
|
||||
[NSException raise: NSGenericException
|
||||
format: @"Unknown class in property list"];
|
||||
}
|
||||
NSAssert(propertyList != nil, NSInvalidArgumentException);
|
||||
NSAssert(d != nil, NSInvalidArgumentException);
|
||||
initSerializerInfo(&info, d);
|
||||
serializeToInfo(propertyList, &info);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Variables to cache class information.
|
||||
*/
|
||||
static Class GArrayClass = 0;
|
||||
static Class GMutableArrayClass = 0;
|
||||
static Class GDataClass = 0;
|
||||
static Class GDictionaryClass = 0;
|
||||
static Class GMutableDictionaryClass = 0;
|
||||
|
||||
typedef struct {
|
||||
NSData *data;
|
||||
unsigned *cursor;
|
||||
BOOL mutable;
|
||||
void (*debImp)();
|
||||
unsigned int (*deiImp)();
|
||||
} _NSDeserializerInfo;
|
||||
|
||||
static SEL debSel = @selector(deserializeBytes:length:atCursor:);
|
||||
static SEL deiSel = @selector(deserializeIntAtCursor:);
|
||||
|
||||
static void
|
||||
initDeserializerInfo(_NSDeserializerInfo* info, NSData *d, unsigned *c, BOOL m)
|
||||
{
|
||||
info->data = d;
|
||||
info->cursor = c;
|
||||
info->mutable = m;
|
||||
info->debImp = (void (*)())[d methodForSelector: debSel];
|
||||
info->deiImp = (unsigned int (*)())[d methodForSelector: deiSel];
|
||||
}
|
||||
|
||||
static id
|
||||
deserializeFromInfo(_NSDeserializerInfo* info)
|
||||
{
|
||||
char code;
|
||||
unsigned int size;
|
||||
|
||||
(*info->debImp)(info->data, debSel, &code, 1, info->cursor);
|
||||
size = (*info->deiImp)(info->data, deiSel, info->cursor);
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case ST_CSTRING:
|
||||
{
|
||||
NSGCString *s;
|
||||
char *b = objc_malloc(size);
|
||||
|
||||
(*info->debImp)(info->data, debSel, b, size, info->cursor);
|
||||
s = [_fastCls._NSGCString allocWithZone: NSDefaultMallocZone()];
|
||||
s = [s initWithCStringNoCopy: b
|
||||
length: size-1
|
||||
fromZone: NSDefaultMallocZone()];
|
||||
return s;
|
||||
}
|
||||
|
||||
case ST_STRING:
|
||||
{
|
||||
NSGString *s;
|
||||
unichar *b = objc_malloc(size*2);
|
||||
|
||||
(*info->debImp)(info->data, debSel, b, size*2, info->cursor);
|
||||
s = [_fastCls._NSGString allocWithZone: NSDefaultMallocZone()];
|
||||
s = [s initWithCharactersNoCopy: b
|
||||
length: size
|
||||
fromZone: NSDefaultMallocZone()];
|
||||
return s;
|
||||
}
|
||||
|
||||
case ST_ARRAY:
|
||||
case ST_MARRAY:
|
||||
{
|
||||
id objects[size];
|
||||
id a;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
objects[i] = deserializeFromInfo(info);
|
||||
if (objects[i] == nil)
|
||||
{
|
||||
while (i > 0)
|
||||
{
|
||||
[objects[--i] release];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
if (code == ST_MARRAY || info->mutable)
|
||||
{
|
||||
a = [GMutableArrayClass allocWithZone: NSDefaultMallocZone()];
|
||||
a = [a initWithObjects: objects
|
||||
count: size];
|
||||
}
|
||||
else
|
||||
{
|
||||
a = [GArrayClass allocWithZone: NSDefaultMallocZone()];
|
||||
a = [a initWithObjects: objects
|
||||
count: size];
|
||||
}
|
||||
while (i > 0)
|
||||
{
|
||||
[objects[--i] release];
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
case ST_DICT:
|
||||
case ST_MDICT:
|
||||
{
|
||||
id keys[size];
|
||||
id objects[size];
|
||||
id d;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
keys[i] = deserializeFromInfo(info);
|
||||
if (keys[i] == nil)
|
||||
{
|
||||
while (i > 0)
|
||||
{
|
||||
[keys[--i] release];
|
||||
[objects[i] release];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
objects[i] = deserializeFromInfo(info);
|
||||
if (objects[i] == nil)
|
||||
{
|
||||
[keys[i] release];
|
||||
while (i > 0)
|
||||
{
|
||||
[keys[--i] release];
|
||||
[objects[i] release];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
if (code == ST_MDICT || info->mutable)
|
||||
{
|
||||
d=[GMutableDictionaryClass allocWithZone: NSDefaultMallocZone()];
|
||||
d = [d initWithObjects: objects
|
||||
forKeys: keys
|
||||
count: size];
|
||||
}
|
||||
else
|
||||
{
|
||||
d = [GDictionaryClass allocWithZone: NSDefaultMallocZone()];
|
||||
d = [d initWithObjects: objects
|
||||
forKeys: keys
|
||||
count: size];
|
||||
}
|
||||
while (i > 0)
|
||||
{
|
||||
[keys[--i] release];
|
||||
[objects[i] release];
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
case ST_DATA:
|
||||
{
|
||||
NSData *d;
|
||||
void *b = objc_malloc(size);
|
||||
|
||||
(*info->debImp)(info->data, debSel, b, size, info->cursor);
|
||||
d = [GDataClass allocWithZone: NSDefaultMallocZone()];
|
||||
d = [d initWithBytesNoCopy: b
|
||||
length: size
|
||||
fromZone: NSDefaultMallocZone()];
|
||||
return d;
|
||||
}
|
||||
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@interface _NSDeserializerProxy : NSProxy
|
||||
{
|
||||
_NSDeserializerInfo info;
|
||||
id plist;
|
||||
}
|
||||
+ (_NSDeserializerProxy*) proxyWithData: (NSData*)d
|
||||
atCursor: (unsigned int*)c
|
||||
mutable: (BOOL)m;
|
||||
@end
|
||||
|
||||
@implementation _NSDeserializerProxy
|
||||
+ (_NSDeserializerProxy*) proxyWithData: (NSData*)d
|
||||
atCursor: (unsigned int*)c
|
||||
mutable: (BOOL)m
|
||||
{
|
||||
_NSDeserializerProxy *proxy;
|
||||
|
||||
proxy = (_NSDeserializerProxy*)NSAllocateObject(self,0,NSDefaultMallocZone());
|
||||
initDeserializerInfo(&proxy->info, [d retain], c, m);
|
||||
return [proxy autorelease];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
[info.data release];
|
||||
[plist release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- forward: (SEL)aSel :(arglist_t)frame
|
||||
{
|
||||
IMP imp;
|
||||
|
||||
if (plist == nil && info.data != nil)
|
||||
{
|
||||
plist = deserializeFromInfo(&info);
|
||||
[info.data release];
|
||||
info.data = nil;
|
||||
}
|
||||
return [plist performv: aSel :frame];
|
||||
}
|
||||
|
||||
- (BOOL) isEqual: (id)other
|
||||
{
|
||||
if (other == self)
|
||||
return YES;
|
||||
else
|
||||
return [[self self] isEqual: other];
|
||||
}
|
||||
|
||||
- (id) self
|
||||
{
|
||||
if (plist == nil && info.data != nil)
|
||||
{
|
||||
plist = deserializeFromInfo(&info);
|
||||
[info.data release];
|
||||
info.data = nil;
|
||||
}
|
||||
return plist;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@implementation NSDeserializer
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (self == [NSDeserializer class])
|
||||
{
|
||||
GArrayClass = [NSGArray class];
|
||||
GMutableArrayClass = [NSGMutableArray class];
|
||||
GDataClass = [NSDataMalloc class];
|
||||
GDictionaryClass = [NSGDictionary class];
|
||||
GMutableDictionaryClass = [NSGMutableDictionary class];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id) deserializePropertyListFromData: (NSData*)data
|
||||
atCursor: (unsigned int*)cursor
|
||||
mutableContainers: (BOOL)flag
|
||||
{
|
||||
NSDeserializer* s = [self new];
|
||||
id o = nil;
|
||||
_NSDeserializerInfo info;
|
||||
id o;
|
||||
|
||||
s->mutableContainer = flag;
|
||||
[data deserializeDataAt: &o
|
||||
ofObjCType: @encode(id)
|
||||
atCursor: cursor
|
||||
context: s];
|
||||
[s release];
|
||||
return o;
|
||||
NSAssert(data != nil, NSInvalidArgumentException);
|
||||
NSAssert(cursor != 0, NSInvalidArgumentException);
|
||||
initDeserializerInfo(&info, data, cursor, flag);
|
||||
o = deserializeFromInfo(&info);
|
||||
[o autorelease];
|
||||
return o;
|
||||
}
|
||||
|
||||
+ (id) deserializePropertyListFromData: (NSData*)data
|
||||
mutableContainers: (BOOL)flag
|
||||
{
|
||||
unsigned int cursor = 0;
|
||||
_NSDeserializerInfo info;
|
||||
unsigned int cursor = 0;
|
||||
id o;
|
||||
|
||||
return [self deserializePropertyListFromData: data
|
||||
atCursor: &cursor
|
||||
mutableContainers: flag];
|
||||
NSAssert(data != nil, NSInvalidArgumentException);
|
||||
initDeserializerInfo(&info, data, &cursor, flag);
|
||||
o = deserializeFromInfo(&info);
|
||||
[o autorelease];
|
||||
return o;
|
||||
}
|
||||
|
||||
- (void) deserializeObjectAt: (id*)object
|
||||
ofObjCType: (const char *)type
|
||||
fromData: (NSData*)data
|
||||
atCursor: (unsigned*)cursor
|
||||
+ (id) deserializePropertyListLazilyFromData: (NSData*)data
|
||||
atCursor: (unsigned*)cursor
|
||||
length: (unsigned)length
|
||||
mutableContainers: (BOOL)flag
|
||||
{
|
||||
SerializerType code;
|
||||
unsigned int size;
|
||||
NSAssert(data != nil, NSInvalidArgumentException);
|
||||
NSAssert(cursor != 0, NSInvalidArgumentException);
|
||||
if (length > [data length] - *cursor)
|
||||
{
|
||||
_NSDeserializerInfo info;
|
||||
id o;
|
||||
|
||||
assert(type == @encode(id));
|
||||
code = (SerializerType)[data deserializeIntAtCursor: cursor];
|
||||
size = (unsigned int)[data deserializeIntAtCursor: cursor];
|
||||
|
||||
switch (code) {
|
||||
case ST_MDATA:
|
||||
{
|
||||
NSMutableData* d = [NSMutableData dataWithCapacity: size];
|
||||
void* b = [d mutableBytes];
|
||||
|
||||
[data deserializeBytes: b length: size atCursor: cursor];
|
||||
*object = d;
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_DATA:
|
||||
{
|
||||
NSMutableData* d;
|
||||
void* b = objc_malloc(size);
|
||||
|
||||
[data deserializeBytes: b length: size atCursor: cursor];
|
||||
d = [NSData dataWithBytesNoCopy: b length: size];
|
||||
*object = d;
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_MCSTRING:
|
||||
case ST_MSTRING:
|
||||
{
|
||||
NSMutableString* s;
|
||||
char* b = objc_malloc(size+1);
|
||||
|
||||
b[size] = '\0';
|
||||
[data deserializeBytes: b length: size atCursor: cursor];
|
||||
s = [[[NSMutableString alloc] initWithCStringNoCopy: b
|
||||
length: size
|
||||
freeWhenDone: YES]
|
||||
autorelease];
|
||||
*object = s;
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_CSTRING:
|
||||
case ST_STRING:
|
||||
{
|
||||
NSString* s;
|
||||
char* b = objc_malloc(size+1);
|
||||
|
||||
b[size] = '\0';
|
||||
[data deserializeBytes: b length: size atCursor: cursor];
|
||||
s = [[[NSString alloc] initWithCStringNoCopy: b
|
||||
length: size
|
||||
freeWhenDone: YES] autorelease];
|
||||
*object = s;
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_MARRAY:
|
||||
case ST_ARRAY:
|
||||
{
|
||||
id *objects = objc_malloc(size*sizeof(id));
|
||||
id a;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
[data deserializeDataAt: &objects[i]
|
||||
ofObjCType: type
|
||||
atCursor: cursor
|
||||
context: self];
|
||||
}
|
||||
if (code == ST_MARRAY || mutableContainer) {
|
||||
a = [[NSMutableArray alloc] initWithObjects: objects
|
||||
count: size];
|
||||
}
|
||||
else {
|
||||
a = [[NSArray alloc] initWithObjects: objects
|
||||
count: size];
|
||||
}
|
||||
objc_free(objects);
|
||||
[a autorelease];
|
||||
*object = a;
|
||||
break;
|
||||
}
|
||||
|
||||
case ST_MDICT:
|
||||
case ST_DICT:
|
||||
{
|
||||
id *keys = objc_malloc(size*sizeof(id));
|
||||
id *objects = objc_malloc(size*sizeof(id));
|
||||
id d;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
[data deserializeDataAt: &keys[i]
|
||||
ofObjCType: type
|
||||
atCursor: cursor
|
||||
context: self];
|
||||
[data deserializeDataAt: &objects[i]
|
||||
ofObjCType: type
|
||||
atCursor: cursor
|
||||
context: self];
|
||||
}
|
||||
if (code == ST_MDICT || mutableContainer) {
|
||||
d = [NSMutableDictionary dictionaryWithObjects: objects
|
||||
forKeys: keys
|
||||
count: size];
|
||||
}
|
||||
else {
|
||||
d = [NSDictionary dictionaryWithObjects: objects
|
||||
forKeys: keys
|
||||
count: size];
|
||||
}
|
||||
objc_free(keys);
|
||||
objc_free(objects);
|
||||
*object = d;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
[NSException raise: NSGenericException
|
||||
format: @"Unknown class in property list"];
|
||||
initDeserializerInfo(&info, data, cursor, flag);
|
||||
o = deserializeFromInfo(&info);
|
||||
[o autorelease];
|
||||
return o;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [_NSDeserializerProxy proxyWithData: data
|
||||
atCursor: cursor
|
||||
mutable: flag];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) serializeObjectAt: (id*)object
|
||||
ofObjCType: (const char *)type
|
||||
intoData: (NSMutableData*)data
|
||||
{
|
||||
[self shouldNotImplement: _cmd];
|
||||
}
|
||||
@end
|
||||
|
||||
|
|
Loading…
Reference in a new issue