2001-12-17 14:31:42 +00:00
|
|
|
|
/** Implementation of NSArchiver for GNUstep
|
1999-04-12 12:53:30 +00:00
|
|
|
|
Copyright (C) 1998,1999 Free Software Foundation, Inc.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1999-04-12 12:53:30 +00:00
|
|
|
|
Written by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
1998-10-24 09:58:16 +00:00
|
|
|
|
Created: October 1998
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1996-05-12 00:56:10 +00:00
|
|
|
|
This file is part of the GNUstep Base Library.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1995-04-09 02:42:37 +00:00
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1995-04-09 02:42:37 +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
|
|
|
|
|
Library General Public License for more details.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1995-04-09 02:42:37 +00:00
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
|
License along with this library; if not, write to the Free
|
1999-09-09 02:56:20 +00:00
|
|
|
|
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSArchiver class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
1995-04-09 02:42:37 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "config.h"
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* Setup for inline operation of pointer map tables.
|
|
|
|
|
*/
|
2002-01-24 17:03:04 +00:00
|
|
|
|
#define GSI_MAP_RETAIN_KEY(M, X)
|
|
|
|
|
#define GSI_MAP_RELEASE_KEY(M, X)
|
|
|
|
|
#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)
|
2002-02-13 18:49:32 +00:00
|
|
|
|
#define GSI_MAP_NOCLEAN 1
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/GSIMap.h"
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
#define _IN_NSARCHIVER_M
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSArchiver.h"
|
1998-10-24 09:58:16 +00:00
|
|
|
|
#undef _IN_NSARCHIVER_M
|
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSObjCRuntime.h"
|
|
|
|
|
#include "Foundation/NSCoder.h"
|
|
|
|
|
#include "Foundation/NSData.h"
|
|
|
|
|
#include "Foundation/NSException.h"
|
|
|
|
|
#include "Foundation/NSUtilities.h"
|
|
|
|
|
#include "Foundation/NSString.h"
|
1995-04-09 02:42:37 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
typedef unsigned char uchar;
|
1995-07-03 22:20:40 +00:00
|
|
|
|
|
2002-05-08 05:43:15 +00:00
|
|
|
|
NSString * const NSInconsistentArchiveException =
|
|
|
|
|
@"NSInconsistentArchiveException";
|
1995-07-03 22:20:40 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
#define PREFIX "GNUstep archive"
|
1995-07-03 22:20:40 +00:00
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* <p>Implementation of [NSCoder] capable of creating sequential archives which
|
|
|
|
|
* must be read in the same order they were written. This class implements
|
|
|
|
|
* methods for saving to and restoring from a serial archive (usually a file
|
|
|
|
|
* on disk, but can be an [NSData] object) as well as methods that can be
|
|
|
|
|
* used by objects that need to write/restore themselves.</p>
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* <p>Note, the sibling class [NSKeyedArchiver] supports a form of archive
|
|
|
|
|
* that is more robust to class changes, and is recommended over this one.</p>
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
@implementation NSArchiver
|
1996-01-26 03:15:14 +00:00
|
|
|
|
|
2000-10-30 18:00:27 +00:00
|
|
|
|
static SEL serSel;
|
|
|
|
|
static SEL tagSel;
|
|
|
|
|
static SEL xRefSel;
|
|
|
|
|
static SEL eObjSel;
|
|
|
|
|
static SEL eValSel;
|
|
|
|
|
|
2000-10-31 11:05:23 +00:00
|
|
|
|
@class NSMutableDataMalloc;
|
|
|
|
|
static Class NSMutableDataMallocClass;
|
|
|
|
|
|
2000-10-30 18:00:27 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (self == [NSArchiver class])
|
|
|
|
|
{
|
|
|
|
|
serSel = @selector(serializeDataAt:ofObjCType:context:);
|
|
|
|
|
tagSel = @selector(serializeTypeTag:);
|
|
|
|
|
xRefSel = @selector(serializeTypeTag:andCrossRef:);
|
|
|
|
|
eObjSel = @selector(encodeObject:);
|
|
|
|
|
eValSel = @selector(encodeValueOfObjCType:at:);
|
2000-10-31 11:05:23 +00:00
|
|
|
|
NSMutableDataMallocClass = [NSMutableDataMalloc class];
|
2000-10-30 18:00:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Creates an NSMutableData instance and calls
|
|
|
|
|
* [initForWritingWithMutableData:].
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (id) init
|
1996-01-26 03:15:14 +00:00
|
|
|
|
{
|
1999-06-04 11:50:05 +00:00
|
|
|
|
NSMutableData *d;
|
|
|
|
|
|
2000-10-31 16:17:33 +00:00
|
|
|
|
d = [[NSMutableDataMallocClass allocWithZone: GSObjCZone(self)] init];
|
1999-06-04 11:50:05 +00:00
|
|
|
|
self = [self initForWritingWithMutableData: d];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
return self;
|
1996-01-26 03:15:14 +00:00
|
|
|
|
}
|
1995-04-15 19:38:52 +00:00
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Init instance that will archive its data to mdata. (Even if
|
|
|
|
|
* [archiveRootObject:toFile:] is called, this still gets written to.)
|
|
|
|
|
*/
|
2002-01-11 10:10:35 +00:00
|
|
|
|
- (id) initForWritingWithMutableData: (NSMutableData*)mdata
|
1995-04-15 19:38:52 +00:00
|
|
|
|
{
|
1998-10-24 09:58:16 +00:00
|
|
|
|
self = [super init];
|
|
|
|
|
if (self)
|
|
|
|
|
{
|
|
|
|
|
NSZone *zone = [self zone];
|
|
|
|
|
|
2002-01-11 10:10:35 +00:00
|
|
|
|
_data = RETAIN(mdata);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if ([self directDataAccess] == YES)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_dst = _data;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_dst = self;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_serImp = [_dst methodForSelector: serSel];
|
|
|
|
|
_tagImp = [_dst methodForSelector: tagSel];
|
|
|
|
|
_xRefImp = [_dst methodForSelector: xRefSel];
|
|
|
|
|
_eObjImp = [self methodForSelector: eObjSel];
|
|
|
|
|
_eValImp = [self methodForSelector: eValSel];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
[self resetArchiver];
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set up map tables.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_clsMap = (GSIMapTable)NSZoneMalloc(zone, sizeof(GSIMapTable_t)*6);
|
|
|
|
|
_cIdMap = &_clsMap[1];
|
|
|
|
|
_uIdMap = &_clsMap[2];
|
|
|
|
|
_ptrMap = &_clsMap[3];
|
|
|
|
|
_namMap = &_clsMap[4];
|
|
|
|
|
_repMap = &_clsMap[5];
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_clsMap, zone, 100);
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_cIdMap, zone, 10);
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_uIdMap, zone, 200);
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_ptrMap, zone, 100);
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_namMap, zone, 1);
|
|
|
|
|
GSIMapInitWithZoneAndCapacity(_repMap, zone, 1);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1996-01-26 03:15:14 +00:00
|
|
|
|
return self;
|
1995-04-15 19:38:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) dealloc
|
1997-05-03 20:16:26 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
RELEASE(_data);
|
|
|
|
|
if (_clsMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapEmptyMap(_clsMap);
|
|
|
|
|
if (_cIdMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapEmptyMap(_cIdMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_uIdMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapEmptyMap(_uIdMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_ptrMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapEmptyMap(_ptrMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_namMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapEmptyMap(_namMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_repMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapEmptyMap(_repMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
NSZoneFree(_clsMap->zone, (void*)_clsMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
2003-08-20 12:13:34 +00:00
|
|
|
|
[super dealloc];
|
1997-05-03 20:16:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Writes serialized representation of object and, recursively, any
|
|
|
|
|
* other objects it holds references to, to byte array.
|
|
|
|
|
*/
|
1995-04-15 19:38:52 +00:00
|
|
|
|
+ (NSData*) archivedDataWithRootObject: (id)rootObject
|
|
|
|
|
{
|
1998-10-24 09:58:16 +00:00
|
|
|
|
NSArchiver *archiver;
|
|
|
|
|
id d;
|
|
|
|
|
NSZone *z = NSDefaultMallocZone();
|
|
|
|
|
|
2000-10-31 11:05:23 +00:00
|
|
|
|
d = [[NSMutableDataMallocClass allocWithZone: z] initWithCapacity: 0];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (d == nil)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
1999-05-27 09:41:31 +00:00
|
|
|
|
archiver = [[self allocWithZone: z] initForWritingWithMutableData: d];
|
|
|
|
|
RELEASE(d);
|
|
|
|
|
d = nil;
|
|
|
|
|
if (archiver)
|
|
|
|
|
{
|
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
[archiver encodeRootObject: rootObject];
|
1999-09-16 07:21:34 +00:00
|
|
|
|
d = AUTORELEASE([archiver->_data copy]);
|
1999-05-27 09:41:31 +00:00
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
RELEASE(archiver);
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
RELEASE(archiver);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return d;
|
1995-04-15 19:38:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Writes out serialized representation of object and, recursively, any
|
|
|
|
|
* other objects it holds references to.
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
+ (BOOL) archiveRootObject: (id)rootObject
|
|
|
|
|
toFile: (NSString*)path
|
1995-04-15 19:38:52 +00:00
|
|
|
|
{
|
1998-10-24 09:58:16 +00:00
|
|
|
|
id d = [self archivedDataWithRootObject: rootObject];
|
1996-01-26 03:15:14 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return [d writeToFile: path atomically: YES];
|
1996-01-26 03:15:14 +00:00
|
|
|
|
}
|
1995-04-15 19:38:52 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) encodeArrayOfObjCType: (const char*)type
|
|
|
|
|
count: (unsigned)count
|
|
|
|
|
at: (const void*)buf
|
1996-01-26 03:15:14 +00:00
|
|
|
|
{
|
1998-10-24 09:58:16 +00:00
|
|
|
|
unsigned i;
|
|
|
|
|
unsigned offset = 0;
|
|
|
|
|
unsigned size = objc_sizeof_type(type);
|
|
|
|
|
uchar info;
|
|
|
|
|
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
1999-01-27 12:49:49 +00:00
|
|
|
|
case _C_ID: info = _GSC_NONE; break;
|
|
|
|
|
case _C_CHR: info = _GSC_CHR; break;
|
|
|
|
|
case _C_UCHR: info = _GSC_UCHR; break;
|
|
|
|
|
case _C_SHT: info = _GSC_SHT | _GSC_S_SHT; break;
|
|
|
|
|
case _C_USHT: info = _GSC_USHT | _GSC_S_SHT; break;
|
|
|
|
|
case _C_INT: info = _GSC_INT | _GSC_S_INT; break;
|
|
|
|
|
case _C_UINT: info = _GSC_UINT | _GSC_S_INT; break;
|
|
|
|
|
case _C_LNG: info = _GSC_LNG | _GSC_S_LNG; break;
|
|
|
|
|
case _C_ULNG: info = _GSC_ULNG | _GSC_S_LNG; break;
|
|
|
|
|
case _C_LNG_LNG: info = _GSC_LNG_LNG | _GSC_S_LNG_LNG; break;
|
|
|
|
|
case _C_ULNG_LNG: info = _GSC_ULNG_LNG | _GSC_S_LNG_LNG; break;
|
|
|
|
|
case _C_FLT: info = _GSC_FLT; break;
|
|
|
|
|
case _C_DBL: info = _GSC_DBL; break;
|
|
|
|
|
default: info = _GSC_NONE; break;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Simple types can be serialized immediately, more complex ones
|
|
|
|
|
* are dealt with by our [encodeValueOfObjCType:at:] method.
|
|
|
|
|
*/
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info == _GSC_NONE)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_initialPass == NO)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_ARY_B);
|
|
|
|
|
(*_serImp)(_dst, serSel, &count, @encode(unsigned), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eValImp)(self, eValSel, type, (char*)buf + offset);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
offset += size;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
else if (_initialPass == NO)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_ARY_B);
|
|
|
|
|
(*_serImp)(_dst, serSel, &count, @encode(unsigned), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, info);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_serImp)(_dst, serSel, (char*)buf + offset, type, nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
offset += size;
|
|
|
|
|
}
|
|
|
|
|
}
|
1996-01-26 03:15:14 +00:00
|
|
|
|
}
|
1995-04-15 19:38:52 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) encodeValueOfObjCType: (const char*)type
|
|
|
|
|
at: (const void*)buf
|
1995-04-15 19:38:52 +00:00
|
|
|
|
{
|
1998-10-24 09:58:16 +00:00
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_ID:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eObjImp)(self, eObjSel, *(void**)buf);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_ARY_B:
|
|
|
|
|
{
|
|
|
|
|
int count = atoi(++type);
|
|
|
|
|
|
|
|
|
|
while (isdigit(*type))
|
|
|
|
|
{
|
|
|
|
|
type++;
|
|
|
|
|
}
|
|
|
|
|
|
2000-07-02 18:57:05 +00:00
|
|
|
|
if (_initialPass == NO)
|
|
|
|
|
{
|
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_ARY_B);
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
[self encodeArrayOfObjCType: type count: count at: buf];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_STRUCT_B:
|
|
|
|
|
{
|
2003-04-10 16:26:09 +00:00
|
|
|
|
struct objc_struct_layout layout;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_initialPass == NO)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_STRUCT_B);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
2003-04-10 16:26:09 +00:00
|
|
|
|
objc_layout_structure (type, &layout);
|
|
|
|
|
while (objc_layout_structure_next_member (&layout))
|
|
|
|
|
{
|
|
|
|
|
int offset;
|
|
|
|
|
int align;
|
|
|
|
|
const char *ftype;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2003-04-10 16:26:09 +00:00
|
|
|
|
objc_layout_structure_get_info (&layout, &offset, &align, &ftype);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2003-04-10 16:26:09 +00:00
|
|
|
|
(*_eValImp)(self, eValSel, ftype, (char*)buf + offset);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_PTR:
|
|
|
|
|
if (*(void**)buf == 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_initialPass == NO)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
2002-08-20 15:07:58 +00:00
|
|
|
|
* Special case - a null pointer gets an xref of zero
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_PTR | _GSC_XREF | _GSC_X_0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_ptrMap, (GSIMapKey)*(void**)buf);
|
|
|
|
|
if (_initialPass == YES)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* First pass - add pointer to map and encode item pointed
|
|
|
|
|
* to in case it is a conditionally encoded object.
|
|
|
|
|
*/
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapAddPair(_ptrMap,
|
1999-06-21 08:30:26 +00:00
|
|
|
|
(GSIMapKey)*(void**)buf, (GSIMapVal)0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
type++;
|
|
|
|
|
buf = *(char**)buf;
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eValImp)(self, eValSel, type, buf);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-04-12 12:53:30 +00:00
|
|
|
|
else if (node == 0 || node->value.uint == 0)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Second pass, unwritten pointer - write it.
|
|
|
|
|
*/
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapAddPair(_ptrMap,
|
|
|
|
|
(GSIMapKey)*(void**)buf, (GSIMapVal)++_xRefP);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node->value.uint = ++_xRefP;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_PTR, node->value.uint);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
type++;
|
|
|
|
|
buf = *(char**)buf;
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eValImp)(self, eValSel, type, buf);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Second pass, write a cross-reference number.
|
|
|
|
|
*/
|
2000-07-04 09:44:05 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_PTR|_GSC_XREF,
|
|
|
|
|
node->value.uint);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
default: /* Types that can be ignored in first pass. */
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_initialPass)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_CLASS:
|
|
|
|
|
if (*(Class*)buf == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
2002-08-20 15:07:58 +00:00
|
|
|
|
* Special case - a null pointer gets an xref of zero
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_CLASS | _GSC_XREF | _GSC_X_0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Class c = *(Class*)buf;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
BOOL done = NO;
|
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_clsMap, (GSIMapKey)(void*)c);
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node != 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_CLASS | _GSC_XREF,
|
1999-04-12 12:53:30 +00:00
|
|
|
|
node->value.uint);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while (done == NO)
|
|
|
|
|
{
|
2000-10-31 16:17:33 +00:00
|
|
|
|
int tmp = GSObjCVersion(c);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
unsigned version = tmp;
|
2000-10-31 16:17:33 +00:00
|
|
|
|
Class s = GSObjCSuper(c);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
if (tmp < 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"negative class version"];
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapAddPair(_clsMap,
|
|
|
|
|
(GSIMapKey)(void*)c, (GSIMapVal)++_xRefC);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* Encode tag and crossref number.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_CLASS, node->value.uint);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* Encode class, and version.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_serImp)(_dst, serSel, &c, @encode(Class), nil);
|
|
|
|
|
(*_serImp)(_dst, serSel, &version, @encode(unsigned), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we have a super class that has not been encoded,
|
|
|
|
|
* we must loop round to encode it here so that its
|
|
|
|
|
* version information will be available when objects
|
|
|
|
|
* of its subclasses are decoded and call
|
|
|
|
|
* [super initWithCoder:ccc]
|
|
|
|
|
*/
|
2000-07-04 09:44:05 +00:00
|
|
|
|
if (s == c || s == 0
|
|
|
|
|
|| GSIMapNodeForKey(_clsMap, (GSIMapKey)(void*)s) != 0)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
done = YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c = s;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Encode an empty tag to terminate the list of classes.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_NONE);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_SEL:
|
|
|
|
|
if (*(SEL*)buf == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
2002-08-20 15:07:58 +00:00
|
|
|
|
* Special case - a null pointer gets an xref of zero
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_SEL | _GSC_XREF | _GSC_X_0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SEL s = *(SEL*)buf;
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapNode node = GSIMapNodeForKey(_ptrMap, (GSIMapKey)(void*)s);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapAddPair(_ptrMap,
|
2000-07-04 09:44:05 +00:00
|
|
|
|
(GSIMapKey)(void*)s, (GSIMapVal)++_xRefP);
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_SEL, node->value.uint);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* Encode selector.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_serImp)(_dst, serSel, buf, @encode(SEL), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2000-07-04 09:44:05 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_SEL|_GSC_XREF,
|
|
|
|
|
node->value.uint);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_CHARPTR:
|
|
|
|
|
if (*(char**)buf == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
2002-08-20 15:07:58 +00:00
|
|
|
|
* Special case - a null pointer gets an xref of zero
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_CHARPTR | _GSC_XREF | _GSC_X_0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_ptrMap, (GSIMapKey)*(char**)buf);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapAddPair(_ptrMap,
|
|
|
|
|
(GSIMapKey)*(char**)buf, (GSIMapVal)++_xRefP);
|
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_CHARPTR, node->value.uint);
|
|
|
|
|
(*_serImp)(_dst, serSel, buf, type, nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_CHARPTR|_GSC_XREF,
|
1999-04-12 12:53:30 +00:00
|
|
|
|
node->value.uint);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_CHR:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_CHR);
|
2001-05-11 15:23:24 +00:00
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(signed char), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_UCHR:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_UCHR);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(unsigned char), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_SHT:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_SHT | _GSC_S_SHT);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(short), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_USHT:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_USHT | _GSC_S_SHT);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(unsigned short), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_INT:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_INT | _GSC_S_INT);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(int), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_UINT:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_UINT | _GSC_S_INT);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(unsigned int), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_LNG:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_LNG | _GSC_S_LNG);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(long), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_ULNG:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_ULNG | _GSC_S_LNG);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(unsigned long), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_LNG_LNG:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_LNG_LNG | _GSC_S_LNG_LNG);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(long long), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_ULNG_LNG:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_ULNG_LNG | _GSC_S_LNG_LNG);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(unsigned long long), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_FLT:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_FLT);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(float), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_DBL:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_DBL);
|
|
|
|
|
(*_serImp)(_dst, serSel, (void*)buf, @encode(double), nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _C_VOID:
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"can't encode void item"];
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"item with unknown type - %s", type];
|
|
|
|
|
}
|
1995-04-15 19:38:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) encodeRootObject: (id)rootObject
|
1995-04-15 19:38:52 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_encodingRoot)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"encoding root object more than once"];
|
|
|
|
|
}
|
1995-04-15 19:38:52 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_encodingRoot = YES;
|
1996-01-26 03:15:14 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* First pass - find conditional objects.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_initialPass = YES;
|
|
|
|
|
(*_eObjImp)(self, eObjSel, rootObject);
|
1996-01-26 19:53:15 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* Second pass - write archive.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_initialPass = NO;
|
|
|
|
|
(*_eObjImp)(self, eObjSel, rootObject);
|
1996-01-26 19:53:15 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* Write sizes of crossref arrays to head of archive.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
[self serializeHeaderAt: _startPos
|
1998-10-24 09:58:16 +00:00
|
|
|
|
version: [self systemVersion]
|
1999-09-16 07:21:34 +00:00
|
|
|
|
classes: _clsMap->nodeCount
|
|
|
|
|
objects: _uIdMap->nodeCount
|
|
|
|
|
pointers: _ptrMap->nodeCount];
|
1996-01-26 19:53:15 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_encodingRoot = NO;
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) encodeConditionalObject: (id)anObject
|
1996-01-26 19:53:15 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_encodingRoot == NO)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"conditionally encoding without root object"];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_initialPass)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Conditionally encoding 'nil' is a no-op.
|
|
|
|
|
*/
|
|
|
|
|
if (anObject == nil)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we have already conditionally encoded this object, we can
|
|
|
|
|
* ignore it this time.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_cIdMap, (GSIMapKey)anObject);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node != 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If we have unconditionally encoded this object, we can ignore
|
|
|
|
|
* it now.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_uIdMap, (GSIMapKey)anObject);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node != 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapAddPair(_cIdMap, (GSIMapKey)anObject, (GSIMapVal)0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else if (anObject == nil)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eObjImp)(self, eObjSel, nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_repMap->nodeCount)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_repMap, (GSIMapKey)anObject);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node)
|
|
|
|
|
{
|
1999-04-12 12:53:30 +00:00
|
|
|
|
anObject = (id)node->value.ptr;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_cIdMap, (GSIMapKey)anObject);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node != 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eObjImp)(self, eObjSel, nil);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eObjImp)(self, eObjSel, anObject);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-01-29 11:37:20 +00:00
|
|
|
|
- (void) encodeDataObject: (NSData*)anObject
|
|
|
|
|
{
|
|
|
|
|
unsigned l = [anObject length];
|
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eValImp)(self, eValSel, @encode(unsigned int), &l);
|
1999-01-29 11:37:20 +00:00
|
|
|
|
if (l)
|
|
|
|
|
{
|
|
|
|
|
const void *b = [anObject bytes];
|
|
|
|
|
unsigned char c = 0; /* Type tag */
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The type tag 'c' is used to specify an encoding scheme for the
|
|
|
|
|
* actual data - at present we have '0' meaning raw data. In the
|
|
|
|
|
* future we might want zipped data for instance.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_eValImp)(self, eValSel, @encode(unsigned char), &c);
|
1999-01-29 11:37:20 +00:00
|
|
|
|
[self encodeArrayOfObjCType: @encode(unsigned char)
|
|
|
|
|
count: l
|
|
|
|
|
at: b];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) encodeObject: (id)anObject
|
1996-01-26 19:53:15 +00:00
|
|
|
|
{
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (anObject == nil)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_initialPass == NO)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Special case - encode a nil pointer as a crossref of zero.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_tagImp)(_dst, tagSel, _GSC_ID | _GSC_XREF, _GSC_X_0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Substitute replacement object if required.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_repMap, (GSIMapKey)anObject);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node)
|
|
|
|
|
{
|
1999-04-12 12:53:30 +00:00
|
|
|
|
anObject = (id)node->value.ptr;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* See if the object has already been encoded.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_uIdMap, (GSIMapKey)anObject);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_initialPass)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Remove object from map of conditionally encoded objects
|
|
|
|
|
* and add it to the map of unconditionay encoded ones.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapRemoveKey(_cIdMap, (GSIMapKey)anObject);
|
|
|
|
|
GSIMapAddPair(_uIdMap, (GSIMapKey)anObject, (GSIMapVal)0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
[anObject encodeWithCoder: self];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-12 12:53:30 +00:00
|
|
|
|
if (node == 0 || node->value.uint == 0)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
Class cls;
|
|
|
|
|
id obj;
|
|
|
|
|
|
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapAddPair(_uIdMap,
|
|
|
|
|
(GSIMapKey)anObject, (GSIMapVal)++_xRefO);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node->value.uint = ++_xRefO;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj = [anObject replacementObjectForArchiver: self];
|
2000-10-31 16:17:33 +00:00
|
|
|
|
if (GSObjCIsInstance(obj) == NO)
|
2000-08-07 22:00:31 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If the object we have been given is actually a class,
|
|
|
|
|
* we encode it as a special case.
|
|
|
|
|
*/
|
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_CID, node->value.uint);
|
|
|
|
|
(*_eValImp)(self, eValSel, @encode(Class), &obj);
|
|
|
|
|
}
|
|
|
|
|
else
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
cls = [obj classForArchiver];
|
|
|
|
|
if (_namMap->nodeCount)
|
|
|
|
|
{
|
|
|
|
|
GSIMapNode n;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
n = GSIMapNodeForKey(_namMap, (GSIMapKey)cls);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
if (n)
|
|
|
|
|
{
|
|
|
|
|
cls = (Class)n->value.ptr;
|
|
|
|
|
}
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
2000-08-07 22:00:31 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_ID, node->value.uint);
|
|
|
|
|
(*_eValImp)(self, eValSel, @encode(Class), &cls);
|
|
|
|
|
[obj encodeWithCoder: self];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2000-07-04 09:44:05 +00:00
|
|
|
|
else
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
(*_xRefImp)(_dst, xRefSel, _GSC_ID | _GSC_XREF, node->value.uint);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns whatever data has been encoded thusfar.
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (NSMutableData*) archiverData
|
1996-02-13 01:50:29 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
return _data;
|
1996-02-13 01:50:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns substitute class used to encode objects of given class. This
|
|
|
|
|
* would have been set through an earlier call to
|
|
|
|
|
* [NSArchiver -encodeClassName:intoClassName:].
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
- (NSString*) classNameEncodedForTrueClassName: (NSString*)trueName
|
1996-01-26 19:53:15 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_namMap->nodeCount)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
Class c;
|
|
|
|
|
|
2002-02-21 13:31:13 +00:00
|
|
|
|
c = GSClassFromName([trueName cString]);
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_namMap, (GSIMapKey)c);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node)
|
|
|
|
|
{
|
1999-04-12 12:53:30 +00:00
|
|
|
|
c = (Class)node->value.ptr;
|
2002-02-21 13:31:13 +00:00
|
|
|
|
return [NSString stringWithCString: GSNameFromClass(c)];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return trueName;
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Specify substitute class used in archiving objects of given class. This
|
|
|
|
|
* class is written to the archive as the class to use for restoring the
|
|
|
|
|
* object, instead of what is returned from [NSObject -classForArchiver].
|
|
|
|
|
* This can be used to provide backward compatibility across class name
|
|
|
|
|
* changes. The object is still encoded by calling
|
|
|
|
|
* <code>encodeWithCoder:</code> as normal.
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) encodeClassName: (NSString*)trueName
|
|
|
|
|
intoClassName: (NSString*)inArchiveName
|
1996-01-26 19:53:15 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
Class tc;
|
|
|
|
|
Class ic;
|
|
|
|
|
|
2002-02-21 13:31:13 +00:00
|
|
|
|
tc = GSClassFromName([trueName cString]);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (tc == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Can't find class '%@'.", trueName];
|
|
|
|
|
}
|
2002-02-21 13:31:13 +00:00
|
|
|
|
ic = GSClassFromName([inArchiveName cString]);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (ic == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Can't find class '%@'.", inArchiveName];
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
node = GSIMapNodeForKey(_namMap, (GSIMapKey)tc);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapAddPair(_namMap, (GSIMapKey)(void*)tc, (GSIMapVal)(void*)ic);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-04-12 12:53:30 +00:00
|
|
|
|
node->value.ptr = (void*)ic;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Set encoder to write out newObject in place of object.
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) replaceObject: (id)object
|
|
|
|
|
withObject: (id)newObject
|
1996-01-26 19:53:15 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIMapNode node;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
if (object == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"attempt to remap nil"];
|
|
|
|
|
}
|
|
|
|
|
if (newObject == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"attempt to remap object to nil"];
|
|
|
|
|
}
|
2000-06-26 11:12:13 +00:00
|
|
|
|
node = GSIMapNodeForKey(_repMap, (GSIMapKey)object);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (node == 0)
|
|
|
|
|
{
|
2000-06-26 11:12:13 +00:00
|
|
|
|
GSIMapAddPair(_repMap, (GSIMapKey)object, (GSIMapVal)newObject);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-04-12 12:53:30 +00:00
|
|
|
|
node->value.ptr = (void*)newObject;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
1998-10-24 09:58:16 +00:00
|
|
|
|
@end
|
1996-01-26 19:53:15 +00:00
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1996-01-26 19:53:15 +00:00
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Catagory for compatibility with old GNUstep encoding.
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
|
|
|
|
@implementation NSArchiver (GNUstep)
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Allow reuse of archiver (clears class substitution maps, etc.) but
|
|
|
|
|
* do not clear out current serialized data.
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (void) resetArchiver
|
1996-01-26 19:53:15 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_clsMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapCleanMap(_clsMap);
|
|
|
|
|
if (_cIdMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapCleanMap(_cIdMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_uIdMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapCleanMap(_uIdMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_ptrMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapCleanMap(_ptrMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_namMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapCleanMap(_namMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
if (_repMap)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
GSIMapCleanMap(_repMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_encodingRoot = NO;
|
|
|
|
|
_initialPass = NO;
|
|
|
|
|
_xRefC = 0;
|
|
|
|
|
_xRefO = 0;
|
|
|
|
|
_xRefP = 0;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Write dummy header
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_startPos = [_data length];
|
|
|
|
|
[self serializeHeaderAt: _startPos
|
1998-10-24 09:58:16 +00:00
|
|
|
|
version: 0
|
|
|
|
|
classes: 0
|
|
|
|
|
objects: 0
|
|
|
|
|
pointers: 0];
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Returns YES.
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (BOOL) directDataAccess
|
1996-01-26 19:53:15 +00:00
|
|
|
|
{
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return YES;
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Writes out header for GNUstep archive format.
|
|
|
|
|
*/
|
2002-01-11 10:10:35 +00:00
|
|
|
|
- (void) serializeHeaderAt: (unsigned)positionInData
|
|
|
|
|
version: (unsigned)systemVersion
|
|
|
|
|
classes: (unsigned)classCount
|
|
|
|
|
objects: (unsigned)objectCount
|
|
|
|
|
pointers: (unsigned)pointerCount
|
1996-01-26 03:15:14 +00:00
|
|
|
|
{
|
1998-10-24 09:58:16 +00:00
|
|
|
|
unsigned headerLength = strlen(PREFIX)+36;
|
|
|
|
|
char header[headerLength+1];
|
1999-09-16 07:21:34 +00:00
|
|
|
|
unsigned dataLength = [_data length];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2002-01-11 10:10:35 +00:00
|
|
|
|
sprintf(header, "%s%08x:%08x:%08x:%08x:", PREFIX, systemVersion, classCount,
|
|
|
|
|
objectCount, pointerCount);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2002-01-11 10:10:35 +00:00
|
|
|
|
if (positionInData + headerLength <= dataLength)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
2002-01-11 10:10:35 +00:00
|
|
|
|
[_data replaceBytesInRange: NSMakeRange(positionInData, headerLength)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
withBytes: header];
|
|
|
|
|
}
|
2002-01-11 10:10:35 +00:00
|
|
|
|
else if (positionInData == dataLength)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
[_data appendBytes: header length: headerLength];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"serializeHeader:at: bad location"];
|
|
|
|
|
}
|
1996-01-26 19:53:15 +00:00
|
|
|
|
}
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1995-04-09 02:42:37 +00:00
|
|
|
|
@end
|
1996-01-26 19:53:15 +00:00
|
|
|
|
|