1994-11-04 16:29:24 +00:00
|
|
|
|
/* Implementation of GNU Objective-C coder object for use serializing
|
1996-01-23 16:55:56 +00:00
|
|
|
|
Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
Written by: R. Andrew McCallum <mccallum@gnu.ai.mit.edu>
|
|
|
|
|
Date: July 1994
|
|
|
|
|
|
|
|
|
|
This file is part of the GNU Objective C Class 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
|
|
|
|
|
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <objects/stdobjects.h>
|
|
|
|
|
#include <objects/Coder.h>
|
|
|
|
|
#include <objects/MemoryStream.h>
|
|
|
|
|
#include <objects/Coding.h>
|
|
|
|
|
#include <objects/Dictionary.h>
|
|
|
|
|
#include <objects/Stack.h>
|
1995-09-08 22:49:50 +00:00
|
|
|
|
#include <objects/Set.h>
|
1996-01-23 22:51:58 +00:00
|
|
|
|
#include <objects/NSString.h>
|
|
|
|
|
#include <objects/Streaming.h>
|
|
|
|
|
#include <objects/Stream.h>
|
|
|
|
|
#include <objects/CStreaming.h>
|
|
|
|
|
#include <objects/CStream.h>
|
|
|
|
|
#include <objects/TextCStream.h>
|
1996-01-26 20:17:19 +00:00
|
|
|
|
#include <objects/BinaryCStream.h>
|
1996-01-23 22:51:58 +00:00
|
|
|
|
#include <objects/StdioStream.h>
|
|
|
|
|
#include <Foundation/NSException.h>
|
1996-01-26 03:06:35 +00:00
|
|
|
|
#include <Foundation/NSGeometry.h>
|
|
|
|
|
#include <Foundation/NSData.h>
|
1996-01-26 20:02:33 +00:00
|
|
|
|
#include <Foundation/NSArchiver.h>
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
|
|
|
|
/* Exception strings */
|
|
|
|
|
id CoderSignatureMalformedException = @"CoderSignatureMalformedException";
|
|
|
|
|
|
|
|
|
|
#define DEFAULT_FORMAT_VERSION 0
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
|
|
|
|
enum {CODER_OBJECT_NIL = 0, CODER_OBJECT, CODER_ROOT_OBJECT,
|
|
|
|
|
CODER_REPEATED_OBJECT, CODER_CLASS_OBJECT,
|
|
|
|
|
CODER_OBJECT_FORWARD_REFERENCE,
|
|
|
|
|
CODER_CLASS_NIL, CODER_CLASS, CODER_REPEATED_CLASS,
|
|
|
|
|
CODER_CONST_PTR_NULL, CODER_CONST_PTR, CODER_REPEATED_CONST_PTR};
|
|
|
|
|
|
|
|
|
|
#define ROUND(V, A) \
|
|
|
|
|
({ typeof(V) __v=(V); typeof(A) __a=(A); \
|
|
|
|
|
__a*((__v+__a-1)/__a); })
|
|
|
|
|
|
1996-01-23 16:55:56 +00:00
|
|
|
|
#define DOING_ROOT_OBJECT (interconnected_stack_height != 0)
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
static BOOL debug_coder = NO;
|
|
|
|
|
static id default_stream_class;
|
|
|
|
|
static id default_cstream_class;
|
|
|
|
|
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* xxx For experimentation. The function in objc-api.h doesn't always
|
|
|
|
|
work for objects; it sometimes returns YES for an instance. */
|
|
|
|
|
/* But, metaclasses return YES too? */
|
|
|
|
|
static BOOL
|
|
|
|
|
my_object_is_class(id object)
|
|
|
|
|
{
|
|
|
|
|
if (object != nil
|
|
|
|
|
#if NeXT_runtime
|
|
|
|
|
&& CLS_ISMETA(((Class)object)->isa)
|
|
|
|
|
&& ((Class)object)->isa != ((Class)object)->isa)
|
|
|
|
|
#else
|
1995-01-26 17:55:52 +00:00
|
|
|
|
&& CLS_ISMETA(((Class)object)->class_pointer)
|
|
|
|
|
&& ((Class)object)->class_pointer != ((Class)object)->class_pointer)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
#endif
|
|
|
|
|
return YES;
|
|
|
|
|
else
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-26 20:02:33 +00:00
|
|
|
|
@interface Coder (Private)
|
|
|
|
|
- (BOOL) _coderHasObjectReference: (unsigned)xref;
|
|
|
|
|
@end
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
@implementation Coder
|
|
|
|
|
|
1995-03-12 19:59:51 +00:00
|
|
|
|
+ (void) initialize
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
if (self == [Coder class])
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
default_stream_class = [MemoryStream class];
|
1996-01-26 20:17:19 +00:00
|
|
|
|
default_cstream_class = [BinaryCStream class];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
assert(sizeof(void*) == sizeof(unsigned));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ setDebugging: (BOOL)f
|
|
|
|
|
{
|
|
|
|
|
debug_coder = f;
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
|
|
|
|
/* Default Stream and CStream class handling. */
|
|
|
|
|
|
|
|
|
|
+ (void) setDefaultCStreamClass: sc
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
default_cstream_class = sc;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
+ defaultCStreamClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
return default_cstream_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
+ (void) setDefaultStreamClass: sc
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
default_stream_class = sc;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
+ defaultStreamClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
return default_stream_class;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
|
|
|
|
/* Signature Handling. */
|
|
|
|
|
|
|
|
|
|
+ (int) defaultFormatVersion
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
return DEFAULT_FORMAT_VERSION;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-24 14:03:19 +00:00
|
|
|
|
#define SIGNATURE_FORMAT_STRING \
|
|
|
|
|
@"GNU Objective C Class Library %s version %d\n"
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) writeSignature
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
/* Careful: the string should not contain newlines. */
|
1996-01-24 14:03:19 +00:00
|
|
|
|
[[cstream stream] writeFormat: SIGNATURE_FORMAT_STRING,
|
1996-01-24 03:12:36 +00:00
|
|
|
|
object_get_class_name(self),
|
|
|
|
|
format_version];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
+ (void) readSignatureFromCStream: (id <CStreaming>) cs
|
1996-01-24 14:03:19 +00:00
|
|
|
|
getClassname: (char *) name
|
1996-01-23 22:51:58 +00:00
|
|
|
|
formatVersion: (int*) version
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
int got;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-01-24 14:03:19 +00:00
|
|
|
|
got = [[cs stream] readFormat: SIGNATURE_FORMAT_STRING,
|
|
|
|
|
name, version];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
if (got != 2)
|
|
|
|
|
[NSException raise:CoderSignatureMalformedException
|
|
|
|
|
format:@"Coder found a malformed signature"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
|
|
|
|
/* Initialization. */
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
/* This is the designated initializer.
|
|
|
|
|
But, don't call it yourself.
|
1994-11-04 16:29:24 +00:00
|
|
|
|
Do override it and call [super...] in subclasses. */
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- _initWithCStream: (id <CStreaming>) cs
|
|
|
|
|
formatVersion: (int) version
|
|
|
|
|
isDecoding: (BOOL) f
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
is_decoding = f;
|
1996-01-23 22:51:58 +00:00
|
|
|
|
format_version = version;
|
|
|
|
|
cstream = [cs retain];
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
object_table = nil;
|
1996-01-23 22:51:58 +00:00
|
|
|
|
classname_map = [[Dictionary alloc] initWithType:@encode(char*)
|
|
|
|
|
keyType:@encode(char*)];
|
1995-09-11 00:36:35 +00:00
|
|
|
|
in_progress_table = [[Array alloc] initWithType:@encode(unsigned)];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
const_ptr_table = [[Dictionary alloc] initWithType:@encode(void*)
|
1995-09-08 22:44:23 +00:00
|
|
|
|
keyType:@encode(unsigned)];
|
1995-10-14 18:19:32 +00:00
|
|
|
|
root_object_table = nil;
|
|
|
|
|
forward_object_table = nil;
|
1995-09-11 00:36:35 +00:00
|
|
|
|
interconnected_stack_height = 0;
|
1996-01-26 03:06:35 +00:00
|
|
|
|
zone = NSDefaultMallocZone();
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
/* This is the designated sub-initializer for all "writing" coders. */
|
|
|
|
|
- initForWritingToStream: (id <Streaming>) s
|
|
|
|
|
withFormatVersion: (int) version
|
|
|
|
|
cStreamClass: (Class) cStreamClass
|
|
|
|
|
cStreamFormatVersion: (int) cStreamFormatVersion
|
|
|
|
|
{
|
|
|
|
|
[self _initWithCStream: [[cStreamClass alloc]
|
|
|
|
|
initForWritingToStream: s
|
|
|
|
|
withFormatVersion: cStreamFormatVersion]
|
|
|
|
|
formatVersion: version
|
|
|
|
|
isDecoding: NO];
|
|
|
|
|
[self writeSignature];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This is the designated sub-initializer for all "reading" coders. */
|
1996-01-23 22:51:58 +00:00
|
|
|
|
+ coderReadingFromStream: (id <Streaming>) stream
|
|
|
|
|
{
|
|
|
|
|
id cs = [CStream cStreamReadingFromStream: stream];
|
1996-01-24 14:03:19 +00:00
|
|
|
|
char name[128]; /* Max classname length. */
|
1996-01-23 22:51:58 +00:00
|
|
|
|
int version;
|
|
|
|
|
id new_coder;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self readSignatureFromCStream: cs
|
1996-01-24 14:03:19 +00:00
|
|
|
|
getClassname: name
|
1996-01-23 22:51:58 +00:00
|
|
|
|
formatVersion: &version];
|
|
|
|
|
|
|
|
|
|
new_coder = [[objc_lookup_class(name) alloc]
|
|
|
|
|
_initWithCStream: cs
|
|
|
|
|
formatVersion: version
|
|
|
|
|
isDecoding: YES];
|
|
|
|
|
return [new_coder autorelease];
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
/* ..Writing... methods */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
- initForWritingToStream: (id <Streaming>) s
|
|
|
|
|
withCStreamClass: (Class) cStreamClass
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-25 16:58:36 +00:00
|
|
|
|
return [self initForWritingToStream: s
|
|
|
|
|
withFormatVersion: DEFAULT_FORMAT_VERSION
|
|
|
|
|
cStreamClass: cStreamClass
|
|
|
|
|
cStreamFormatVersion: [cStreamClass defaultFormatVersion]];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
- initForWritingToStream: (id <Streaming>) s
|
1996-01-24 03:12:36 +00:00
|
|
|
|
{
|
1996-01-25 16:58:36 +00:00
|
|
|
|
return [self initForWritingToStream: s
|
|
|
|
|
withCStreamClass: [[self class] defaultCStreamClass]];
|
1996-01-24 03:12:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
- initForWritingToFile: (id <String>) filename
|
|
|
|
|
withFormatVersion: (int) version
|
|
|
|
|
cStreamClass: (Class) cStreamClass
|
|
|
|
|
cStreamFormatVersion: (int) cStreamFormatVersion
|
1996-01-25 15:27:30 +00:00
|
|
|
|
{
|
1996-01-25 16:58:36 +00:00
|
|
|
|
return [self initForWritingToStream: [StdioStream
|
|
|
|
|
streamWithFilename: filename
|
|
|
|
|
fmode: "w"]
|
|
|
|
|
withFormatVersion: version
|
|
|
|
|
cStreamClass: cStreamClass
|
|
|
|
|
cStreamFormatVersion: cStreamFormatVersion];
|
1996-01-25 15:27:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
- initForWritingToFile: (id <String>) filename
|
|
|
|
|
withCStreamClass: (Class) cStreamClass
|
1996-01-24 03:12:36 +00:00
|
|
|
|
{
|
1996-01-25 16:58:36 +00:00
|
|
|
|
return [self initForWritingToStream: [StdioStream
|
|
|
|
|
streamWithFilename: filename
|
|
|
|
|
fmode: "w"]
|
|
|
|
|
withCStreamClass: cStreamClass];
|
1996-01-24 03:12:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 15:27:30 +00:00
|
|
|
|
- initForWritingToFile: (id <String>) filename
|
|
|
|
|
{
|
|
|
|
|
return [self initForWritingToStream:
|
|
|
|
|
[StdioStream streamWithFilename: filename
|
|
|
|
|
fmode: "w"]];
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-24 03:12:36 +00:00
|
|
|
|
+ coderWritingToStream: (id <Streaming>)s
|
|
|
|
|
{
|
|
|
|
|
return [[[self alloc] initForWritingToStream: s]
|
|
|
|
|
autorelease];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ coderWritingToFile: (id <String>)filename
|
|
|
|
|
{
|
|
|
|
|
return [self coderWritingToStream:
|
|
|
|
|
[StdioStream streamWithFilename: filename
|
|
|
|
|
fmode: "w"]];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
+ (BOOL) encodeRootObject: anObject
|
|
|
|
|
withName: (id <String>) name
|
|
|
|
|
toStream: (id <Streaming>)stream
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-25 16:58:36 +00:00
|
|
|
|
id c = [[Coder alloc] initForWritingToStream: stream];
|
|
|
|
|
[c encodeRootObject: anObject withName: name];
|
|
|
|
|
[c closeCoder];
|
|
|
|
|
[c release];
|
|
|
|
|
return YES;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
+ (BOOL) encodeRootObject: anObject
|
|
|
|
|
withName: (id <String>) name
|
|
|
|
|
toFile: (id <String>) filename
|
|
|
|
|
{
|
|
|
|
|
return [self encodeRootObject: anObject
|
|
|
|
|
withName: name
|
|
|
|
|
toStream: [StdioStream streamWithFilename: filename
|
|
|
|
|
fmode: "w"]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ..Reading... methods */
|
|
|
|
|
|
|
|
|
|
+ coderReadingFromFile: (id <String>) filename
|
|
|
|
|
{
|
|
|
|
|
return [self coderReadingFromStream:
|
|
|
|
|
[StdioStream streamWithFilename: filename
|
|
|
|
|
fmode: "r"]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ decodeObjectWithName: (id <String> *) name
|
|
|
|
|
fromStream: (id <Streaming>)stream;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
id c, o;
|
|
|
|
|
c = [self coderReadingFromStream:stream];
|
1996-01-25 16:58:36 +00:00
|
|
|
|
[c decodeObjectAt: &o withName: name];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
return [o autorelease];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
+ decodeObjectWithName: (id <String> *) name
|
|
|
|
|
fromFile: (id <String>) filename;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-25 16:58:36 +00:00
|
|
|
|
return [self decodeObjectWithName: name
|
|
|
|
|
fromStream:
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[StdioStream streamWithFilename:filename fmode: "r"]];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 16:58:36 +00:00
|
|
|
|
- init
|
|
|
|
|
{
|
|
|
|
|
/* Or should we provide some kind of default? */
|
|
|
|
|
[self shouldNotImplement:_cmd];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Functions and methods for keeping cross-references
|
|
|
|
|
so objects aren't written/read twice. */
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* These _coder... methods may be overriden by subclasses so that
|
|
|
|
|
cross-references can be kept differently.
|
|
|
|
|
|
|
|
|
|
For instance, ConnectedCoder keeps cross-references to const
|
|
|
|
|
pointers on a per-Connection basis instead of a per-Coder basis.
|
|
|
|
|
We avoid encoding/decoding the same classes and selectors over and
|
|
|
|
|
over again.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static inline id
|
|
|
|
|
new_object_table()
|
|
|
|
|
{
|
|
|
|
|
return [[Dictionary alloc] initWithType:@encode(void*)
|
|
|
|
|
keyType:@encode(unsigned)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) _coderHasObjectReference: (unsigned)xref
|
|
|
|
|
{
|
|
|
|
|
if (!object_table)
|
|
|
|
|
object_table = new_object_table();
|
|
|
|
|
return [object_table includesKey:xref];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- _coderObjectAtReference: (unsigned)xref;
|
|
|
|
|
{
|
|
|
|
|
if (!object_table)
|
|
|
|
|
object_table = new_object_table();
|
|
|
|
|
return [object_table elementAtKey:xref].id_u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _coderPutObject: anObj atReference: (unsigned)xref
|
|
|
|
|
{
|
|
|
|
|
if (!object_table)
|
|
|
|
|
object_table = new_object_table();
|
|
|
|
|
[object_table putElement:anObj atKey:xref];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Using the next three methods, subclasses can change the way that
|
|
|
|
|
const pointers (like SEL, Class, Atomic strings, etc) are
|
|
|
|
|
archived. */
|
|
|
|
|
|
|
|
|
|
/* Only use _coderHasConstPtrReference during encoding, not decoding.
|
|
|
|
|
Otherwise you'll confuse ConnectedCoder that distinguishes between
|
|
|
|
|
incoming and outgoing tables. xxx What am I talking about here?? */
|
|
|
|
|
|
|
|
|
|
- (BOOL) _coderHasConstPtrReference: (unsigned)xref
|
|
|
|
|
{
|
|
|
|
|
return [const_ptr_table includesKey:xref];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static elt
|
|
|
|
|
exc_return_null(arglist_t f)
|
|
|
|
|
{
|
|
|
|
|
return (void*)0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (const void*) _coderConstPtrAtReference: (unsigned)xref;
|
|
|
|
|
{
|
|
|
|
|
return [const_ptr_table elementAtKey:xref
|
|
|
|
|
ifAbsentCall:exc_return_null].void_ptr_u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _coderPutConstPtr: (const void*)p atReference: (unsigned)xref
|
|
|
|
|
{
|
|
|
|
|
assert(![const_ptr_table includesKey:xref]);
|
|
|
|
|
[const_ptr_table putElement:(void*)p atKey:xref];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Here are the methods for root objects */
|
|
|
|
|
|
|
|
|
|
- (void) _coderPushRootObjectTable
|
|
|
|
|
{
|
1995-10-14 18:19:32 +00:00
|
|
|
|
if (!root_object_table)
|
|
|
|
|
root_object_table = [[Dictionary alloc] initWithType:@encode(void*)
|
|
|
|
|
keyType:@encode(unsigned)];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _coderPopRootObjectTable
|
|
|
|
|
{
|
1995-10-14 18:19:32 +00:00
|
|
|
|
assert(root_object_table);
|
|
|
|
|
[root_object_table release];
|
|
|
|
|
root_object_table = nil;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- _coderTopRootObjectTable
|
|
|
|
|
{
|
1995-10-14 18:19:32 +00:00
|
|
|
|
assert(root_object_table);
|
|
|
|
|
return root_object_table;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Here are the methods for forward object references. */
|
|
|
|
|
|
|
|
|
|
- (void) _coderPushForwardObjectTable
|
|
|
|
|
{
|
1995-10-14 18:19:32 +00:00
|
|
|
|
if (!forward_object_table)
|
|
|
|
|
forward_object_table = [[Dictionary alloc] initWithType:@encode(void*)
|
|
|
|
|
keyType:@encode(unsigned)];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _coderPopForwardObjectTable
|
|
|
|
|
{
|
1995-10-14 18:19:32 +00:00
|
|
|
|
assert(forward_object_table);
|
|
|
|
|
[forward_object_table release];
|
|
|
|
|
forward_object_table = nil;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- _coderTopForwardObjectTable
|
|
|
|
|
{
|
1995-10-14 18:19:32 +00:00
|
|
|
|
assert(forward_object_table);
|
|
|
|
|
return forward_object_table;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (struct objc_list *) _coderForwardObjectsAtReference: (unsigned)xref
|
|
|
|
|
{
|
|
|
|
|
return (struct objc_list*)
|
1995-10-14 18:19:32 +00:00
|
|
|
|
[[self _coderTopForwardObjectTable] elementAtKey:xref
|
1994-11-04 16:29:24 +00:00
|
|
|
|
ifAbsentCall:exc_return_null].void_ptr_u;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) _coderPutForwardObjects: (struct objc_list *)head
|
|
|
|
|
atReference: (unsigned)xref
|
|
|
|
|
{
|
1995-10-14 18:19:32 +00:00
|
|
|
|
[[self _coderTopForwardObjectTable] putElement:head atKey:xref];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is the Coder's interface to the over-ridable
|
|
|
|
|
"_coderPutObject:atReference" method. Do not override it. It
|
|
|
|
|
handles the root_object_table. */
|
|
|
|
|
|
|
|
|
|
- (void) _internalCoderPutObject: anObj atReference: (unsigned)xref
|
|
|
|
|
{
|
1996-01-23 16:55:56 +00:00
|
|
|
|
if (DOING_ROOT_OBJECT)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
assert(![[self _coderTopRootObjectTable] includesKey:xref]);
|
|
|
|
|
[[self _coderTopRootObjectTable] putElement:anObj atKey:xref];
|
|
|
|
|
}
|
|
|
|
|
[self _coderPutObject:anObj atReference:xref];
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
|
|
|
|
/* Method for encoding things. */
|
|
|
|
|
|
|
|
|
|
- (void) decodeValueOfCType: (const char*)type
|
|
|
|
|
at: (void*)d
|
|
|
|
|
withName: (id <String> *)namePtr
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[cstream decodeValueOfCType:type
|
|
|
|
|
at:d
|
|
|
|
|
withName:namePtr];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeValueOfCType: (const char*)type
|
|
|
|
|
at: (const void*)d
|
|
|
|
|
withName: (id <String>)name
|
|
|
|
|
{
|
|
|
|
|
[cstream encodeValueOfCType:type
|
|
|
|
|
at:d
|
|
|
|
|
withName:name];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeBytes: (const char *)b
|
|
|
|
|
count: (unsigned)c
|
|
|
|
|
withName: (id <String>)name
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) decodeBytes: (char *)b
|
|
|
|
|
count: (unsigned*)c
|
|
|
|
|
withName: (id <String> *) name
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
- (void) encodeTag: (unsigned char)t
|
|
|
|
|
{
|
1996-01-26 20:02:33 +00:00
|
|
|
|
if ([cstream respondsToSelector: @selector(encodeTag:)])
|
|
|
|
|
[(id)cstream encodeTag:t];
|
|
|
|
|
else
|
|
|
|
|
[self encodeValueOfCType:@encode(unsigned char)
|
|
|
|
|
at:&t
|
|
|
|
|
withName:@"Coder tag"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned char) decodeTag
|
|
|
|
|
{
|
1996-01-26 20:02:33 +00:00
|
|
|
|
if ([cstream respondsToSelector: @selector(decodeTag)])
|
|
|
|
|
return [(id)cstream decodeTag];
|
|
|
|
|
{
|
|
|
|
|
unsigned char t;
|
|
|
|
|
[self decodeValueOfCType:@encode(unsigned char)
|
|
|
|
|
at:&t
|
|
|
|
|
withName:NULL];
|
|
|
|
|
return t;
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeClass: aClass
|
|
|
|
|
{
|
|
|
|
|
[self encodeIndent];
|
|
|
|
|
if (aClass == Nil)
|
|
|
|
|
{
|
|
|
|
|
[self encodeTag: CODER_CLASS_NIL];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned xref = PTR2LONG(aClass);
|
|
|
|
|
if ([self _coderHasConstPtrReference:xref])
|
|
|
|
|
{
|
|
|
|
|
[self encodeTag: CODER_REPEATED_CLASS];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Class cross-reference number"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char *class_name = class_get_class_name(aClass);
|
|
|
|
|
int class_version = class_get_version(aClass);
|
|
|
|
|
|
|
|
|
|
assert(class_name);
|
|
|
|
|
assert(*class_name);
|
1996-01-26 20:02:33 +00:00
|
|
|
|
/* Do classname substitution, ala encodeClassName:intoClassName */
|
|
|
|
|
if ([classname_map includesKey: class_name])
|
|
|
|
|
class_name = [classname_map elementAtKey: class_name].char_ptr_u;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self encodeTag: CODER_CLASS];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Class cross-reference number"];
|
|
|
|
|
[self encodeValueOfCType:@encode(char*)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&class_name
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Class name"];
|
|
|
|
|
[self encodeValueOfCType:@encode(int)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&class_version
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Class version"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self _coderPutConstPtr:aClass atReference:xref];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[self encodeUnindent];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- decodeClass
|
|
|
|
|
{
|
|
|
|
|
unsigned char tag;
|
|
|
|
|
char *class_name;
|
|
|
|
|
int class_version;
|
|
|
|
|
id ret = Nil;
|
|
|
|
|
|
|
|
|
|
[self decodeIndent];
|
|
|
|
|
tag = [self decodeTag];
|
|
|
|
|
switch (tag)
|
|
|
|
|
{
|
|
|
|
|
case CODER_CLASS_NIL:
|
|
|
|
|
break;
|
|
|
|
|
case CODER_CLASS:
|
|
|
|
|
{
|
|
|
|
|
unsigned xref;
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
|
|
|
|
withName:NULL];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(char*)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&class_name
|
|
|
|
|
withName:NULL];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(int)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&class_version
|
|
|
|
|
withName:NULL];
|
|
|
|
|
ret = objc_lookup_class(class_name);
|
|
|
|
|
if (ret == Nil)
|
|
|
|
|
[self error:"Couldn't find class `%s'", class_name];
|
|
|
|
|
if (class_get_version(ret) != class_version)
|
|
|
|
|
[self error:"Class version mismatch, executable %d != encoded %d",
|
|
|
|
|
class_get_version(ret), class_version];
|
|
|
|
|
if ([self _coderHasConstPtrReference:xref])
|
|
|
|
|
[self error:"two classes have the same cross-reference number"];
|
|
|
|
|
[self _coderPutConstPtr:ret atReference:xref];
|
|
|
|
|
if (debug_coder)
|
|
|
|
|
fprintf(stderr, "Coder decoding registered class xref %u\n", xref);
|
|
|
|
|
(*objc_free)(class_name);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODER_REPEATED_CLASS:
|
|
|
|
|
{
|
|
|
|
|
unsigned xref;
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
|
|
|
|
withName:NULL];
|
|
|
|
|
ret = (id) [self _coderConstPtrAtReference:xref];
|
|
|
|
|
if (!ret)
|
|
|
|
|
[self error:"repeated class cross-reference number %u not found",
|
|
|
|
|
xref];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
[self error:"unrecognized class tag = %d", (int)tag];
|
|
|
|
|
}
|
|
|
|
|
[self decodeUnindent];
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) encodeAtomicString: (const char*) sp
|
|
|
|
|
withName: (id <String>) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
/* xxx Add repeat-string-ptr checking here. */
|
|
|
|
|
[self notImplemented:_cmd];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:@encode(char*) at:&sp withName:name];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (const char *) decodeAtomicStringWithName: (id <String> *) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
char *s;
|
|
|
|
|
/* xxx Add repeat-string-ptr checking here */
|
|
|
|
|
[self notImplemented:_cmd];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(char*) at:&s withName:name];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define NO_SEL_TYPES "none"
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) encodeSelector: (SEL)sel withName: (id <String>) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self encodeName:name];
|
|
|
|
|
[self encodeIndent];
|
|
|
|
|
if (sel == 0)
|
|
|
|
|
{
|
|
|
|
|
[self encodeTag: CODER_CONST_PTR_NULL];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned xref = PTR2LONG(sel);
|
|
|
|
|
if ([self _coderHasConstPtrReference:xref])
|
|
|
|
|
{
|
|
|
|
|
[self encodeTag: CODER_REPEATED_CONST_PTR];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"SEL cross-reference number"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
const char *sel_name;
|
|
|
|
|
const char *sel_types;
|
|
|
|
|
|
|
|
|
|
[self encodeTag: CODER_CONST_PTR];
|
|
|
|
|
sel_name = sel_get_name(sel);
|
|
|
|
|
#if NeXT_runtime
|
|
|
|
|
sel_types = NO_SEL_TYPES;
|
|
|
|
|
#else
|
|
|
|
|
sel_types = sel_get_type(sel);
|
|
|
|
|
#endif
|
1995-03-23 03:20:04 +00:00
|
|
|
|
#if 1 /* xxx Yipes,... careful... */
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* xxx Think about something like this. */
|
|
|
|
|
if (!sel_types)
|
|
|
|
|
sel_types = sel_get_type(sel_get_any_uid(sel_get_name(sel)));
|
|
|
|
|
#endif
|
|
|
|
|
if (!sel_name) [self error:"ObjC runtime didn't provide SEL name"];
|
|
|
|
|
if (!*sel_name) [self error:"ObjC runtime didn't provide SEL name"];
|
|
|
|
|
if (!sel_types) [self error:"ObjC runtime didn't provide SEL type"];
|
|
|
|
|
if (!*sel_types) [self error:"ObjC runtime didn't provide SEL type"];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"SEL cross-reference number"];
|
|
|
|
|
[self encodeValueOfCType:@encode(char*)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&sel_name
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"SEL name"];
|
|
|
|
|
[self encodeValueOfCType:@encode(char*)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&sel_types
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"SEL types"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self _coderPutConstPtr:sel atReference:xref];
|
|
|
|
|
if (debug_coder)
|
|
|
|
|
fprintf(stderr, "Coder encoding registered sel xref %u\n", xref);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[self encodeUnindent];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (SEL) decodeSelectorWithName: (id <String> *) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
char tag;
|
|
|
|
|
SEL ret = NULL;
|
|
|
|
|
|
|
|
|
|
[self decodeName:name];
|
|
|
|
|
[self decodeIndent];
|
|
|
|
|
tag = [self decodeTag];
|
|
|
|
|
switch (tag)
|
|
|
|
|
{
|
|
|
|
|
case CODER_CONST_PTR_NULL:
|
|
|
|
|
break;
|
|
|
|
|
case CODER_CONST_PTR:
|
|
|
|
|
{
|
|
|
|
|
unsigned xref;
|
|
|
|
|
char *sel_name;
|
|
|
|
|
char *sel_types;
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
|
|
|
|
withName:NULL];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(char *)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&sel_name
|
|
|
|
|
withName:NULL];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(char *)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&sel_types
|
|
|
|
|
withName:NULL];
|
|
|
|
|
#if NeXT_runtime
|
|
|
|
|
ret = sel_getUid(sel_name);
|
|
|
|
|
#else
|
|
|
|
|
if (!strcmp(sel_types, NO_SEL_TYPES))
|
|
|
|
|
ret = sel_get_any_uid(sel_name);
|
|
|
|
|
else
|
|
|
|
|
ret = sel_get_typed_uid(sel_name, sel_types);
|
|
|
|
|
#endif
|
|
|
|
|
if (!ret)
|
|
|
|
|
[self error:"Could not find selector (%s) with types [%s]",
|
|
|
|
|
sel_name, sel_types];
|
|
|
|
|
#if ! NeXT_runtime
|
|
|
|
|
if (strcmp(sel_types, NO_SEL_TYPES)
|
|
|
|
|
&& !(sel_types_match(sel_types, ret->sel_types)))
|
|
|
|
|
[self error:"ObjC runtime didn't provide SEL with matching type"];
|
|
|
|
|
#endif
|
|
|
|
|
[self _coderPutConstPtr:ret atReference:xref];
|
|
|
|
|
if (debug_coder)
|
|
|
|
|
fprintf(stderr, "Coder decoding registered sel xref %u\n", xref);
|
|
|
|
|
(*objc_free)(sel_name);
|
|
|
|
|
(*objc_free)(sel_types);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODER_REPEATED_CONST_PTR:
|
|
|
|
|
{
|
|
|
|
|
unsigned xref;
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
|
|
|
|
withName:NULL];
|
|
|
|
|
ret = (SEL)[self _coderConstPtrAtReference:xref];
|
|
|
|
|
if (!ret)
|
|
|
|
|
[self error:"repeated selector cross-reference number %u not found",
|
|
|
|
|
xref];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
[self error:"unrecognized selector tag = %d", (int)tag];
|
|
|
|
|
}
|
|
|
|
|
[self decodeUnindent];
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) encodeValueOfObjCType: (const char*) type
|
|
|
|
|
at: (const void*) d
|
|
|
|
|
withName: (id <String>) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_CLASS:
|
|
|
|
|
[self encodeName:name];
|
|
|
|
|
[self encodeClass: *(id*)d];
|
|
|
|
|
break;
|
|
|
|
|
case _C_ATOM:
|
|
|
|
|
[self encodeAtomicString:*(char**)d withName:name];
|
|
|
|
|
break;
|
|
|
|
|
case _C_SEL:
|
|
|
|
|
{
|
|
|
|
|
[self encodeSelector:*(SEL*)d withName:name];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case _C_ID:
|
|
|
|
|
[self encodeObject:*(id*)d withName:name];
|
|
|
|
|
break;
|
|
|
|
|
default:
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:type at:d withName:name];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) decodeValueOfObjCType: (const char*)type
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at: (void*)d
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String> *)namePtr
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
switch (*type)
|
|
|
|
|
{
|
|
|
|
|
case _C_CLASS:
|
|
|
|
|
{
|
|
|
|
|
[self decodeName:namePtr];
|
|
|
|
|
*(id*)d = [self decodeClass];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case _C_ATOM:
|
|
|
|
|
*(const char**)d = [self decodeAtomicStringWithName:namePtr];
|
|
|
|
|
break;
|
|
|
|
|
case _C_SEL:
|
|
|
|
|
*(SEL*)d = [self decodeSelectorWithName:namePtr];
|
|
|
|
|
break;
|
|
|
|
|
case _C_ID:
|
|
|
|
|
[self decodeObjectAt:d withName:namePtr];
|
|
|
|
|
break;
|
|
|
|
|
default:
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:type at:d withName:namePtr];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
/* xxx We need to catch unions and make a sensible error message */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
- (void) startEncodingInterconnectedObjects
|
|
|
|
|
{
|
1995-09-11 00:36:35 +00:00
|
|
|
|
if (interconnected_stack_height++)
|
|
|
|
|
return;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self _coderPushRootObjectTable];
|
|
|
|
|
[self _coderPushForwardObjectTable];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) finishEncodingInterconnectedObjects
|
|
|
|
|
{
|
|
|
|
|
/* xxx Perhaps we should look at the forward references and
|
|
|
|
|
encode here any forward-referenced objects that haven't been
|
1996-01-23 16:55:56 +00:00
|
|
|
|
encoded yet. No---the current behavior implements NeXT's
|
|
|
|
|
-encodeConditionalObject: */
|
1995-09-11 00:36:35 +00:00
|
|
|
|
assert (interconnected_stack_height);
|
|
|
|
|
if (--interconnected_stack_height)
|
|
|
|
|
return;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self _coderPopRootObjectTable];
|
|
|
|
|
[self _coderPopForwardObjectTable];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) startDecodingInterconnectedObjects
|
|
|
|
|
{
|
1995-09-11 00:36:35 +00:00
|
|
|
|
if (interconnected_stack_height++)
|
|
|
|
|
return;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self _coderPushRootObjectTable];
|
|
|
|
|
[self _coderPushForwardObjectTable];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) finishDecodingInterconnectedObjects
|
|
|
|
|
{
|
|
|
|
|
SEL awake_sel = sel_get_any_uid("awakeAfterUsingCoder:");
|
|
|
|
|
|
1995-09-11 00:36:35 +00:00
|
|
|
|
assert (interconnected_stack_height);
|
|
|
|
|
if (--interconnected_stack_height)
|
|
|
|
|
return;
|
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* resolve object forward references */
|
1995-10-14 18:19:32 +00:00
|
|
|
|
if (forward_object_table)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
void set_obj_addrs_for_xref(elt key, elt content)
|
|
|
|
|
{
|
|
|
|
|
const struct objc_list *addr_list = content.void_ptr_u;
|
|
|
|
|
id object = [self _coderObjectAtReference:key.unsigned_int_u];
|
|
|
|
|
/* If reference isn't there, object will be nil, and all the
|
|
|
|
|
forward references to that object will be set to nil.
|
|
|
|
|
I suppose this is fine. */
|
|
|
|
|
while (addr_list)
|
|
|
|
|
{
|
|
|
|
|
*((id*)(addr_list->head)) = object;
|
|
|
|
|
addr_list = addr_list->tail;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[[self _coderTopForwardObjectTable]
|
|
|
|
|
withKeyElementsAndContentElementsCall:set_obj_addrs_for_xref];
|
|
|
|
|
[self _coderPopForwardObjectTable];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* call awake all the objects read */
|
|
|
|
|
if (awake_sel)
|
|
|
|
|
{
|
|
|
|
|
void ask_awake(elt e)
|
|
|
|
|
{
|
|
|
|
|
if (__objc_responds_to(e.id_u, awake_sel))
|
|
|
|
|
(*objc_msg_lookup(e.id_u,awake_sel))(e.id_u, awake_sel, self);
|
|
|
|
|
}
|
|
|
|
|
[[self _coderTopRootObjectTable] withElementsCall:ask_awake];
|
|
|
|
|
}
|
|
|
|
|
[self _coderPopRootObjectTable];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* NOTE: This *can* be called recursively */
|
|
|
|
|
- (void) encodeRootObject: anObj
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String>)name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeName:@"Root Object"];
|
1995-09-11 00:36:35 +00:00
|
|
|
|
[self encodeIndent];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self encodeTag:CODER_ROOT_OBJECT];
|
|
|
|
|
[self startEncodingInterconnectedObjects];
|
|
|
|
|
[self encodeObject:anObj withName:name];
|
|
|
|
|
[self finishEncodingInterconnectedObjects];
|
1995-09-11 00:36:35 +00:00
|
|
|
|
[self encodeUnindent];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) _decodeRootObjectAt: (id*)ret withName: (id <String> *) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self startDecodingInterconnectedObjects];
|
|
|
|
|
[self decodeObjectAt:ret withName:name];
|
|
|
|
|
[self finishDecodingInterconnectedObjects];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* These two methods are the designated coder methods called when
|
|
|
|
|
we've determined that the object has not already been
|
|
|
|
|
encoded---we're not simply going to encode a cross-reference number
|
|
|
|
|
to the object, we're actually going to encode an object (either a
|
|
|
|
|
proxy to the object or the object itself).
|
|
|
|
|
|
|
|
|
|
ConnectedCoder overrides _doEncodeObject: in order to implement
|
|
|
|
|
the encoding of proxies. */
|
|
|
|
|
|
|
|
|
|
- (void) _doEncodeBycopyObject: anObj
|
|
|
|
|
{
|
1996-01-26 20:02:33 +00:00
|
|
|
|
id encoded_object, encoded_class;
|
|
|
|
|
if ([[self class] isKindOf: [NSCoder class]]
|
|
|
|
|
&& ! [[self class] isKindOf: [NSArchiver class]])
|
|
|
|
|
/* Make sure we don't do this for the Coder class, because
|
|
|
|
|
by default Coder should behave like NSArchiver. */
|
|
|
|
|
{
|
|
|
|
|
encoded_object = [anObj replacementObjectForCoder: (NSCoder*)self];
|
|
|
|
|
encoded_class = [encoded_object classForCoder];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
encoded_object = [anObj replacementObjectForArchiver: (NSArchiver*)self];
|
|
|
|
|
encoded_class = [encoded_object classForArchiver];
|
|
|
|
|
}
|
|
|
|
|
[self encodeClass: encoded_class];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* xxx Make sure it responds to this selector! */
|
1996-01-26 20:02:33 +00:00
|
|
|
|
[encoded_object encodeWithCoder: (NSCoder*)self];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* This method overridden by ConnectedCoder */
|
|
|
|
|
- (void) _doEncodeObject: anObj
|
|
|
|
|
{
|
|
|
|
|
[self _doEncodeBycopyObject:anObj];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is the designated object encoder */
|
|
|
|
|
- (void) _encodeObject: anObj
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String>) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
isBycopy: (BOOL) bycopy_flag
|
|
|
|
|
isForwardReference: (BOOL) forward_ref_flag
|
|
|
|
|
{
|
|
|
|
|
[self encodeName:name];
|
|
|
|
|
[self encodeIndent];
|
|
|
|
|
if (!anObj)
|
|
|
|
|
{
|
|
|
|
|
[self encodeTag:CODER_OBJECT_NIL];
|
|
|
|
|
}
|
|
|
|
|
else if (my_object_is_class(anObj))
|
|
|
|
|
{
|
|
|
|
|
[self encodeTag:CODER_CLASS_OBJECT];
|
|
|
|
|
[self encodeClass:anObj];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unsigned xref = PTR2LONG(anObj);
|
|
|
|
|
if ([self _coderHasObjectReference:xref])
|
|
|
|
|
{
|
|
|
|
|
[self encodeTag:CODER_REPEATED_OBJECT];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Object cross-reference number"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
1995-09-08 22:44:23 +00:00
|
|
|
|
else if (forward_ref_flag
|
1995-09-08 22:49:50 +00:00
|
|
|
|
|| [in_progress_table includesElement:xref])
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self encodeTag:CODER_OBJECT_FORWARD_REFERENCE];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Object forward cross-reference number"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
1995-09-08 22:49:50 +00:00
|
|
|
|
[in_progress_table addElement:xref];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self encodeTag:CODER_OBJECT];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Object cross-reference number"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self encodeIndent];
|
|
|
|
|
if (bycopy_flag)
|
|
|
|
|
[self _doEncodeBycopyObject:anObj];
|
|
|
|
|
else
|
|
|
|
|
[self _doEncodeObject:anObj];
|
|
|
|
|
[self encodeUnindent];
|
1995-09-08 22:44:23 +00:00
|
|
|
|
[self _internalCoderPutObject:anObj atReference:xref];
|
1995-09-08 22:49:50 +00:00
|
|
|
|
[in_progress_table removeElement:xref];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
[self encodeUnindent];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeObject: anObj
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String>)name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self _encodeObject:anObj withName:name isBycopy:NO isForwardReference:NO];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1996-01-26 03:06:35 +00:00
|
|
|
|
- (void) encodeBycopyObject: anObj
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String>)name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self _encodeObject:anObj withName:name isBycopy:YES isForwardReference:NO];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeObjectReference: anObj
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String>)name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self _encodeObject:anObj withName:name isBycopy:NO isForwardReference:YES];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is the designated (and one-and-only) object decoder */
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) decodeObjectAt: (id*) anObjPtr withName: (id <String> *) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
unsigned char tag;
|
|
|
|
|
|
|
|
|
|
[self decodeName:name];
|
|
|
|
|
[self decodeIndent];
|
|
|
|
|
tag = [self decodeTag];
|
|
|
|
|
switch (tag)
|
|
|
|
|
{
|
|
|
|
|
case CODER_OBJECT_NIL:
|
|
|
|
|
*anObjPtr = nil;
|
|
|
|
|
break;
|
|
|
|
|
case CODER_CLASS_OBJECT:
|
|
|
|
|
*anObjPtr = [self decodeClass];
|
|
|
|
|
break;
|
|
|
|
|
case CODER_OBJECT:
|
|
|
|
|
{
|
|
|
|
|
unsigned xref;
|
1995-03-08 23:04:52 +00:00
|
|
|
|
Class object_class;
|
1995-04-09 01:32:33 +00:00
|
|
|
|
SEL new_sel = sel_get_any_uid("newWithCoder:");
|
|
|
|
|
Method* new_method;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
|
|
|
|
withName:NULL];
|
|
|
|
|
[self decodeIndent];
|
|
|
|
|
object_class = [self decodeClass];
|
1995-04-09 01:32:33 +00:00
|
|
|
|
/* xxx Should change the runtime.
|
|
|
|
|
class_get_class_method should take the class as its first
|
|
|
|
|
argument, not the metaclass! */
|
|
|
|
|
new_method = class_get_class_method(class_get_meta_class(object_class),
|
|
|
|
|
new_sel);
|
|
|
|
|
if (new_method)
|
|
|
|
|
*anObjPtr = (*(new_method->method_imp))(object_class, new_sel, self);
|
1994-11-04 16:29:24 +00:00
|
|
|
|
else
|
1995-04-08 18:44:45 +00:00
|
|
|
|
{
|
|
|
|
|
SEL init_sel = sel_get_any_uid("initWithCoder:");
|
1995-04-09 01:32:33 +00:00
|
|
|
|
Method *init_method =
|
|
|
|
|
class_get_instance_method(object_class, init_sel);
|
|
|
|
|
/*xxx Fix this NS_NOZONE. */
|
1996-01-26 03:06:35 +00:00
|
|
|
|
*anObjPtr = (id) NSAllocateObject (object_class, 0, zone);
|
1995-04-09 01:32:33 +00:00
|
|
|
|
if (init_method)
|
|
|
|
|
*anObjPtr =
|
|
|
|
|
(*(init_method->method_imp))(*anObjPtr, init_sel, self);
|
1995-04-08 18:44:45 +00:00
|
|
|
|
/* xxx else, error? */
|
|
|
|
|
}
|
1994-11-04 16:29:24 +00:00
|
|
|
|
/* Would get error here with Connection-wide object references
|
|
|
|
|
because addProxy gets called in +newRemote:connection: */
|
|
|
|
|
if ([self _coderHasObjectReference:xref])
|
|
|
|
|
[self error:"two objects have the same cross-reference number"];
|
|
|
|
|
if (debug_coder)
|
|
|
|
|
fprintf(stderr, "Coder decoding registered class xref %u\n", xref);
|
|
|
|
|
[self _internalCoderPutObject:*anObjPtr atReference:xref];
|
|
|
|
|
[self decodeUnindent];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODER_ROOT_OBJECT:
|
|
|
|
|
{
|
|
|
|
|
[self _decodeRootObjectAt:anObjPtr withName:name];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODER_REPEATED_OBJECT:
|
|
|
|
|
{
|
|
|
|
|
unsigned xref;
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
|
|
|
|
withName:NULL];
|
|
|
|
|
*anObjPtr = [self _coderObjectAtReference:xref];
|
|
|
|
|
if (!*anObjPtr)
|
|
|
|
|
[self error:"repeated object cross-reference number %u not found",
|
|
|
|
|
xref];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case CODER_OBJECT_FORWARD_REFERENCE:
|
|
|
|
|
{
|
|
|
|
|
unsigned xref;
|
|
|
|
|
struct objc_list* addr_list;
|
|
|
|
|
|
1996-01-23 16:55:56 +00:00
|
|
|
|
if (!DOING_ROOT_OBJECT)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[self error:"can't decode forward reference when not decoding "
|
|
|
|
|
"a root object"];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfCType:@encode(unsigned)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:&xref
|
|
|
|
|
withName:NULL];
|
|
|
|
|
addr_list = [self _coderForwardObjectsAtReference:xref];
|
|
|
|
|
[self _coderPutForwardObjects:list_cons(anObjPtr,addr_list)
|
|
|
|
|
atReference:xref];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
[self error:"unrecognized object tag = %d", (int)tag];
|
|
|
|
|
}
|
|
|
|
|
[self decodeUnindent];
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) encodeWithName: (id <String>)name
|
|
|
|
|
valuesOfObjCTypes: (const char *)types, ...
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
[self encodeName:name];
|
|
|
|
|
va_start(ap, types);
|
|
|
|
|
while (*types)
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfObjCType:types
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:va_arg(ap, void*)
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Encoded Types Component"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
types = objc_skip_typespec(types);
|
|
|
|
|
}
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) decodeWithName: (id <String> *)name
|
|
|
|
|
valuesOfObjCTypes: (const char *)types, ...
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
[self decodeName:name];
|
|
|
|
|
va_start(ap, types);
|
|
|
|
|
while (*types)
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfObjCType:types
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:va_arg(ap, void*)
|
|
|
|
|
withName:NULL];
|
|
|
|
|
types = objc_skip_typespec(types);
|
|
|
|
|
}
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) encodeValueOfObjCTypes: (const char *)types
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at: (const void *)d
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String>)name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self encodeName:name];
|
|
|
|
|
while (*types)
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfObjCType:types
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:d
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Encoded Types Component"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
types = objc_skip_typespec(types);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) decodeValueOfObjCTypes: (const char *)types
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at: (void *)d
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String> *)name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
[self decodeName:name];
|
|
|
|
|
while (*types)
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfObjCType:types
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:d
|
|
|
|
|
withName:NULL];
|
|
|
|
|
types = objc_skip_typespec(types);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) encodeArrayOfObjCType: (const char *)type
|
1994-11-04 16:29:24 +00:00
|
|
|
|
count: (unsigned)c
|
1996-01-26 03:06:35 +00:00
|
|
|
|
at: (const void *)d
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String>)name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int offset = objc_sizeof_type(type);
|
|
|
|
|
const char *where = d;
|
|
|
|
|
|
|
|
|
|
[self encodeName:name];
|
|
|
|
|
for (i = 0; i < c; i++)
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self encodeValueOfObjCType:type
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:where
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName:@"Encoded Array Component"];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
where += offset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) decodeArrayOfObjCType: (const char *)type
|
1995-09-11 00:36:35 +00:00
|
|
|
|
count: (unsigned)c
|
1996-01-26 03:06:35 +00:00
|
|
|
|
at: (void *)d
|
1996-01-23 22:51:58 +00:00
|
|
|
|
withName: (id <String> *) name
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int offset = objc_sizeof_type(type);
|
|
|
|
|
char *where = d;
|
|
|
|
|
|
|
|
|
|
[self decodeName:name];
|
1995-09-11 00:36:35 +00:00
|
|
|
|
for (i = 0; i < c; i++)
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self decodeValueOfObjCType:type
|
1994-11-04 16:29:24 +00:00
|
|
|
|
at:where
|
|
|
|
|
withName:NULL];
|
|
|
|
|
where += offset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-25 15:27:30 +00:00
|
|
|
|
/* We must separate the idea of "closing" a coder and "deallocating"
|
|
|
|
|
a coder because of delays in deallocation due to -autorelease. */
|
|
|
|
|
- (void) closeCoder
|
|
|
|
|
{
|
|
|
|
|
[[cstream stream] closeStream];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) isClosed
|
|
|
|
|
{
|
|
|
|
|
return [[cstream stream] isClosed];
|
|
|
|
|
}
|
|
|
|
|
|
1995-03-12 19:59:51 +00:00
|
|
|
|
- (void) dealloc
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
/* xxx No. [self _finishDecodeRootObject]; */
|
1995-03-12 19:59:51 +00:00
|
|
|
|
[const_ptr_table release];
|
1995-09-08 22:44:23 +00:00
|
|
|
|
[in_progress_table release];
|
1995-03-12 19:59:51 +00:00
|
|
|
|
[object_table release];
|
1995-10-14 18:19:32 +00:00
|
|
|
|
[forward_object_table release];
|
|
|
|
|
[root_object_table release];
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[cstream release];
|
1995-03-12 19:59:51 +00:00
|
|
|
|
[super dealloc];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeIndent
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[cstream encodeIndent];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeUnindent
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[cstream encodeUnindent];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) decodeIndent
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[cstream decodeIndent];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) decodeUnindent
|
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[cstream decodeUnindent];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) encodeName: (id <String>)n
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[cstream encodeName: n];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (void) decodeName: (id <String> *)n
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[cstream decodeName: n];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-26 03:06:35 +00:00
|
|
|
|
|
|
|
|
|
/* Substituting Classes */
|
|
|
|
|
|
1996-01-26 20:02:33 +00:00
|
|
|
|
- (id <String>) classNameEncodedForTrueClassName: (id <String>) trueName
|
1996-01-26 03:06:35 +00:00
|
|
|
|
{
|
1996-01-26 20:02:33 +00:00
|
|
|
|
assert ( ! [self isDecoding]);
|
|
|
|
|
return [NSString stringWithCString:
|
|
|
|
|
[classname_map elementAtKey:
|
|
|
|
|
[trueName cStringNoCopy]].char_ptr_u];
|
1996-01-26 03:06:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeClassName: (id <String>) trueName
|
|
|
|
|
intoClassName: (id <String>) inArchiveName
|
|
|
|
|
{
|
1996-01-26 20:02:33 +00:00
|
|
|
|
assert ( ! [self isDecoding]);
|
|
|
|
|
[classname_map putElement: [inArchiveName cStringNoCopy]
|
|
|
|
|
atKey: [trueName cStringNoCopy]];
|
1996-01-26 03:06:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (NSString*) classNameDecodedForArchiveClassName: (NSString*) inArchiveName
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void) decodeClassName: (NSString*) inArchiveName
|
|
|
|
|
asClassName:(NSString *)trueName
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Managing Zones */
|
|
|
|
|
|
|
|
|
|
- (NSZone*) objectZone
|
|
|
|
|
{
|
|
|
|
|
return zone;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) setObjectZone: (NSZone*)z
|
|
|
|
|
{
|
|
|
|
|
zone = z;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
|
|
|
|
/* Access to instance variables. */
|
|
|
|
|
|
1996-01-26 03:06:35 +00:00
|
|
|
|
- cStream
|
|
|
|
|
{
|
|
|
|
|
return cstream;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (int) formatVersion
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
|
|
|
|
return format_version;
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
- (BOOL) isDecoding
|
1994-11-04 16:29:24 +00:00
|
|
|
|
{
|
1996-01-23 22:51:58 +00:00
|
|
|
|
return is_decoding;
|
1994-11-04 16:29:24 +00:00
|
|
|
|
}
|
|
|
|
|
|
1996-01-23 22:51:58 +00:00
|
|
|
|
|
1994-11-04 16:29:24 +00:00
|
|
|
|
- (void) resetCoder
|
|
|
|
|
{
|
|
|
|
|
/* xxx Finish this */
|
1996-01-23 22:51:58 +00:00
|
|
|
|
[self notImplemented:_cmd];
|
1994-11-04 16:29:24 +00:00
|
|
|
|
[const_ptr_table empty];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
1996-01-26 20:02:33 +00:00
|
|
|
|
|
1996-01-26 03:06:35 +00:00
|
|
|
|
@implementation Coder (NSCoderCompatibility)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Encoding Data */
|
|
|
|
|
|
|
|
|
|
- (void) encodeValueOfObjCType: (const char*)type
|
|
|
|
|
at: (const void*)address;
|
|
|
|
|
{
|
|
|
|
|
[self encodeValueOfObjCType: type at: address withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeArrayOfObjCType: (const char*)type
|
|
|
|
|
count: (unsigned)count
|
|
|
|
|
at: (const void*)array
|
|
|
|
|
{
|
|
|
|
|
[self encodeArrayOfObjCType: type count: count at: array withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-26 20:02:33 +00:00
|
|
|
|
- (void) encodeObject: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
[self encodeObject: anObject withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
1996-01-26 03:06:35 +00:00
|
|
|
|
- (void) encodeBycopyObject: (id)anObject
|
|
|
|
|
{
|
|
|
|
|
[self encodeBycopyObject: anObject withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeConditionalObject: (id)anObject
|
|
|
|
|
{
|
1996-01-26 20:02:33 +00:00
|
|
|
|
/* Apparently, NeXT's implementation doesn't actually
|
|
|
|
|
handle *forward* references, (hence it's use of -decodeObject,
|
|
|
|
|
instead of decodeObjectAt:.)
|
|
|
|
|
So here, we only encode the object for real if the object has
|
|
|
|
|
already been written.
|
|
|
|
|
This means that if you encode a web of objects with the more
|
|
|
|
|
powerful GNU Coder, and then try to decode them with NSArchiver,
|
|
|
|
|
you could get corrupt data on the stack when Coder resolves its
|
|
|
|
|
forward references. I recommend just using the GNU Coder. */
|
|
|
|
|
#if 1
|
|
|
|
|
unsigned xref = PTR2LONG(anObject);
|
|
|
|
|
if ([self _coderHasObjectReference:xref])
|
|
|
|
|
[self encodeObject: anObject];
|
|
|
|
|
else
|
|
|
|
|
[self encodeObject: nil];
|
|
|
|
|
#else
|
1996-01-26 03:06:35 +00:00
|
|
|
|
[self encodeObjectReference: anObject withName: NULL];
|
1996-01-26 20:02:33 +00:00
|
|
|
|
#endif
|
1996-01-26 03:06:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeDataObject: (NSData*)data
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodePropertyList: (id)plist
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodePoint: (NSPoint)point
|
|
|
|
|
{
|
|
|
|
|
[self encodeValueOfObjCType:@encode(NSPoint)
|
|
|
|
|
at:&point
|
|
|
|
|
withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeRect: (NSRect)rect
|
|
|
|
|
{
|
|
|
|
|
[self encodeValueOfObjCType:@encode(NSRect) at:&rect withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeRootObject: (id)rootObject
|
|
|
|
|
{
|
|
|
|
|
[self encodeRootObject: rootObject withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeSize: (NSSize)size
|
|
|
|
|
{
|
|
|
|
|
[self encodeValueOfObjCType:@encode(NSSize) at:&size withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) encodeValuesOfObjCTypes: (const char*)types,...
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Decoding Data */
|
|
|
|
|
|
|
|
|
|
- (void) decodeValueOfObjCType: (const char*)type
|
|
|
|
|
at: (void*)address
|
|
|
|
|
{
|
|
|
|
|
[self decodeValueOfObjCType: type at: address withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) decodeArrayOfObjCType: (const char*)type
|
|
|
|
|
count: (unsigned)count
|
|
|
|
|
at: (void*)address
|
|
|
|
|
{
|
|
|
|
|
[self decodeArrayOfObjCType: type count: count at: address withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSData*) decodeDataObject
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) decodeObject
|
|
|
|
|
{
|
|
|
|
|
/* xxx This won't work for decoding forward references!!! */
|
|
|
|
|
id o;
|
|
|
|
|
[self decodeObjectAt: &o withName: NULL];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) decodePropertyList
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSPoint) decodePoint
|
|
|
|
|
{
|
|
|
|
|
NSPoint point;
|
|
|
|
|
[self decodeValueOfObjCType:@encode(NSPoint)
|
|
|
|
|
at:&point
|
|
|
|
|
withName: NULL];
|
|
|
|
|
return point;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSRect) decodeRect
|
|
|
|
|
{
|
|
|
|
|
NSRect rect;
|
|
|
|
|
[self decodeValueOfObjCType:@encode(NSRect)
|
|
|
|
|
at:&rect
|
|
|
|
|
withName: NULL];
|
|
|
|
|
return rect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSSize) decodeSize
|
|
|
|
|
{
|
|
|
|
|
NSSize size;
|
|
|
|
|
[self decodeValueOfObjCType:@encode(NSSize)
|
|
|
|
|
at:&size
|
|
|
|
|
withName: NULL];
|
|
|
|
|
return size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) decodeValuesOfObjCTypes: (const char*)types,...
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Getting a Version */
|
|
|
|
|
|
|
|
|
|
- (unsigned int) systemVersion
|
|
|
|
|
{
|
|
|
|
|
return format_version; /* xxx Is this right? */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (unsigned int) versionForClassName: (NSString*)className
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end /* of (NSCoderCompatibility) */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@implementation Coder (NSArchiverCompatibility)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initializing an archiver */
|
|
|
|
|
|
|
|
|
|
@interface NSData (Streaming) <Streaming>
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
- (id) initForWritingWithMutableData: (NSMutableData*)mdata
|
|
|
|
|
{
|
|
|
|
|
/* This relies on the fact that GNU extentions to NSMutableData
|
|
|
|
|
cause it to conform to <Streaming>. */
|
|
|
|
|
[self initForWritingToStream: mdata];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Archiving Data */
|
|
|
|
|
|
|
|
|
|
+ (NSData*) archivedDataWithRootObject: (id)rootObject
|
|
|
|
|
{
|
|
|
|
|
id d = [[NSMutableData alloc] init];
|
|
|
|
|
id a = [[NSArchiver alloc] initForWritingWithMutableData:d];
|
|
|
|
|
[a encodeRootObject:rootObject];
|
|
|
|
|
return [d autorelease];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (BOOL) archiveRootObject: (id)rootObject toFile: (NSString*)path
|
|
|
|
|
{
|
|
|
|
|
/* xxx fix this return value */
|
|
|
|
|
id d = [self archivedDataWithRootObject:rootObject];
|
|
|
|
|
[d writeToFile:path atomically:NO];
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Getting data from the archiver */
|
|
|
|
|
|
|
|
|
|
+ unarchiveObjectWithData: (NSData*) data
|
|
|
|
|
{
|
|
|
|
|
return [self decodeObjectWithName: NULL fromStream: data];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ unarchiveObjectWithFile: (NSString*) path
|
|
|
|
|
{
|
|
|
|
|
return [self decodeObjectWithName: NULL fromFile: path];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSMutableData*) archiverData
|
|
|
|
|
{
|
|
|
|
|
[self notImplemented:_cmd];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|