mirror of https://github.com/rxi/json.lua.git
Fix escape sequence parser for decoding strings
Improved logic to parse escape sequences when decoding strings. The former gsub logic is replaced by a clean token parser. This fixes the problem that the parser tries to decode any ``\u`` sequence (also invalid unicode escape sequences) when a valid escape sequence is found somewhere else in the string. MWE: ```lua json = require("json") json.decode("{\"fail\":\"\\\\url{http://www.example.com/} vs. \\u0023\"}") ```pull/22/head
parent
d1e3b0f5d0
commit
673d41a4fb
39
json.lua
39
json.lua
|
@ -216,52 +216,43 @@ end
|
||||||
|
|
||||||
|
|
||||||
local function parse_string(str, i)
|
local function parse_string(str, i)
|
||||||
local has_unicode_escape = false
|
local s = ""
|
||||||
local has_surrogate_escape = false
|
local j = i + 1
|
||||||
local has_escape = false
|
while j <= #str do
|
||||||
local last
|
|
||||||
for j = i + 1, #str do
|
|
||||||
local x = str:byte(j)
|
local x = str:byte(j)
|
||||||
|
|
||||||
if x < 32 then
|
if x < 32 then
|
||||||
decode_error(str, j, "control character in string")
|
decode_error(str, j, "control character in string")
|
||||||
end
|
end
|
||||||
|
|
||||||
if last == 92 then -- "\\" (escape char)
|
if x == 92 then -- "\\" (escape char)
|
||||||
if x == 117 then -- "u" (unicode escape sequence)
|
if str:byte(j + 1) == 117 then -- "u" (unicode escape sequence)
|
||||||
local hex = str:sub(j + 1, j + 5)
|
local hex = str:sub(j + 2, j + 6)
|
||||||
if not hex:find("%x%x%x%x") then
|
if not hex:find("%x%x%x%x") then
|
||||||
decode_error(str, j, "invalid unicode escape in string")
|
decode_error(str, j, "invalid unicode escape in string")
|
||||||
end
|
end
|
||||||
if hex:find("^[dD][89aAbB]") then
|
if hex:find("^[dD][89aAbB]") then
|
||||||
has_surrogate_escape = true
|
s = s .. parse_unicode_escape(str:sub(j, j + 12))
|
||||||
|
j = j + 12
|
||||||
else
|
else
|
||||||
has_unicode_escape = true
|
s = s .. parse_unicode_escape(str:sub(j, j + 6))
|
||||||
|
j = j + 6
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
local c = string.char(x)
|
local c = str:sub(j + 1, j + 1)
|
||||||
if not escape_chars[c] then
|
if not escape_chars[c] then
|
||||||
decode_error(str, j, "invalid escape char '" .. c .. "' in string")
|
decode_error(str, j, "invalid escape char '" .. c .. "' in string")
|
||||||
end
|
end
|
||||||
has_escape = true
|
s = s .. escape_char_map_inv[str:sub(j, j + 1)]
|
||||||
|
j = j + 2
|
||||||
end
|
end
|
||||||
last = nil
|
|
||||||
|
|
||||||
elseif x == 34 then -- '"' (end of string)
|
elseif x == 34 then -- '"' (end of string)
|
||||||
local s = str:sub(i + 1, j - 1)
|
|
||||||
if has_surrogate_escape then
|
|
||||||
s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape)
|
|
||||||
end
|
|
||||||
if has_unicode_escape then
|
|
||||||
s = s:gsub("\\u....", parse_unicode_escape)
|
|
||||||
end
|
|
||||||
if has_escape then
|
|
||||||
s = s:gsub("\\.", escape_char_map_inv)
|
|
||||||
end
|
|
||||||
return s, j + 1
|
return s, j + 1
|
||||||
|
|
||||||
else
|
else
|
||||||
last = x
|
s = s .. string.char(x)
|
||||||
|
j = j + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
decode_error(str, i, "expected closing quote for string")
|
decode_error(str, i, "expected closing quote for string")
|
||||||
|
|
Loading…
Reference in New Issue