From 65241c052d09c3043f515d95e97453e98569a6ce Mon Sep 17 00:00:00 2001 From: richard Date: Mon, 16 Oct 2000 12:35:42 +0000 Subject: [PATCH] Class cluster and encoding/decoding fixes. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@7825 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 28 +++++++++ Source/NSArray.m | 10 +++ Source/NSAttributedString.m | 115 ++++++++++++++++++++++++++++++++--- Source/NSCalendarDate.m | 2 +- Source/NSConcreteNumber.m | 24 ++++---- Source/NSData.m | 22 ------- Source/NSDate.m | 51 ++++++---------- Source/NSDictionary.m | 59 +++++++++++++++++- Source/NSGAttributedString.m | 71 +-------------------- Source/NSHost.m | 4 -- Source/NSNumber.m | 48 +++++++++++++-- Source/NSString.m | 20 ------ 12 files changed, 276 insertions(+), 178 deletions(-) diff --git a/ChangeLog b/ChangeLog index 68c16eeca..559a38c6e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2000-10-16 Richard Frith-Macdonald + + Attempts to make sure that when members of a class cluster are encoded + (either for archiving or for sending over DO), they are encoded as + the abstract class hiding the other classes in the cluster - this + should mean that (in future) changes in the private concrete classes + used should not effect existing archives and running DO applications. + * Source/NSDate.m: Implement -classForCoder to encode as the + abstract class. Implement ([-encodeWithCoder:]) and ([-initWithCoder:]) + in abstract class. + * Source/NSDictionary.m: Implement -classForCoder to encode as the + abstract class. Implement ([-encodeWithCoder:]) and ([-initWithCoder:]) + in abstract class. + * Source/NSArray.m: Implement -classForCoder to encode as the abstract + class. + * Source/NSAttributedString.m: Implement -classForCoder to encode as + the abstract class. Implement ([-encodeWithCoder:]) and + ([-initWithCoder:]) in abstract class. + * Source/NSGAttributedString.m: Remove coding/encoding stuff - now done + in abstract class. + * Source/NSNumber.m: Implement -classForCoder to encode numbers as the + abstract class. + Modified ([-encodeWithCoder:]) and ([-initWithCoder:]) to encode objc + type when encoding as abstract class. + * Source/NSConcreteNumber.m: Modified encoding method to mirror + abstract class method. Old ([-initWithCoder:]) method retained to + decode old format records from archives. + 2000-10-11 Adam Fedor * Source/NSObject.m (+initialize): Initialize Window sockets diff --git a/Source/NSArray.m b/Source/NSArray.m index 00b07b7c8..b3d517e4a 100644 --- a/Source/NSArray.m +++ b/Source/NSArray.m @@ -137,6 +137,11 @@ static SEL rlSel = @selector(removeLastObject); /* The NSCoding Protocol */ +- (Class) classForCoder +{ + return NSArray_abstract_class; +} + - (void) encodeWithCoder: (NSCoder*)aCoder { unsigned count = [self count]; @@ -802,6 +807,11 @@ static NSString *indentStrings[] = { } } +- (Class) classForCoder +{ + return NSMutableArray_abstract_class; +} + /* The NSCopying Protocol */ - (id) copyWithZone: (NSZone*)zone diff --git a/Source/NSAttributedString.m b/Source/NSAttributedString.m index 18c6acc0d..bea169651 100644 --- a/Source/NSAttributedString.m +++ b/Source/NSAttributedString.m @@ -117,20 +117,73 @@ static Class NSMutableAttributedString_concrete_class; return NSAllocateObject(self, 0, z); } +- (Class) classForCoder +{ + return NSAttributedString_abstract_class; +} + - (void) encodeWithCoder: (NSCoder*)aCoder { - [self subclassResponsibility: _cmd]; + NSRange r = NSMakeRange(0, 0); + unsigned index = NSMaxRange(r); + unsigned length = [self length]; + NSString *string = [self string]; + NSDictionary *attrs; + + [aCoder encodeObject: string]; + while (index < length) + { + attrs = [self attributesAtIndex: index effectiveRange: &r]; + index = NSMaxRange(r); + [aCoder encodeValueOfObjCType: @encode(unsigned int) at: &index]; + [aCoder encodeObject: attrs]; + } } - (id) initWithCoder: (NSCoder*)aDecoder { - [self subclassResponsibility: _cmd]; - return nil; -} + NSString *string = [aDecoder decodeObject]; + unsigned length = [string length]; -- (Class) classForPortCoder -{ - return [self class]; + if (length == 0) + { + self = [self initWithString: string attributes: nil]; + } + else + { + unsigned index; + NSDictionary *attrs; + + [aDecoder decodeValueOfObjCType: @encode(unsigned int) at: &index]; + attrs = [aDecoder decodeObject]; + if (index == length) + { + self = [self initWithString: string attributes: attrs]; + } + else + { + NSRange r = NSMakeRange(0, index); + unsigned last = index; + NSMutableAttributedString *m; + + m = [NSMutableAttributedString alloc]; + m = [m initWithString: string attributes: nil]; + [m setAttributes: attrs range: r]; + while (index < length); + { + [aDecoder decodeValueOfObjCType: @encode(unsigned int) + at: &index]; + attrs = [aDecoder decodeObject]; + r = NSMakeRange(last, index - last); + [m setAttributes: attrs range: r]; + last = index; + } + RELEASE(self); + self = [m copy]; + RELEASE(m); + } + } + return self; } - (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder @@ -473,7 +526,7 @@ static Class NSMutableAttributedString_concrete_class; @implementation NSMutableAttributedString -+ allocWithZone: (NSZone*)z ++ (id) allocWithZone: (NSZone*)z { if (self == NSMutableAttributedString_abstract_class) return NSAllocateObject(NSMutableAttributedString_concrete_class, 0, z); @@ -481,6 +534,52 @@ static Class NSMutableAttributedString_concrete_class; return NSAllocateObject(self, 0, z); } +- (Class) classForCoder +{ + return NSMutableAttributedString_abstract_class; +} + +- (id) initWithCoder: (NSCoder*)aDecoder +{ + NSString *string = [aDecoder decodeObject]; + unsigned length = [string length]; + + if (length == 0) + { + self = [self initWithString: string attributes: nil]; + } + else + { + unsigned index; + NSDictionary *attrs; + + [aDecoder decodeValueOfObjCType: @encode(unsigned int) at: &index]; + attrs = [aDecoder decodeObject]; + if (index == length) + { + self = [self initWithString: string attributes: attrs]; + } + else + { + NSRange r = NSMakeRange(0, index); + unsigned last = index; + + self = [self initWithString: string attributes: nil]; + [self setAttributes: attrs range: r]; + while (index < length); + { + [aDecoder decodeValueOfObjCType: @encode(unsigned int) + at: &index]; + attrs = [aDecoder decodeObject]; + r = NSMakeRange(last, index - last); + [self setAttributes: attrs range: r]; + last = index; + } + } + } + return self; +} + //Retrieving character information - (NSMutableString*) mutableString { diff --git a/Source/NSCalendarDate.m b/Source/NSCalendarDate.m index 70aa87c2e..9de6bcccc 100644 --- a/Source/NSCalendarDate.m +++ b/Source/NSCalendarDate.m @@ -175,7 +175,7 @@ GSTime(int day, int month, int year, int h, int m, int s) return newObj; } -- (Class) classForPortCoder +- (Class) classForCoder { return [self class]; } diff --git a/Source/NSConcreteNumber.m b/Source/NSConcreteNumber.m index 34815766a..6917c200f 100644 --- a/Source/NSConcreteNumber.m +++ b/Source/NSConcreteNumber.m @@ -439,23 +439,23 @@ } // NSCoding -- (Class) classForCoder -{ - return [self class]; -} - -- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder -{ - if ([aCoder isByref] == NO) - return self; - return [super replacementObjectForPortCoder: aCoder]; -} +/* + * Exact mirror of NSNumber abstract class coding method. + */ - (void) encodeWithCoder: (NSCoder*)coder { - [coder encodeValueOfObjCType: @encode(TYPE_TYPE) at: &data]; + const char *t = @encode(TYPE_TYPE); + + [coder encodeValueOfObjCType: @encode(char) at: t]; + [coder encodeValueOfObjCType: t at: &data]; } +/* + * NSNumber objects should have been encoded with their class set to the + * abstract class. If they haven't then we must be encoding from an old + * archive, so we must implement the old initWithCoder: method. + */ - (id) initWithCoder: (NSCoder*)coder { [coder decodeValueOfObjCType: @encode(TYPE_TYPE) at: &data]; diff --git a/Source/NSData.m b/Source/NSData.m index 9ae93295d..3a92265a2 100644 --- a/Source/NSData.m +++ b/Source/NSData.m @@ -1913,23 +1913,11 @@ failure: return self; } -/* NSCoding */ - -- (Class) classForArchiver -{ - return dataMalloc; /* Will not be static data when decoded. */ -} - - (Class) classForCoder { return dataMalloc; /* Will not be static data when decoded. */ } -- (Class) classForPortCoder -{ - return dataMalloc; /* Will not be static data when decoded. */ -} - /* Basic methods */ - (const void*) bytes @@ -2510,21 +2498,11 @@ getBytes(void* dst, void* src, unsigned len, unsigned limit, unsigned *pos) return (NSData*)NSAllocateObject(mutableDataMalloc, 0, z); } -- (Class) classForArchiver -{ - return mutableDataMalloc; -} - - (Class) classForCoder { return mutableDataMalloc; } -- (Class) classForPortCoder -{ - return mutableDataMalloc; -} - - (id) copy { return [[dataMalloc allocWithZone: NSDefaultMallocZone()] diff --git a/Source/NSDate.m b/Source/NSDate.m index fb9dc1974..b9fd6de32 100644 --- a/Source/NSDate.m +++ b/Source/NSDate.m @@ -870,15 +870,15 @@ GSTimeNow() return NSCopyObject(self, 0, zone); } -- (Class) classForPortCoder +- (Class) classForCoder { - /* Make sure that Connection's always send us bycopy, - i.e. as our own class, not a Proxy class. */ return abstractClass; } - (id) replacementObjectForPortCoder: (NSPortCoder*)aRmc { + /* Make sure that Connection's always send us bycopy, + i.e. as our own class, not a Proxy class. */ return self; } @@ -895,8 +895,20 @@ GSTimeNow() id o; [coder decodeValueOfObjCType: @encode(NSTimeInterval) at: &interval]; - o = [[concreteClass alloc] initWithTimeIntervalSinceReferenceDate: interval]; - [self release]; + if (interval == DISTANT_PAST) + { + o = RETAIN([abstractClass distantPast]); + } + else if (interval == DISTANT_FUTURE) + { + o = RETAIN([abstractClass distantFuture]); + } + else + { + o = [concreteClass allocWithZone: NSDefaultMallocZone()]; + o = [o initWithTimeIntervalSinceReferenceDate: interval]; + } + RELEASE(self); return o; } @@ -1116,16 +1128,6 @@ GSTimeNow() } } -- (Class) classForPortCoder -{ - return [self class]; -} - -- (id) replacementObjectForPortCoder: (NSPortCoder*)aRmc -{ - return self; -} - - (void) encodeWithCoder: (NSCoder*)coder { [coder encodeValueOfObjCType: @encode(NSTimeInterval) @@ -1259,25 +1261,6 @@ GSTimeNow() } } -- (Class) classForPortCoder -{ - return [self class]; -} - -- (id) replacementObjectForPortCoder: (NSPortCoder*)aRmc -{ - return self; -} - -- (void) encodeWithCoder: (NSCoder*)coder -{ -} - -- (id) initWithCoder: (NSCoder*)coder -{ - return self; -} - - (id) autorelease { return self; diff --git a/Source/NSDictionary.m b/Source/NSDictionary.m index ac8524772..7c1960177 100644 --- a/Source/NSDictionary.m +++ b/Source/NSDictionary.m @@ -33,6 +33,7 @@ #include #include #include +#include #include @interface NSDictionaryNonCore : NSDictionary @@ -126,15 +127,62 @@ static SEL appSel = @selector(appendString:); initWithDictionary: self]; } +- (Class) classForCoder +{ + return NSDictionary_abstract_class; +} + - (void) encodeWithCoder: (NSCoder*)aCoder { - [self subclassResponsibility: _cmd]; + unsigned count = [self count]; + + [aCoder encodeValueOfObjCType: @encode(unsigned) at: &count]; + if (count > 0) + { + NSEnumerator *enumerator = [self keyEnumerator]; + id key; + IMP enc; + IMP nxt; + IMP ofk; + + nxt = [enumerator methodForSelector: @selector(nextObject)]; + enc = [aCoder methodForSelector: @selector(encodeObject:)]; + ofk = [self methodForSelector: @selector(objectForKey:)]; + + while ((key = (*nxt)(enumerator, @selector(nextObject))) != nil) + { + id val = (*ofk)(self, @selector(objectForKey:), key); + + (*enc)(aCoder, @selector(encodeObject:), key); + (*enc)(aCoder, @selector(encodeObject:), val); + } + } } - (id) initWithCoder: (NSCoder*)aCoder { - [self subclassResponsibility: _cmd]; - return nil; + unsigned count; + + [aCoder decodeValueOfObjCType: @encode(unsigned) at: &count]; + if (count > 0) + { + id *keys = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*count); + id *vals = NSZoneMalloc(NSDefaultMallocZone(), sizeof(id)*count); + unsigned i; + IMP dec; + + dec = [aCoder methodForSelector: @selector(decodeObject)]; + for (i = 0; i < count; i++) + { + keys[i] = (*dec)(aCoder, @selector(decodeObject)); + vals[i] = (*dec)(aCoder, @selector(decodeObject)); + } + self = [self initWithObjects: vals forKeys: keys count: count]; + NSZoneFree(NSDefaultMallocZone(), keys); + NSZoneFree(NSDefaultMallocZone(), vals); + } + + return self; } @end @@ -898,6 +946,11 @@ static NSString *indentStrings[] = { return newDictionary; } +- (Class) classForCoder +{ + return NSMutableDictionary_abstract_class; +} + /* This is the designated initializer */ - (id) initWithCapacity: (unsigned)numItems { diff --git a/Source/NSGAttributedString.m b/Source/NSGAttributedString.m index 6ac9a29fe..670dc917c 100644 --- a/Source/NSGAttributedString.m +++ b/Source/NSGAttributedString.m @@ -33,7 +33,7 @@ /* Warning - [-initWithString:attributes:] is the designated initialiser, * but it doesn't provide any way to perform the function of the * [-initWithAttributedString:] initialiser. - * In order to work youd this, the string argument of the + * In order to work round this, the string argument of the * designated initialiser has been overloaded such that it * is expected to accept an NSAttributedString here instead of * a string. If you create an NSAttributedString subclass, you @@ -89,29 +89,6 @@ loc, attrs]; } -- (Class) classForPortCoder -{ - return [self class]; -} - -- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder -{ - return self; -} - -- (void) encodeWithCoder: (NSCoder*)aCoder -{ - [aCoder encodeValueOfObjCType: @encode(unsigned) at: &loc]; - [aCoder encodeValueOfObjCType: @encode(id) at: &attrs]; -} - -- (id) initWithCoder: (NSCoder*)aCoder -{ - [aCoder decodeValueOfObjCType: @encode(unsigned) at: &loc]; - [aCoder decodeValueOfObjCType: @encode(id) at: &attrs]; - return self; -} - @end @@ -289,29 +266,6 @@ _attributesAtIndexEffectiveRange( _setup(); } -- (Class) classForPortCoder -{ - return [self class]; -} - -- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder -{ - return self; -} - -- (void) encodeWithCoder: (NSCoder*)aCoder -{ - [aCoder encodeValueOfObjCType: @encode(id) at: &_textChars]; - [aCoder encodeValueOfObjCType: @encode(id) at: &_infoArray]; -} - -- (id) initWithCoder: (NSCoder*)aCoder -{ - [aCoder decodeValueOfObjCType: @encode(id) at: &_textChars]; - [aCoder decodeValueOfObjCType: @encode(id) at: &_infoArray]; - return self; -} - - (id) initWithString: (NSString*)aString attributes: (NSDictionary*)attributes { @@ -396,29 +350,6 @@ _attributesAtIndexEffectiveRange( _setup(); } -- (Class) classForPortCoder -{ - return [self class]; -} - -- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder -{ - return self; -} - -- (void) encodeWithCoder: (NSCoder*)aCoder -{ - [aCoder encodeValueOfObjCType: @encode(id) at: &_textChars]; - [aCoder encodeValueOfObjCType: @encode(id) at: &_infoArray]; -} - -- (id) initWithCoder: (NSCoder*)aCoder -{ - [aCoder decodeValueOfObjCType: @encode(id) at: &_textChars]; - [aCoder decodeValueOfObjCType: @encode(id) at: &_infoArray]; - return self; -} - - (id) initWithString: (NSString*)aString attributes: (NSDictionary*)attributes { diff --git a/Source/NSHost.m b/Source/NSHost.m index 45af9c178..40a2d86cd 100644 --- a/Source/NSHost.m +++ b/Source/NSHost.m @@ -358,10 +358,6 @@ static NSString *myHostName = nil; } /* Methods for encoding/decoding*/ -- (Class) classForPortCoder -{ - return [self class]; -} - (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder { diff --git a/Source/NSNumber.m b/Source/NSNumber.m index 70faba695..ef94815ae 100644 --- a/Source/NSNumber.m +++ b/Source/NSNumber.m @@ -2255,9 +2255,9 @@ static Class doubleNumberClass; * NSCoding */ -- (Class) classForPortCoder +- (Class) classForCoder { - return [self class]; + return abstractClass; } - (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder @@ -2269,12 +2269,52 @@ static Class doubleNumberClass; - (void) encodeWithCoder: (NSCoder*)coder { - [coder encodeValueOfObjCType: [self objCType] at: [self pointerValue]]; + const char *t = [self objCType]; + + [coder encodeValueOfObjCType: @encode(char) at: t]; + [coder encodeValueOfObjCType: t at: [self pointerValue]]; } - (id) initWithCoder: (NSCoder*)coder { - [coder decodeValueOfObjCType: [self objCType] at: [self pointerValue]]; + char t[2]; + union { + signed char c; + unsigned char C; + signed short s; + unsigned short S; + signed int i; + unsigned int I; + signed long l; + unsigned long L; + signed long long q; + unsigned long long Q; + float f; + double d; + } data; + + [coder decodeValueOfObjCType: @encode(char) at: t]; + t[1] = '\0'; + [coder decodeValueOfObjCType: t at: &data]; + switch (*t) + { + case 'c': self = [self initWithChar: data.c]; break; + case 'C': self = [self initWithUnsignedChar: data.C]; break; + case 's': self = [self initWithShort: data.s]; break; + case 'S': self = [self initWithUnsignedShort: data.S]; break; + case 'i': self = [self initWithInt: data.i]; break; + case 'I': self = [self initWithUnsignedInt: data.I]; break; + case 'l': self = [self initWithLong: data.l]; break; + case 'L': self = [self initWithUnsignedLong: data.L]; break; + case 'q': self = [self initWithLongLong: data.q]; break; + case 'Q': self = [self initWithUnsignedLongLong: data.Q]; break; + case 'f': self = [self initWithFloat: data.f]; break; + case 'd': self = [self initWithDouble: data.d]; break; + default: + [self dealloc]; + self = nil; + NSLog(@"Attempt to decode number with unknown ObjC type"); + } return self; } @end diff --git a/Source/NSString.m b/Source/NSString.m index f66a7b106..229f1bce4 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -2824,21 +2824,11 @@ handle_printf_atsign (FILE *stream, return self; } -- (Class) classForArchiver -{ - return NSString_class; -} - - (Class) classForCoder { return NSString_class; } -- (Class) classForPortCoder -{ - return NSString_class; -} - - (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder { if ([aCoder isByref] == NO) @@ -2999,21 +2989,11 @@ handle_printf_atsign (FILE *stream, RELEASE(tmp); } -- (Class) classForArchiver -{ - return NSMutableString_class; -} - - (Class) classForCoder { return NSMutableString_class; } -- (Class) classForPortCoder -{ - return NSMutableString_class; -} - - (void) deleteCharactersInRange: (NSRange)range { [self replaceCharactersInRange: range withString: nil];