Skip to content

Commit 781fef2

Browse files
authored
Correctly encode key strings in dictionaries (#12)
1 parent 9298cda commit 781fef2

File tree

1 file changed

+35
-36
lines changed

1 file changed

+35
-36
lines changed

Sources/PureSwiftJSONParsing/JSONValue.swift

Lines changed: 35 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -41,36 +41,7 @@ extension JSONValue {
4141
UInt8(ascii: "f"), UInt8(ascii: "a"), UInt8(ascii: "l"), UInt8(ascii: "s"), UInt8(ascii: "e")
4242
])
4343
case .string(let string):
44-
bytes.append(UInt8(ascii: "\""))
45-
let stringBytes = string.utf8
46-
var startCopyIndex = stringBytes.startIndex
47-
var nextIndex = startCopyIndex
48-
49-
while nextIndex != stringBytes.endIndex {
50-
switch stringBytes[nextIndex] {
51-
case 0..<32, UInt8(ascii: "\""), UInt8(ascii: "\\"):
52-
// All Unicode characters may be placed within the
53-
// quotation marks, except for the characters that MUST be escaped:
54-
// quotation mark, reverse solidus, and the control characters (U+0000
55-
// through U+001F).
56-
// https://tools.ietf.org/html/rfc7159#section-7
57-
58-
// copy the current range over
59-
bytes.append(contentsOf: stringBytes[startCopyIndex..<nextIndex])
60-
bytes.append(UInt8(ascii: "\\"))
61-
bytes.append(stringBytes[nextIndex])
62-
63-
nextIndex = stringBytes.index(after: nextIndex)
64-
startCopyIndex = nextIndex
65-
default:
66-
nextIndex = stringBytes.index(after: nextIndex)
67-
}
68-
}
69-
70-
// copy everything, that hasn't been copied yet
71-
bytes.append(contentsOf: stringBytes[startCopyIndex..<nextIndex])
72-
73-
bytes.append(UInt8(ascii: "\""))
44+
encodeString(string, to: &bytes)
7445
case .number(let string):
7546
bytes.append(contentsOf: string.utf8)
7647
case .array(let array):
@@ -89,24 +60,52 @@ extension JSONValue {
8960
var iterator = dict.makeIterator()
9061
bytes.append(UInt8(ascii: "{"))
9162
if let (key, value) = iterator.next() {
92-
bytes.append(UInt8(ascii: "\""))
93-
bytes.append(contentsOf: key.utf8)
94-
bytes.append(UInt8(ascii: "\""))
63+
encodeString(key, to: &bytes)
9564
bytes.append(UInt8(ascii: ":"))
9665
value.appendBytes(to: &bytes)
9766
}
9867
while let (key, value) = iterator.next() {
9968
bytes.append(UInt8(ascii: ","))
100-
bytes.append(UInt8(ascii: "\""))
101-
bytes.append(contentsOf: key.utf8)
102-
bytes.append(UInt8(ascii: "\""))
69+
encodeString(key, to: &bytes)
10370
bytes.append(UInt8(ascii: ":"))
10471
value.appendBytes(to: &bytes)
10572
}
10673
bytes.append(UInt8(ascii: "}"))
10774
}
10875
}
10976

77+
private func encodeString(_ string: String, to bytes: inout [UInt8]) {
78+
bytes.append(UInt8(ascii: "\""))
79+
let stringBytes = string.utf8
80+
var startCopyIndex = stringBytes.startIndex
81+
var nextIndex = startCopyIndex
82+
83+
while nextIndex != stringBytes.endIndex {
84+
switch stringBytes[nextIndex] {
85+
case 0..<32, UInt8(ascii: "\""), UInt8(ascii: "\\"):
86+
// All Unicode characters may be placed within the
87+
// quotation marks, except for the characters that MUST be escaped:
88+
// quotation mark, reverse solidus, and the control characters (U+0000
89+
// through U+001F).
90+
// https://tools.ietf.org/html/rfc7159#section-7
91+
92+
// copy the current range over
93+
bytes.append(contentsOf: stringBytes[startCopyIndex..<nextIndex])
94+
bytes.append(UInt8(ascii: "\\"))
95+
bytes.append(stringBytes[nextIndex])
96+
97+
nextIndex = stringBytes.index(after: nextIndex)
98+
startCopyIndex = nextIndex
99+
default:
100+
nextIndex = stringBytes.index(after: nextIndex)
101+
}
102+
}
103+
104+
// copy everything, that hasn't been copied yet
105+
bytes.append(contentsOf: stringBytes[startCopyIndex..<nextIndex])
106+
bytes.append(UInt8(ascii: "\""))
107+
}
108+
110109
public var debugDataTypeDescription: String {
111110
switch self {
112111
case .array(_):

0 commit comments

Comments
 (0)