Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
json
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
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
Libraries
json
Commits
5f723bbe
Unverified
Commit
5f723bbe
authored
7 years ago
by
Niels Lohmann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
realized callback parser wirh SAX interface #971
parent
4f6b2b64
develop
bon8
coverity_scan
feature/optional
gcc_warning_flags
icpc
issue2228
issue2615
issue2932
issue3232_use_catch
master
release/3.10.2
release/3.10.3
release/3.10.4
release/3.10.5
string_view
string_view2
update_doctest
3.6.1
3.3.0
3.2.0
v3.10.5
v3.10.4
v3.10.3
v3.10.2
v3.10.1
v3.10.0
v3.9.1
v3.9.0
v3.8.0
v3.7.3
v3.7.2
v3.7.1
v3.7.0
v3.6.1
v3.6.0
v3.5.0
v3.4.0
v3.3.0
v3.2.0
No related merge requests found
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
273 additions
and
698 deletions
+273
-698
include/nlohmann/detail/input/json_sax.hpp
include/nlohmann/detail/input/json_sax.hpp
+122
-31
include/nlohmann/detail/input/parser.hpp
include/nlohmann/detail/input/parser.hpp
+0
-318
single_include/nlohmann/json.hpp
single_include/nlohmann/json.hpp
+122
-349
test/src/unit-ubjson.cpp
test/src/unit-ubjson.cpp
+29
-0
No files found.
include/nlohmann/detail/input/json_sax.hpp
View file @
5f723bbe
...
@@ -242,7 +242,7 @@ class json_sax_dom_parser : public json_sax<BasicJsonType>
...
@@ -242,7 +242,7 @@ class json_sax_dom_parser : public json_sax<BasicJsonType>
return
false
;
return
false
;
}
}
bool
is_errored
()
const
constexpr
bool
is_errored
()
const
{
{
return
errored
;
return
errored
;
}
}
...
@@ -303,7 +303,7 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
...
@@ -303,7 +303,7 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
using
parse_event_t
=
typename
BasicJsonType
::
parse_event_t
;
using
parse_event_t
=
typename
BasicJsonType
::
parse_event_t
;
json_sax_dom_callback_parser
(
BasicJsonType
&
r
,
json_sax_dom_callback_parser
(
BasicJsonType
&
r
,
const
parser_callback_t
cb
=
nullptr
,
const
parser_callback_t
cb
,
const
bool
allow_exceptions_
=
true
)
const
bool
allow_exceptions_
=
true
)
:
root
(
r
),
callback
(
cb
),
allow_exceptions
(
allow_exceptions_
)
:
root
(
r
),
callback
(
cb
),
allow_exceptions
(
allow_exceptions_
)
{
{
...
@@ -348,15 +348,21 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
...
@@ -348,15 +348,21 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
bool
start_object
(
std
::
size_t
len
)
override
bool
start_object
(
std
::
size_t
len
)
override
{
{
const
bool
keep
=
callback
(
ref_stack
.
size
()
+
1
,
parse_event_t
::
object_start
,
discarded
);
// check callback for object start
const
bool
keep
=
callback
(
static_cast
<
int
>
(
ref_stack
.
size
())
+
1
,
parse_event_t
::
object_start
,
discarded
);
keep_stack
.
push_back
(
keep
);
keep_stack
.
push_back
(
keep
);
ref_stack
.
push_back
(
handle_value
(
BasicJsonType
::
value_t
::
object
));
auto
val
=
handle_value
(
BasicJsonType
::
value_t
::
object
);
ref_stack
.
push_back
(
val
.
second
);
if
(
JSON_UNLIKELY
(
len
!=
json_sax
<
BasicJsonType
>::
no_limit
and
len
>
ref_stack
.
back
()
->
max_size
()))
// check object limit
if
(
ref_stack
.
back
())
{
{
JSON_THROW
(
out_of_range
::
create
(
408
,
if
(
JSON_UNLIKELY
(
len
!=
json_sax
<
BasicJsonType
>::
no_limit
and
len
>
ref_stack
.
back
()
->
max_size
()))
"excessive object size: "
+
std
::
to_string
(
len
)));
{
JSON_THROW
(
out_of_range
::
create
(
408
,
"excessive object size: "
+
std
::
to_string
(
len
)));
}
}
}
return
true
;
return
true
;
...
@@ -365,38 +371,73 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
...
@@ -365,38 +371,73 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
bool
key
(
string_t
&
val
)
override
bool
key
(
string_t
&
val
)
override
{
{
BasicJsonType
k
=
BasicJsonType
(
val
);
BasicJsonType
k
=
BasicJsonType
(
val
);
const
bool
keep
=
callback
(
ref_stack
.
size
(),
parse_event_t
::
key
,
k
);
// add null at given key and store the reference for later
// check callback for key
object_element
=
&
(
ref_stack
.
back
()
->
m_value
.
object
->
operator
[](
val
));
const
bool
keep
=
callback
(
static_cast
<
int
>
(
ref_stack
.
size
()),
parse_event_t
::
key
,
k
);
key_keep_stack
.
push_back
(
keep
);
// add discarded value at given key and store the reference for later
if
(
keep
and
ref_stack
.
back
())
{
object_element
=
&
(
ref_stack
.
back
()
->
m_value
.
object
->
operator
[](
val
)
=
discarded
);
}
return
true
;
return
true
;
}
}
bool
end_object
()
override
bool
end_object
()
override
{
{
const
bool
keep
=
callback
(
ref_stack
.
size
()
-
1
,
parse_event_t
::
object_end
,
*
ref_stack
.
back
())
;
bool
keep
=
true
;
if
(
not
keep
)
if
(
ref_stack
.
back
()
)
{
{
// discard object
keep
=
callback
(
static_cast
<
int
>
(
ref_stack
.
size
())
-
1
,
parse_event_t
::
object_end
,
*
ref_stack
.
back
());
*
ref_stack
.
back
()
=
discarded
;
if
(
not
keep
)
{
// discard object
*
ref_stack
.
back
()
=
discarded
;
}
}
}
assert
(
not
ref_stack
.
empty
());
assert
(
not
keep_stack
.
empty
());
ref_stack
.
pop_back
();
ref_stack
.
pop_back
();
keep_stack
.
pop_back
();
keep_stack
.
pop_back
();
if
(
not
ref_stack
.
empty
()
and
ref_stack
.
back
())
{
// remove discarded value
if
(
ref_stack
.
back
()
->
is_object
())
{
for
(
auto
it
=
ref_stack
.
back
()
->
begin
();
it
!=
ref_stack
.
back
()
->
end
();
++
it
)
{
if
(
it
->
is_discarded
())
{
ref_stack
.
back
()
->
erase
(
it
);
break
;
}
}
}
}
return
true
;
return
true
;
}
}
bool
start_array
(
std
::
size_t
len
)
override
bool
start_array
(
std
::
size_t
len
)
override
{
{
const
bool
keep
=
callback
(
ref_stack
.
size
(
)
+
1
,
parse_event_t
::
array_start
,
discarded
);
const
bool
keep
=
callback
(
static_cast
<
int
>
(
ref_stack
.
size
()
)
+
1
,
parse_event_t
::
array_start
,
discarded
);
keep_stack
.
push_back
(
keep
);
keep_stack
.
push_back
(
keep
);
ref_stack
.
push_back
(
handle_value
(
BasicJsonType
::
value_t
::
array
));
auto
val
=
handle_value
(
BasicJsonType
::
value_t
::
array
);
ref_stack
.
push_back
(
val
.
second
);
if
(
JSON_UNLIKELY
(
len
!=
json_sax
<
BasicJsonType
>::
no_limit
and
len
>
ref_stack
.
back
()
->
max_size
()))
// check array limit
if
(
ref_stack
.
back
())
{
{
JSON_THROW
(
out_of_range
::
create
(
408
,
if
(
JSON_UNLIKELY
(
len
!=
json_sax
<
BasicJsonType
>::
no_limit
and
len
>
ref_stack
.
back
()
->
max_size
()))
"excessive array size: "
+
std
::
to_string
(
len
)));
{
JSON_THROW
(
out_of_range
::
create
(
408
,
"excessive array size: "
+
std
::
to_string
(
len
)));
}
}
}
return
true
;
return
true
;
...
@@ -404,15 +445,32 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
...
@@ -404,15 +445,32 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
bool
end_array
()
override
bool
end_array
()
override
{
{
const
bool
keep
=
callback
(
ref_stack
.
size
()
-
1
,
parse_event_t
::
array_end
,
*
ref_stack
.
back
());
bool
keep
=
true
;
if
(
not
keep
)
if
(
ref_stack
.
back
())
{
{
// discard array
keep
=
callback
(
static_cast
<
int
>
(
ref_stack
.
size
())
-
1
,
parse_event_t
::
array_end
,
*
ref_stack
.
back
());
*
ref_stack
.
back
()
=
discarded
;
if
(
not
keep
)
{
// discard array
*
ref_stack
.
back
()
=
discarded
;
}
}
}
assert
(
not
ref_stack
.
empty
());
assert
(
not
keep_stack
.
empty
());
ref_stack
.
pop_back
();
ref_stack
.
pop_back
();
keep_stack
.
pop_back
();
keep_stack
.
pop_back
();
// remove discarded value
if
(
not
keep
and
not
ref_stack
.
empty
())
{
if
(
ref_stack
.
back
()
->
is_array
())
{
ref_stack
.
back
()
->
m_value
.
array
->
pop_back
();
}
}
return
true
;
return
true
;
}
}
...
@@ -442,7 +500,7 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
...
@@ -442,7 +500,7 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
return
false
;
return
false
;
}
}
bool
is_errored
()
const
constexpr
bool
is_errored
()
const
{
{
return
errored
;
return
errored
;
}
}
...
@@ -453,28 +511,59 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
...
@@ -453,28 +511,59 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
root.
root.
@invariant If the ref stack contains a value, then it is an array or an
@invariant If the ref stack contains a value, then it is an array or an
object to which we can add elements
object to which we can add elements
@return pair of boolean (whether value should be kept) and pointer (to the
passed value in the ref_stack hierarchy; nullptr if not kept)
*/
*/
template
<
typename
Value
>
template
<
typename
Value
>
BasicJsonType
*
handle_value
(
Value
&&
v
)
std
::
pair
<
bool
,
BasicJsonType
*>
handle_value
(
Value
&&
v
)
{
{
assert
(
not
keep_stack
.
empty
());
// do not handle this value if we know it would be added to a discarded
// container
if
(
not
keep_stack
.
back
())
{
return
{
false
,
nullptr
};
}
// create value and check callback
auto
value
=
BasicJsonType
(
std
::
forward
<
Value
>
(
v
));
const
bool
keep
=
callback
(
static_cast
<
int
>
(
ref_stack
.
size
()),
parse_event_t
::
value
,
value
);
// do not handle this value if we just learnt it shall be discarded
if
(
not
keep
)
{
return
{
false
,
nullptr
};
}
if
(
ref_stack
.
empty
())
if
(
ref_stack
.
empty
())
{
{
root
=
BasicJsonType
(
std
::
forward
<
Value
>
(
v
)
);
root
=
std
::
move
(
value
);
return
&
root
;
return
{
true
,
&
root
}
;
}
}
else
else
{
{
assert
(
ref_stack
.
back
()
->
is_array
()
or
ref_stack
.
back
()
->
is_object
());
assert
(
ref_stack
.
back
()
->
is_array
()
or
ref_stack
.
back
()
->
is_object
());
if
(
ref_stack
.
back
()
->
is_array
())
if
(
ref_stack
.
back
()
->
is_array
())
{
{
ref_stack
.
back
()
->
m_value
.
array
->
emplace_back
(
std
::
forward
<
Value
>
(
v
));
ref_stack
.
back
()
->
m_value
.
array
->
push_back
(
std
::
move
(
value
));
return
&
(
ref_stack
.
back
()
->
m_value
.
array
->
back
())
;
return
{
true
,
&
(
ref_stack
.
back
()
->
m_value
.
array
->
back
())}
;
}
}
else
else
{
{
// check if we should store an element for the current key
assert
(
not
key_keep_stack
.
empty
());
const
bool
store_element
=
key_keep_stack
.
back
();
key_keep_stack
.
pop_back
();
if
(
not
store_element
)
{
return
{
false
,
nullptr
};
}
assert
(
object_element
);
assert
(
object_element
);
*
object_element
=
BasicJsonType
(
std
::
forward
<
Value
>
(
v
)
);
*
object_element
=
std
::
move
(
value
);
return
object_element
;
return
{
true
,
object_element
}
;
}
}
}
}
}
}
...
@@ -485,6 +574,8 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
...
@@ -485,6 +574,8 @@ class json_sax_dom_callback_parser : public json_sax<BasicJsonType>
std
::
vector
<
BasicJsonType
*>
ref_stack
;
std
::
vector
<
BasicJsonType
*>
ref_stack
;
/// stack to manage which values to keep
/// stack to manage which values to keep
std
::
vector
<
bool
>
keep_stack
;
std
::
vector
<
bool
>
keep_stack
;
/// stack to manage which object keys to keep
std
::
vector
<
bool
>
key_keep_stack
;
/// helper to hold the reference for the next object element
/// helper to hold the reference for the next object element
BasicJsonType
*
object_element
=
nullptr
;
BasicJsonType
*
object_element
=
nullptr
;
/// whether a syntax error occurred
/// whether a syntax error occurred
...
...
This diff is collapsed.
Click to expand it.
include/nlohmann/detail/input/parser.hpp
View file @
5f723bbe
This diff is collapsed.
Click to expand it.
single_include/nlohmann/json.hpp
View file @
5f723bbe
This diff is collapsed.
Click to expand it.
test/src/unit-ubjson.cpp
View file @
5f723bbe
...
@@ -1309,6 +1309,35 @@ TEST_CASE("UBJSON")
...
@@ -1309,6 +1309,35 @@ TEST_CASE("UBJSON")
CHECK_THROWS_AS
(
json
::
to_ubjson
(
j
),
json
::
out_of_range
&
);
CHECK_THROWS_AS
(
json
::
to_ubjson
(
j
),
json
::
out_of_range
&
);
CHECK_THROWS_WITH
(
json
::
to_ubjson
(
j
),
"[json.exception.out_of_range.407] number overflow serializing 9223372036854775808"
);
CHECK_THROWS_WITH
(
json
::
to_ubjson
(
j
),
"[json.exception.out_of_range.407] number overflow serializing 9223372036854775808"
);
}
}
SECTION
(
"excessive size"
)
{
SECTION
(
"array"
)
{
std
::
vector
<
uint8_t
>
v_ubjson
=
{
'['
,
'$'
,
'Z'
,
'#'
,
'L'
,
0x78
,
0x28
,
0x00
,
0x68
,
0x28
,
0x69
,
0x69
,
0x17
};
CHECK_THROWS_AS
(
json
::
from_ubjson
(
v_ubjson
),
json
::
out_of_range
&
);
json
j
;
nlohmann
::
detail
::
json_sax_dom_callback_parser
<
json
>
scp
(
j
,
[](
int
,
json
::
parse_event_t
,
const
json
&
)
{
return
true
;
});
CHECK_THROWS_AS
(
json
::
sax_parse
(
v_ubjson
,
&
scp
,
json
::
input_format_t
::
ubjson
),
json
::
out_of_range
&
);
}
SECTION
(
"object"
)
{
std
::
vector
<
uint8_t
>
v_ubjson
=
{
'{'
,
'$'
,
'Z'
,
'#'
,
'L'
,
0x78
,
0x28
,
0x00
,
0x68
,
0x28
,
0x69
,
0x69
,
0x17
};
CHECK_THROWS_AS
(
json
::
from_ubjson
(
v_ubjson
),
json
::
out_of_range
&
);
json
j
;
nlohmann
::
detail
::
json_sax_dom_callback_parser
<
json
>
scp
(
j
,
[](
int
,
json
::
parse_event_t
,
const
json
&
)
{
return
true
;
});
CHECK_THROWS_AS
(
json
::
sax_parse
(
v_ubjson
,
&
scp
,
json
::
input_format_t
::
ubjson
),
json
::
out_of_range
&
);
}
}
}
}
SECTION
(
"SAX aborts"
)
SECTION
(
"SAX aborts"
)
...
...
This diff is collapsed.
Click to expand it.
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