Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
514b0244
Commit
514b0244
authored
Sep 28, 2011
by
Rob Jonson
Committed by
Jean-Baptiste Kempf
Oct 05, 2011
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
lua:add dkjson
Signed-off-by:
Jean-Baptiste Kempf
<
jb@videolan.org
>
parent
ab90a0b9
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
808 additions
and
0 deletions
+808
-0
share/Makefile.am
share/Makefile.am
+2
-0
share/lua/modules/dkjson.lua
share/lua/modules/dkjson.lua
+806
-0
No files found.
share/Makefile.am
View file @
514b0244
...
...
@@ -149,6 +149,7 @@ nobase_vlclib_DATA = \
lua/meta/art/01_googleimage.luac
\
lua/meta/fetcher/tvrage.luac
\
lua/meta/reader/filename.luac
\
lua/modules/dkjson.luac
\
lua/modules/sandbox.luac
\
lua/modules/simplexml.luac
\
lua/playlist/anevia_streams.luac
\
...
...
@@ -215,6 +216,7 @@ EXTRA_DIST += \
lua/meta/fetcher/tvrage.lua
\
lua/meta/reader/README.txt
\
lua/meta/reader/filename.lua
\
lua/modules/dkjson.lua
\
lua/modules/sandbox.lua
\
lua/modules/simplexml.lua
\
lua/playlist/README.txt
\
...
...
share/lua/modules/dkjson.lua
0 → 100644
View file @
514b0244
--[==[
David Kolf's JSON module for Lua 5.1/5.2
========================================
*Version 2.1*
This module writes no global values, not even the module table.
Import it using
json = require ("dkjson")
Exported functions and values:
`json.encode (object [, state])`
--------------------------------
Create a string representing the object. `Object` can be a table,
a string, a number, a boolean, `nil`, `json.null` or any object with
a function `__tojson` in its metatable. A table can only use strings
and numbers as keys and its values have to be valid objects as
well. It raises an error for any invalid data types or reference
cycles.
`state` is an optional table with the following fields:
- `indent`
When `indent` (a boolean) is set, the created string will contain
newlines and indentations. Otherwise it will be one long line.
- `keyorder`
`keyorder` is an array to specify the ordering of keys in the
encoded output. If an object has keys which are not in this array
they are written after the sorted keys.
- `level`
This is the initial level of indentation used when `indent` is
set. For each level two spaces are added. When absent it is set
to 0.
- `buffer`
`buffer` is an array to store the strings for the result so they
can be concatenated at once. When it isn't given, the encode
function will create it temporary and will return the
concatenated result.
- `bufferlen`
When `bufferlen` is set, it has to be the index of the last
element of `buffer`.
- `tables`
`tables` is a set to detect reference cycles. It is created
temporary when absent. Every table that is currently processed
is used as key, the value is `true`.
When `state.buffer` was set, the return value will be `true` on
success. Without `state.buffer` the return value will be a string.
`json.decode (string [, position [, null]])`
--------------------------------------------
Decode `string` starting at `position` or at 1 if `position` was
omitted.
`null` is an optional value to be returned for null values. The
default is `nil`, but you could set it to `json.null` or any other
value.
The return values are the object or `nil`, the position of the next
character that doesn't belong to the object, and in case of errors
an error message.
Two metatables are created. Every array or object that is decoded gets
a metatable with the `__jsontype` field set to either `array` or
`object`. If you want to provide your own metatables use the syntax
json.decode (string, position, null, objectmeta, arraymeta)
`<metatable>.__jsonorder`
-------------------------
`__jsonorder` can overwrite the `keyorder` for a specific table.
`<metatable>.__jsontype`
------------------------
`__jsontype` can be either `"array"` or `"object"`. This is mainly useful
for tables that can be empty. (The default for empty tables is
`"array"`).
`<metatable>.__tojson (self, state)`
------------------------------------
You can provide your own `__tojson` function in a metatable. In this
function you can either add directly to the buffer and return true,
or you can return a string. On errors nil and a message should be
returned.
`json.null`
-----------
You can use this value for setting explicit `null` values.
`json.version`
--------------
Set to `"dkjson 2.1"`.
`json.quotestring (string)`
---------------------------
Quote a UTF-8 string and escape critical characters using JSON
escape sequences. This function is only necessary when you build
your own `__tojson` functions.
`json.addnewline (state)`
-------------------------
When `state.indent` is set, add a newline to `state.buffer` and spaces
according to `state.level`.
LPeg support
------------
When the local configuration variable
`always_try_using_lpeg` is set, this module tries to load LPeg to
replace the functions `quotestring` and `decode`. The speed increase
is significant. You can get the LPeg module at
<http://www.inf.puc-rio.br/~roberto/lpeg/>.
When LPeg couldn't be loaded, the pure Lua functions stay active.
In case you don't want this module to require LPeg on its own,
disable this option:
--]==]
local
always_try_using_lpeg
=
true
--[==[
In this case you can later load LPeg support using
### `json.use_lpeg ()`
Require the LPeg module and replace the functions `quotestring` and
and `decode` with functions that use LPeg patterns.
This function returns the module table, so you can load the module
using:
json = require "dkjson".use_lpeg()
Alternatively you can use `pcall` so the JSON module still works when
LPeg isn't found.
json = require "dkjson"
pcall (json.use_lpeg)
### `json.using_lpeg`
This variable is set to `true` when LPeg was loaded successfully.
You can contact the author by sending an e-mail to 'kolf' at the
e-mail provider 'gmx.de'.
---------------------------------------------------------------------
*Copyright (C) 2010, 2011 David Heiko Kolf*
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.
<!-- This documentation can be parsed using Markdown to generate HTML.
The source code is enclosed in a HTML comment so it won't be displayed
by browsers, but it should be removed from the final HTML file as
it isn't a valid HTML comment (and wastes space).
-->
<!--]==]
-- global dependencies:
local
pairs
,
type
,
tostring
,
tonumber
,
getmetatable
,
setmetatable
,
rawset
=
pairs
,
type
,
tostring
,
tonumber
,
getmetatable
,
setmetatable
,
rawset
local
error
,
require
,
pcall
=
error
,
require
,
pcall
local
floor
,
huge
=
math.floor
,
math.huge
local
strrep
,
gsub
,
strsub
,
strbyte
,
strchar
,
strfind
,
strlen
,
strformat
=
string.rep
,
string.gsub
,
string.sub
,
string.byte
,
string.char
,
string.find
,
string.len
,
string.format
local
concat
=
table.concat
if
_VERSION
==
'Lua
5.1'
then
local
function
noglobals
(
s
,
k
,
v
)
error
(
"global access: "
..
k
,
2
)
end
setfenv
(
1
,
setmetatable
({},
{
__index
=
noglobals
,
__newindex
=
noglobals
}))
end
local
_ENV
=
nil
-- blocking globals in Lua 5.2
local
json
=
{
version
=
"dkjson 2.1"
}
pcall
(
function
()
-- Enable access to blocked metatables.
-- Don't worry, this module doesn't change anything in them.
local
debmeta
=
require
"debug"
.
getmetatable
if
debmeta
then
getmetatable
=
debmeta
end
end
)
json
.
null
=
setmetatable
({},
{
__tojson
=
function
()
return
"null"
end
})
local
function
isarray
(
tbl
)
local
max
,
n
,
arraylen
=
0
,
0
,
0
for
k
,
v
in
pairs
(
tbl
)
do
if
k
==
'n'
and
type
(
v
)
==
'number'
then
arraylen
=
v
if
v
>
max
then
max
=
v
end
else
if
type
(
k
)
~=
'number'
or
k
<
1
or
floor
(
k
)
~=
k
then
return
false
end
if
k
>
max
then
max
=
k
end
n
=
n
+
1
end
end
if
max
>
10
and
max
>
arraylen
and
max
>
n
*
2
then
return
false
-- don't create an array with too many holes
end
return
true
,
max
end
local
escapecodes
=
{
[
"
\"
"
]
=
"
\\\"
"
,
[
"
\\
"
]
=
"
\\\\
"
,
[
"
\b
"
]
=
"
\\
b"
,
[
"
\f
"
]
=
"
\\
f"
,
[
"
\n
"
]
=
"
\\
n"
,
[
"
\r
"
]
=
"
\\
r"
,
[
"
\t
"
]
=
"
\\
t"
}
local
function
escapeutf8
(
uchar
)
local
value
=
escapecodes
[
uchar
]
if
value
then
return
value
end
local
a
,
b
,
c
,
d
=
strbyte
(
uchar
,
1
,
4
)
a
,
b
,
c
,
d
=
a
or
0
,
b
or
0
,
c
or
0
,
d
or
0
if
a
<=
0x7f
then
value
=
a
elseif
0xc0
<=
a
and
a
<=
0xdf
and
b
>=
0x80
then
value
=
(
a
-
0xc0
)
*
0x40
+
b
-
0x80
elseif
0xe0
<=
a
and
a
<=
0xef
and
b
>=
0x80
and
c
>=
0x80
then
value
=
((
a
-
0xe0
)
*
0x40
+
b
-
0x80
)
*
0x40
+
c
-
0x80
elseif
0xf0
<=
a
and
a
<=
0xf7
and
b
>=
0x80
and
c
>=
0x80
and
d
>=
0x80
then
value
=
(((
a
-
0xf0
)
*
0x40
+
b
-
0x80
)
*
0x40
+
c
-
0x80
)
*
0x40
+
d
-
0x80
else
return
""
end
if
value
<=
0xffff
then
return
strformat
(
"
\\
u%.4x"
,
value
)
elseif
value
<=
0x10ffff
then
-- encode as UTF-16 surrogate pair
value
=
value
-
0x10000
local
highsur
,
lowsur
=
0xD800
+
floor
(
value
/
0x400
),
0xDC00
+
(
value
%
0x400
)
return
strformat
(
"
\\
u%.4x\\u%.4x"
,
highsur
,
lowsur
)
else
return
""
end
end
local
function
fsub
(
str
,
pattern
,
repl
)
-- gsub always builds a new string in a buffer, even when no match
-- exists. First using find should be more efficient when most strings
-- don't contain the pattern.
if
strfind
(
str
,
pattern
)
then
return
gsub
(
str
,
pattern
,
repl
)
else
return
str
end
end
local
function
quotestring
(
value
)
-- based on the regexp "escapable" in https://github.com/douglascrockford/JSON-js
value
=
fsub
(
value
,
"[%z\1-\31\"
\\\
127
]
", escapeutf8)
if strfind (value, "
[
\
194
\
216
\
220
\
225
\
226
\
239
]
") then
value = fsub (value, "
\
194
[
\
128
-
\
159
\
173
]
", escapeutf8)
value = fsub (value, "
\
216
[
\
128
-
\
132
]
", escapeutf8)
value = fsub (value, "
\
220
\
143
", escapeutf8)
value = fsub (value, "
\
225
\
158
[
\
180
\
181
]
", escapeutf8)
value = fsub (value, "
\
226
\
128
[
\
140
-
\
143
\
168
\
175
]
", escapeutf8)
value = fsub (value, "
\
226
\
129
[
\
160
-
\
175
]
", escapeutf8)
value = fsub (value, "
\
239
\
187
\
191
", escapeutf8)
value = fsub (value, "
\
239
\
191
[
\
176
\
191
]
", escapeutf8)
end
return "
\
""
..
value
..
"
\"
"
end
json
.
quotestring
=
quotestring
local
function
addnewline2
(
level
,
buffer
,
buflen
)
buffer
[
buflen
+
1
]
=
"
\n
"
buffer
[
buflen
+
2
]
=
strrep
(
" "
,
level
)
buflen
=
buflen
+
2
return
buflen
end
function
json
.
addnewline
(
state
)
if
state
.
indent
then
state
.
bufferlen
=
addnewline2
(
state
.
level
or
0
,
state
.
buffer
,
state
.
bufferlen
or
#
(
state
.
buffer
))
end
end
local
encode2
-- forward declaration
local
function
addpair
(
key
,
value
,
prev
,
indent
,
level
,
buffer
,
buflen
,
tables
,
globalorder
)
local
kt
=
type
(
key
)
if
kt
~=
'string'
and
kt
~=
'number'
then
return
nil
,
"type '"
..
kt
..
"' is not supported as a key by JSON."
end
if
prev
then
buflen
=
buflen
+
1
buffer
[
buflen
]
=
","
end
if
indent
then
buflen
=
addnewline2
(
level
,
buffer
,
buflen
)
end
buffer
[
buflen
+
1
]
=
quotestring
(
key
)
buffer
[
buflen
+
2
]
=
":"
return
encode2
(
value
,
indent
,
level
,
buffer
,
buflen
+
2
,
tables
,
globalorder
)
end
encode2
=
function
(
value
,
indent
,
level
,
buffer
,
buflen
,
tables
,
globalorder
)
local
valtype
=
type
(
value
)
local
valmeta
=
getmetatable
(
value
)
valmeta
=
type
(
valmeta
)
==
'table'
and
valmeta
-- only tables
local
valtojson
=
valmeta
and
valmeta
.
__tojson
if
valtojson
then
if
tables
[
value
]
then
return
nil
,
"reference cycle"
end
tables
[
value
]
=
true
local
state
=
{
indent
=
indent
,
level
=
level
,
buffer
=
buffer
,
bufferlen
=
buflen
,
tables
=
tables
,
keyorder
=
globalorder
}
local
ret
,
msg
=
valtojson
(
value
,
state
)
if
not
ret
then
return
nil
,
msg
end
tables
[
value
]
=
nil
buflen
=
state
.
bufferlen
if
type
(
ret
)
==
'string'
then
buflen
=
buflen
+
1
buffer
[
buflen
]
=
ret
end
elseif
value
==
nil
then
buflen
=
buflen
+
1
buffer
[
buflen
]
=
"null"
elseif
valtype
==
'number'
then
local
s
if
value
~=
value
or
value
>=
huge
or
-
value
>=
huge
then
-- This is the behaviour of the original JSON implementation.
s
=
"null"
else
s
=
tostring
(
value
)
end
buflen
=
buflen
+
1
buffer
[
buflen
]
=
s
elseif
valtype
==
'boolean'
then
buflen
=
buflen
+
1
buffer
[
buflen
]
=
value
and
"true"
or
"false"
elseif
valtype
==
'string'
then
buflen
=
buflen
+
1
buffer
[
buflen
]
=
quotestring
(
value
)
elseif
valtype
==
'table'
then
if
tables
[
value
]
then
return
nil
,
"reference cycle"
end
tables
[
value
]
=
true
level
=
level
+
1
local
metatype
=
valmeta
and
valmeta
.
__jsontype
local
isa
,
n
if
metatype
==
'array'
then
isa
=
true
n
=
value
.
n
or
#
value
elseif
metatype
==
'object'
then
isa
=
false
else
isa
,
n
=
isarray
(
value
)
end
local
msg
if
isa
then
-- JSON array
buflen
=
buflen
+
1
buffer
[
buflen
]
=
"["
for
i
=
1
,
n
do
buflen
,
msg
=
encode2
(
value
[
i
],
indent
,
level
,
buffer
,
buflen
,
tables
,
globalorder
)
if
not
buflen
then
return
nil
,
msg
end
if
i
<
n
then
buflen
=
buflen
+
1
buffer
[
buflen
]
=
","
end
end
buflen
=
buflen
+
1
buffer
[
buflen
]
=
"]"
else
-- JSON object
local
prev
=
false
buflen
=
buflen
+
1
buffer
[
buflen
]
=
"{"
local
order
=
valmeta
and
valmeta
.
__jsonorder
or
globalorder
if
order
then
local
used
=
{}
n
=
#
order
for
i
=
1
,
n
do
local
k
=
order
[
i
]
local
v
=
value
[
k
]
if
v
then
used
[
k
]
=
true
buflen
,
msg
=
addpair
(
k
,
v
,
prev
,
indent
,
level
,
buffer
,
buflen
,
tables
,
globalorder
)
prev
=
true
-- add a seperator before the next element
end
end
for
k
,
v
in
pairs
(
value
)
do
if
not
used
[
k
]
then
buflen
,
msg
=
addpair
(
k
,
v
,
prev
,
indent
,
level
,
buffer
,
buflen
,
tables
,
globalorder
)
if
not
buflen
then
return
nil
,
msg
end
prev
=
true
-- add a seperator before the next element
end
end
else
-- unordered
for
k
,
v
in
pairs
(
value
)
do
buflen
,
msg
=
addpair
(
k
,
v
,
prev
,
indent
,
level
,
buffer
,
buflen
,
tables
,
globalorder
)
if
not
buflen
then
return
nil
,
msg
end
prev
=
true
-- add a seperator before the next element
end
end
if
indent
then
buflen
=
addnewline2
(
level
-
1
,
buffer
,
buflen
)
end
buflen
=
buflen
+
1
buffer
[
buflen
]
=
"}"
end
tables
[
value
]
=
nil
else
return
nil
,
"type '"
..
valtype
..
"' is not supported by JSON."
end
return
buflen
end
function
json
.
encode
(
value
,
state
)
state
=
state
or
{}
local
oldbuffer
=
state
.
buffer
local
buffer
=
oldbuffer
or
{}
local
ret
,
msg
=
encode2
(
value
,
state
.
indent
,
state
.
level
or
0
,
buffer
,
state
.
bufferlen
or
0
,
state
.
tables
or
{},
state
.
keyorder
)
if
not
ret
then
error
(
msg
,
2
)
elseif
oldbuffer
then
state
.
bufferlen
=
ret
return
true
else
return
concat
(
buffer
)
end
end
local
function
loc
(
str
,
where
)
local
line
,
pos
,
linepos
=
1
,
1
,
1
while
true
do
pos
=
strfind
(
str
,
"
\n
"
,
pos
,
true
)
if
pos
and
pos
<
where
then
line
=
line
+
1
linepos
=
pos
pos
=
pos
+
1
else
break
end
end
return
"line "
..
line
..
", column "
..
(
where
-
linepos
)
end
local
function
unterminated
(
str
,
what
,
where
)
return
nil
,
strlen
(
str
)
+
1
,
"unterminated "
..
what
..
" at "
..
loc
(
str
,
where
)
end
local
function
scanwhite
(
str
,
pos
)
while
true
do
pos
=
strfind
(
str
,
"%S"
,
pos
)
if
not
pos
then
return
nil
end
if
strsub
(
str
,
pos
,
pos
+
2
)
==
"
\239\187\191
"
then
-- UTF-8 Byte Order Mark
pos
=
pos
+
3
else
return
pos
end
end
end
local
escapechars
=
{
[
"
\"
"
]
=
"
\"
"
,
[
"
\\
"
]
=
"
\\
"
,
[
"/"
]
=
"/"
,
[
"b"
]
=
"
\b
"
,
[
"f"
]
=
"
\f
"
,
[
"n"
]
=
"
\n
"
,
[
"r"
]
=
"
\r
"
,
[
"t"
]
=
"
\t
"
}
local
function
unichar
(
value
)
if
value
<
0
then
return
nil
elseif
value
<=
0x007f
then
return
strchar
(
value
)
elseif
value
<=
0x07ff
then
return
strchar
(
0xc0
+
floor
(
value
/
0x40
),
0x80
+
(
floor
(
value
)
%
0x40
))
elseif
value
<=
0xffff
then
return
strchar
(
0xe0
+
floor
(
value
/
0x1000
),
0x80
+
(
floor
(
value
/
0x40
)
%
0x40
),
0x80
+
(
floor
(
value
)
%
0x40
))
elseif
value
<=
0x10ffff
then
return
strchar
(
0xf0
+
floor
(
value
/
0x40000
),
0x80
+
(
floor
(
value
/
0x1000
)
%
0x40
),
0x80
+
(
floor
(
value
/
0x40
)
%
0x40
),
0x80
+
(
floor
(
value
)
%
0x40
))
else
return
nil
end
end
local
function
scanstring
(
str
,
pos
)
local
lastpos
=
pos
+
1
local
buffer
,
n
=
{},
0
while
true
do
local
nextpos
=
strfind
(
str
,
"[\"
\\
]
", lastpos)
if not nextpos then
return unterminated (str, "
string
", pos)
end
if nextpos > lastpos then
n = n + 1
buffer[n] = strsub (str, lastpos, nextpos - 1)
end
if strsub (str, nextpos, nextpos) == "
\
""
then
lastpos
=
nextpos
+
1
break
else
local
escchar
=
strsub
(
str
,
nextpos
+
1
,
nextpos
+
1
)
local
value
if
escchar
==
"u"
then
value
=
tonumber
(
strsub
(
str
,
nextpos
+
2
,
nextpos
+
5
),
16
)
if
value
then
local
value2
if
0xD800
<=
value
and
value
<=
0xDBff
then
-- we have the high surrogate of UTF-16. Check if there is a
-- low surrogate escaped nearby to combine them.
if
strsub
(
str
,
nextpos
+
6
,
nextpos
+
7
)
==
"
\\
u"
then
value2
=
tonumber
(
strsub
(
str
,
nextpos
+
8
,
nextpos
+
11
),
16
)
if
value2
and
0xDC00
<=
value2
and
value2
<=
0xDFFF
then
value
=
(
value
-
0xD800
)
*
0x400
+
(
value2
-
0xDC00
)
+
0x10000
else
value2
=
nil
-- in case it was out of range for a low surrogate
end
end
end
value
=
value
and
unichar
(
value
)
if
value
then
if
value2
then
lastpos
=
nextpos
+
12
else
lastpos
=
nextpos
+
6
end
end
end
end
if
not
value
then
value
=
escapechars
[
escchar
]
or
escchar
lastpos
=
nextpos
+
2
end
n
=
n
+
1
buffer
[
n
]
=
value
end
end
if
n
==
1
then
return
buffer
[
1
],
lastpos
elseif
n
>
1
then
return
concat
(
buffer
),
lastpos
else
return
""
,
lastpos
end
end
local
scanvalue
-- forward declaration
local
function
scantable
(
what
,
closechar
,
str
,
startpos
,
nullval
,
objectmeta
,
arraymeta
)
local
len
=
strlen
(
str
)
local
tbl
,
n
=
{},
0
local
pos
=
startpos
+
1
if
what
==
'object'
then
setmetatable
(
tbl
,
objectmeta
)
else
setmetatable
(
tbl
,
arraymeta
)
end
while
true
do
pos
=
scanwhite
(
str
,
pos
)
if
not
pos
then
return
unterminated
(
str
,
what
,
startpos
)
end
local
char
=
strsub
(
str
,
pos
,
pos
)
if
char
==
closechar
then
return
tbl
,
pos
+
1
end
local
val1
,
err
val1
,
pos
,
err
=
scanvalue
(
str
,
pos
,
nullval
,
objectmeta
,
arraymeta
)
if
err
then
return
nil
,
pos
,
err
end
pos
=
scanwhite
(
str
,
pos
)
if
not
pos
then
return
unterminated
(
str
,
what
,
startpos
)
end
char
=
strsub
(
str
,
pos
,
pos
)
if
char
==
":"
then
if
val1
==
nil
then
return
nil
,
pos
,
"cannot use nil as table index (at "
..
loc
(
str
,
pos
)
..
")"
end
pos
=
scanwhite
(
str
,
pos
+
1
)
if
not
pos
then
return
unterminated
(
str
,
what
,
startpos
)
end
local
val2
val2
,
pos
,
err
=
scanvalue
(
str
,
pos
,
nullval
,
objectmeta
,
arraymeta
)
if
err
then
return
nil
,
pos
,
err
end
tbl
[
val1
]
=
val2
pos
=
scanwhite
(
str
,
pos
)
if
not
pos
then
return
unterminated
(
str
,
what
,
startpos
)
end
char
=
strsub
(
str
,
pos
,
pos
)
else
n
=
n
+
1
tbl
[
n
]
=
val1
end
if
char
==
","
then
pos
=
pos
+
1
end
end
end
scanvalue
=
function
(
str
,
pos
,
nullval
,
objectmeta
,
arraymeta
)
pos
=
pos
or
1
pos
=
scanwhite
(
str
,
pos
)
if
not
pos
then
return
nil
,
strlen
(
str
)
+
1
,
"no valid JSON value (reached the end)"
end
local
char
=
strsub
(
str
,
pos
,
pos
)
if
char
==
"{"
then
return
scantable
(
'object'
,
"}"
,
str
,
pos
,
nullval
,
objectmeta
,
arraymeta
)
elseif
char
==
"["
then
return
scantable
(
'array'
,
"]"
,
str
,
pos
,
nullval
,
objectmeta
,
arraymeta
)
elseif
char
==
"
\"
"
then
return
scanstring
(
str
,
pos
)
else
local
pstart
,
pend
=
strfind
(
str
,
"^%-?[%d%.]+[eE]?[%+%-]?%d*"
,
pos
)
if
pstart
then
local
number
=
tonumber
(
strsub
(
str
,
pstart
,
pend
))
if
number
then
return
number
,
pend
+
1
end
end
pstart
,
pend
=
strfind
(
str
,
"^%a%w*"
,
pos
)
if
pstart
then
local
name
=
strsub
(
str
,
pstart
,
pend
)
if
name
==
"true"
then
return
true
,
pend
+
1
elseif
name
==
"false"
then
return
false
,
pend
+
1
elseif
name
==
"null"
then
return
nullval
,
pend
+
1
end
end
return
nil
,
pos
,
"no valid JSON value at "
..
loc
(
str
,
pos
)
end
end
function
json
.
decode
(
str
,
pos
,
nullval
,
objectmeta
,
arraymeta
)
objectmeta
=
objectmeta
or
{
__jsontype
=
'object'
}
arraymeta
=
arraymeta
or
{
__jsontype
=
'array'
}
return
scanvalue
(
str
,
pos
,
nullval
,
objectmeta
,
arraymeta
)
end
function
json
.
use_lpeg
()
local
g
=
require
(
"lpeg"
)
local
pegmatch
=
g
.
match
local
P
,
S
,
R
,
V
=
g
.
P
,
g
.
S
,
g
.
R
,
g
.
V
local
SpecialChars
=
(
R
"
\0\31
"
+
S
"
\"\\\127
"
+
P
"
\194
"
*
(
R
"
\128\159
"
+
P
"
\173
"
)
+
P
"
\216
"
*
R
"
\128\132
"
+
P
"
\220\132
"
+
P
"
\225\158
"
*
S
"
\180\181
"
+
P
"
\226\128
"
*
(
R
"
\140\143
"
+
S
"
\168\175
"
)
+
P
"
\226\129
"
*
R
"
\160\175
"
+
P
"
\239\187\191
"
+
P
"
\229\191
"
+
R
"
\176\191
"
)
/
escapeutf8
local
QuoteStr
=
g
.
Cs
(
g
.
Cc
"
\"
"
*
(
SpecialChars
+
1
)
^
0
*
g
.
Cc
"
\"
"
)
quotestring
=
function
(
str
)
return
pegmatch
(
QuoteStr
,
str
)
end
json
.
quotestring
=
quotestring
local
function
ErrorCall
(
str
,
pos
,
msg
,
state
)
if
not
state
.
msg
then
state
.
msg
=
msg
..
" at "
..
loc
(
str
,
pos
)
state
.
pos
=
pos
end
return
false
end
local
function
Err
(
msg
)
return
g
.
Cmt
(
g
.
Cc
(
msg
)
*
g
.
Carg
(
2
),
ErrorCall
)
end
local
Space
=
(
S
" \n\r\t"
+
P
"
\239\187\191
"
)
^
0
local
PlainChar
=
1
-
S
"
\"\\\n\r
"
local
EscapeSequence
=
(
P
"
\\
"
*
g
.
C
(
S
"
\"\\
/bfnrt"
+
Err
"unsupported escape sequence"
))
/
escapechars
local
HexDigit
=
R
(
"09"
,
"af"
,
"AF"
)
local
function
UTF16Surrogate
(
match
,
pos
,
high
,
low
)
high
,
low
=
tonumber
(
high
,
16
),
tonumber
(
low
,
16
)
if
0xD800
<=
high
and
high
<=
0xDBff
and
0xDC00
<=
low
and
low
<=
0xDFFF
then
return
true
,
unichar
((
high
-
0xD800
)
*
0x400
+
(
low
-
0xDC00
)
+
0x10000
)
else
return
false
end
end
local
function
UTF16BMP
(
hex
)
return
unichar
(
tonumber
(
hex
,
16
))
end
local
U16Sequence
=
(
P
"
\\
u"
*
g
.
C
(
HexDigit
*
HexDigit
*
HexDigit
*
HexDigit
))
local
UnicodeEscape
=
g
.
Cmt
(
U16Sequence
*
U16Sequence
,
UTF16Surrogate
)
+
U16Sequence
/
UTF16BMP
local
Char
=
UnicodeEscape
+
EscapeSequence
+
PlainChar
local
String
=
P
"
\"
"
*
g
.
Cs
(
Char
^
0
)
*
(
P
"
\"
"
+
Err
"unterminated string"
)
local
Integer
=
P
"-"
^
(
-
1
)
*
(
P
"0"
+
(
R
"19"
*
R
"09"
^
0
))
local
Fractal
=
P
"."
*
R
"09"
^
0
local
Exponent
=
(
S
"eE"
)
*
(
S
"+-"
)
^
(
-
1
)
*
R
"09"
^
1
local
Number
=
(
Integer
*
Fractal
^
(
-
1
)
*
Exponent
^
(
-
1
))
/
tonumber
local
Constant
=
P
"true"
*
g
.
Cc
(
true
)
+
P
"false"
*
g
.
Cc
(
false
)
+
P
"null"
*
g
.
Carg
(
1
)
local
SimpleValue
=
Number
+
String
+
Constant
local
ArrayContent
,
ObjectContent
-- The functions parsearray and parseobject parse only a single value/pair
-- at a time and store them directly to avoid hitting the LPeg limits.
local
function
parsearray
(
str
,
pos
,
nullval
,
state
)
local
obj
,
cont
local
npos
local
t
,
nt
=
{},
0
repeat
obj
,
cont
,
npos
=
pegmatch
(
ArrayContent
,
str
,
pos
,
nullval
,
state
)
if
not
npos
then
break
end
pos
=
npos
nt
=
nt
+
1
t
[
nt
]
=
obj
until
cont
==
'last'
return
pos
,
setmetatable
(
t
,
state
.
arraymeta
)
end
local
function
parseobject
(
str
,
pos
,
nullval
,
state
)
local
obj
,
key
,
cont
local
npos
local
t
=
{}
repeat
key
,
obj
,
cont
,
npos
=
pegmatch
(
ObjectContent
,
str
,
pos
,
nullval
,
state
)
if
not
npos
then
break
end
pos
=
npos
t
[
key
]
=
obj
until
cont
==
'last'
return
pos
,
setmetatable
(
t
,
state
.
objectmeta
)
end
local
Array
=
P
"["
*
g
.
Cmt
(
g
.
Carg
(
1
)
*
g
.
Carg
(
2
),
parsearray
)
*
Space
*
(
P
"]"
+
Err
"']' expected"
)
local
Object
=
P
"{"
*
g
.
Cmt
(
g
.
Carg
(
1
)
*
g
.
Carg
(
2
),
parseobject
)
*
Space
*
(
P
"}"
+
Err
"'}' expected"
)
local
Value
=
Space
*
(
Array
+
Object
+
SimpleValue
)
local
ExpectedValue
=
Value
+
Space
*
Err
"value expected"
ArrayContent
=
Value
*
Space
*
(
P
","
*
g
.
Cc
'cont'
+
g
.
Cc
'last'
)
*
g
.
Cp
()
local
Pair
=
g
.
Cg
(
Space
*
String
*
Space
*
(
P
":"
+
Err
"colon expected"
)
*
ExpectedValue
)
ObjectContent
=
Pair
*
Space
*
(
P
","
*
g
.
Cc
'cont'
+
g
.
Cc
'last'
)
*
g
.
Cp
()
local
DecodeValue
=
ExpectedValue
*
g
.
Cp
()
function
json
.
decode
(
str
,
pos
,
nullval
,
objectmeta
,
arraymeta
)
local
state
=
{
objectmeta
=
objectmeta
or
{
__jsontype
=
'object'
},
arraymeta
=
arraymeta
or
{
__jsontype
=
'array'
}
}
local
obj
,
retpos
=
pegmatch
(
DecodeValue
,
str
,
pos
,
nullval
,
state
)
if
state
.
msg
then
return
nil
,
state
.
pos
,
state
.
msg
else
return
obj
,
retpos
end
end
-- use this function only once:
json
.
use_lpeg
=
function
()
return
json
end
json
.
using_lpeg
=
true
return
json
-- so you can get the module using json = require "dkjson".use_lpeg()
end
if
always_try_using_lpeg
then
pcall
(
json
.
use_lpeg
)
end
return
json
-->
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment