Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -560,10 +560,25 @@ * @return An initialized OFString */ - initWithContentsOfURL: (OFURL*)URL encoding: (of_string_encoding_t)encoding; +/*! + * @brief Writes the OFString into the specified C string with the specified + * encoding. + * + * @param cString The C string to write into + * @param maxLength The maximum number of bytes to write into the C string, + * including the terminating zero + * @param encoding The encoding to use for writing into the C string + * @return The number of bytes written into the C string, without the + * terminating zero + */ +- (size_t)getCString: (char*)cString + maxLength: (size_t)maxLength + encoding: (of_string_encoding_t)encoding; + /*! * @brief Returns the OFString as a C string in the specified encoding. * * The result is valid until the autorelease pool is released. If you want to * use the result outside the scope of the current autorelease pool, you have to Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -18,12 +18,10 @@ #include #include #include -#include - #include #import "OFString.h" #import "OFString_UTF8.h" #import "OFArray.h" @@ -987,52 +985,44 @@ } return self; } -- (const char*)cStringWithEncoding: (of_string_encoding_t)encoding +- (size_t)getCString: (char*)cString + maxLength: (size_t)maxLength + encoding: (of_string_encoding_t)encoding { const of_unichar_t *characters = [self characters]; size_t i, length = [self length]; - OFObject *object = [[[OFObject alloc] init] autorelease]; - char *cString; switch (encoding) { case OF_STRING_ENCODING_UTF_8:; - size_t cStringLength, j = 0; - - cString = [object allocMemoryWithSize: (length * 4) + 1]; - cStringLength = length; + size_t j = 0; for (i = 0; i < length; i++) { char buffer[4]; size_t len = of_string_utf8_encode(characters[i], buffer); + /* + * Check for one more than the current index, as we + * need one for the terminating zero. + */ + if (j + len >= maxLength) + @throw [OFOutOfRangeException + exceptionWithClass: [self class]]; + switch (len) { case 1: cString[j++] = buffer[0]; - break; - case 2: - cStringLength++; - - memcpy(cString + j, buffer, 2); - j += 2; - - break; - case 3: - cStringLength += 2; - - memcpy(cString + j, buffer, 3); - j += 3; - - break; - case 4: - cStringLength += 3; - - memcpy(cString + j, buffer, 4); - j += 4; + + break; + case 2: + case 3: + case 4: + memcpy(cString + j, buffer, len); + j += len; break; default: @throw [OFInvalidEncodingException exceptionWithClass: [self class]]; @@ -1039,22 +1029,15 @@ } } cString[j] = '\0'; - assert(j == cStringLength); - - @try { - cString = [object resizeMemory: cString - size: cStringLength + 1]; - } @catch (OFOutOfMemoryException *e) { - /* We don't care, as we only tried to make it smaller */ - } - - break; + return j; case OF_STRING_ENCODING_ASCII: - cString = [object allocMemoryWithSize: length + 1]; + if (length + 1 > maxLength) + @throw [OFOutOfRangeException + exceptionWithClass: [self class]]; for (i = 0; i < length; i++) { if OF_UNLIKELY (characters[i] > 0x80) @throw [OFInvalidEncodingException exceptionWithClass: [self class]]; @@ -1062,13 +1045,15 @@ cString[i] = (char)characters[i]; } cString[i] = '\0'; - break; + return length; case OF_STRING_ENCODING_ISO_8859_1: - cString = [object allocMemoryWithSize: length + 1]; + if (length + 1 > maxLength) + @throw [OFOutOfRangeException + exceptionWithClass: [self class]]; for (i = 0; i < length; i++) { if OF_UNLIKELY (characters[i] > 0xFF) @throw [OFInvalidEncodingException exceptionWithClass: [self class]]; @@ -1076,13 +1061,15 @@ cString[i] = (uint8_t)characters[i]; } cString[i] = '\0'; - break; + return length; case OF_STRING_ENCODING_ISO_8859_15: - cString = [object allocMemoryWithSize: length + 1]; + if (length + 1 > maxLength) + @throw [OFOutOfRangeException + exceptionWithClass: [self class]]; for (i = 0; i < length; i++) { of_unichar_t c = characters[i]; switch (c) { @@ -1132,13 +1119,15 @@ cString[i] = (uint8_t)c; } cString[i] = '\0'; - break; + return length; case OF_STRING_ENCODING_WINDOWS_1252: - cString = [object allocMemoryWithSize: length + 1]; + if (length + 1 > maxLength) + @throw [OFOutOfRangeException + exceptionWithClass: [self class]]; for (i = 0; i < length; i++) { of_unichar_t c = characters[i]; if OF_UNLIKELY (c >= 0x80 && c <= 0x9F) @@ -1236,10 +1225,52 @@ cString[i] = (uint8_t)c; } cString[i] = '\0'; + return length; + default: + @throw [OFNotImplementedException + exceptionWithClass: [self class] + selector: _cmd]; + } +} + +- (const char*)cStringWithEncoding: (of_string_encoding_t)encoding +{ + OFObject *object = [[[OFObject alloc] init] autorelease]; + size_t length = [self length]; + char *cString; + + switch (encoding) { + case OF_STRING_ENCODING_UTF_8:; + size_t cStringLength; + + cString = [object allocMemoryWithSize: (length * 4) + 1]; + + cStringLength = [self getCString: cString + maxLength: (length * 4) + 1 + encoding: OF_STRING_ENCODING_UTF_8]; + + @try { + cString = [object resizeMemory: cString + size: cStringLength + 1]; + } @catch (OFOutOfMemoryException *e) { + /* We don't care, as we only tried to make it smaller */ + } + + break; + case OF_STRING_ENCODING_ASCII: + case OF_STRING_ENCODING_ISO_8859_1: + case OF_STRING_ENCODING_ISO_8859_15: + case OF_STRING_ENCODING_WINDOWS_1252: + cString = [object allocMemoryWithSize: length + 1]; + + [self getCString: cString + maxLength: length + 1 + encoding: encoding]; + break; default: @throw [OFNotImplementedException exceptionWithClass: [self class] selector: _cmd]; Index: src/OFString_UTF8.m ================================================================== --- src/OFString_UTF8.m +++ src/OFString_UTF8.m @@ -415,34 +415,24 @@ s->cString = [self allocMemoryWithSize: (length * 4) + 1]; s->length = length; for (i = 0; i < length; i++) { char buffer[4]; + size_t len = of_string_utf8_encode(characters[i], + buffer); - switch (of_string_utf8_encode(characters[i], buffer)) { + switch (len) { case 1: s->cString[j++] = buffer[0]; break; case 2: - s->isUTF8 = YES; - - memcpy(s->cString + j, buffer, 2); - j += 2; - - break; case 3: - s->isUTF8 = YES; - - memcpy(s->cString + j, buffer, 3); - j += 3; - - break; case 4: s->isUTF8 = YES; - memcpy(s->cString + j, buffer, 4); - j += 4; + memcpy(s->cString + j, buffer, len); + j += len; break; default: @throw [OFInvalidEncodingException exceptionWithClass: [self class]]; @@ -486,19 +476,18 @@ } 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]; of_unichar_t character = (swap ? OF_BSWAP16(string[i]) : string[i]); - size_t characterLen; + size_t len; /* Missing high surrogate */ if ((character & 0xFC00) == 0xDC00) @throw [OFInvalidEncodingException exceptionWithClass: [self class]]; @@ -520,55 +509,40 @@ character = (((character & 0x3FF) << 10) | (nextCharacter & 0x3FF)) + 0x10000; i++; - s->cStringLength--; s->length--; } - characterLen = of_string_utf8_encode(character, buffer); + len = of_string_utf8_encode(character, buffer); - switch (characterLen) { + switch (len) { 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; + memcpy(s->cString + j, buffer, len); + j += len; break; default: @throw [OFInvalidEncodingException 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]; @@ -603,37 +577,25 @@ s->cString = [self allocMemoryWithSize: (length * 4) + 1]; s->length = length; for (i = 0; i < length; i++) { char buffer[4]; - size_t characterLen = of_string_utf8_encode( + size_t len = of_string_utf8_encode( (swap ? OF_BSWAP32(characters[i]) : characters[i]), buffer); - switch (characterLen) { + switch (len) { case 1: s->cString[j++] = buffer[0]; break; case 2: - s->isUTF8 = YES; - - memcpy(s->cString + j, buffer, 2); - j += 2; - - break; case 3: - s->isUTF8 = YES; - - memcpy(s->cString + j, buffer, 3); - j += 3; - - break; case 4: s->isUTF8 = YES; - memcpy(s->cString + j, buffer, 4); - j += 4; + memcpy(s->cString + j, buffer, len); + j += len; break; default: @throw [OFInvalidEncodingException exceptionWithClass: [self class]]; @@ -773,21 +735,45 @@ if (s != NULL && s->freeWhenDone != NULL) free(s->freeWhenDone); [super dealloc]; } + +- (size_t)getCString: (char*)cString + maxLength: (size_t)maxLength + encoding: (of_string_encoding_t)encoding +{ + switch (encoding) { + case OF_STRING_ENCODING_ASCII: + if (s->isUTF8) + @throw [OFInvalidEncodingException + exceptionWithClass: [self class]]; + /* intentional fall-through */ + case OF_STRING_ENCODING_UTF_8: + if (s->cStringLength + 1 > maxLength) + @throw [OFOutOfRangeException + exceptionWithClass: [self class]]; + + memcpy(cString, s->cString, s->cStringLength + 1); + + return s->cStringLength; + default: + return [super getCString: cString + maxLength: maxLength + encoding: encoding]; + } +} - (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->isUTF8) @throw [OFInvalidEncodingException exceptionWithClass: [self class]]; - + /* intentional fall-through */ + case OF_STRING_ENCODING_UTF_8: return s->cString; default: return [super cStringWithEncoding: encoding]; } }