@@ -15,19 +15,17 @@ */ #include "config.h" #include -#include #include #include -#include -#include #include #import "OFString.h" +#import "OFString_UTF8.h" #import "OFArray.h" #import "OFDictionary.h" #import "OFFile.h" #import "OFURL.h" #import "OFHTTPRequest.h" @@ -47,13 +45,10 @@ #import "macros.h" #import "of_asprintf.h" #import "unicode.h" -extern const uint16_t of_iso_8859_15[256]; -extern const uint16_t of_windows_1252[256]; - /* References for static linking */ void _references_to_categories_of_OFString(void) { _OFString_Hashing_reference = 1; _OFString_Serialization_reference = 1; @@ -60,25 +55,10 @@ _OFString_URLEncoding_reference = 1; _OFString_XMLEscaping_reference = 1; _OFString_XMLUnescaping_reference = 1; } -static inline int -memcasecmp(const char *first, const char *second, size_t length) -{ - size_t i; - - for (i = 0; i < length; i++) { - if (tolower((int)first[i]) > tolower((int)second[i])) - return OF_ORDERED_DESCENDING; - if (tolower((int)first[i]) < tolower((int)second[i])) - return OF_ORDERED_ASCENDING; - } - - return OF_ORDERED_SAME; -} - int of_string_check_utf8(const char *cString, size_t cStringLength, size_t *length) { size_t i, tmpLength = cStringLength; int UTF8 = 0; @@ -258,12 +238,219 @@ while (*string_ != 0) string_++; return (size_t)(string_ - string); } + +static struct { + Class isa; +} placeholder; + +@interface OFString_placeholder: OFString +@end + +@implementation OFString_placeholder +- init +{ + return (id)[[OFString_UTF8 alloc] init]; +} + +- initWithUTF8String: (const char*)UTF8String +{ + return (id)[[OFString_UTF8 alloc] initWithUTF8String: UTF8String]; +} + +- initWithUTF8String: (const char*)UTF8String + length: (size_t)UTF8StringLength +{ + return (id)[[OFString_UTF8 alloc] initWithUTF8String: UTF8String + length: UTF8StringLength]; +} + +- initWithCString: (const char*)cString + encoding: (of_string_encoding_t)encoding +{ + return (id)[[OFString_UTF8 alloc] initWithCString: cString + encoding: encoding]; +} + +- initWithCString: (const char*)cString + encoding: (of_string_encoding_t)encoding + length: (size_t)cStringLength +{ + return (id)[[OFString_UTF8 alloc] initWithCString: cString + encoding: encoding + length: cStringLength]; +} + +- initWithString: (OFString*)string +{ + return (id)[[OFString_UTF8 alloc] initWithString: string]; +} + +- initWithUnicodeString: (const of_unichar_t*)string +{ + return (id)[[OFString_UTF8 alloc] initWithUnicodeString: string]; +} + +- initWithUnicodeString: (const of_unichar_t*)string + byteOrder: (of_endianess_t)byteOrder +{ + return (id)[[OFString_UTF8 alloc] initWithUnicodeString: string + byteOrder: byteOrder]; +} + +- initWithUnicodeString: (const of_unichar_t*)string + length: (size_t)length +{ + return (id)[[OFString_UTF8 alloc] initWithUnicodeString: string + length: length]; +} + +- initWithUnicodeString: (const of_unichar_t*)string + byteOrder: (of_endianess_t)byteOrder + length: (size_t)length +{ + return (id)[[OFString_UTF8 alloc] initWithUnicodeString: string + byteOrder: byteOrder + length: length]; +} + +- initWithUTF16String: (const uint16_t*)string +{ + return (id)[[OFString_UTF8 alloc] initWithUTF16String: string]; +} + +- initWithUTF16String: (const uint16_t*)string + byteOrder: (of_endianess_t)byteOrder +{ + return (id)[[OFString_UTF8 alloc] initWithUTF16String: string + byteOrder: byteOrder]; +} + +- initWithUTF16String: (const uint16_t*)string + length: (size_t)length +{ + return (id)[[OFString_UTF8 alloc] initWithUTF16String: string + length: length]; +} + +- initWithUTF16String: (const uint16_t*)string + byteOrder: (of_endianess_t)byteOrder + length: (size_t)length +{ + return (id)[[OFString_UTF8 alloc] initWithUTF16String: string + byteOrder: byteOrder + length: length]; +} + +- initWithFormat: (OFConstantString*)format, ... +{ + id ret; + va_list arguments; + + va_start(arguments, format); + ret = [[OFString_UTF8 alloc] initWithFormat: format + arguments: arguments]; + va_end(arguments); + + return ret; +} + +- initWithFormat: (OFConstantString*)format + arguments: (va_list)arguments +{ + return (id)[[OFString_UTF8 alloc] initWithFormat: format + arguments: arguments]; +} + +- initWithPath: (OFString*)firstComponent, ... +{ + id ret; + va_list arguments; + + va_start(arguments, firstComponent); + ret = [[OFString_UTF8 alloc] initWithPath: firstComponent + arguments: arguments]; + va_end(arguments); + + return ret; +} + +- initWithPath: (OFString*)firstComponent + arguments: (va_list)arguments +{ + return (id)[[OFString_UTF8 alloc] initWithPath: firstComponent + arguments: arguments]; +} + +- initWithContentsOfFile: (OFString*)path +{ + return (id)[[OFString_UTF8 alloc] initWithContentsOfFile: path]; +} + +- initWithContentsOfFile: (OFString*)path + encoding: (of_string_encoding_t)encoding +{ + return (id)[[OFString_UTF8 alloc] initWithContentsOfFile: path + encoding: encoding]; +} + +- initWithContentsOfURL: (OFURL*)URL +{ + return (id)[[OFString_UTF8 alloc] initWithContentsOfURL: URL]; +} + +- initWithContentsOfURL: (OFURL*)URL + encoding: (of_string_encoding_t)encoding +{ + return (id)[[OFString_UTF8 alloc] initWithContentsOfURL: URL + encoding: encoding]; +} + +- initWithSerialization: (OFXMLElement*)element +{ + return (id)[[OFString_UTF8 alloc] initWithSerialization: element]; +} + +- retain +{ + return self; +} + +- autorelease +{ + return self; +} + +- (void)release +{ +} + +- (void)dealloc +{ + @throw [OFNotImplementedException exceptionWithClass: isa + selector: _cmd]; + [super dealloc]; /* Get rid of a stupid warning */ +} +@end @implementation OFString ++ (void)initialize +{ + if (self == [OFString class]) + placeholder.isa = [OFString_placeholder class]; +} + ++ alloc +{ + if (self == [OFString class]) + return (id)&placeholder; + + return [super alloc]; +} + + string { return [[[self alloc] init] autorelease]; } @@ -407,24 +594,18 @@ encoding: encoding] autorelease]; } - init { - self = [super init]; - - @try { - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); - - s->cString = [self allocMemoryWithSize: 1]; - s->cString[0] = '\0'; - } @catch (id e) { + if (isa == [OFString class]) { + Class c = isa; [self release]; - @throw e; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; } - return self; + return [super init]; } - initWithUTF8String: (const char*)UTF8String { return [self initWithCString: UTF8String @@ -450,162 +631,22 @@ - initWithCString: (const char*)cString encoding: (of_string_encoding_t)encoding length: (size_t)cStringLength { - self = [super init]; - - @try { - size_t i, j; - const uint16_t *table; - - if (encoding == OF_STRING_ENCODING_UTF_8 && - cStringLength >= 3 && !memcmp(cString, "\xEF\xBB\xBF", 3)) { - cString += 3; - cStringLength -= 3; - } - - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); - - s->cString = [self allocMemoryWithSize: cStringLength + 1]; - s->cStringLength = cStringLength; - - if (encoding == OF_STRING_ENCODING_UTF_8 || - encoding == OF_STRING_ENCODING_ASCII) { - switch (of_string_check_utf8(cString, cStringLength, - &s->length)) { - case 1: - if (encoding == OF_STRING_ENCODING_ASCII) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - s->UTF8 = YES; - break; - case -1: - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - } - - memcpy(s->cString, cString, cStringLength); - s->cString[cStringLength] = 0; - - return self; - } - - /* All other encodings we support are single byte encodings */ - s->length = cStringLength; - - if (encoding == OF_STRING_ENCODING_ISO_8859_1) { - for (i = j = 0; i < cStringLength; i++) { - char buffer[4]; - size_t bytes; - - if (!(cString[i] & 0x80)) { - s->cString[j++] = cString[i]; - continue; - } - - s->UTF8 = YES; - bytes = of_string_unicode_to_utf8( - (uint8_t)cString[i], buffer); - - if (bytes == 0) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - s->cStringLength += bytes - 1; - s->cString = [self - resizeMemory: s->cString - toSize: s->cStringLength + 1]; - - memcpy(s->cString + j, buffer, bytes); - j += bytes; - } - - s->cString[s->cStringLength] = 0; - - return self; - } - - switch (encoding) { - case OF_STRING_ENCODING_ISO_8859_15: - table = of_iso_8859_15; - break; - case OF_STRING_ENCODING_WINDOWS_1252: - table = of_windows_1252; - break; - default: - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - } - - for (i = j = 0; i < cStringLength; i++) { - char buffer[4]; - of_unichar_t character; - size_t characterBytes; - - if (!(cString[i] & 0x80)) { - s->cString[j++] = cString[i]; - continue; - } - - character = table[(uint8_t)cString[i]]; - - if (character == 0xFFFD) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - s->UTF8 = YES; - characterBytes = of_string_unicode_to_utf8(character, - buffer); - - if (characterBytes == 0) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - s->cStringLength += characterBytes - 1; - s->cString = [self resizeMemory: s->cString - toSize: s->cStringLength + 1]; - - memcpy(s->cString + j, buffer, characterBytes); - j += characterBytes; - } - - s->cString[s->cStringLength] = 0; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; } - initWithString: (OFString*)string { - self = [super init]; - - @try { - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); - - /* - * We need one call to make sure it's initialized (in case it's - * a constant string). - */ - s->cStringLength = [string UTF8StringLength]; - s->UTF8 = string->s->UTF8; - s->length = string->s->length; - - s->cString = [self allocMemoryWithSize: s->cStringLength + 1]; - memcpy(s->cString, string->s->cString, s->cStringLength + 1); - } @catch (id e) { - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; } - initWithUnicodeString: (const of_unichar_t*)string { return [self initWithUnicodeString: string @@ -631,87 +672,14 @@ - initWithUnicodeString: (const of_unichar_t*)string byteOrder: (of_endianess_t)byteOrder length: (size_t)length { - self = [super init]; - - @try { - size_t i, j = 0; - BOOL swap = NO; - - if (length > 0 && *string == 0xFEFF) { - string++; - length--; - } else if (length > 0 && *string == 0xFFFE0000) { - swap = YES; - string++; - length--; - } else if (byteOrder != OF_ENDIANESS_NATIVE) - swap = YES; - - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); - - s->cStringLength = length; - s->cString = [self allocMemoryWithSize: (length * 4) + 1]; - s->length = length; - - for (i = 0; i < length; i++) { - char buffer[4]; - size_t characterLen = of_string_unicode_to_utf8( - (swap ? of_bswap32(string[i]) : string[i]), - buffer); - - switch (characterLen) { - case 1: - s->cString[j++] = buffer[0]; - break; - case 2: - s->UTF8 = YES; - s->cStringLength++; - - memcpy(s->cString + j, buffer, 2); - j += 2; - - break; - case 3: - s->UTF8 = YES; - s->cStringLength += 2; - - memcpy(s->cString + j, buffer, 3); - j += 3; - - break; - case 4: - s->UTF8 = YES; - s->cStringLength += 3; - - memcpy(s->cString + j, buffer, 4); - j += 4; - - break; - default: - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - } - } - - s->cString[j] = '\0'; - - @try { - s->cString = [self resizeMemory: s->cString - toSize: s->cStringLength + 1]; - } @catch (OFOutOfMemoryException *e) { - /* We don't care, as we only tried to make it smaller */ - } - } @catch (id e) { - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; } - initWithUTF16String: (const uint16_t*)string { return [self initWithUTF16String: string @@ -737,113 +705,14 @@ - initWithUTF16String: (const uint16_t*)string byteOrder: (of_endianess_t)byteOrder length: (size_t)length { - self = [super init]; - - @try { - size_t i, j = 0; - BOOL swap = NO; - - if (length > 0 && *string == 0xFEFF) { - string++; - length--; - } else if (length > 0 && *string == 0xFFFE) { - swap = YES; - string++; - length--; - } else if (byteOrder != OF_ENDIANESS_NATIVE) - swap = YES; - - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); - - s->cStringLength = length; - s->cString = [self allocMemoryWithSize: (length * 4) + 1]; - s->length = length; - - for (i = 0; i < length; i++) { - char buffer[4]; - of_unichar_t character = - (swap ? of_bswap16(string[i]) : string[i]); - size_t characterLen; - - /* Missing high surrogate */ - if ((character & 0xFC00) == 0xDC00) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - if ((character & 0xFC00) == 0xD800) { - uint16_t nextCharacter; - - if (length <= i + 1) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - nextCharacter = (swap - ? of_bswap16(string[i + 1]) - : string[i + 1]); - character = (((character & 0x3FF) << 10) | - (nextCharacter & 0x3FF)) + 0x10000; - - i++; - s->cStringLength--; - s->length--; - } - - characterLen = of_string_unicode_to_utf8( - character, buffer); - - switch (characterLen) { - case 1: - s->cString[j++] = buffer[0]; - break; - case 2: - s->UTF8 = YES; - s->cStringLength++; - - memcpy(s->cString + j, buffer, 2); - j += 2; - - break; - case 3: - s->UTF8 = YES; - s->cStringLength += 2; - - memcpy(s->cString + j, buffer, 3); - j += 3; - - break; - case 4: - s->UTF8 = YES; - s->cStringLength += 3; - - memcpy(s->cString + j, buffer, 4); - j += 4; - - break; - default: - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - } - } - - s->cString[j] = '\0'; - - @try { - s->cString = [self resizeMemory: s->cString - toSize: s->cStringLength + 1]; - } @catch (OFOutOfMemoryException *e) { - /* We don't care, as we only tried to make it smaller */ - } - } @catch (id e) { - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; } - initWithFormat: (OFConstantString*)format, ... { id ret; @@ -858,52 +727,14 @@ } - initWithFormat: (OFConstantString*)format arguments: (va_list)arguments { - self = [super init]; - - @try { - int cStringLength; - - if (format == nil) - @throw [OFInvalidArgumentException - exceptionWithClass: isa - selector: _cmd]; - - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); - - if ((cStringLength = of_vasprintf(&s->cString, - [format UTF8String], arguments)) == -1) - @throw [OFInvalidFormatException - exceptionWithClass: isa]; - - s->cStringLength = cStringLength; - - @try { - switch (of_string_check_utf8(s->cString, - cStringLength, &s->length)) { - case 1: - s->UTF8 = YES; - break; - case -1: - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - } - - [self addMemoryToPool: s->cString]; - } @catch (id e) { - free(s->cString); - @throw e; - } - } @catch (id e) { - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; } - initWithPath: (OFString*)firstComponent, ... { id ret; @@ -918,67 +749,14 @@ } - initWithPath: (OFString*)firstComponent arguments: (va_list)arguments { - self = [super init]; - - @try { - OFString *component; - size_t i, cStringLength; - va_list argumentsCopy; - - s = [self allocMemoryWithSize: sizeof(*s)]; - memset(s, 0, sizeof(*s)); - - /* - * First needs to be a call to be sure it is initialized, in - * case it's a constant string. - */ - s->cStringLength = [firstComponent UTF8StringLength]; - s->UTF8 = firstComponent->s->UTF8; - s->length = firstComponent->s->length; - - /* Calculate length and see if we need UTF-8 */ - va_copy(argumentsCopy, arguments); - while ((component = va_arg(argumentsCopy, OFString*)) != nil) { - /* First needs to be a call, see above */ - s->cStringLength += 1 + [component UTF8StringLength]; - s->length += 1 + component->s->length; - - if (component->s->UTF8) - s->UTF8 = YES; - } - - s->cString = [self allocMemoryWithSize: s->cStringLength + 1]; - - cStringLength = [firstComponent UTF8StringLength]; - memcpy(s->cString, [firstComponent UTF8String], cStringLength); - i = cStringLength; - - while ((component = va_arg(arguments, OFString*)) != nil) { - /* - * We already sent each component a message, so we can - * be sure they are initialized and access them - * directly. - */ - cStringLength = component->s->cStringLength; - - s->cString[i] = OF_PATH_DELIMITER; - memcpy(s->cString + i + 1, component->s->cString, - cStringLength); - - i += 1 + cStringLength; - } - - s->cString[i] = '\0'; - } @catch (id e) { - [self release]; - @throw e; - } - - return self; + Class c = isa; + [self release]; + @throw [OFNotImplementedException exceptionWithClass: c + selector: _cmd]; } - initWithContentsOfFile: (OFString*)path { return [self initWithContentsOfFile: path @@ -1096,15 +874,26 @@ - initWithSerialization: (OFXMLElement*)element { @try { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - if (![[element name] isEqual: [self className]] || - ![[element namespace] isEqual: OF_SERIALIZATION_NS]) + if (![[element namespace] isEqual: OF_SERIALIZATION_NS]) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; + + if ([self isKindOfClass: [OFMutableString class]]) { + if (![[element name] isEqual: @"OFMutableString"]) + @throw [OFInvalidArgumentException + exceptionWithClass: isa + selector: _cmd]; + } else { + if (![[element name] isEqual: @"OFString"]) + @throw [OFInvalidArgumentException + exceptionWithClass: isa + selector: _cmd]; + } self = [self initWithString: [element stringValue]]; [pool release]; } @catch (id e) { @@ -1115,72 +904,85 @@ return self; } - (const char*)UTF8String { - return s->cString; + /* TODO: Implement! */ + @throw [OFNotImplementedException exceptionWithClass: isa + selector: _cmd]; } - (const char*)cStringWithEncoding: (of_string_encoding_t)encoding { - switch (encoding) { - case OF_STRING_ENCODING_UTF_8: - return s->cString; - case OF_STRING_ENCODING_ASCII: - if (s->UTF8) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - return s->cString; - default: - @throw [OFNotImplementedException exceptionWithClass: isa - selector: _cmd]; - } + /* TODO: Implement! */ + @throw [OFNotImplementedException exceptionWithClass: isa + selector: _cmd]; } - (size_t)length { - return s->length; + @throw [OFNotImplementedException exceptionWithClass: isa + selector: _cmd]; } - (size_t)UTF8StringLength { - return s->cStringLength; + /* TODO: Implement! */ + @throw [OFNotImplementedException exceptionWithClass: isa + selector: _cmd]; } - (size_t)cStringLengthWithEncoding: (of_string_encoding_t)encoding { - switch (encoding) { - case OF_STRING_ENCODING_UTF_8: - return s->cStringLength; - case OF_STRING_ENCODING_ASCII: - if (s->UTF8) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - return s->cStringLength; - default: - @throw [OFNotImplementedException exceptionWithClass: isa - selector: _cmd]; - } + /* TODO: Implement! */ + @throw [OFNotImplementedException exceptionWithClass: isa + selector: _cmd]; +} + +- (of_unichar_t)characterAtIndex: (size_t)index +{ + @throw [OFNotImplementedException exceptionWithClass: isa + selector: _cmd]; +} + +- (void)getCharacters: (of_unichar_t*)buffer + inRange: (of_range_t)range +{ + size_t i; + + for (i = 0; i < range.length; i++) + buffer[i] = [self characterAtIndex: range.start + i]; } - (BOOL)isEqual: (id)object { + OFAutoreleasePool *pool; OFString *otherString; + const of_unichar_t *unicodeString, *otherUnicodeString; + size_t length; if (![object isKindOfClass: [OFString class]]) return NO; otherString = object; + length = [self length]; - if ([otherString UTF8StringLength] != s->cStringLength || - otherString->s->length != s->length) + if ([otherString length] != length) + return NO; + + pool = [[OFAutoreleasePool alloc] init]; + + unicodeString = [self unicodeString]; + otherUnicodeString = [otherString unicodeString]; + + if (memcmp(unicodeString, otherUnicodeString, + length * sizeof(of_unichar_t))) { + [pool release]; return NO; + } - if (strcmp(s->cString, otherString->s->cString)) - return NO; + [pool release]; return YES; } - copy @@ -1193,126 +995,120 @@ return [[OFMutableString alloc] initWithString: self]; } - (of_comparison_result_t)compare: (id)object { + OFAutoreleasePool *pool; OFString *otherString; - size_t otherCStringLength, minimumCStringLength; - int compare; + const of_unichar_t *unicodeString, *otherUnicodeString; + size_t i, minimumLength; if (![object isKindOfClass: [OFString class]]) @throw [OFInvalidArgumentException exceptionWithClass: isa selector: _cmd]; otherString = object; - otherCStringLength = [otherString UTF8StringLength]; - minimumCStringLength = (s->cStringLength > otherCStringLength - ? otherCStringLength : s->cStringLength); - - if ((compare = memcmp(s->cString, [otherString UTF8String], - minimumCStringLength)) == 0) { - if (s->cStringLength > otherCStringLength) - return OF_ORDERED_DESCENDING; - if (s->cStringLength < otherCStringLength) - return OF_ORDERED_ASCENDING; - return OF_ORDERED_SAME; - } - - if (compare > 0) - return OF_ORDERED_DESCENDING; - else - return OF_ORDERED_ASCENDING; + minimumLength = ([self length] > [otherString length] + ? [otherString length] : [self length]); + + pool = [[OFAutoreleasePool alloc] init]; + + unicodeString = [self unicodeString]; + otherUnicodeString = [otherString unicodeString]; + + for (i = 0; i < minimumLength; i++) { + if (unicodeString[i] > otherUnicodeString[i]) { + [pool release]; + return OF_ORDERED_DESCENDING; + } + + if (unicodeString[i] < otherUnicodeString[i]) { + [pool release]; + return OF_ORDERED_ASCENDING; + } + } + + [pool release]; + + if ([self length] > [otherString length]) + return OF_ORDERED_DESCENDING; + if ([self length] < [otherString length]) + return OF_ORDERED_ASCENDING; + + return OF_ORDERED_SAME; } - (of_comparison_result_t)caseInsensitiveCompare: (OFString*)otherString { - const char *otherCString; - size_t i, j, otherCStringLength, minimumCStringLength; - int compare; - - if (![otherString isKindOfClass: [OFString class]]) - @throw [OFInvalidArgumentException exceptionWithClass: isa - selector: _cmd]; - - otherCString = [otherString UTF8String]; - otherCStringLength = [otherString UTF8StringLength]; - - if (!s->UTF8) { - minimumCStringLength = (s->cStringLength > otherCStringLength - ? otherCStringLength : s->cStringLength); - - if ((compare = memcasecmp(s->cString, otherCString, - minimumCStringLength)) == 0) { - if (s->cStringLength > otherCStringLength) - return OF_ORDERED_DESCENDING; - if (s->cStringLength < otherCStringLength) - return OF_ORDERED_ASCENDING; - return OF_ORDERED_SAME; - } - - if (compare > 0) - return OF_ORDERED_DESCENDING; - else - return OF_ORDERED_ASCENDING; - } - - i = j = 0; - - while (i < s->cStringLength && j < otherCStringLength) { - of_unichar_t c1, c2; - size_t l1, l2; - - l1 = of_string_utf8_to_unicode(s->cString + i, - s->cStringLength - i, &c1); - l2 = of_string_utf8_to_unicode(otherCString + j, - otherCStringLength - j, &c2); - - if (l1 == 0 || l2 == 0 || c1 > 0x10FFFF || c2 > 0x10FFFF) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - if (c1 >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) { - of_unichar_t tc = - of_unicode_casefolding_table[c1 >> 8][c1 & 0xFF]; - - if (tc) - c1 = tc; - } - - if (c2 >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) { - of_unichar_t tc = - of_unicode_casefolding_table[c2 >> 8][c2 & 0xFF]; - - if (tc) - c2 = tc; - } - - if (c1 > c2) - return OF_ORDERED_DESCENDING; - if (c1 < c2) - return OF_ORDERED_ASCENDING; - - i += l1; - j += l2; - } - - if (s->cStringLength - i > otherCStringLength - j) - return OF_ORDERED_DESCENDING; - else if (s->cStringLength - i < otherCStringLength - j) + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + const of_unichar_t *string, *otherUnicodeString; + size_t i, length, otherLength, minimumLength; + + string = [self unicodeString]; + otherUnicodeString = [otherString unicodeString]; + length = [self length]; + otherLength = [otherString length]; + + minimumLength = (length > otherLength ? otherLength : length); + + for (i = 0; i < minimumLength; i++) { + of_unichar_t c = string[i]; + of_unichar_t oc = otherUnicodeString[i]; + + if (c >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) { + of_unichar_t tc = + of_unicode_casefolding_table[c >> 8][c & 0xFF]; + + if (tc) + c = tc; + } + + if (oc >> 8 < OF_UNICODE_CASEFOLDING_TABLE_SIZE) { + of_unichar_t tc = + of_unicode_casefolding_table[oc >> 8][oc & 0xFF]; + + if (tc) + oc = tc; + } + + if (c > oc) { + [pool release]; + return OF_ORDERED_DESCENDING; + } + if (c < oc) { + [pool release]; + return OF_ORDERED_ASCENDING; + } + } + + [pool release]; + + if (length > otherLength) + return OF_ORDERED_DESCENDING; + if (length < otherLength) return OF_ORDERED_ASCENDING; return OF_ORDERED_SAME; } - (uint32_t)hash { + const of_unichar_t *unicodeString = [self unicodeString]; + size_t i, length = [self length]; uint32_t hash; - size_t i; OF_HASH_INIT(hash); - for (i = 0; i < s->cStringLength; i++) - OF_HASH_ADD(hash, s->cString[i]); + + for (i = 0; i < length; i++) { + const of_unichar_t c = unicodeString[i]; + + OF_HASH_ADD(hash, (c & 0xFF000000) >> 24); + OF_HASH_ADD(hash, (c & 0x00FF0000) >> 16); + OF_HASH_ADD(hash, (c & 0x00FF0000) >> 8); + OF_HASH_ADD(hash, c & 0xFF); + } + OF_HASH_FINALIZE(hash); return hash; } @@ -1325,14 +1121,14 @@ { OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; OFXMLElement *element; OFString *className; - if ([self isKindOfClass: [OFConstantString class]]) - className = @"OFString"; + if ([self isKindOfClass: [OFMutableString class]]) + className = @"OFMutableString"; else - className = [self className]; + className = @"OFString"; element = [OFXMLElement elementWithName: className namespace: OF_SERIALIZATION_NS stringValue: self]; @@ -1341,105 +1137,119 @@ [element autorelease]; return element; } -- (of_unichar_t)characterAtIndex: (size_t)index -{ - of_unichar_t character; - - if (index >= s->length) - @throw [OFOutOfRangeException exceptionWithClass: isa]; - - if (!s->UTF8) - return s->cString[index]; - - index = of_string_index_to_position(s->cString, index, - s->cStringLength); - - if (!of_string_utf8_to_unicode(s->cString + index, - s->cStringLength - index, &character)) - @throw [OFInvalidEncodingException exceptionWithClass: isa]; - - return character; -} - - (size_t)indexOfFirstOccurrenceOfString: (OFString*)string { - const char *cString = [string UTF8String]; - size_t i, cStringLength = [string UTF8StringLength]; + OFAutoreleasePool *pool; + const of_unichar_t *unicodeString, *searchString; + size_t i, length, searchLength; - if (cStringLength == 0) - return 0; + if ((searchLength = [string length]) == 0) + return [self length]; - if (cStringLength > s->cStringLength) + if (searchLength > (length = [self length])) return OF_INVALID_INDEX; - for (i = 0; i <= s->cStringLength - cStringLength; i++) - if (!memcmp(s->cString + i, cString, cStringLength)) - return of_string_position_to_index(s->cString, i); + pool = [[OFAutoreleasePool alloc] init]; + + unicodeString = [self unicodeString]; + searchString = [string unicodeString]; + + for (i = 0; i <= length - searchLength; i++) { + if (!memcmp(unicodeString + i, searchString, + searchLength * sizeof(of_unichar_t))) { + [pool release]; + return i; + } + } + + [pool release]; return OF_INVALID_INDEX; } - (size_t)indexOfLastOccurrenceOfString: (OFString*)string { - const char *cString = [string UTF8String]; - size_t i, cStringLength = [string UTF8StringLength]; - - if (cStringLength == 0) - return of_string_position_to_index(s->cString, - s->cStringLength); - - if (cStringLength > s->cStringLength) - return OF_INVALID_INDEX; - - for (i = s->cStringLength - cStringLength;; i--) { - if (!memcmp(s->cString + i, cString, cStringLength)) - return of_string_position_to_index(s->cString, i); - - /* Did not match and we're at the last char */ - if (i == 0) - return OF_INVALID_INDEX; - } + OFAutoreleasePool *pool; + const of_unichar_t *unicodeString, *searchString; + size_t i, length, searchLength; + + if ((searchLength = [string length]) == 0) + return [self length]; + + if (searchLength > (length = [self length])) + return OF_INVALID_INDEX; + + pool = [[OFAutoreleasePool alloc] init]; + + unicodeString = [self unicodeString]; + searchString = [string unicodeString]; + + for (i = length - searchLength;; i--) { + if (!memcmp(unicodeString + i, searchString, + searchLength * sizeof(of_unichar_t))) { + [pool release]; + return i; + } + + /* Did not match and we're at the last character */ + if (i == 0) + break; + } + + [pool release]; + + return OF_INVALID_INDEX; } - (BOOL)containsString: (OFString*)string { - const char *cString = [string UTF8String]; - size_t i, cStringLength = string->s->cStringLength; + OFAutoreleasePool *pool; + const of_unichar_t *unicodeString, *searchString; + size_t i, length, searchLength; - if (cStringLength == 0) + if ((searchLength = [string length]) == 0) return YES; - if (cStringLength > s->cStringLength) + if (searchLength > (length = [self length])) return NO; - for (i = 0; i <= s->cStringLength - cStringLength; i++) - if (!memcmp(s->cString + i, cString, cStringLength)) + pool = [[OFAutoreleasePool alloc] init]; + + unicodeString = [self unicodeString]; + searchString = [string unicodeString]; + + for (i = 0; i <= length - searchLength; i++) { + if (!memcmp(unicodeString + i, searchString, + searchLength * sizeof(of_unichar_t))) { + [pool release]; return YES; + } + } + + [pool release]; return NO; } - (OFString*)substringWithRange: (of_range_t)range { - size_t start = range.start; - size_t end = range.start + range.length; + OFAutoreleasePool *pool; + OFString *ret; - if (end > s->length) + if (range.start + range.length > [self length]) @throw [OFOutOfRangeException exceptionWithClass: isa]; - if (s->UTF8) { - start = of_string_index_to_position(s->cString, start, - s->cStringLength); - end = of_string_index_to_position(s->cString, end, - s->cStringLength); - } - - return [OFString stringWithUTF8String: s->cString + start - length: end - start]; + pool = [[OFAutoreleasePool alloc] init]; + ret = [[OFString alloc] + initWithUnicodeString: [self unicodeString] + range.start + length: range.length]; + [pool release]; + + return [ret autorelease]; } - (OFString*)stringByAppendingString: (OFString*)string { OFMutableString *new; @@ -1531,58 +1341,98 @@ return new; } - (BOOL)hasPrefix: (OFString*)prefix { - size_t cStringLength = [prefix UTF8StringLength]; + OFAutoreleasePool *pool; + of_unichar_t *tmp; + const of_unichar_t *prefixString; + size_t prefixLength; + int compare; - if (cStringLength > s->cStringLength) + if ((prefixLength = [prefix length]) > [self length]) return NO; - return !memcmp(s->cString, [prefix UTF8String], cStringLength); + tmp = alloca(prefixLength * sizeof(of_unichar_t)); + [self getCharacters: tmp + inRange: of_range(0, prefixLength)]; + + pool = [[OFAutoreleasePool alloc] init]; + + prefixString = [prefix unicodeString]; + compare = memcmp(tmp, prefixString, + prefixLength * sizeof(of_unichar_t)); + + [pool release]; + + return !compare; } - (BOOL)hasSuffix: (OFString*)suffix { - size_t cStringLength = [suffix UTF8StringLength]; + OFAutoreleasePool *pool; + of_unichar_t *tmp; + const of_unichar_t *suffixString; + size_t length, suffixLength; + int compare; - if (cStringLength > s->cStringLength) + if ((suffixLength = [suffix length]) > [self length]) return NO; - return !memcmp(s->cString + (s->cStringLength - cStringLength), - [suffix UTF8String], cStringLength); + length = [self length]; + + tmp = alloca(suffixLength * sizeof(of_unichar_t)); + [self getCharacters: tmp + inRange: of_range(length - suffixLength, suffixLength)]; + + pool = [[OFAutoreleasePool alloc] init]; + + suffixString = [suffix unicodeString]; + compare = memcmp(tmp, suffixString, + suffixLength * sizeof(of_unichar_t)); + + [pool release]; + + return !compare; } - (OFArray*)componentsSeparatedByString: (OFString*)delimiter { OFAutoreleasePool *pool; - OFMutableArray *array; - const char *cString = [delimiter UTF8String]; - size_t cStringLength = [delimiter UTF8StringLength]; + OFMutableArray *array = [OFMutableArray array]; + const of_unichar_t *string, *delimiterString; + size_t length = [self length]; + size_t delimiterLength = [delimiter length]; size_t i, last; - array = [OFMutableArray array]; pool = [[OFAutoreleasePool alloc] init]; - if (cStringLength > s->cStringLength) { + string = [self unicodeString]; + delimiterString = [delimiter unicodeString]; + + if (delimiterLength > length) { [array addObject: [[self copy] autorelease]]; + [array makeImmutable]; + [pool release]; return array; } - for (i = 0, last = 0; i <= s->cStringLength - cStringLength; i++) { - if (memcmp(s->cString + i, cString, cStringLength)) + for (i = 0, last = 0; i <= length - delimiterLength; i++) { + if (memcmp(string + i, delimiterString, + delimiterLength * sizeof(of_unichar_t))) continue; - [array addObject: - [OFString stringWithUTF8String: s->cString + last - length: i - last]]; - i += cStringLength - 1; + [array addObject: [self substringWithRange: + of_range(last, i - last)]]; + + i += delimiterLength - 1; last = i + 1; } - [array addObject: [OFString stringWithUTF8String: s->cString + last]]; + [array addObject: + [self substringWithRange: of_range(last, length - last)]]; [array makeImmutable]; [pool release]; @@ -1591,42 +1441,43 @@ - (OFArray*)pathComponents { OFMutableArray *ret; OFAutoreleasePool *pool; - size_t i, last = 0, pathCStringLength = s->cStringLength; + const of_unichar_t *string; + size_t i, last = 0, length = [self length]; ret = [OFMutableArray array]; - if (pathCStringLength == 0) + if (length == 0) return ret; pool = [[OFAutoreleasePool alloc] init]; -#ifndef _WIN32 - if (s->cString[pathCStringLength - 1] == OF_PATH_DELIMITER) -#else - if (s->cString[pathCStringLength - 1] == '/' || - s->cString[pathCStringLength - 1] == '\\') -#endif - pathCStringLength--; - - for (i = 0; i < pathCStringLength; i++) { -#ifndef _WIN32 - if (s->cString[i] == OF_PATH_DELIMITER) { -#else - if (s->cString[i] == '/' || s->cString[i] == '\\') { -#endif - [ret addObject: - [OFString stringWithUTF8String: s->cString + last - length: i - last]]; + string = [self unicodeString]; + +#ifndef _WIN32 + if (string[length - 1] == OF_PATH_DELIMITER) +#else + if (string[length - 1] == '/' || string[length - 1] == '\\') +#endif + length--; + + for (i = 0; i < length; i++) { +#ifndef _WIN32 + if (string[i] == OF_PATH_DELIMITER) { +#else + if (string[i] == '/' || string[i] == '\\') { +#endif + [ret addObject: [self substringWithRange: + of_range(last, i - last)]]; + last = i + 1; } } - [ret addObject: [OFString stringWithUTF8String: s->cString + last - length: i - last]]; + [ret addObject: [self substringWithRange: of_range(last, i - last)]]; [ret makeImmutable]; [pool release]; @@ -1633,180 +1484,208 @@ return ret; } - (OFString*)lastPathComponent { - size_t pathCStringLength = s->cStringLength; + OFAutoreleasePool *pool; + const of_unichar_t *string; + size_t length = [self length]; ssize_t i; - if (pathCStringLength == 0) + if (length == 0) return @""; + pool = [[OFAutoreleasePool alloc] init]; + + string = [self unicodeString]; + #ifndef _WIN32 - if (s->cString[pathCStringLength - 1] == OF_PATH_DELIMITER) + if (string[length - 1] == OF_PATH_DELIMITER) #else - if (s->cString[pathCStringLength - 1] == '/' || - s->cString[pathCStringLength - 1] == '\\') + if (string[length - 1] == '/' || string[length - 1] == '\\') #endif - pathCStringLength--; + length--; - for (i = pathCStringLength - 1; i >= 0; i--) { + for (i = length - 1; i >= 0; i--) { #ifndef _WIN32 - if (s->cString[i] == OF_PATH_DELIMITER) { + if (string[i] == OF_PATH_DELIMITER) { #else - if (s->cString[i] == '/' || s->cString[i] == '\\') { + if (string[i] == '/' || string[i] == '\\') { #endif i++; break; } } + + [pool release]; /* * Only one component, but the trailing delimiter might have been * removed, so return a new string anyway. */ if (i < 0) i = 0; - return [OFString stringWithUTF8String: s->cString + i - length: pathCStringLength - i]; + return [self substringWithRange: of_range(i, length - i)]; } - (OFString*)stringByDeletingLastPathComponent { - size_t i, pathCStringLength = s->cStringLength; + OFAutoreleasePool *pool; + const of_unichar_t *string; + size_t i, length = [self length]; - if (pathCStringLength == 0) + if (length == 0) return @""; -#ifndef _WIN32 - if (s->cString[pathCStringLength - 1] == OF_PATH_DELIMITER) -#else - if (s->cString[pathCStringLength - 1] == '/' || - s->cString[pathCStringLength - 1] == '\\') -#endif - pathCStringLength--; - - if (pathCStringLength == 0) - return [OFString stringWithUTF8String: s->cString - length: 1]; - - for (i = pathCStringLength - 1; i >= 1; i--) -#ifndef _WIN32 - if (s->cString[i] == OF_PATH_DELIMITER) -#else - if (s->cString[i] == '/' || s->cString[i] == '\\') -#endif - return [OFString stringWithUTF8String: s->cString - length: i]; - -#ifndef _WIN32 - if (s->cString[0] == OF_PATH_DELIMITER) -#else - if (s->cString[0] == '/' || s->cString[0] == '\\') -#endif - return [OFString stringWithUTF8String: s->cString - length: 1]; + pool = [[OFAutoreleasePool alloc] init]; + + string = [self unicodeString]; + +#ifndef _WIN32 + if (string[length - 1] == OF_PATH_DELIMITER) +#else + if (string[length - 1] == '/' || string[length - 1] == '\\') +#endif + length--; + + if (length == 0) { + [pool release]; + return [self substringWithRange: of_range(0, 1)]; + } + + for (i = length - 1; i >= 1; i--) { +#ifndef _WIN32 + if (string[i] == OF_PATH_DELIMITER) { +#else + if (string[i] == '/' || string[i] == '\\') { +#endif + [pool release]; + return [self substringWithRange: of_range(0, i)]; + } + } + +#ifndef _WIN32 + if (string[0] == OF_PATH_DELIMITER) { +#else + if (string[0] == '/' || string[0] == '\\') { +#endif + [pool release]; + return [self substringWithRange: of_range(0, 1)]; + } + + [pool release]; return @"."; } - (intmax_t)decimalValue { - const char *cString = s->cString; - size_t cStringLength = s->cStringLength; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + const of_unichar_t *string = [self unicodeString]; + size_t length = [self length]; int i = 0; intmax_t value = 0; BOOL expectWhitespace = NO; - while (*cString == ' ' || *cString == '\t' || *cString == '\n' || - *cString == '\r' || *cString == '\f') { - cString++; - cStringLength--; + while (*string == ' ' || *string == '\t' || *string == '\n' || + *string == '\r' || *string == '\f') { + string++; + length--; + } + + if (length == 0) { + [pool release]; + return 0; } - if (cString[0] == '-' || cString[0] == '+') + if (string[0] == '-' || string[0] == '+') i++; - for (; i < cStringLength; i++) { + for (; i < length; i++) { if (expectWhitespace) { - if (cString[i] != ' ' && cString[i] != '\t' && - cString[i] != '\n' && cString[i] != '\r' && - cString[i] != '\f') + if (string[i] != ' ' && string[i] != '\t' && + string[i] != '\n' && string[i] != '\r' && + string[i] != '\f') @throw [OFInvalidFormatException exceptionWithClass: isa]; continue; } - if (cString[i] >= '0' && cString[i] <= '9') { + if (string[i] >= '0' && string[i] <= '9') { if (INTMAX_MAX / 10 < value || - INTMAX_MAX - value * 10 < cString[i] - '0') + INTMAX_MAX - value * 10 < string[i] - '0') @throw [OFOutOfRangeException exceptionWithClass: isa]; - value = (value * 10) + (cString[i] - '0'); - } else if (cString[i] == ' ' || cString[i] == '\t' || - cString[i] == '\n' || cString[i] == '\r' || - cString[i] == '\f') + value = (value * 10) + (string[i] - '0'); + } else if (string[i] == ' ' || string[i] == '\t' || + string[i] == '\n' || string[i] == '\r' || + string[i] == '\f') expectWhitespace = YES; else @throw [OFInvalidFormatException exceptionWithClass: isa]; } - if (cString[0] == '-') + if (string[0] == '-') value *= -1; + + [pool release]; return value; } - (uintmax_t)hexadecimalValue { - const char *cString = s->cString; - size_t cStringLength = s->cStringLength; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + const of_unichar_t *string = [self unicodeString]; + size_t length = [self length]; int i = 0; uintmax_t value = 0; BOOL expectWhitespace = NO, foundValue = NO; - while (*cString == ' ' || *cString == '\t' || *cString == '\n' || - *cString == '\r' || *cString == '\f') { - cString++; - cStringLength--; - } - - if (cStringLength == 0) - return 0; - - if (cStringLength >= 2 && cString[0] == '0' && cString[1] == 'x') - i = 2; - else if (cStringLength >= 1 && (cString[0] == 'x' || cString[0] == '$')) - i = 1; - - for (; i < cStringLength; i++) { + while (*string == ' ' || *string == '\t' || *string == '\n' || + *string == '\r' || *string == '\f') { + string++; + length--; + } + + if (length == 0) { + [pool release]; + return 0; + } + + if (length >= 2 && string[0] == '0' && string[1] == 'x') + i = 2; + else if (length >= 1 && (string[0] == 'x' || string[0] == '$')) + i = 1; + + for (; i < length; i++) { uintmax_t newValue; if (expectWhitespace) { - if (cString[i] != ' ' && cString[i] != '\t' && - cString[i] != '\n' && cString[i] != '\r' && - cString[i] != '\f') + if (string[i] != ' ' && string[i] != '\t' && + string[i] != '\n' && string[i] != '\r' && + string[i] != '\f') @throw [OFInvalidFormatException exceptionWithClass: isa]; continue; } - if (cString[i] >= '0' && cString[i] <= '9') { - newValue = (value << 4) | (cString[i] - '0'); - foundValue = YES; - } else if (cString[i] >= 'A' && cString[i] <= 'F') { - newValue = (value << 4) | (cString[i] - 'A' + 10); - foundValue = YES; - } else if (cString[i] >= 'a' && cString[i] <= 'f') { - newValue = (value << 4) | (cString[i] - 'a' + 10); - foundValue = YES; - } else if (cString[i] == 'h' || cString[i] == ' ' || - cString[i] == '\t' || cString[i] == '\n' || - cString[i] == '\r' || cString[i] == '\f') { + if (string[i] >= '0' && string[i] <= '9') { + newValue = (value << 4) | (string[i] - '0'); + foundValue = YES; + } else if (string[i] >= 'A' && string[i] <= 'F') { + newValue = (value << 4) | (string[i] - 'A' + 10); + foundValue = YES; + } else if (string[i] >= 'a' && string[i] <= 'f') { + newValue = (value << 4) | (string[i] - 'a' + 10); + foundValue = YES; + } else if (string[i] == 'h' || string[i] == ' ' || + string[i] == '\t' || string[i] == '\n' || + string[i] == '\r' || string[i] == '\f') { expectWhitespace = YES; continue; } else @throw [OFInvalidFormatException exceptionWithClass: isa]; @@ -1818,16 +1697,19 @@ } if (!foundValue) @throw [OFInvalidFormatException exceptionWithClass: isa]; + [pool release]; + return value; } - (float)floatValue { - const char *cString = s->cString; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + const char *cString = [self UTF8String]; char *endPointer = NULL; float value; while (*cString == ' ' || *cString == '\t' || *cString == '\n' || *cString == '\r' || *cString == '\f') @@ -1842,16 +1724,19 @@ *endPointer != '\n' && *endPointer != '\r' && *endPointer != '\f') @throw [OFInvalidFormatException exceptionWithClass: isa]; + [pool release]; + return value; } - (double)doubleValue { - const char *cString = s->cString; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + const char *cString = [self UTF8String]; char *endPointer = NULL; double value; while (*cString == ' ' || *cString == '\t' || *cString == '\n' || *cString == '\r' || *cString == '\f') @@ -1866,77 +1751,58 @@ *endPointer != '\n' && *endPointer != '\r' && *endPointer != '\f') @throw [OFInvalidFormatException exceptionWithClass: isa]; + [pool release]; + return value; } - (const of_unichar_t*)unicodeString { OFObject *object = [[[OFObject alloc] init] autorelease]; + size_t length = [self length]; of_unichar_t *ret; - size_t i, j; - ret = [object allocMemoryForNItems: s->length + 1 + ret = [object allocMemoryForNItems: length + 1 ofSize: sizeof(of_unichar_t)]; - - i = 0; - j = 0; - - while (i < s->cStringLength) { - of_unichar_t c; - size_t cLen; - - cLen = of_string_utf8_to_unicode(s->cString + i, - s->cStringLength - i, &c); - - if (cLen == 0 || c > 0x10FFFF) - @throw [OFInvalidEncodingException - exceptionWithClass: isa]; - - ret[j++] = c; - i += cLen; - } - - ret[j] = 0; + [self getCharacters: ret + inRange: of_range(0, length)]; + ret[length] = 0; return ret; } - (const uint16_t*)UTF16String { OFObject *object = [[[OFObject alloc] init] autorelease]; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; + const of_unichar_t *unicodeString = [self unicodeString]; + size_t length = [self length]; uint16_t *ret; size_t i, j; /* Allocate memory for the worst case */ - ret = [object allocMemoryForNItems: s->length * 2 + 1 + ret = [object allocMemoryForNItems: length * 2 + 1 ofSize: sizeof(uint16_t)]; - i = 0; j = 0; - while (i < s->cStringLength) { - of_unichar_t c; - size_t cLen; - - cLen = of_string_utf8_to_unicode(s->cString + i, - s->cStringLength - i, &c); - - if (cLen == 0 || c > 0x10FFFF) + for (i = 0; i < length; i++) { + of_unichar_t c = unicodeString[i]; + + if (c > 0x10FFFF) @throw [OFInvalidEncodingException exceptionWithClass: isa]; if (c > 0xFFFF) { c -= 0x10000; ret[j++] = of_bswap16_if_le(0xD800 | (c >> 10)); ret[j++] = of_bswap16_if_le(0xDC00 | (c & 0x3FF)); } else ret[j++] = of_bswap16_if_le(c); - - i += cLen; } ret[j] = 0; @try { @@ -1944,10 +1810,12 @@ toNItems: j + 1 ofSize: sizeof(uint16_t)]; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only tried to make it smaller */ } + + [pool release]; return ret; } - (void)writeToFile: (OFString*)path @@ -1963,41 +1831,39 @@ } #ifdef OF_HAVE_BLOCKS - (void)enumerateLinesUsingBlock: (of_string_line_enumeration_block_t)block { - OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init]; - const char *cString = s->cString; - const char *last = cString; + OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init], *pool2; + const of_unichar_t *string = [self unicodeString]; + size_t i, last = 0, length = [self length]; BOOL stop = NO, lastCarriageReturn = NO; - while (!stop && *cString != 0) { - if (lastCarriageReturn && *cString == '\n') { - lastCarriageReturn = NO; + pool2 = [[OFAutoreleasePool alloc] init]; - cString++; + for (i = 0; i < length && !stop; i++) { + if (lastCarriageReturn && string[i] == '\n') { + lastCarriageReturn = NO; last++; continue; } - if (*cString == '\n' || *cString == '\r') { - block([OFString - stringWithUTF8String: last - length: cString - last], &stop); - last = cString + 1; + if (string[i] == '\n' || string[i] == '\r') { + block([self substringWithRange: + of_range(last, i - last)], &stop); + last = i + 1; - [pool releaseObjects]; + [pool2 releaseObjects]; } - lastCarriageReturn = (*cString == '\r'); - cString++; + lastCarriageReturn = (string[i] == '\r'); } if (!stop) - block([OFString stringWithUTF8String: last - length: cString - last], &stop); + block([self substringWithRange: of_range(last, i - last)], + &stop); [pool release]; } #endif @end