Skip to content

Commit e94bf45

Browse files
committed
Attempt to fix decode_scanString
1 parent 834e308 commit e94bf45

File tree

1 file changed

+41
-40
lines changed

1 file changed

+41
-40
lines changed

json4lua/json/json.lua

+41-40
Original file line numberDiff line numberDiff line change
@@ -275,15 +275,17 @@ end
275275
-- START SoniEx2
276276
-- Initialize some things used by decode_scanString
277277
-- You know, for efficiency
278-
local keepEscape = {}
279-
base.setmetatable(keepEscape, {__index = function(t,k)
278+
local escapeSequences = {
279+
["\\t"] = "\t",
280+
["\\f"] = "\f",
281+
["\\r"] = "\r",
282+
["\\n"] = "\n",
283+
["\\b"] = "\b"
284+
}
285+
base.setmetatable(escapeSequences, {__index = function(t,k)
280286
-- skip "\" aka strip escape
281287
return string.sub(k,2)
282288
end})
283-
-- string.gmatch is 5.1+, string.gfind is 5.0
284-
for c in (string.gmatch or string.gfind)([["\bfnrtu]],".") do
285-
keepEscape["\\" .. c] = "\\" .. c
286-
end
287289
-- END SoniEx2
288290

289291
--- Scans a JSON string from the opening inverted comma or single quote to the
@@ -298,43 +300,42 @@ function decode_scanString(s,startPos)
298300
base.assert(startPos, 'decode_scanString(..) called without start position')
299301
local startChar = string.sub(s,startPos,startPos)
300302
-- START SoniEx2
301-
local endPos
302-
local oldStart = startPos
303-
startPos,endPos = string.find(s, startChar .. ".-[^\\]" .. startChar, startPos)
304-
base.assert(startPos == oldStart,'decode_scanString called for a non-string')
305-
base.assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
306-
-- convert into valid Lua string
307-
local ns = string.sub(s, startPos, endPos)
308-
-- remove escapes Lua can't deal with
309-
-- we use a function wrapper here for 5.0 compatibility
310-
ns = string.gsub(ns, "\\.", function(k) return keepEscape[k] end)
311-
-- parse \uXXXX TO UTF-8!!!
312-
ns = string.gsub(ns, "\\u....", function(a)
313-
a = string.sub(a, 3) -- strip \u
314-
local n = base.tonumber(a, 16)
315-
base.assert(n, "String decoding failed: bad Unicode escape " .. a .. " for string at position " .. startPos .. " : " .. endPos)
316-
-- math.floor(x/2^y) == lazy right shift
317-
-- a % 2^b == bitwise_and(a, (2^b)-1)
318-
-- 64 = 2^6
319-
-- 4096 = 2^12 (or 2^6 * 2^6)
320-
if n < 0x80 then
321-
return string.char(n % 0x80)
322-
elseif n < 0x800 then
323-
-- [110x xxxx] [10xx xxxx]
324-
return string.char(0xC0 + (math.floor(n/64) % 0x20)) .. string.char(0x80 + (n % 0x40))
303+
-- PS: I don't think single quotes are valid JSON
304+
base.assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string')
305+
--base.assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
306+
local t = {}
307+
local i,j = startPos,startPos
308+
while string.find(s, startChar, j+1) ~= j+1 do
309+
local oldj = j
310+
i,j = string.find(ns, "\\.", j+1)
311+
table.insert(t, string.sub(ns, oldj+1, i-1)
312+
if string.sub(ns, i, j) == "\\u" then
313+
local a = string.sub(ns,j+1,j+4)
314+
j = j + 4
315+
local n = base.tonumber(a, 16)
316+
base.assert(n, "String decoding failed: bad Unicode escape " .. a .. " for string at position " .. startPos .. " : " .. endPos)
317+
-- math.floor(x/2^y) == lazy right shift
318+
-- a % 2^b == bitwise_and(a, (2^b)-1)
319+
-- 64 = 2^6
320+
-- 4096 = 2^12 (or 2^6 * 2^6)
321+
local x
322+
if n < 0x80 then
323+
x = string.char(n % 0x80)
324+
elseif n < 0x800 then
325+
-- [110x xxxx] [10xx xxxx]
326+
x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40))
327+
else
328+
-- [1110 xxxx] [10xx xxxx] [10xx xxxx]
329+
x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40))
330+
end
331+
table.insert(t, x)
325332
else
326-
-- [1110 xxxx] [10xx xxxx] [10xx xxxx]
327-
return string.char(0xE0 + (math.floor(n/4096) % 0x10)) .. string.char(0x80 + (math.floor(n/64) % 0x40)) .. string.char(0x80 + (n % 0x40))
333+
table.insert(t, escapeSequences[string.sub(ns, i, j)])
328334
end
329-
end)
335+
end
336+
base.assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart)
337+
return table.concat(t,""), j+2
330338
-- END SoniEx2
331-
332-
local stringValue = 'return ' .. ns -- SoniEx2: use ns instead of string.sub(s, startPos, endPos)
333-
334-
local stringEval = base.loadstring(stringValue)
335-
base.assert(stringEval, 'Failed to load string [ ' .. stringValue .. '] in JSON4Lua.decode_scanString at position ' .. startPos .. ' : ' .. endPos .. "\nThis is a bug!")
336-
337-
return stringEval(), endPos + 1 -- SoniEx2: we have to add 1 to endPos
338339
end
339340

340341
--- Scans a JSON string skipping all whitespace from the current start position.

0 commit comments

Comments
 (0)