diff --git a/ChangeLog b/ChangeLog index 6f54e2090..ca1d11374 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ case where it has to be inferred from the actual data. Follow the instructions in http://www.w3.org/TR/REC-xml/ but be a bit more tolerant. (ebcdic not supported). + * Headers/Foundation/GSString.m: Add a few new methods from macosx. + * Source/NSString.m: ditto. + * Source/GSString.m: ditto. 2005-05-04 Richard Frith-Macdonald diff --git a/Headers/Foundation/NSString.h b/Headers/Foundation/NSString.h index 751a9248a..dceb08f7a 100644 --- a/Headers/Foundation/NSString.h +++ b/Headers/Foundation/NSString.h @@ -192,9 +192,13 @@ enum { + (id) string; + (id) stringWithCharacters: (const unichar*)chars length: (unsigned int)length; +#ifndef STRICT_OPENSTEP ++ (id) stringWithCString: (const char*)byteString + encoding: (NSStringEncoding)encoding; +#endif + (id) stringWithCString: (const char*)byteString length: (unsigned int)length; -+ (id) stringWithCString: (const char*) byteString; ++ (id) stringWithCString: (const char*)byteString; + (id) stringWithFormat: (NSString*)format,...; + (id) stringWithContentsOfFile:(NSString *)path; @@ -296,6 +300,16 @@ enum { #endif // Getting C Strings - (const char*) cString; +#ifndef STRICT_OPENSTEP +- (const char*) cStringUsingEncoding: (NSStringEncoding)encoding; +- (void) getCString: (char*)buffer + maxLength: (unsigned int)maxLength + encoding: (NSStringEncoding)encoding; +- (id) initWithCString: (const char*)byteString + encoding: (NSStringEncoding)encoding; +- (unsigned) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding; +- (unsigned) maximumLengthOfBytesUsingEncoding: (NSStringEncoding)encoding; +#endif - (unsigned int) cStringLength; - (void) getCString: (char*)buffer; - (void) getCString: (char*)buffer @@ -565,9 +579,9 @@ enum { */ - (NSArray*) stringsByAppendingPaths: (NSArray*)paths; -+ (NSString*) localizedStringWithFormat: (NSString*) format, ...; ++ (NSString*) localizedStringWithFormat: (NSString*)format, ...; -+ (id) stringWithString: (NSString*) aString; ++ (id) stringWithString: (NSString*)aString; + (id) stringWithContentsOfURL: (NSURL*)url; + (id) stringWithUTF8String: (const char*)bytes; - (id) initWithFormat: (NSString*)format @@ -621,7 +635,7 @@ enum { length: (unsigned int)length; + (id) stringWithCString: (const char*)byteString length: (unsigned int)length; -+ (id) stringWithCString: (const char*) byteString; ++ (id) stringWithCString: (const char*)byteString; + (id) stringWithFormat: (NSString*)format,...; + (id) stringWithContentsOfFile: (NSString*)path; + (NSMutableString*) stringWithCapacity: (unsigned int)capacity; diff --git a/Source/GSString.m b/Source/GSString.m index b91a0458d..50450294b 100644 --- a/Source/GSString.m +++ b/Source/GSString.m @@ -921,7 +921,7 @@ compare_u(GSStr self, NSString *aString, unsigned mask, NSRange aRange) } static inline char* -cString_c(GSStr self) +cString_c(GSStr self, NSStringEncoding enc) { unsigned char *r; @@ -929,7 +929,7 @@ cString_c(GSStr self) { return ""; } - if (defEnc == intEnc) + if (enc == intEnc) { r = (unsigned char*)GSAutoreleasedBuffer(self->_count+1); @@ -956,7 +956,7 @@ cString_c(GSStr self) [NSException raise: NSCharacterConversionException format: @"Can't convert to/from Unicode string."]; } - if (GSFromUnicode((unsigned char**)&r, &s, u, l, defEnc, + if (GSFromUnicode((unsigned char**)&r, &s, u, l, enc, NSDefaultMallocZone(), GSUniTerminate|GSUniTemporary|GSUniStrict) == NO) { NSZoneFree(NSDefaultMallocZone(), u); @@ -970,7 +970,7 @@ cString_c(GSStr self) } static inline char* -cString_u(GSStr self) +cString_u(GSStr self, NSStringEncoding enc) { unsigned c = self->_count; @@ -983,7 +983,7 @@ cString_u(GSStr self) unsigned int l = 0; unsigned char *r = 0; - if (GSFromUnicode(&r, &l, self->_contents.u, c, defEnc, + if (GSFromUnicode(&r, &l, self->_contents.u, c, enc, NSDefaultMallocZone(), GSUniTerminate|GSUniTemporary|GSUniStrict) == NO) { [NSException raise: NSCharacterConversionException @@ -994,9 +994,9 @@ cString_u(GSStr self) } static inline unsigned int -cStringLength_c(GSStr self) +cStringLength_c(GSStr self, NSStringEncoding enc) { - if (defEnc == intEnc) + if (enc == intEnc) { return self->_count; } @@ -1023,7 +1023,7 @@ cStringLength_c(GSStr self) [NSException raise: NSCharacterConversionException format: @"Can't convert to/from Unicode string."]; } - if (GSFromUnicode(0, &s, u, l, defEnc, 0, GSUniStrict) == NO) + if (GSFromUnicode(0, &s, u, l, enc, 0, GSUniStrict) == NO) { NSZoneFree(NSDefaultMallocZone(), u); [NSException raise: NSCharacterConversionException @@ -1036,7 +1036,7 @@ cStringLength_c(GSStr self) } static inline unsigned int -cStringLength_u(GSStr self) +cStringLength_u(GSStr self, NSStringEncoding enc) { unsigned c = self->_count; @@ -1048,7 +1048,7 @@ cStringLength_u(GSStr self) { unsigned l = 0; - if (GSFromUnicode(0, &l, self->_contents.u, c, defEnc, 0, GSUniStrict) + if (GSFromUnicode(0, &l, self->_contents.u, c, enc, 0, GSUniStrict) == NO) { [NSException raise: NSCharacterConversionException @@ -2130,12 +2130,17 @@ transmute(GSStr self, NSString *aString) - (const char *) cString { - return cString_c((GSStr)self); + return cString_c((GSStr)self, defEnc); +} + +- (const char *) cStringUsingEncoding: (NSStringEncoding)encoding +{ + return cString_c((GSStr)self, encoding); } - (unsigned int) cStringLength { - return cStringLength_c((GSStr)self); + return cStringLength_c((GSStr)self, defEnc); } - (NSData*) dataUsingEncoding: (NSStringEncoding)encoding @@ -2232,6 +2237,11 @@ transmute(GSStr self, NSString *aString) return _count; } +- (unsigned int) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding +{ + return cStringLength_c((GSStr)self, encoding); +} + - (const char*) lossyCString { return lossyCString_c((GSStr)self); @@ -2449,12 +2459,17 @@ agree, create a new GSCInlineString otherwise. - (const char *) cString { - return cString_u((GSStr)self); + return cString_u((GSStr)self, defEnc); +} + +- (const char *) cStringUsingEncoding: (NSStringEncoding)encoding +{ + return cString_u((GSStr)self, encoding); } - (unsigned int) cStringLength { - return cStringLength_u((GSStr)self); + return cStringLength_u((GSStr)self, defEnc); } - (NSData*) dataUsingEncoding: (NSStringEncoding)encoding @@ -2554,6 +2569,11 @@ agree, create a new GSCInlineString otherwise. return _count; } +- (unsigned int) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding +{ + return cStringLength_u((GSStr)self, encoding); +} + - (const char*) lossyCString { return lossyCString_u((GSStr)self); @@ -2864,17 +2884,25 @@ agree, create a new GSUnicodeInlineString otherwise. - (const char *) cString { if (_flags.wide == 1) - return cString_u((GSStr)self); + return cString_u((GSStr)self, defEnc); else - return cString_c((GSStr)self); + return cString_c((GSStr)self, defEnc); +} + +- (const char *) cStringUsingEncoding: (NSStringEncoding)encoding +{ + if (_flags.wide == 1) + return cString_u((GSStr)self, encoding); + else + return cString_c((GSStr)self, encoding); } - (unsigned int) cStringLength { if (_flags.wide == 1) - return cStringLength_u((GSStr)self); + return cStringLength_u((GSStr)self, defEnc); else - return cStringLength_c((GSStr)self); + return cStringLength_c((GSStr)self, defEnc); } - (NSData*) dataUsingEncoding: (NSStringEncoding)encoding @@ -3171,6 +3199,14 @@ agree, create a new GSUnicodeInlineString otherwise. return _count; } +- (unsigned int) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding +{ + if (_flags.wide == 1) + return cStringLength_u((GSStr)self, encoding); + else + return cStringLength_c((GSStr)self, encoding); +} + - (const char*) lossyCString { if (_flags.wide == 1) @@ -3540,6 +3576,11 @@ agree, create a new GSUnicodeInlineString otherwise. return [_parent cString]; } +- (const char *) cStringUsingEncoding +{ + return [_parent cStringUsingEncoding]; +} + - (unsigned int) cStringLength { return [_parent cStringLength]; @@ -3603,6 +3644,13 @@ agree, create a new GSUnicodeInlineString otherwise. [_parent getCString: buffer maxLength: maxLength]; } +- (void) getCString: (char*)buffer + maxLength: (unsigned int)maxLength + encoding: (NSStringEncoding)encoding +{ + [_parent getCString: buffer maxLength: maxLength encoding: encoding]; +} + - (void) getCString: (char*)buffer maxLength: (unsigned int)maxLength range: (NSRange)aRange @@ -3640,11 +3688,21 @@ agree, create a new GSUnicodeInlineString otherwise. return [_parent length]; } +- (unsigned int) lengthOfBytesUsingEncoding +{ + return [_parent lengthOfBytesUsingEncoding]; +} + - (const char*) lossyCString { return [_parent lossyCString]; } +- (unsigned int) maximumLengthOfBytesUsingEncoding +{ + return [_parent maximumLengthOfBytesUsingEncoding]; +} + - (NSRange) rangeOfComposedCharacterSequenceAtIndex: (unsigned)anIndex { return [_parent rangeOfComposedCharacterSequenceAtIndex: anIndex]; @@ -3708,17 +3766,25 @@ agree, create a new GSUnicodeInlineString otherwise. - (const char *) cString { if (((GSStr)_parent)->_flags.wide == 1) - return cString_u((GSStr)_parent); + return cString_u((GSStr)_parent, defEnc); else - return cString_c((GSStr)_parent); + return cString_c((GSStr)_parent, defEnc); +} + +- (const char *) cStringUsingEncoding: (NSStringEncoding)encoding +{ + if (((GSStr)_parent)->_flags.wide == 1) + return cString_u((GSStr)_parent, encoding); + else + return cString_c((GSStr)_parent, encoding); } - (unsigned int) cStringLength { if (((GSStr)_parent)->_flags.wide == 1) - return cStringLength_u((GSStr)_parent); + return cStringLength_u((GSStr)_parent, defEnc); else - return cStringLength_c((GSStr)_parent); + return cStringLength_c((GSStr)_parent, defEnc); } - (NSData*) dataUsingEncoding: (NSStringEncoding)encoding @@ -3800,6 +3866,14 @@ agree, create a new GSUnicodeInlineString otherwise. return ((GSStr)_parent)->_count; } +- (unsigned int) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding +{ + if (((GSStr)_parent)->_flags.wide == 1) + return cStringLength_u((GSStr)_parent, encoding); + else + return cStringLength_c((GSStr)_parent, encoding); +} + - (const char*) lossyCString { if (((GSStr)_parent)->_flags.wide == 1) @@ -3808,6 +3882,11 @@ agree, create a new GSUnicodeInlineString otherwise. return lossyCString_c((GSStr)_parent); } +- (unsigned int) maximumLengthOfBytesUsingEncoding +{ + return [_parent maximumLengthOfBytesUsingEncoding]; +} + - (NSRange) rangeOfComposedCharacterSequenceAtIndex: (unsigned)anIndex { if (((GSStr)_parent)->_flags.wide == 1) diff --git a/Source/NSString.m b/Source/NSString.m index 74f64a69c..08a4ae659 100644 --- a/Source/NSString.m +++ b/Source/NSString.m @@ -584,7 +584,7 @@ handle_printf_atsign (FILE *stream, * null-terminated and encoded in the default C string encoding. (Characters * will be converted to unicode representation internally.) */ -+ (id) stringWithCString: (const char*) byteString ++ (id) stringWithCString: (const char*)byteString { NSString *obj; unsigned length = byteString ? strlen(byteString) : 0; @@ -594,6 +594,21 @@ handle_printf_atsign (FILE *stream, return AUTORELEASE(obj); } +/** + * Create a string based on the given C (char[]) string, which should be + * null-terminated and encoded in the specified C string encoding. + * Characters may be converted to unicode representation internally. + */ ++ (id) stringWithCString: (const char*)byteString + encoding: (NSStringEncoding)encoding +{ + NSString *obj; + + obj = [self allocWithZone: NSDefaultMallocZone()]; + obj = [obj initWithCString: byteString encoding: encoding]; + return AUTORELEASE(obj); +} + /** * Create a string based on the given C (char[]) string, which may contain * null bytes and should be encoded in the default C string encoding. @@ -1145,6 +1160,19 @@ handle_printf_atsign (FILE *stream, return self; } +/** + *

Initialize with given C string byteString up to first nul byte. + * Characters converted to unicode based on the specified C encoding. + * Copies the string.

+ */ +- (id) initWithCString: (const char*)byteString + encoding: (NSStringEncoding)encoding +{ + return [self initWithBytes: byteString + length: strlen(byteString) + encoding: encoding]; +} + /** *

Initialize with given C string byteString up to length, regardless of * presence of null bytes. Characters converted to unicode based on the @@ -2801,6 +2829,60 @@ handle_printf_atsign (FILE *stream, return (const char*)[m bytes]; } +/** + * Returns a pointer to a null terminated string of 8-bit characters in the + * specified encoding.
+ * The memory pointed to is not owned by the caller, so the + * caller must copy its contents to keep it.
+ * Raises an * NSCharacterConversionException if loss of + * information would occur during conversion. + */ +- (const char*) cStringUsingEncoding: (NSStringEncoding)encoding +{ + NSData *d; + NSMutableData *m; + + d = [self dataUsingEncoding: encoding allowLossyConversion: NO]; + if (d == nil) + { + [NSException raise: NSCharacterConversionException + format: @"unable to convert to cString"]; + } + m = [d mutableCopy]; + [m appendBytes: "" length: 1]; + AUTORELEASE(m); + return (const char*)[m bytes]; +} + +/** + * Returns the number of bytes needed to encode the receiver in the + * specified encoding (without adding a nul character terminator).
+ * Returns 0 if the conversion is not possible. + */ +- (unsigned) lengthOfBytesUsingEncoding: (NSStringEncoding)encoding +{ + NSData *d; + + d = [self dataUsingEncoding: encoding allowLossyConversion: NO]; + return [d length]; +} + +/** + * Returns a size guaranteed to be large enough to encode the receiver in the + * specified encoding (without adding a nul character terminator). This may + * be larger than the actual number of bytes needed. + */ +- (unsigned) maximumLengthOfBytesUsingEncoding: (NSStringEncoding)encoding +{ + if (encoding == NSUnicodeStringEncoding) + return [self length] * 2; + if (encoding == NSUTF8StringEncoding) + return [self length] * 6; + if (encoding == NSUTF7StringEncoding) + return [self length] * 8; + return [self length]; // Assume single byte/char +} + /** * Returns a C string converted using the default C string encoding, which may * result in information loss. The memory pointed to is not owned by the @@ -2878,6 +2960,23 @@ handle_printf_atsign (FILE *stream, remainingRange: NULL]; } +/** + * Retrieve up to maxLength bytes from the receiver into the buffer.
+ * The buffer must be at least maxLength + 1 bytes long, so that it has + * room for the nul terminator that this method adds. + */ +- (void) getCString: (char*)buffer + maxLength: (unsigned int)maxLength + encoding: (NSStringEncoding)encoding +{ + NSData *d = [self dataUsingEncoding: encoding]; + unsigned len = [d length]; + + if (len > maxLength) len = maxLength; + memcpy(buffer, [d bytes], len); + buffer[len] = '\0'; +} + /** * Converts characters from the given range of the string to the c string * encoding and stores the resulting bytes in the given buffer. As many @@ -2939,7 +3038,7 @@ handle_printf_atsign (FILE *stream, // Getting Numeric Values -// xxx Sould we use NSScanner here ? +// xxx Should we use NSScanner here ? /** * If the string consists of the words 'true' or 'yes' (case insensitive)