commit
c09035dba0
4 changed files with 95 additions and 73 deletions
|
|
@ -19,30 +19,36 @@ namespace fc
|
|||
{
|
||||
legacy_parser = 0,
|
||||
strict_parser = 1,
|
||||
relaxed_parser = 2
|
||||
relaxed_parser = 2,
|
||||
legacy_parser_with_string_doubles = 3
|
||||
};
|
||||
enum output_formatting
|
||||
{
|
||||
stringify_large_ints_and_doubles = 0,
|
||||
legacy_generator = 1
|
||||
};
|
||||
|
||||
static ostream& to_stream( ostream& out, const fc::string& );
|
||||
static ostream& to_stream( ostream& out, const variant& v );
|
||||
static ostream& to_stream( ostream& out, const variants& v );
|
||||
static ostream& to_stream( ostream& out, const variant_object& v );
|
||||
static ostream& to_stream( ostream& out, const fc::string&);
|
||||
static ostream& to_stream( ostream& out, const variant& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static ostream& to_stream( ostream& out, const variants& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static ostream& to_stream( ostream& out, const variant_object& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
|
||||
static variant from_stream( buffered_istream& in, parse_type ptype = legacy_parser );
|
||||
|
||||
static variant from_string( const string& utf8_str, parse_type ptype = legacy_parser );
|
||||
static variants variants_from_string( const string& utf8_str, parse_type ptype = legacy_parser );
|
||||
static string to_string( const variant& v );
|
||||
static string to_pretty_string( const variant& v );
|
||||
static string to_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static string to_pretty_string( const variant& v, output_formatting format = stringify_large_ints_and_doubles );
|
||||
|
||||
static bool is_valid( const std::string& json_str, parse_type ptype = legacy_parser );
|
||||
|
||||
template<typename T>
|
||||
static void save_to_file( const T& v, const fc::path& fi, bool pretty = true )
|
||||
static void save_to_file( const T& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles )
|
||||
{
|
||||
save_to_file( variant(v), fi, pretty );
|
||||
save_to_file( variant(v), fi, pretty, format );
|
||||
}
|
||||
|
||||
static void save_to_file( const variant& v, const fc::path& fi, bool pretty = true );
|
||||
static void save_to_file( const variant& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles );
|
||||
static variant from_file( const fc::path& p, parse_type ptype = legacy_parser );
|
||||
|
||||
template<typename T>
|
||||
|
|
@ -52,19 +58,19 @@ namespace fc
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
static string to_string( const T& v )
|
||||
static string to_string( const T& v, output_formatting format = stringify_large_ints_and_doubles )
|
||||
{
|
||||
return to_string( variant(v) );
|
||||
return to_string( variant(v), format );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static string to_pretty_string( const T& v )
|
||||
static string to_pretty_string( const T& v, output_formatting format = stringify_large_ints_and_doubles )
|
||||
{
|
||||
return to_pretty_string( variant(v) );
|
||||
return to_pretty_string( variant(v), format );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void save_to_file( const T& v, const std::string& p, bool pretty = true )
|
||||
static void save_to_file( const T& v, const std::string& p, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles )
|
||||
{
|
||||
save_to_file( variant(v), fc::path(p), pretty );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -581,7 +581,7 @@ namespace fc { namespace json_relaxed
|
|||
continue;
|
||||
}
|
||||
if( skip_white_space(in) ) continue;
|
||||
string key = stringFromStream<T, strict>( in );
|
||||
string key = json_relaxed::stringFromStream<T, strict>( in );
|
||||
skip_white_space(in);
|
||||
if( in.peek() != ':' )
|
||||
{
|
||||
|
|
@ -589,7 +589,7 @@ namespace fc { namespace json_relaxed
|
|||
("key", key) );
|
||||
}
|
||||
in.get();
|
||||
auto val = variant_from_stream<T, strict>( in );
|
||||
auto val = json_relaxed::variant_from_stream<T, strict>( in );
|
||||
|
||||
obj(std::move(key),std::move(val));
|
||||
skip_white_space(in);
|
||||
|
|
@ -630,7 +630,7 @@ namespace fc { namespace json_relaxed
|
|||
continue;
|
||||
}
|
||||
if( skip_white_space(in) ) continue;
|
||||
ar.push_back( variant_from_stream<T, strict>(in) );
|
||||
ar.push_back( json_relaxed::variant_from_stream<T, strict>(in) );
|
||||
skip_white_space(in);
|
||||
}
|
||||
if( in.peek() != ']' )
|
||||
|
|
@ -647,7 +647,7 @@ namespace fc { namespace json_relaxed
|
|||
variant numberFromStream( T& in )
|
||||
{ try {
|
||||
fc::string token = tokenFromStream(in);
|
||||
variant result = parseNumberOrStr<strict>( token );
|
||||
variant result = json_relaxed::parseNumberOrStr<strict>( token );
|
||||
if( strict && !(result.is_int64() || result.is_uint64() || result.is_double()) )
|
||||
FC_THROW_EXCEPTION( parse_error_exception, "expected: number" );
|
||||
return result;
|
||||
|
|
@ -700,11 +700,11 @@ namespace fc { namespace json_relaxed
|
|||
in.get();
|
||||
continue;
|
||||
case '"':
|
||||
return stringFromStream<T, strict>( in );
|
||||
return json_relaxed::stringFromStream<T, strict>( in );
|
||||
case '{':
|
||||
return objectFromStream<T, strict>( in );
|
||||
return json_relaxed::objectFromStream<T, strict>( in );
|
||||
case '[':
|
||||
return arrayFromStream<T, strict>( in );
|
||||
return json_relaxed::arrayFromStream<T, strict>( in );
|
||||
case '-':
|
||||
case '+':
|
||||
case '.':
|
||||
|
|
@ -718,7 +718,7 @@ namespace fc { namespace json_relaxed
|
|||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return numberFromStream<T, strict>( in );
|
||||
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':
|
||||
|
|
@ -729,7 +729,7 @@ namespace fc { namespace json_relaxed
|
|||
case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
|
||||
case 'Y': case 'Z':
|
||||
case '_': case '/':
|
||||
return wordFromStream<T, strict>( in );
|
||||
return json_relaxed::wordFromStream<T, strict>( in );
|
||||
case 0x04: // ^D end of transmission
|
||||
case EOF:
|
||||
FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" );
|
||||
|
|
|
|||
104
src/io/json.cpp
104
src/io/json.cpp
|
|
@ -15,20 +15,19 @@
|
|||
namespace fc
|
||||
{
|
||||
// forward declarations of provided functions
|
||||
template<typename T> variant variant_from_stream( T& in );
|
||||
template<typename T, json::parse_type parser_type> variant variant_from_stream( T& in );
|
||||
template<typename T> char parseEscape( T& in );
|
||||
template<typename T> fc::string stringFromStream( T& in );
|
||||
template<typename T> bool skip_white_space( T& in );
|
||||
template<typename T> fc::string stringFromToken( T& in );
|
||||
template<typename T> variant_object objectFromStream( T& in );
|
||||
template<typename T> variants arrayFromStream( T& in );
|
||||
template<typename T> variant number_from_stream( T& in );
|
||||
template<typename T, json::parse_type parser_type> variant_object objectFromStream( T& in );
|
||||
template<typename T, json::parse_type parser_type> variants arrayFromStream( T& in );
|
||||
template<typename T, json::parse_type parser_type> variant number_from_stream( T& in );
|
||||
template<typename T> variant token_from_stream( T& in );
|
||||
template<typename T> variant variant_from_stream( T& in );
|
||||
void escape_string( const string& str, ostream& os );
|
||||
template<typename T> void to_stream( T& os, const variants& a );
|
||||
template<typename T> void to_stream( T& os, const variant_object& o );
|
||||
template<typename T> void to_stream( T& os, const variant& v );
|
||||
template<typename T> void to_stream( T& os, const variants& a, json::output_formatting format );
|
||||
template<typename T> void to_stream( T& os, const variant_object& o, json::output_formatting format );
|
||||
template<typename T> void to_stream( T& os, const variant& v, json::output_formatting format );
|
||||
fc::string pretty_print( const fc::string& v, uint8_t indent );
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +167,7 @@ namespace fc
|
|||
("token", token.str() ) );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variant_object objectFromStream( T& in )
|
||||
{
|
||||
mutable_variant_object obj;
|
||||
|
|
@ -197,7 +196,7 @@ namespace fc
|
|||
("key", key) );
|
||||
}
|
||||
in.get();
|
||||
auto val = variant_from_stream( in );
|
||||
auto val = variant_from_stream<T, parser_type>( in );
|
||||
|
||||
obj(std::move(key),std::move(val));
|
||||
skip_white_space(in);
|
||||
|
|
@ -219,7 +218,7 @@ namespace fc
|
|||
} FC_RETHROW_EXCEPTIONS( warn, "Error parsing object" );
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variants arrayFromStream( T& in )
|
||||
{
|
||||
variants ar;
|
||||
|
|
@ -238,7 +237,7 @@ namespace fc
|
|||
continue;
|
||||
}
|
||||
if( skip_white_space(in) ) continue;
|
||||
ar.push_back( variant_from_stream(in) );
|
||||
ar.push_back( variant_from_stream<T, parser_type>(in) );
|
||||
skip_white_space(in);
|
||||
}
|
||||
if( in.peek() != ']' )
|
||||
|
|
@ -251,7 +250,7 @@ namespace fc
|
|||
return ar;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variant number_from_stream( T& in )
|
||||
{
|
||||
fc::stringstream ss;
|
||||
|
|
@ -309,7 +308,7 @@ namespace fc
|
|||
if (str == "-." || str == ".") // check the obviously wrong things we could have encountered
|
||||
FC_THROW_EXCEPTION(parse_error_exception, "Can't parse token \"${token}\" as a JSON numeric constant", ("token", str));
|
||||
if( dot )
|
||||
return to_double(str);
|
||||
return parser_type == json::legacy_parser_with_string_doubles ? variant(str) : variant(to_double(str));
|
||||
if( neg )
|
||||
return to_int64(str);
|
||||
return to_uint64(str);
|
||||
|
|
@ -386,7 +385,7 @@ namespace fc
|
|||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
template<typename T, json::parse_type parser_type>
|
||||
variant variant_from_stream( T& in )
|
||||
{
|
||||
skip_white_space(in);
|
||||
|
|
@ -404,9 +403,9 @@ namespace fc
|
|||
case '"':
|
||||
return stringFromStream( in );
|
||||
case '{':
|
||||
return objectFromStream( in );
|
||||
return objectFromStream<T, parser_type>( in );
|
||||
case '[':
|
||||
return arrayFromStream( in );
|
||||
return arrayFromStream<T, parser_type>( in );
|
||||
case '-':
|
||||
case '.':
|
||||
case '0':
|
||||
|
|
@ -419,7 +418,7 @@ namespace fc
|
|||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return number_from_stream( in );
|
||||
return number_from_stream<T, parser_type>( in );
|
||||
// null, true, false, or 'warning' / string
|
||||
case 'n':
|
||||
case 't':
|
||||
|
|
@ -466,7 +465,9 @@ namespace fc
|
|||
switch( ptype )
|
||||
{
|
||||
case legacy_parser:
|
||||
return variant_from_stream( in );
|
||||
return variant_from_stream<fc::stringstream, legacy_parser>( in );
|
||||
case legacy_parser_with_string_doubles:
|
||||
return variant_from_stream<fc::stringstream, legacy_parser_with_string_doubles>( in );
|
||||
case strict_parser:
|
||||
return json_relaxed::variant_from_stream<fc::stringstream, true>( in );
|
||||
case relaxed_parser:
|
||||
|
|
@ -548,14 +549,14 @@ namespace fc
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void to_stream( T& os, const variants& a )
|
||||
void to_stream( T& os, const variants& a, json::output_formatting format )
|
||||
{
|
||||
os << '[';
|
||||
auto itr = a.begin();
|
||||
|
||||
while( itr != a.end() )
|
||||
{
|
||||
to_stream( os, *itr );
|
||||
to_stream( os, *itr, format );
|
||||
++itr;
|
||||
if( itr != a.end() )
|
||||
os << ',';
|
||||
|
|
@ -563,7 +564,7 @@ namespace fc
|
|||
os << ']';
|
||||
}
|
||||
template<typename T>
|
||||
void to_stream( T& os, const variant_object& o )
|
||||
void to_stream( T& os, const variant_object& o, json::output_formatting format )
|
||||
{
|
||||
os << '{';
|
||||
auto itr = o.begin();
|
||||
|
|
@ -572,7 +573,7 @@ namespace fc
|
|||
{
|
||||
escape_string( itr->key(), os );
|
||||
os << ':';
|
||||
to_stream( os, itr->value() );
|
||||
to_stream( os, itr->value(), format );
|
||||
++itr;
|
||||
if( itr != o.end() )
|
||||
os << ',';
|
||||
|
|
@ -581,7 +582,7 @@ namespace fc
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
void to_stream( T& os, const variant& v )
|
||||
void to_stream( T& os, const variant& v, json::output_formatting format )
|
||||
{
|
||||
switch( v.get_type() )
|
||||
{
|
||||
|
|
@ -591,24 +592,30 @@ namespace fc
|
|||
case variant::int64_type:
|
||||
{
|
||||
int64_t i = v.as_int64();
|
||||
if( i > 0xffffffff )
|
||||
if( format == json::stringify_large_ints_and_doubles &&
|
||||
i > 0xffffffff )
|
||||
os << '"'<<v.as_string()<<'"';
|
||||
else
|
||||
os << i;
|
||||
|
||||
return;
|
||||
}
|
||||
case variant::uint64_type:
|
||||
{
|
||||
uint64_t i = v.as_uint64();
|
||||
if( i > 0xffffffff )
|
||||
if( format == json::stringify_large_ints_and_doubles &&
|
||||
i > 0xffffffff )
|
||||
os << '"'<<v.as_string()<<'"';
|
||||
else
|
||||
os << i;
|
||||
|
||||
return;
|
||||
}
|
||||
case variant::double_type:
|
||||
//os << v.as_string();
|
||||
if (format == json::stringify_large_ints_and_doubles)
|
||||
os << '"'<<v.as_string()<<'"';
|
||||
else
|
||||
os << v.as_string();
|
||||
return;
|
||||
case variant::bool_type:
|
||||
os << v.as_string();
|
||||
|
|
@ -622,22 +629,22 @@ namespace fc
|
|||
case variant::array_type:
|
||||
{
|
||||
const variants& a = v.get_array();
|
||||
to_stream( os, a );
|
||||
to_stream( os, a, format );
|
||||
return;
|
||||
}
|
||||
case variant::object_type:
|
||||
{
|
||||
const variant_object& o = v.get_object();
|
||||
to_stream(os, o );
|
||||
to_stream(os, o, format );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fc::string json::to_string( const variant& v )
|
||||
fc::string json::to_string( const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
{
|
||||
fc::stringstream ss;
|
||||
fc::to_stream( ss, v );
|
||||
fc::to_stream( ss, v, format );
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
|
@ -732,23 +739,23 @@ namespace fc
|
|||
|
||||
|
||||
|
||||
fc::string json::to_pretty_string( const variant& v )
|
||||
fc::string json::to_pretty_string( const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
{
|
||||
return pretty_print(to_string(v), 2);
|
||||
return pretty_print(to_string(v, format), 2);
|
||||
}
|
||||
|
||||
void json::save_to_file( const variant& v, const fc::path& fi, bool pretty )
|
||||
void json::save_to_file( const variant& v, const fc::path& fi, bool pretty, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
{
|
||||
if( pretty )
|
||||
{
|
||||
auto str = json::to_pretty_string( v );
|
||||
auto str = json::to_pretty_string( v, format );
|
||||
fc::ofstream o(fi);
|
||||
o.write( str.c_str(), str.size() );
|
||||
}
|
||||
else
|
||||
{
|
||||
fc::ofstream o(fi);
|
||||
fc::to_stream( o, v );
|
||||
fc::to_stream( o, v, format );
|
||||
}
|
||||
}
|
||||
variant json::from_file( const fc::path& p, parse_type ptype )
|
||||
|
|
@ -760,7 +767,9 @@ namespace fc
|
|||
switch( ptype )
|
||||
{
|
||||
case legacy_parser:
|
||||
return variant_from_stream( bi );
|
||||
return variant_from_stream<boost::filesystem::ifstream, legacy_parser>( bi );
|
||||
case legacy_parser_with_string_doubles:
|
||||
return variant_from_stream<boost::filesystem::ifstream, legacy_parser_with_string_doubles>( bi );
|
||||
case strict_parser:
|
||||
return json_relaxed::variant_from_stream<boost::filesystem::ifstream, true>( bi );
|
||||
case relaxed_parser:
|
||||
|
|
@ -774,7 +783,9 @@ namespace fc
|
|||
switch( ptype )
|
||||
{
|
||||
case legacy_parser:
|
||||
return variant_from_stream( in );
|
||||
return variant_from_stream<fc::buffered_istream, legacy_parser>( in );
|
||||
case legacy_parser_with_string_doubles:
|
||||
return variant_from_stream<fc::buffered_istream, legacy_parser_with_string_doubles>( in );
|
||||
case strict_parser:
|
||||
return json_relaxed::variant_from_stream<buffered_istream, true>( in );
|
||||
case relaxed_parser:
|
||||
|
|
@ -784,19 +795,19 @@ namespace fc
|
|||
}
|
||||
}
|
||||
|
||||
ostream& json::to_stream( ostream& out, const variant& v )
|
||||
ostream& json::to_stream( ostream& out, const variant& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
{
|
||||
fc::to_stream( out, v );
|
||||
fc::to_stream( out, v, format );
|
||||
return out;
|
||||
}
|
||||
ostream& json::to_stream( ostream& out, const variants& v )
|
||||
ostream& json::to_stream( ostream& out, const variants& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
{
|
||||
fc::to_stream( out, v );
|
||||
fc::to_stream( out, v, format );
|
||||
return out;
|
||||
}
|
||||
ostream& json::to_stream( ostream& out, const variant_object& v )
|
||||
ostream& json::to_stream( ostream& out, const variant_object& v, output_formatting format /* = stringify_large_ints_and_doubles */ )
|
||||
{
|
||||
fc::to_stream( out, v );
|
||||
fc::to_stream( out, v, format );
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
@ -807,7 +818,10 @@ namespace fc
|
|||
switch( ptype )
|
||||
{
|
||||
case legacy_parser:
|
||||
variant_from_stream( in );
|
||||
variant_from_stream<fc::stringstream, legacy_parser>( in );
|
||||
break;
|
||||
case legacy_parser_with_string_doubles:
|
||||
variant_from_stream<fc::stringstream, legacy_parser_with_string_doubles>( in );
|
||||
break;
|
||||
case strict_parser:
|
||||
json_relaxed::variant_from_stream<fc::stringstream, true>( in );
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <locale>
|
||||
#include <limits>
|
||||
|
||||
/**
|
||||
* Implemented with std::string for now.
|
||||
|
|
@ -127,11 +128,12 @@ namespace fc {
|
|||
FC_RETHROW_EXCEPTIONS( warn, "${i} => double", ("i",i) )
|
||||
}
|
||||
|
||||
fc::string to_string( double d)
|
||||
fc::string to_string(double d)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(12) << std::fixed << d;
|
||||
return ss.str(); //boost::lexical_cast<std::string>(d);
|
||||
// +2 is required to ensure that the double is rounded correctly when read back in. http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
|
||||
std::stringstream ss;
|
||||
ss << std::setprecision(std::numeric_limits<double>::digits10 + 2) << std::fixed << d;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
fc::string to_string( uint64_t d)
|
||||
|
|
|
|||
Loading…
Reference in a new issue