Skip to content

Commit 892a01c

Browse files
committed
Escape reserved characters in JSON strings
1 parent 869b411 commit 892a01c

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

assembly/JSON.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,20 @@ export namespace JSON {
149149
}
150150

151151
toString(): string {
152-
return "\"" + this._str + "\"";
152+
let escaped: i32[] = [];
153+
for (let i = 0; i < this._str.length; i++) {
154+
const charCode = this._str.charCodeAt(i)
155+
const char = this._str.charAt(i)
156+
if (
157+
charCode == 0x22 || // " quotation mark U+0022
158+
charCode == 0x5C || // \ reverse solidus U+005C
159+
charCode < 0x20 // control characters
160+
) {
161+
escaped.push(0x5c); // add a reverse solidus (backslash) to escape reserved chars
162+
}
163+
escaped.push(charCode)
164+
}
165+
return "\"" + String.fromCharCodes(escaped) + "\"";
153166
}
154167
}
155168

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { JSON } from '../JSON'
2+
3+
describe('Escaped characters', () => {
4+
it('Does not escape characters unneccessarily', () => {
5+
const strings = [
6+
'sphinx of black quartz, judge my vow',
7+
'{}',
8+
'[]',
9+
'/',
10+
'|',
11+
'/|||/|||[{]}<>,.',
12+
'ஂ ஃ அ ஆ இ ஈ உ ஊ எ ஏ ஐ ஒ ஓ ஔ க ங ச ஜ ஞ ட ண த ந ன ப ம ய ர ற ல ள',
13+
'ᄀ ᄁ ᄂ ᄃ ᄄ ᄅ ᄆ ᄇ ᄈ ᄉ ᄊ ᄋ ᄌ ᄍ ᄎ ᄏ ᄐ ᄑ ᄒ ᄓ ᄔ ᄕ ᄖ ᄗ ᄘ ᄙ ᄚ ᄛ ',
14+
'℀ ℁ ℂ ℃ ℄ ℅ ℆ ℇ ℈ ℉ ℊ ℋ ℌ ℍ ℎ ℏ ℐ ℑ ℒ ℓ ℔ ℕ № ℗ ℘ ℙ ℚ ℛ ℜ ℝ ℞ ℟ ℠ ℡ ™ ℣ ℤ ℥ Ω ℧ ℨ ℩ K Å ℬ ℭ ℮ ℯ ℰ ℱ Ⅎ ℳ ℴ ℵ ℶ ℷ ℸ ',
15+
'☀ ☁ ☂ ☃ ☄ ★ ☆ ☇ ☈ ☉ ☊ ☋ ☌ ☍ ☎ ☏ ☐ ☑ ☒ ☓ ☚ ☛ ☜ ☝ ☞ ☟ ☠ ☡ ☢ ☣ ☤ ☥ ☦ ☧ ☨ ☩ ☪ ☫ ☬ ☭ ☮ ☯ ☰ ☱ ☲ ☳ ☴ ☵ ☶ ☷ ☸ ☹ ☺ ☻ ☼ ☽ ☾ ☿ ♀ ♁ ♂ ♃ ♄ ♅ ♆ ♇ ♈ ♉ ♊ ♋ ♌ ♍ ♎ ♏ ♐ ♑ ♒ ♓',
16+
]
17+
strings.forEach((str) => {
18+
const jsonStr = new JSON.Str(str)
19+
expect(jsonStr.toString()).toBe('"' + str + '"')
20+
})
21+
})
22+
it('Escapes quotes and backslashes', () => {
23+
const strings = ['"', '\\', '"\\"', '\\"\\"']
24+
strings.forEach((str) => {
25+
const jsonStr = new JSON.Str(str)
26+
expect(jsonStr.toString()).toBe('"' + escaped(str) + '"')
27+
})
28+
})
29+
it('Escapes control characters', () => {
30+
const strings = ['\n', '\r', '\r\n', '\b', '\f', '\t', '\v', '\b\f\t\v\r']
31+
strings.forEach((str) => {
32+
const jsonStr = new JSON.Str(str)
33+
expect(jsonStr.toString()).toBe('"' + escaped(str) + '"')
34+
})
35+
})
36+
})
37+
38+
function escaped(str: string): string {
39+
const escapedChars: i32[] = []
40+
for (let i = 0; i < str.length; i++) {
41+
const charCode = str.charCodeAt(i)
42+
if (
43+
charCode < 0x20 || // control characters
44+
charCode == 0x22 || // double quote (")
45+
charCode == 0x5c
46+
) {
47+
// backslash / reverse solidus (\)
48+
escapedChars.push(0x5c)
49+
}
50+
escapedChars.push(charCode)
51+
}
52+
return String.fromCharCodes(escapedChars)
53+
}

0 commit comments

Comments
 (0)