forked from steemit/fc
-
Notifications
You must be signed in to change notification settings - Fork 89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON parsing fix from steem PR 2178 #15
Merged
Merged
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
bbe2a8b
JSON parsing fix from steem PR 2178
pmconrad b12205c
Minor optimization
pmconrad 0c75709
Added unit tests for stringstream, [io]fstream and buffered_[io]stream
pmconrad 72e96e3
Added first json test case
pmconrad 52f6810
Fixed from_file
pmconrad 4d782e8
Deduplicate some code
pmconrad 8c09ff0
Added json write/validate/read test
pmconrad e37d9a5
Code cleanups and simplifications
pmconrad 43fabf6
Code deduplication
pmconrad cb9c61f
Avoid legacy_generator
pmconrad 1ae3cc2
Make unused parsers compile-time optional
pmconrad b4f3947
Include variants_from_string in parser test
pmconrad 4bb8bf7
Fixed relaxed parser wrt "" input
pmconrad d336af8
Applied variant_from_stream fix from regular to relaxed
pmconrad a7e0c88
Added test case for recursion depth 240
pmconrad 90137d4
Fix for recursion depth limitation
pmconrad 2bacd5f
Added broken_nul_parser to preserve previous behaviour
pmconrad 66ed9fc
Minor fixes
pmconrad 1412df1
Make broken_nul_parser usable
pmconrad f9802f6
Added max_depth parameter to all to_/from_ methods
pmconrad 1331485
Stringify numbers >MAXINT or <MININT
pmconrad d24bee8
Added test case for exception in exception handling
pmconrad 527daab
Moved format_string from variant.cpp to string.cpp (it is declared in…
pmconrad File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,7 @@ | |
namespace fc { namespace json_relaxed | ||
{ | ||
template<typename T, bool strict> | ||
variant variant_from_stream( T& in ); | ||
variant variant_from_stream( T& in, uint32_t depth ); | ||
|
||
template<typename T> | ||
fc::string tokenFromStream( T& in ) | ||
|
@@ -104,8 +104,15 @@ namespace fc { namespace json_relaxed | |
if( in.peek() == q ) | ||
{ | ||
in.get(); | ||
if( in.peek() != q ) | ||
return fc::string(); | ||
try | ||
{ | ||
if( in.peek() != q ) | ||
return fc::string(); | ||
} | ||
catch( const fc::eof_exception& e ) | ||
{ | ||
return fc::string(); | ||
} | ||
|
||
// triple quote processing | ||
if( strict ) | ||
|
@@ -562,86 +569,18 @@ namespace fc { namespace json_relaxed | |
} FC_CAPTURE_AND_RETHROW( (token) ) } | ||
|
||
template<typename T, bool strict> | ||
variant_object objectFromStream( T& in ) | ||
variant_object objectFromStream( T& in, uint32_t depth ) | ||
{ | ||
mutable_variant_object obj; | ||
try | ||
{ | ||
char c = in.peek(); | ||
if( c != '{' ) | ||
FC_THROW_EXCEPTION( parse_error_exception, | ||
"Expected '{', but read '${char}'", | ||
("char",string(&c, &c + 1)) ); | ||
in.get(); | ||
skip_white_space(in); | ||
while( in.peek() != '}' ) | ||
{ | ||
if( in.peek() == ',' ) | ||
{ | ||
in.get(); | ||
continue; | ||
} | ||
if( skip_white_space(in) ) continue; | ||
string key = json_relaxed::stringFromStream<T, strict>( in ); | ||
skip_white_space(in); | ||
if( in.peek() != ':' ) | ||
{ | ||
FC_THROW_EXCEPTION( parse_error_exception, "Expected ':' after key \"${key}\"", | ||
("key", key) ); | ||
} | ||
in.get(); | ||
auto val = json_relaxed::variant_from_stream<T, strict>( in ); | ||
|
||
obj(std::move(key),std::move(val)); | ||
skip_white_space(in); | ||
} | ||
if( in.peek() == '}' ) | ||
{ | ||
in.get(); | ||
return obj; | ||
} | ||
FC_THROW_EXCEPTION( parse_error_exception, "Expected '}' after ${variant}", ("variant", obj ) ); | ||
} | ||
catch( const fc::eof_exception& e ) | ||
{ | ||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.to_detail_string() ) ); | ||
} | ||
catch( const std::ios_base::failure& e ) | ||
{ | ||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF: ${e}", ("e", e.what() ) ); | ||
} FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" ); | ||
std::function<std::string(T&)> get_key = []( T& in ){ return json_relaxed::stringFromStream<T, strict>( in ); }; | ||
std::function<variant(T&)> get_value = [depth]( T& in ){ return json_relaxed::variant_from_stream<T, strict>( in, depth ); }; | ||
return objectFromStreamBase<T>( in, get_key, get_value ); | ||
} | ||
|
||
template<typename T, bool strict> | ||
variants arrayFromStream( T& in ) | ||
variants arrayFromStream( T& in, uint32_t depth ) | ||
{ | ||
variants ar; | ||
try | ||
{ | ||
if( in.peek() != '[' ) | ||
FC_THROW_EXCEPTION( parse_error_exception, "Expected '['" ); | ||
in.get(); | ||
skip_white_space(in); | ||
|
||
while( in.peek() != ']' ) | ||
{ | ||
if( in.peek() == ',' ) | ||
{ | ||
in.get(); | ||
continue; | ||
} | ||
if( skip_white_space(in) ) continue; | ||
ar.push_back( json_relaxed::variant_from_stream<T, strict>(in) ); | ||
skip_white_space(in); | ||
} | ||
if( in.peek() != ']' ) | ||
FC_THROW_EXCEPTION( parse_error_exception, "Expected ']' after parsing ${variant}", | ||
("variant", ar) ); | ||
|
||
in.get(); | ||
} FC_RETHROW_EXCEPTIONS( warn, "Attempting to parse array ${array}", | ||
("array", ar ) ); | ||
return ar; | ||
std::function<variant(T&)> get_value = [depth]( T& in ){ return json_relaxed::variant_from_stream<T, strict>( in, depth ); }; | ||
return arrayFromStreamBase<T>( in, get_value ); | ||
} | ||
|
||
template<typename T, bool strict> | ||
|
@@ -686,60 +625,52 @@ namespace fc { namespace json_relaxed | |
} | ||
|
||
template<typename T, bool strict> | ||
variant variant_from_stream( T& in ) | ||
variant variant_from_stream( T& in, uint32_t depth ) | ||
{ | ||
FC_ASSERT( depth < MAX_RECURSION_DEPTH, "Too many nested items in JSON string!" ); | ||
skip_white_space(in); | ||
variant var; | ||
while( signed char c = in.peek() ) | ||
signed char c = in.peek(); | ||
switch( c ) | ||
{ | ||
switch( c ) | ||
{ | ||
case ' ': | ||
case '\t': | ||
case '\n': | ||
case '\r': | ||
in.get(); | ||
continue; | ||
case '"': | ||
return json_relaxed::stringFromStream<T, strict>( in ); | ||
case '{': | ||
return json_relaxed::objectFromStream<T, strict>( in ); | ||
case '[': | ||
return json_relaxed::arrayFromStream<T, strict>( in ); | ||
case '-': | ||
case '+': | ||
case '.': | ||
case '0': | ||
case '1': | ||
case '2': | ||
case '3': | ||
case '4': | ||
case '5': | ||
case '6': | ||
case '7': | ||
case '8': | ||
case '9': | ||
return json_relaxed::numberFromStream<T, strict>( in ); | ||
// null, true, false, or 'warning' / string | ||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': | ||
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': | ||
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': | ||
case 'y': case 'z': | ||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': | ||
case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': | ||
case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': | ||
case 'Y': case 'Z': | ||
case '_': case '/': | ||
return json_relaxed::wordFromStream<T, strict>( in ); | ||
case 0x04: // ^D end of transmission | ||
case EOF: | ||
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); | ||
default: | ||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"", | ||
("c", c)("s", stringFromToken(in)) ); | ||
} | ||
case '"': | ||
return json_relaxed::stringFromStream<T, strict>( in ); | ||
case '{': | ||
return json_relaxed::objectFromStream<T, strict>( in, depth + 1 ); | ||
case '[': | ||
return json_relaxed::arrayFromStream<T, strict>( in, depth + 1 ); | ||
case '-': | ||
case '+': | ||
case '.': | ||
case '0': | ||
case '1': | ||
case '2': | ||
case '3': | ||
case '4': | ||
case '5': | ||
case '6': | ||
case '7': | ||
case '8': | ||
case '9': | ||
return json_relaxed::numberFromStream<T, strict>( in ); | ||
// null, true, false, or 'warning' / string | ||
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': | ||
case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': | ||
case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': | ||
case 'y': case 'z': | ||
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': | ||
case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': | ||
case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': | ||
case 'Y': case 'Z': | ||
case '_': case '/': | ||
return json_relaxed::wordFromStream<T, strict>( in ); | ||
case 0x04: // ^D end of transmission | ||
case EOF: | ||
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); | ||
case 0: | ||
default: | ||
FC_THROW_EXCEPTION( parse_error_exception, "Unexpected char '${c}' in \"${s}\"", | ||
("c", c)("s", stringFromToken(in)) ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about |
||
} | ||
return variant(); | ||
} | ||
|
||
} } // fc::json_relaxed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about single quotes? According to
stringFromStream(...)
, Ifstrict
isfalse
, need to support it and raw strings etc.