2004-02-02 12:26:59 +00:00
|
|
|
|
/** Implementation for NSKeyedArchiver for GNUstep
|
2004-01-22 09:37:07 +00:00
|
|
|
|
Copyright (C) 2004 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
|
Date: January 2004
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2004-01-22 09:37:07 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
2019-12-09 23:36:00 +00:00
|
|
|
|
Lesser General Public License for more details.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
2004-01-22 09:37:07 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2024-11-07 13:37:59 +00:00
|
|
|
|
Software Foundation, Inc., 31 Milk Street #960789 Boston, MA 02196 USA.
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
|
#import "common.h"
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#define EXPOSE_NSKeyedArchiver_IVARS 1
|
|
|
|
|
#import "Foundation/NSAutoreleasePool.h"
|
|
|
|
|
#import "Foundation/NSData.h"
|
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
|
#import "Foundation/NSScanner.h"
|
|
|
|
|
#import "Foundation/NSValue.h"
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#import "GSPrivate.h"
|
2004-01-25 18:39:20 +00:00
|
|
|
|
|
|
|
|
|
@class GSString;
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* Setup for inline operation of pointer map tables.
|
|
|
|
|
*/
|
2011-03-29 08:16:02 +00:00
|
|
|
|
#define GSI_MAP_KTYPES GSUNION_PTR | GSUNION_OBJ | GSUNION_CLS | GSUNION_NSINT
|
|
|
|
|
#define GSI_MAP_VTYPES GSUNION_PTR | GSUNION_OBJ | GSUNION_NSINT
|
2004-01-22 09:37:07 +00:00
|
|
|
|
#define GSI_MAP_RETAIN_VAL(M, X)
|
|
|
|
|
#define GSI_MAP_RELEASE_VAL(M, X)
|
2011-03-29 08:16:02 +00:00
|
|
|
|
#define GSI_MAP_HASH(M, X) ((X).nsu)
|
2006-08-25 15:49:01 +00:00
|
|
|
|
#define GSI_MAP_EQUAL(M, X,Y) ((X).ptr == (Y).ptr)
|
2004-01-25 18:39:20 +00:00
|
|
|
|
#undef GSI_MAP_NOCLEAN
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#define GSI_MAP_RETAIN_KEY(M, X) RETAIN(X.obj)
|
|
|
|
|
#define GSI_MAP_RELEASE_KEY(M, X) RELEASE(X.obj)
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
2004-04-06 10:45:22 +00:00
|
|
|
|
#include "GNUstepBase/GSIMap.h"
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define _IN_NSKEYEDARCHIVER_M 1
|
2010-02-17 11:47:06 +00:00
|
|
|
|
#import "Foundation/NSKeyedArchiver.h"
|
2004-01-22 09:37:07 +00:00
|
|
|
|
#undef _IN_NSKEYEDARCHIVER_M
|
|
|
|
|
|
|
|
|
|
static NSMapTable *globalClassMap = 0;
|
|
|
|
|
|
2004-01-27 11:31:41 +00:00
|
|
|
|
static Class NSStringClass = 0;
|
|
|
|
|
static Class NSScannerClass = 0;
|
|
|
|
|
static SEL scanFloatSel;
|
|
|
|
|
static SEL scanStringSel;
|
|
|
|
|
static SEL scannerSel;
|
2009-02-23 20:42:32 +00:00
|
|
|
|
static BOOL (*scanFloatImp)(NSScanner*, SEL, CGFloat*);
|
2004-01-27 11:31:41 +00:00
|
|
|
|
static BOOL (*scanStringImp)(NSScanner*, SEL, NSString*, NSString**);
|
|
|
|
|
static id (*scannerImp)(Class, SEL, NSString*);
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
setupCache(void)
|
|
|
|
|
{
|
|
|
|
|
if (NSStringClass == 0)
|
|
|
|
|
{
|
|
|
|
|
NSStringClass = [NSString class];
|
|
|
|
|
NSScannerClass = [NSScanner class];
|
2009-02-23 20:42:32 +00:00
|
|
|
|
if (sizeof(CGFloat) == sizeof(double))
|
|
|
|
|
{
|
|
|
|
|
scanFloatSel = @selector(scanDouble:);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
scanFloatSel = @selector(scanFloat:);
|
|
|
|
|
}
|
2004-01-27 11:31:41 +00:00
|
|
|
|
scanStringSel = @selector(scanString:intoString:);
|
|
|
|
|
scannerSel = @selector(scannerWithString:);
|
2009-02-23 20:42:32 +00:00
|
|
|
|
scanFloatImp = (BOOL (*)(NSScanner*, SEL, CGFloat*))
|
2004-01-27 11:31:41 +00:00
|
|
|
|
[NSScannerClass instanceMethodForSelector: scanFloatSel];
|
|
|
|
|
scanStringImp = (BOOL (*)(NSScanner*, SEL, NSString*, NSString**))
|
|
|
|
|
[NSScannerClass instanceMethodForSelector: scanStringSel];
|
|
|
|
|
scannerImp = (id (*)(Class, SEL, NSString*))
|
|
|
|
|
[NSScannerClass methodForSelector: scannerSel];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
#define CHECKKEY \
|
|
|
|
|
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 ([_enc objectForKey: aKey] != nil) \
|
|
|
|
|
{ \
|
|
|
|
|
[NSException raise: NSInvalidArgumentException \
|
|
|
|
|
format: @"%@, duplicate key '%@' in %@", \
|
|
|
|
|
NSStringFromClass([self class]), aKey, NSStringFromSelector(_cmd)]; \
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-25 18:39:20 +00:00
|
|
|
|
/*
|
|
|
|
|
* 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;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
@interface NSKeyedArchiver (Private)
|
2004-01-25 18:39:20 +00:00
|
|
|
|
- (id) _encodeObject: (id)anObject conditional: (BOOL)conditional;
|
2004-01-22 09:37:07 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2004-01-27 11:31:41 +00:00
|
|
|
|
@implementation NSKeyedArchiver (Internal)
|
2004-01-25 18:39:20 +00:00
|
|
|
|
/**
|
|
|
|
|
* Internal method used to encode an array relatively efficiently.<br />
|
|
|
|
|
* Some MacOS-X library classes seem to use this.
|
2004-01-22 09:37:07 +00:00
|
|
|
|
*/
|
2004-01-25 18:39:20 +00:00
|
|
|
|
- (void) _encodeArrayOfObjects: (NSArray*)anArray forKey: (NSString*)aKey
|
2004-01-22 09:37:07 +00:00
|
|
|
|
{
|
2004-01-25 18:39:20 +00:00
|
|
|
|
id o;
|
|
|
|
|
CHECKKEY
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
2004-01-25 18:39:20 +00:00
|
|
|
|
if (anArray == nil)
|
|
|
|
|
{
|
|
|
|
|
o = makeReference(0);
|
|
|
|
|
}
|
|
|
|
|
else
|
2004-01-22 09:37:07 +00:00
|
|
|
|
{
|
2004-01-25 18:39:20 +00:00
|
|
|
|
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;
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
2004-01-25 18:39:20 +00:00
|
|
|
|
[_enc setObject: o forKey: aKey];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
2004-01-28 07:33:20 +00:00
|
|
|
|
|
|
|
|
|
- (void) _encodePropertyList: (id)anObject forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
[_enc setObject: anObject forKey: aKey];
|
|
|
|
|
}
|
2004-01-27 11:31:41 +00:00
|
|
|
|
@end
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
2004-01-27 11:31:41 +00:00
|
|
|
|
@implementation NSKeyedArchiver (Private)
|
2004-01-22 09:37:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* The real workhorse of the archiving process ... this deals with all
|
2004-01-25 18:39:20 +00:00
|
|
|
|
* archiving of objects. It returns the object to be stored in the
|
|
|
|
|
* mapping dictionary (_enc).
|
2004-01-22 09:37:07 +00:00
|
|
|
|
*/
|
2004-01-25 18:39:20 +00:00
|
|
|
|
- (id) _encodeObject: (id)anObject conditional: (BOOL)conditional
|
2004-01-22 09:37:07 +00:00
|
|
|
|
{
|
|
|
|
|
id original = anObject;
|
|
|
|
|
GSIMapNode node;
|
|
|
|
|
id objectInfo = nil; // Encoded object
|
|
|
|
|
NSMutableDictionary *m = nil;
|
2004-01-25 18:39:20 +00:00
|
|
|
|
NSDictionary *refObject;
|
|
|
|
|
unsigned ref = 0; // Reference to nil
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
|
|
|
|
if (anObject != nil)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Obtain replacement object for the value being encoded.
|
|
|
|
|
* Notify delegate of progress and set up new mapping if necessary.
|
|
|
|
|
*/
|
|
|
|
|
node = GSIMapNodeForKey(_repMap, (GSIMapKey)anObject);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
anObject = [original replacementObjectForKeyedArchiver: self];
|
|
|
|
|
if (_delegate != nil)
|
|
|
|
|
{
|
|
|
|
|
if (anObject != nil)
|
|
|
|
|
{
|
|
|
|
|
anObject = [_delegate archiver: self
|
|
|
|
|
willEncodeObject: anObject];
|
|
|
|
|
}
|
|
|
|
|
if (original != anObject)
|
|
|
|
|
{
|
|
|
|
|
[_delegate archiver: self
|
|
|
|
|
willReplaceObject: original
|
|
|
|
|
withObject: anObject];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
GSIMapAddPair(_repMap, (GSIMapKey)original, (GSIMapVal)anObject);
|
|
|
|
|
}
|
2006-08-05 03:28:57 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If the object has a replacement, use it.
|
|
|
|
|
*/
|
|
|
|
|
anObject = node->value.obj;
|
|
|
|
|
}
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (anObject != nil)
|
|
|
|
|
{
|
|
|
|
|
node = GSIMapNodeForKey(_uIdMap, (GSIMapKey)anObject);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
if (conditional == YES)
|
|
|
|
|
{
|
|
|
|
|
node = GSIMapNodeForKey(_cIdMap, (GSIMapKey)anObject);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
ref = [_obj count];
|
2011-03-29 09:40:14 +00:00
|
|
|
|
GSIMapAddPair(_cIdMap,
|
|
|
|
|
(GSIMapKey)anObject, (GSIMapVal)(NSUInteger)ref);
|
2004-01-22 09:37:07 +00:00
|
|
|
|
/*
|
|
|
|
|
* Use the null object as a placeholder for a conditionally
|
|
|
|
|
* encoded object.
|
|
|
|
|
*/
|
|
|
|
|
[_obj addObject: [_obj objectAtIndex: 0]];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This object has already been conditionally encoded.
|
|
|
|
|
*/
|
2011-03-29 08:16:02 +00:00
|
|
|
|
ref = node->value.nsu;
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2006-08-14 07:16:26 +00:00
|
|
|
|
Class c = [anObject classForKeyedArchiver];
|
2004-01-25 18:39:20 +00:00
|
|
|
|
|
2006-08-05 03:28:57 +00:00
|
|
|
|
// FIXME ... exactly what classes are stored directly???
|
2006-08-14 07:16:26 +00:00
|
|
|
|
if (c == [NSString class]
|
|
|
|
|
|| c == [NSNumber class]
|
|
|
|
|
|| c == [NSDate class]
|
|
|
|
|
|| c == [NSData class]
|
|
|
|
|
)
|
2004-01-22 09:37:07 +00:00
|
|
|
|
{
|
|
|
|
|
objectInfo = anObject;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// We store a dictionary describing the object.
|
|
|
|
|
m = [NSMutableDictionary new];
|
|
|
|
|
objectInfo = m;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node = GSIMapNodeForKey(_cIdMap, (GSIMapKey)anObject);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Not encoded ... create dictionary for it.
|
|
|
|
|
*/
|
|
|
|
|
ref = [_obj count];
|
2011-03-29 09:40:14 +00:00
|
|
|
|
GSIMapAddPair(_uIdMap,
|
|
|
|
|
(GSIMapKey)anObject, (GSIMapVal)(NSUInteger)ref);
|
2004-01-22 09:37:07 +00:00
|
|
|
|
[_obj addObject: objectInfo];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Conditionally encoded ... replace with actual value.
|
|
|
|
|
*/
|
2011-03-29 08:16:02 +00:00
|
|
|
|
ref = node->value.nsu;
|
2011-03-29 09:40:14 +00:00
|
|
|
|
GSIMapAddPair(_uIdMap,
|
|
|
|
|
(GSIMapKey)anObject, (GSIMapVal)(NSUInteger)ref);
|
2004-01-22 09:37:07 +00:00
|
|
|
|
GSIMapRemoveKey(_cIdMap, (GSIMapKey)anObject);
|
|
|
|
|
[_obj replaceObjectAtIndex: ref withObject: objectInfo];
|
|
|
|
|
}
|
|
|
|
|
RELEASE(m);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-03-29 08:16:02 +00:00
|
|
|
|
ref = node->value.nsu;
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2004-01-25 18:39:20 +00:00
|
|
|
|
* Build an object to reference the encoded value of anObject
|
2004-01-22 09:37:07 +00:00
|
|
|
|
*/
|
2004-01-25 18:39:20 +00:00
|
|
|
|
refObject = makeReference(ref);
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* objectInfo is a dictionary describing the object.
|
|
|
|
|
*/
|
|
|
|
|
if (objectInfo != nil && m == objectInfo)
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *savedEnc = _enc;
|
|
|
|
|
unsigned savedKeyNum = _keyNum;
|
|
|
|
|
Class c = [anObject class];
|
|
|
|
|
NSString *classname;
|
|
|
|
|
Class mapped;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Map the class of the object to the actual class it is encoded as.
|
|
|
|
|
* First ask the object, then apply any name mappings to that value.
|
|
|
|
|
*/
|
|
|
|
|
mapped = [anObject classForKeyedArchiver];
|
|
|
|
|
if (mapped != nil)
|
|
|
|
|
{
|
|
|
|
|
c = mapped;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
classname = [self classNameForClass: c];
|
|
|
|
|
if (classname == nil)
|
|
|
|
|
{
|
|
|
|
|
classname = [[self class] classNameForClass: c];
|
|
|
|
|
}
|
|
|
|
|
if (classname == nil)
|
|
|
|
|
{
|
|
|
|
|
classname = NSStringFromClass(c);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c = NSClassFromString(classname);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* At last, get the object to encode itself. Save and restore the
|
2004-01-22 09:37:07 +00:00
|
|
|
|
* current object scope of course.
|
|
|
|
|
*/
|
|
|
|
|
_enc = m;
|
|
|
|
|
_keyNum = 0;
|
|
|
|
|
[anObject encodeWithCoder: self];
|
|
|
|
|
_keyNum = savedKeyNum;
|
|
|
|
|
_enc = savedEnc;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This is ugly, but it seems to be the way MacOS-X does it ...
|
|
|
|
|
* We create class information by storing it directly into the
|
|
|
|
|
* table of all objects, and making a reference so we can look
|
|
|
|
|
* up the table entry by class pointer.
|
|
|
|
|
* A much cleaner way to do it would be by encoding the class
|
|
|
|
|
* normally, but we are trying to be compatible.
|
|
|
|
|
*
|
|
|
|
|
* Also ... we encode the class *after* encoding the instance,
|
|
|
|
|
* simply because that seems to be the way MacOS-X does it and
|
|
|
|
|
* we want to maximise compatibility (perhaps they had good reason?)
|
|
|
|
|
*/
|
|
|
|
|
node = GSIMapNodeForKey(_uIdMap, (GSIMapKey)c);
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *cDict;
|
|
|
|
|
NSMutableArray *hierarchy;
|
|
|
|
|
|
|
|
|
|
ref = [_obj count];
|
2011-03-29 09:40:14 +00:00
|
|
|
|
GSIMapAddPair(_uIdMap,
|
|
|
|
|
(GSIMapKey)c, (GSIMapVal)(NSUInteger)ref);
|
2004-01-22 09:37:07 +00:00
|
|
|
|
cDict = [[NSMutableDictionary alloc] initWithCapacity: 2];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* record class name
|
|
|
|
|
*/
|
|
|
|
|
[cDict setObject: classname forKey: @"$classname"];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Record the class hierarchy for this object.
|
|
|
|
|
*/
|
|
|
|
|
hierarchy = [NSMutableArray new];
|
|
|
|
|
while (c != 0)
|
|
|
|
|
{
|
2005-06-27 08:46:08 +00:00
|
|
|
|
Class next = [c superclass];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
|
|
|
|
[hierarchy addObject: NSStringFromClass(c)];
|
|
|
|
|
if (next == c)
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
c = next;
|
|
|
|
|
}
|
|
|
|
|
[cDict setObject: hierarchy forKey: @"$classes"];
|
|
|
|
|
RELEASE(hierarchy);
|
|
|
|
|
[_obj addObject: cDict];
|
|
|
|
|
RELEASE(cDict);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-03-29 08:16:02 +00:00
|
|
|
|
ref = node->value.nsu;
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now create a reference to the class information and store it
|
|
|
|
|
* in the object description dictionary for the object we just encoded.
|
|
|
|
|
*/
|
2004-01-25 18:39:20 +00:00
|
|
|
|
[m setObject: makeReference(ref) forKey: @"$class"];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we have encoded the object information, tell the delegaate.
|
|
|
|
|
*/
|
|
|
|
|
if (objectInfo != nil && _delegate != nil)
|
|
|
|
|
{
|
|
|
|
|
[_delegate archiver: self didEncodeObject: anObject];
|
|
|
|
|
}
|
2004-01-25 18:39:20 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Return the dictionary identifying the encoded object.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2004-01-25 18:39:20 +00:00
|
|
|
|
return refObject;
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSKeyedArchiver
|
|
|
|
|
|
2020-04-24 07:59:17 +00:00
|
|
|
|
+ (NSData *) archivedDataWithRootObject: (id)anObject
|
|
|
|
|
requiringSecureCoding: (BOOL)requiresSecureCoding
|
|
|
|
|
error: (NSError **)error
|
|
|
|
|
{
|
2020-05-12 18:01:44 +00:00
|
|
|
|
NSData *d = nil;
|
|
|
|
|
|
2020-05-12 18:02:50 +00:00
|
|
|
|
if (requiresSecureCoding == NO)
|
2020-04-24 07:59:17 +00:00
|
|
|
|
{
|
2020-05-12 18:01:44 +00:00
|
|
|
|
NSMutableData *m = nil;
|
|
|
|
|
NSKeyedArchiver *a = nil;
|
|
|
|
|
|
2020-04-24 07:59:17 +00:00
|
|
|
|
error = NULL;
|
2020-05-12 18:01:44 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
m = [[NSMutableData alloc] initWithCapacity: 10240];
|
|
|
|
|
a = [[NSKeyedArchiver alloc] initForWritingWithMutableData: m];
|
|
|
|
|
[a encodeObject: anObject forKey: @"root"];
|
|
|
|
|
[a finishEncoding];
|
|
|
|
|
d = [m copy];
|
|
|
|
|
DESTROY(m);
|
|
|
|
|
DESTROY(a);
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
DESTROY(m);
|
|
|
|
|
DESTROY(a);
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER;
|
2020-04-24 07:59:17 +00:00
|
|
|
|
}
|
2020-05-12 18:01:44 +00:00
|
|
|
|
|
|
|
|
|
return AUTORELEASE(d);
|
2020-04-24 07:59:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-05-12 18:01:44 +00:00
|
|
|
|
/*
|
|
|
|
|
* When I tried this on MacOS 10.3 it encoded the object with the key 'root',
|
|
|
|
|
* so this implementation does the same.
|
|
|
|
|
*/
|
|
|
|
|
+ (NSData*) archivedDataWithRootObject: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
return [self archivedDataWithRootObject: anObject
|
|
|
|
|
requiringSecureCoding: NO
|
|
|
|
|
error: NULL];
|
|
|
|
|
}
|
2020-04-24 07:59:17 +00:00
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
+ (BOOL) archiveRootObject: (id)anObject toFile: (NSString*)aPath
|
|
|
|
|
{
|
2011-02-28 19:49:57 +00:00
|
|
|
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
|
|
|
|
NSData *d;
|
|
|
|
|
BOOL result;
|
2004-01-22 09:37:07 +00:00
|
|
|
|
|
|
|
|
|
d = [self archivedDataWithRootObject: anObject];
|
|
|
|
|
result = [d writeToFile: aPath atomically: YES];
|
2011-05-27 11:48:44 +00:00
|
|
|
|
[pool drain];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSString*) classNameForClass: (Class)aClass
|
|
|
|
|
{
|
|
|
|
|
return (NSString*)NSMapGet(globalClassMap, (void*)aClass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (globalClassMap == 0)
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
globalClassMap =
|
2004-01-22 09:37:07 +00:00
|
|
|
|
NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
2013-08-22 15:44:54 +00:00
|
|
|
|
[[NSObject leakAt: &globalClassMap] release];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) setClassName: (NSString*)aString forClass: (Class)aClass
|
|
|
|
|
{
|
|
|
|
|
if (aString == nil)
|
|
|
|
|
{
|
|
|
|
|
NSMapRemove(globalClassMap, (void*)aClass);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSMapInsert(globalClassMap, (void*)aClass, aString);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-13 06:29:53 +00:00
|
|
|
|
- (BOOL) requiresSecureCoding
|
|
|
|
|
{
|
|
|
|
|
return _requiresSecureCoding;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setRequiresSecureCoding: (BOOL)flag
|
|
|
|
|
{
|
|
|
|
|
_requiresSecureCoding = flag;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 20:43:34 +00:00
|
|
|
|
- (BOOL) allowsKeyedCoding
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (NSString*) classNameForClass: (Class)aClass
|
|
|
|
|
{
|
|
|
|
|
return (NSString*)NSMapGet(_clsMap, (void*)aClass);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
RELEASE(_enc);
|
|
|
|
|
RELEASE(_obj);
|
|
|
|
|
RELEASE(_data);
|
|
|
|
|
if (_clsMap != 0)
|
|
|
|
|
{
|
|
|
|
|
NSFreeMapTable(_clsMap);
|
|
|
|
|
_clsMap = 0;
|
|
|
|
|
}
|
|
|
|
|
if (_cIdMap)
|
|
|
|
|
{
|
|
|
|
|
GSIMapEmptyMap(_cIdMap);
|
|
|
|
|
if (_uIdMap)
|
|
|
|
|
{
|
|
|
|
|
GSIMapEmptyMap(_uIdMap);
|
|
|
|
|
}
|
|
|
|
|
if (_repMap)
|
|
|
|
|
{
|
|
|
|
|
GSIMapEmptyMap(_repMap);
|
|
|
|
|
}
|
|
|
|
|
NSZoneFree(_cIdMap->zone, (void*)_cIdMap);
|
|
|
|
|
}
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) delegate
|
|
|
|
|
{
|
|
|
|
|
return _delegate;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-08 21:44:38 +00:00
|
|
|
|
- (NSString*) description
|
|
|
|
|
{
|
|
|
|
|
if (_data == nil)
|
|
|
|
|
{
|
|
|
|
|
// For consistency with OSX
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"method sent to uninitialised archiver"];
|
|
|
|
|
}
|
|
|
|
|
return [super description];
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-25 18:39:20 +00:00
|
|
|
|
- (void) encodeArrayOfObjCType: (const char*)aType
|
2009-02-23 20:42:32 +00:00
|
|
|
|
count: (NSUInteger)aCount
|
2004-01-25 18:39:20 +00:00
|
|
|
|
at: (const void*)address
|
|
|
|
|
{
|
|
|
|
|
id o;
|
|
|
|
|
|
|
|
|
|
o = [[_NSKeyedCoderOldStyleArray alloc] initWithObjCType: aType
|
|
|
|
|
count: aCount
|
|
|
|
|
at: address];
|
|
|
|
|
[self encodeObject: o];
|
|
|
|
|
RELEASE(o);
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (void) encodeBool: (BOOL)aBool forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
|
|
|
|
[_enc setObject: [NSNumber numberWithBool: aBool] forKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-18 12:34:56 +00:00
|
|
|
|
- (void) encodeBytes: (const uint8_t*)aPointer
|
|
|
|
|
length: (NSUInteger)length
|
|
|
|
|
forKey: (NSString*)aKey
|
2004-01-22 09:37:07 +00:00
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
|
|
|
|
[_enc setObject: [NSData dataWithBytes: aPointer length: length]
|
|
|
|
|
forKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeConditionalObject: (id)anObject
|
|
|
|
|
{
|
2004-01-25 18:39:20 +00:00
|
|
|
|
NSString *aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
|
|
|
|
|
|
|
|
|
|
anObject = [self _encodeObject: anObject conditional: YES];
|
|
|
|
|
[_enc setObject: anObject forKey: aKey];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeConditionalObject: (id)anObject forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
2004-01-25 18:39:20 +00:00
|
|
|
|
anObject = [self _encodeObject: anObject conditional: YES];
|
|
|
|
|
[_enc setObject: anObject forKey: aKey];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeDouble: (double)aDouble forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
|
|
|
|
[_enc setObject: [NSNumber numberWithDouble: aDouble] forKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeFloat: (float)aFloat forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
|
|
|
|
[_enc setObject: [NSNumber numberWithFloat: aFloat] forKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeInt: (int)anInteger forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
|
|
|
|
[_enc setObject: [NSNumber numberWithInt: anInteger] forKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-25 11:53:21 +00:00
|
|
|
|
- (void) encodeInteger: (NSInteger)anInteger forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
|
|
|
|
[_enc setObject: [NSNumber numberWithInteger: anInteger] forKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (void) encodeInt32: (int32_t)anInteger forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
|
|
|
|
[_enc setObject: [NSNumber numberWithLong: anInteger] forKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeInt64: (int64_t)anInteger forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
|
|
|
|
[_enc setObject: [NSNumber numberWithLongLong: anInteger] forKey: aKey];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeObject: (id)anObject
|
|
|
|
|
{
|
2004-01-25 18:39:20 +00:00
|
|
|
|
NSString *aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
|
|
|
|
|
|
|
|
|
|
anObject = [self _encodeObject: anObject conditional: NO];
|
|
|
|
|
[_enc setObject: anObject forKey: aKey];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeObject: (id)anObject forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
CHECKKEY
|
|
|
|
|
|
2004-01-25 18:39:20 +00:00
|
|
|
|
anObject = [self _encodeObject: anObject conditional: NO];
|
|
|
|
|
[_enc setObject: anObject forKey: aKey];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-01-24 06:39:21 +00:00
|
|
|
|
- (void) encodePoint: (NSPoint)p
|
|
|
|
|
{
|
2009-02-23 20:42:32 +00:00
|
|
|
|
[self encodeValueOfObjCType: @encode(CGFloat) at: &p.x];
|
|
|
|
|
[self encodeValueOfObjCType: @encode(CGFloat) at: &p.y];
|
2004-01-24 06:39:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeRect: (NSRect)r
|
|
|
|
|
{
|
2009-02-23 20:42:32 +00:00
|
|
|
|
[self encodeValueOfObjCType: @encode(CGFloat) at: &r.origin.x];
|
|
|
|
|
[self encodeValueOfObjCType: @encode(CGFloat) at: &r.origin.y];
|
|
|
|
|
[self encodeValueOfObjCType: @encode(CGFloat) at: &r.size.width];
|
|
|
|
|
[self encodeValueOfObjCType: @encode(CGFloat) at: &r.size.height];
|
2004-01-24 06:39:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeSize: (NSSize)s
|
|
|
|
|
{
|
2009-02-23 20:42:32 +00:00
|
|
|
|
[self encodeValueOfObjCType: @encode(CGFloat) at: &s.width];
|
|
|
|
|
[self encodeValueOfObjCType: @encode(CGFloat) at: &s.height];
|
2004-01-24 06:39:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (void) encodeValueOfObjCType: (const char*)type
|
|
|
|
|
at: (const void*)address
|
|
|
|
|
{
|
|
|
|
|
NSString *aKey;
|
|
|
|
|
id o;
|
|
|
|
|
|
2012-07-11 04:51:42 +00:00
|
|
|
|
type = GSSkipTypeQualifierAndLayoutInfo(type);
|
2004-01-22 09:37:07 +00:00
|
|
|
|
if (*type == _C_ID || *type == _C_CLASS)
|
|
|
|
|
{
|
|
|
|
|
[self encodeObject: *(id*)address];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
aKey = [NSString stringWithFormat: @"$%u", _keyNum++];
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_SEL:
|
|
|
|
|
{
|
|
|
|
|
// Selectors are encoded by name as strings.
|
|
|
|
|
o = NSStringFromSelector(*(SEL*)address);
|
|
|
|
|
[self encodeObject: o];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_CHARPTR:
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Bizzarely MacOS-X seems to encode char* values by creating
|
|
|
|
|
* string objects and encoding those objects!
|
|
|
|
|
*/
|
2006-10-09 14:00:01 +00:00
|
|
|
|
o = [NSString stringWithUTF8String: (char*)address];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
[self encodeObject: o];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_CHR:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
o = [NSNumber numberWithInt: (NSInteger)*(char*)address];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_UCHR:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
o = [NSNumber numberWithInt: (NSInteger)*(unsigned char*)address];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_SHT:
|
2009-02-23 20:42:32 +00:00
|
|
|
|
o = [NSNumber numberWithInt: (NSInteger)*(short*)address];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_USHT:
|
|
|
|
|
o = [NSNumber numberWithLong: (long)*(unsigned short*)address];
|
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_INT:
|
2015-01-16 15:25:50 +00:00
|
|
|
|
o = [NSNumber numberWithInt: *(int*)address];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_UINT:
|
2015-01-16 15:25:50 +00:00
|
|
|
|
o = [NSNumber numberWithUnsignedInt: *(unsigned int*)address];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_LNG:
|
|
|
|
|
o = [NSNumber numberWithLong: *(long*)address];
|
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_ULNG:
|
|
|
|
|
o = [NSNumber numberWithUnsignedLong: *(unsigned long*)address];
|
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_LNG_LNG:
|
|
|
|
|
o = [NSNumber numberWithLongLong: *(long long*)address];
|
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_ULNG_LNG:
|
|
|
|
|
o = [NSNumber numberWithUnsignedLongLong:
|
|
|
|
|
*(unsigned long long*)address];
|
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_FLT:
|
|
|
|
|
o = [NSNumber numberWithFloat: *(float*)address];
|
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_DBL:
|
|
|
|
|
o = [NSNumber numberWithDouble: *(double*)address];
|
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
|
2021-08-07 14:37:52 +00:00
|
|
|
|
#if defined(_C_BOOL) && (!defined(__GNUC__) || __GNUC__ > 2)
|
2015-09-22 09:46:10 +00:00
|
|
|
|
case _C_BOOL:
|
|
|
|
|
o = [NSNumber numberWithInt: (NSInteger)*(_Bool*)address];
|
|
|
|
|
[_enc setObject: o forKey: aKey];
|
|
|
|
|
return;
|
|
|
|
|
#endif
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
case _C_STRUCT_B:
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-[%@ %@]: this archiver cannote encode structs",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
|
return;
|
|
|
|
|
|
2007-06-26 19:12:45 +00:00
|
|
|
|
case _C_ARY_B:
|
|
|
|
|
{
|
|
|
|
|
int count = atoi(++type);
|
|
|
|
|
|
|
|
|
|
while (isdigit(*type))
|
|
|
|
|
{
|
|
|
|
|
type++;
|
|
|
|
|
}
|
|
|
|
|
[self encodeArrayOfObjCType: type count: count at: address];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
default: /* Types that can be ignored in first pass. */
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-[%@ %@]: unknown type encoding ('%c')",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd), *type];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) finishEncoding
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *final;
|
|
|
|
|
NSData *data;
|
|
|
|
|
NSString *error;
|
|
|
|
|
|
|
|
|
|
[_delegate archiverWillFinish: self];
|
|
|
|
|
|
|
|
|
|
final = [NSMutableDictionary new];
|
|
|
|
|
[final setObject: NSStringFromClass([self class]) forKey: @"$archiver"];
|
2004-03-31 10:54:14 +00:00
|
|
|
|
[final setObject: [NSNumber numberWithInt: 100000] forKey: @"$version"];
|
2004-01-22 09:37:07 +00:00
|
|
|
|
[final setObject: _enc forKey: @"$top"];
|
|
|
|
|
[final setObject: _obj forKey: @"$objects"];
|
|
|
|
|
data = [NSPropertyListSerialization dataFromPropertyList: final
|
|
|
|
|
format: _format
|
|
|
|
|
errorDescription: &error];
|
|
|
|
|
RELEASE(final);
|
|
|
|
|
[_data setData: data];
|
|
|
|
|
[_delegate archiverDidFinish: self];
|
|
|
|
|
}
|
|
|
|
|
|
2007-06-26 19:12:45 +00:00
|
|
|
|
- (id) init
|
|
|
|
|
{
|
|
|
|
|
Class c = [self class];
|
2010-02-25 18:49:31 +00:00
|
|
|
|
DESTROY(self);
|
2007-06-26 19:12:45 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"-[%@ init]: cannot use -init for initialisation",
|
|
|
|
|
NSStringFromClass(c)];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (id) initForWritingWithMutableData: (NSMutableData*)data
|
|
|
|
|
{
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (self)
|
|
|
|
|
{
|
|
|
|
|
NSZone *zone = [self zone];
|
|
|
|
|
|
|
|
|
|
_keyNum = 0;
|
|
|
|
|
_data = RETAIN(data);
|
|
|
|
|
|
|
|
|
|
_clsMap = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
|
NSObjectMapValueCallBacks, 0);
|
|
|
|
|
/*
|
|
|
|
|
* Set up map tables.
|
|
|
|
|
*/
|
|
|
|
|
_cIdMap = (GSIMapTable)NSZoneMalloc(zone, sizeof(GSIMapTable_t)*5);
|
|
|
|
|
_uIdMap = &_cIdMap[1];
|
|
|
|
|
_repMap = &_cIdMap[2];
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_cIdMap, zone, 10);
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_uIdMap, zone, 200);
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_repMap, zone, 1);
|
|
|
|
|
|
|
|
|
|
_enc = [NSMutableDictionary new]; // Top level mapping dict
|
|
|
|
|
_obj = [NSMutableArray new]; // Array of objects.
|
|
|
|
|
[_obj addObject: @"$null"]; // Placeholder.
|
|
|
|
|
|
2006-01-09 05:07:09 +00:00
|
|
|
|
_format = NSPropertyListBinaryFormat_v1_0;
|
2004-01-22 09:37:07 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPropertyListFormat) outputFormat
|
|
|
|
|
{
|
|
|
|
|
return _format;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setClassName: (NSString*)aString forClass: (Class)aClass
|
|
|
|
|
{
|
|
|
|
|
if (aString == nil)
|
|
|
|
|
{
|
|
|
|
|
NSMapRemove(_clsMap, (void*)aClass);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSMapInsert(_clsMap, (void*)aClass, aString);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setDelegate: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
_delegate = anObject; // Not retained.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setOutputFormat: (NSPropertyListFormat)format
|
|
|
|
|
{
|
|
|
|
|
_format = format;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSObject (NSKeyedArchiverDelegate)
|
2005-11-28 15:41:35 +00:00
|
|
|
|
/** <override-dummy />
|
|
|
|
|
*/
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (void) archiver: (NSKeyedArchiver*)anArchiver didEncodeObject: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
}
|
2005-11-28 15:41:35 +00:00
|
|
|
|
/** <override-dummy />
|
|
|
|
|
*/
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (id) archiver: (NSKeyedArchiver*)anArchiver willEncodeObject: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
return anObject;
|
|
|
|
|
}
|
2005-11-28 15:41:35 +00:00
|
|
|
|
/** <override-dummy />
|
|
|
|
|
*/
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (void) archiverDidFinish: (NSKeyedArchiver*)anArchiver
|
|
|
|
|
{
|
|
|
|
|
}
|
2005-11-28 15:41:35 +00:00
|
|
|
|
/** <override-dummy />
|
|
|
|
|
*/
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (void) archiverWillFinish: (NSKeyedArchiver*)anArchiver
|
|
|
|
|
{
|
|
|
|
|
}
|
2005-11-28 15:41:35 +00:00
|
|
|
|
/** <override-dummy />
|
|
|
|
|
*/
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (void) archiver: (NSKeyedArchiver*)anArchiver
|
|
|
|
|
willReplaceObject: (id)anObject
|
|
|
|
|
withObject: (id)newObject
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
@implementation NSObject (NSKeyedArchiverObjectSubstitution)
|
2004-01-22 09:37:07 +00:00
|
|
|
|
- (Class) classForKeyedArchiver
|
|
|
|
|
{
|
|
|
|
|
return [self classForArchiver];
|
|
|
|
|
}
|
|
|
|
|
- (id) replacementObjectForKeyedArchiver: (NSKeyedArchiver*)archiver
|
|
|
|
|
{
|
|
|
|
|
return [self replacementObjectForArchiver: nil];
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSCoder (NSGeometryKeyedCoding)
|
|
|
|
|
- (void) encodePoint: (NSPoint)aPoint forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
NSString *val;
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
val = [NSString stringWithFormat: @"{%g, %g}", aPoint.x, aPoint.y];
|
|
|
|
|
[self encodeObject: val forKey: aKey];
|
|
|
|
|
}
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
- (void) encodeRect: (NSRect)aRect forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
NSString *val;
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
val = [NSString stringWithFormat: @"{{%g, %g}, {%g, %g}}",
|
|
|
|
|
aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height];
|
|
|
|
|
[self encodeObject: val forKey: aKey];
|
|
|
|
|
}
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
- (void) encodeSize: (NSSize)aSize forKey: (NSString*)aKey
|
|
|
|
|
{
|
|
|
|
|
NSString *val;
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
val = [NSString stringWithFormat: @"{%g, %g}", aSize.width, aSize.height];
|
|
|
|
|
[self encodeObject: val forKey: aKey];
|
|
|
|
|
}
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
- (NSPoint) decodePointForKey: (NSString*)aKey
|
|
|
|
|
{
|
2004-01-27 11:31:41 +00:00
|
|
|
|
NSString *val = [self decodeObjectForKey: aKey];
|
2004-01-24 20:40:44 +00:00
|
|
|
|
NSPoint aPoint;
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:49:01 +00:00
|
|
|
|
if (val == 0)
|
2004-01-27 11:31:41 +00:00
|
|
|
|
{
|
|
|
|
|
aPoint = NSMakePoint(0, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSScanner *scanner;
|
|
|
|
|
|
|
|
|
|
setupCache();
|
|
|
|
|
scanner = (*scannerImp)(NSScannerClass, scannerSel, val);
|
|
|
|
|
if (!(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
|
|
|
|
|
|| !(*scanFloatImp)(scanner, scanFloatSel, &aPoint.x)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
|
|
|
|
|
|| !(*scanFloatImp)(scanner, scanFloatSel, &aPoint.y)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @"}", NULL))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@]: bad value - '%@'",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd), val];
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-01-24 20:40:44 +00:00
|
|
|
|
return aPoint;
|
|
|
|
|
}
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
- (NSRect) decodeRectForKey: (NSString*)aKey
|
|
|
|
|
{
|
2004-01-27 11:31:41 +00:00
|
|
|
|
NSString *val = [self decodeObjectForKey: aKey];
|
2004-01-24 20:40:44 +00:00
|
|
|
|
NSRect aRect;
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:49:01 +00:00
|
|
|
|
if (val == 0)
|
2004-01-27 11:31:41 +00:00
|
|
|
|
{
|
|
|
|
|
aRect = NSMakeRect(0, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSScanner *scanner;
|
|
|
|
|
|
|
|
|
|
setupCache();
|
|
|
|
|
scanner = (*scannerImp)(NSScannerClass, scannerSel, val);
|
|
|
|
|
if (!(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
|
|
|
|
|
|| !(*scanFloatImp)(scanner, scanFloatSel, &aRect.origin.x)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
|
|
|
|
|
|| !(*scanFloatImp)(scanner, scanFloatSel, &aRect.origin.y)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @"}", NULL)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
|
|
|
|
|
|| !(*scanFloatImp)(scanner, scanFloatSel, &aRect.size.width)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
|
|
|
|
|
|| !(*scanFloatImp)(scanner, scanFloatSel, &aRect.size.height)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @"}", NULL)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @"}", NULL))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@]: bad value - '%@'",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd), val];
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-01-24 20:40:44 +00:00
|
|
|
|
return aRect;
|
|
|
|
|
}
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:40:44 +00:00
|
|
|
|
- (NSSize) decodeSizeForKey: (NSString*)aKey
|
|
|
|
|
{
|
2004-01-27 11:31:41 +00:00
|
|
|
|
NSString *val = [self decodeObjectForKey: aKey];
|
2004-01-24 20:40:44 +00:00
|
|
|
|
NSSize aSize;
|
2004-01-27 11:31:41 +00:00
|
|
|
|
|
2004-01-24 20:49:01 +00:00
|
|
|
|
if (val == 0)
|
2004-01-27 11:31:41 +00:00
|
|
|
|
{
|
|
|
|
|
aSize = NSMakeSize(0, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSScanner *scanner;
|
|
|
|
|
|
|
|
|
|
setupCache();
|
|
|
|
|
scanner = (*scannerImp)(NSScannerClass, scannerSel, val);
|
|
|
|
|
if (!(*scanStringImp)(scanner, scanStringSel, @"{", NULL)
|
|
|
|
|
|| !(*scanFloatImp)(scanner, scanFloatSel, &aSize.width)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @",", NULL)
|
|
|
|
|
|| !(*scanFloatImp)(scanner, scanFloatSel, &aSize.height)
|
|
|
|
|
|| !(*scanStringImp)(scanner, scanStringSel, @"}", NULL))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ -%@]: bad value - '%@'",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd), val];
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-01-24 20:40:44 +00:00
|
|
|
|
return aSize;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|