Abuse filter log

Abuse Filter navigation (Home | Recent filter changes | Examine past edits | Abuse log)
Jump to navigation Jump to search
Details for log entry 2

12:57, 26 March 2024: Thecoda (talk | contribs) triggered global filter 1, performing the action "edit" on Module:Json. Actions taken: Disallow; Filter description: Global AF - Short new page with external link (examine)

Changes made in edit

--
-- json.lua
-- https://github.com/rxi/json.lua
--
-- Copyright (c) 2019 rxi
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
-- this software and associated documentation files (the "Software"), to deal in
-- the Software without restriction, including without limitation the rights to
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do
-- so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in all
-- copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.
--

local json = { _version = "0.1.2" }

-------------------------------------------------------------------------------
-- Encode
-------------------------------------------------------------------------------

local encode

local escape_char_map = {
[ "\\" ] = "\\\\",
[ "\"" ] = "\\\"",
[ "\b" ] = "\\b",
[ "\f" ] = "\\f",
[ "\n" ] = "\\n",
[ "\r" ] = "\\r",
[ "\t" ] = "\\t",
}

local escape_char_map_inv = { [ "\\/" ] = "/" }
for k, v in pairs(escape_char_map) do
escape_char_map_inv[v] = k
end


local function escape_char(c)
return escape_char_map[c] or string.format("\\u%04x", c:byte())
end


local function encode_nil(val)
return "null"
end


local function encode_table(val, stack)
local res = {}
stack = stack or {}

-- Circular reference?
if stack[val] then error("circular reference") end

stack[val] = true

if rawget(val, 1) ~= nil or next(val) == nil then
-- Treat as array -- check keys are valid and it is not sparse
local n = 0
for k in pairs(val) do
if type(k) ~= "number" then
error("invalid table: mixed or invalid key types")
end
n = n + 1
end
if n ~= #val then
error("invalid table: sparse array")
end
-- Encode
for i, v in ipairs(val) do
table.insert(res, encode(v, stack))
end
stack[val] = nil
return "[" .. table.concat(res, ",") .. "]"

else
-- Treat as an object
for k, v in pairs(val) do
if type(k) ~= "string" then
error("invalid table: mixed or invalid key types")
end
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
end
stack[val] = nil
return "{" .. table.concat(res, ",") .. "}"
end
end


local function encode_string(val)
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end


local function encode_number(val)
-- Check for NaN, -inf and inf
if val ~= val or val <= -math.huge or val >= math.huge then
error("unexpected number value '" .. tostring(val) .. "'")
end
return string.format("%.14g", val)
end


local type_func_map = {
[ "nil" ] = encode_nil,
[ "table" ] = encode_table,
[ "string" ] = encode_string,
[ "number" ] = encode_number,
[ "boolean" ] = tostring,
}


encode = function(val, stack)
local t = type(val)
local f = type_func_map[t]
if f then
return f(val, stack)
end
error("unexpected type '" .. t .. "'")
end


function json.encode(val)
return ( encode(val) )
end


-------------------------------------------------------------------------------
-- Decode
-------------------------------------------------------------------------------

local parse

local function create_set(...)
local res = {}
for i = 1, select("#", ...) do
res[ select(i, ...) ] = true
end
return res
end

local space_chars = create_set(" ", "\t", "\r", "\n")
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
local literals = create_set("true", "false", "null")

local literal_map = {
[ "true" ] = true,
[ "false" ] = false,
[ "null" ] = nil,
}


local function next_char(str, idx, set, negate)
for i = idx, #str do
if set[str:sub(i, i)] ~= negate then
return i
end
end
return #str + 1
end


local function decode_error(str, idx, msg)
local line_count = 1
local col_count = 1
for i = 1, idx - 1 do
col_count = col_count + 1
if str:sub(i, i) == "\n" then
line_count = line_count + 1
col_count = 1
end
end
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
end


local function codepoint_to_utf8(n)
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
local f = math.floor
if n <= 0x7f then
return string.char(n)
elseif n <= 0x7ff then
return string.char(f(n / 64) + 192, n % 64 + 128)
elseif n <= 0xffff then
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
elseif n <= 0x10ffff then
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
f(n % 4096 / 64) + 128, n % 64 + 128)
end
error( string.format("invalid unicode codepoint '%x'", n) )
end


local function parse_unicode_escape(s)
local n1 = tonumber( s:sub(3, 6), 16 )
local n2 = tonumber( s:sub(9, 12), 16 )
-- Surrogate pair?
if n2 then
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
else
return codepoint_to_utf8(n1)
end
end


local function parse_string(str, i)
local has_unicode_escape = false
local has_surrogate_escape = false
local has_escape = false
local last
for j = i + 1, #str do
local x = str:byte(j)

if x < 32 then
decode_error(str, j, "control character in string")
end

if last == 92 then -- "\\" (escape char)
if x == 117 then -- "u" (unicode escape sequence)
local hex = str:sub(j + 1, j + 5)
if not hex:find("%x%x%x%x") then
decode_error(str, j, "invalid unicode escape in string")
end
if hex:find("^[dD][89aAbB]") then
has_surrogate_escape = true
else
has_unicode_escape = true
end
else
local c = string.char(x)
if not escape_chars[c] then
decode_error(str, j, "invalid escape char '" .. c .. "' in string")
end
has_escape = true
end
last = nil

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

else
last = x
end
end
decode_error(str, i, "expected closing quote for string")
end


local function parse_number(str, i)
local x = next_char(str, i, delim_chars)
local s = str:sub(i, x - 1)
local n = tonumber(s)
if not n then
decode_error(str, i, "invalid number '" .. s .. "'")
end
return n, x
end


local function parse_literal(str, i)
local x = next_char(str, i, delim_chars)
local word = str:sub(i, x - 1)
if not literals[word] then
decode_error(str, i, "invalid literal '" .. word .. "'")
end
return literal_map[word], x
end


local function parse_array(str, i)
local res = {}
local n = 1
i = i + 1
while 1 do
local x
i = next_char(str, i, space_chars, true)
-- Empty / end of array?
if str:sub(i, i) == "]" then
i = i + 1
break
end
-- Read token
x, i = parse(str, i)
res[n] = x
n = n + 1
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "]" then break end
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
end
return res, i
end


local function parse_object(str, i)
local res = {}
i = i + 1
while 1 do
local key, val
i = next_char(str, i, space_chars, true)
-- Empty / end of object?
if str:sub(i, i) == "}" then
i = i + 1
break
end
-- Read key
if str:sub(i, i) ~= '"' then
decode_error(str, i, "expected string for key")
end
key, i = parse(str, i)
-- Read ':' delimiter
i = next_char(str, i, space_chars, true)
if str:sub(i, i) ~= ":" then
decode_error(str, i, "expected ':' after key")
end
i = next_char(str, i + 1, space_chars, true)
-- Read value
val, i = parse(str, i)
-- Set
res[key] = val
-- Next token
i = next_char(str, i, space_chars, true)
local chr = str:sub(i, i)
i = i + 1
if chr == "}" then break end
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
end
return res, i
end


local char_func_map = {
[ '"' ] = parse_string,
[ "0" ] = parse_number,
[ "1" ] = parse_number,
[ "2" ] = parse_number,
[ "3" ] = parse_number,
[ "4" ] = parse_number,
[ "5" ] = parse_number,
[ "6" ] = parse_number,
[ "7" ] = parse_number,
[ "8" ] = parse_number,
[ "9" ] = parse_number,
[ "-" ] = parse_number,
[ "t" ] = parse_literal,
[ "f" ] = parse_literal,
[ "n" ] = parse_literal,
[ "[" ] = parse_array,
[ "{" ] = parse_object,
}


parse = function(str, idx)
local chr = str:sub(idx, idx)
local f = char_func_map[chr]
if f then
return f(str, idx)
end
decode_error(str, idx, "unexpected character '" .. chr .. "'")
end


function json.decode(str)
if type(str) ~= "string" then
error("expected argument of type string, got " .. type(str))
end
local res, idx = parse(str, next_char(str, 1, space_chars, true))
idx = next_char(str, idx, space_chars, true)
if idx <= #str then
decode_error(str, idx, "trailing garbage")
end
return res
end


return json

Action parameters

VariableValue
Edit count of the user (user_editcount)
1
Name of the user account (user_name)
'Thecoda'
Rights that the user has (user_rights)
[ 0 => 'createaccount', 1 => 'read', 2 => 'createpage', 3 => 'createtalk', 4 => 'writeapi', 5 => 'viewmywatchlist', 6 => 'editmywatchlist', 7 => 'viewmyprivateinfo', 8 => 'editmyprivateinfo', 9 => 'editmyoptions', 10 => 'abusefilter-log-detail', 11 => 'abusefilter-view', 12 => 'abusefilter-log', 13 => 'move', 14 => 'move-subpages', 15 => 'move-rootuserpages', 16 => 'move-categorypages', 17 => 'movefile', 18 => 'edit', 19 => 'upload', 20 => 'reupload', 21 => 'reupload-shared', 22 => 'minoredit', 23 => 'editmyusercss', 24 => 'editmyuserjson', 25 => 'editmyuserjs', 26 => 'editmyuserjsredirect', 27 => 'purge', 28 => 'sendemail', 29 => 'applychangetags', 30 => 'changetags', 31 => 'editcontentmodel', 32 => 'mwoauthproposeconsumer', 33 => 'mwoauthupdateownconsumer', 34 => 'spamblacklistlog', 35 => 'oathauth-enable', 36 => 'mwoauthmanagemygrants', 37 => 'autoconfirmed', 38 => 'editsemiprotected', 39 => 'suppressredirect' ]
Page ID (page_id)
0
Page namespace (page_namespace)
828
Page title (without namespace) (page_title)
'Json'
Full page title (page_prefixedtitle)
'Module:Json'
Action (action)
'edit'
Edit summary/reason (summary)
''
Old content model (old_content_model)
''
New content model (new_content_model)
'Scribunto'
Old page wikitext, before the edit (old_wikitext)
''
New page wikitext, after the edit (new_wikitext)
'-- -- json.lua -- https://github.com/rxi/json.lua -- -- Copyright (c) 2019 rxi -- -- Permission is hereby granted, free of charge, to any person obtaining a copy of -- this software and associated documentation files (the "Software"), to deal in -- the Software without restriction, including without limitation the rights to -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -- of the Software, and to permit persons to whom the Software is furnished to do -- so, subject to the following conditions: -- -- The above copyright notice and this permission notice shall be included in all -- copies or substantial portions of the Software. -- -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -- SOFTWARE. -- local json = { _version = "0.1.2" } ------------------------------------------------------------------------------- -- Encode ------------------------------------------------------------------------------- local encode local escape_char_map = { [ "\\" ] = "\\\\", [ "\"" ] = "\\\"", [ "\b" ] = "\\b", [ "\f" ] = "\\f", [ "\n" ] = "\\n", [ "\r" ] = "\\r", [ "\t" ] = "\\t", } local escape_char_map_inv = { [ "\\/" ] = "/" } for k, v in pairs(escape_char_map) do escape_char_map_inv[v] = k end local function escape_char(c) return escape_char_map[c] or string.format("\\u%04x", c:byte()) end local function encode_nil(val) return "null" end local function encode_table(val, stack) local res = {} stack = stack or {} -- Circular reference? if stack[val] then error("circular reference") end stack[val] = true if rawget(val, 1) ~= nil or next(val) == nil then -- Treat as array -- check keys are valid and it is not sparse local n = 0 for k in pairs(val) do if type(k) ~= "number" then error("invalid table: mixed or invalid key types") end n = n + 1 end if n ~= #val then error("invalid table: sparse array") end -- Encode for i, v in ipairs(val) do table.insert(res, encode(v, stack)) end stack[val] = nil return "[" .. table.concat(res, ",") .. "]" else -- Treat as an object for k, v in pairs(val) do if type(k) ~= "string" then error("invalid table: mixed or invalid key types") end table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) end stack[val] = nil return "{" .. table.concat(res, ",") .. "}" end end local function encode_string(val) return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' end local function encode_number(val) -- Check for NaN, -inf and inf if val ~= val or val <= -math.huge or val >= math.huge then error("unexpected number value '" .. tostring(val) .. "'") end return string.format("%.14g", val) end local type_func_map = { [ "nil" ] = encode_nil, [ "table" ] = encode_table, [ "string" ] = encode_string, [ "number" ] = encode_number, [ "boolean" ] = tostring, } encode = function(val, stack) local t = type(val) local f = type_func_map[t] if f then return f(val, stack) end error("unexpected type '" .. t .. "'") end function json.encode(val) return ( encode(val) ) end ------------------------------------------------------------------------------- -- Decode ------------------------------------------------------------------------------- local parse local function create_set(...) local res = {} for i = 1, select("#", ...) do res[ select(i, ...) ] = true end return res end local space_chars = create_set(" ", "\t", "\r", "\n") local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") local literals = create_set("true", "false", "null") local literal_map = { [ "true" ] = true, [ "false" ] = false, [ "null" ] = nil, } local function next_char(str, idx, set, negate) for i = idx, #str do if set[str:sub(i, i)] ~= negate then return i end end return #str + 1 end local function decode_error(str, idx, msg) local line_count = 1 local col_count = 1 for i = 1, idx - 1 do col_count = col_count + 1 if str:sub(i, i) == "\n" then line_count = line_count + 1 col_count = 1 end end error( string.format("%s at line %d col %d", msg, line_count, col_count) ) end local function codepoint_to_utf8(n) -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa local f = math.floor if n <= 0x7f then return string.char(n) elseif n <= 0x7ff then return string.char(f(n / 64) + 192, n % 64 + 128) elseif n <= 0xffff then return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) elseif n <= 0x10ffff then return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, f(n % 4096 / 64) + 128, n % 64 + 128) end error( string.format("invalid unicode codepoint '%x'", n) ) end local function parse_unicode_escape(s) local n1 = tonumber( s:sub(3, 6), 16 ) local n2 = tonumber( s:sub(9, 12), 16 ) -- Surrogate pair? if n2 then return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) else return codepoint_to_utf8(n1) end end local function parse_string(str, i) local has_unicode_escape = false local has_surrogate_escape = false local has_escape = false local last for j = i + 1, #str do local x = str:byte(j) if x < 32 then decode_error(str, j, "control character in string") end if last == 92 then -- "\\" (escape char) if x == 117 then -- "u" (unicode escape sequence) local hex = str:sub(j + 1, j + 5) if not hex:find("%x%x%x%x") then decode_error(str, j, "invalid unicode escape in string") end if hex:find("^[dD][89aAbB]") then has_surrogate_escape = true else has_unicode_escape = true end else local c = string.char(x) if not escape_chars[c] then decode_error(str, j, "invalid escape char '" .. c .. "' in string") end has_escape = true end last = nil 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 else last = x end end decode_error(str, i, "expected closing quote for string") end local function parse_number(str, i) local x = next_char(str, i, delim_chars) local s = str:sub(i, x - 1) local n = tonumber(s) if not n then decode_error(str, i, "invalid number '" .. s .. "'") end return n, x end local function parse_literal(str, i) local x = next_char(str, i, delim_chars) local word = str:sub(i, x - 1) if not literals[word] then decode_error(str, i, "invalid literal '" .. word .. "'") end return literal_map[word], x end local function parse_array(str, i) local res = {} local n = 1 i = i + 1 while 1 do local x i = next_char(str, i, space_chars, true) -- Empty / end of array? if str:sub(i, i) == "]" then i = i + 1 break end -- Read token x, i = parse(str, i) res[n] = x n = n + 1 -- Next token i = next_char(str, i, space_chars, true) local chr = str:sub(i, i) i = i + 1 if chr == "]" then break end if chr ~= "," then decode_error(str, i, "expected ']' or ','") end end return res, i end local function parse_object(str, i) local res = {} i = i + 1 while 1 do local key, val i = next_char(str, i, space_chars, true) -- Empty / end of object? if str:sub(i, i) == "}" then i = i + 1 break end -- Read key if str:sub(i, i) ~= '"' then decode_error(str, i, "expected string for key") end key, i = parse(str, i) -- Read ':' delimiter i = next_char(str, i, space_chars, true) if str:sub(i, i) ~= ":" then decode_error(str, i, "expected ':' after key") end i = next_char(str, i + 1, space_chars, true) -- Read value val, i = parse(str, i) -- Set res[key] = val -- Next token i = next_char(str, i, space_chars, true) local chr = str:sub(i, i) i = i + 1 if chr == "}" then break end if chr ~= "," then decode_error(str, i, "expected '}' or ','") end end return res, i end local char_func_map = { [ '"' ] = parse_string, [ "0" ] = parse_number, [ "1" ] = parse_number, [ "2" ] = parse_number, [ "3" ] = parse_number, [ "4" ] = parse_number, [ "5" ] = parse_number, [ "6" ] = parse_number, [ "7" ] = parse_number, [ "8" ] = parse_number, [ "9" ] = parse_number, [ "-" ] = parse_number, [ "t" ] = parse_literal, [ "f" ] = parse_literal, [ "n" ] = parse_literal, [ "[" ] = parse_array, [ "{" ] = parse_object, } parse = function(str, idx) local chr = str:sub(idx, idx) local f = char_func_map[chr] if f then return f(str, idx) end decode_error(str, idx, "unexpected character '" .. chr .. "'") end function json.decode(str) if type(str) ~= "string" then error("expected argument of type string, got " .. type(str)) end local res, idx = parse(str, next_char(str, 1, space_chars, true)) idx = next_char(str, idx, space_chars, true) if idx <= #str then decode_error(str, idx, "trailing garbage") end return res end return json'
Unified diff of changes made by edit (edit_diff)
'@@ -1,0 +1,401 @@ +-- +-- json.lua +-- https://github.com/rxi/json.lua +-- +-- Copyright (c) 2019 rxi +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy of +-- this software and associated documentation files (the "Software"), to deal in +-- the Software without restriction, including without limitation the rights to +-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +-- of the Software, and to permit persons to whom the Software is furnished to do +-- so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in all +-- copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. +-- + +local json = { _version = "0.1.2" } + +------------------------------------------------------------------------------- +-- Encode +------------------------------------------------------------------------------- + +local encode + +local escape_char_map = { + [ "\\" ] = "\\\\", + [ "\"" ] = "\\\"", + [ "\b" ] = "\\b", + [ "\f" ] = "\\f", + [ "\n" ] = "\\n", + [ "\r" ] = "\\r", + [ "\t" ] = "\\t", +} + +local escape_char_map_inv = { [ "\\/" ] = "/" } +for k, v in pairs(escape_char_map) do + escape_char_map_inv[v] = k +end + + +local function escape_char(c) + return escape_char_map[c] or string.format("\\u%04x", c:byte()) +end + + +local function encode_nil(val) + return "null" +end + + +local function encode_table(val, stack) + local res = {} + stack = stack or {} + + -- Circular reference? + if stack[val] then error("circular reference") end + + stack[val] = true + + if rawget(val, 1) ~= nil or next(val) == nil then + -- Treat as array -- check keys are valid and it is not sparse + local n = 0 + for k in pairs(val) do + if type(k) ~= "number" then + error("invalid table: mixed or invalid key types") + end + n = n + 1 + end + if n ~= #val then + error("invalid table: sparse array") + end + -- Encode + for i, v in ipairs(val) do + table.insert(res, encode(v, stack)) + end + stack[val] = nil + return "[" .. table.concat(res, ",") .. "]" + + else + -- Treat as an object + for k, v in pairs(val) do + if type(k) ~= "string" then + error("invalid table: mixed or invalid key types") + end + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) + end + stack[val] = nil + return "{" .. table.concat(res, ",") .. "}" + end +end + + +local function encode_string(val) + return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' +end + + +local function encode_number(val) + -- Check for NaN, -inf and inf + if val ~= val or val <= -math.huge or val >= math.huge then + error("unexpected number value '" .. tostring(val) .. "'") + end + return string.format("%.14g", val) +end + + +local type_func_map = { + [ "nil" ] = encode_nil, + [ "table" ] = encode_table, + [ "string" ] = encode_string, + [ "number" ] = encode_number, + [ "boolean" ] = tostring, +} + + +encode = function(val, stack) + local t = type(val) + local f = type_func_map[t] + if f then + return f(val, stack) + end + error("unexpected type '" .. t .. "'") +end + + +function json.encode(val) + return ( encode(val) ) +end + + +------------------------------------------------------------------------------- +-- Decode +------------------------------------------------------------------------------- + +local parse + +local function create_set(...) + local res = {} + for i = 1, select("#", ...) do + res[ select(i, ...) ] = true + end + return res +end + +local space_chars = create_set(" ", "\t", "\r", "\n") +local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") +local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") +local literals = create_set("true", "false", "null") + +local literal_map = { + [ "true" ] = true, + [ "false" ] = false, + [ "null" ] = nil, +} + + +local function next_char(str, idx, set, negate) + for i = idx, #str do + if set[str:sub(i, i)] ~= negate then + return i + end + end + return #str + 1 +end + + +local function decode_error(str, idx, msg) + local line_count = 1 + local col_count = 1 + for i = 1, idx - 1 do + col_count = col_count + 1 + if str:sub(i, i) == "\n" then + line_count = line_count + 1 + col_count = 1 + end + end + error( string.format("%s at line %d col %d", msg, line_count, col_count) ) +end + + +local function codepoint_to_utf8(n) + -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa + local f = math.floor + if n <= 0x7f then + return string.char(n) + elseif n <= 0x7ff then + return string.char(f(n / 64) + 192, n % 64 + 128) + elseif n <= 0xffff then + return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) + elseif n <= 0x10ffff then + return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, + f(n % 4096 / 64) + 128, n % 64 + 128) + end + error( string.format("invalid unicode codepoint '%x'", n) ) +end + + +local function parse_unicode_escape(s) + local n1 = tonumber( s:sub(3, 6), 16 ) + local n2 = tonumber( s:sub(9, 12), 16 ) + -- Surrogate pair? + if n2 then + return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) + else + return codepoint_to_utf8(n1) + end +end + + +local function parse_string(str, i) + local has_unicode_escape = false + local has_surrogate_escape = false + local has_escape = false + local last + for j = i + 1, #str do + local x = str:byte(j) + + if x < 32 then + decode_error(str, j, "control character in string") + end + + if last == 92 then -- "\\" (escape char) + if x == 117 then -- "u" (unicode escape sequence) + local hex = str:sub(j + 1, j + 5) + if not hex:find("%x%x%x%x") then + decode_error(str, j, "invalid unicode escape in string") + end + if hex:find("^[dD][89aAbB]") then + has_surrogate_escape = true + else + has_unicode_escape = true + end + else + local c = string.char(x) + if not escape_chars[c] then + decode_error(str, j, "invalid escape char '" .. c .. "' in string") + end + has_escape = true + end + last = nil + + 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 + + else + last = x + end + end + decode_error(str, i, "expected closing quote for string") +end + + +local function parse_number(str, i) + local x = next_char(str, i, delim_chars) + local s = str:sub(i, x - 1) + local n = tonumber(s) + if not n then + decode_error(str, i, "invalid number '" .. s .. "'") + end + return n, x +end + + +local function parse_literal(str, i) + local x = next_char(str, i, delim_chars) + local word = str:sub(i, x - 1) + if not literals[word] then + decode_error(str, i, "invalid literal '" .. word .. "'") + end + return literal_map[word], x +end + + +local function parse_array(str, i) + local res = {} + local n = 1 + i = i + 1 + while 1 do + local x + i = next_char(str, i, space_chars, true) + -- Empty / end of array? + if str:sub(i, i) == "]" then + i = i + 1 + break + end + -- Read token + x, i = parse(str, i) + res[n] = x + n = n + 1 + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "]" then break end + if chr ~= "," then decode_error(str, i, "expected ']' or ','") end + end + return res, i +end + + +local function parse_object(str, i) + local res = {} + i = i + 1 + while 1 do + local key, val + i = next_char(str, i, space_chars, true) + -- Empty / end of object? + if str:sub(i, i) == "}" then + i = i + 1 + break + end + -- Read key + if str:sub(i, i) ~= '"' then + decode_error(str, i, "expected string for key") + end + key, i = parse(str, i) + -- Read ':' delimiter + i = next_char(str, i, space_chars, true) + if str:sub(i, i) ~= ":" then + decode_error(str, i, "expected ':' after key") + end + i = next_char(str, i + 1, space_chars, true) + -- Read value + val, i = parse(str, i) + -- Set + res[key] = val + -- Next token + i = next_char(str, i, space_chars, true) + local chr = str:sub(i, i) + i = i + 1 + if chr == "}" then break end + if chr ~= "," then decode_error(str, i, "expected '}' or ','") end + end + return res, i +end + + +local char_func_map = { + [ '"' ] = parse_string, + [ "0" ] = parse_number, + [ "1" ] = parse_number, + [ "2" ] = parse_number, + [ "3" ] = parse_number, + [ "4" ] = parse_number, + [ "5" ] = parse_number, + [ "6" ] = parse_number, + [ "7" ] = parse_number, + [ "8" ] = parse_number, + [ "9" ] = parse_number, + [ "-" ] = parse_number, + [ "t" ] = parse_literal, + [ "f" ] = parse_literal, + [ "n" ] = parse_literal, + [ "[" ] = parse_array, + [ "{" ] = parse_object, +} + + +parse = function(str, idx) + local chr = str:sub(idx, idx) + local f = char_func_map[chr] + if f then + return f(str, idx) + end + decode_error(str, idx, "unexpected character '" .. chr .. "'") +end + + +function json.decode(str) + if type(str) ~= "string" then + error("expected argument of type string, got " .. type(str)) + end + local res, idx = parse(str, next_char(str, 1, space_chars, true)) + idx = next_char(str, idx, space_chars, true) + if idx <= #str then + decode_error(str, idx, "trailing garbage") + end + return res +end + + +return json '
New page size (new_size)
10056
Old page size (old_size)
0
Lines added in edit (added_lines)
[ 0 => '--', 1 => '-- json.lua', 2 => '-- https://github.com/rxi/json.lua', 3 => '--', 4 => '-- Copyright (c) 2019 rxi', 5 => '--', 6 => '-- Permission is hereby granted, free of charge, to any person obtaining a copy of', 7 => '-- this software and associated documentation files (the "Software"), to deal in', 8 => '-- the Software without restriction, including without limitation the rights to', 9 => '-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies', 10 => '-- of the Software, and to permit persons to whom the Software is furnished to do', 11 => '-- so, subject to the following conditions:', 12 => '--', 13 => '-- The above copyright notice and this permission notice shall be included in all', 14 => '-- copies or substantial portions of the Software.', 15 => '--', 16 => '-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR', 17 => '-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,', 18 => '-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE', 19 => '-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER', 20 => '-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,', 21 => '-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE', 22 => '-- SOFTWARE.', 23 => '--', 24 => '', 25 => 'local json = { _version = "0.1.2" }', 26 => '', 27 => '-------------------------------------------------------------------------------', 28 => '-- Encode', 29 => '-------------------------------------------------------------------------------', 30 => '', 31 => 'local encode', 32 => '', 33 => 'local escape_char_map = {', 34 => ' [ "\\" ] = "\\\\",', 35 => ' [ "\"" ] = "\\\"",', 36 => ' [ "\b" ] = "\\b",', 37 => ' [ "\f" ] = "\\f",', 38 => ' [ "\n" ] = "\\n",', 39 => ' [ "\r" ] = "\\r",', 40 => ' [ "\t" ] = "\\t",', 41 => '}', 42 => '', 43 => 'local escape_char_map_inv = { [ "\\/" ] = "/" }', 44 => 'for k, v in pairs(escape_char_map) do', 45 => ' escape_char_map_inv[v] = k', 46 => 'end', 47 => '', 48 => '', 49 => 'local function escape_char(c)', 50 => ' return escape_char_map[c] or string.format("\\u%04x", c:byte())', 51 => 'end', 52 => '', 53 => '', 54 => 'local function encode_nil(val)', 55 => ' return "null"', 56 => 'end', 57 => '', 58 => '', 59 => 'local function encode_table(val, stack)', 60 => ' local res = {}', 61 => ' stack = stack or {}', 62 => '', 63 => ' -- Circular reference?', 64 => ' if stack[val] then error("circular reference") end', 65 => '', 66 => ' stack[val] = true', 67 => '', 68 => ' if rawget(val, 1) ~= nil or next(val) == nil then', 69 => ' -- Treat as array -- check keys are valid and it is not sparse', 70 => ' local n = 0', 71 => ' for k in pairs(val) do', 72 => ' if type(k) ~= "number" then', 73 => ' error("invalid table: mixed or invalid key types")', 74 => ' end', 75 => ' n = n + 1', 76 => ' end', 77 => ' if n ~= #val then', 78 => ' error("invalid table: sparse array")', 79 => ' end', 80 => ' -- Encode', 81 => ' for i, v in ipairs(val) do', 82 => ' table.insert(res, encode(v, stack))', 83 => ' end', 84 => ' stack[val] = nil', 85 => ' return "[" .. table.concat(res, ",") .. "]"', 86 => '', 87 => ' else', 88 => ' -- Treat as an object', 89 => ' for k, v in pairs(val) do', 90 => ' if type(k) ~= "string" then', 91 => ' error("invalid table: mixed or invalid key types")', 92 => ' end', 93 => ' table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))', 94 => ' end', 95 => ' stack[val] = nil', 96 => ' return "{" .. table.concat(res, ",") .. "}"', 97 => ' end', 98 => 'end', 99 => '', 100 => '', 101 => 'local function encode_string(val)', 102 => ' return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'', 103 => 'end', 104 => '', 105 => '', 106 => 'local function encode_number(val)', 107 => ' -- Check for NaN, -inf and inf', 108 => ' if val ~= val or val <= -math.huge or val >= math.huge then', 109 => ' error("unexpected number value '" .. tostring(val) .. "'")', 110 => ' end', 111 => ' return string.format("%.14g", val)', 112 => 'end', 113 => '', 114 => '', 115 => 'local type_func_map = {', 116 => ' [ "nil" ] = encode_nil,', 117 => ' [ "table" ] = encode_table,', 118 => ' [ "string" ] = encode_string,', 119 => ' [ "number" ] = encode_number,', 120 => ' [ "boolean" ] = tostring,', 121 => '}', 122 => '', 123 => '', 124 => 'encode = function(val, stack)', 125 => ' local t = type(val)', 126 => ' local f = type_func_map[t]', 127 => ' if f then', 128 => ' return f(val, stack)', 129 => ' end', 130 => ' error("unexpected type '" .. t .. "'")', 131 => 'end', 132 => '', 133 => '', 134 => 'function json.encode(val)', 135 => ' return ( encode(val) )', 136 => 'end', 137 => '', 138 => '', 139 => '-------------------------------------------------------------------------------', 140 => '-- Decode', 141 => '-------------------------------------------------------------------------------', 142 => '', 143 => 'local parse', 144 => '', 145 => 'local function create_set(...)', 146 => ' local res = {}', 147 => ' for i = 1, select("#", ...) do', 148 => ' res[ select(i, ...) ] = true', 149 => ' end', 150 => ' return res', 151 => 'end', 152 => '', 153 => 'local space_chars = create_set(" ", "\t", "\r", "\n")', 154 => 'local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")', 155 => 'local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")', 156 => 'local literals = create_set("true", "false", "null")', 157 => '', 158 => 'local literal_map = {', 159 => ' [ "true" ] = true,', 160 => ' [ "false" ] = false,', 161 => ' [ "null" ] = nil,', 162 => '}', 163 => '', 164 => '', 165 => 'local function next_char(str, idx, set, negate)', 166 => ' for i = idx, #str do', 167 => ' if set[str:sub(i, i)] ~= negate then', 168 => ' return i', 169 => ' end', 170 => ' end', 171 => ' return #str + 1', 172 => 'end', 173 => '', 174 => '', 175 => 'local function decode_error(str, idx, msg)', 176 => ' local line_count = 1', 177 => ' local col_count = 1', 178 => ' for i = 1, idx - 1 do', 179 => ' col_count = col_count + 1', 180 => ' if str:sub(i, i) == "\n" then', 181 => ' line_count = line_count + 1', 182 => ' col_count = 1', 183 => ' end', 184 => ' end', 185 => ' error( string.format("%s at line %d col %d", msg, line_count, col_count) )', 186 => 'end', 187 => '', 188 => '', 189 => 'local function codepoint_to_utf8(n)', 190 => ' -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa', 191 => ' local f = math.floor', 192 => ' if n <= 0x7f then', 193 => ' return string.char(n)', 194 => ' elseif n <= 0x7ff then', 195 => ' return string.char(f(n / 64) + 192, n % 64 + 128)', 196 => ' elseif n <= 0xffff then', 197 => ' return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)', 198 => ' elseif n <= 0x10ffff then', 199 => ' return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,', 200 => ' f(n % 4096 / 64) + 128, n % 64 + 128)', 201 => ' end', 202 => ' error( string.format("invalid unicode codepoint '%x'", n) )', 203 => 'end', 204 => '', 205 => '', 206 => 'local function parse_unicode_escape(s)', 207 => ' local n1 = tonumber( s:sub(3, 6), 16 )', 208 => ' local n2 = tonumber( s:sub(9, 12), 16 )', 209 => ' -- Surrogate pair?', 210 => ' if n2 then', 211 => ' return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)', 212 => ' else', 213 => ' return codepoint_to_utf8(n1)', 214 => ' end', 215 => 'end', 216 => '', 217 => '', 218 => 'local function parse_string(str, i)', 219 => ' local has_unicode_escape = false', 220 => ' local has_surrogate_escape = false', 221 => ' local has_escape = false', 222 => ' local last', 223 => ' for j = i + 1, #str do', 224 => ' local x = str:byte(j)', 225 => '', 226 => ' if x < 32 then', 227 => ' decode_error(str, j, "control character in string")', 228 => ' end', 229 => '', 230 => ' if last == 92 then -- "\\" (escape char)', 231 => ' if x == 117 then -- "u" (unicode escape sequence)', 232 => ' local hex = str:sub(j + 1, j + 5)', 233 => ' if not hex:find("%x%x%x%x") then', 234 => ' decode_error(str, j, "invalid unicode escape in string")', 235 => ' end', 236 => ' if hex:find("^[dD][89aAbB]") then', 237 => ' has_surrogate_escape = true', 238 => ' else', 239 => ' has_unicode_escape = true', 240 => ' end', 241 => ' else', 242 => ' local c = string.char(x)', 243 => ' if not escape_chars[c] then', 244 => ' decode_error(str, j, "invalid escape char '" .. c .. "' in string")', 245 => ' end', 246 => ' has_escape = true', 247 => ' end', 248 => ' last = nil', 249 => '', 250 => ' elseif x == 34 then -- '"' (end of string)', 251 => ' local s = str:sub(i + 1, j - 1)', 252 => ' if has_surrogate_escape then', 253 => ' s = s:gsub("\\u[dD][89aAbB]..\\u....", parse_unicode_escape)', 254 => ' end', 255 => ' if has_unicode_escape then', 256 => ' s = s:gsub("\\u....", parse_unicode_escape)', 257 => ' end', 258 => ' if has_escape then', 259 => ' s = s:gsub("\\.", escape_char_map_inv)', 260 => ' end', 261 => ' return s, j + 1', 262 => '', 263 => ' else', 264 => ' last = x', 265 => ' end', 266 => ' end', 267 => ' decode_error(str, i, "expected closing quote for string")', 268 => 'end', 269 => '', 270 => '', 271 => 'local function parse_number(str, i)', 272 => ' local x = next_char(str, i, delim_chars)', 273 => ' local s = str:sub(i, x - 1)', 274 => ' local n = tonumber(s)', 275 => ' if not n then', 276 => ' decode_error(str, i, "invalid number '" .. s .. "'")', 277 => ' end', 278 => ' return n, x', 279 => 'end', 280 => '', 281 => '', 282 => 'local function parse_literal(str, i)', 283 => ' local x = next_char(str, i, delim_chars)', 284 => ' local word = str:sub(i, x - 1)', 285 => ' if not literals[word] then', 286 => ' decode_error(str, i, "invalid literal '" .. word .. "'")', 287 => ' end', 288 => ' return literal_map[word], x', 289 => 'end', 290 => '', 291 => '', 292 => 'local function parse_array(str, i)', 293 => ' local res = {}', 294 => ' local n = 1', 295 => ' i = i + 1', 296 => ' while 1 do', 297 => ' local x', 298 => ' i = next_char(str, i, space_chars, true)', 299 => ' -- Empty / end of array?', 300 => ' if str:sub(i, i) == "]" then', 301 => ' i = i + 1', 302 => ' break', 303 => ' end', 304 => ' -- Read token', 305 => ' x, i = parse(str, i)', 306 => ' res[n] = x', 307 => ' n = n + 1', 308 => ' -- Next token', 309 => ' i = next_char(str, i, space_chars, true)', 310 => ' local chr = str:sub(i, i)', 311 => ' i = i + 1', 312 => ' if chr == "]" then break end', 313 => ' if chr ~= "," then decode_error(str, i, "expected ']' or ','") end', 314 => ' end', 315 => ' return res, i', 316 => 'end', 317 => '', 318 => '', 319 => 'local function parse_object(str, i)', 320 => ' local res = {}', 321 => ' i = i + 1', 322 => ' while 1 do', 323 => ' local key, val', 324 => ' i = next_char(str, i, space_chars, true)', 325 => ' -- Empty / end of object?', 326 => ' if str:sub(i, i) == "}" then', 327 => ' i = i + 1', 328 => ' break', 329 => ' end', 330 => ' -- Read key', 331 => ' if str:sub(i, i) ~= '"' then', 332 => ' decode_error(str, i, "expected string for key")', 333 => ' end', 334 => ' key, i = parse(str, i)', 335 => ' -- Read ':' delimiter', 336 => ' i = next_char(str, i, space_chars, true)', 337 => ' if str:sub(i, i) ~= ":" then', 338 => ' decode_error(str, i, "expected ':' after key")', 339 => ' end', 340 => ' i = next_char(str, i + 1, space_chars, true)', 341 => ' -- Read value', 342 => ' val, i = parse(str, i)', 343 => ' -- Set', 344 => ' res[key] = val', 345 => ' -- Next token', 346 => ' i = next_char(str, i, space_chars, true)', 347 => ' local chr = str:sub(i, i)', 348 => ' i = i + 1', 349 => ' if chr == "}" then break end', 350 => ' if chr ~= "," then decode_error(str, i, "expected '}' or ','") end', 351 => ' end', 352 => ' return res, i', 353 => 'end', 354 => '', 355 => '', 356 => 'local char_func_map = {', 357 => ' [ '"' ] = parse_string,', 358 => ' [ "0" ] = parse_number,', 359 => ' [ "1" ] = parse_number,', 360 => ' [ "2" ] = parse_number,', 361 => ' [ "3" ] = parse_number,', 362 => ' [ "4" ] = parse_number,', 363 => ' [ "5" ] = parse_number,', 364 => ' [ "6" ] = parse_number,', 365 => ' [ "7" ] = parse_number,', 366 => ' [ "8" ] = parse_number,', 367 => ' [ "9" ] = parse_number,', 368 => ' [ "-" ] = parse_number,', 369 => ' [ "t" ] = parse_literal,', 370 => ' [ "f" ] = parse_literal,', 371 => ' [ "n" ] = parse_literal,', 372 => ' [ "[" ] = parse_array,', 373 => ' [ "{" ] = parse_object,', 374 => '}', 375 => '', 376 => '', 377 => 'parse = function(str, idx)', 378 => ' local chr = str:sub(idx, idx)', 379 => ' local f = char_func_map[chr]', 380 => ' if f then', 381 => ' return f(str, idx)', 382 => ' end', 383 => ' decode_error(str, idx, "unexpected character '" .. chr .. "'")', 384 => 'end', 385 => '', 386 => '', 387 => 'function json.decode(str)', 388 => ' if type(str) ~= "string" then', 389 => ' error("expected argument of type string, got " .. type(str))', 390 => ' end', 391 => ' local res, idx = parse(str, next_char(str, 1, space_chars, true))', 392 => ' idx = next_char(str, idx, space_chars, true)', 393 => ' if idx <= #str then', 394 => ' decode_error(str, idx, "trailing garbage")', 395 => ' end', 396 => ' return res', 397 => 'end', 398 => '', 399 => '', 400 => 'return json' ]
Unix timestamp of change (timestamp)
'1711457863'