diff --git a/include/fc/io/json.hpp b/include/fc/io/json.hpp index 983025f..299378f 100644 --- a/include/fc/io/json.hpp +++ b/include/fc/io/json.hpp @@ -19,7 +19,8 @@ namespace fc { legacy_parser = 0, strict_parser = 1, - relaxed_parser = 2 + relaxed_parser = 2, + legacy_parser_with_string_doubles = 3 }; static ostream& to_stream( ostream& out, const fc::string& ); diff --git a/include/fc/io/json_relaxed.hpp b/include/fc/io/json_relaxed.hpp index aa50948..b7a135f 100644 --- a/include/fc/io/json_relaxed.hpp +++ b/include/fc/io/json_relaxed.hpp @@ -577,7 +577,7 @@ namespace fc { namespace json_relaxed continue; } if( skip_white_space(in) ) continue; - string key = stringFromStream( in ); + string key = json_relaxed::stringFromStream( in ); skip_white_space(in); if( in.peek() != ':' ) { @@ -585,7 +585,7 @@ namespace fc { namespace json_relaxed ("key", key) ); } in.get(); - auto val = variant_from_stream( in ); + auto val = json_relaxed::variant_from_stream( in ); obj(std::move(key),std::move(val)); skip_white_space(in); @@ -626,7 +626,7 @@ namespace fc { namespace json_relaxed continue; } if( skip_white_space(in) ) continue; - ar.push_back( variant_from_stream(in) ); + ar.push_back( json_relaxed::variant_from_stream(in) ); skip_white_space(in); } if( in.peek() != ']' ) @@ -643,7 +643,7 @@ namespace fc { namespace json_relaxed variant numberFromStream( T& in ) { fc::string token = tokenFromStream(in); - variant result = parseNumberOrStr( token ); + variant result = json_relaxed::parseNumberOrStr( token ); if( strict && !(result.is_int64() || result.is_uint64() || result.is_double()) ) FC_THROW_EXCEPTION( parse_error_exception, "expected: number" ); return result; @@ -696,11 +696,11 @@ namespace fc { namespace json_relaxed in.get(); continue; case '"': - return stringFromStream( in ); + return json_relaxed::stringFromStream( in ); case '{': - return objectFromStream( in ); + return json_relaxed::objectFromStream( in ); case '[': - return arrayFromStream( in ); + return json_relaxed::arrayFromStream( in ); case '-': case '+': case '.': @@ -714,7 +714,7 @@ namespace fc { namespace json_relaxed case '7': case '8': case '9': - return numberFromStream( in ); + return json_relaxed::numberFromStream( 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': @@ -725,7 +725,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( in ); + return json_relaxed::wordFromStream( in ); case 0x04: // ^D end of transmission case EOF: FC_THROW_EXCEPTION( eof_exception, "unexpected end of file" ); diff --git a/src/io/json.cpp b/src/io/json.cpp index 4ecf307..022df59 100644 --- a/src/io/json.cpp +++ b/src/io/json.cpp @@ -15,16 +15,15 @@ namespace fc { // forward declarations of provided functions - template variant variant_from_stream( T& in ); + template variant variant_from_stream( T& in ); template char parseEscape( T& in ); template fc::string stringFromStream( T& in ); template bool skip_white_space( T& in ); template fc::string stringFromToken( T& in ); - template variant_object objectFromStream( T& in ); - template variants arrayFromStream( T& in ); - template variant number_from_stream( T& in ); + template variant_object objectFromStream( T& in ); + template variants arrayFromStream( T& in ); + template variant number_from_stream( T& in ); template variant token_from_stream( T& in ); - template variant variant_from_stream( T& in ); void escape_string( const string& str, ostream& os ); template void to_stream( T& os, const variants& a ); template void to_stream( T& os, const variant_object& o ); @@ -168,7 +167,7 @@ namespace fc ("token", token.str() ) ); } - template + template 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( 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 + template 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(in) ); skip_white_space(in); } if( in.peek() != ']' ) @@ -251,7 +250,7 @@ namespace fc return ar; } - template + template 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 + template 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( in ); case '[': - return arrayFromStream( in ); + return arrayFromStream( 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( in ); // null, true, false, or 'warning' / string case 'n': case 't': @@ -443,7 +442,9 @@ namespace fc switch( ptype ) { case legacy_parser: - return variant_from_stream( in ); + return variant_from_stream( in ); + case legacy_parser_with_string_doubles: + return variant_from_stream( in ); case strict_parser: return json_relaxed::variant_from_stream( in ); case relaxed_parser: @@ -709,7 +710,9 @@ namespace fc switch( ptype ) { case legacy_parser: - return variant_from_stream( bi ); + return variant_from_stream( bi ); + case legacy_parser_with_string_doubles: + return variant_from_stream( bi ); case strict_parser: return json_relaxed::variant_from_stream( bi ); case relaxed_parser: @@ -723,7 +726,9 @@ namespace fc switch( ptype ) { case legacy_parser: - return variant_from_stream( in ); + return variant_from_stream( in ); + case legacy_parser_with_string_doubles: + return variant_from_stream( in ); case strict_parser: return json_relaxed::variant_from_stream( in ); case relaxed_parser: @@ -756,7 +761,10 @@ namespace fc switch( ptype ) { case legacy_parser: - variant_from_stream( in ); + variant_from_stream( in ); + break; + case legacy_parser_with_string_doubles: + variant_from_stream( in ); break; case strict_parser: json_relaxed::variant_from_stream( in ); diff --git a/src/string.cpp b/src/string.cpp index 93b6b7a..0b7cb9f 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -9,6 +9,7 @@ #include #include #include +#include /** * 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(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::digits10 + 2) << std::fixed << d; + return ss.str(); } fc::string to_string( uint64_t d)