Index: src/OFString+URLEncoding.m ================================================================== --- src/OFString+URLEncoding.m +++ src/OFString+URLEncoding.m @@ -21,10 +21,11 @@ #import "OFString+URLEncoding.h" #import "OFCharacterSet.h" #import "OFInvalidFormatException.h" +#import "OFInvalidEncodingException.h" #import "OFOutOfMemoryException.h" /* Reference for static linking */ int _OFString_URLEncoding_reference; @@ -46,20 +47,31 @@ if (characterIsMember(allowedCharacters, @selector(characterIsMember:), c)) [ret appendCharacters: &c length: 1]; else { - unsigned char high = c >> 4; - unsigned char low = c & 0x0F; - of_unichar_t escaped[3]; - - escaped[0] = '%'; - escaped[1] = (high > 9 ? high - 10 + 'A' : high + '0'); - escaped[2] = (low > 9 ? low - 10 + 'A' : low + '0'); - - [ret appendCharacters: escaped - length: 3]; + char buffer[4]; + size_t bufferLen; + + if ((bufferLen = of_string_utf8_encode(c, buffer)) == 0) + @throw [OFInvalidEncodingException exception]; + + for (size_t j = 0; j < bufferLen; j++) { + unsigned char byte = buffer[j]; + unsigned char high = byte >> 4; + unsigned char low = byte & 0x0F; + char escaped[3]; + + escaped[0] = '%'; + escaped[1] = + (high > 9 ? high - 10 + 'A' : high + '0'); + escaped[2] = + (low > 9 ? low - 10 + 'A' : low + '0'); + + [ret appendUTF8String: escaped + length: 3]; + } } } objc_autoreleasePoolPop(pool); Index: tests/OFStringTests.m ================================================================== --- tests/OFStringTests.m +++ tests/OFStringTests.m @@ -781,18 +781,19 @@ TEST(@"-[SHA512Hash]", [[C(@"asdfoobar") SHA512Hash] isEqual: @"0464c427da158b02161bb44a3090bbfc594611ef6a53603640454b56412a9247c" @"3579a329e53a5dc74676b106755e3394f9454a2d42273242615d32f80437d61"]) + OFCharacterSet *cs = [OFCharacterSet + characterSetWithCharactersInString: @"abfo'_~$๐Ÿ"]; TEST(@"-[stringByURLEncodingWithAllowedCharacters:]", - [[C(@"foo\"ba'_~$]") stringByURLEncodingWithAllowedCharacters: - [OFCharacterSet URLPathAllowedCharacterSet]] - isEqual: @"foo%22ba'_~$%5D"]) + [[C(@"foo\"ba'_~$]๐Ÿ๐ŸŒ") stringByURLEncodingWithAllowedCharacters: + cs] isEqual: @"foo%22ba'_~$%5D๐Ÿ%F0%9F%8D%8C"]) TEST(@"-[stringByURLDecoding]", - [[C(@"foo%20bar%22+%24") stringByURLDecoding] - isEqual: @"foo bar\"+$"]) + [[C(@"foo%20bar%22+%24%F0%9F%8D%8C") stringByURLDecoding] + isEqual: @"foo bar\"+$๐ŸŒ"]) TEST(@"-[insertString:atIndex:]", (s[0] = [mutableStringClass stringWithString: @"๐„žรถรถรถbรคโ‚ฌ"]) && R([s[0] insertString: @"รครถรผ" atIndex: 3]) &&