Index: src/OFMutableString.h ================================================================== --- src/OFMutableString.h +++ src/OFMutableString.h @@ -27,10 +27,26 @@ * @param index The index where to set the character */ - (void)setCharacter: (of_unichar_t)character atIndex: (size_t)index; +/*! + * @brief Appends another OFString to the OFMutableString. + * + * @param string An OFString to append + */ +- (void)appendString: (OFString*)string; + +/*! + * @brief Appends the specified characters to the OFMutableString. + * + * @param characters An array of characters to append + * @param length The length of the array of characters + */ +- (void)appendCharacters: (of_unichar_t*)characters + length: (size_t)length; + /*! * @brief Appends a UTF-8 encoded C string to the OFMutableString. * * @param UTF8String A UTF-8 encoded C string to append */ @@ -65,17 +81,10 @@ */ - (void)appendCString: (const char*)cString encoding: (of_string_encoding_t)encoding length: (size_t)cStringLength; -/*! - * @brief Appends another OFString to the OFMutableString. - * - * @param string An OFString to append - */ -- (void)appendString: (OFString*)string; - /*! * @brief Appends a formatted string to the OFMutableString. * * See printf for the format syntax. As an addition, %@ is available as format * specifier for objects. Index: src/OFMutableString.m ================================================================== --- src/OFMutableString.m +++ src/OFMutableString.m @@ -284,10 +284,27 @@ [self replaceCharactersInRange: of_range(index, 1) withString: string]; objc_autoreleasePoolPop(pool); } + +- (void)appendString: (OFString*)string +{ + return [self insertString: string + atIndex: [self length]]; +} + +- (void)appendCharacters: (of_unichar_t*)characters + length: (size_t)length +{ + void *pool = objc_autoreleasePoolPush(); + + return [self appendString: [OFString stringWithCharacters: characters + length: length]]; + + objc_autoreleasePoolPop(pool); +} - (void)appendUTF8String: (const char*)UTF8String { void *pool = objc_autoreleasePoolPush(); @@ -329,16 +346,10 @@ length: cStringLength]]; objc_autoreleasePoolPop(pool); } -- (void)appendString: (OFString*)string -{ - return [self insertString: string - atIndex: [self length]]; -} - - (void)appendFormat: (OFConstantString*)format, ... { va_list arguments; va_start(arguments, format); Index: src/OFMutableString_UTF8.m ================================================================== --- src/OFMutableString_UTF8.m +++ src/OFMutableString_UTF8.m @@ -388,10 +388,71 @@ if (((OFString_UTF8*)string)->s->isUTF8) s->isUTF8 = YES; } else s->isUTF8 = YES; } + +- (void)appendCharacters: (of_unichar_t*)characters + length: (size_t)length +{ + char *tmp; + + tmp = [self allocMemoryWithSize: (length * 4) + 1]; + @try { + size_t i, j = 0; + BOOL isUTF8 = NO; + + for (i = 0; i < length; i++) { + char buffer[4]; + + switch (of_string_utf8_encode(characters[i], buffer)) { + case 1: + tmp[j++] = buffer[0]; + break; + case 2: + isUTF8 = YES; + + memcpy(tmp + j, buffer, 2); + j += 2; + + break; + case 3: + isUTF8 = YES; + + memcpy(tmp + j, buffer, 3); + j += 3; + + break; + case 4: + isUTF8 = YES; + + memcpy(tmp + j, buffer, 4); + j += 4; + + break; + default: + @throw [OFInvalidEncodingException + exceptionWithClass: [self class]]; + } + } + + tmp[j] = '\0'; + + s->hashed = NO; + s->cString = [self resizeMemory: s->cString + size: s->cStringLength + j + 1]; + memcpy(s->cString + s->cStringLength, tmp, j + 1); + + s->cStringLength += j; + s->length += length; + + if (isUTF8) + s->isUTF8 = YES; + } @finally { + [self freeMemory: tmp]; + } +} - (void)appendFormat: (OFConstantString*)format arguments: (va_list)arguments { char *UTF8String; Index: src/OFString_UTF8.m ================================================================== --- src/OFString_UTF8.m +++ src/OFString_UTF8.m @@ -422,11 +422,10 @@ } else if (byteOrder != OF_BYTE_ORDER_NATIVE) swap = YES; s = &s_store; - s->cStringLength = length; s->cString = [self allocMemoryWithSize: (length * 4) + 1]; s->length = length; for (i = 0; i < length; i++) { char buffer[4]; @@ -438,27 +437,24 @@ case 1: s->cString[j++] = buffer[0]; break; case 2: s->isUTF8 = YES; - s->cStringLength++; memcpy(s->cString + j, buffer, 2); j += 2; break; case 3: s->isUTF8 = YES; - s->cStringLength += 2; memcpy(s->cString + j, buffer, 3); j += 3; break; case 4: s->isUTF8 = YES; - s->cStringLength += 3; memcpy(s->cString + j, buffer, 4); j += 4; break; @@ -467,14 +463,15 @@ exceptionWithClass: [self class]]; } } s->cString[j] = '\0'; + s->cStringLength = j; @try { s->cString = [self resizeMemory: s->cString - size: s->cStringLength + 1]; + size: j + 1]; } @catch (OFOutOfMemoryException *e) { /* We don't care, as we only tried to make it smaller */ } } @catch (id e) { [self release]; Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -116,10 +116,14 @@ TEST(@"-[appendString:] and -[appendUTF8String:]", R([s[1] appendUTF8String: "1๐„ž"]) && R([s[1] appendString: @"3"]) && R([s[0] appendString: s[1]]) && [s[0] isEqual: @"tรคsโ‚ฌ1๐„ž3"]) + TEST(@"-[appendCharacters:length:]", + R([s[1] appendCharacters: ucstr + 6 + length: 2]) && [s[1] isEqual: @"1๐„ž3r๐Ÿ€บ"]) + TEST(@"-[length]", [s[0] length] == 7) TEST(@"-[UTF8StringLength]", [s[0] UTF8StringLength] == 13) TEST(@"-[hash]", [s[0] hash] == 0x705583C0) TEST(@"-[characterAtIndex:]", [s[0] characterAtIndex: 0] == 't' &&