diff --git a/Sources/FoundationEssentials/JSON/JSONWriter.swift b/Sources/FoundationEssentials/JSON/JSONWriter.swift index 4b0a4cc04..2ecf8b7b5 100644 --- a/Sources/FoundationEssentials/JSON/JSONWriter.swift +++ b/Sources/FoundationEssentials/JSON/JSONWriter.swift @@ -140,11 +140,11 @@ internal struct JSONWriter { appendAccumulatedBytes(from: mark, to: cursor, followedByContentsOf: [._backslash, UInt8(ascii: "t")]) case 0x0...0xf: appendAccumulatedBytes(from: mark, to: cursor, followedByContentsOf: [._backslash, UInt8(ascii: "u"), UInt8(ascii: "0"), UInt8(ascii: "0"), UInt8(ascii: "0")]) - writer(ascii: valueToASCII(cursor.pointee / 16)) + writer(ascii: valueToASCII(cursor.pointee)) case 0x10...0x1f: appendAccumulatedBytes(from: mark, to: cursor, followedByContentsOf: [._backslash, UInt8(ascii: "u"), UInt8(ascii: "0"), UInt8(ascii: "0")]) - writer(ascii: valueToASCII(cursor.pointee % 16)) writer(ascii: valueToASCII(cursor.pointee / 16)) + writer(ascii: valueToASCII(cursor.pointee % 16)) default: // Accumulate this byte cursor += 1 diff --git a/Tests/FoundationEssentialsTests/JSONEncoderTests.swift b/Tests/FoundationEssentialsTests/JSONEncoderTests.swift index 1f3f1a3c3..d9fe7aa77 100644 --- a/Tests/FoundationEssentialsTests/JSONEncoderTests.swift +++ b/Tests/FoundationEssentialsTests/JSONEncoderTests.swift @@ -1159,12 +1159,22 @@ final class JSONEncoderTests : XCTestCase { "\"\\u00E9\"" : "é", // G-clef (UTF16 surrogate pair) 0x1D11E - "\"\\uD834\\uDD1E\"" : "𝄞" + "\"\\uD834\\uDD1E\"" : "𝄞", ] for (input, expectedOutput) in testCases { _test(JSONString: input, to: expectedOutput) } } + + func test_encodingJSONHexUnicodeEscapes() throws { + let testCases = [ + "\u{0001}\u{0002}\u{0003}": "\"\\u0001\\u0002\\u0003\"", + "\u{0010}\u{0018}\u{001f}": "\"\\u0010\\u0018\\u001f\"", + ] + for (string, json) in testCases { + _testRoundTrip(of: string, expectedJSON: Data(json.utf8)) + } + } func test_JSONBadUnicodeEscapes() { let badCases = ["\\uD834", "\\uD834hello", "hello\\uD834", "\\uD834\\u1221", "\\uD8", "\\uD834x\\uDD1E"]