Update talents + beasts
This commit is contained in:
25
tools/luajson/json.lua
Normal file
25
tools/luajson/json.lua
Normal file
@ -0,0 +1,25 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
package.path = package.path .. ";lpeg/?.lua"
|
||||
local decode = require("json.decode")
|
||||
local encode = require("json.encode")
|
||||
local util = require("json.util")
|
||||
|
||||
local _G = _G
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local json = {
|
||||
_VERSION = "1.3.4",
|
||||
_DESCRIPTION = "LuaJSON : customizable JSON decoder/encoder",
|
||||
_COPYRIGHT = "Copyright (c) 2007-2014 Thomas Harning Jr. <harningt@gmail.com>",
|
||||
decode = decode,
|
||||
encode = encode,
|
||||
util = util
|
||||
}
|
||||
|
||||
_G.json = json
|
||||
|
||||
return json
|
171
tools/luajson/json/decode.lua
Normal file
171
tools/luajson/json/decode.lua
Normal file
@ -0,0 +1,171 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local lpeg = require("lpeg")
|
||||
|
||||
local error = error
|
||||
local pcall = pcall
|
||||
|
||||
local jsonutil = require("json.util")
|
||||
local merge = jsonutil.merge
|
||||
local util = require("json.decode.util")
|
||||
|
||||
local decode_state = require("json.decode.state")
|
||||
|
||||
local setmetatable, getmetatable = setmetatable, getmetatable
|
||||
local assert = assert
|
||||
local ipairs, pairs = ipairs, pairs
|
||||
local string_char = require("string").char
|
||||
|
||||
local type = type
|
||||
|
||||
local require = require
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local modulesToLoad = {
|
||||
"composite",
|
||||
"strings",
|
||||
"number",
|
||||
"others"
|
||||
}
|
||||
local loadedModules = {
|
||||
}
|
||||
|
||||
local json_decode = {}
|
||||
|
||||
json_decode.default = {
|
||||
unicodeWhitespace = true,
|
||||
initialObject = false,
|
||||
nothrow = false
|
||||
}
|
||||
|
||||
local modes_defined = { "default", "strict", "simple" }
|
||||
|
||||
json_decode.simple = {}
|
||||
|
||||
json_decode.strict = {
|
||||
unicodeWhitespace = true,
|
||||
initialObject = true,
|
||||
nothrow = false
|
||||
}
|
||||
|
||||
for _,name in ipairs(modulesToLoad) do
|
||||
local mod = require("json.decode." .. name)
|
||||
if mod.mergeOptions then
|
||||
for _, mode in pairs(modes_defined) do
|
||||
mod.mergeOptions(json_decode[mode], mode)
|
||||
end
|
||||
end
|
||||
loadedModules[#loadedModules + 1] = mod
|
||||
end
|
||||
|
||||
-- Shift over default into defaultOptions to permit build optimization
|
||||
local defaultOptions = json_decode.default
|
||||
json_decode.default = nil
|
||||
|
||||
local function generateDecoder(lexer, options)
|
||||
-- Marker to permit detection of final end
|
||||
local marker = {}
|
||||
local parser = lpeg.Ct((options.ignored * lexer)^0 * lpeg.Cc(marker)) * options.ignored * (lpeg.P(-1) + util.unexpected())
|
||||
local decoder = function(data)
|
||||
local state = decode_state.create(options)
|
||||
local parsed = parser:match(data)
|
||||
assert(parsed, "Invalid JSON data")
|
||||
local i = 0
|
||||
while true do
|
||||
i = i + 1
|
||||
local item = parsed[i]
|
||||
if item == marker then break end
|
||||
if type(item) == 'function' and item ~= jsonutil.undefined and item ~= jsonutil.null then
|
||||
item(state)
|
||||
else
|
||||
state:set_value(item)
|
||||
end
|
||||
end
|
||||
if options.initialObject then
|
||||
assert(type(state.previous) == 'table', "Initial value not an object or array")
|
||||
end
|
||||
-- Make sure stack is empty
|
||||
assert(state.i == 0, "Unclosed elements present")
|
||||
return state.previous
|
||||
end
|
||||
if options.nothrow then
|
||||
return function(data)
|
||||
local status, rv = pcall(decoder, data)
|
||||
if status then
|
||||
return rv
|
||||
else
|
||||
return nil, rv
|
||||
end
|
||||
end
|
||||
end
|
||||
return decoder
|
||||
end
|
||||
|
||||
local function buildDecoder(mode)
|
||||
mode = mode and merge({}, defaultOptions, mode) or defaultOptions
|
||||
for _, mod in ipairs(loadedModules) do
|
||||
if mod.mergeOptions then
|
||||
mod.mergeOptions(mode)
|
||||
end
|
||||
end
|
||||
local ignored = mode.unicodeWhitespace and util.unicode_ignored or util.ascii_ignored
|
||||
-- Store 'ignored' in the global options table
|
||||
mode.ignored = ignored
|
||||
|
||||
--local grammar = {
|
||||
-- [1] = mode.initialObject and (ignored * (object_type + array_type)) or value_type
|
||||
--}
|
||||
local lexer
|
||||
for _, mod in ipairs(loadedModules) do
|
||||
local new_lexer = mod.generateLexer(mode)
|
||||
lexer = lexer and lexer + new_lexer or new_lexer
|
||||
end
|
||||
return generateDecoder(lexer, mode)
|
||||
end
|
||||
|
||||
-- Since 'default' is nil, we cannot take map it
|
||||
local defaultDecoder = buildDecoder(json_decode.default)
|
||||
local prebuilt_decoders = {}
|
||||
for _, mode in pairs(modes_defined) do
|
||||
if json_decode[mode] ~= nil then
|
||||
prebuilt_decoders[json_decode[mode]] = buildDecoder(json_decode[mode])
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
Options:
|
||||
number => number decode options
|
||||
string => string decode options
|
||||
array => array decode options
|
||||
object => object decode options
|
||||
initialObject => whether or not to require the initial object to be a table/array
|
||||
allowUndefined => whether or not to allow undefined values
|
||||
]]
|
||||
local function getDecoder(mode)
|
||||
mode = mode == true and json_decode.strict or mode or json_decode.default
|
||||
local decoder = mode == nil and defaultDecoder or prebuilt_decoders[mode]
|
||||
if decoder then
|
||||
return decoder
|
||||
end
|
||||
return buildDecoder(mode)
|
||||
end
|
||||
|
||||
local function decode(data, mode)
|
||||
local decoder = getDecoder(mode)
|
||||
return decoder(data)
|
||||
end
|
||||
|
||||
local mt = {}
|
||||
mt.__call = function(self, ...)
|
||||
return decode(...)
|
||||
end
|
||||
|
||||
json_decode.getDecoder = getDecoder
|
||||
json_decode.decode = decode
|
||||
json_decode.util = util
|
||||
setmetatable(json_decode, mt)
|
||||
|
||||
return json_decode
|
190
tools/luajson/json/decode/composite.lua
Normal file
190
tools/luajson/json/decode/composite.lua
Normal file
@ -0,0 +1,190 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local pairs = pairs
|
||||
local type = type
|
||||
|
||||
local lpeg = require("lpeg")
|
||||
|
||||
local util = require("json.decode.util")
|
||||
local jsonutil = require("json.util")
|
||||
|
||||
local rawset = rawset
|
||||
|
||||
local assert = assert
|
||||
local tostring = tostring
|
||||
|
||||
local error = error
|
||||
local getmetatable = getmetatable
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local defaultOptions = {
|
||||
array = {
|
||||
trailingComma = true
|
||||
},
|
||||
object = {
|
||||
trailingComma = true,
|
||||
number = true,
|
||||
identifier = true,
|
||||
setObjectKey = rawset
|
||||
},
|
||||
calls = {
|
||||
defs = nil,
|
||||
-- By default, do not allow undefined calls to be de-serialized as call objects
|
||||
allowUndefined = false
|
||||
}
|
||||
}
|
||||
|
||||
local modeOptions = {
|
||||
default = nil,
|
||||
strict = {
|
||||
array = {
|
||||
trailingComma = false
|
||||
},
|
||||
object = {
|
||||
trailingComma = false,
|
||||
number = false,
|
||||
identifier = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local function BEGIN_ARRAY(state)
|
||||
state:push()
|
||||
state:new_array()
|
||||
end
|
||||
local function END_ARRAY(state)
|
||||
state:end_array()
|
||||
state:pop()
|
||||
end
|
||||
|
||||
local function BEGIN_OBJECT(state)
|
||||
state:push()
|
||||
state:new_object()
|
||||
end
|
||||
local function END_OBJECT(state)
|
||||
state:end_object()
|
||||
state:pop()
|
||||
end
|
||||
|
||||
local function END_CALL(state)
|
||||
state:end_call()
|
||||
state:pop()
|
||||
end
|
||||
|
||||
local function SET_KEY(state)
|
||||
state:set_key()
|
||||
end
|
||||
|
||||
local function NEXT_VALUE(state)
|
||||
state:put_value()
|
||||
end
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, true, 'array', defaultOptions, mode and modeOptions[mode])
|
||||
jsonutil.doOptionMerge(options, true, 'object', defaultOptions, mode and modeOptions[mode])
|
||||
jsonutil.doOptionMerge(options, true, 'calls', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
|
||||
local isPattern
|
||||
if lpeg.type then
|
||||
function isPattern(value)
|
||||
return lpeg.type(value) == 'pattern'
|
||||
end
|
||||
else
|
||||
local metaAdd = getmetatable(lpeg.P("")).__add
|
||||
function isPattern(value)
|
||||
return getmetatable(value).__add == metaAdd
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function generateSingleCallLexer(name, func)
|
||||
if type(name) ~= 'string' and not isPattern(name) then
|
||||
error("Invalid functionCalls name: " .. tostring(name) .. " not a string or LPEG pattern")
|
||||
end
|
||||
-- Allow boolean or function to match up w/ encoding permissions
|
||||
if type(func) ~= 'boolean' and type(func) ~= 'function' then
|
||||
error("Invalid functionCalls item: " .. name .. " not a function")
|
||||
end
|
||||
local function buildCallCapture(name)
|
||||
return function(state)
|
||||
if func == false then
|
||||
error("Function call on '" .. name .. "' not permitted")
|
||||
end
|
||||
state:push()
|
||||
state:new_call(name, func)
|
||||
end
|
||||
end
|
||||
local nameCallCapture
|
||||
if type(name) == 'string' then
|
||||
nameCallCapture = lpeg.P(name .. "(") * lpeg.Cc(name) / buildCallCapture
|
||||
else
|
||||
-- Name matcher expected to produce a capture
|
||||
nameCallCapture = name * "(" / buildCallCapture
|
||||
end
|
||||
-- Call func over nameCallCapture and value to permit function receiving name
|
||||
return nameCallCapture
|
||||
end
|
||||
|
||||
local function generateNamedCallLexers(options)
|
||||
if not options.calls or not options.calls.defs then
|
||||
return
|
||||
end
|
||||
local callCapture
|
||||
for name, func in pairs(options.calls.defs) do
|
||||
local newCapture = generateSingleCallLexer(name, func)
|
||||
if not callCapture then
|
||||
callCapture = newCapture
|
||||
else
|
||||
callCapture = callCapture + newCapture
|
||||
end
|
||||
end
|
||||
return callCapture
|
||||
end
|
||||
|
||||
local function generateCallLexer(options)
|
||||
local lexer
|
||||
local namedCapture = generateNamedCallLexers(options)
|
||||
if options.calls and options.calls.allowUndefined then
|
||||
lexer = generateSingleCallLexer(lpeg.C(util.identifier), true)
|
||||
end
|
||||
if namedCapture then
|
||||
lexer = lexer and lexer + namedCapture or namedCapture
|
||||
end
|
||||
if lexer then
|
||||
lexer = lexer + lpeg.P(")") * lpeg.Cc(END_CALL)
|
||||
end
|
||||
return lexer
|
||||
end
|
||||
|
||||
local function generateLexer(options)
|
||||
local ignored = options.ignored
|
||||
local array_options, object_options = options.array, options.object
|
||||
local lexer =
|
||||
lpeg.P("[") * lpeg.Cc(BEGIN_ARRAY)
|
||||
+ lpeg.P("]") * lpeg.Cc(END_ARRAY)
|
||||
+ lpeg.P("{") * lpeg.Cc(BEGIN_OBJECT)
|
||||
+ lpeg.P("}") * lpeg.Cc(END_OBJECT)
|
||||
+ lpeg.P(":") * lpeg.Cc(SET_KEY)
|
||||
+ lpeg.P(",") * lpeg.Cc(NEXT_VALUE)
|
||||
if object_options.identifier then
|
||||
-- Add identifier match w/ validation check that it is in key
|
||||
lexer = lexer + lpeg.C(util.identifier) * ignored * lpeg.P(":") * lpeg.Cc(SET_KEY)
|
||||
end
|
||||
local callLexers = generateCallLexer(options)
|
||||
if callLexers then
|
||||
lexer = lexer + callLexers
|
||||
end
|
||||
return lexer
|
||||
end
|
||||
|
||||
local composite = {
|
||||
mergeOptions = mergeOptions,
|
||||
generateLexer = generateLexer
|
||||
}
|
||||
|
||||
return composite
|
100
tools/luajson/json/decode/number.lua
Normal file
100
tools/luajson/json/decode/number.lua
Normal file
@ -0,0 +1,100 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local lpeg = require("lpeg")
|
||||
local tonumber = tonumber
|
||||
local jsonutil = require("json.util")
|
||||
local merge = jsonutil.merge
|
||||
local util = require("json.decode.util")
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local digit = lpeg.R("09")
|
||||
local digits = digit^1
|
||||
|
||||
-- Illegal octal declaration
|
||||
local illegal_octal_detect = #(lpeg.P('0') * digits) * util.denied("Octal numbers")
|
||||
|
||||
local int = (lpeg.P('-') + 0) * (lpeg.R("19") * digits + illegal_octal_detect + digit)
|
||||
|
||||
local frac = lpeg.P('.') * digits
|
||||
|
||||
local exp = lpeg.S("Ee") * (lpeg.S("-+") + 0) * digits
|
||||
|
||||
local nan = lpeg.S("Nn") * lpeg.S("Aa") * lpeg.S("Nn")
|
||||
local inf = lpeg.S("Ii") * lpeg.P("nfinity")
|
||||
local ninf = lpeg.P('-') * lpeg.S("Ii") * lpeg.P("nfinity")
|
||||
local hex = (lpeg.P("0x") + lpeg.P("0X")) * lpeg.R("09","AF","af")^1
|
||||
|
||||
local defaultOptions = {
|
||||
nan = true,
|
||||
inf = true,
|
||||
frac = true,
|
||||
exp = true,
|
||||
hex = false
|
||||
}
|
||||
|
||||
local modeOptions = {}
|
||||
|
||||
modeOptions.strict = {
|
||||
nan = false,
|
||||
inf = false
|
||||
}
|
||||
|
||||
local nan_value = 0/0
|
||||
local inf_value = 1/0
|
||||
local ninf_value = -1/0
|
||||
|
||||
--[[
|
||||
Options: configuration options for number rules
|
||||
nan: match NaN
|
||||
inf: match Infinity
|
||||
frac: match fraction portion (.0)
|
||||
exp: match exponent portion (e1)
|
||||
DEFAULT: nan, inf, frac, exp
|
||||
]]
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
local function generateLexer(options)
|
||||
options = options.number
|
||||
local ret = int
|
||||
if options.frac then
|
||||
ret = ret * (frac + 0)
|
||||
else
|
||||
ret = ret * (#frac * util.denied("Fractions", "number.frac") + 0)
|
||||
end
|
||||
if options.exp then
|
||||
ret = ret * (exp + 0)
|
||||
else
|
||||
ret = ret * (#exp * util.denied("Exponents", "number.exp") + 0)
|
||||
end
|
||||
if options.hex then
|
||||
ret = hex + ret
|
||||
else
|
||||
ret = #hex * util.denied("Hexadecimal", "number.hex") + ret
|
||||
end
|
||||
-- Capture number now
|
||||
ret = ret / tonumber
|
||||
if options.nan then
|
||||
ret = ret + nan / function() return nan_value end
|
||||
else
|
||||
ret = ret + #nan * util.denied("NaN", "number.nan")
|
||||
end
|
||||
if options.inf then
|
||||
ret = ret + ninf / function() return ninf_value end + inf / function() return inf_value end
|
||||
else
|
||||
ret = ret + (#ninf + #inf) * util.denied("+/-Inf", "number.inf")
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local number = {
|
||||
int = int,
|
||||
mergeOptions = mergeOptions,
|
||||
generateLexer = generateLexer
|
||||
}
|
||||
|
||||
return number
|
62
tools/luajson/json/decode/others.lua
Normal file
62
tools/luajson/json/decode/others.lua
Normal file
@ -0,0 +1,62 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local lpeg = require("lpeg")
|
||||
local jsonutil = require("json.util")
|
||||
local merge = jsonutil.merge
|
||||
local util = require("json.decode.util")
|
||||
|
||||
-- Container module for other JavaScript types (bool, null, undefined)
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
-- For null and undefined, use the util.null value to preserve null-ness
|
||||
local booleanCapture =
|
||||
lpeg.P("true") * lpeg.Cc(true)
|
||||
+ lpeg.P("false") * lpeg.Cc(false)
|
||||
|
||||
local nullCapture = lpeg.P("null")
|
||||
local undefinedCapture = lpeg.P("undefined")
|
||||
|
||||
local defaultOptions = {
|
||||
allowUndefined = true,
|
||||
null = jsonutil.null,
|
||||
undefined = jsonutil.undefined
|
||||
}
|
||||
|
||||
local modeOptions = {}
|
||||
|
||||
modeOptions.simple = {
|
||||
null = false, -- Mapped to nil
|
||||
undefined = false -- Mapped to nil
|
||||
}
|
||||
modeOptions.strict = {
|
||||
allowUndefined = false
|
||||
}
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
local function generateLexer(options)
|
||||
-- The 'or nil' clause allows false to map to a nil value since 'nil' cannot be merged
|
||||
options = options.others
|
||||
local valueCapture = (
|
||||
booleanCapture
|
||||
+ nullCapture * lpeg.Cc(options.null or nil)
|
||||
)
|
||||
if options.allowUndefined then
|
||||
valueCapture = valueCapture + undefinedCapture * lpeg.Cc(options.undefined or nil)
|
||||
else
|
||||
valueCapture = valueCapture + #undefinedCapture * util.denied("undefined", "others.allowUndefined")
|
||||
end
|
||||
return valueCapture
|
||||
end
|
||||
|
||||
local others = {
|
||||
mergeOptions = mergeOptions,
|
||||
generateLexer = generateLexer
|
||||
}
|
||||
|
||||
return others
|
189
tools/luajson/json/decode/state.lua
Normal file
189
tools/luajson/json/decode/state.lua
Normal file
@ -0,0 +1,189 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local jsonutil = require("json.util")
|
||||
local assert = assert
|
||||
local type = type
|
||||
local next = next
|
||||
local unpack = require("table").unpack or unpack
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local state_ops = {}
|
||||
local state_mt = {
|
||||
__index = state_ops
|
||||
}
|
||||
|
||||
function state_ops.pop(self)
|
||||
self.previous_set = true
|
||||
self.previous = self.active
|
||||
local i = self.i
|
||||
-- Load in this array into the active item
|
||||
self.active = self.stack[i]
|
||||
self.active_state = self.state_stack[i]
|
||||
self.active_key = self.key_stack[i]
|
||||
self.stack[i] = nil
|
||||
self.state_stack[i] = nil
|
||||
self.key_stack[i] = nil
|
||||
|
||||
self.i = i - 1
|
||||
end
|
||||
|
||||
function state_ops.push(self)
|
||||
local i = self.i + 1
|
||||
self.i = i
|
||||
|
||||
self.stack[i] = self.active
|
||||
self.state_stack[i] = self.active_state
|
||||
self.key_stack[i] = self.active_key
|
||||
end
|
||||
|
||||
function state_ops.put_object_value(self, trailing)
|
||||
local object_options = self.options.object
|
||||
if trailing and object_options.trailingComma then
|
||||
if not self.active_key then
|
||||
return
|
||||
end
|
||||
end
|
||||
assert(self.active_key, "Missing key value")
|
||||
object_options.setObjectKey(self.active, self.active_key, self:grab_value())
|
||||
self.active_key = nil
|
||||
end
|
||||
|
||||
function state_ops.put_array_value(self, trailing)
|
||||
-- Safety check
|
||||
if trailing and not self.previous_set and self.options.array.trailingComma then
|
||||
return
|
||||
end
|
||||
local new_index = self.active_state + 1
|
||||
self.active_state = new_index
|
||||
self.active[new_index] = self:grab_value()
|
||||
end
|
||||
|
||||
function state_ops.put_value(self, trailing)
|
||||
if self.active_state == 'object' then
|
||||
self:put_object_value(trailing)
|
||||
else
|
||||
self:put_array_value(trailing)
|
||||
end
|
||||
end
|
||||
|
||||
function state_ops.new_array(self)
|
||||
local new_array = {}
|
||||
if jsonutil.InitArray then
|
||||
new_array = jsonutil.InitArray(new_array) or new_array
|
||||
end
|
||||
self.active = new_array
|
||||
self.active_state = 0
|
||||
self.active_key = nil
|
||||
self:unset_value()
|
||||
end
|
||||
|
||||
function state_ops.end_array(self)
|
||||
if self.previous_set or self.active_state ~= 0 then
|
||||
-- Not an empty array
|
||||
self:put_value(true)
|
||||
end
|
||||
if self.active_state ~= #self.active then
|
||||
-- Store the length in
|
||||
self.active.n = self.active_state
|
||||
end
|
||||
end
|
||||
|
||||
function state_ops.new_object(self)
|
||||
local new_object = {}
|
||||
self.active = new_object
|
||||
self.active_state = 'object'
|
||||
self.active_key = nil
|
||||
self:unset_value()
|
||||
end
|
||||
|
||||
function state_ops.end_object(self)
|
||||
if self.previous_set or next(self.active) then
|
||||
-- Not an empty object
|
||||
self:put_value(true)
|
||||
end
|
||||
end
|
||||
|
||||
function state_ops.new_call(self, name, func)
|
||||
-- TODO setup properly
|
||||
local new_call = {}
|
||||
new_call.name = name
|
||||
new_call.func = func
|
||||
self.active = new_call
|
||||
self.active_state = 0
|
||||
self.active_key = nil
|
||||
self:unset_value()
|
||||
end
|
||||
|
||||
function state_ops.end_call(self)
|
||||
if self.previous_set or self.active_state ~= 0 then
|
||||
-- Not an empty array
|
||||
self:put_value(true)
|
||||
end
|
||||
if self.active_state ~= #self.active then
|
||||
-- Store the length in
|
||||
self.active.n = self.active_state
|
||||
end
|
||||
local func = self.active.func
|
||||
if func == true then
|
||||
func = jsonutil.buildCall
|
||||
end
|
||||
self.active = func(self.active.name, unpack(self.active, 1, self.active.n or #self.active))
|
||||
end
|
||||
|
||||
|
||||
function state_ops.unset_value(self)
|
||||
self.previous_set = false
|
||||
self.previous = nil
|
||||
end
|
||||
|
||||
function state_ops.grab_value(self)
|
||||
assert(self.previous_set, "Previous value not set")
|
||||
self.previous_set = false
|
||||
return self.previous
|
||||
end
|
||||
|
||||
function state_ops.set_value(self, value)
|
||||
assert(not self.previous_set, "Value set when one already in slot")
|
||||
self.previous_set = true
|
||||
self.previous = value
|
||||
end
|
||||
|
||||
function state_ops.set_key(self)
|
||||
assert(self.active_state == 'object', "Cannot set key on array")
|
||||
local value = self:grab_value()
|
||||
local value_type = type(value)
|
||||
if self.options.object.number then
|
||||
assert(value_type == 'string' or value_type == 'number', "As configured, a key must be a number or string")
|
||||
else
|
||||
assert(value_type == 'string', "As configured, a key must be a string")
|
||||
end
|
||||
self.active_key = value
|
||||
end
|
||||
|
||||
|
||||
local function create(options)
|
||||
local ret = {
|
||||
options = options,
|
||||
stack = {},
|
||||
state_stack = {},
|
||||
key_stack = {},
|
||||
i = 0,
|
||||
active = nil,
|
||||
active_key = nil,
|
||||
previous = nil,
|
||||
active_state = nil
|
||||
|
||||
}
|
||||
return setmetatable(ret, state_mt)
|
||||
end
|
||||
|
||||
local state = {
|
||||
create = create
|
||||
}
|
||||
|
||||
return state
|
133
tools/luajson/json/decode/strings.lua
Normal file
133
tools/luajson/json/decode/strings.lua
Normal file
@ -0,0 +1,133 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local lpeg = require("lpeg")
|
||||
local jsonutil = require("json.util")
|
||||
local util = require("json.decode.util")
|
||||
local merge = jsonutil.merge
|
||||
|
||||
local tonumber = tonumber
|
||||
local string_char = require("string").char
|
||||
local floor = require("math").floor
|
||||
local table_concat = require("table").concat
|
||||
|
||||
local error = error
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local function get_error(item)
|
||||
local fmt_string = item .. " in string [%q] @ %i:%i"
|
||||
return lpeg.P(function(data, index)
|
||||
local line, line_index, bad_char, last_line = util.get_invalid_character_info(data, index)
|
||||
local err = fmt_string:format(bad_char, line, line_index)
|
||||
error(err)
|
||||
end) * 1
|
||||
end
|
||||
|
||||
local bad_unicode = get_error("Illegal unicode escape")
|
||||
local bad_hex = get_error("Illegal hex escape")
|
||||
local bad_character = get_error("Illegal character")
|
||||
local bad_escape = get_error("Illegal escape")
|
||||
|
||||
local knownReplacements = {
|
||||
["'"] = "'",
|
||||
['"'] = '"',
|
||||
['\\'] = '\\',
|
||||
['/'] = '/',
|
||||
b = '\b',
|
||||
f = '\f',
|
||||
n = '\n',
|
||||
r = '\r',
|
||||
t = '\t',
|
||||
v = '\v',
|
||||
z = '\z'
|
||||
}
|
||||
|
||||
-- according to the table at http://da.wikipedia.org/wiki/UTF-8
|
||||
local function utf8DecodeUnicode(code1, code2)
|
||||
code1, code2 = tonumber(code1, 16), tonumber(code2, 16)
|
||||
if code1 == 0 and code2 < 0x80 then
|
||||
return string_char(code2)
|
||||
end
|
||||
if code1 < 0x08 then
|
||||
return string_char(
|
||||
0xC0 + code1 * 4 + floor(code2 / 64),
|
||||
0x80 + code2 % 64)
|
||||
end
|
||||
return string_char(
|
||||
0xE0 + floor(code1 / 16),
|
||||
0x80 + (code1 % 16) * 4 + floor(code2 / 64),
|
||||
0x80 + code2 % 64)
|
||||
end
|
||||
|
||||
local function decodeX(code)
|
||||
code = tonumber(code, 16)
|
||||
return string_char(code)
|
||||
end
|
||||
|
||||
local doSimpleSub = lpeg.C(lpeg.S("'\"\\/bfnrtvz")) / knownReplacements
|
||||
local doUniSub = lpeg.P('u') * (lpeg.C(util.hexpair) * lpeg.C(util.hexpair) + bad_unicode)
|
||||
local doXSub = lpeg.P('x') * (lpeg.C(util.hexpair) + bad_hex)
|
||||
|
||||
local defaultOptions = {
|
||||
badChars = '',
|
||||
additionalEscapes = false, -- disallow untranslated escapes
|
||||
escapeCheck = #lpeg.S('bfnrtv/\\"xu\'z'), -- no check on valid characters
|
||||
decodeUnicode = utf8DecodeUnicode,
|
||||
strict_quotes = false
|
||||
}
|
||||
|
||||
local modeOptions = {}
|
||||
|
||||
modeOptions.strict = {
|
||||
badChars = '\b\f\n\r\t\v',
|
||||
additionalEscapes = false, -- no additional escapes
|
||||
escapeCheck = #lpeg.S('bfnrtv/\\"u'), --only these chars are allowed to be escaped
|
||||
strict_quotes = true
|
||||
}
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
local function buildCaptureString(quote, badChars, escapeMatch)
|
||||
local captureChar = (1 - lpeg.S("\\" .. badChars .. quote)) + (lpeg.P("\\") / "" * escapeMatch)
|
||||
-- During error, force end
|
||||
local captureString = captureChar^0 + (-#lpeg.P(quote) * bad_character + -1)
|
||||
return lpeg.P(quote) * lpeg.Cs(captureString) * lpeg.P(quote)
|
||||
end
|
||||
|
||||
local function generateLexer(options)
|
||||
options = options.strings
|
||||
local quotes = { '"' }
|
||||
if not options.strict_quotes then
|
||||
quotes[#quotes + 1] = "'"
|
||||
end
|
||||
local escapeMatch = doSimpleSub
|
||||
escapeMatch = escapeMatch + doXSub / decodeX
|
||||
escapeMatch = escapeMatch + doUniSub / options.decodeUnicode
|
||||
if options.escapeCheck then
|
||||
escapeMatch = options.escapeCheck * escapeMatch + bad_escape
|
||||
end
|
||||
if options.additionalEscapes then
|
||||
escapeMatch = options.additionalEscapes + escapeMatch
|
||||
end
|
||||
local captureString
|
||||
for i = 1, #quotes do
|
||||
local cap = buildCaptureString(quotes[i], options.badChars, escapeMatch)
|
||||
if captureString == nil then
|
||||
captureString = cap
|
||||
else
|
||||
captureString = captureString + cap
|
||||
end
|
||||
end
|
||||
return captureString
|
||||
end
|
||||
|
||||
local strings = {
|
||||
mergeOptions = mergeOptions,
|
||||
generateLexer = generateLexer
|
||||
}
|
||||
|
||||
return strings
|
121
tools/luajson/json/decode/util.lua
Normal file
121
tools/luajson/json/decode/util.lua
Normal file
@ -0,0 +1,121 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local lpeg = require("lpeg")
|
||||
local select = select
|
||||
local pairs, ipairs = pairs, ipairs
|
||||
local tonumber = tonumber
|
||||
local string_char = require("string").char
|
||||
local rawset = rawset
|
||||
local jsonutil = require("json.util")
|
||||
|
||||
local error = error
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local table_concat = require("table").concat
|
||||
|
||||
local merge = require("json.util").merge
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local function get_invalid_character_info(input, index)
|
||||
local parsed = input:sub(1, index)
|
||||
local bad_character = input:sub(index, index)
|
||||
local _, line_number = parsed:gsub('\n',{})
|
||||
local last_line = parsed:match("\n([^\n]+.)$") or parsed
|
||||
return line_number, #last_line, bad_character, last_line
|
||||
end
|
||||
|
||||
local function build_report(msg)
|
||||
local fmt = msg:gsub("%%", "%%%%") .. " @ character: %i %i:%i [%s] line:\n%s"
|
||||
return lpeg.P(function(data, pos)
|
||||
local line, line_index, bad_char, last_line = get_invalid_character_info(data, pos)
|
||||
local text = fmt:format(pos, line, line_index, bad_char, last_line)
|
||||
error(text)
|
||||
end) * 1
|
||||
end
|
||||
local function unexpected()
|
||||
local msg = "unexpected character"
|
||||
return build_report(msg)
|
||||
end
|
||||
local function denied(item, option)
|
||||
local msg
|
||||
if option then
|
||||
msg = ("'%s' denied by option set '%s'"):format(item, option)
|
||||
else
|
||||
msg = ("'%s' denied"):format(item)
|
||||
end
|
||||
return build_report(msg)
|
||||
end
|
||||
|
||||
-- 09, 0A, 0B, 0C, 0D, 20
|
||||
local ascii_space = lpeg.S("\t\n\v\f\r ")
|
||||
local unicode_space
|
||||
do
|
||||
local chr = string_char
|
||||
local u_space = ascii_space
|
||||
-- \u0085 \u00A0
|
||||
u_space = u_space + lpeg.P(chr(0xC2)) * lpeg.S(chr(0x85) .. chr(0xA0))
|
||||
-- \u1680 \u180E
|
||||
u_space = u_space + lpeg.P(chr(0xE1)) * (lpeg.P(chr(0x9A, 0x80)) + chr(0xA0, 0x8E))
|
||||
-- \u2000 - \u200A, also 200B
|
||||
local spacing_end = ""
|
||||
for i = 0x80,0x8b do
|
||||
spacing_end = spacing_end .. chr(i)
|
||||
end
|
||||
-- \u2028 \u2029 \u202F
|
||||
spacing_end = spacing_end .. chr(0xA8) .. chr(0xA9) .. chr(0xAF)
|
||||
u_space = u_space + lpeg.P(chr(0xE2, 0x80)) * lpeg.S(spacing_end)
|
||||
-- \u205F
|
||||
u_space = u_space + lpeg.P(chr(0xE2, 0x81, 0x9F))
|
||||
-- \u3000
|
||||
u_space = u_space + lpeg.P(chr(0xE3, 0x80, 0x80))
|
||||
-- BOM \uFEFF
|
||||
u_space = u_space + lpeg.P(chr(0xEF, 0xBB, 0xBF))
|
||||
unicode_space = u_space
|
||||
end
|
||||
|
||||
local identifier = lpeg.R("AZ","az","__") * lpeg.R("AZ","az", "__", "09") ^0
|
||||
|
||||
local hex = lpeg.R("09","AF","af")
|
||||
local hexpair = hex * hex
|
||||
|
||||
local comments = {
|
||||
cpp = lpeg.P("//") * (1 - lpeg.P("\n"))^0 * lpeg.P("\n"),
|
||||
c = lpeg.P("/*") * (1 - lpeg.P("*/"))^0 * lpeg.P("*/")
|
||||
}
|
||||
|
||||
local comment = comments.cpp + comments.c
|
||||
|
||||
local ascii_ignored = (ascii_space + comment)^0
|
||||
|
||||
local unicode_ignored = (unicode_space + comment)^0
|
||||
|
||||
-- Parse the lpeg version skipping patch-values
|
||||
-- LPEG <= 0.7 have no version value... so 0.7 is value
|
||||
local DecimalLpegVersion = lpeg.version and tonumber(lpeg.version():match("^(%d+%.%d+)")) or 0.7
|
||||
|
||||
local function setObjectKeyForceNumber(t, key, value)
|
||||
key = tonumber(key) or key
|
||||
return rawset(t, key, value)
|
||||
end
|
||||
|
||||
local util = {
|
||||
unexpected = unexpected,
|
||||
denied = denied,
|
||||
ascii_space = ascii_space,
|
||||
unicode_space = unicode_space,
|
||||
identifier = identifier,
|
||||
hex = hex,
|
||||
hexpair = hexpair,
|
||||
comments = comments,
|
||||
comment = comment,
|
||||
ascii_ignored = ascii_ignored,
|
||||
unicode_ignored = unicode_ignored,
|
||||
DecimalLpegVersion = DecimalLpegVersion,
|
||||
get_invalid_character_info = get_invalid_character_info,
|
||||
setObjectKeyForceNumber = setObjectKeyForceNumber
|
||||
}
|
||||
|
||||
return util
|
161
tools/luajson/json/encode.lua
Normal file
161
tools/luajson/json/encode.lua
Normal file
@ -0,0 +1,161 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local type = type
|
||||
local assert, error = assert, error
|
||||
local getmetatable, setmetatable = getmetatable, setmetatable
|
||||
|
||||
local ipairs, pairs = ipairs, pairs
|
||||
local require = require
|
||||
|
||||
local output = require("json.encode.output")
|
||||
|
||||
local util = require("json.util")
|
||||
local util_merge, isCall = util.merge, util.isCall
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
--[[
|
||||
List of encoding modules to load.
|
||||
Loaded in sequence such that earlier encoders get priority when
|
||||
duplicate type-handlers exist.
|
||||
]]
|
||||
local modulesToLoad = {
|
||||
"strings",
|
||||
"number",
|
||||
"calls",
|
||||
"others",
|
||||
"array",
|
||||
"object"
|
||||
}
|
||||
-- Modules that have been loaded
|
||||
local loadedModules = {}
|
||||
|
||||
local json_encode = {}
|
||||
|
||||
-- Configuration bases for client apps
|
||||
local modes_defined = { "default", "strict" }
|
||||
|
||||
json_encode.default = {}
|
||||
json_encode.strict = {
|
||||
initialObject = true -- Require an object at the root
|
||||
}
|
||||
|
||||
-- For each module, load it and its defaults
|
||||
for _,name in ipairs(modulesToLoad) do
|
||||
local mod = require("json.encode." .. name)
|
||||
if mod.mergeOptions then
|
||||
for _, mode in pairs(modes_defined) do
|
||||
mod.mergeOptions(json_encode[mode], mode)
|
||||
end
|
||||
end
|
||||
loadedModules[name] = mod
|
||||
end
|
||||
|
||||
-- NOTE: Nested not found, so assume unsupported until use case arises
|
||||
local function flattenOutput(out, value)
|
||||
assert(type(value) ~= 'table')
|
||||
out = out or {}
|
||||
out[#out + 1] = value
|
||||
return out
|
||||
end
|
||||
|
||||
-- Prepares the encoding map from the already provided modules and new config
|
||||
local function prepareEncodeMap(options)
|
||||
local map = {}
|
||||
for _, name in ipairs(modulesToLoad) do
|
||||
local encodermap = loadedModules[name].getEncoder(options[name])
|
||||
for valueType, encoderSet in pairs(encodermap) do
|
||||
map[valueType] = flattenOutput(map[valueType], encoderSet)
|
||||
end
|
||||
end
|
||||
return map
|
||||
end
|
||||
|
||||
--[[
|
||||
Encode a value with a given encoding map and state
|
||||
]]
|
||||
local function encodeWithMap(value, map, state, isObjectKey)
|
||||
local t = type(value)
|
||||
local encoderList = assert(map[t], "Failed to encode value, unhandled type: " .. t)
|
||||
for _, encoder in ipairs(encoderList) do
|
||||
local ret = encoder(value, state, isObjectKey)
|
||||
if false ~= ret then
|
||||
return ret
|
||||
end
|
||||
end
|
||||
error("Failed to encode value, encoders for " .. t .. " deny encoding")
|
||||
end
|
||||
|
||||
|
||||
local function getBaseEncoder(options)
|
||||
local encoderMap = prepareEncodeMap(options)
|
||||
if options.preProcess then
|
||||
local preProcess = options.preProcess
|
||||
return function(value, state, isObjectKey)
|
||||
local ret = preProcess(value, isObjectKey or false)
|
||||
if nil ~= ret then
|
||||
value = ret
|
||||
end
|
||||
return encodeWithMap(value, encoderMap, state)
|
||||
end
|
||||
end
|
||||
return function(value, state, isObjectKey)
|
||||
return encodeWithMap(value, encoderMap, state)
|
||||
end
|
||||
end
|
||||
--[[
|
||||
Retreive an initial encoder instance based on provided options
|
||||
the initial encoder is responsible for initializing state
|
||||
State has at least these values configured: encode, check_unique, already_encoded
|
||||
]]
|
||||
function json_encode.getEncoder(options)
|
||||
options = options and util_merge({}, json_encode.default, options) or json_encode.default
|
||||
local encode = getBaseEncoder(options)
|
||||
|
||||
local function initialEncode(value)
|
||||
if options.initialObject then
|
||||
local errorMessage = "Invalid arguments: expects a JSON Object or Array at the root"
|
||||
assert(type(value) == 'table' and not isCall(value, options), errorMessage)
|
||||
end
|
||||
|
||||
local alreadyEncoded = {}
|
||||
local function check_unique(value)
|
||||
assert(not alreadyEncoded[value], "Recursive encoding of value")
|
||||
alreadyEncoded[value] = true
|
||||
end
|
||||
|
||||
local outputEncoder = options.output and options.output() or output.getDefault()
|
||||
local state = {
|
||||
encode = encode,
|
||||
check_unique = check_unique,
|
||||
already_encoded = alreadyEncoded, -- To unmark encoding when moving up stack
|
||||
outputEncoder = outputEncoder
|
||||
}
|
||||
local ret = encode(value, state)
|
||||
if nil ~= ret then
|
||||
return outputEncoder.simple and outputEncoder.simple(ret) or ret
|
||||
end
|
||||
end
|
||||
return initialEncode
|
||||
end
|
||||
|
||||
-- CONSTRUCT STATE WITH FOLLOWING (at least)
|
||||
--[[
|
||||
encoder
|
||||
check_unique -- used by inner encoders to make sure value is unique
|
||||
already_encoded -- used to unmark a value as unique
|
||||
]]
|
||||
function json_encode.encode(data, options)
|
||||
return json_encode.getEncoder(options)(data)
|
||||
end
|
||||
|
||||
local mt = {}
|
||||
mt.__call = function(self, ...)
|
||||
return json_encode.encode(...)
|
||||
end
|
||||
|
||||
setmetatable(json_encode, mt)
|
||||
|
||||
return json_encode
|
110
tools/luajson/json/encode/array.lua
Normal file
110
tools/luajson/json/encode/array.lua
Normal file
@ -0,0 +1,110 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local jsonutil = require("json.util")
|
||||
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local assert = assert
|
||||
|
||||
local table = require("table")
|
||||
local math = require("math")
|
||||
local table_concat = table.concat
|
||||
local math_floor, math_modf = math.floor, math.modf
|
||||
|
||||
local jsonutil = require("json.util")
|
||||
local util_IsArray = jsonutil.IsArray
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local defaultOptions = {
|
||||
isArray = util_IsArray
|
||||
}
|
||||
|
||||
local modeOptions = {}
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'array', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
--[[
|
||||
Utility function to determine whether a table is an array or not.
|
||||
Criteria for it being an array:
|
||||
* ExternalIsArray returns true (or false directly reports not-array)
|
||||
* If the table has an 'n' value that is an integer >= 1 then it
|
||||
is an array... may result in false positives (should check some values
|
||||
before it)
|
||||
* It is a contiguous list of values with zero string-based keys
|
||||
]]
|
||||
local function isArray(val, options)
|
||||
local externalIsArray = options and options.isArray
|
||||
|
||||
if externalIsArray then
|
||||
local ret = externalIsArray(val)
|
||||
if ret == true or ret == false then
|
||||
return ret
|
||||
end
|
||||
end
|
||||
-- Use the 'n' element if it's a number
|
||||
if type(val.n) == 'number' and math_floor(val.n) == val.n and val.n >= 1 then
|
||||
return true
|
||||
end
|
||||
local len = #val
|
||||
for k,v in pairs(val) do
|
||||
if type(k) ~= 'number' then
|
||||
return false
|
||||
end
|
||||
local _, decim = math_modf(k)
|
||||
if not (decim == 0 and 1<=k) then
|
||||
return false
|
||||
end
|
||||
if k > len then -- Use Lua's length as absolute determiner
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--[[
|
||||
Cleanup function to unmark a value as in the encoding process and return
|
||||
trailing results
|
||||
]]
|
||||
local function unmarkAfterEncode(tab, state, ...)
|
||||
state.already_encoded[tab] = nil
|
||||
return ...
|
||||
end
|
||||
local function getEncoder(options)
|
||||
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||
local function encodeArray(tab, state)
|
||||
if not isArray(tab, options) then
|
||||
return false
|
||||
end
|
||||
-- Make sure this value hasn't been encoded yet
|
||||
state.check_unique(tab)
|
||||
local encode = state.encode
|
||||
local compositeEncoder = state.outputEncoder.composite
|
||||
local valueEncoder = [[
|
||||
for i = 1, (composite.n or #composite) do
|
||||
local val = composite[i]
|
||||
PUTINNER(i ~= 1)
|
||||
val = encode(val, state)
|
||||
val = val or ''
|
||||
if val then
|
||||
PUTVALUE(val)
|
||||
end
|
||||
end
|
||||
]]
|
||||
return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '[', ']', ',', tab, encode, state))
|
||||
end
|
||||
return { table = encodeArray }
|
||||
end
|
||||
|
||||
local array = {
|
||||
mergeOptions = mergeOptions,
|
||||
isArray = isArray,
|
||||
getEncoder = getEncoder
|
||||
}
|
||||
|
||||
return array
|
68
tools/luajson/json/encode/calls.lua
Normal file
68
tools/luajson/json/encode/calls.lua
Normal file
@ -0,0 +1,68 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local table = require("table")
|
||||
local table_concat = table.concat
|
||||
|
||||
local select = select
|
||||
local getmetatable, setmetatable = getmetatable, setmetatable
|
||||
local assert = assert
|
||||
|
||||
local jsonutil = require("json.util")
|
||||
|
||||
local isCall, decodeCall = jsonutil.isCall, jsonutil.decodeCall
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local defaultOptions = {
|
||||
}
|
||||
|
||||
-- No real default-option handling needed...
|
||||
local modeOptions = {}
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'calls', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
|
||||
--[[
|
||||
Encodes 'value' as a function call
|
||||
Must have parameters in the 'callData' field of the metatable
|
||||
name == name of the function call
|
||||
parameters == array of parameters to encode
|
||||
]]
|
||||
local function getEncoder(options)
|
||||
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||
local function encodeCall(value, state)
|
||||
if not isCall(value) then
|
||||
return false
|
||||
end
|
||||
local encode = state.encode
|
||||
local name, params = decodeCall(value)
|
||||
local compositeEncoder = state.outputEncoder.composite
|
||||
local valueEncoder = [[
|
||||
for i = 1, (composite.n or #composite) do
|
||||
local val = composite[i]
|
||||
PUTINNER(i ~= 1)
|
||||
val = encode(val, state)
|
||||
val = val or ''
|
||||
if val then
|
||||
PUTVALUE(val)
|
||||
end
|
||||
end
|
||||
]]
|
||||
return compositeEncoder(valueEncoder, name .. '(', ')', ',', params, encode, state)
|
||||
end
|
||||
return {
|
||||
table = encodeCall,
|
||||
['function'] = encodeCall
|
||||
}
|
||||
end
|
||||
|
||||
local calls = {
|
||||
mergeOptions = mergeOptions,
|
||||
getEncoder = getEncoder
|
||||
}
|
||||
|
||||
return calls
|
58
tools/luajson/json/encode/number.lua
Normal file
58
tools/luajson/json/encode/number.lua
Normal file
@ -0,0 +1,58 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local tostring = tostring
|
||||
local assert = assert
|
||||
local jsonutil = require("json.util")
|
||||
local huge = require("math").huge
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local defaultOptions = {
|
||||
nan = true,
|
||||
inf = true
|
||||
}
|
||||
|
||||
local modeOptions = {}
|
||||
modeOptions.strict = {
|
||||
nan = false,
|
||||
inf = false
|
||||
}
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'number', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
|
||||
local function encodeNumber(number, options)
|
||||
if number ~= number then
|
||||
assert(options.nan, "Invalid number: NaN not enabled")
|
||||
return "NaN"
|
||||
end
|
||||
if number == huge then
|
||||
assert(options.inf, "Invalid number: Infinity not enabled")
|
||||
return "Infinity"
|
||||
end
|
||||
if number == -huge then
|
||||
assert(options.inf, "Invalid number: Infinity not enabled")
|
||||
return "-Infinity"
|
||||
end
|
||||
return tostring(number)
|
||||
end
|
||||
|
||||
local function getEncoder(options)
|
||||
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||
return {
|
||||
number = function(number, state)
|
||||
return encodeNumber(number, options)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local number = {
|
||||
mergeOptions = mergeOptions,
|
||||
getEncoder = getEncoder
|
||||
}
|
||||
|
||||
return number
|
77
tools/luajson/json/encode/object.lua
Normal file
77
tools/luajson/json/encode/object.lua
Normal file
@ -0,0 +1,77 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local pairs = pairs
|
||||
local assert = assert
|
||||
|
||||
local type = type
|
||||
local tostring = tostring
|
||||
|
||||
local table_concat = require("table").concat
|
||||
local jsonutil = require("json.util")
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local defaultOptions = {
|
||||
}
|
||||
|
||||
local modeOptions = {}
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'object', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
--[[
|
||||
Cleanup function to unmark a value as in the encoding process and return
|
||||
trailing results
|
||||
]]
|
||||
local function unmarkAfterEncode(tab, state, ...)
|
||||
state.already_encoded[tab] = nil
|
||||
return ...
|
||||
end
|
||||
--[[
|
||||
Encode a table as a JSON Object ( keys = strings, values = anything else )
|
||||
]]
|
||||
local function encodeTable(tab, options, state)
|
||||
-- Make sure this value hasn't been encoded yet
|
||||
state.check_unique(tab)
|
||||
local encode = state.encode
|
||||
local compositeEncoder = state.outputEncoder.composite
|
||||
local valueEncoder = [[
|
||||
local first = true
|
||||
for k, v in pairs(composite) do
|
||||
local ti = type(k)
|
||||
assert(ti == 'string' or ti == 'number' or ti == 'boolean', "Invalid object index type: " .. ti)
|
||||
local name = encode(tostring(k), state, true)
|
||||
if first then
|
||||
first = false
|
||||
else
|
||||
name = ',' .. name
|
||||
end
|
||||
PUTVALUE(name .. ':')
|
||||
local val = encode(v, state)
|
||||
val = val or ''
|
||||
if val then
|
||||
PUTVALUE(val)
|
||||
end
|
||||
end
|
||||
]]
|
||||
return unmarkAfterEncode(tab, state, compositeEncoder(valueEncoder, '{', '}', nil, tab, encode, state))
|
||||
end
|
||||
|
||||
local function getEncoder(options)
|
||||
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||
return {
|
||||
table = function(tab, state)
|
||||
return encodeTable(tab, options, state)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local object = {
|
||||
mergeOptions = mergeOptions,
|
||||
getEncoder = getEncoder
|
||||
}
|
||||
|
||||
return object
|
66
tools/luajson/json/encode/others.lua
Normal file
66
tools/luajson/json/encode/others.lua
Normal file
@ -0,0 +1,66 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local tostring = tostring
|
||||
|
||||
local assert = assert
|
||||
local jsonutil = require("json.util")
|
||||
local type = type
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
-- Shortcut that works
|
||||
local encodeBoolean = tostring
|
||||
|
||||
local defaultOptions = {
|
||||
allowUndefined = true,
|
||||
null = jsonutil.null,
|
||||
undefined = jsonutil.undefined
|
||||
}
|
||||
|
||||
local modeOptions = {}
|
||||
|
||||
modeOptions.strict = {
|
||||
allowUndefined = false
|
||||
}
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'others', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
local function getEncoder(options)
|
||||
options = options and jsonutil.merge({}, defaultOptions, options) or defaultOptions
|
||||
local function encodeOthers(value, state)
|
||||
if value == options.null then
|
||||
return 'null'
|
||||
elseif value == options.undefined then
|
||||
assert(options.allowUndefined, "Invalid value: Unsupported 'Undefined' parameter")
|
||||
return 'undefined'
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
local function encodeBoolean(value, state)
|
||||
return value and 'true' or 'false'
|
||||
end
|
||||
local nullType = type(options.null)
|
||||
local undefinedType = options.undefined and type(options.undefined)
|
||||
-- Make sure that all of the types handled here are handled
|
||||
local ret = {
|
||||
boolean = encodeBoolean,
|
||||
['nil'] = function() return 'null' end,
|
||||
[nullType] = encodeOthers
|
||||
}
|
||||
if undefinedType then
|
||||
ret[undefinedType] = encodeOthers
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local others = {
|
||||
encodeBoolean = encodeBoolean,
|
||||
mergeOptions = mergeOptions,
|
||||
getEncoder = getEncoder
|
||||
}
|
||||
|
||||
return others
|
91
tools/luajson/json/encode/output.lua
Normal file
91
tools/luajson/json/encode/output.lua
Normal file
@ -0,0 +1,91 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local type = type
|
||||
local assert, error = assert, error
|
||||
local table_concat = require("table").concat
|
||||
local loadstring = loadstring or load
|
||||
|
||||
local io = require("io")
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local output_utility = require("json.encode.output_utility")
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local tableCompositeCache = setmetatable({}, {__mode = 'v'})
|
||||
|
||||
local TABLE_VALUE_WRITER = [[
|
||||
ret[#ret + 1] = %VALUE%
|
||||
]]
|
||||
|
||||
local TABLE_INNER_WRITER = ""
|
||||
|
||||
--[[
|
||||
nextValues can output a max of two values to throw into the data stream
|
||||
expected to be called until nil is first return value
|
||||
value separator should either be attached to v1 or in innerValue
|
||||
]]
|
||||
local function defaultTableCompositeWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state)
|
||||
if type(nextValues) == 'string' then
|
||||
local fun = output_utility.prepareEncoder(defaultTableCompositeWriter, nextValues, innerValue, TABLE_VALUE_WRITER, TABLE_INNER_WRITER)
|
||||
local ret = {}
|
||||
fun(composite, ret, encode, state)
|
||||
return beginValue .. table_concat(ret, innerValue) .. closeValue
|
||||
end
|
||||
end
|
||||
|
||||
-- no 'simple' as default action is just to return the value
|
||||
local function getDefault()
|
||||
return { composite = defaultTableCompositeWriter }
|
||||
end
|
||||
|
||||
-- BEGIN IO-WRITER OUTPUT
|
||||
local IO_INNER_WRITER = [[
|
||||
if %WRITE_INNER% then
|
||||
state.__outputFile:write(%INNER_VALUE%)
|
||||
end
|
||||
]]
|
||||
local IO_VALUE_WRITER = [[
|
||||
state.__outputFile:write(%VALUE%)
|
||||
]]
|
||||
|
||||
local function buildIoWriter(output)
|
||||
if not output then -- Default to stdout
|
||||
output = io.output()
|
||||
end
|
||||
local function ioWriter(nextValues, beginValue, closeValue, innerValue, composite, encode, state)
|
||||
-- HOOK OUTPUT STATE
|
||||
state.__outputFile = output
|
||||
if type(nextValues) == 'string' then
|
||||
local fun = output_utility.prepareEncoder(ioWriter, nextValues, innerValue, IO_VALUE_WRITER, IO_INNER_WRITER)
|
||||
local ret = {}
|
||||
output:write(beginValue)
|
||||
fun(composite, ret, encode, state)
|
||||
output:write(closeValue)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local function ioSimpleWriter(encoded)
|
||||
if encoded then
|
||||
output:write(encoded)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
return { composite = ioWriter, simple = ioSimpleWriter }
|
||||
end
|
||||
local function getIoWriter(output)
|
||||
return function()
|
||||
return buildIoWriter(output)
|
||||
end
|
||||
end
|
||||
|
||||
local output = {
|
||||
getDefault = getDefault,
|
||||
getIoWriter = getIoWriter
|
||||
}
|
||||
|
||||
return output
|
54
tools/luajson/json/encode/output_utility.lua
Normal file
54
tools/luajson/json/encode/output_utility.lua
Normal file
@ -0,0 +1,54 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local setmetatable = setmetatable
|
||||
local assert, loadstring = assert, loadstring or load
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
-- Key == weak, if main key goes away, then cache cleared
|
||||
local outputCache = setmetatable({}, {__mode = 'k'})
|
||||
-- TODO: inner tables weak?
|
||||
|
||||
local function buildFunction(nextValues, innerValue, valueWriter, innerWriter)
|
||||
local putInner = ""
|
||||
if innerValue and innerWriter then
|
||||
-- Prepare the lua-string representation of the separator to put in between values
|
||||
local formattedInnerValue = ("%q"):format(innerValue)
|
||||
-- Fill in the condition %WRITE_INNER% and the %INNER_VALUE% to actually write
|
||||
putInner = innerWriter:gsub("%%WRITE_INNER%%", "%%1"):gsub("%%INNER_VALUE%%", formattedInnerValue)
|
||||
end
|
||||
-- Template-in the value writer (if present) and its conditional argument
|
||||
local functionCode = nextValues:gsub("PUTINNER(%b())", putInner)
|
||||
-- %VALUE% is to be filled in by the value-to-write
|
||||
valueWriter = valueWriter:gsub("%%VALUE%%", "%%1")
|
||||
-- Template-in the value writer with its argument
|
||||
functionCode = functionCode:gsub("PUTVALUE(%b())", valueWriter)
|
||||
functionCode = [[
|
||||
return function(composite, ret, encode, state)
|
||||
]] .. functionCode .. [[
|
||||
end
|
||||
]]
|
||||
return assert(loadstring(functionCode))()
|
||||
end
|
||||
|
||||
local function prepareEncoder(cacheKey, nextValues, innerValue, valueWriter, innerWriter)
|
||||
local cache = outputCache[cacheKey]
|
||||
if not cache then
|
||||
cache = {}
|
||||
outputCache[cacheKey] = cache
|
||||
end
|
||||
local fun = cache[nextValues]
|
||||
if not fun then
|
||||
fun = buildFunction(nextValues, innerValue, valueWriter, innerWriter)
|
||||
cache[nextValues] = fun
|
||||
end
|
||||
return fun
|
||||
end
|
||||
|
||||
local output_utility = {
|
||||
prepareEncoder = prepareEncoder
|
||||
}
|
||||
|
||||
return output_utility
|
88
tools/luajson/json/encode/strings.lua
Normal file
88
tools/luajson/json/encode/strings.lua
Normal file
@ -0,0 +1,88 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local string_char = require("string").char
|
||||
local pairs = pairs
|
||||
|
||||
local jsonutil = require("json.util")
|
||||
local util_merge = jsonutil.merge
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local normalEncodingMap = {
|
||||
['"'] = '\\"',
|
||||
['\\'] = '\\\\',
|
||||
['/'] = '\\/',
|
||||
['\b'] = '\\b',
|
||||
['\f'] = '\\f',
|
||||
['\n'] = '\\n',
|
||||
['\r'] = '\\r',
|
||||
['\t'] = '\\t',
|
||||
['\v'] = '\\v' -- not in official spec, on report, removing
|
||||
}
|
||||
|
||||
local xEncodingMap = {}
|
||||
for char, encoded in pairs(normalEncodingMap) do
|
||||
xEncodingMap[char] = encoded
|
||||
end
|
||||
|
||||
-- Pre-encode the control characters to speed up encoding...
|
||||
-- NOTE: UTF-8 may not work out right w/ JavaScript
|
||||
-- JavaScript uses 2 bytes after a \u... yet UTF-8 is a
|
||||
-- byte-stream encoding, not pairs of bytes (it does encode
|
||||
-- some letters > 1 byte, but base case is 1)
|
||||
for i = 0, 255 do
|
||||
local c = string_char(i)
|
||||
if c:match('[%z\1-\031\128-\255]') and not normalEncodingMap[c] then
|
||||
-- WARN: UTF8 specializes values >= 0x80 as parts of sequences...
|
||||
-- without \x encoding, do not allow encoding > 7F
|
||||
normalEncodingMap[c] = ('\\u%.4X'):format(i)
|
||||
xEncodingMap[c] = ('\\x%.2X'):format(i)
|
||||
end
|
||||
end
|
||||
|
||||
local defaultOptions = {
|
||||
xEncode = false, -- Encode single-bytes as \xXX
|
||||
processor = nil, -- Simple processor for the string prior to quoting
|
||||
-- / is not required to be quoted but it helps with certain decoding
|
||||
-- Required encoded characters, " \, and 00-1F (0 - 31)
|
||||
encodeSet = '\\"/%z\1-\031',
|
||||
encodeSetAppend = nil -- Chars to append to the default set
|
||||
}
|
||||
|
||||
local modeOptions = {}
|
||||
|
||||
local function mergeOptions(options, mode)
|
||||
jsonutil.doOptionMerge(options, false, 'strings', defaultOptions, mode and modeOptions[mode])
|
||||
end
|
||||
|
||||
local function getEncoder(options)
|
||||
options = options and util_merge({}, defaultOptions, options) or defaultOptions
|
||||
local encodeSet = options.encodeSet
|
||||
if options.encodeSetAppend then
|
||||
encodeSet = encodeSet .. options.encodeSetAppend
|
||||
end
|
||||
local encodingMap = options.xEncode and xEncodingMap or normalEncodingMap
|
||||
local encodeString
|
||||
if options.processor then
|
||||
local processor = options.processor
|
||||
encodeString = function(s, state)
|
||||
return '"' .. processor(s:gsub('[' .. encodeSet .. ']', encodingMap)) .. '"'
|
||||
end
|
||||
else
|
||||
encodeString = function(s, state)
|
||||
return '"' .. s:gsub('[' .. encodeSet .. ']', encodingMap) .. '"'
|
||||
end
|
||||
end
|
||||
return {
|
||||
string = encodeString
|
||||
}
|
||||
end
|
||||
|
||||
local strings = {
|
||||
mergeOptions = mergeOptions,
|
||||
getEncoder = getEncoder
|
||||
}
|
||||
|
||||
return strings
|
152
tools/luajson/json/util.lua
Normal file
152
tools/luajson/json/util.lua
Normal file
@ -0,0 +1,152 @@
|
||||
--[[
|
||||
Licensed according to the included 'LICENSE' document
|
||||
Author: Thomas Harning Jr <harningt@gmail.com>
|
||||
]]
|
||||
local type = type
|
||||
local print = print
|
||||
local tostring = tostring
|
||||
local pairs = pairs
|
||||
local getmetatable, setmetatable = getmetatable, setmetatable
|
||||
local select = select
|
||||
|
||||
local _ENV = nil
|
||||
|
||||
local function foreach(tab, func)
|
||||
for k, v in pairs(tab) do
|
||||
func(k,v)
|
||||
end
|
||||
end
|
||||
local function printValue(tab, name)
|
||||
local parsed = {}
|
||||
local function doPrint(key, value, space)
|
||||
space = space or ''
|
||||
if type(value) == 'table' then
|
||||
if parsed[value] then
|
||||
print(space .. key .. '= <' .. parsed[value] .. '>')
|
||||
else
|
||||
parsed[value] = key
|
||||
print(space .. key .. '= {')
|
||||
space = space .. ' '
|
||||
foreach(value, function(key, value) doPrint(key, value, space) end)
|
||||
end
|
||||
else
|
||||
if type(value) == 'string' then
|
||||
value = '[[' .. tostring(value) .. ']]'
|
||||
end
|
||||
print(space .. key .. '=' .. tostring(value))
|
||||
end
|
||||
end
|
||||
doPrint(name, tab)
|
||||
end
|
||||
|
||||
local function clone(t)
|
||||
local ret = {}
|
||||
for k,v in pairs(t) do
|
||||
ret[k] = v
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
local function inner_merge(t, remaining, from, ...)
|
||||
if remaining == 0 then
|
||||
return t
|
||||
end
|
||||
if from then
|
||||
for k,v in pairs(from) do
|
||||
t[k] = v
|
||||
end
|
||||
end
|
||||
return inner_merge(t, remaining - 1, ...)
|
||||
end
|
||||
|
||||
--[[*
|
||||
Shallow-merges tables in order onto the first table.
|
||||
|
||||
@param t table to merge entries onto
|
||||
@param ... sequence of 0 or more tables to merge onto 't'
|
||||
|
||||
@returns table 't' from input
|
||||
]]
|
||||
local function merge(t, ...)
|
||||
return inner_merge(t, select('#', ...), ...)
|
||||
end
|
||||
|
||||
-- Function to insert nulls into the JSON stream
|
||||
local function null()
|
||||
return null
|
||||
end
|
||||
|
||||
-- Marker for 'undefined' values
|
||||
local function undefined()
|
||||
return undefined
|
||||
end
|
||||
|
||||
local ArrayMT = {}
|
||||
|
||||
--[[
|
||||
Return's true if the metatable marks it as an array..
|
||||
Or false if it has no array component at all
|
||||
Otherwise nil to get the normal detection component working
|
||||
]]
|
||||
local function IsArray(value)
|
||||
if type(value) ~= 'table' then return false end
|
||||
local meta = getmetatable(value)
|
||||
local ret = meta == ArrayMT or (meta ~= nil and meta.__is_luajson_array)
|
||||
if not ret then
|
||||
if #value == 0 then return false end
|
||||
else
|
||||
return ret
|
||||
end
|
||||
end
|
||||
local function InitArray(array)
|
||||
setmetatable(array, ArrayMT)
|
||||
return array
|
||||
end
|
||||
|
||||
local CallMT = {}
|
||||
|
||||
local function isCall(value)
|
||||
return CallMT == getmetatable(value)
|
||||
end
|
||||
|
||||
local function buildCall(name, ...)
|
||||
local callData = {
|
||||
name = name,
|
||||
parameters = {n = select('#', ...), ...}
|
||||
}
|
||||
return setmetatable(callData, CallMT)
|
||||
end
|
||||
|
||||
local function decodeCall(callData)
|
||||
if not isCall(callData) then return nil end
|
||||
return callData.name, callData.parameters
|
||||
end
|
||||
|
||||
local function doOptionMerge(options, nested, name, defaultOptions, modeOptions)
|
||||
if nested then
|
||||
modeOptions = modeOptions and modeOptions[name]
|
||||
defaultOptions = defaultOptions and defaultOptions[name]
|
||||
end
|
||||
options[name] = merge(
|
||||
{},
|
||||
defaultOptions,
|
||||
modeOptions,
|
||||
options[name]
|
||||
)
|
||||
end
|
||||
|
||||
local json_util = {
|
||||
printValue = printValue,
|
||||
clone = clone,
|
||||
merge = merge,
|
||||
null = null,
|
||||
undefined = undefined,
|
||||
IsArray = IsArray,
|
||||
InitArray = InitArray,
|
||||
isCall = isCall,
|
||||
buildCall = buildCall,
|
||||
decodeCall = decodeCall,
|
||||
doOptionMerge = doOptionMerge
|
||||
}
|
||||
|
||||
return json_util
|
95
tools/luajson/test_json.lua
Normal file
95
tools/luajson/test_json.lua
Normal file
@ -0,0 +1,95 @@
|
||||
package.path = package.path .. ";lua_scripts/libraries/luajson/?.lua"
|
||||
|
||||
local JSON = require"json"
|
||||
|
||||
local jsontest = [[{ 1:{"scn_ptz_id":"",
|
||||
"scn_ptz_prepos":"Preset 176",
|
||||
"scn_ptz_order":1,
|
||||
"scn_ptz_duration":"30",
|
||||
"scn_ptz_rally_delay":"2"}
|
||||
,
|
||||
2:{"scn_ptz_id":"","scn_ptz_prepos":"route","scn_ptz_order":2,"scn_ptz_duration":"30","scn_ptz_rally_delay":"2"} }
|
||||
]]
|
||||
local jsontest2 = [[{
|
||||
"extension":"mpg",
|
||||
"id":1545148451781,
|
||||
"name":"Foule_1280x720p.mpg",
|
||||
"size":67240746,
|
||||
"date":1545148451,
|
||||
"mime":"video\/mpeg",
|
||||
"filename":"1545148451781.mpg",
|
||||
"dir":"\/home\/pixalarm_data\/fileprocessor_data",
|
||||
"function_metadatas":
|
||||
{
|
||||
"function_faceblur":
|
||||
{
|
||||
"date":1545228627,
|
||||
"current_frame":"845",
|
||||
"polygons":[
|
||||
{
|
||||
"polygon_id":"new_1",
|
||||
"polygon_vertex":"[
|
||||
[0.14254859611231102,0.12476007677543186],[0.13174946004319654,0.4740882917466411],
|
||||
[0.3898488120950324,0.6621880998080614],[0.4038876889848812,0.11516314779270634]
|
||||
]",
|
||||
"polygon_frame_start":"1",
|
||||
"polygon_frame_stop":"300",
|
||||
"polygon_type":"full_blur"
|
||||
},
|
||||
{
|
||||
"polygon_id":"new_2",
|
||||
"polygon_vertex":"[
|
||||
[0.6198704103671706,0.1727447216890595],[0.5496760259179265,0.6007677543186181],
|
||||
[0.7775377969762419,0.7946257197696737],[0.9028077753779697,0.761996161228407],
|
||||
[0.9481641468682506,0.2821497120921305],[0.7829373650107991,0.04798464491362764]
|
||||
]",
|
||||
"polygon_frame_start":"200",
|
||||
"polygon_frame_stop":"845",
|
||||
"polygon_type":"no_blur"
|
||||
}
|
||||
],
|
||||
"framecuts":[
|
||||
["17","110"],
|
||||
["248","298"],
|
||||
["488","620"],
|
||||
["378","428"]
|
||||
],
|
||||
"face_selection":[
|
||||
{
|
||||
"frame":"21",
|
||||
"x":"0.5",
|
||||
"y":"0.356"
|
||||
},
|
||||
{
|
||||
"frame":"108",
|
||||
"x":"0.4289",
|
||||
"y":"0.275"
|
||||
},
|
||||
{
|
||||
"frame":"294",
|
||||
"x":"0.726",
|
||||
"y":"0.2364"
|
||||
}
|
||||
],
|
||||
"blur_type":"blur",
|
||||
"blur_area":"face"
|
||||
}
|
||||
},
|
||||
"total_frame":"845",
|
||||
"status":"DECODE_FINISHED",
|
||||
"fps":"25.00"
|
||||
}]]
|
||||
|
||||
local res = JSON.decode(jsontest2)
|
||||
for k, v in pairs(res) do
|
||||
print( k, v)
|
||||
end
|
||||
|
||||
res = JSON.decode( '{"content" : {},"date" : "2014-12-30T08:29:48Z","error" : {"code" : 0,"httpcode" : 200,"message" : ""},"status" : 1}' )
|
||||
for k, v in pairs(res) do
|
||||
print( k, v)
|
||||
end
|
||||
|
||||
local jsondata = JSON.encode( res )
|
||||
print(jsondata)
|
||||
|
Reference in New Issue
Block a user