mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 09:04:13 +00:00
([Decoder +readSignatureFromCStream:csgetClassname:
nameformatVersion:version]): Better commented. ([Decoder -_coderSubstituteObject:atReference:]): New method. ([Decoder -_coderPushRootObjectTable]): Better commented. ([Decoder -finishDecodingInterconnectedObjects]): Implement an approach to root-object-based -awakeAfterUsingCoder. ([Decoder -decodeObjectAt:anObjPtr:name]): Send -awakeAfterUsingCoder: here. First see if the object actually responds to it, then send it and make the object substitution if necessary. Also make the appropriate substitution in Decoder's internal tables matching references numbers to objects. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@1988 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
dd5068589e
commit
4b18ef1a32
1 changed files with 80 additions and 25 deletions
105
Source/Decoder.m
105
Source/Decoder.m
|
@ -1,5 +1,5 @@
|
|||
/* Abstract class for reading objects from a stream
|
||||
Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
Copyright (C) 1996, 1997 Free Software Foundation, Inc.
|
||||
|
||||
Written by: Andrew Kachites McCallum <mccallum@gnu.ai.mit.edu>
|
||||
Created: February 1996, with core from Coder, created 1994.
|
||||
|
@ -47,6 +47,7 @@ static int debug_coder = 0;
|
|||
int minor_version;
|
||||
int subminor_version;
|
||||
|
||||
/* SIGNATURE_FORMAT_STRING is defined in gnustep/base/CoderPrivate.h */
|
||||
got = [[cs stream] readFormat: SIGNATURE_FORMAT_STRING,
|
||||
&package_name,
|
||||
&major_version,
|
||||
|
@ -133,6 +134,11 @@ static int debug_coder = 0;
|
|||
return ([xref_2_object count] - 1);
|
||||
}
|
||||
|
||||
- (void) _coderSubstituteObject: anObj atReference: (unsigned)xref
|
||||
{
|
||||
[xref_2_object replaceObjectAtIndex: xref withObject: anObj];
|
||||
}
|
||||
|
||||
- _coderObjectAtReference: (unsigned)xref
|
||||
{
|
||||
assert (xref_2_object);
|
||||
|
@ -140,7 +146,10 @@ static int debug_coder = 0;
|
|||
}
|
||||
|
||||
|
||||
/* The methods for the root object table */
|
||||
/* The methods for the root object table. The *root* object table
|
||||
(XREF_2_OBJECT_ROOT) isn't really used for much right now, but it
|
||||
may be in the future. For now, most of the work is don't by
|
||||
XREF_2_OBJECT. */
|
||||
|
||||
- (void) _coderPushRootObjectTable
|
||||
{
|
||||
|
@ -291,6 +300,12 @@ static int debug_coder = 0;
|
|||
return xref;
|
||||
}
|
||||
|
||||
- (void) _coderInternalSubstituteObject: anObj atReference: (unsigned)xref
|
||||
{
|
||||
[self _coderSubstituteObject: anObj atReference: xref];
|
||||
/* xxx If we ever use the root object table, do something with it also. */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Method for decoding things. */
|
||||
|
@ -490,10 +505,6 @@ static int debug_coder = 0;
|
|||
|
||||
- (void) finishDecodingInterconnectedObjects
|
||||
{
|
||||
#if 0
|
||||
SEL awake_sel = sel_get_any_uid("awakeAfterUsingCoder:");
|
||||
#endif
|
||||
|
||||
assert (interconnect_stack_height);
|
||||
|
||||
/* xxx This might not be the right thing to do; perhaps we should do
|
||||
|
@ -507,25 +518,34 @@ static int debug_coder = 0;
|
|||
/* xxx fix the use of _coderPopForwardObjectTable and
|
||||
_coderPopRootObjectTable. */
|
||||
|
||||
#if 0
|
||||
/* Send "-awakeAfterUsingCoder:" to all the objects that were read */
|
||||
{
|
||||
SEL awake_sel = sel_get_any_uid("awakeAfterUsingCoder:");
|
||||
if (awake_sel)
|
||||
{
|
||||
int i;
|
||||
id table = [self _coderTopRootObjectTable];
|
||||
|
||||
/* Loop through all objects that we decoded by this Decoder */
|
||||
for (i = [table count]-1; i >= 0; i--)
|
||||
{
|
||||
id o = [table objectAtIndex: i];
|
||||
if (__objc_responds_to(o, awake_sel))
|
||||
{
|
||||
replacement_obj =
|
||||
(*objc_msg_lookup(e.id_u,awake_sel))(o, awake_sel, self);
|
||||
/* xxx Make the replacement in the decoder's object tables. */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* resolve object forward references */
|
||||
[self _coderResolveTopForwardReferences];
|
||||
[self _coderPopForwardObjectTable];
|
||||
|
||||
#if 0
|
||||
When should this be done?
|
||||
/* send "-awakeAfterUsingCoder:" to all the objects that were read */
|
||||
/* xxx But this doesn't currently handle the return of a different
|
||||
object than was messaged! */
|
||||
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];
|
||||
}
|
||||
#endif
|
||||
[self _coderPopRootObjectTable];
|
||||
}
|
||||
|
||||
|
@ -618,6 +638,8 @@ static int debug_coder = 0;
|
|||
SEL new_sel = sel_get_any_uid ("newWithCoder:");
|
||||
Method* new_method;
|
||||
BOOL create_ref_before_init = [self _createReferenceBeforeInit];
|
||||
/* Initialize this to <0 so we can tell below if it's been set */
|
||||
int xref = -1;
|
||||
|
||||
[self decodeIndent];
|
||||
object_class = [self decodeClass];
|
||||
|
@ -630,19 +652,52 @@ static int debug_coder = 0;
|
|||
*anObjPtr = (*(new_method->method_imp))(object_class, new_sel, self);
|
||||
else
|
||||
{
|
||||
SEL init_sel = sel_get_any_uid("initWithCoder:");
|
||||
SEL init_sel = sel_get_any_uid ("initWithCoder:");
|
||||
Method *init_method =
|
||||
class_get_instance_method(object_class, init_sel);
|
||||
class_get_instance_method (object_class, init_sel);
|
||||
/* xxx Or should I send +alloc? */
|
||||
*anObjPtr = (id) NSAllocateObject (object_class, 0, zone);
|
||||
if (create_ref_before_init)
|
||||
[self _coderInternalCreateReferenceForObject: *anObjPtr];
|
||||
xref = [self _coderInternalCreateReferenceForObject: *anObjPtr];
|
||||
if (init_method)
|
||||
*anObjPtr =
|
||||
(*(init_method->method_imp))(*anObjPtr, init_sel, self);
|
||||
/* xxx else what, error? */
|
||||
}
|
||||
/* xxx Should I sent -awakeUsingCoder: here instead of above? */
|
||||
|
||||
/* Send -awakeAfterUsingCoder: */
|
||||
/* xxx Unknown whether -awakeUsingCoder: should be sent here, or
|
||||
when Decoder is deallocated, or after a root object is finished
|
||||
decoding. */
|
||||
/* NOTE: Use of this with the NeXT archiving methods is
|
||||
tricky, because if [*anObj initWithCoder:] creates any
|
||||
objects that references *anObj, and if [*anObj
|
||||
awakeAfterUsingCoder:] replaces itself, then the
|
||||
subobject's references will not be to the replacement.
|
||||
There is no way to magically fix this circular dependancy;
|
||||
users must be aware. We should just make sure we require
|
||||
the same cautions as NeXT's implementation. Note that, with
|
||||
the GNU archiving methods, this problem doesn't occur because
|
||||
we don't register the object until after it has been fully
|
||||
initialized and awakened. */
|
||||
{
|
||||
SEL awake_sel = sel_get_any_uid ("awakeAfterUsingCoder:");
|
||||
IMP awake_imp = objc_msg_lookup (*anObjPtr, awake_sel);
|
||||
id replacement;
|
||||
|
||||
if (awake_imp)
|
||||
{
|
||||
replacement = (*awake_imp) (*anObjPtr, awake_sel, self);
|
||||
if (replacement != *anObjPtr)
|
||||
{
|
||||
if (xref > 0)
|
||||
[self _coderInternalSubstituteObject: replacement
|
||||
atReference: xref];
|
||||
*anObjPtr = replacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self decodeUnindent];
|
||||
|
||||
/* If this was a CODER_OBJECT_FORWARD_SATISFIER, then remember it. */
|
||||
|
|
Loading…
Reference in a new issue