2001-12-17 14:31:42 +00:00
|
|
|
|
/** Implementation of NSUnarchiver for GNUstep
|
1998-10-24 09:58:16 +00:00
|
|
|
|
Copyright (C) 1998 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
|
|
Written by: Richard frith-Macdonald <richard@brainstorm.co.Ik>
|
|
|
|
|
Created: October 1998
|
|
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
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>NSUnarchiver class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "config.h"
|
2000-06-14 04:03:56 +00:00
|
|
|
|
#include <string.h>
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSObjCRuntime.h"
|
|
|
|
|
#include "Foundation/NSZone.h"
|
|
|
|
|
#include "Foundation/NSException.h"
|
|
|
|
|
#include "Foundation/NSByteOrder.h"
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1998-11-20 13:19:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Setup for inline operation of arrays.
|
|
|
|
|
*/
|
2002-01-31 07:20:16 +00:00
|
|
|
|
#define GSI_ARRAY_RETAIN(A, X)
|
|
|
|
|
#define GSI_ARRAY_RELEASE(A, X)
|
2002-02-20 08:32:08 +00:00
|
|
|
|
#define GSI_ARRAY_TYPES GSUNION_OBJ|GSUNION_SEL|GSUNION_PTR
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2003-07-31 23:49:32 +00:00
|
|
|
|
#include "GNUstepBase/GSIArray.h"
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1998-11-20 13:19:23 +00:00
|
|
|
|
#define _IN_NSUNARCHIVER_M
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSArchiver.h"
|
1998-10-24 09:58:16 +00:00
|
|
|
|
#undef _IN_NSUNARCHIVER_M
|
|
|
|
|
|
2003-06-07 01:24:41 +00:00
|
|
|
|
#include "Foundation/NSAutoreleasePool.h"
|
|
|
|
|
#include "Foundation/NSCoder.h"
|
|
|
|
|
#include "Foundation/NSData.h"
|
|
|
|
|
#include "Foundation/NSUtilities.h"
|
|
|
|
|
#include "Foundation/NSString.h"
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
static const char*
|
1999-01-27 12:49:49 +00:00
|
|
|
|
typeToName1(char type)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-01-27 12:49:49 +00:00
|
|
|
|
switch (type)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
case _C_CLASS: return "class";
|
|
|
|
|
case _C_ID: return "object";
|
|
|
|
|
case _C_SEL: return "selector";
|
|
|
|
|
case _C_CHR: return "char";
|
|
|
|
|
case _C_UCHR: return "unsigned char";
|
|
|
|
|
case _C_SHT: return "short";
|
|
|
|
|
case _C_USHT: return "unsigned short";
|
|
|
|
|
case _C_INT: return "int";
|
|
|
|
|
case _C_UINT: return "unsigned int";
|
|
|
|
|
case _C_LNG: return "long";
|
|
|
|
|
case _C_ULNG: return "unsigned long";
|
|
|
|
|
case _C_LNG_LNG: return "long long";
|
|
|
|
|
case _C_ULNG_LNG: return "unsigned long long";
|
|
|
|
|
case _C_FLT: return "float";
|
|
|
|
|
case _C_DBL: return "double";
|
|
|
|
|
case _C_PTR: return "pointer";
|
|
|
|
|
case _C_CHARPTR: return "cstring";
|
|
|
|
|
case _C_ARY_B: return "array";
|
|
|
|
|
case _C_STRUCT_B: return "struct";
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
static char buf1[32];
|
|
|
|
|
static char buf2[32];
|
|
|
|
|
static char *bufptr = buf1;
|
|
|
|
|
|
|
|
|
|
if (bufptr == buf1)
|
|
|
|
|
{
|
|
|
|
|
bufptr = buf2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bufptr = buf1;
|
|
|
|
|
}
|
|
|
|
|
sprintf(bufptr, "unknown type info - 0x%x", type);
|
|
|
|
|
return bufptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
static const char*
|
|
|
|
|
typeToName2(char type)
|
|
|
|
|
{
|
|
|
|
|
switch (type & _GSC_MASK)
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
case _GSC_CID: return "class (encoded as id)";
|
1999-01-27 12:49:49 +00:00
|
|
|
|
case _GSC_CLASS: return "class";
|
|
|
|
|
case _GSC_ID: return "object";
|
|
|
|
|
case _GSC_SEL: return "selector";
|
|
|
|
|
case _GSC_CHR: return "char";
|
|
|
|
|
case _GSC_UCHR: return "unsigned char";
|
|
|
|
|
case _GSC_SHT: return "short";
|
|
|
|
|
case _GSC_USHT: return "unsigned short";
|
|
|
|
|
case _GSC_INT: return "int";
|
|
|
|
|
case _GSC_UINT: return "unsigned int";
|
|
|
|
|
case _GSC_LNG: return "long";
|
|
|
|
|
case _GSC_ULNG: return "unsigned long";
|
|
|
|
|
case _GSC_LNG_LNG: return "long long";
|
|
|
|
|
case _GSC_ULNG_LNG: return "unsigned long long";
|
|
|
|
|
case _GSC_FLT: return "float";
|
|
|
|
|
case _GSC_DBL: return "double";
|
|
|
|
|
case _GSC_PTR: return "pointer";
|
|
|
|
|
case _GSC_CHARPTR: return "cstring";
|
|
|
|
|
case _GSC_ARY_B: return "array";
|
|
|
|
|
case _GSC_STRUCT_B: return "struct";
|
|
|
|
|
default:
|
|
|
|
|
{
|
|
|
|
|
static char buf1[32];
|
|
|
|
|
static char buf2[32];
|
|
|
|
|
static char *bufptr = buf1;
|
|
|
|
|
|
|
|
|
|
if (bufptr == buf1)
|
|
|
|
|
{
|
|
|
|
|
bufptr = buf2;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bufptr = buf1;
|
|
|
|
|
}
|
|
|
|
|
sprintf(bufptr, "unknown type info - 0x%x", type);
|
|
|
|
|
return bufptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* There are thirtyone possible basic types. We reserve a type of zero
|
|
|
|
|
* to mean that no information is specified. The slots in this array
|
|
|
|
|
* MUST correspond to the definitions in NSData.h
|
|
|
|
|
*/
|
|
|
|
|
static char type_map[32] = {
|
|
|
|
|
0,
|
|
|
|
|
_C_CHR,
|
|
|
|
|
_C_UCHR,
|
|
|
|
|
_C_SHT,
|
|
|
|
|
_C_USHT,
|
|
|
|
|
_C_INT,
|
|
|
|
|
_C_UINT,
|
|
|
|
|
_C_LNG,
|
|
|
|
|
_C_ULNG,
|
1999-02-03 15:50:50 +00:00
|
|
|
|
#ifdef _C_LNG_LNG
|
1999-01-27 12:49:49 +00:00
|
|
|
|
_C_LNG_LNG,
|
|
|
|
|
_C_ULNG_LNG,
|
1999-01-28 10:51:29 +00:00
|
|
|
|
#else
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
#endif
|
1999-01-27 12:49:49 +00:00
|
|
|
|
_C_FLT,
|
|
|
|
|
_C_DBL,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
_C_ID,
|
|
|
|
|
_C_CLASS,
|
|
|
|
|
_C_SEL,
|
|
|
|
|
_C_PTR,
|
|
|
|
|
_C_CHARPTR,
|
|
|
|
|
_C_ARY_B,
|
|
|
|
|
_C_STRUCT_B,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0,
|
|
|
|
|
0
|
|
|
|
|
};
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
static inline void
|
|
|
|
|
typeCheck(char t1, char t2)
|
|
|
|
|
{
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (type_map[(t2 & _GSC_MASK)] != t1)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"expected %s and got %s",
|
1999-01-27 12:49:49 +00:00
|
|
|
|
typeToName1(t1), typeToName2(t2)];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define PREFIX "GNUstep archive"
|
|
|
|
|
|
2000-10-30 18:00:27 +00:00
|
|
|
|
static SEL desSel;
|
|
|
|
|
static SEL tagSel;
|
|
|
|
|
static SEL dValSel;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1998-11-27 09:29:20 +00:00
|
|
|
|
@interface NSUnarchiverClassInfo : NSObject
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
@public
|
1998-10-24 09:58:16 +00:00
|
|
|
|
NSString *original;
|
|
|
|
|
NSString *name;
|
|
|
|
|
Class class;
|
|
|
|
|
}
|
|
|
|
|
+ (id) newWithName: (NSString*)n;
|
|
|
|
|
- (void) mapToClass: (Class)c withName: (NSString*)name;
|
|
|
|
|
@end
|
|
|
|
|
|
1998-11-27 09:29:20 +00:00
|
|
|
|
@implementation NSUnarchiverClassInfo
|
1998-10-24 09:58:16 +00:00
|
|
|
|
+ (id) newWithName: (NSString*)n
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
NSUnarchiverClassInfo *info;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1998-11-27 09:29:20 +00:00
|
|
|
|
info = (NSUnarchiverClassInfo*)NSAllocateObject(self,0,NSDefaultMallocZone());
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (info)
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
info->original = [n copyWithZone: NSDefaultMallocZone()];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
return info;
|
|
|
|
|
}
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
|
RELEASE(original);
|
1998-11-27 09:29:20 +00:00
|
|
|
|
if (name)
|
|
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
|
RELEASE(name);
|
1998-11-27 09:29:20 +00:00
|
|
|
|
}
|
|
|
|
|
NSDeallocateObject(self);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
- (void) mapToClass: (Class)c withName: (NSString*)n
|
|
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
|
ASSIGN(name, n);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
class = c;
|
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
/*
|
1998-11-27 09:29:20 +00:00
|
|
|
|
* Dictionary used by NSUnarchiver class to keep track of
|
|
|
|
|
* NSUnarchiverClassInfo objects used to map classes by name when
|
|
|
|
|
* unarchiving.
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
|
|
|
|
static NSMutableDictionary *clsDict; /* Class information */
|
|
|
|
|
|
1998-11-27 09:29:20 +00:00
|
|
|
|
@interface NSUnarchiverObjectInfo : NSUnarchiverClassInfo
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
@public
|
1998-10-24 09:58:16 +00:00
|
|
|
|
unsigned version;
|
1998-11-27 09:29:20 +00:00
|
|
|
|
NSUnarchiverClassInfo *overrides;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
@end
|
|
|
|
|
|
1998-11-27 09:29:20 +00:00
|
|
|
|
inline Class
|
|
|
|
|
mapClassObject(NSUnarchiverObjectInfo *info)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
if (info->overrides == nil)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
info->overrides = [clsDict objectForKey: info->original];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1998-11-27 09:29:20 +00:00
|
|
|
|
if (info->overrides)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
return info->overrides->class;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1998-11-27 09:29:20 +00:00
|
|
|
|
else
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
return info->class;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1998-11-27 09:29:20 +00:00
|
|
|
|
|
|
|
|
|
inline NSString*
|
|
|
|
|
mapClassName(NSUnarchiverObjectInfo *info)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
if (info->overrides == nil)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
info->overrides = [clsDict objectForKey: info->original];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1998-11-27 09:29:20 +00:00
|
|
|
|
if (info->overrides)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
return info->overrides->name;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1998-11-27 09:29:20 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return info->name;
|
|
|
|
|
}
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1998-11-27 09:29:20 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSUnarchiverObjectInfo
|
1998-10-24 09:58:16 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
|
/**
|
|
|
|
|
* This class reconstructs objects from an archive.<br />
|
|
|
|
|
* <strong>Re-using the archiver</strong><br />
|
|
|
|
|
* <p>
|
2002-11-04 15:39:43 +00:00
|
|
|
|
* The -resetUnarchiverWithData:atIndex: method lets you re-use
|
2002-06-06 14:02:59 +00:00
|
|
|
|
* the archive to decode a new data object or, in conjunction
|
|
|
|
|
* with the 'cursor' method (which reports the current decoding
|
|
|
|
|
* position in the archive), decode a second archive that exists
|
|
|
|
|
* in the data object after the first one.
|
|
|
|
|
* </p>
|
|
|
|
|
* <strong>Subclassing with different input format.</strong><br />
|
|
|
|
|
* NSUnarchiver normally reads directly from an NSData object using
|
|
|
|
|
* the methods -
|
|
|
|
|
* <deflist>
|
2002-11-04 15:39:43 +00:00
|
|
|
|
* <term>-deserializeTypeTag:andCrossRef:atCursor:</term>
|
2002-06-06 14:02:59 +00:00
|
|
|
|
* <desc>
|
|
|
|
|
* to decode type tags for data items, the tag is the
|
|
|
|
|
* first byte of the character encoding string for the
|
|
|
|
|
* data type (as provided by '@encode(xxx)'), possibly
|
|
|
|
|
* with the top bit set to indicate that what follows is
|
2002-11-04 15:39:43 +00:00
|
|
|
|
* a crossreference to an item already encoded.<br />
|
|
|
|
|
* Also decode a crossreference number either to identify the
|
2002-06-06 14:02:59 +00:00
|
|
|
|
* following item, or to refer to a previously encoded item.
|
|
|
|
|
* Objects, Classes, Selectors, CStrings and Pointer items
|
|
|
|
|
* have crossreference encoding, other types do not.
|
|
|
|
|
* </desc>
|
2002-11-04 15:39:43 +00:00
|
|
|
|
* <term>[NSData-deserializeDataAt:ofObjCType:atCursor:context:]</term>
|
2002-06-06 14:02:59 +00:00
|
|
|
|
* <desc>
|
|
|
|
|
* to decode all other information.
|
|
|
|
|
* </desc>
|
|
|
|
|
* </deflist>
|
|
|
|
|
* <p>
|
|
|
|
|
* And uses other NSData methods to read the archive header information
|
|
|
|
|
* from within the method:
|
|
|
|
|
* [-deserializeHeaderAt:version:classes:objects:pointers:]
|
|
|
|
|
* to read a fixed size header including archiver version
|
|
|
|
|
* (obtained by [self systemVersion]) and crossreference
|
|
|
|
|
* table sizes.
|
|
|
|
|
* </p>
|
|
|
|
|
* <p>
|
|
|
|
|
* To subclass NSUnarchiver, you must implement your own versions of the
|
|
|
|
|
* four methods above, and override the 'directDataAccess' method to
|
|
|
|
|
* return NO so that the archiver knows to use your serialization
|
|
|
|
|
* methods rather than those in the NSData object.
|
|
|
|
|
* </p>
|
|
|
|
|
*/
|
1998-10-24 09:58:16 +00:00
|
|
|
|
@implementation NSUnarchiver
|
|
|
|
|
|
2000-10-31 11:05:23 +00:00
|
|
|
|
@class NSDataMalloc;
|
|
|
|
|
static Class NSDataMallocClass;
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if ([self class] == [NSUnarchiver class])
|
|
|
|
|
{
|
2000-10-30 18:00:27 +00:00
|
|
|
|
desSel = @selector(deserializeDataAt:ofObjCType:atCursor:context:);
|
|
|
|
|
tagSel = @selector(deserializeTypeTag:andCrossRef:atCursor:);
|
|
|
|
|
dValSel = @selector(decodeValueOfObjCType:at:);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
clsDict = [[NSMutableDictionary alloc] initWithCapacity: 200];
|
2000-10-31 11:05:23 +00:00
|
|
|
|
NSDataMallocClass = [NSDataMalloc class];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id) unarchiveObjectWithData: (NSData*)anObject
|
|
|
|
|
{
|
|
|
|
|
NSUnarchiver *unarchiver;
|
|
|
|
|
id obj;
|
|
|
|
|
|
1999-07-02 07:35:41 +00:00
|
|
|
|
unarchiver = [[self alloc] initForReadingWithData: anObject];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
obj = [unarchiver decodeObject];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
2001-03-03 14:49:11 +00:00
|
|
|
|
obj = nil;
|
1999-05-06 19:37:45 +00:00
|
|
|
|
RELEASE(unarchiver);
|
1998-10-28 13:58:05 +00:00
|
|
|
|
[localException raise];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
1999-05-06 19:37:45 +00:00
|
|
|
|
RELEASE(unarchiver);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (id) unarchiveObjectWithFile: (NSString*)path
|
|
|
|
|
{
|
2000-10-31 11:05:23 +00:00
|
|
|
|
NSData *d = [NSDataMallocClass dataWithContentsOfFile: path];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
if (d != nil)
|
|
|
|
|
{
|
|
|
|
|
return [self unarchiveObjectWithData: d];
|
|
|
|
|
}
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
1999-05-06 19:37:45 +00:00
|
|
|
|
RELEASE(data);
|
|
|
|
|
RELEASE(objDict);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (clsMap)
|
|
|
|
|
{
|
1998-11-20 13:19:23 +00:00
|
|
|
|
NSZone *z = clsMap->zone;
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayClear(clsMap);
|
|
|
|
|
GSIArrayClear(objMap);
|
|
|
|
|
GSIArrayClear(ptrMap);
|
1998-11-20 13:19:23 +00:00
|
|
|
|
NSZoneFree(z, (void*)clsMap);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) initForReadingWithData: (NSData*)anObject
|
|
|
|
|
{
|
|
|
|
|
if (anObject == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nil data passed to initForReadingWithData:"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self = [super init];
|
|
|
|
|
if (self)
|
|
|
|
|
{
|
|
|
|
|
dValImp = [self methodForSelector: dValSel];
|
|
|
|
|
zone = [self zone];
|
|
|
|
|
/*
|
|
|
|
|
* If we are not deserializing directly from the data object
|
|
|
|
|
* then we cache our own deserialisation methods.
|
|
|
|
|
*/
|
|
|
|
|
if ([self directDataAccess] == NO)
|
|
|
|
|
{
|
|
|
|
|
src = self; /* Default object to handle serialisation */
|
|
|
|
|
desImp = [src methodForSelector: desSel];
|
1999-01-27 12:49:49 +00:00
|
|
|
|
tagImp = (void (*)(id, SEL, unsigned char*, unsigned*, unsigned*))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
[src methodForSelector: tagSel];
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* objDict is a dictionary of objects for mapping classes of
|
|
|
|
|
* one name to be those of another name! It also handles
|
|
|
|
|
* keeping track of the version numbers that the classes were
|
|
|
|
|
* encoded with.
|
|
|
|
|
*/
|
|
|
|
|
objDict = [[NSMutableDictionary allocWithZone: zone]
|
|
|
|
|
initWithCapacity: 200];
|
|
|
|
|
|
1999-07-02 07:35:41 +00:00
|
|
|
|
NS_DURING
|
|
|
|
|
{
|
|
|
|
|
[self resetUnarchiverWithData: anObject atIndex: 0];
|
|
|
|
|
}
|
|
|
|
|
NS_HANDLER
|
|
|
|
|
{
|
|
|
|
|
RELEASE(self);
|
|
|
|
|
[localException raise];
|
|
|
|
|
}
|
|
|
|
|
NS_ENDHANDLER
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) decodeArrayOfObjCType: (const char*)type
|
|
|
|
|
count: (unsigned)expected
|
|
|
|
|
at: (void*)buf
|
|
|
|
|
{
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int i;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
int offset = 0;
|
2003-01-03 20:14:47 +00:00
|
|
|
|
unsigned int size = (unsigned int)objc_sizeof_type(type);
|
1999-01-27 12:49:49 +00:00
|
|
|
|
unsigned char info;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
unsigned count;
|
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
(*tagImp)(src, tagSel, &info, 0, &cursor);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
(*desImp)(src, desSel, &count, @encode(unsigned), &cursor, nil);
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info != _GSC_ARY_B)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
1999-01-27 12:49:49 +00:00
|
|
|
|
format: @"expected array and got %s", typeToName2(info)];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
if (count != expected)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"expected array count %u and got %u",
|
|
|
|
|
expected, count];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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; break;
|
|
|
|
|
case _C_USHT: info = _GSC_USHT; break;
|
|
|
|
|
case _C_INT: info = _GSC_INT; break;
|
|
|
|
|
case _C_UINT: info = _GSC_UINT; break;
|
|
|
|
|
case _C_LNG: info = _GSC_LNG; break;
|
|
|
|
|
case _C_ULNG: info = _GSC_ULNG; break;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
#ifdef _C_LNG_LNG
|
1999-01-27 12:49:49 +00:00
|
|
|
|
case _C_LNG_LNG: info = _GSC_LNG_LNG; break;
|
|
|
|
|
case _C_ULNG_LNG: info = _GSC_ULNG_LNG; break;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
#endif
|
1999-01-27 12:49:49 +00:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info == _GSC_NONE)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
(*dValImp)(self, dValSel, type, (char*)buf + offset);
|
|
|
|
|
offset += size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-01-27 12:49:49 +00:00
|
|
|
|
unsigned char ainfo;
|
|
|
|
|
|
|
|
|
|
(*tagImp)(src, tagSel, &ainfo, 0, &cursor);
|
|
|
|
|
if (info != (ainfo & _GSC_MASK))
|
|
|
|
|
{
|
2000-08-07 22:00:31 +00:00
|
|
|
|
if (info != _GSC_ID || (ainfo & _GSC_MASK) != _GSC_CID)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"expected %s and got %s",
|
|
|
|
|
typeToName2(info), typeToName2(ainfo)];
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
}
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
(*desImp)(src, desSel, (char*)buf + offset, type, &cursor, nil);
|
|
|
|
|
offset += size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) decodeValueOfObjCType: (const char*)type
|
|
|
|
|
at: (void*)address
|
|
|
|
|
{
|
1999-01-27 12:49:49 +00:00
|
|
|
|
unsigned xref;
|
|
|
|
|
unsigned char info;
|
|
|
|
|
#if GS_HAVE_I128
|
|
|
|
|
gsu128 bigval;
|
|
|
|
|
#else
|
|
|
|
|
#if GS_HAVE_I64
|
|
|
|
|
gsu64 bigval;
|
|
|
|
|
#else
|
|
|
|
|
gsu32 bigval;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
(*tagImp)(src, tagSel, &info, &xref, &cursor);
|
|
|
|
|
|
|
|
|
|
switch (info & _GSC_MASK)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-01-27 12:49:49 +00:00
|
|
|
|
case _GSC_ID:
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
id obj;
|
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
typeCheck(*type, _GSC_ID);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
1999-01-27 12:49:49 +00:00
|
|
|
|
* Special case - a zero crossref value size is a nil pointer.
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if ((info & _GSC_SIZE) == 0)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
obj = nil;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info & _GSC_XREF)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref >= GSIArrayCount(objMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"object crossref missing - %d",
|
|
|
|
|
xref];
|
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
obj = GSIArrayItemAtIndex(objMap, xref).obj;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* If it's a cross-reference, we need to retain it in
|
|
|
|
|
* order to give the appearance that it's actually a
|
|
|
|
|
* new object.
|
|
|
|
|
*/
|
1999-09-28 19:35:09 +00:00
|
|
|
|
IF_NO_GC(RETAIN(obj));
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
id rep;
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref != GSIArrayCount(objMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"extra object crossref - %d",
|
|
|
|
|
xref];
|
|
|
|
|
}
|
|
|
|
|
(*dValImp)(self, dValSel, @encode(Class), &c);
|
|
|
|
|
|
2002-02-21 13:31:13 +00:00
|
|
|
|
if (c == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"decoded nil class"];
|
|
|
|
|
}
|
1998-10-24 09:58:16 +00:00
|
|
|
|
obj = [c allocWithZone: zone];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayAddItem(objMap, (GSIArrayItem)obj);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
rep = [obj initWithCoder: self];
|
|
|
|
|
if (rep != obj)
|
|
|
|
|
{
|
|
|
|
|
obj = rep;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArraySetItemAtIndex(objMap, (GSIArrayItem)obj, xref);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rep = [obj awakeAfterUsingCoder: self];
|
|
|
|
|
if (rep != obj)
|
|
|
|
|
{
|
|
|
|
|
obj = rep;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArraySetItemAtIndex(objMap, (GSIArrayItem)obj, xref);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*(id*)address = obj;
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
|
|
|
|
|
case _GSC_CLASS:
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
Class c;
|
1998-11-27 09:29:20 +00:00
|
|
|
|
NSUnarchiverObjectInfo *classInfo;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
Class dummy;
|
|
|
|
|
|
2000-08-07 22:00:31 +00:00
|
|
|
|
if (*type != _C_ID)
|
|
|
|
|
{
|
|
|
|
|
typeCheck(*type, _GSC_CLASS);
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
/*
|
|
|
|
|
* Special case - a zero crossref value size is a nil pointer.
|
|
|
|
|
*/
|
|
|
|
|
if ((info & _GSC_SIZE) == 0)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
*(SEL*)address = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info & _GSC_XREF)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref >= GSIArrayCount(clsMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"class crossref missing - %d", xref];
|
|
|
|
|
}
|
2002-02-21 13:31:13 +00:00
|
|
|
|
classInfo = (NSUnarchiverObjectInfo*)
|
|
|
|
|
GSIArrayItemAtIndex(clsMap, xref).obj;
|
1998-11-27 09:29:20 +00:00
|
|
|
|
*(Class*)address = mapClassObject(classInfo);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
while ((info & _GSC_MASK) == _GSC_CLASS)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned cver;
|
|
|
|
|
NSString *className;
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref != GSIArrayCount(clsMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"extra class crossref - %d", xref];
|
|
|
|
|
}
|
|
|
|
|
(*desImp)(src, desSel, &c, @encode(Class), &cursor, nil);
|
|
|
|
|
(*desImp)(src, desSel, &cver, @encode(unsigned), &cursor, nil);
|
|
|
|
|
if (c == 0)
|
|
|
|
|
{
|
2002-02-21 13:31:13 +00:00
|
|
|
|
NSLog(@"[%s %s] decoded nil class",
|
|
|
|
|
GSNameFromClass([self class]), GSNameFromSelector(_cmd));
|
|
|
|
|
className = @"_NSUnarchiverUnknownClass";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
className = NSStringFromClass(c);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
classInfo = [objDict objectForKey: className];
|
|
|
|
|
if (classInfo == nil)
|
|
|
|
|
{
|
2002-02-21 13:31:13 +00:00
|
|
|
|
classInfo = [NSUnarchiverObjectInfo
|
|
|
|
|
newWithName: className];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
[classInfo mapToClass: c withName: className];
|
|
|
|
|
[objDict setObject: classInfo forKey: className];
|
1999-05-06 19:37:45 +00:00
|
|
|
|
RELEASE(classInfo);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1998-11-27 09:29:20 +00:00
|
|
|
|
classInfo->version = cver;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayAddItem(clsMap, (GSIArrayItem)classInfo);
|
1998-11-27 09:29:20 +00:00
|
|
|
|
*(Class*)address = mapClassObject(classInfo);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
/*
|
|
|
|
|
* Point the address to a dummy location and read the
|
|
|
|
|
* next tag - if it is another class, loop to get it.
|
|
|
|
|
*/
|
|
|
|
|
address = &dummy;
|
1999-01-27 12:49:49 +00:00
|
|
|
|
(*tagImp)(src, tagSel, &info, &xref, &cursor);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info != _GSC_NONE)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"class list improperly terminated"];
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
|
|
|
|
|
case _GSC_SEL:
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
SEL sel;
|
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
typeCheck(*type, _GSC_SEL);
|
|
|
|
|
/*
|
|
|
|
|
* Special case - a zero crossref value size is a nil pointer.
|
|
|
|
|
*/
|
|
|
|
|
if ((info & _GSC_SIZE) == 0)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
*(SEL*)address = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info & _GSC_XREF)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref >= GSIArrayCount(ptrMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"sel crossref missing - %d", xref];
|
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
sel = GSIArrayItemAtIndex(ptrMap, xref).sel;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref != GSIArrayCount(ptrMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"extra sel crossref - %d", xref];
|
|
|
|
|
}
|
|
|
|
|
(*desImp)(src, desSel, &sel, @encode(SEL), &cursor, nil);
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayAddItem(ptrMap, (GSIArrayItem)sel);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
*(SEL*)address = sel;
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
|
|
|
|
|
case _GSC_ARY_B:
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
int count;
|
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
typeCheck(*type, _GSC_ARY_B);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
count = atoi(++type);
|
|
|
|
|
while (isdigit(*type))
|
|
|
|
|
{
|
|
|
|
|
type++;
|
|
|
|
|
}
|
|
|
|
|
[self decodeArrayOfObjCType: type count: count at: address];
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
|
|
|
|
|
case _GSC_STRUCT_B:
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
2003-04-10 16:26:09 +00:00
|
|
|
|
struct objc_struct_layout layout;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
typeCheck(*type, _GSC_STRUCT_B);
|
2003-04-10 16:26:09 +00:00
|
|
|
|
objc_layout_structure (type, &layout);
|
|
|
|
|
while (objc_layout_structure_next_member (&layout))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
2003-04-10 16:26:09 +00:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
(*dValImp)(self, dValSel, ftype, (char*)address + offset);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-27 12:49:49 +00:00
|
|
|
|
case _GSC_PTR:
|
|
|
|
|
{
|
|
|
|
|
typeCheck(*type, _GSC_PTR);
|
|
|
|
|
/*
|
|
|
|
|
* Special case - a zero crossref value size is a nil pointer.
|
|
|
|
|
*/
|
|
|
|
|
if ((info & _GSC_SIZE) == 0)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
*(void**)address = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info & _GSC_XREF)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref >= GSIArrayCount(ptrMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"ptr crossref missing - %d", xref];
|
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
*(void**)address = GSIArrayItemAtIndex(ptrMap, xref).ptr;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned size;
|
|
|
|
|
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (GSIArrayCount(ptrMap) != xref)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"extra ptr crossref - %d", xref];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
1998-10-28 13:58:05 +00:00
|
|
|
|
* Allocate memory for object to be decoded into and
|
|
|
|
|
* add it to the crossref map.
|
1998-10-24 09:58:16 +00:00
|
|
|
|
*/
|
|
|
|
|
size = objc_sizeof_type(++type);
|
2003-03-02 07:47:18 +00:00
|
|
|
|
*(void**)address = GSAutoreleasedBuffer(size);
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayAddItem(ptrMap, (GSIArrayItem)*(void**)address);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Decode value and add memory to map for crossrefs.
|
|
|
|
|
*/
|
|
|
|
|
(*dValImp)(self, dValSel, type, *(void**)address);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
|
|
|
|
|
case _GSC_CHARPTR:
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-01-27 12:49:49 +00:00
|
|
|
|
typeCheck(*type, _GSC_CHARPTR);
|
|
|
|
|
/*
|
|
|
|
|
* Special case - a zero crossref value size is a nil pointer.
|
|
|
|
|
*/
|
|
|
|
|
if ((info & _GSC_SIZE) == 0)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
*(char**)address = 0;
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
if (info & _GSC_XREF)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref >= GSIArrayCount(ptrMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"string crossref missing - %d", xref];
|
|
|
|
|
}
|
1999-06-21 08:30:26 +00:00
|
|
|
|
*(char**)address = GSIArrayItemAtIndex(ptrMap, xref).str;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (xref != GSIArrayCount(ptrMap))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"extra string crossref - %d", xref];
|
|
|
|
|
}
|
|
|
|
|
(*desImp)(src, desSel, address, @encode(char*), &cursor, nil);
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayAddItem(ptrMap, (GSIArrayItem)*(void**)address);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
1999-01-27 12:49:49 +00:00
|
|
|
|
|
|
|
|
|
case _GSC_CHR:
|
|
|
|
|
case _GSC_UCHR:
|
2001-05-11 15:23:24 +00:00
|
|
|
|
/* Encoding of chars is not consistant across platforms, so we
|
|
|
|
|
loosen the type checking a little */
|
|
|
|
|
if (*type != type_map[_GSC_CHR] && *type != type_map[_GSC_UCHR])
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"expected %s and got %s",
|
|
|
|
|
typeToName1(*type), typeToName2(info)];
|
|
|
|
|
}
|
1998-10-24 09:58:16 +00:00
|
|
|
|
(*desImp)(src, desSel, address, type, &cursor, nil);
|
1999-01-27 12:49:49 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _GSC_SHT:
|
|
|
|
|
case _GSC_USHT:
|
|
|
|
|
typeCheck(*type, info & _GSC_MASK);
|
|
|
|
|
if ((info & _GSC_SIZE) == _GSC_S_SHT)
|
|
|
|
|
{
|
|
|
|
|
(*desImp)(src, desSel, address, type, &cursor, nil);
|
|
|
|
|
return;
|
|
|
|
|
}
|
1998-10-24 09:58:16 +00:00
|
|
|
|
break;
|
1999-01-27 12:49:49 +00:00
|
|
|
|
|
|
|
|
|
case _GSC_INT:
|
|
|
|
|
case _GSC_UINT:
|
|
|
|
|
typeCheck(*type, info & _GSC_MASK);
|
|
|
|
|
if ((info & _GSC_SIZE) == _GSC_S_INT)
|
|
|
|
|
{
|
|
|
|
|
(*desImp)(src, desSel, address, type, &cursor, nil);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case _GSC_LNG:
|
|
|
|
|
case _GSC_ULNG:
|
|
|
|
|
typeCheck(*type, info & _GSC_MASK);
|
|
|
|
|
if ((info & _GSC_SIZE) == _GSC_S_LNG)
|
|
|
|
|
{
|
|
|
|
|
(*desImp)(src, desSel, address, type, &cursor, nil);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
#ifdef _C_LNG_LNG
|
1999-01-27 12:49:49 +00:00
|
|
|
|
case _GSC_LNG_LNG:
|
|
|
|
|
case _GSC_ULNG_LNG:
|
|
|
|
|
typeCheck(*type, info & _GSC_MASK);
|
|
|
|
|
if ((info & _GSC_SIZE) == _GSC_S_LNG_LNG)
|
|
|
|
|
{
|
|
|
|
|
(*desImp)(src, desSel, address, type, &cursor, nil);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
case _GSC_FLT:
|
|
|
|
|
typeCheck(*type, _GSC_FLT);
|
|
|
|
|
(*desImp)(src, desSel, address, type, &cursor, nil);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case _GSC_DBL:
|
|
|
|
|
typeCheck(*type, _GSC_DBL);
|
|
|
|
|
(*desImp)(src, desSel, address, type, &cursor, nil);
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"read unknown type info - %d", info];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We fall through to here only when we have to decode a value
|
|
|
|
|
* whose natural size on this system is not the same as on the
|
|
|
|
|
* machine on which the archive was created.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* First, we read the data and convert it to the largest size
|
|
|
|
|
* this system can support.
|
|
|
|
|
*/
|
|
|
|
|
switch (info & _GSC_SIZE)
|
|
|
|
|
{
|
|
|
|
|
case _GSC_I16: /* Encoded as 16-bit */
|
|
|
|
|
{
|
|
|
|
|
gsu16 val;
|
|
|
|
|
|
|
|
|
|
(*desImp)(src, desSel, &val, @encode(gsu16), &cursor, nil);
|
|
|
|
|
bigval = val;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
break;
|
1999-01-27 12:49:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _GSC_I32: /* Encoded as 32-bit */
|
|
|
|
|
{
|
|
|
|
|
gsu32 val;
|
|
|
|
|
|
|
|
|
|
(*desImp)(src, desSel, &val, @encode(gsu32), &cursor, nil);
|
|
|
|
|
bigval = val;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
break;
|
1999-01-27 12:49:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case _GSC_I64: /* Encoded as 64-bit */
|
|
|
|
|
{
|
|
|
|
|
gsu64 val;
|
|
|
|
|
|
|
|
|
|
(*desImp)(src, desSel, &val, @encode(gsu64), &cursor, nil);
|
|
|
|
|
#if GS_HAVE_I64
|
|
|
|
|
bigval = val;
|
|
|
|
|
#else
|
2000-07-04 09:44:05 +00:00
|
|
|
|
bigval = GSSwapBigI64ToHost(val);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
#endif
|
|
|
|
|
break;
|
1999-01-27 12:49:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default: /* A 128-bit value */
|
|
|
|
|
{
|
|
|
|
|
gsu128 val;
|
|
|
|
|
|
|
|
|
|
(*desImp)(src, desSel, &val, @encode(gsu128), &cursor, nil);
|
|
|
|
|
#if GS_HAVE_I128
|
|
|
|
|
bigval = val;
|
|
|
|
|
#else
|
1999-02-08 10:46:32 +00:00
|
|
|
|
val = GSSwapBigI128ToHost(val);
|
1999-01-27 12:49:49 +00:00
|
|
|
|
#if GS_HAVE_I64
|
|
|
|
|
bigval = *(gsu64*)&val;
|
|
|
|
|
#else
|
|
|
|
|
bigval = *(gsu32*)&val;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
1998-10-24 09:58:16 +00:00
|
|
|
|
break;
|
1999-01-27 12:49:49 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now we copy from the 'bigval' to the destination location.
|
|
|
|
|
*/
|
|
|
|
|
switch (info & _GSC_MASK)
|
|
|
|
|
{
|
|
|
|
|
case _GSC_SHT:
|
|
|
|
|
*(short*)address = (short)bigval;
|
|
|
|
|
return;
|
|
|
|
|
case _GSC_USHT:
|
|
|
|
|
*(unsigned short*)address = (unsigned short)bigval;
|
|
|
|
|
return;
|
|
|
|
|
case _GSC_INT:
|
|
|
|
|
*(int*)address = (int)bigval;
|
|
|
|
|
return;
|
|
|
|
|
case _GSC_UINT:
|
|
|
|
|
*(unsigned int*)address = (unsigned int)bigval;
|
|
|
|
|
return;
|
|
|
|
|
case _GSC_LNG:
|
|
|
|
|
*(long*)address = (long)bigval;
|
|
|
|
|
return;
|
|
|
|
|
case _GSC_ULNG:
|
|
|
|
|
*(unsigned long*)address = (unsigned long)bigval;
|
|
|
|
|
return;
|
|
|
|
|
#ifdef _C_LNG_LNG
|
|
|
|
|
case _GSC_LNG_LNG:
|
|
|
|
|
*(long long*)address = (long long)bigval;
|
|
|
|
|
return;
|
|
|
|
|
case _GSC_ULNG_LNG:
|
|
|
|
|
*(unsigned long long*)address = (unsigned long long)bigval;
|
|
|
|
|
return;
|
|
|
|
|
#endif
|
1998-10-24 09:58:16 +00:00
|
|
|
|
default:
|
1999-01-27 12:49:49 +00:00
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"type/size information error"];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-01-29 11:37:20 +00:00
|
|
|
|
- (NSData*) decodeDataObject
|
|
|
|
|
{
|
|
|
|
|
unsigned l;
|
|
|
|
|
|
|
|
|
|
(*dValImp)(self, dValSel, @encode(unsigned int), &l);
|
|
|
|
|
if (l)
|
|
|
|
|
{
|
|
|
|
|
unsigned char c;
|
|
|
|
|
|
|
|
|
|
(*dValImp)(self, dValSel, @encode(unsigned char), &c);
|
|
|
|
|
if (c == 0)
|
|
|
|
|
{
|
|
|
|
|
void *b;
|
|
|
|
|
NSData *d;
|
2000-06-27 16:18:02 +00:00
|
|
|
|
NSZone *z;
|
1999-01-29 11:37:20 +00:00
|
|
|
|
|
2000-06-27 16:18:02 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
z = GSAtomicMallocZone();
|
|
|
|
|
#else
|
|
|
|
|
z = zone;
|
|
|
|
|
#endif
|
|
|
|
|
b = NSZoneMalloc(z, l);
|
1999-01-29 11:37:20 +00:00
|
|
|
|
[self decodeArrayOfObjCType: @encode(unsigned char)
|
|
|
|
|
count: l
|
|
|
|
|
at: b];
|
2000-06-27 16:18:02 +00:00
|
|
|
|
d = [[NSData allocWithZone: zone] initWithBytesNoCopy: b
|
2000-09-27 15:26:16 +00:00
|
|
|
|
length: l];
|
2000-06-27 16:18:02 +00:00
|
|
|
|
IF_NO_GC(AUTORELEASE(d));
|
1999-01-29 11:37:20 +00:00
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
else
|
2000-06-27 16:18:02 +00:00
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Decoding data object with unknown type"];
|
|
|
|
|
}
|
1999-01-29 11:37:20 +00:00
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
return [NSData data];
|
1999-01-29 11:37:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
1998-10-24 09:58:16 +00:00
|
|
|
|
- (BOOL) isAtEnd
|
|
|
|
|
{
|
|
|
|
|
return (cursor >= [data length]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSZone*) objectZone
|
|
|
|
|
{
|
|
|
|
|
return zone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setObjectZone: (NSZone*)aZone
|
|
|
|
|
{
|
|
|
|
|
zone = aZone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned) systemVersion
|
|
|
|
|
{
|
|
|
|
|
return version;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSString*) classNameDecodedForArchiveClassName: (NSString*)nameInArchive
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
NSUnarchiverClassInfo *info = [clsDict objectForKey: nameInArchive];
|
2002-02-26 13:55:47 +00:00
|
|
|
|
NSString *alias;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2002-02-26 13:55:47 +00:00
|
|
|
|
if (info == nil)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
alias = info->name;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (alias)
|
|
|
|
|
{
|
|
|
|
|
return alias;
|
|
|
|
|
}
|
|
|
|
|
return nameInArchive;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) decodeClassName: (NSString*)nameInArchive
|
|
|
|
|
asClassName: (NSString*)trueName
|
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
|
2002-02-21 13:31:13 +00:00
|
|
|
|
c = GSClassFromName([trueName cString]);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (c == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"can't find class %@", trueName];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
NSUnarchiverClassInfo *info = [clsDict objectForKey: nameInArchive];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
if (info == nil)
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
info = [NSUnarchiverClassInfo newWithName: nameInArchive];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
[clsDict setObject: info forKey: nameInArchive];
|
1999-05-06 19:37:45 +00:00
|
|
|
|
RELEASE(info);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
[info mapToClass: c withName: trueName];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) classNameDecodedForArchiveClassName: (NSString*)nameInArchive
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
NSUnarchiverObjectInfo *info = [objDict objectForKey: nameInArchive];
|
2002-02-26 13:55:47 +00:00
|
|
|
|
NSString *alias;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
2002-02-26 13:55:47 +00:00
|
|
|
|
if (info == nil)
|
|
|
|
|
{
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
alias = mapClassName(info);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (alias)
|
|
|
|
|
{
|
|
|
|
|
return alias;
|
|
|
|
|
}
|
|
|
|
|
return nameInArchive;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- (void) decodeClassName: (NSString*)nameInArchive
|
|
|
|
|
asClassName: (NSString*)trueName
|
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
|
2002-02-21 13:31:13 +00:00
|
|
|
|
c = GSClassFromName([trueName cString]);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (c == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"can't find class %@", trueName];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
NSUnarchiverObjectInfo *info = [objDict objectForKey: nameInArchive];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
if (info == nil)
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
info = [NSUnarchiverObjectInfo newWithName: nameInArchive];
|
1998-10-24 09:58:16 +00:00
|
|
|
|
[objDict setObject: info forKey: nameInArchive];
|
1999-05-06 19:37:45 +00:00
|
|
|
|
RELEASE(info);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
[info mapToClass: c withName: trueName];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) replaceObject: (id)anObject withObject: (id)replacement
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
1999-04-12 12:53:30 +00:00
|
|
|
|
if (replacement == anObject)
|
|
|
|
|
return;
|
1999-06-21 08:30:26 +00:00
|
|
|
|
for (i = GSIArrayCount(objMap) - 1; i > 0; i--)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
if (GSIArrayItemAtIndex(objMap, i).obj == anObject)
|
1998-10-24 09:58:16 +00:00
|
|
|
|
{
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArraySetItemAtIndex(objMap, (GSIArrayItem)replacement, i);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"object to be replaced does not exist"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned) versionForClassName: (NSString*)className
|
|
|
|
|
{
|
1998-11-27 09:29:20 +00:00
|
|
|
|
NSUnarchiverObjectInfo *info;
|
|
|
|
|
|
|
|
|
|
info = [objDict objectForKey: className];
|
2002-02-26 12:43:50 +00:00
|
|
|
|
if (info == nil)
|
|
|
|
|
{
|
|
|
|
|
return NSNotFound;
|
|
|
|
|
}
|
1998-11-27 09:29:20 +00:00
|
|
|
|
return info->version;
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation NSUnarchiver (GNUstep)
|
|
|
|
|
|
|
|
|
|
/* Re-using the unarchiver */
|
|
|
|
|
|
|
|
|
|
- (unsigned) cursor
|
|
|
|
|
{
|
|
|
|
|
return cursor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) resetUnarchiverWithData: (NSData*)anObject
|
|
|
|
|
atIndex: (unsigned)pos
|
|
|
|
|
{
|
|
|
|
|
unsigned sizeC;
|
|
|
|
|
unsigned sizeO;
|
|
|
|
|
unsigned sizeP;
|
|
|
|
|
|
|
|
|
|
if (anObject == nil)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"nil passed to resetUnarchiverWithData:atIndex:"];
|
|
|
|
|
}
|
|
|
|
|
if (data != anObject)
|
|
|
|
|
{
|
|
|
|
|
Class c;
|
|
|
|
|
|
1999-07-02 07:35:41 +00:00
|
|
|
|
TEST_RELEASE(data);
|
1999-05-06 19:37:45 +00:00
|
|
|
|
data = RETAIN(anObject);
|
2000-10-31 16:17:33 +00:00
|
|
|
|
c = GSObjCClass(data);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
if (src != self)
|
|
|
|
|
{
|
|
|
|
|
src = data;
|
|
|
|
|
if (c != dataClass)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Cache methods for deserialising from the data object.
|
|
|
|
|
*/
|
|
|
|
|
desImp = [src methodForSelector: desSel];
|
1999-01-27 12:49:49 +00:00
|
|
|
|
tagImp = (void (*)(id, SEL, unsigned char*, unsigned*, unsigned*))
|
1998-10-24 09:58:16 +00:00
|
|
|
|
[src methodForSelector: tagSel];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
dataClass = c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Read header including version and crossref table sizes.
|
|
|
|
|
*/
|
|
|
|
|
cursor = pos;
|
|
|
|
|
[self deserializeHeaderAt: &cursor
|
|
|
|
|
version: &version
|
|
|
|
|
classes: &sizeC
|
|
|
|
|
objects: &sizeO
|
|
|
|
|
pointers: &sizeP];
|
|
|
|
|
|
|
|
|
|
if (clsMap == 0)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Allocate and initialise arrays to build crossref maps in.
|
|
|
|
|
*/
|
1999-06-21 08:30:26 +00:00
|
|
|
|
clsMap = NSZoneMalloc(zone, sizeof(GSIArray_t)*3);
|
|
|
|
|
GSIArrayInitWithZoneAndCapacity(clsMap, zone, sizeC);
|
2002-02-20 08:32:08 +00:00
|
|
|
|
GSIArrayAddItem(clsMap, (GSIArrayItem)(void*)0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
objMap = &clsMap[1];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayInitWithZoneAndCapacity(objMap, zone, sizeO);
|
2002-02-20 08:32:08 +00:00
|
|
|
|
GSIArrayAddItem(objMap, (GSIArrayItem)(void*)0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
|
|
|
|
|
ptrMap = &clsMap[2];
|
1999-06-21 08:30:26 +00:00
|
|
|
|
GSIArrayInitWithZoneAndCapacity(ptrMap, zone, sizeP);
|
2002-02-20 08:32:08 +00:00
|
|
|
|
GSIArrayAddItem(ptrMap, (GSIArrayItem)(void*)0);
|
1998-10-24 09:58:16 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
clsMap->count = 1;
|
|
|
|
|
objMap->count = 1;
|
|
|
|
|
ptrMap->count = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[objDict removeAllObjects];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) deserializeHeaderAt: (unsigned*)pos
|
|
|
|
|
version: (unsigned*)v
|
|
|
|
|
classes: (unsigned*)c
|
|
|
|
|
objects: (unsigned*)o
|
|
|
|
|
pointers: (unsigned*)p
|
|
|
|
|
{
|
|
|
|
|
unsigned plen = strlen(PREFIX);
|
|
|
|
|
unsigned size = plen+36;
|
|
|
|
|
char header[size+1];
|
|
|
|
|
|
|
|
|
|
[data getBytes: header range: NSMakeRange(*pos, size)];
|
|
|
|
|
*pos += size;
|
|
|
|
|
header[size] = '\0';
|
|
|
|
|
if (strncmp(header, PREFIX, plen) != 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Archive has wrong prefix"];
|
|
|
|
|
}
|
|
|
|
|
if (sscanf(&header[plen], "%x:%x:%x:%x:", v, c, o, p) != 4)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInternalInconsistencyException
|
|
|
|
|
format: @"Archive has wrong prefix"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) directDataAccess
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|