Index: src/OFConstantString.m ================================================================== --- src/OFConstantString.m +++ src/OFConstantString.m @@ -97,11 +97,11 @@ ivars = OFAllocZeroedMemory(1, sizeof(*ivars)); ivars->cString = _cString; ivars->cStringLength = _cStringLength; switch (_OFUTF8StringCheck(ivars->cString, ivars->cStringLength, - &ivars->length)) { + &ivars->length, &ivars->containsNull)) { case 1: ivars->isUTF8 = true; break; case -1: OFFreeMemory(ivars); Index: src/OFMutableUTF8String.m ================================================================== --- src/OFMutableUTF8String.m +++ src/OFMutableUTF8String.m @@ -206,10 +206,13 @@ _s->cStringLength); if (idx >= _s->cStringLength) @throw [OFOutOfRangeException exception]; + if (character == 0) + _s->containsNull = true; + /* Shortcut if old and new character both are ASCII */ if (character < 0x80 && !(_s->cString[idx] & 0x80)) { _s->hasHash = false; _s->cString[idx] = character; return; @@ -270,11 +273,12 @@ memcmp(UTF8String, "\xEF\xBB\xBF", 3) == 0) { UTF8String += 3; UTF8StringLength -= 3; } - switch (_OFUTF8StringCheck(UTF8String, UTF8StringLength, &length)) { + switch (_OFUTF8StringCheck(UTF8String, UTF8StringLength, &length, + &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; @@ -299,11 +303,12 @@ memcmp(UTF8String, "\xEF\xBB\xBF", 3) == 0) { UTF8String += 3; UTF8StringLength -= 3; } - switch (_OFUTF8StringCheck(UTF8String, UTF8StringLength, &length)) { + switch (_OFUTF8StringCheck(UTF8String, UTF8StringLength, &length, + &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; @@ -352,11 +357,11 @@ size_t UTF8StringLength; if (string == nil) @throw [OFInvalidArgumentException exception]; - UTF8String = string.UTF8String; + UTF8String = [string insecureCStringWithEncoding: OFStringEncodingUTF8]; UTF8StringLength = string.UTF8StringLength; _s->hasHash = false; _s->cString = OFResizeMemory(_s->cString, _s->cStringLength + UTF8StringLength + 1, 1); @@ -369,13 +374,16 @@ if ([string isKindOfClass: [OFUTF8String class]] || [string isKindOfClass: [OFMutableUTF8String class]]) { if (((OFMutableUTF8String *)string)->_s->isUTF8) _s->isUTF8 = true; + + if (((OFMutableUTF8String *)string)->_s->containsNull) + _s->containsNull = true; } else { switch (_OFUTF8StringCheck(UTF8String, UTF8StringLength, - NULL)) { + NULL, &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; @@ -387,11 +395,11 @@ { char *tmp = OFAllocMemory((length * 4) + 1, 1); @try { size_t j = 0; - bool isUTF8 = false; + bool isUTF8 = false, containsNull = false; for (size_t i = 0; i < length; i++) { size_t len = _OFUTF8StringEncode(characters[i], tmp + j); @@ -398,10 +406,13 @@ if (len == 0) @throw [OFInvalidEncodingException exception]; if (len > 1) isUTF8 = true; + + if (characters[i] == 0) + containsNull = true; j += len; } tmp[j] = '\0'; @@ -414,10 +425,13 @@ _s->cStringLength += j; _s->length += length; if (isUTF8) _s->isUTF8 = true; + + if (containsNull) + _s->containsNull = true; } @finally { OFFreeMemory(tmp); } } @@ -450,11 +464,11 @@ if (_s->isUTF8) idx = _OFUTF8StringIndexToPosition(_s->cString, idx, _s->cStringLength); - UTF8String = string.UTF8String; + UTF8String = [string insecureCStringWithEncoding: OFStringEncodingUTF8]; UTF8StringLength = string.UTF8StringLength; newCStringLength = _s->cStringLength + UTF8StringLength; _s->hasHash = false; _s->cString = OFResizeMemory(_s->cString, newCStringLength + 1, 1); @@ -469,13 +483,16 @@ if ([string isKindOfClass: [OFUTF8String class]] || [string isKindOfClass: [OFMutableUTF8String class]]) { if (((OFMutableUTF8String *)string)->_s->isUTF8) _s->isUTF8 = true; + + if (((OFMutableUTF8String *)string)->_s->containsNull) + _s->containsNull = true; } else { switch (_OFUTF8StringCheck(UTF8String, UTF8StringLength, - NULL)) { + NULL, &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; @@ -502,10 +519,18 @@ _s->cStringLength - end); _s->hasHash = false; _s->length -= range.length; _s->cStringLength -= end - start; _s->cString[_s->cStringLength] = 0; + + if (_s->containsNull) { + _s->containsNull = false; + + for (size_t i = 0; i < _s->cStringLength; i++) + if (_s->cString[i] == '\0') + _s->containsNull = true; + } @try { _s->cString = OFResizeMemory(_s->cString, _s->cStringLength + 1, 1); } @catch (OFOutOfMemoryException *e) { @@ -535,11 +560,12 @@ _s->cStringLength); end = _OFUTF8StringIndexToPosition(_s->cString, end, _s->cStringLength); } - replacementString = replacement.UTF8String; + replacementString = + [replacement insecureCStringWithEncoding: OFStringEncodingUTF8]; replacementLength = replacement.UTF8StringLength; newCStringLength = _s->cStringLength - (end - start) + replacementLength; _s->hasHash = false; @@ -574,29 +600,42 @@ if ([replacement isKindOfClass: [OFUTF8String class]] || [replacement isKindOfClass: [OFMutableUTF8String class]]) { if (((OFMutableUTF8String *)replacement)->_s->isUTF8) _s->isUTF8 = true; + + if (((OFMutableUTF8String *)replacement)->_s->containsNull) + _s->containsNull = true; } else { switch (_OFUTF8StringCheck(replacementString, replacementLength, - NULL)) { + NULL, &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; } } + + if (_s->containsNull) { + _s->containsNull = false; + + for (size_t i = 0; i < _s->cStringLength; i++) + if (_s->cString[i] == '\0') + _s->containsNull = true; + } } - (void)replaceOccurrencesOfString: (OFString *)string withString: (OFString *)replacement options: (int)options range: (OFRange)range { - const char *searchString = string.UTF8String; - const char *replacementString = replacement.UTF8String; + const char *searchString = + [string insecureCStringWithEncoding: OFStringEncodingUTF8]; + const char *replacementString = + [replacement insecureCStringWithEncoding: OFStringEncodingUTF8]; size_t searchLength = string.UTF8StringLength; size_t replacementLength = replacement.UTF8StringLength; size_t last, newCStringLength, newLength; char *newCString; @@ -667,20 +706,31 @@ if ([replacement isKindOfClass: [OFUTF8String class]] || [replacement isKindOfClass: [OFMutableUTF8String class]]) { if (((OFMutableUTF8String *)replacement)->_s->isUTF8) _s->isUTF8 = true; + + if (((OFMutableUTF8String *)replacement)->_s->containsNull) + _s->containsNull = true; } else { switch (_OFUTF8StringCheck(replacementString, replacementLength, - NULL)) { + NULL, &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; } } + + if (_s->containsNull) { + _s->containsNull = false; + + for (size_t i = 0; i < _s->cStringLength; i++) + if (_s->cString[i] == '\0') + _s->containsNull = true; + } } - (void)deleteLeadingWhitespaces { size_t i; Index: src/OFSequencedPacketSocket.h ================================================================== --- src/OFSequencedPacketSocket.h +++ src/OFSequencedPacketSocket.h @@ -275,11 +275,11 @@ #ifdef OF_HAVE_BLOCKS /** * @brief Asynchronously receives a packet and stores it into the specified * buffer. * - * @deprecated Use @ref asyncReceiveIntoBuffer:lenght:handler: instead. + * @deprecated Use @ref asyncReceiveIntoBuffer:length:handler: instead. * * If the buffer is too small, the receive operation fails. * * @param buffer The buffer to write the packet to * @param length The length of the buffer @@ -291,11 +291,11 @@ */ - (void)asyncReceiveIntoBuffer: (void *)buffer length: (size_t)length block: (OFSequencedPacketSocketAsyncReceiveBlock)block OF_DEPRECATED(ObjFW, 1, 2, - "Use -[asyncReceiveIntoBuffer:lenght:handler:] instead"); + "Use -[asyncReceiveIntoBuffer:length:handler:] instead"); /** * @brief Asynchronously receives a packet and stores it into the specified * buffer. * Index: src/OFString+JSONParsing.m ================================================================== --- src/OFString+JSONParsing.m +++ src/OFString+JSONParsing.m @@ -188,10 +188,14 @@ break; case 't': buffer[i++] = '\t'; (*pointer)++; break; + case '0': + buffer[i++] = '\0'; + (*pointer)++; + break; /* Parse Unicode escape sequence */ case 'u':; OFChar16 c1, c2; OFUnichar c; size_t l; Index: src/OFString.h ================================================================== --- src/OFString.h +++ src/OFString.h @@ -921,10 +921,23 @@ * @param encoding The encoding for the C string * @return The OFString as a C string in the specified encoding */ - (const char *)lossyCStringWithEncoding: (OFStringEncoding)encoding; +/** + * @brief Returns the OFString as an insecure C string (meaning it can contain + * `\0`) 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 + * copy it. + * + * @param encoding The encoding for the C string + * @return The OFString as a C string in the specified encoding + */ +- (const char *)insecureCStringWithEncoding: (OFStringEncoding)encoding; + /** * @brief Returns the number of bytes the string needs in the specified * encoding. * * @param encoding The encoding for the string Index: src/OFString.m ================================================================== --- src/OFString.m +++ src/OFString.m @@ -101,47 +101,49 @@ @interface OFString () - (size_t)of_getCString: (char *)cString maxLength: (size_t)maxLength encoding: (OFStringEncoding)encoding - lossy: (bool)lossy OF_DIRECT; + lossy: (bool)lossy + insecure: (bool)insecure OF_DIRECT; - (const char *)of_cStringWithEncoding: (OFStringEncoding)encoding - lossy: (bool)lossy OF_DIRECT; + lossy: (bool)lossy + insecure: (bool)insecure OF_DIRECT; - (OFString *) of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options depth: (size_t)depth; @end @interface OFPlaceholderString: OFString @end extern bool _OFUnicodeToISO8859_2(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToISO8859_3(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToISO8859_15(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToWindows1250(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToWindows1251(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToWindows1252(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToCodepage437(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToCodepage850(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToCodepage852(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToCodepage858(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToMacRoman(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToKOI8R(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); extern bool _OFUnicodeToKOI8U(const OFUnichar *, unsigned char *, - size_t, bool); + size_t, bool, bool); /* References for static linking */ void OF_VISIBILITY_HIDDEN _references_to_categories_of_OFString(void) { @@ -375,18 +377,23 @@ return copy; } #ifdef OF_OBJFW_RUNTIME static bool -isASCII(const char *string, size_t length) +isASCIIWithoutNull(const char *string, size_t length) { uint8_t combined = 0; + bool containsNull = false; - for (size_t i = 0; i < length; i++) + for (size_t i = 0; i < length; i++) { combined |= string[i]; - return !(combined & ~0x7F); + if (string[i] == '\0') + containsNull = true; + } + + return !(combined & ~0x7F) && !containsNull; } #endif @implementation OFPlaceholderString #ifdef __clang__ @@ -409,11 +416,11 @@ if (length == 0) return (id)@""; #ifdef OF_OBJFW_RUNTIME if (length <= MAX_TAGGED_POINTER_LENGTH && - isASCII(UTF8String, length)) { + isASCIIWithoutNull(UTF8String, length)) { id ret = [OFTaggedPointerString stringWithASCIIString: UTF8String length: length]; if (ret != nil) @@ -437,11 +444,11 @@ if (UTF8StringLength == 0) return (id)@""; #ifdef OF_OBJFW_RUNTIME if (UTF8StringLength <= MAX_TAGGED_POINTER_LENGTH && - isASCII(UTF8String, UTF8StringLength)) { + isASCIIWithoutNull(UTF8String, UTF8StringLength)) { id ret = [OFTaggedPointerString stringWithASCIIString: UTF8String length: UTF8StringLength]; if (ret != nil) @@ -487,11 +494,11 @@ if (length == 0) return (id)@""; #ifdef OF_OBJFW_RUNTIME if (length <= MAX_TAGGED_POINTER_LENGTH && - isASCII(cString, length)) { + isASCIIWithoutNull(cString, length)) { id ret = [OFTaggedPointerString stringWithASCIIString: cString length: length]; if (ret != nil) @@ -523,11 +530,11 @@ if (cStringLength == 0) return (id)@""; #ifdef OF_OBJFW_RUNTIME if (cStringLength <= MAX_TAGGED_POINTER_LENGTH && - isASCII(cString, cStringLength)) { + isASCIIWithoutNull(cString, cStringLength)) { id ret = [OFTaggedPointerString stringWithASCIIString: cString length: cStringLength]; if (ret != nil) @@ -567,22 +574,22 @@ return (id)@""; #ifdef OF_OBJFW_RUNTIME if (length <= MAX_TAGGED_POINTER_LENGTH) { char buffer[MAX_TAGGED_POINTER_LENGTH]; - bool isUnicode = false; + bool useTaggedPointer = true; for (size_t i = 0; i < length; i++) { - if (string[i] >= 0x80) { - isUnicode = true; + if (string[i] >= 0x80 || string[i] == 0) { + useTaggedPointer = false; break; } buffer[i] = (char)string[i]; } - if (!isUnicode) { + if (useTaggedPointer) { id ret = [OFTaggedPointerString stringWithASCIIString: buffer length: length]; if (ret != nil) @@ -1176,10 +1183,11 @@ - (size_t)of_getCString: (char *)cString maxLength: (size_t)maxLength encoding: (OFStringEncoding)encoding lossy: (bool)lossy + insecure: (bool)insecure { const OFUnichar *characters = self.characters; size_t i, length = self.length; switch (encoding) { @@ -1186,11 +1194,16 @@ case OFStringEncodingUTF8:; size_t j = 0; for (i = 0; i < length; i++) { char buffer[4]; - size_t len = _OFUTF8StringEncode(characters[i], buffer); + size_t len; + + if OF_UNLIKELY (!insecure && characters[i] == 0) + @throw [OFInvalidEncodingException exception]; + + len = _OFUTF8StringEncode(characters[i], buffer); /* * Check for one more than the current index, as we * need one for the terminating zero. */ @@ -1222,10 +1235,13 @@ case OFStringEncodingASCII: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; for (i = 0; i < length; i++) { + if OF_UNLIKELY (!insecure && characters[i] == 0) + @throw [OFInvalidEncodingException exception]; + if OF_UNLIKELY (characters[i] > 0x80) { if (lossy) cString[i] = '?'; else @throw [OFInvalidEncodingException @@ -1240,10 +1256,13 @@ case OFStringEncodingISO8859_1: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; for (i = 0; i < length; i++) { + if OF_UNLIKELY (!insecure && characters[i] == 0) + @throw [OFInvalidEncodingException exception]; + if OF_UNLIKELY (characters[i] > 0xFF) { if (lossy) cString[i] = '?'; else @throw [OFInvalidEncodingException @@ -1259,11 +1278,11 @@ case OFStringEncodingISO8859_2: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToISO8859_2(characters, (unsigned char *)cString, - length, lossy)) + length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1272,11 +1291,11 @@ case OFStringEncodingISO8859_3: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToISO8859_3(characters, (unsigned char *)cString, - length, lossy)) + length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1285,11 +1304,11 @@ case OFStringEncodingISO8859_15: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToISO8859_15(characters, - (unsigned char *)cString, length, lossy)) + (unsigned char *)cString, length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1298,11 +1317,11 @@ case OFStringEncodingWindows1250: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToWindows1250(characters, - (unsigned char *)cString, length, lossy)) + (unsigned char *)cString, length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1311,11 +1330,11 @@ case OFStringEncodingWindows1251: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToWindows1251(characters, - (unsigned char *)cString, length, lossy)) + (unsigned char *)cString, length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1324,11 +1343,11 @@ case OFStringEncodingWindows1252: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToWindows1252(characters, - (unsigned char *)cString, length, lossy)) + (unsigned char *)cString, length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1337,11 +1356,11 @@ case OFStringEncodingCodepage437: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToCodepage437(characters, - (unsigned char *)cString, length, lossy)) + (unsigned char *)cString, length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1350,11 +1369,11 @@ case OFStringEncodingCodepage850: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToCodepage850(characters, - (unsigned char *)cString, length, lossy)) + (unsigned char *)cString, length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1363,11 +1382,11 @@ case OFStringEncodingCodepage852: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToCodepage852(characters, - (unsigned char *)cString, length, lossy)) + (unsigned char *)cString, length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1376,11 +1395,11 @@ case OFStringEncodingCodepage858: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToCodepage858(characters, - (unsigned char *)cString, length, lossy)) + (unsigned char *)cString, length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1389,11 +1408,11 @@ case OFStringEncodingMacRoman: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToMacRoman(characters, (unsigned char *)cString, - length, lossy)) + length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1402,11 +1421,11 @@ case OFStringEncodingKOI8R: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToKOI8R(characters, (unsigned char *)cString, - length, lossy)) + length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1415,11 +1434,11 @@ case OFStringEncodingKOI8U: if (length + 1 > maxLength) @throw [OFOutOfRangeException exception]; if (!_OFUnicodeToKOI8U(characters, (unsigned char *)cString, - length, lossy)) + length, lossy, insecure)) @throw [OFInvalidEncodingException exception]; cString[length] = '\0'; return length; @@ -1434,25 +1453,28 @@ encoding: (OFStringEncoding)encoding { return [self of_getCString: cString maxLength: maxLength encoding: encoding - lossy: false]; + lossy: false + insecure: false]; } - (size_t)getLossyCString: (char *)cString maxLength: (size_t)maxLength encoding: (OFStringEncoding)encoding { return [self of_getCString: cString maxLength: maxLength encoding: encoding - lossy: true]; + lossy: true + insecure: false]; } - (const char *)of_cStringWithEncoding: (OFStringEncoding)encoding lossy: (bool)lossy + insecure: (bool)insecure { size_t length = self.length; char *cString; size_t cStringLength; const char *ret; @@ -1464,11 +1486,12 @@ @try { cStringLength = [self of_getCString: cString maxLength: (length * 4) + 1 encoding: OFStringEncodingUTF8 - lossy: lossy]; + lossy: lossy + insecure: insecure]; } @catch (id e) { OFFreeMemory(cString); @throw e; } @@ -1498,11 +1521,12 @@ @try { cStringLength = [self of_getCString: cString maxLength: length + 1 encoding: encoding - lossy: lossy]; + lossy: lossy + insecure: insecure]; } @catch (id e) { OFFreeMemory(cString); @throw e; } @@ -1523,21 +1547,34 @@ return ret; } - (const char *)cStringWithEncoding: (OFStringEncoding)encoding { - return [self of_cStringWithEncoding: encoding lossy: false]; + return [self of_cStringWithEncoding: encoding + lossy: false + insecure: false]; } - (const char *)lossyCStringWithEncoding: (OFStringEncoding)encoding { - return [self of_cStringWithEncoding: encoding lossy: true]; + return [self of_cStringWithEncoding: encoding + lossy: true + insecure: false]; +} + +- (const char *)insecureCStringWithEncoding: (OFStringEncoding)encoding +{ + return [self of_cStringWithEncoding: encoding + lossy: false + insecure: true]; } - (const char *)UTF8String { - return [self cStringWithEncoding: OFStringEncodingUTF8]; + return [self of_cStringWithEncoding: OFStringEncodingUTF8 + lossy: false + insecure: false]; } - (size_t)length { OF_UNRECOGNIZED_SELECTOR @@ -1553,12 +1590,16 @@ characters = self.characters; length = self.length; for (size_t i = 0; i < length; i++) { char buffer[4]; - size_t len = _OFUTF8StringEncode(characters[i], buffer); + size_t len; + if (characters[i] == 0) + @throw [OFInvalidArgumentException exception]; + + len = _OFUTF8StringEncode(characters[i], buffer); if (len == 0) @throw [OFInvalidEncodingException exception]; UTF8StringLength += len; } @@ -1799,13 +1840,14 @@ [JSON replaceOccurrencesOfString: @"\r" withString: @"\\r"]; [JSON replaceOccurrencesOfString: @"\t" withString: @"\\t"]; if (options & OFJSONRepresentationOptionJSON5) { [JSON replaceOccurrencesOfString: @"\n" withString: @"\\\n"]; + [JSON replaceOccurrencesOfString: @"\0" withString: @"\\0"]; if (options & OFJSONRepresentationOptionIsIdentifier) { - const char *cString = self.UTF8String; + const char *cString = JSON.UTF8String; if ((!OFASCIIIsAlpha(cString[0]) && cString[0] != '_' && cString[0] != '$') || strpbrk(cString, " \n\r\t\b\f\\\"'") != NULL) { [JSON insertString: @"\"" atIndex: 0]; @@ -1815,10 +1857,11 @@ [JSON insertString: @"\"" atIndex: 0]; [JSON appendString: @"\""]; } } else { [JSON replaceOccurrencesOfString: @"\n" withString: @"\\n"]; + [JSON replaceOccurrencesOfString: @"\0" withString: @"\\u0000"]; [JSON insertString: @"\"" atIndex: 0]; [JSON appendString: @"\""]; } @@ -1861,11 +1904,12 @@ [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; - [data addItems: self.UTF8String count: length]; + [data addItems: [self insecureCStringWithEncoding: OFStringEncodingUTF8] + count: length]; return data; } - (OFRange)rangeOfString: (OFString *)string @@ -2656,11 +2700,11 @@ j = 0; for (size_t i = 0; i < length; i++) { OFUnichar c = characters[i]; - if (c > 0x10FFFF) { + if (c > 0x10FFFF || c == 0) { OFFreeMemory(buffer); @throw [OFInvalidEncodingException exception]; } if (swap) { @@ -2731,13 +2775,17 @@ buffer = OFAllocMemory(length + 1, sizeof(OFChar32)); @try { [self getCharacters: buffer inRange: OFMakeRange(0, length)]; buffer[length] = 0; - if (byteOrder != OFByteOrderNative) - for (size_t i = 0; i < length; i++) + for (size_t i = 0; i < length; i++) { + if (buffer[i] == 0) + @throw [OFInvalidEncodingException exception]; + + if (byteOrder != OFByteOrderNative) buffer[i] = OFByteSwap32(buffer[i]); + } ret = [[OFData dataWithItemsNoCopy: buffer count: length + 1 itemSize: sizeof(OFChar32) freeWhenDone: true] items]; Index: src/OFTCPSocket.h ================================================================== --- src/OFTCPSocket.h +++ src/OFTCPSocket.h @@ -29,11 +29,11 @@ #ifdef OF_HAVE_BLOCKS /** * @brief A block which is called when the socket connected. * - * @deprecated Use @ref OFTCPSocketConnecetedHandler instead. + * @deprecated Use @ref OFTCPSocketConnectedHandler instead. * * @param exception An exception which occurred while connecting the socket or * `nil` on success */ typedef void (^OFTCPSocketAsyncConnectBlock)(id _Nullable exception) Index: src/OFUTF8String+Private.h ================================================================== --- src/OFUTF8String+Private.h +++ src/OFUTF8String+Private.h @@ -29,11 +29,11 @@ @end #ifdef __cplusplus extern "C" { #endif -extern int _OFUTF8StringCheck(const char *, size_t, size_t *_Nullable) +extern int _OFUTF8StringCheck(const char *, size_t, size_t *_Nullable, bool *) OF_VISIBILITY_HIDDEN; extern size_t _OFUTF8StringIndexToPosition(const char *, size_t, size_t) OF_VISIBILITY_HIDDEN; #ifdef __cplusplus } Index: src/OFUTF8String.h ================================================================== --- src/OFUTF8String.h +++ src/OFUTF8String.h @@ -31,11 +31,11 @@ * pointer to `&_storage`. */ struct OFUTF8StringIvars { char *cString; size_t cStringLength; - bool isUTF8; + bool isUTF8, containsNull; size_t length; bool hasHash; unsigned long hash; bool freeWhenDone; } *restrict _s; Index: src/OFUTF8String.m ================================================================== --- src/OFUTF8String.m +++ src/OFUTF8String.m @@ -90,16 +90,21 @@ return OFOrderedSame; } int -_OFUTF8StringCheck(const char *UTF8String, size_t UTF8Length, size_t *length) +_OFUTF8StringCheck(const char *UTF8String, size_t UTF8Length, size_t *length, + bool *containsNull) { size_t tmpLength = UTF8Length; int isUTF8 = 0; + bool tmpContainsNull = false; for (size_t i = 0; i < UTF8Length; i++) { + if OF_UNLIKELY (UTF8String[i] == '\0') + tmpContainsNull = true; + /* No sign of UTF-8 here */ if OF_LIKELY (!(UTF8String[i] & 0x80)) continue; isUTF8 = 1; @@ -153,10 +158,13 @@ } if (length != NULL) *length = tmpLength; + if (containsNull != NULL) + *containsNull = tmpContainsNull; + return isUTF8; } static size_t positionToIndex(const char *string, size_t position) @@ -216,11 +224,11 @@ _s->cString = storage; _s->cStringLength = UTF8StringLength; switch (_OFUTF8StringCheck(UTF8String, UTF8StringLength, - &_s->length)) { + &_s->length, &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; @@ -260,11 +268,11 @@ _s->freeWhenDone = true; if (encoding == OFStringEncodingUTF8 || encoding == OFStringEncodingASCII) { switch (_OFUTF8StringCheck(cString, cStringLength, - &_s->length)) { + &_s->length, &_s->containsNull)) { case 1: if (encoding == OFStringEncodingASCII) @throw [OFInvalidEncodingException exception]; @@ -293,13 +301,16 @@ _s->cString[j++] = cString[i]; continue; } _s->isUTF8 = true; + + if OF_UNLIKELY (cString[i] == '\0') + _s->containsNull = true; + bytes = _OFUTF8StringEncode( (uint8_t)cString[i], buffer); - if (bytes == 0) @throw [OFInvalidEncodingException exception]; _s->cStringLength += bytes - 1; @@ -384,10 +395,13 @@ _s->cString[j++] = (char)unichar; continue; } _s->isUTF8 = true; + + if OF_UNLIKELY (cString[i] == '\0') + _s->containsNull = true; byteLength = _OFUTF8StringEncode(unichar, buffer); if (byteLength == 0) @throw [OFInvalidEncodingException exception]; @@ -431,11 +445,11 @@ UTF8String += 3; UTF8StringLength -= 3; } switch (_OFUTF8StringCheck(UTF8String, UTF8StringLength, - &_s->length)) { + &_s->length, &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; @@ -461,19 +475,23 @@ _s->cStringLength = string.UTF8StringLength; _s->length = string.length; _s->cString = OFAllocMemory(_s->cStringLength + 1, 1); - memcpy(_s->cString, string.UTF8String, _s->cStringLength + 1); + memcpy(_s->cString, + [string insecureCStringWithEncoding: OFStringEncodingUTF8], + _s->cStringLength + 1); _s->freeWhenDone = true; if ([string isKindOfClass: [OFUTF8String class]] || - [string isKindOfClass: [OFMutableUTF8String class]]) + [string isKindOfClass: [OFMutableUTF8String class]]) { _s->isUTF8 = ((OFUTF8String *)string)->_s->isUTF8; - else { + _s->containsNull = + ((OFUTF8String *)string)->_s->containsNull; + } else { switch (_OFUTF8StringCheck(_s->cString, - _s->cStringLength, NULL)) { + _s->cStringLength, NULL, &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; @@ -509,10 +527,13 @@ if (len == 0) @throw [OFInvalidEncodingException exception]; if (len > 1) _s->isUTF8 = true; + + if OF_UNLIKELY (characters[i] == 0) + _s->containsNull = true; j += len; } _s->cString[j] = '\0'; @@ -595,10 +616,13 @@ @throw [OFInvalidEncodingException exception]; if (len > 1) _s->isUTF8 = true; + if OF_UNLIKELY (character == 0) + _s->containsNull = true; + j += len; } _s->cString[j] = '\0'; _s->cStringLength = j; @@ -643,14 +667,13 @@ _s->freeWhenDone = true; j = 0; for (size_t i = 0; i < length; i++) { char buffer[4]; - size_t len = _OFUTF8StringEncode((swap - ? OFByteSwap32(characters[i]) - : characters[i]), - buffer); + OFUnichar character = (swap + ? OFByteSwap32(characters[i]) : characters[i]); + size_t len = _OFUTF8StringEncode(character, buffer); switch (len) { case 1: _s->cString[j++] = buffer[0]; break; @@ -664,10 +687,13 @@ break; default: @throw [OFInvalidEncodingException exception]; } + + if OF_UNLIKELY (character == 0) + _s->containsNull = true; } _s->cString[j] = '\0'; _s->cStringLength = j; @@ -704,11 +730,11 @@ _s->cStringLength = cStringLength; @try { switch (_OFUTF8StringCheck(tmp, cStringLength, - &_s->length)) { + &_s->length, &_s->containsNull)) { case 1: _s->isUTF8 = true; break; case -1: @throw [OFInvalidEncodingException exception]; @@ -738,10 +764,13 @@ - (size_t)getCString: (char *)cString maxLength: (size_t)maxLength encoding: (OFStringEncoding)encoding { + if (_s->containsNull) + @throw [OFInvalidEncodingException exception]; + switch (encoding) { case OFStringEncodingASCII: if (_s->isUTF8) @throw [OFInvalidEncodingException exception]; /* intentional fall-through */ @@ -759,10 +788,13 @@ } } - (const char *)cStringWithEncoding: (OFStringEncoding)encoding { + if (_s->containsNull) + @throw [OFInvalidEncodingException exception]; + switch (encoding) { case OFStringEncodingASCII: if (_s->isUTF8) @throw [OFInvalidEncodingException exception]; /* intentional fall-through */ @@ -770,13 +802,30 @@ return _s->cString; default: return [super cStringWithEncoding: encoding]; } } + +- (const char *)insecureCStringWithEncoding: (OFStringEncoding)encoding +{ + switch (encoding) { + case OFStringEncodingASCII: + if (_s->isUTF8) + @throw [OFInvalidEncodingException exception]; + /* intentional fall-through */ + case OFStringEncodingUTF8: + return _s->cString; + default: + return [super insecureCStringWithEncoding: encoding]; + } +} - (const char *)UTF8String { + if (_s->containsNull) + @throw [OFInvalidEncodingException exception]; + return _s->cString; } - (size_t)length { @@ -818,11 +867,13 @@ if (([string isKindOfClass: [OFUTF8String class]] || [string isKindOfClass: [OFMutableUTF8String class]]) && _s->hasHash && string->_s->hasHash && _s->hash != string->_s->hash) return false; - if (strcmp(_s->cString, string.UTF8String) != 0) + if (memcmp(_s->cString, + [string insecureCStringWithEncoding: OFStringEncodingUTF8], + _s->cStringLength) != 0) return false; return true; } @@ -839,11 +890,12 @@ otherCStringLength = string.UTF8StringLength; minimumCStringLength = (_s->cStringLength > otherCStringLength ? otherCStringLength : _s->cStringLength); - if ((compare = memcmp(_s->cString, string.UTF8String, + if ((compare = memcmp(_s->cString, + [string insecureCStringWithEncoding: OFStringEncodingUTF8], minimumCStringLength)) == 0) { if (_s->cStringLength > otherCStringLength) return OFOrderedDescending; if (_s->cStringLength < otherCStringLength) return OFOrderedAscending; @@ -866,11 +918,12 @@ int compare; if (string == self) return OFOrderedSame; - otherCString = string.UTF8String; + otherCString = + [string insecureCStringWithEncoding: OFStringEncodingUTF8]; otherCStringLength = string.UTF8StringLength; #ifdef OF_HAVE_UNICODE_TABLES if (!_s->isUTF8) { #endif @@ -1010,11 +1063,12 @@ - (OFRange)rangeOfString: (OFString *)string options: (OFStringSearchOptions)options range: (OFRange)range { - const char *cString = string.UTF8String; + const char *cString = + [string insecureCStringWithEncoding: OFStringEncodingUTF8]; size_t cStringLength = string.UTF8StringLength; size_t rangeLocation, rangeLength; if (range.length > SIZE_MAX - range.location || range.location + range.length > _s->length) @@ -1068,11 +1122,12 @@ return OFMakeRange(OFNotFound, 0); } - (bool)containsString: (OFString *)string { - const char *cString = string.UTF8String; + const char *cString = + [string insecureCStringWithEncoding: OFStringEncodingUTF8]; size_t cStringLength = string.UTF8StringLength; if (cStringLength == 0) return true; @@ -1110,11 +1165,13 @@ size_t cStringLength = prefix.UTF8StringLength; if (cStringLength > _s->cStringLength) return false; - return (memcmp(_s->cString, prefix.UTF8String, cStringLength) == 0); + return (memcmp(_s->cString, + [prefix insecureCStringWithEncoding: OFStringEncodingUTF8], + cStringLength) == 0); } - (bool)hasSuffix: (OFString *)suffix { size_t cStringLength = suffix.UTF8StringLength; @@ -1121,11 +1178,12 @@ if (cStringLength > _s->cStringLength) return false; return (memcmp(_s->cString + (_s->cStringLength - cStringLength), - suffix.UTF8String, cStringLength) == 0); + [suffix insecureCStringWithEncoding: OFStringEncodingUTF8], + cStringLength) == 0); } - (OFArray *)componentsSeparatedByString: (OFString *)delimiter options: (OFStringSeparationOptions)options { @@ -1143,11 +1201,11 @@ if (delimiter.length == 0) return [OFArray arrayWithObject: self]; array = [OFMutableArray array]; pool = objc_autoreleasePoolPush(); - cString = delimiter.UTF8String; + cString = [delimiter insecureCStringWithEncoding: OFStringEncodingUTF8]; cStringLength = delimiter.UTF8StringLength; if (cStringLength > _s->cStringLength) { [array addObject: [[self copy] autorelease]]; objc_autoreleasePoolPop(pool); @@ -1214,14 +1272,19 @@ return ret; } - (const OFChar32 *)UTF32StringWithByteOrder: (OFByteOrder)byteOrder { - OFChar32 *buffer = OFAllocMemory(_s->length + 1, sizeof(OFChar32)); + OFChar32 *buffer; size_t i = 0, j = 0; const OFChar32 *ret; + if (_s->containsNull) + @throw [OFInvalidEncodingException exception]; + + buffer = OFAllocMemory(_s->length + 1, sizeof(OFChar32)); + while (i < _s->cStringLength) { OFChar32 c; ssize_t cLen; cLen = _OFUTF8StringDecode(_s->cString + i, Index: src/encodings/codepage-437.m ================================================================== --- src/encodings/codepage-437.m +++ src/encodings/codepage-437.m @@ -132,14 +132,19 @@ }; static const uint8_t page25Start = 0x00; bool OF_VISIBILITY_HIDDEN _OFUnicodeToCodepage437(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return 0; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/codepage-850.m ================================================================== --- src/encodings/codepage-850.m +++ src/encodings/codepage-850.m @@ -107,14 +107,19 @@ }; static const uint8_t page25Start = 0x00; bool OF_VISIBILITY_HIDDEN _OFUnicodeToCodepage850(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/codepage-852.m ================================================================== --- src/encodings/codepage-852.m +++ src/encodings/codepage-852.m @@ -112,14 +112,19 @@ }; static const uint8_t page25Start = 0x00; bool OF_VISIBILITY_HIDDEN _OFUnicodeToCodepage852(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/codepage-858.m ================================================================== --- src/encodings/codepage-858.m +++ src/encodings/codepage-858.m @@ -113,14 +113,19 @@ }; static const uint8_t page25Start = 0x00; bool OF_VISIBILITY_HIDDEN _OFUnicodeToCodepage858(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/iso-8859-15.m ================================================================== --- src/encodings/iso-8859-15.m +++ src/encodings/iso-8859-15.m @@ -63,14 +63,19 @@ }; static const uint8_t page20Start = 0xAC; bool OF_VISIBILITY_HIDDEN _OFUnicodeToISO8859_15(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/iso-8859-2.m ================================================================== --- src/encodings/iso-8859-2.m +++ src/encodings/iso-8859-2.m @@ -83,14 +83,19 @@ }; static const uint8_t page2Start = 0xC7; bool OF_VISIBILITY_HIDDEN _OFUnicodeToISO8859_2(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/iso-8859-3.m ================================================================== --- src/encodings/iso-8859-3.m +++ src/encodings/iso-8859-3.m @@ -80,14 +80,19 @@ }; static const uint8_t page2Start = 0xD8; bool OF_VISIBILITY_HIDDEN _OFUnicodeToISO8859_3(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/koi8-r.m ================================================================== --- src/encodings/koi8-r.m +++ src/encodings/koi8-r.m @@ -118,14 +118,19 @@ }; static const uint8_t page25Start = 0x00; bool OF_VISIBILITY_HIDDEN _OFUnicodeToKOI8R(const OFUnichar *input, unsigned char *output, size_t length, - bool lossy) + bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/koi8-u.m ================================================================== --- src/encodings/koi8-u.m +++ src/encodings/koi8-u.m @@ -126,14 +126,19 @@ }; static const uint8_t page25Start = 0x00; bool OF_VISIBILITY_HIDDEN _OFUnicodeToKOI8U(const OFUnichar *input, unsigned char *output, size_t length, - bool lossy) + bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/mac-roman.m ================================================================== --- src/encodings/mac-roman.m +++ src/encodings/mac-roman.m @@ -152,14 +152,19 @@ }; static const uint8_t pageFBStart = 0x01; bool OF_VISIBILITY_HIDDEN _OFUnicodeToMacRoman(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/windows-1250.m ================================================================== --- src/encodings/windows-1250.m +++ src/encodings/windows-1250.m @@ -116,14 +116,19 @@ }; static const uint8_t page21Start = 0x22; bool OF_VISIBILITY_HIDDEN _OFUnicodeToWindows1250(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/windows-1251.m ================================================================== --- src/encodings/windows-1251.m +++ src/encodings/windows-1251.m @@ -105,14 +105,19 @@ }; static const uint8_t page21Start = 0x16; bool OF_VISIBILITY_HIDDEN _OFUnicodeToWindows1251(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: src/encodings/windows-1252.m ================================================================== --- src/encodings/windows-1252.m +++ src/encodings/windows-1252.m @@ -101,14 +101,19 @@ }; static const uint8_t page21Start = 0x22; bool OF_VISIBILITY_HIDDEN _OFUnicodeToWindows1252(const OFUnichar *input, unsigned char *output, - size_t length, bool lossy) + size_t length, bool lossy, bool insecure) { for (size_t i = 0; i < length; i++) { - OFUnichar c = input[i]; + OFUnichar c; + + if OF_UNLIKELY (!insecure && input[i] == 0) + return false; + + c = input[i]; if OF_UNLIKELY (c > 0x7F) { uint8_t idx; if OF_UNLIKELY (c > 0xFFFF) { Index: tests/OFJSONTests.m ================================================================== --- tests/OFJSONTests.m +++ tests/OFJSONTests.m @@ -26,20 +26,20 @@ { OFDictionary *_dictionary; } @end -static OFString *string = @"{\"foo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF," +static OFString *string = @"{\"f\\0oo\"\t:'b\\na\\r', \"x\":/*foo*/ [.5\r,0xF," @"null//bar\n,\"foo\",false]}"; @implementation OFJSONTests - (void)setUp { [super setUp]; _dictionary = [[OTOrderedDictionary alloc] initWithKeysAndObjects: - @"foo", @"b\na\r", + @"f\0oo", @"b\na\r", @"x", [OFArray arrayWithObjects: [OFNumber numberWithFloat: .5f], [OFNumber numberWithInt: 0xF], [OFNull null], @"foo", @@ -61,11 +61,11 @@ } - (void)testJSONRepresentation { OTAssert(_dictionary.JSONRepresentation, - @"{\"foo\":\"b\\na\\r\",\"x\":[0.5,15,null,\"foo\",false]}"); + @"{\"f\\u0000oo\":\"b\\na\\r\",\"x\":[0.5,15,null,\"foo\",false]}"); } - (void)testSortedJSONRepresentation { OTAssertEqualObjects( @@ -77,19 +77,19 @@ - (void)testPrettyJSONRepresentation { OTAssertEqualObjects([_dictionary JSONRepresentationWithOptions: OFJSONRepresentationOptionPretty], - @"{\n\t\"foo\": \"b\\na\\r\",\n\t\"x\": [\n\t\t0.5,\n\t\t15," + @"{\n\t\"f\\u0000oo\": \"b\\na\\r\",\n\t\"x\": [\n\t\t0.5,\n\t\t15," @"\n\t\tnull,\n\t\t\"foo\",\n\t\tfalse\n\t]\n}"); } - (void)testJSON5Representation { OTAssertEqualObjects([_dictionary JSONRepresentationWithOptions: OFJSONRepresentationOptionJSON5], - @"{foo:\"b\\\na\\r\",x:[0.5,15,null,\"foo\",false]}"); + @"{\"f\\0oo\":\"b\\\na\\r\",x:[0.5,15,null,\"foo\",false]}"); } - (void)testObjectByParsingJSONFailsWithInvalidJSON { OTAssertThrowsSpecific([@"{" objectByParsingJSON],