From 4386ba0c61e6460ec2abe9ac73601e85feacfbe3 Mon Sep 17 00:00:00 2001 From: richard Date: Fri, 20 Oct 2000 10:30:51 +0000 Subject: [PATCH] Various improvements and bugfixes git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@7856 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 9 + Headers/gnustep/base/NSString.h | 3 +- Source/GSString.m | 448 ++++++++++++++++++++++++-------- Source/NSCalendarDate.m | 54 ++-- Source/NSString.m | 44 +++- 5 files changed, 428 insertions(+), 130 deletions(-) diff --git a/ChangeLog b/ChangeLog index 559a38c6e..3d680dbef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2000-10-20 Richard Frith-Macdonald + + * Source/NSString.m: ([-initWithCharacters:length:]) use + ([-initWithCStringNoCopy:length:freeWhenDone:]) if possible. + * Source/GSString.m: Much tidying up. Added two new concrete + classes for substrings. + * Source/NSCalendarDate.m: ([-initWithString:calendarFormat:locale:]) + avoid any attempt to read beyond the supplied string. + 2000-10-16 Richard Frith-Macdonald Attempts to make sure that when members of a class cluster are encoded diff --git a/Headers/gnustep/base/NSString.h b/Headers/gnustep/base/NSString.h index 455b33ca3..bd731343d 100644 --- a/Headers/gnustep/base/NSString.h +++ b/Headers/gnustep/base/NSString.h @@ -345,7 +345,8 @@ enum { unsigned int wide: 1; // 16-bit characters in string? unsigned int ascii: 1; // String contains only ascii? unsigned int free: 1; // Should free memory? - unsigned int hash: 30; + unsigned int unused: 1; + unsigned int hash: 28; } _flags; } @end diff --git a/Source/GSString.m b/Source/GSString.m index 4ae60f2c0..fca336b1d 100644 --- a/Source/GSString.m +++ b/Source/GSString.m @@ -49,16 +49,48 @@ #include #include +/* + * GSCString - concrete class for strings using 8-bit character sets. + */ @interface GSCString : GSString { } @end +/* + * GSCSubString - concrete subclass of GSCString, that relys on the + * data stored in a GSCString object. + */ +@interface GSCSubString : GSCString +{ +@public + GSCString *_parent; +} +@end + +/* + * GSUString - concrete class for strings using 16-bit character sets. + */ @interface GSUString : GSString { } @end +/* + * GSUSubString - concrete subclass of GSUString, that relys on the + * data stored in a GSUString object. + */ +@interface GSUSubString : GSUString +{ +@public + GSUString *_parent; +} +@end + +/* + * GSMString - concrete mutable string, capable of changing its storage + * from holding 8-bit to 16-bit character set. + */ @interface GSMString : NSMutableString { union { @@ -70,7 +102,8 @@ unsigned int wide: 1; unsigned int ascii: 1; unsigned int free: 1; - unsigned int hash: 30; + unsigned int unused: 1; + unsigned int hash: 28; } _flags; NSZone *_zone; unsigned int _capacity; @@ -126,8 +159,11 @@ typedef struct { static Class NSDataClass = 0; static Class NSStringClass = 0; +static Class GSStringClass = 0; static Class GSCStringClass = 0; +static Class GSCSubStringClass = 0; static Class GSUStringClass = 0; +static Class GSUSubStringClass = 0; static Class GSMStringClass = 0; static Class NXConstantStringClass = 0; @@ -140,6 +176,10 @@ static unsigned (*hashImp)(id, SEL) = 0; static NSStringEncoding defEnc = 0; +/* + * The setup() function is called when any concrete string class is + * initialized, and cached classes and some method implementations. + */ static void setup() { @@ -151,8 +191,11 @@ setup() NSDataClass = [NSData class]; NSStringClass = [NSString class]; + GSStringClass = [GSString class]; GSCStringClass = [GSCString class]; GSUStringClass = [GSUString class]; + GSCSubStringClass = [GSCSubString class]; + GSUSubStringClass = [GSUSubString class]; GSMStringClass = [GSMString class]; NXConstantStringClass = [NXConstantString class]; @@ -168,6 +211,19 @@ setup() } +/* + * The following inline functions are used by the concrete string classes + * to implement their core functionality. + * GSCString uses the functions with the _c suffix. + * GSCSubString and NXConstant inherit methods from GSCString. + * GSUString uses the functions with the _u suffix. + * GSUSubString inherits methods from GSUString. + * GSMString uses all the functions, selecting the _c or _u versions + * depending on whether its storage is 8-bit or 16-bit. + * In addition, GSMString uses a few functions without a suffix that are + * peculiar to its memory management (shrinking, growing, and converting). + */ + static inline BOOL boolValue_c(ivars self) { @@ -230,14 +286,35 @@ canBeConvertedToEncoding_c(ivars self, NSStringEncoding enc) { if (enc == defEnc) return YES; + else if (self->_flags.ascii == 1) + return YES; else - return (*convertImp)((id)self, convertSel, enc); + { + BOOL result = (*convertImp)((id)self, convertSel, enc); + + if (enc == NSASCIIStringEncoding) + { + self->_flags.ascii = 1; + } + return result; + } } static inline BOOL canBeConvertedToEncoding_u(ivars self, NSStringEncoding enc) { - return (*convertImp)((id)self, convertSel, enc); + if (self->_flags.ascii == 1) + return YES; + else + { + BOOL result = (*convertImp)((id)self, convertSel, enc); + + if (enc == NSASCIIStringEncoding) + { + self->_flags.ascii = 1; + } + return result; + } } static inline unichar @@ -270,13 +347,16 @@ compare_c(ivars self, NSString *aString, unsigned mask, NSRange aRange) if (aString == nil) [NSException raise: NSInvalidArgumentException format: @"compare with nil"]; + if (fastIsInstance(aString) == NO) + return strCompCsNs((id)self, aString, mask, aRange); + c = fastClass(aString); - if (c == GSUStringClass + if (fastClassIsKindOfClass(c, GSUStringClass) == YES || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 1)) return strCompCsUs((id)self, aString, mask, aRange); - else if (c == GSCStringClass - || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 0) - || c == NXConstantStringClass) + else if (fastClassIsKindOfClass(c, GSCStringClass) == YES + || c == NXConstantStringClass + || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 0)) return strCompCsCs((id)self, aString, mask, aRange); else return strCompCsNs((id)self, aString, mask, aRange); @@ -289,13 +369,16 @@ compare_u(ivars self, NSString *aString, unsigned mask, NSRange aRange) if (aString == nil) [NSException raise: NSInvalidArgumentException format: @"compare with nil"]; + if (fastIsInstance(aString) == NO) + return strCompUsNs((id)self, aString, mask, aRange); + c = fastClass(aString); - if (c == GSUStringClass + if (fastClassIsKindOfClass(c, GSUStringClass) || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 1)) return strCompUsUs((id)self, aString, mask, aRange); - else if (c == GSCStringClass - || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 0) - || c == NXConstantStringClass) + else if (fastClassIsKindOfClass(c, GSCStringClass) + || c == NXConstantStringClass + || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 0)) return strCompUsCs((id)self, aString, mask, aRange); else return strCompUsNs((id)self, aString, mask, aRange); @@ -386,11 +469,11 @@ dataUsingEncoding_c(ivars self, NSStringEncoding encoding, BOOL flag) return [NSDataClass dataWithBytesNoCopy: buff length: t+2]; } else if ((encoding == defEnc) - ||((defEnc == NSASCIIStringEncoding) - && ((encoding == NSISOLatin1StringEncoding) - || (encoding == NSISOLatin2StringEncoding) - || (encoding == NSNEXTSTEPStringEncoding) - || (encoding == NSNonLossyASCIIStringEncoding)))) + || ((defEnc == NSASCIIStringEncoding) + && ((encoding == NSISOLatin1StringEncoding) + || (encoding == NSISOLatin2StringEncoding) + || (encoding == NSNEXTSTEPStringEncoding) + || (encoding == NSNonLossyASCIIStringEncoding)))) { unsigned char *buff; @@ -621,16 +704,6 @@ getCString_u(ivars self, char *buffer, unsigned int maxLength, buffer[len] = '\0'; } -static inline unsigned -hash(ivars self) -{ - if (self->_flags.hash == 0) - { - self->_flags.hash = (*hashImp)((id)self, hashSel); - } - return self->_flags.hash; -} - static inline int intValue_c(ivars self) { @@ -668,7 +741,7 @@ intValue_u(ivars self) } static inline BOOL -isEqual(ivars self, id anObject) +isEqual_c(ivars self, id anObject) { Class c; @@ -680,8 +753,21 @@ isEqual(ivars self, id anObject) { return NO; } + if (fastIsInstance(anObject) == NO) + { + return NO; + } c = fastClassOfInstance(anObject); - if (c == GSCStringClass || c == GSUStringClass || c == GSMStringClass) + if (c == NXConstantStringClass) + { + ivars other = (ivars)anObject; + NSRange r = {0, self->_count}; + + if (strCompCsCs((id)self, (id)other, 0, r) == NSOrderedSame) + return YES; + return NO; + } + else if (fastClassIsKindOfClass(c, GSStringClass) == YES) { ivars other = (ivars)anObject; NSRange r = {0, self->_count}; @@ -701,40 +787,7 @@ isEqual(ivars self, id anObject) */ if (other->_flags.wide == 1) { - if (self->_flags.wide == 1) - { - if (strCompUsUs((id)self, (id)other, 0, r) == NSOrderedSame) - return YES; - } - else - { - if (strCompCsUs((id)self, (id)other, 0, r) == NSOrderedSame) - return YES; - } - } - else - { - if (self->_flags.wide == 1) - { - if (strCompUsCs((id)self, (id)other, 0, r) == NSOrderedSame) - return YES; - } - else - { - if (strCompCsCs((id)self, (id)other, 0, r) == NSOrderedSame) - return YES; - } - } - return NO; - } - else if (c == NXConstantStringClass) - { - ivars other = (ivars)anObject; - NSRange r = {0, self->_count}; - - if (self->_flags.wide == 1) - { - if (strCompUsCs((id)self, (id)other, 0, r) == NSOrderedSame) + if (strCompCsUs((id)self, (id)other, 0, r) == NSOrderedSame) return YES; } else @@ -744,8 +797,71 @@ isEqual(ivars self, id anObject) } return NO; } - else if (c == nil) + else if (fastClassIsKindOfClass(c, NSStringClass)) { + return (*equalImp)((id)self, equalSel, anObject); + } + else + { + return NO; + } +} + +static inline BOOL +isEqual_u(ivars self, id anObject) +{ + Class c; + + if (anObject == (id)self) + { + return YES; + } + if (anObject == nil) + { + return NO; + } + if (fastIsInstance(anObject) == NO) + { + return NO; + } + c = fastClassOfInstance(anObject); + if (c == NXConstantStringClass) + { + ivars other = (ivars)anObject; + NSRange r = {0, self->_count}; + + if (strCompUsCs((id)self, (id)other, 0, r) == NSOrderedSame) + return YES; + return NO; + } + else if (fastClassIsKindOfClass(c, GSStringClass) == YES) + { + ivars other = (ivars)anObject; + NSRange r = {0, self->_count}; + + /* + * First see if the hash is the same - if not, we can't be equal. + */ + if (self->_flags.hash == 0) + self->_flags.hash = (*hashImp)((id)self, hashSel); + if (other->_flags.hash == 0) + other->_flags.hash = (*hashImp)((id)other, hashSel); + if (self->_flags.hash != other->_flags.hash) + return NO; + + /* + * Do a compare depending on the type of the other string. + */ + if (other->_flags.wide == 1) + { + if (strCompUsUs((id)self, (id)other, 0, r) == NSOrderedSame) + return YES; + } + else + { + if (strCompUsCs((id)self, (id)other, 0, r) == NSOrderedSame) + return YES; + } return NO; } else if (fastClassIsKindOfClass(c, NSStringClass)) @@ -925,13 +1041,16 @@ rangeOfString_c(ivars self, NSString *aString, unsigned mask, NSRange aRange) if (aString == nil) [NSException raise: NSInvalidArgumentException format: @"range of nil"]; + if (fastIsInstance(aString) == NO) + return strRangeCsNs((id)self, aString, mask, aRange); + c = fastClass(aString); - if (c == GSUStringClass + if (fastClassIsKindOfClass(c, GSUStringClass) == YES || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 1)) return strRangeCsUs((id)self, aString, mask, aRange); - else if (c == GSCStringClass - || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 0) - || c == NXConstantStringClass) + else if (fastClassIsKindOfClass(c, GSCStringClass) == YES + || c == NXConstantStringClass + || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 0)) return strRangeCsCs((id)self, aString, mask, aRange); else return strRangeCsNs((id)self, aString, mask, aRange); @@ -944,32 +1063,21 @@ rangeOfString_u(ivars self, NSString *aString, unsigned mask, NSRange aRange) if (aString == nil) [NSException raise: NSInvalidArgumentException format: @"range of nil"]; + if (fastIsInstance(aString) == NO) + return strRangeUsNs((id)self, aString, mask, aRange); + c = fastClass(aString); - if (c == GSUStringClass + if (fastClassIsKindOfClass(c, GSUStringClass) == YES || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 1)) return strRangeUsUs((id)self, aString, mask, aRange); - else if (c == GSCStringClass - || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 0) - || c == NXConstantStringClass) + else if (fastClassIsKindOfClass(c, GSCStringClass) == YES + || c == NXConstantStringClass + || (c == GSMStringClass && ((ivars)aString)->_flags.wide == 0)) return strRangeUsCs((id)self, aString, mask, aRange); else return strRangeUsNs((id)self, aString, mask, aRange); } -static inline NSString* -substringFromRange_c(ivars self, NSRange aRange) -{ - return [GSCStringClass stringWithCString: - self->_contents.c + aRange.location length: aRange.length]; -} - -static inline NSString* -substringFromRange_u(ivars self, NSRange aRange) -{ - return [GSUStringClass stringWithCharacters: - self->_contents.u + aRange.location length: aRange.length]; -} - /* * Function to examine the given string and see if it is one of our concrete * string classes. Converts the mutable string (self) from 8-bit to 16-bit @@ -987,8 +1095,24 @@ transmute(ivars self, NSString *aString) other = (ivars)aString; transmute = YES; + /* + * Unless we are sure that the other string we are going to insert into + * this one contains only ascii characters, we clear the flag that says + * we contain only ascii. + */ + if (fastClassIsKindOfClass(c, GSStringClass) == NO + || c == NXConstantStringClass || other->_flags.ascii == 0) + { + self->_flags.ascii = 0; + } + if (self->_flags.wide == 1) { + /* + * This is already a unicode string, so we don't need to transmute, + * but we still need to know if the other string is a unicode + * string whose ivars we can access directly. + */ transmute = NO; if ((c != GSMStringClass || other->_flags.wide != 1) && c != GSUStringClass) @@ -1001,20 +1125,39 @@ transmute(ivars self, NSString *aString) if (c == GSCStringClass || c == NXConstantStringClass || (c == GSMStringClass && other->_flags.wide == 0)) { + /* + * This is a C string, but the other string is also a C string + * so we don't need to transmute, and we can use its ivars. + */ transmute = NO; } else if ([aString canBeConvertedToEncoding: defEnc] == YES) { + /* + * This is a C string, but the other string can be converted to + * a C string, so we don't need to transmute, but we can not use + * its ivars. + */ transmute = NO; other = 0; } else if ((c == GSMStringClass && other->_flags.wide == 1) || c == GSUStringClass) { + /* + * This is a C string, and the other string can not be converted + * to a C string, so we need to transmute, and will then be able + * to use its ivars. + */ transmute = YES; } else { + /* + * This is a C string, and the other string can not be converted + * to a C string, so we need to transmute, but even then we will + * not be able to use the other strings ivars. + */ other = 0; } } @@ -1235,7 +1378,11 @@ transmute(ivars self, NSString *aString) - (unsigned) hash { - return hash((ivars)self); + if (self->_flags.hash == 0) + { + self->_flags.hash = (*hashImp)((id)self, hashSel); + } + return self->_flags.hash; } - (int) intValue @@ -1245,7 +1392,12 @@ transmute(ivars self, NSString *aString) - (BOOL) isEqual: (id)anObject { - return isEqual((ivars)self, anObject); + return isEqual_c((ivars)self, anObject); +} + +- (BOOL) isEqualToString: (NSString*)anObject +{ + return isEqual_c((ivars)self, anObject); } - (unsigned int) length @@ -1293,8 +1445,22 @@ transmute(ivars self, NSString *aString) - (NSString*) substringFromRange: (NSRange)aRange { + GSCSubString *sub; + GS_RANGE_CHECK(aRange, _count); - return substringFromRange_c((ivars)self, aRange); + + sub = [GSCSubStringClass allocWithZone: NSDefaultMallocZone()]; + sub = [sub initWithCStringNoCopy: self->_contents.c + aRange.location + length: aRange.length + freeWhenDone: NO]; + if (sub != nil) + { + sub->_parent = RETAIN(self); + if (_flags.ascii == 1) + ((ivars)sub)->_flags.ascii = 1; + AUTORELEASE(sub); + } + return sub; } // private method for Unicode level 3 implementation @@ -1307,6 +1473,16 @@ transmute(ivars self, NSString *aString) +@implementation GSCSubString +- (void) dealloc +{ + RELEASE(_parent); + [super dealloc]; +} +@end + + + @implementation GSUString + (id) alloc @@ -1472,7 +1648,11 @@ transmute(ivars self, NSString *aString) - (unsigned) hash { - return hash((ivars)self); + if (self->_flags.hash == 0) + { + self->_flags.hash = (*hashImp)((id)self, hashSel); + } + return self->_flags.hash; } - (int) intValue @@ -1482,7 +1662,12 @@ transmute(ivars self, NSString *aString) - (BOOL) isEqual: (id)anObject { - return isEqual((ivars)self, anObject); + return isEqual_u((ivars)self, anObject); +} + +- (BOOL) isEqualToString: (NSString*)anObject +{ + return isEqual_u((ivars)self, anObject); } - (unsigned int) length @@ -1530,8 +1715,22 @@ transmute(ivars self, NSString *aString) - (NSString*) substringFromRange: (NSRange)aRange { + GSUSubString *sub; + GS_RANGE_CHECK(aRange, _count); - return substringFromRange_u((ivars)self, aRange); + + sub = [GSUStringClass allocWithZone: NSDefaultMallocZone()]; + sub = [sub initWithCharactersNoCopy: self->_contents.u + aRange.location + length: aRange.length + freeWhenDone: NO]; + if (sub != nil) + { + sub->_parent = RETAIN(self); + if (_flags.ascii == 1) + ((ivars)sub)->_flags.ascii = 1; + AUTORELEASE(sub); + } + return sub; } // private method for Unicode level 3 implementation @@ -1550,6 +1749,16 @@ transmute(ivars self, NSString *aString) +@implementation GSUSubString +- (void) dealloc +{ + RELEASE(_parent); + [super dealloc]; +} +@end + + + @implementation GSMString + (id) alloc @@ -1783,7 +1992,11 @@ transmute(ivars self, NSString *aString) - (unsigned) hash { - return hash((ivars)self); + if (self->_flags.hash == 0) + { + self->_flags.hash = (*hashImp)((id)self, hashSel); + } + return self->_flags.hash; } - (id) init @@ -1868,7 +2081,18 @@ transmute(ivars self, NSString *aString) - (BOOL) isEqual: (id)anObject { - return isEqual((ivars)self, anObject); + if (_flags.wide == 1) + return isEqual_u((ivars)self, anObject); + else + return isEqual_c((ivars)self, anObject); +} + +- (BOOL) isEqualToString: (NSString*)anObject +{ + if (_flags.wide == 1) + return isEqual_u((ivars)self, anObject); + else + return isEqual_c((ivars)self, anObject); } - (unsigned int) length @@ -2071,9 +2295,15 @@ transmute(ivars self, NSString *aString) GS_RANGE_CHECK(aRange, _count); if (_flags.wide == 1) - return substringFromRange_u((ivars)self, aRange); + { + return [GSUStringClass stringWithCharacters: + self->_contents.u + aRange.location length: aRange.length]; + } else - return substringFromRange_c((ivars)self, aRange); + { + return [GSCStringClass stringWithCString: + self->_contents.c + aRange.location length: aRange.length]; + } } // private method for Unicode level 3 implementation @@ -2246,9 +2476,14 @@ transmute(ivars self, NSString *aString) { return NO; } + if (fastIsInstance(anObject) == NO) + { + return NO; + } c = fastClassOfInstance(anObject); - if (c == GSCStringClass || c == NXConstantStringClass + if (fastClassIsKindOfClass(c, GSCStringClass) == YES + || c == NXConstantStringClass || (c == GSMStringClass && ((ivars)anObject)->_flags.wide == 0)) { ivars other = (ivars)anObject; @@ -2259,16 +2494,13 @@ transmute(ivars self, NSString *aString) return NO; return YES; } - else if (c == GSUStringClass || c == GSMStringClass) + else if (fastClassIsKindOfClass(c, GSUStringClass) == YES + || c == GSMStringClass) { if (strCompCsUs(self, anObject, 0, (NSRange){0,_count}) == NSOrderedSame) return YES; return NO; } - else if (c == nil) - { - return NO; - } else if (fastClassIsKindOfClass(c, NSStringClass)) { return (*equalImp)(self, equalSel, anObject); @@ -2291,9 +2523,14 @@ transmute(ivars self, NSString *aString) { return NO; } + if (fastIsInstance(anObject) == NO) + { + return NO; + } c = fastClassOfInstance(anObject); - if (c == GSCStringClass || c == NXConstantStringClass + if (fastClassIsKindOfClass(c, GSCStringClass) == YES + || c == NXConstantStringClass || (c == GSMStringClass && ((ivars)anObject)->_flags.wide == 0)) { ivars other = (ivars)anObject; @@ -2304,16 +2541,13 @@ transmute(ivars self, NSString *aString) return NO; return YES; } - else if (c == GSUStringClass || c == GSMStringClass) + else if (fastClassIsKindOfClass(c, GSUStringClass) == YES + || c == GSMStringClass) { if (strCompCsUs(self, anObject, 0, (NSRange){0,_count}) == NSOrderedSame) return YES; return NO; } - else if (c == nil) - { - return NO; - } else if (fastClassIsKindOfClass(c, NSStringClass)) { return (*equalImp)(self, equalSel, anObject); diff --git a/Source/NSCalendarDate.m b/Source/NSCalendarDate.m index 9de6bcccc..504b99581 100644 --- a/Source/NSCalendarDate.m +++ b/Source/NSCalendarDate.m @@ -354,12 +354,15 @@ static inline int getDigits(const char *from, char *to, int limit) } else { - if (source[sourceIdx] != format[formatIdx]) + if (sourceIdx < sourceLen) { - NSLog(@"Expected literal '%c' but got '%c'", - format[formatIdx], source[sourceIdx]); + if (source[sourceIdx] != format[formatIdx]) + { + NSLog(@"Expected literal '%c' but gmtt '%c'", + format[formatIdx], source[sourceIdx]); + } + sourceIdx++; } - sourceIdx++; } } else @@ -371,19 +374,28 @@ static inline int getDigits(const char *from, char *to, int limit) { case '%': // skip literal % - if (source[sourceIdx] != '%') + if (sourceIdx < sourceLen) { - NSLog(@"Expected literal '%' but got '%c'", - source[sourceIdx]); + if (source[sourceIdx] != '%') + { + NSLog(@"Expected literal '%' but got '%c'", + source[sourceIdx]); + } + sourceIdx++; } - sourceIdx++; break; case 'a': // Are Short names three chars in all locales????? - tmpStr[0] = toupper(source[sourceIdx++]); - tmpStr[1] = tolower(source[sourceIdx++]); - tmpStr[2] = tolower(source[sourceIdx++]); + tmpStr[0] = toupper(source[sourceIdx]); + if (sourceIdx < sourceLen) + sourceIdx++; + tmpStr[1] = tolower(source[sourceIdx]); + if (sourceIdx < sourceLen) + sourceIdx++; + tmpStr[2] = tolower(source[sourceIdx]); + if (sourceIdx < sourceLen) + sourceIdx++; tmpStr[3] = '\0'; { NSString *currDay; @@ -437,9 +449,15 @@ static inline int getDigits(const char *from, char *to, int limit) case 'b': // Are Short names three chars in all locales????? - tmpStr[0] = toupper(source[sourceIdx++]); - tmpStr[1] = tolower(source[sourceIdx++]); - tmpStr[2] = tolower(source[sourceIdx++]); + tmpStr[0] = toupper(source[sourceIdx]); + if (sourceIdx < sourceLen) + sourceIdx++; + tmpStr[1] = tolower(source[sourceIdx]); + if (sourceIdx < sourceLen) + sourceIdx++; + tmpStr[2] = tolower(source[sourceIdx]); + if (sourceIdx < sourceLen) + sourceIdx++; tmpStr[3] = '\0'; { NSString *currMonth; @@ -530,8 +548,12 @@ static inline int getDigits(const char *from, char *to, int limit) case 'p': // Questionable assumption that all am/pm indicators are 2 // characters and in upper case.... - tmpStr[0] = toupper(source[sourceIdx++]); - tmpStr[1] = toupper(source[sourceIdx++]); + tmpStr[0] = toupper(source[sourceIdx]); + if (sourceIdx < sourceLen) + sourceIdx++; + tmpStr[1] = toupper(source[sourceIdx]); + if (sourceIdx < sourceLen) + sourceIdx++; tmpStr[2] = '\0'; { NSString *currAMPM; diff --git a/Source/NSString.m b/Source/NSString.m index 229f1bce4..1d6f44491 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -343,15 +343,47 @@ handle_printf_atsign (FILE *stream, { if (length > 0) { - unichar *s = NSZoneMalloc(fastZone(self), sizeof(unichar)*length); + int i; + BOOL isAscii = YES; - if (chars != 0) + if (chars == 0) { - memcpy(s, chars, sizeof(unichar)*length); + [NSException raise: NSInvalidArgumentException + format: @"nul pointer but non-zero length"]; + } + for (i = 0; i < length; i++) + { + if (chars[i] >= 128) + { + isAscii = NO; + break; + } + } + if (isAscii == YES) + { + char *s; + + s = NSZoneMalloc(fastZone(self), length); + + for (i = 0; i < length; i++) + { + s[i] = (unsigned char)chars[i]; + } + self = [self initWithCStringNoCopy: s + length: length + freeWhenDone: YES]; + } + else + { + unichar *s; + + s = NSZoneMalloc(fastZone(self), sizeof(unichar)*length); + + memcpy(s, chars, sizeof(unichar)*length); + self = [self initWithCharactersNoCopy: s + length: length + freeWhenDone: YES]; } - self = [self initWithCharactersNoCopy: s - length: length - freeWhenDone: YES]; } else {