@@ -275,15 +275,17 @@ end
275
275
-- START SoniEx2
276
276
-- Initialize some things used by decode_scanString
277
277
-- 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 )
280
286
-- skip "\" aka strip escape
281
287
return string.sub (k ,2 )
282
288
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
287
289
-- END SoniEx2
288
290
289
291
--- Scans a JSON string from the opening inverted comma or single quote to the
@@ -298,43 +300,42 @@ function decode_scanString(s,startPos)
298
300
base .assert (startPos , ' decode_scanString(..) called without start position' )
299
301
local startChar = string.sub (s ,startPos ,startPos )
300
302
-- 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 )
325
332
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 )])
328
334
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
330
338
-- 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 .. " \n This is a bug!" )
336
-
337
- return stringEval (), endPos + 1 -- SoniEx2: we have to add 1 to endPos
338
339
end
339
340
340
341
--- Scans a JSON string skipping all whitespace from the current start position.
0 commit comments