Various fixes towards standardising runtime API and to cope with

unarchiving better where a class referred to in the archive does
not exist in the executing program.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@12625 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-Macdonald 2002-02-21 13:31:13 +00:00
parent 737d93b364
commit 59bdeabe4b
8 changed files with 324 additions and 110 deletions

View file

@ -2,10 +2,18 @@
* Source/NSValue.m: Fixed bug in archiving NSValue objects ... was
creating faulty archives which would crash on unarchiving.
If you have any archives created using the buggy code, try to
unarchive them by using the previous version of this file but
with the RELEASE() of the decoded NSData object removed. This
*might* permit archive recovery, though it will cause a memory leak.
* Headers/Foundation/NSObjCRuntime.h: Made GS... function names more
consistent with NeXT/Apple ones. Provide new ivar handling API.
Don't crash when asked for a class which does not exist.
* Source/NSObject.m: partial conversion to new runtime api.
* Source/NSData.m: partial conversion to new runtime api. Don't
raise an exception if a class we are deserializing does not exist.
Just warn and return a nul class.
* Source/NSArchiver.m: better clasname handling.
* Source/NSUnarchiver.m: try to gracefully handle the case where an
archive contains the name of a class we don't have linked in to our
code.
* Source/NSPortCoder.m: ditto.
2002-02-20 Richard Frith-Macdonald <rfm@gnu.org>

View file

@ -79,6 +79,15 @@ GS_EXPORT void NSLogv (NSString* format, va_list args);
* Get the type encoding for a named ivar,
* and copy a value into an ivar.
*/
GS_EXPORT BOOL GSFindInstanceVariable(id obj, const char *name,
const char **type, unsigned int *size, int *offset);
GS_EXPORT void GSGetVariable(id obj, int offset, unsigned int size, void *data);
GS_EXPORT void GSSetVariable(id obj, int offset, unsigned int size,
const void *data);
/*
* The following three functions are deprecated and will be removed in future
*/
GS_EXPORT BOOL GSInstanceVariableInfo(id obj, NSString *iVarName,
const char **type, unsigned *size, unsigned *offset);
GS_EXPORT BOOL GSGetInstanceVariable(id obj, NSString *name, void* data);
@ -124,24 +133,150 @@ GSObjCIsKindOf(Class this, Class other)
return NO;
}
/** <deprecated />
*/
FOUNDATION_STATIC_INLINE const char*
GSObjCName(Class this)
{
return class_get_class_name(this);
}
/** <deprecated />
*/
FOUNDATION_STATIC_INLINE const char*
GSObjCSelectorName(SEL this)
{
if (this == 0)
return 0;
return sel_get_name(this);
}
/** <deprecated />
*/
FOUNDATION_STATIC_INLINE const char*
GSObjCSelectorTypes(SEL this)
{
return sel_get_type(this);
}
/**
* Given a class name, return the corresponding class or
* a nul pointer if the class cannot be found. <br />
* If the argument is nil, return a nul pointer.
*/
FOUNDATION_STATIC_INLINE Class
GSClassFromName(const char *name)
{
if (name == 0)
return 0;
return objc_lookup_class(name);
}
/**
* Return the name of the supplied class, or a nul pointer if no class
* was supplied.
*/
FOUNDATION_STATIC_INLINE const char*
GSNameFromClass(Class this)
{
if (this == 0)
return 0;
return class_get_class_name(this);
}
/**
* Return the name of the supplied selector, or a nul pointer if no selector
* was supplied.
*/
FOUNDATION_STATIC_INLINE const char*
GSNameFromSelector(SEL this)
{
if (this == 0)
return 0;
return sel_get_name(this);
}
/**
* Return a selector matching the specified name, or nil if no name is
* supplied. The returned selector could be any one with the name.<br />
* If no selector already exists, creates one.
*/
FOUNDATION_STATIC_INLINE SEL
GSSelectorFromName(const char *name)
{
if (name == 0)
{
return 0;
}
else
{
SEL s = sel_get_any_uid(name);
if (s == 0)
{
s = sel_get_uid(name);
}
return s;
}
}
/**
* Return the selector for the specified name and types. Returns a nul
* pointer if the name is nul. Uses any available selector if the types
* argument is nul. Creates a new selector if necessary.
*/
FOUNDATION_STATIC_INLINE SEL
GSSelectorFromNameAndTypes(const char *name, const char *types)
{
if (name == 0)
{
return 0;
}
else
{
SEL s;
if (types == 0)
{
s = sel_get_any_typed_uid(name);
}
else
{
s = sel_get_typed_uid(name, types);
}
if (s == 0)
{
if (types == 0)
{
s = sel_register_name(name);
}
else
{
s = sel_register_typed_name(name, types);
}
}
return s;
}
}
/**
* Return the type information from the specified selector.
* May return a nul pointer if the selector was a nul pointer or if it
* was not typed.
*/
FOUNDATION_STATIC_INLINE const char*
GSTypesFromSelector(SEL this)
{
if (this == 0)
return 0;
return sel_get_type(this);
}
FOUNDATION_STATIC_INLINE Class
GSObjCSuper(Class this)
{

View file

@ -826,12 +826,12 @@ static Class NSMutableDataMallocClass;
GSIMapNode node;
Class c;
c = objc_get_class([trueName cString]);
c = GSClassFromName([trueName cString]);
node = GSIMapNodeForKey(_namMap, (GSIMapKey)c);
if (node)
{
c = (Class)node->value.ptr;
return [NSString stringWithCString: GSObjCName(c)];
return [NSString stringWithCString: GSNameFromClass(c)];
}
}
return trueName;
@ -844,13 +844,13 @@ static Class NSMutableDataMallocClass;
Class tc;
Class ic;
tc = objc_get_class([trueName cString]);
tc = GSClassFromName([trueName cString]);
if (tc == 0)
{
[NSException raise: NSInternalInconsistencyException
format: @"Can't find class '%@'.", trueName];
}
ic = objc_get_class([inArchiveName cString]);
ic = GSClassFromName([inArchiveName cString]);
if (ic == 0)
{
[NSException raise: NSInternalInconsistencyException

View file

@ -1145,11 +1145,12 @@ failure:
length: ni
atCursor: cursor];
name[ni] = '\0';
c = objc_get_class(name);
c = GSClassFromName(name);
if (c == 0)
{
[NSException raise: NSInternalInconsistencyException
format: @"can't find class - %s", name];
NSLog(@"[%s %s] can't find class - %s",
GSNameFromClass([self class]),
GSNameFromSelector(_cmd), name);
}
*(Class*)data = c;
}
@ -1783,7 +1784,7 @@ failure:
}
case _C_CLASS:
{
const char *name = *(Class*)data?GSObjCName(*(Class*)data):"";
const char *name = *(Class*)data?GSNameFromClass(*(Class*)data):"";
gsu16 ln = (gsu16)strlen(name);
gsu16 ni;
@ -1797,9 +1798,9 @@ failure:
}
case _C_SEL:
{
const char *name = *(SEL*)data?GSObjCSelectorName(*(SEL*)data):"";
const char *name = *(SEL*)data?GSNameFromSelector(*(SEL*)data):"";
gsu16 ln = (name == 0) ? 0 : (gsu16)strlen(name);
const char *types = *(SEL*)data?GSObjCSelectorTypes(*(SEL*)data):"";
const char *types = *(SEL*)data?GSTypesFromSelector(*(SEL*)data):"";
gsu16 lt = (types == 0) ? 0 : (gsu16)strlen(types);
gsu16 ni;
@ -2242,11 +2243,12 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
getBytes((void*)name, bytes, ni, length, cursor);
name[ni] = '\0';
c = objc_get_class(name);
c = GSClassFromName(name);
if (c == 0)
{
[NSException raise: NSInternalInconsistencyException
format: @"can't find class - %s", name];
NSLog(@"[%s %s] can't find class - %s",
GSNameFromClass([self class]),
GSNameFromSelector(_cmd), name);
}
*(Class*)data = c;
}
@ -2973,7 +2975,7 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
}
case _C_CLASS:
{
const char *name = *(Class*)data?GSObjCName(*(Class*)data):"";
const char *name = *(Class*)data?GSNameFromClass(*(Class*)data):"";
gsu16 ln = (gsu16)strlen(name);
gsu16 minimum = length + ln + sizeof(gsu16);
gsu16 ni;
@ -2994,9 +2996,9 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos)
}
case _C_SEL:
{
const char *name = *(SEL*)data?GSObjCSelectorName(*(SEL*)data):"";
const char *name = *(SEL*)data?GSNameFromSelector(*(SEL*)data):"";
gsu16 ln = (name == 0) ? 0 : (gsu16)strlen(name);
const char *types = *(SEL*)data?GSObjCSelectorTypes(*(SEL*)data):"";
const char *types = *(SEL*)data?GSTypesFromSelector(*(SEL*)data):"";
gsu16 lt = (types == 0) ? 0 : (gsu16)strlen(types);
gsu16 minimum = length + ln + lt + 2*sizeof(gsu16);
gsu16 ni;

View file

@ -36,7 +36,7 @@ NSString *
NSStringFromSelector(SEL aSelector)
{
if (aSelector != (SEL)0)
return [NSString stringWithCString: GSObjCSelectorName(aSelector)];
return [NSString stringWithCString: GSNameFromSelector(aSelector)];
return nil;
}
@ -44,7 +44,7 @@ SEL
NSSelectorFromString(NSString *aSelectorName)
{
if (aSelectorName != nil)
return sel_get_any_uid ([aSelectorName cString]);
return GSSelectorFromName ([aSelectorName lossyCString]);
return (SEL)0;
}
@ -52,7 +52,7 @@ Class
NSClassFromString(NSString *aClassName)
{
if (aClassName != nil)
return objc_lookup_class ([aClassName cString]);
return GSClassFromName ([aClassName lossyCString]);
return (Class)0;
}
@ -60,7 +60,7 @@ NSString *
NSStringFromClass(Class aClass)
{
if (aClass != (Class)0)
return [NSString stringWithCString: (char*)GSObjCName(aClass)];
return [NSString stringWithCString: (char*)GSNameFromClass(aClass)];
return nil;
}
@ -76,11 +76,17 @@ NSGetSizeAndAlignment(const char *typePtr, unsigned *sizep, unsigned *alignp)
return typePtr;
}
/**
* This function is used to locate information about the instance
* variable of obj called name. It returns YES if the variable
* was found, NO otherwise. If it returns YES, then the values
* pointed to by type, size, and offset will be set (except where
* they are nul pointers).
*/
BOOL
GSInstanceVariableInfo(id obj, NSString *iVarName,
const char **type, unsigned *size, unsigned *offset)
GSFindInstanceVariable(id obj, const char *name,
const char **type, unsigned int *size, int *offset)
{
const char *name = [iVarName cString];
Class class;
struct objc_ivar_list *ivars;
struct objc_ivar *ivar = 0;
@ -118,38 +124,71 @@ GSInstanceVariableInfo(id obj, NSString *iVarName,
return YES;
}
BOOL
GSGetInstanceVariable(id obj, NSString *name, void *data)
/**
* This function performs no checking ... you should use it only where
* you are providing information from a call to GSFindInstanceVariable()
* and you know that the data area provided is the correct size.
*/
void
GSGetVariable(id obj, int offset, unsigned int size, void *data)
{
int offset;
const char *type;
unsigned int size;
if (GSInstanceVariableInfo(obj, name, &type, &size, &offset) == NO)
{
return NO;
}
//This very highly unprobable value can be used as a marker
NSCAssert(offset != UINT_MAX, @"Bad Offset");
memcpy(data, ((void*)obj) + offset, size);
return YES;
}
BOOL
GSSetInstanceVariable(id obj, NSString *name, const void *data)
/**
* This function performs no checking ... you should use it only where
* you are providing information from a call to GSFindInstanceVariable()
* and you know that the data area provided is the correct size.
*/
void
GSSetVariable(id obj, int offset, unsigned int size, const void *data)
{
int offset;
const char *type;
unsigned int size;
if (GSInstanceVariableInfo(obj, name, &type, &size, &offset) == NO)
{
return NO;
}
//This very highly unprobable value can be used as a marker
NSCAssert(offset != UINT_MAX, @"Bad Offset");
memcpy(((void*)obj) + offset, data, size);
return YES;
}
/** <deprecated />
*/
BOOL
GSInstanceVariableInfo(id obj, NSString *iVarName,
const char **type, unsigned *size, unsigned *offset)
{
const char *name = [iVarName cString];
return GSFindInstanceVariable(obj, name, type, size, offset);
}
/** <deprecated />
*/
BOOL
GSGetInstanceVariable(id obj, NSString *iVarName, void *data)
{
const char *name = [iVarName cString];
int offset;
unsigned int size;
if (GSFindInstanceVariable(obj, name, 0, &size, &offset) == YES)
{
GSGetVariable(obj, offset, size, data);
return YES;
}
return NO;
}
/** <deprecated />
*/
BOOL
GSSetInstanceVariable(id obj, NSString *iVarName, const void *data)
{
const char *name = [iVarName cString];
int offset;
unsigned int size;
if (GSFindInstanceVariable(obj, name, 0, &size, &offset) == YES)
{
GSSetVariable(obj, offset, size, data);
return YES;
}
return NO;
}
/* Getting a system error message on a variety of systems */

View file

@ -395,7 +395,7 @@ NSAllocateObject(Class aClass, unsigned extraBytes, NSZone *zone)
{
new = NSZoneMalloc(zone, size);
NSLog(@"No garbage collection information for '%s'",
GSObjCName(aClass));
GSNameFromClass(aClass));
}
else if ([aClass requiresTypedMemory])
{
@ -1289,7 +1289,7 @@ static BOOL double_release_check_enabled = NO;
static id
GSGetValue(NSObject *self, NSString *key, SEL sel,
const char *type, unsigned size, unsigned off)
const char *type, unsigned size, int off)
{
if (sel != 0)
{
@ -1589,7 +1589,7 @@ GSGetValue(NSObject *self, NSString *key, SEL sel,
static void
GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
const char *type, unsigned size, unsigned off)
const char *type, unsigned size, int off)
{
if (sel != 0)
{
@ -1915,69 +1915,80 @@ GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
- (id) storedValueForKey: (NSString*)aKey
{
SEL sel = 0;
const char *type = NULL;
unsigned size;
unsigned off;
NSString *name;
NSString *cap;
if ([[self class] useStoredAccessor] == NO)
{
return [self valueForKey: aKey];
}
size = [aKey length];
size = [aKey cStringLength];
if (size < 1)
{
[NSException raise: NSInvalidArgumentException
format: @"storedValueForKey: ... empty key"];
return NO; // avoid compiler warnings.
}
cap = [[aKey substringToIndex: 1] uppercaseString];
if (size > 1)
else
{
cap = [cap stringByAppendingString: [aKey substringFromIndex: 1]];
}
SEL sel = 0;
const char *type = NULL;
unsigned off;
const char *name;
char buf[size+5];
char lo;
char hi;
name = [NSString stringWithFormat: @"_get%@", cap];
sel = NSSelectorFromString(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
{
name = [NSString stringWithFormat: @"_%@", aKey];
sel = NSSelectorFromString(name);
strcpy(buf, "_get");
[aKey getCString: &buf[4]];
lo = buf[4];
hi = islower(lo) ? toupper(lo) : lo;
buf[4] = hi;
name = buf; // _getKey
sel = sel_get_any_uid(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
{
sel = 0;
}
}
if (sel == 0)
{
if ([[self class] accessInstanceVariablesDirectly] == YES)
{
name = [NSString stringWithFormat: @"_%@", aKey];
if (GSInstanceVariableInfo(self, name, &type, &size, &off) == NO)
{
name = aKey;
GSInstanceVariableInfo(self, name, &type, &size, &off);
}
}
if (type == NULL)
{
name = [NSString stringWithFormat: @"get%@", cap];
sel = NSSelectorFromString(name);
buf[3] = '_';
buf[4] = lo;
name = &buf[3]; // _key
sel = sel_get_any_uid(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
{
name = aKey;
sel = NSSelectorFromString(name);
sel = 0;
}
}
if (sel == 0)
{
if ([[self class] accessInstanceVariablesDirectly] == YES)
{
// _key
if (GSFindInstanceVariable(self, name, &type, &size, &off) == NO)
{
name = &buf[4]; // key
GSFindInstanceVariable(self, name, &type, &size, &off);
}
}
if (type == NULL)
{
buf[3] = 't';
buf[4] = hi;
name = &buf[1]; // getKey
sel = sel_get_any_uid(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
{
sel = 0;
buf[4] = lo;
name = &buf[4]; // key
sel = sel_get_any_uid(name);
if (sel == 0 || [self respondsToSelector: sel] == NO)
{
sel = 0;
}
}
}
}
return GSGetValue(self, aKey, sel, type, size, off);
}
return GSGetValue(self, aKey, sel, type, size, off);
}
- (void) takeStoredValue: (id)anObject forKey: (NSString*)aKey
@ -1985,7 +1996,7 @@ GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
SEL sel;
const char *type;
unsigned size;
unsigned off;
int off;
NSString *cap;
NSString *name;
@ -2041,7 +2052,7 @@ GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
SEL sel;
const char *type;
unsigned size;
unsigned off;
int off;
NSString *cap;
NSString *name;
@ -2130,7 +2141,7 @@ GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
NSString *name = nil;
const char *type = NULL;
unsigned size;
unsigned off;
int off;
size = [aKey length];
if (size < 1)
@ -2337,7 +2348,7 @@ GSSetValue(NSObject *self, NSString *key, id val, SEL sel,
- (BOOL) isMemberOfClassNamed: (const char*)aClassName
{
return ((aClassName!=NULL)
&&!strcmp(GSObjCName(GSObjCClass(self)), aClassName));
&&!strcmp(GSNameFromClass(GSObjCClass(self)), aClassName));
}
+ (struct objc_method_description *) descriptionForInstanceMethod: (SEL)aSel

View file

@ -546,6 +546,12 @@ static IMP _xRefImp; /* Serialize a crossref. */
}
(*_dValImp)(self, dValSel, @encode(Class), &c);
if (c == 0)
{
NSLog(@"[%s %s] decoded nil class",
GSNameFromClass([self class]),
GSNameFromSelector(_cmd));
}
obj = [c allocWithZone: _zone];
GSIArrayAddItem(_objAry, (GSIArrayItem)obj);
@ -657,8 +663,8 @@ static IMP _xRefImp; /* Serialize a crossref. */
nil);
if (c == 0)
{
[NSException raise: NSInternalInconsistencyException
format: @"decoded nil class"];
NSLog(@"[%s %s] decoded nil class",
GSNameFromClass([self class]), GSNameFromSelector(_cmd));
}
classInfo = [GSClassInfo newWithClass: c andVersion: cver];
GSIArrayAddItem(_clsAry, (GSIArrayItem)classInfo);
@ -1860,7 +1866,10 @@ static IMP _xRefImp; /* Serialize a crossref. */
while (count-- > 0)
{
info = GSIArrayItemAtIndex(_clsAry, count).obj;
[_cInfo setObject: info forKey: NSStringFromClass(info->class)];
if (info->class != 0)
{
[_cInfo setObject: info forKey: NSStringFromClass(info->class)];
}
}
}
info = [_cInfo objectForKey: className];

View file

@ -292,7 +292,6 @@ mapClassName(NSUnarchiverObjectInfo *info)
@implementation NSUnarchiverObjectInfo
@end
@implementation NSUnarchiver
@class NSDataMalloc;
@ -543,6 +542,11 @@ static Class NSDataMallocClass;
}
(*dValImp)(self, dValSel, @encode(Class), &c);
if (c == 0)
{
[NSException raise: NSInternalInconsistencyException
format: @"decoded nil class"];
}
obj = [c allocWithZone: zone];
GSIArrayAddItem(objMap, (GSIArrayItem)obj);
@ -590,7 +594,8 @@ static Class NSDataMallocClass;
[NSException raise: NSInternalInconsistencyException
format: @"class crossref missing - %d", xref];
}
classInfo = (NSUnarchiverObjectInfo*)GSIArrayItemAtIndex(clsMap, xref).obj;
classInfo = (NSUnarchiverObjectInfo*)
GSIArrayItemAtIndex(clsMap, xref).obj;
*(Class*)address = mapClassObject(classInfo);
return;
}
@ -608,14 +613,19 @@ static Class NSDataMallocClass;
(*desImp)(src, desSel, &cver, @encode(unsigned), &cursor, nil);
if (c == 0)
{
[NSException raise: NSInternalInconsistencyException
format: @"decoded nil class"];
NSLog(@"[%s %s] decoded nil class",
GSNameFromClass([self class]), GSNameFromSelector(_cmd));
className = @"_NSUnarchiverUnknownClass";
}
else
{
className = NSStringFromClass(c);
}
className = NSStringFromClass(c);
classInfo = [objDict objectForKey: className];
if (classInfo == nil)
{
classInfo = [NSUnarchiverObjectInfo newWithName: className];
classInfo = [NSUnarchiverObjectInfo
newWithName: className];
[classInfo mapToClass: c withName: className];
[objDict setObject: classInfo forKey: className];
RELEASE(classInfo);
@ -1041,7 +1051,7 @@ static Class NSDataMallocClass;
{
Class c;
c = objc_get_class([trueName cString]);
c = GSClassFromName([trueName cString]);
if (c == 0)
{
[NSException raise: NSInvalidArgumentException
@ -1079,7 +1089,7 @@ static Class NSDataMallocClass;
{
Class c;
c = objc_get_class([trueName cString]);
c = GSClassFromName([trueName cString]);
if (c == 0)
{
[NSException raise: NSInvalidArgumentException