From 33215ffb6e588c454fef59b19cce11b4b869cb16 Mon Sep 17 00:00:00 2001 From: Abit Date: Mon, 19 Mar 2018 17:35:57 +0100 Subject: [PATCH] Merge pull request #21 from pmconrad/variant_fix Variant fix --- include/fc/array.hpp | 8 +- include/fc/config.hpp | 5 + include/fc/container/flat.hpp | 33 +- include/fc/crypto/bigint.hpp | 4 +- include/fc/crypto/elliptic.hpp | 8 +- include/fc/crypto/pke.hpp | 8 +- include/fc/crypto/ripemd160.hpp | 4 +- include/fc/crypto/sha1.hpp | 4 +- include/fc/crypto/sha224.hpp | 4 +- include/fc/crypto/sha256.hpp | 4 +- include/fc/crypto/sha512.hpp | 4 +- include/fc/exception/exception.hpp | 8 +- include/fc/filesystem.hpp | 4 +- include/fc/fixed_string.hpp | 24 +- include/fc/interprocess/container.hpp | 66 ++-- include/fc/io/enum_type.hpp | 8 +- include/fc/io/json.hpp | 10 +- include/fc/io/raw.hpp | 9 +- include/fc/io/varint.hpp | 8 +- include/fc/log/console_appender.hpp | 5 +- include/fc/log/file_appender.hpp | 3 +- include/fc/log/gelf_appender.hpp | 3 +- include/fc/log/log_message.hpp | 26 +- include/fc/log/logger.hpp | 3 +- include/fc/network/ip.hpp | 8 +- include/fc/network/url.hpp | 4 +- include/fc/real128.hpp | 4 +- include/fc/reflect/variant.hpp | 61 ++-- include/fc/rpc/api_connection.hpp | 95 ++--- include/fc/rpc/cli.hpp | 1 + include/fc/rpc/http_api.hpp | 2 +- include/fc/rpc/json_connection.hpp | 7 +- include/fc/rpc/websocket_api.hpp | 2 +- include/fc/static_variant.hpp | 21 +- include/fc/string.hpp | 2 +- include/fc/time.hpp | 4 +- include/fc/uint128.hpp | 4 +- include/fc/variant.hpp | 480 ++++++++++++++------------ include/fc/variant_object.hpp | 33 +- src/crypto/bigint.cpp | 12 +- src/crypto/elliptic_common.cpp | 16 +- src/crypto/pke.cpp | 12 +- src/crypto/ripemd160.cpp | 26 +- src/crypto/sha1.cpp | 15 +- src/crypto/sha224.cpp | 25 +- src/crypto/sha256.cpp | 24 +- src/crypto/sha512.cpp | 23 +- src/exception.cpp | 28 +- src/filesystem.cpp | 8 +- src/io/varint.cpp | 8 +- src/log/console_appender.cpp | 11 +- src/log/file_appender.cpp | 8 +- src/log/gelf_appender.cpp | 4 +- src/log/log_message.cpp | 47 +-- src/log/logger_config.cpp | 1 - src/network/ip.cpp | 8 +- src/network/url.cpp | 4 +- src/real128.cpp | 4 +- src/rpc/http_api.cpp | 15 +- src/rpc/json_connection.cpp | 24 +- src/rpc/websocket_api.cpp | 24 +- src/string.cpp | 4 +- src/time.cpp | 16 +- src/uint128.cpp | 30 +- src/variant.cpp | 122 ++++--- src/variant_object.cpp | 23 +- tests/api.cpp | 10 +- tests/crypto/sha_tests.cpp | 4 +- tests/io/json_tests.cpp | 20 +- tests/network/http/websocket_test.cpp | 4 + 70 files changed, 823 insertions(+), 748 deletions(-) diff --git a/include/fc/array.hpp b/include/fc/array.hpp index 8453447..541cd69 100755 --- a/include/fc/array.hpp +++ b/include/fc/array.hpp @@ -102,14 +102,14 @@ namespace fc { { return 0 != memcmp( a.data, b.data, N*sizeof(T) ); } template - void to_variant( const array& bi, variant& v ) + void to_variant( const array& bi, variant& v, uint32_t max_depth = 1 ) { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, 1 ); } template - void from_variant( const variant& v, array& bi ) + void from_variant( const variant& v, array& bi, uint32_t max_depth = 1 ) { - std::vector ve = v.as< std::vector >(); + std::vector ve = v.as< std::vector >( 1 ); if( ve.size() ) { memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); diff --git a/include/fc/config.hpp b/include/fc/config.hpp index 2f646bd..d08eaf1 100644 --- a/include/fc/config.hpp +++ b/include/fc/config.hpp @@ -2,3 +2,8 @@ // The maximum level of object nesting is around 20% of this value #define FC_PACK_MAX_DEPTH 1000 #endif + +#ifndef FC_MAX_LOG_OBJECT_DEPTH + // how many levels of nested objects are displayed in log messages + #define FC_MAX_LOG_OBJECT_DEPTH 200 +#endif \ No newline at end of file diff --git a/include/fc/container/flat.hpp b/include/fc/container/flat.hpp index b323c25..2eca459 100755 --- a/include/fc/container/flat.hpp +++ b/include/fc/container/flat.hpp @@ -99,41 +99,48 @@ namespace fc { template - void to_variant( const flat_set& var, variant& vo ) + void to_variant( const flat_set& var, variant& vo, uint32_t _max_depth ) { + FC_ASSERT( _max_depth > 0 ); + --_max_depth; std::vector vars(var.size()); size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = variant(*itr); + for( const auto& item : var ) + vars[i++] = variant( item, _max_depth ); vo = vars; } template - void from_variant( const variant& var, flat_set& vo ) + void from_variant( const variant& var, flat_set& vo, uint32_t _max_depth ) { + FC_ASSERT( _max_depth > 0 ); + --_max_depth; const variants& vars = var.get_array(); vo.clear(); vo.reserve( vars.size() ); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as() ); + for( const auto& item : vars ) + vo.insert( item.as(_max_depth) ); } template - void to_variant( const flat_map& var, variant& vo ) + void to_variant( const flat_map& var, variant& vo, uint32_t _max_depth ) { + FC_ASSERT( _max_depth > 0 ); + --_max_depth; std::vector< variant > vars(var.size()); size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = fc::variant(*itr); + for( const auto& item : var ) + vars[i++] = variant( item, _max_depth ); vo = vars; } template - void from_variant( const variant& var, flat_map& vo ) + void from_variant( const variant& var, flat_map& vo, uint32_t _max_depth ) { + FC_ASSERT( _max_depth > 0 ); + --_max_depth; const variants& vars = var.get_array(); vo.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as< std::pair >() ); - + for( const auto& item : vars ) + vo.insert( item.as>(_max_depth) ); } } diff --git a/include/fc/crypto/bigint.hpp b/include/fc/crypto/bigint.hpp index b91631a..58703a1 100755 --- a/include/fc/crypto/bigint.hpp +++ b/include/fc/crypto/bigint.hpp @@ -69,8 +69,8 @@ namespace fc { class variant; /** encodes the big int as base64 string, or a number */ - void to_variant( const bigint& bi, variant& v ); + void to_variant( const bigint& bi, variant& v, uint32_t max_depth = 1 ); /** decodes the big int as base64 string, or a number */ - void from_variant( const variant& v, bigint& bi ); + void from_variant( const variant& v, bigint& bi, uint32_t max_depth = 1 ); } // namespace fc diff --git a/include/fc/crypto/elliptic.hpp b/include/fc/crypto/elliptic.hpp index 5491e5c..5218aae 100755 --- a/include/fc/crypto/elliptic.hpp +++ b/include/fc/crypto/elliptic.hpp @@ -230,10 +230,10 @@ namespace fc { } // namespace ecc - void to_variant( const ecc::private_key& var, variant& vo ); - void from_variant( const variant& var, ecc::private_key& vo ); - void to_variant( const ecc::public_key& var, variant& vo ); - void from_variant( const variant& var, ecc::public_key& vo ); + void to_variant( const ecc::private_key& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, ecc::private_key& vo, uint32_t max_depth ); + void to_variant( const ecc::public_key& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, ecc::public_key& vo, uint32_t max_depth ); namespace raw { diff --git a/include/fc/crypto/pke.hpp b/include/fc/crypto/pke.hpp index 551ef99..db33b46 100755 --- a/include/fc/crypto/pke.hpp +++ b/include/fc/crypto/pke.hpp @@ -108,10 +108,10 @@ namespace fc { } } class variant; - void to_variant( const public_key& bi, variant& v ); - void from_variant( const variant& v, public_key& bi ); - void to_variant( const private_key& bi, variant& v ); - void from_variant( const variant& v, private_key& bi ); + void to_variant( const public_key& bi, variant& v, uint32_t max_depth = 1 ); + void from_variant( const variant& v, public_key& bi, uint32_t max_depth = 1 ); + void to_variant( const private_key& bi, variant& v, uint32_t max_depth = 1 ); + void from_variant( const variant& v, private_key& bi, uint32_t max_depth = 1 ); } // fc diff --git a/include/fc/crypto/ripemd160.hpp b/include/fc/crypto/ripemd160.hpp index 912c392..1982e43 100755 --- a/include/fc/crypto/ripemd160.hpp +++ b/include/fc/crypto/ripemd160.hpp @@ -72,8 +72,8 @@ class ripemd160 }; class variant; - void to_variant( const ripemd160& bi, variant& v ); - void from_variant( const variant& v, ripemd160& bi ); + void to_variant( const ripemd160& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, ripemd160& bi, uint32_t max_depth ); typedef ripemd160 uint160_t; typedef ripemd160 uint160; diff --git a/include/fc/crypto/sha1.hpp b/include/fc/crypto/sha1.hpp index 32fc2e4..a269797 100755 --- a/include/fc/crypto/sha1.hpp +++ b/include/fc/crypto/sha1.hpp @@ -66,8 +66,8 @@ class sha1 }; class variant; - void to_variant( const sha1& bi, variant& v ); - void from_variant( const variant& v, sha1& bi ); + void to_variant( const sha1& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, sha1& bi, uint32_t max_depth ); } // namespace fc diff --git a/include/fc/crypto/sha224.hpp b/include/fc/crypto/sha224.hpp index a621208..311e24f 100755 --- a/include/fc/crypto/sha224.hpp +++ b/include/fc/crypto/sha224.hpp @@ -71,8 +71,8 @@ class sha224 }; class variant; - void to_variant( const sha224& bi, variant& v ); - void from_variant( const variant& v, sha224& bi ); + void to_variant( const sha224& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, sha224& bi, uint32_t max_depth ); } // fc namespace std diff --git a/include/fc/crypto/sha256.hpp b/include/fc/crypto/sha256.hpp index 39b436b..5c93c0b 100755 --- a/include/fc/crypto/sha256.hpp +++ b/include/fc/crypto/sha256.hpp @@ -101,8 +101,8 @@ class sha256 typedef sha256 uint256; class variant; - void to_variant( const sha256& bi, variant& v ); - void from_variant( const variant& v, sha256& bi ); + void to_variant( const sha256& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, sha256& bi, uint32_t max_depth ); uint64_t hash64(const char* buf, size_t len); diff --git a/include/fc/crypto/sha512.hpp b/include/fc/crypto/sha512.hpp index ef10887..2f77b21 100755 --- a/include/fc/crypto/sha512.hpp +++ b/include/fc/crypto/sha512.hpp @@ -69,8 +69,8 @@ class sha512 typedef fc::sha512 uint512; class variant; - void to_variant( const sha512& bi, variant& v ); - void from_variant( const variant& v, sha512& bi ); + void to_variant( const sha512& bi, variant& v, uint32_t max_depth ); + void from_variant( const variant& v, sha512& bi, uint32_t max_depth ); } // fc diff --git a/include/fc/exception/exception.hpp b/include/fc/exception/exception.hpp index 6fb66fa..091cc4b 100755 --- a/include/fc/exception/exception.hpp +++ b/include/fc/exception/exception.hpp @@ -116,8 +116,8 @@ namespace fc */ virtual std::shared_ptr dynamic_copy_exception()const; - friend void to_variant( const exception& e, variant& v ); - friend void from_variant( const variant& e, exception& ll ); + friend void to_variant( const exception& e, variant& v, uint32_t max_depth ); + friend void from_variant( const variant& e, exception& ll, uint32_t max_depth ); exception& operator=( const exception& copy ); exception& operator=( exception&& copy ); @@ -125,8 +125,8 @@ namespace fc std::unique_ptr my; }; - void to_variant( const exception& e, variant& v ); - void from_variant( const variant& e, exception& ll ); + void to_variant( const exception& e, variant& v, uint32_t max_depth ); + void from_variant( const variant& e, exception& ll, uint32_t max_depth ); typedef std::shared_ptr exception_ptr; typedef optional oexception; diff --git a/include/fc/filesystem.hpp b/include/fc/filesystem.hpp index 7484f2a..38fb74a 100755 --- a/include/fc/filesystem.hpp +++ b/include/fc/filesystem.hpp @@ -182,8 +182,8 @@ namespace fc { const fc::path& current_path(); class variant; - void to_variant( const fc::path&, fc::variant& ); - void from_variant( const fc::variant& , fc::path& ); + void to_variant( const fc::path&, fc::variant&, uint32_t max_depth = 1 ); + void from_variant( const fc::variant&, fc::path&, uint32_t max_depth = 1 ); template<> struct get_typename { static const char* name() { return "path"; } }; diff --git a/include/fc/fixed_string.hpp b/include/fc/fixed_string.hpp index ce00390..a91b651 100755 --- a/include/fc/fixed_string.hpp +++ b/include/fc/fixed_string.hpp @@ -121,43 +121,23 @@ namespace fc { left -= 1024; } s.read( buf, left ); - - /* - s.seekp( s.tellp() + (size.value - sizeof(Storage)) ); - char tmp; - size.value -= sizeof(storage); - while( size.value ){ s.read( &tmp, 1 ); --size.value; } - */ - // s.skip( size.value - sizeof(Storage) ); } else { s.read( (char*)&u.data, size.value ); } } } - - /* - template - inline void pack( Stream& s, const boost::multiprecision::number& d, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { - s.write( (const char*)&d, sizeof(d) ); - } - - template - inline void unpack( Stream& s, boost::multiprecision::number& u, uint32_t _max_depth=FC_PACK_MAX_DEPTH ) { - s.read( (const char*)&u, sizeof(u) ); - } - */ } } #include namespace fc { template - void to_variant( const fixed_string& s, variant& v ) { + void to_variant( const fixed_string& s, variant& v, uint32_t max_depth = 1 ) { v = std::string(s); } template - void from_variant( const variant& v, fixed_string& s ) { + void from_variant( const variant& v, fixed_string& s, uint32_t max_depth = 1 ) { s = v.as_string(); } } diff --git a/include/fc/interprocess/container.hpp b/include/fc/interprocess/container.hpp index f61a68c..7ede74b 100755 --- a/include/fc/interprocess/container.hpp +++ b/include/fc/interprocess/container.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace fc { @@ -16,87 +17,76 @@ namespace fc { namespace bip = boost::interprocess; template - void to_variant( const bip::deque< T... >& t, fc::variant& v ) { + void to_variant( const bip::deque< T... >& t, fc::variant& v, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + --max_depth; std::vector vars(t.size()); for( size_t i = 0; i < t.size(); ++i ) { - vars[i] = t[i]; + to_variant( t[i], vars[i], max_depth ); } v = std::move(vars); } template - void from_variant( const fc::variant& v, bip::deque< T, A... >& d ) { + void from_variant( const fc::variant& v, bip::deque< T, A... >& d, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + --max_depth; const variants& vars = v.get_array(); d.clear(); d.resize( vars.size() ); for( uint32_t i = 0; i < vars.size(); ++i ) { - from_variant( vars[i], d[i] ); + from_variant( vars[i], d[i], max_depth ); } } - //bip::map == boost::map template - void to_variant( const bip::map< K, V, T... >& var, fc::variant& vo ) { + void to_variant( const bip::map< K, V, T... >& var, fc::variant& vo, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + --max_depth; std::vector< variant > vars(var.size()); size_t i = 0; for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = fc::variant(*itr); + vars[i] = fc::variant( *itr, max_depth ); vo = vars; } -/* - template - void from_variant( const variant& var, bip::map& vo ) - { - const variants& vars = var.get_array(); - vo.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as< std::pair >() ); Not safe for interprocess. Needs allocator - } -*/ template - void to_variant( const bip::vector< T... >& t, fc::variant& v ) { + void to_variant( const bip::vector< T... >& t, fc::variant& v, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + --max_depth; std::vector vars(t.size()); for( size_t i = 0; i < t.size(); ++i ) { - vars[i] = t[i]; + to_variant( t[i], vars[i], max_depth ); } v = std::move(vars); } template - void from_variant( const fc::variant& v, bip::vector< T, A... >& d ) { + void from_variant( const fc::variant& v, bip::vector< T, A... >& d, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + --max_depth; const variants& vars = v.get_array(); d.clear(); d.resize( vars.size() ); for( uint32_t i = 0; i < vars.size(); ++i ) { - from_variant( vars[i], d[i] ); + from_variant( vars[i], d[i], max_depth ); } } template - void to_variant( const bip::set< T... >& t, fc::variant& v ) { + void to_variant( const bip::set< T... >& t, fc::variant& v, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + --max_depth; std::vector vars; vars.reserve(t.size()); for( const auto& item : t ) { - vars.emplace_back( item ); + vars.emplace_back( variant( item, max_depth ) ); } v = std::move(vars); } -/* - template - void from_variant( const fc::variant& v, bip::set< T, A... >& d ) { - const variants& vars = v.get_array(); - d.clear(); - d.reserve( vars.size() ); - for( uint32_t i = 0; i < vars.size(); ++i ) { - from_variant( vars[i], d[i] ); Not safe for interprocess. Needs allocator - } - } -*/ - template - void to_variant( const bip::vector& t, fc::variant& v ) + void to_variant( const bip::vector& t, fc::variant& v, uint32_t max_depth = 1 ) { if( t.size() ) v = variant(fc::to_hex(t.data(), t.size())); @@ -105,7 +95,7 @@ namespace fc { } template - void from_variant( const fc::variant& v, bip::vector& d ) + void from_variant( const fc::variant& v, bip::vector& d, uint32_t max_depth = 1 ) { auto str = v.as_string(); d.resize( str.size() / 2 ); @@ -114,8 +104,6 @@ namespace fc { size_t r = fc::from_hex( str, d.data(), d.size() ); FC_ASSERT( r == d.size() ); } - // std::string b64 = base64_decode( var.as_string() ); - // vo = std::vector( b64.c_str(), b64.c_str() + b64.size() ); } namespace raw { diff --git a/include/fc/io/enum_type.hpp b/include/fc/io/enum_type.hpp index 46da877..0d35c4b 100755 --- a/include/fc/io/enum_type.hpp +++ b/include/fc/io/enum_type.hpp @@ -48,14 +48,14 @@ namespace fc template - void to_variant( const enum_type& var, variant& vo ) + void to_variant( const enum_type& var, variant& vo, uint32_t max_depth = 1 ) { - vo = (EnumType)var.value; + to_variant( var.value, vo, max_depth ); } template - void from_variant( const variant& var, enum_type& vo ) + void from_variant( const variant& var, enum_type& vo, uint32_t max_depth ) { - vo.value = var.as(); + vo.value = var.as(1); } diff --git a/include/fc/io/json.hpp b/include/fc/io/json.hpp index 21d07c4..1980f74 100755 --- a/include/fc/io/json.hpp +++ b/include/fc/io/json.hpp @@ -52,7 +52,7 @@ namespace fc template static void save_to_file( const T& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - save_to_file( variant(v), fi, pretty, format, max_depth ); + save_to_file( variant(v, max_depth), fi, pretty, format, max_depth ); } static void save_to_file( const variant& v, const fc::path& fi, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ); @@ -61,25 +61,25 @@ namespace fc template static T from_file( const fc::path& p, parse_type ptype = legacy_parser, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - return json::from_file(p, ptype, max_depth).as(); + return json::from_file(p, ptype, max_depth).as(max_depth); } template static string to_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - return to_string( variant(v), format, max_depth ); + return to_string( variant(v, max_depth), format, max_depth ); } template static string to_pretty_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - return to_pretty_string( variant(v), format, max_depth ); + return to_pretty_string( variant(v, max_depth), format, max_depth ); } template static void save_to_file( const T& v, const std::string& p, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH ) { - save_to_file( variant(v), fc::path(p), pretty, format, max_depth ); + save_to_file( variant(v, max_depth), fc::path(p), pretty, format, max_depth ); } }; diff --git a/include/fc/io/raw.hpp b/include/fc/io/raw.hpp index 98f21d8..2125865 100755 --- a/include/fc/io/raw.hpp +++ b/include/fc/io/raw.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -57,15 +58,17 @@ namespace fc { inline void pack( Stream& s, const fc::log_message& msg, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); - fc::raw::pack( s, variant(msg), _max_depth - 1 ); // TODO check variant depth? + --_max_depth; + fc::raw::pack( s, variant( msg, std::min( _max_depth, uint32_t(FC_MAX_LOG_OBJECT_DEPTH) ) ), _max_depth ); } template inline void unpack( Stream& s, fc::log_message& msg, uint32_t _max_depth ) { FC_ASSERT( _max_depth > 0 ); fc::variant vmsg; - fc::raw::unpack( s, vmsg, _max_depth - 1 ); - msg = vmsg.as(); // TODO check depth? + --_max_depth; + fc::raw::unpack( s, vmsg, _max_depth ); + msg = vmsg.as( std::min( _max_depth, uint32_t(FC_MAX_LOG_OBJECT_DEPTH) ) ); } template diff --git a/include/fc/io/varint.hpp b/include/fc/io/varint.hpp index b4988c5..00a8023 100755 --- a/include/fc/io/varint.hpp +++ b/include/fc/io/varint.hpp @@ -70,10 +70,10 @@ struct signed_int { class variant; -void to_variant( const signed_int& var, variant& vo ); -void from_variant( const variant& var, signed_int& vo ); -void to_variant( const unsigned_int& var, variant& vo ); -void from_variant( const variant& var, unsigned_int& vo ); +void to_variant( const signed_int& var, variant& vo, uint32_t max_depth = 1 ); +void from_variant( const variant& var, signed_int& vo, uint32_t max_depth = 1 ); +void to_variant( const unsigned_int& var, variant& vo, uint32_t max_depth = 1 ); +void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth = 1 ); } // namespace fc diff --git a/include/fc/log/console_appender.hpp b/include/fc/log/console_appender.hpp index c15fcf0..4048da6 100755 --- a/include/fc/log/console_appender.hpp +++ b/include/fc/log/console_appender.hpp @@ -38,11 +38,12 @@ namespace fc { config() :format( "${timestamp} ${thread_name} ${context} ${file}:${line} ${method} ${level}] ${message}" ), - stream(console_appender::stream::std_error),flush(true){} + stream(console_appender::stream::std_error),max_object_depth(FC_MAX_LOG_OBJECT_DEPTH),flush(true){} fc::string format; console_appender::stream::type stream; std::vector level_colors; + uint32_t max_object_depth; bool flush; }; @@ -69,4 +70,4 @@ namespace fc FC_REFLECT_ENUM( fc::console_appender::stream::type, (std_out)(std_error) ) FC_REFLECT_ENUM( fc::console_appender::color::type, (red)(green)(brown)(blue)(magenta)(cyan)(white)(console_default) ) FC_REFLECT( fc::console_appender::level_color, (level)(color) ) -FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(flush) ) +FC_REFLECT( fc::console_appender::config, (format)(stream)(level_colors)(max_object_depth)(flush) ) diff --git a/include/fc/log/file_appender.hpp b/include/fc/log/file_appender.hpp index 70a6e0a..4ffa146 100755 --- a/include/fc/log/file_appender.hpp +++ b/include/fc/log/file_appender.hpp @@ -19,6 +19,7 @@ class file_appender : public appender { microseconds rotation_interval; microseconds rotation_limit; bool rotation_compression = false; + uint32_t max_object_depth; }; file_appender( const variant& args ); ~file_appender(); @@ -32,4 +33,4 @@ class file_appender : public appender { #include FC_REFLECT( fc::file_appender::config, - (format)(filename)(flush)(rotate)(rotation_interval)(rotation_limit)(rotation_compression) ) + (format)(filename)(flush)(rotate)(rotation_interval)(rotation_limit)(rotation_compression)(max_object_depth) ) diff --git a/include/fc/log/gelf_appender.hpp b/include/fc/log/gelf_appender.hpp index 2228313..ba81c3d 100755 --- a/include/fc/log/gelf_appender.hpp +++ b/include/fc/log/gelf_appender.hpp @@ -15,6 +15,7 @@ namespace fc { string endpoint = "127.0.0.1:12201"; string host = "fc"; // the name of the host, source or application that sent this message (just passed through to GELF server) + uint32_t max_object_depth; }; gelf_appender(const variant& args); @@ -29,4 +30,4 @@ namespace fc #include FC_REFLECT(fc::gelf_appender::config, - (endpoint)(host)) + (endpoint)(host)(max_object_depth)) diff --git a/include/fc/log/log_message.hpp b/include/fc/log/log_message.hpp index c17c0e6..06bd59f 100755 --- a/include/fc/log/log_message.hpp +++ b/include/fc/log/log_message.hpp @@ -3,6 +3,7 @@ * @file log_message.hpp * @brief Defines types and helper macros necessary for generating log messages. */ +#include #include #include #include @@ -51,8 +52,8 @@ namespace fc values value; }; - void to_variant( log_level e, variant& v ); - void from_variant( const variant& e, log_level& ll ); + void to_variant( log_level e, variant& v, uint32_t max_depth = 1 ); + void from_variant( const variant& e, log_level& ll, uint32_t max_depth = 1 ); /** * @brief provides information about where and when a log message was generated. @@ -69,8 +70,8 @@ namespace fc uint64_t line, const char* method ); ~log_context(); - explicit log_context( const variant& v ); - variant to_variant()const; + explicit log_context( const variant& v, uint32_t max_depth ); + variant to_variant( uint32_t max_depth )const; string get_file()const; uint64_t get_line_number()const; @@ -89,8 +90,8 @@ namespace fc std::shared_ptr my; }; - void to_variant( const log_context& l, variant& v ); - void from_variant( const variant& l, log_context& c ); + void to_variant( const log_context& l, variant& v, uint32_t max_depth ); + void from_variant( const variant& l, log_context& c, uint32_t max_depth ); /** * @brief aggregates a message along with the context and associated meta-information. @@ -120,8 +121,8 @@ namespace fc log_message( log_context ctx, std::string format, variant_object args = variant_object() ); ~log_message(); - log_message( const variant& v ); - variant to_variant()const; + log_message( const variant& v, uint32_t max_depth ); + variant to_variant(uint32_t max_depth)const; string get_message()const; @@ -133,8 +134,8 @@ namespace fc std::shared_ptr my; }; - void to_variant( const log_message& l, variant& v ); - void from_variant( const variant& l, log_message& c ); + void to_variant( const log_message& l, variant& v, uint32_t max_depth ); + void from_variant( const variant& l, log_message& c, uint32_t max_depth ); typedef std::vector log_messages; @@ -165,8 +166,8 @@ FC_REFLECT_TYPENAME( fc::log_message ); * @param FORMAT A const char* string containing zero or more references to keys as "${key}" * @param ... A set of key/value pairs denoted as ("key",val)("key2",val2)... */ -#define FC_LOG_MESSAGE_GENERATE_PARAMETER_NAME(VALUE) BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(VALUE), fc::variant(VALUE) BOOST_PP_RPAREN() -#define FC_LOG_MESSAGE_DONT_GENERATE_PARAMETER_NAME(NAME, VALUE) BOOST_PP_LPAREN() NAME, fc::variant(VALUE) BOOST_PP_RPAREN() +#define FC_LOG_MESSAGE_GENERATE_PARAMETER_NAME(VALUE) BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(VALUE), fc::variant(VALUE, FC_MAX_LOG_OBJECT_DEPTH) BOOST_PP_RPAREN() +#define FC_LOG_MESSAGE_DONT_GENERATE_PARAMETER_NAME(NAME, VALUE) BOOST_PP_LPAREN() NAME, fc::variant(VALUE, FC_MAX_LOG_OBJECT_DEPTH) BOOST_PP_RPAREN() #define FC_LOG_MESSAGE_GENERATE_PARAMETER_NAMES_IF_NEEDED(r, data, PARAMETER_AND_MAYBE_NAME) BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE PARAMETER_AND_MAYBE_NAME,1),FC_LOG_MESSAGE_GENERATE_PARAMETER_NAME,FC_LOG_MESSAGE_DONT_GENERATE_PARAMETER_NAME)PARAMETER_AND_MAYBE_NAME #define FC_LOG_MESSAGE_STRING_ONLY(LOG_LEVEL, FORMAT) \ @@ -174,6 +175,5 @@ FC_REFLECT_TYPENAME( fc::log_message ); #define FC_LOG_MESSAGE_WITH_SUBSTITUTIONS(LOG_LEVEL, FORMAT, ...) \ fc::log_message(FC_LOG_CONTEXT(LOG_LEVEL), FORMAT, fc::mutable_variant_object() BOOST_PP_SEQ_FOR_EACH(FC_LOG_MESSAGE_GENERATE_PARAMETER_NAMES_IF_NEEDED, _, BOOST_PP_VARIADIC_SEQ_TO_SEQ(__VA_ARGS__))) - #define FC_LOG_MESSAGE(LOG_LEVEL, ...) \ BOOST_PP_EXPAND(BOOST_PP_IF(BOOST_PP_EQUAL(BOOST_PP_VARIADIC_SIZE(__VA_ARGS__),1),FC_LOG_MESSAGE_STRING_ONLY,FC_LOG_MESSAGE_WITH_SUBSTITUTIONS)(LOG_LEVEL,__VA_ARGS__)) diff --git a/include/fc/log/logger.hpp b/include/fc/log/logger.hpp index a0e85b3..fa5369e 100755 --- a/include/fc/log/logger.hpp +++ b/include/fc/log/logger.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -145,7 +146,7 @@ namespace fc BOOST_PP_STRINGIZE(base) ": ${" BOOST_PP_STRINGIZE( base ) "} " #define FC_FORMAT_ARGS(r, unused, base) \ - BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(base),fc::variant(base) BOOST_PP_RPAREN() + BOOST_PP_LPAREN() BOOST_PP_STRINGIZE(base),fc::variant(base,FC_MAX_LOG_OBJECT_DEPTH) BOOST_PP_RPAREN() #define FC_FORMAT( SEQ )\ BOOST_PP_SEQ_FOR_EACH( FC_FORMAT_ARG, v, SEQ ) diff --git a/include/fc/network/ip.hpp b/include/fc/network/ip.hpp index 04c5030..7a55616 100755 --- a/include/fc/network/ip.hpp +++ b/include/fc/network/ip.hpp @@ -73,11 +73,11 @@ namespace fc { } class variant; - void to_variant( const ip::endpoint& var, variant& vo ); - void from_variant( const variant& var, ip::endpoint& vo ); + void to_variant( const ip::endpoint& var, variant& vo, uint32_t _max_depth = 2 ); + void from_variant( const variant& var, ip::endpoint& vo, uint32_t _max_depth = 2 ); - void to_variant( const ip::address& var, variant& vo ); - void from_variant( const variant& var, ip::address& vo ); + void to_variant( const ip::address& var, variant& vo, uint32_t _max_depth = 1 ); + void from_variant( const variant& var, ip::address& vo, uint32_t _max_depth = 1 ); namespace raw diff --git a/include/fc/network/url.hpp b/include/fc/network/url.hpp index 4d6066c..9d59d70 100755 --- a/include/fc/network/url.hpp +++ b/include/fc/network/url.hpp @@ -56,8 +56,8 @@ namespace fc { std::shared_ptr my; }; - void to_variant( const url& u, fc::variant& v ); - void from_variant( const fc::variant& v, url& u ); + void to_variant( const url& u, fc::variant& v, uint32_t max_depth = 1 ); + void from_variant( const fc::variant& v, url& u, uint32_t max_depth = 1 ); /** * Used to create / manipulate a URL diff --git a/include/fc/real128.hpp b/include/fc/real128.hpp index 142f5ec..e445ab6 100755 --- a/include/fc/real128.hpp +++ b/include/fc/real128.hpp @@ -36,8 +36,8 @@ namespace fc { uint128 fixed; }; - void to_variant( const real128& var, variant& vo ); - void from_variant( const variant& var, real128& vo ); + void to_variant( const real128& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, real128& vo, uint32_t max_depth = 1 ); namespace raw { diff --git a/include/fc/reflect/variant.hpp b/include/fc/reflect/variant.hpp index 31bbbdf..60dcea8 100755 --- a/include/fc/reflect/variant.hpp +++ b/include/fc/reflect/variant.hpp @@ -5,17 +5,19 @@ namespace fc { template - void to_variant( const T& o, variant& v ); + void to_variant( const T& o, variant& v, uint32_t max_depth ); template - void from_variant( const variant& v, T& o ); + void from_variant( const variant& v, T& o, uint32_t max_depth ); template class to_variant_visitor { public: - to_variant_visitor( mutable_variant_object& mvo, const T& v ) - :vo(mvo),val(v){} + to_variant_visitor( mutable_variant_object& mvo, const T& v, uint32_t max_depth ) + :vo(mvo),val(v),_max_depth(max_depth - 1) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + } template void operator()( const char* name )const @@ -28,63 +30,67 @@ namespace fc void add( mutable_variant_object& vo, const char* name, const optional& v )const { if( v.valid() ) - vo(name,*v); + vo(name, variant( *v, _max_depth )); } template void add( mutable_variant_object& vo, const char* name, const M& v )const - { vo(name,v); } + { vo(name, variant( v, _max_depth )); } mutable_variant_object& vo; const T& val; + const uint32_t _max_depth; }; template class from_variant_visitor { public: - from_variant_visitor( const variant_object& _vo, T& v ) - :vo(_vo),val(v){} + from_variant_visitor( const variant_object& _vo, T& v, uint32_t max_depth ) + :vo(_vo),val(v),_max_depth(max_depth - 1) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + } template void operator()( const char* name )const { auto itr = vo.find(name); if( itr != vo.end() ) - from_variant( itr->value(), val.*member ); + from_variant( itr->value(), val.*member, _max_depth ); } const variant_object& vo; T& val; + const uint32_t _max_depth; }; - template - struct if_enum + template + struct if_enum { - template - static inline void to_variant( const T& v, fc::variant& vo ) - { + template + static inline void to_variant( const T& v, fc::variant& vo, uint32_t max_depth ) + { mutable_variant_object mvo; - fc::reflector::visit( to_variant_visitor( mvo, v ) ); + fc::reflector::visit( to_variant_visitor( mvo, v, max_depth ) ); vo = fc::move(mvo); - } - template - static inline void from_variant( const fc::variant& v, T& o ) - { + } + template + static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth ) + { const variant_object& vo = v.get_object(); - fc::reflector::visit( from_variant_visitor( vo, o ) ); - } + fc::reflector::visit( from_variant_visitor( vo, o, max_depth ) ); + } }; template<> struct if_enum { template - static inline void to_variant( const T& o, fc::variant& v ) + static inline void to_variant( const T& o, fc::variant& v, uint32_t max_depth = 1 ) { v = fc::reflector::to_fc_string(o); } template - static inline void from_variant( const fc::variant& v, T& o ) + static inline void from_variant( const fc::variant& v, T& o, uint32_t max_depth = 1 ) { if( v.is_string() ) o = fc::reflector::from_string( v.get_string().c_str() ); @@ -95,15 +101,14 @@ namespace fc template - void to_variant( const T& o, variant& v ) + void to_variant( const T& o, variant& v, uint32_t max_depth ) { - if_enum::is_enum>::to_variant( o, v ); + if_enum::is_enum>::to_variant( o, v, max_depth ); } template - void from_variant( const variant& v, T& o ) + void from_variant( const variant& v, T& o, uint32_t max_depth ) { - if_enum::is_enum>::from_variant( v, o ); + if_enum::is_enum>::from_variant( v, o, max_depth ); } - } diff --git a/include/fc/rpc/api_connection.hpp b/include/fc/rpc/api_connection.hpp index 1cd5561..1345c45 100755 --- a/include/fc/rpc/api_connection.hpp +++ b/include/fc/rpc/api_connection.hpp @@ -8,7 +8,6 @@ #include #include #include -//#include namespace fc { class api_connection; @@ -37,31 +36,34 @@ namespace fc { return [=]( Args... args ) { return f( a0, args... ); }; } template - R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e ) + R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth = 1 ) { return f(); } template - R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e ) + R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth ) { FC_ASSERT( a0 != e ); - return call_generic( bind_first_arg( f, a0->as< typename std::decay::type >() ), a0+1, e ); + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + return call_generic( bind_first_arg( f, a0->as< typename std::decay::type >( max_depth - 1 ) ), a0+1, e, max_depth - 1 ); } template - std::function to_generic( const std::function& f ) + std::function to_generic( const std::function& f ) { - return [=]( const variants& args ) { - return variant( call_generic( f, args.begin(), args.end() ) ); + return [=]( const variants& args, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + return variant( call_generic( f, args.begin(), args.end(), max_depth - 1 ), max_depth - 1 ); }; } template - std::function to_generic( const std::function& f ) + std::function to_generic( const std::function& f ) { - return [=]( const variants& args ) { - call_generic( f, args.begin(), args.end() ); + return [=]( const variants& args, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + call_generic( f, args.begin(), args.end(), max_depth - 1 ); return variant(); }; } @@ -139,31 +141,34 @@ namespace fc { } template - R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e )const + R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth = 1 )const { return f(); } template - R call_generic( const std::function,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) + R call_generic( const std::function,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth ) { FC_ASSERT( a0 != e, "too few arguments passed to method" ); - detail::callback_functor arg0( get_connection(), a0->as() ); - return call_generic( this->bind_first_arg,Args...>( f, std::function(arg0) ), a0+1, e ); + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + detail::callback_functor arg0( get_connection(), a0->as(1) ); + return call_generic( this->bind_first_arg,Args...>( f, std::function(arg0) ), a0+1, e, max_depth - 1 ); } template - R call_generic( const std::function&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e ) + R call_generic( const std::function&,Args...)>& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth ) { FC_ASSERT( a0 != e, "too few arguments passed to method" ); - detail::callback_functor arg0( get_connection(), a0->as() ); - return call_generic( this->bind_first_arg&,Args...>( f, arg0 ), a0+1, e ); + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + detail::callback_functor arg0( get_connection(), a0->as(1) ); + return call_generic( this->bind_first_arg&,Args...>( f, arg0 ), a0+1, e, max_depth - 1 ); } template - R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e ) + R call_generic( const std::function& f, variants::const_iterator a0, variants::const_iterator e, uint32_t max_depth ) { FC_ASSERT( a0 != e, "too few arguments passed to method" ); - return call_generic( this->bind_first_arg( f, a0->as< typename std::decay::type >() ), a0+1, e ); + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + return call_generic( this->bind_first_arg( f, a0->as< typename std::decay::type >( max_depth - 1 ) ), a0+1, e, max_depth - 1 ); } struct api_visitor @@ -207,7 +212,7 @@ namespace fc { class api_connection : public std::enable_shared_from_this { public: - api_connection(){} + api_connection(uint32_t max_depth):_max_conversion_depth(max_depth){} virtual ~api_connection(){}; @@ -232,12 +237,12 @@ namespace fc { variant receive_callback( uint64_t callback_id, const variants& args = variants() )const { FC_ASSERT( _local_callbacks.size() > callback_id ); - return _local_callbacks[callback_id]( args ); + return _local_callbacks[callback_id]( args, _max_conversion_depth ); } void receive_notice( uint64_t callback_id, const variants& args = variants() )const { FC_ASSERT( _local_callbacks.size() > callback_id ); - _local_callbacks[callback_id]( args ); + _local_callbacks[callback_id]( args, _max_conversion_depth ); } template @@ -262,10 +267,11 @@ namespace fc { std::vector get_method_names( api_id_type local_api_id = 0 )const { return _local_apis[local_api_id]->get_method_names(); } fc::signal closed; + const uint32_t _max_conversion_depth; // for nested structures, json, variant etc. private: - std::vector< std::unique_ptr > _local_apis; - std::map< uint64_t, api_id_type > _handle_to_id; - std::vector< std::function > _local_callbacks; + std::vector< std::unique_ptr > _local_apis; + std::map< uint64_t, api_id_type > _handle_to_id; + std::vector< std::function > _local_callbacks; struct api_visitor @@ -281,15 +287,16 @@ namespace fc { api_visitor() = delete; template - static Result from_variant( const variant& v, Result*, const std::shared_ptr& ) + static Result from_variant( const variant& v, Result*, const std::shared_ptr&, uint32_t max_depth ) { - return v.as(); + return v.as( max_depth ); } template static fc::api from_variant( const variant& v, fc::api* /*used for template deduction*/, - const std::shared_ptr& con + const std::shared_ptr& con, + uint32_t max_depth = 1 ) { return con->get_remote_api( v.as_uint64() ); @@ -298,7 +305,8 @@ namespace fc { static fc::api_ptr from_variant( const variant& v, fc::api_ptr* /* used for template deduction */, - const std::shared_ptr& con + const std::shared_ptr& con, + uint32_t max_depth = 1 ) { if( v.is_null() ) @@ -307,9 +315,9 @@ namespace fc { } template - static fc::variant convert_callbacks( const std::shared_ptr&, const T& v ) + static fc::variant convert_callbacks( const std::shared_ptr& con, const T& v ) { - return fc::variant(v); + return fc::variant( v, con->_max_conversion_depth ); } template @@ -325,7 +333,7 @@ namespace fc { auto api_id = _api_id; memb = [con,api_id,name]( Args... args ) { auto var_result = con->send_call( api_id, name, { convert_callbacks(con,args)...} ); - return from_variant( var_result, (Result*)nullptr, con ); + return from_variant( var_result, (Result*)nullptr, con, con->_max_conversion_depth ); }; } template @@ -343,6 +351,9 @@ namespace fc { class local_api_connection : public api_connection { public: + local_api_connection( uint32_t max_depth ) : api_connection(max_depth){} + ~local_api_connection(){} + /** makes calls to the remote server */ virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() ) override { @@ -389,7 +400,7 @@ namespace fc { auto con = api_con.lock(); FC_ASSERT( con, "not connected" ); - auto api_result = gapi->call_generic( f, args.begin(), args.end() ); + auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth ); return con->register_api( api_result ); }; } @@ -403,7 +414,7 @@ namespace fc { auto con = api_con.lock(); FC_ASSERT( con, "not connected" ); - auto api_result = gapi->call_generic( f, args.begin(), args.end() ); + auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth ); if( api_result ) return con->register_api( *api_result ); return variant(); @@ -420,7 +431,7 @@ namespace fc { auto con = api_con.lock(); FC_ASSERT( con, "not connected" ); - auto api_result = gapi->call_generic( f, args.begin(), args.end() ); + auto api_result = gapi->call_generic( f, args.begin(), args.end(), con->_max_conversion_depth ); if( !api_result ) return variant(); return api_result->register_api( *con ); @@ -430,18 +441,24 @@ namespace fc { template std::function generic_api::api_visitor::to_generic( const std::function& f )const { + auto con = _api_con.lock(); + FC_ASSERT( con, "not connected" ); + uint32_t max_depth = con->_max_conversion_depth; generic_api* gapi = &_api; - return [f,gapi]( const variants& args ) { - return variant( gapi->call_generic( f, args.begin(), args.end() ) ); + return [f,gapi,max_depth]( const variants& args ) { + return variant( gapi->call_generic( f, args.begin(), args.end(), max_depth ), max_depth ); }; } template std::function generic_api::api_visitor::to_generic( const std::function& f )const { + auto con = _api_con.lock(); + FC_ASSERT( con, "not connected" ); + uint32_t max_depth = con->_max_conversion_depth; generic_api* gapi = &_api; - return [f,gapi]( const variants& args ) { - gapi->call_generic( f, args.begin(), args.end() ); + return [f,gapi,max_depth]( const variants& args ) { + gapi->call_generic( f, args.begin(), args.end(), max_depth ); return variant(); }; } diff --git a/include/fc/rpc/cli.hpp b/include/fc/rpc/cli.hpp index bb4975f..6670a14 100755 --- a/include/fc/rpc/cli.hpp +++ b/include/fc/rpc/cli.hpp @@ -16,6 +16,7 @@ namespace fc { namespace rpc { class cli : public api_connection { public: + cli( uint32_t max_depth ) : api_connection(max_depth) {} ~cli(); virtual variant send_call( api_id_type api_id, string method_name, variants args = variants() ); diff --git a/include/fc/rpc/http_api.hpp b/include/fc/rpc/http_api.hpp index 47eb289..a693655 100755 --- a/include/fc/rpc/http_api.hpp +++ b/include/fc/rpc/http_api.hpp @@ -11,7 +11,7 @@ namespace fc { namespace rpc { class http_api_connection : public api_connection { public: - http_api_connection(); + http_api_connection(uint32_t max_conversion_depth); ~http_api_connection(); virtual variant send_call( diff --git a/include/fc/rpc/json_connection.hpp b/include/fc/rpc/json_connection.hpp index 04cd041..af76e89 100755 --- a/include/fc/rpc/json_connection.hpp +++ b/include/fc/rpc/json_connection.hpp @@ -21,7 +21,7 @@ namespace fc { namespace rpc { typedef std::function method; typedef std::function named_param_method; - json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out ); + json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out, uint32_t max_depth ); ~json_connection(); /** @@ -303,7 +303,10 @@ namespace fc { namespace rpc { /// Sending in a variant_object will be issued as named parameters variant call( const fc::string& method, const variant_object& named_args ); ///@} - + + protected: + const uint32_t _max_conversion_depth; // for nested structures, json, variant etc. + private: std::unique_ptr my; }; diff --git a/include/fc/rpc/websocket_api.hpp b/include/fc/rpc/websocket_api.hpp index 92d7f2e..ebb6fe7 100755 --- a/include/fc/rpc/websocket_api.hpp +++ b/include/fc/rpc/websocket_api.hpp @@ -10,7 +10,7 @@ namespace fc { namespace rpc { class websocket_api_connection : public api_connection { public: - websocket_api_connection( fc::http::websocket_connection& c ); + websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_conversion_depth ); ~websocket_api_connection(); virtual variant send_call( diff --git a/include/fc/static_variant.hpp b/include/fc/static_variant.hpp index d6206c2..ed8c66f 100755 --- a/include/fc/static_variant.hpp +++ b/include/fc/static_variant.hpp @@ -344,42 +344,45 @@ struct visitor { struct from_static_variant { variant& var; - from_static_variant( variant& dv ):var(dv){} + const uint32_t _max_depth; + from_static_variant( variant& dv, uint32_t max_depth ):var(dv),_max_depth(max_depth){} typedef void result_type; template void operator()( const T& v )const { - to_variant( v, var ); + to_variant( v, var, _max_depth ); } }; struct to_static_variant { const variant& var; - to_static_variant( const variant& dv ):var(dv){} + const uint32_t _max_depth; + to_static_variant( const variant& dv, uint32_t max_depth ):var(dv),_max_depth(max_depth){} typedef void result_type; template void operator()( T& v )const { - from_variant( var, v ); + from_variant( var, v, _max_depth ); } }; - template void to_variant( const fc::static_variant& s, fc::variant& v ) + template void to_variant( const fc::static_variant& s, fc::variant& v, uint32_t max_depth ) { - variant tmp; + FC_ASSERT( max_depth > 0 ); variants vars(2); vars[0] = s.which(); - s.visit( from_static_variant(vars[1]) ); + s.visit( from_static_variant(vars[1], max_depth - 1) ); v = std::move(vars); } - template void from_variant( const fc::variant& v, fc::static_variant& s ) + template void from_variant( const fc::variant& v, fc::static_variant& s, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0 ); auto ar = v.get_array(); if( ar.size() < 2 ) return; s.set_which( ar[0].as_uint64() ); - s.visit( to_static_variant(ar[1]) ); + s.visit( to_static_variant(ar[1], max_depth - 1) ); } template struct get_typename { static const char* name() { return typeid(static_variant).name(); } }; diff --git a/include/fc/string.hpp b/include/fc/string.hpp index dc942b9..13e10da 100755 --- a/include/fc/string.hpp +++ b/include/fc/string.hpp @@ -25,7 +25,7 @@ namespace fc typedef fc::optional ostring; class variant_object; - fc::string format_string( const fc::string&, const variant_object& ); + fc::string format_string( const fc::string&, const variant_object&, uint32_t max_object_depth = 200 ); fc::string trim( const fc::string& ); fc::string to_lower( const fc::string& ); string trim_and_normalize_spaces( const string& s ); diff --git a/include/fc/time.hpp b/include/fc/time.hpp index 11aa96d..c78c0f3 100755 --- a/include/fc/time.hpp +++ b/include/fc/time.hpp @@ -38,8 +38,8 @@ namespace fc { inline microseconds days(int64_t d) { return hours(24*d); } class variant; - void to_variant( const fc::microseconds&, fc::variant& ); - void from_variant( const fc::variant& , fc::microseconds& ); + void to_variant( const fc::microseconds&, fc::variant&, uint32_t max_depth = 1 ); + void from_variant( const fc::variant&, fc::microseconds&, uint32_t max_depth = 1 ); class time_point { public: diff --git a/include/fc/uint128.hpp b/include/fc/uint128.hpp index e2a72cc..9c49bd6 100755 --- a/include/fc/uint128.hpp +++ b/include/fc/uint128.hpp @@ -121,8 +121,8 @@ namespace fc class variant; - void to_variant( const uint128& var, variant& vo ); - void from_variant( const variant& var, uint128& vo ); + void to_variant( const uint128& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, uint128& vo, uint32_t max_depth = 1 ); namespace raw { diff --git a/include/fc/variant.hpp b/include/fc/variant.hpp index 4b3821c..24de676 100755 --- a/include/fc/variant.hpp +++ b/include/fc/variant.hpp @@ -17,6 +17,17 @@ #include #include +#ifdef FC_ASSERT +#define _FC_ASSERT(...) FC_ASSERT( __VA_ARGS__ ) +#else +// poor man's FC_ASSERT, want to avoid recursive inclusion of exception.hpp +namespace fc +{ +void throw_assertion_failure( const std::string& message ); +} +#define _FC_ASSERT( cond, msg ) { if( !(cond) ) { fc::throw_assertion_failure( #cond ": " msg ); } } +#endif + namespace fc { /** @@ -27,8 +38,8 @@ namespace fc * for your Serializable_type * * @code - * void to_variant( const Serializable_type& e, variant& v ); - * void from_variant( const variant& e, Serializable_type& ll ); + * void to_variant( const Serializable_type& e, variant& v, uint32_t max_depth ); + * void from_variant( const variant& e, Serializable_type& ll, uint32_t max_depth ); * @endcode */ @@ -44,117 +55,120 @@ namespace fc struct blob { std::vector data; }; - void to_variant( const blob& var, variant& vo ); - void from_variant( const variant& var, blob& vo ); + void to_variant( const blob& var, variant& vo, uint32_t max_depth = 1); + void from_variant( const variant& var, blob& vo, uint32_t max_depth = 1 ); - template void to_variant( const boost::multi_index_container& s, variant& v ); - template void from_variant( const variant& v, boost::multi_index_container& s ); + template void to_variant( const boost::multi_index_container& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, boost::multi_index_container& s, uint32_t max_depth ); - template void to_variant( const smart_ref& s, variant& v ); - template void from_variant( const variant& v, smart_ref& s ); - template void to_variant( const safe& s, variant& v ); - template void from_variant( const variant& v, safe& s ); - template void to_variant( const std::unique_ptr& s, variant& v ); - template void from_variant( const variant& v, std::unique_ptr& s ); + template void to_variant( const smart_ref& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, smart_ref& s, uint32_t max_depth ); + template void to_variant( const safe& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, safe& s, uint32_t max_depth ); + template void to_variant( const std::unique_ptr& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, std::unique_ptr& s, uint32_t max_depth ); - template void to_variant( const static_variant& s, variant& v ); - template void from_variant( const variant& v, static_variant& s ); + template void to_variant( const static_variant& s, variant& v, uint32_t max_depth ); + template void from_variant( const variant& v, static_variant& s, uint32_t max_depth ); - void to_variant( const uint8_t& var, variant& vo ); - void from_variant( const variant& var, uint8_t& vo ); - void to_variant( const int8_t& var, variant& vo ); - void from_variant( const variant& var, int8_t& vo ); + void to_variant( const uint8_t& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, uint8_t& vo, uint32_t max_depth = 1 ); + void to_variant( const int8_t& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, int8_t& vo, uint32_t max_depth = 1 ); - void to_variant( const uint16_t& var, variant& vo ); - void from_variant( const variant& var, uint16_t& vo ); - void to_variant( const int16_t& var, variant& vo ); - void from_variant( const variant& var, int16_t& vo ); + void to_variant( const uint16_t& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, uint16_t& vo, uint32_t max_depth = 1 ); + void to_variant( const int16_t& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, int16_t& vo, uint32_t max_depth = 1 ); - void to_variant( const uint32_t& var, variant& vo ); - void from_variant( const variant& var, uint32_t& vo ); - void to_variant( const int32_t& var, variant& vo ); - void from_variant( const variant& var, int32_t& vo ); + void to_variant( const uint32_t& var, variant& vo, uint32_t max_depth = 1 ); + /** @ingroup Serializable */ + void from_variant( const variant& var, uint32_t& vo, uint32_t max_depth = 1 ); + void to_variant( const int32_t& var, variant& vo, uint32_t max_depth = 1 ); + /** @ingroup Serializable */ + void from_variant( const variant& var, int32_t& vo, uint32_t max_depth = 1 ); - void to_variant( const variant_object& var, variant& vo ); - void from_variant( const variant& var, variant_object& vo ); - void to_variant( const mutable_variant_object& var, variant& vo ); - void from_variant( const variant& var, mutable_variant_object& vo ); - void to_variant( const std::vector& var, variant& vo ); - void from_variant( const variant& var, std::vector& vo ); + void to_variant( const uint64_t& var, variant& vo, uint32_t max_depth = 1 ); + void to_variant( const int64_t& var, variant& vo, uint32_t max_depth = 1 ); + + void to_variant( const variant_object& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, variant_object& vo, uint32_t max_depth ); + void to_variant( const mutable_variant_object& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, mutable_variant_object& vo, uint32_t max_depth ); + void to_variant( const std::vector& var, variant& vo, uint32_t max_depth = 1 ); + void from_variant( const variant& var, std::vector& vo, uint32_t max_depth = 1 ); template - void to_variant( const std::unordered_map& var, variant& vo ); + void to_variant( const std::unordered_map& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::unordered_map& vo ); + void from_variant( const variant& var, std::unordered_map& vo, uint32_t max_depth ); template - void to_variant( const fc::flat_map& var, variant& vo ); + void to_variant( const fc::flat_map& var, variant& vo, uint32_t max_depth ); template - void from_variant(const variant& var, flat_map& vo); + void from_variant(const variant& var, flat_map& vo, uint32_t max_depth ); template - void to_variant( const std::map& var, variant& vo ); + void to_variant( const std::map& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::map& vo ); + void from_variant( const variant& var, std::map& vo, uint32_t max_depth ); template - void to_variant( const std::multimap& var, variant& vo ); + void to_variant( const std::multimap& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::multimap& vo ); + void from_variant( const variant& var, std::multimap& vo, uint32_t max_depth ); template - void to_variant( const std::unordered_set& var, variant& vo ); + void to_variant( const std::unordered_set& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::unordered_set& vo ); + void from_variant( const variant& var, std::unordered_set& vo, uint32_t max_depth ); template - void to_variant( const std::deque& var, variant& vo ); + void to_variant( const std::deque& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::deque& vo ); + void from_variant( const variant& var, std::deque& vo, uint32_t max_depth ); template - void to_variant( const fc::flat_set& var, variant& vo ); + void to_variant( const fc::flat_set& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, fc::flat_set& vo ); + void from_variant( const variant& var, fc::flat_set& vo, uint32_t max_depth ); template - void to_variant( const std::set& var, variant& vo ); + void to_variant( const std::set& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::set& vo ); + void from_variant( const variant& var, std::set& vo, uint32_t max_depth ); - void to_variant( const time_point& var, variant& vo ); - void from_variant( const variant& var, time_point& vo ); + void to_variant( const time_point& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, time_point& vo, uint32_t max_depth ); - void to_variant( const time_point_sec& var, variant& vo ); - void from_variant( const variant& var, time_point_sec& vo ); + void to_variant( const time_point_sec& var, variant& vo, uint32_t max_depth ); + void from_variant( const variant& var, time_point_sec& vo, uint32_t max_depth ); - void to_variant( const microseconds& input_microseconds, variant& output_variant ); - void from_variant( const variant& input_variant, microseconds& output_microseconds ); + void to_variant( const microseconds& input_microseconds, variant& output_variant, uint32_t max_depth ); + void from_variant( const variant& input_variant, microseconds& output_microseconds, uint32_t max_depth ); #ifdef __APPLE__ - void to_variant( size_t s, variant& v ); + void to_variant( size_t s, variant& v, uint32_t max_depth = 1 ); #elif defined(_MSC_VER) - void to_variant( unsigned long s, variant& v); + void to_variant( unsigned long s, variant& v, uint32_t max_depth = 1 ); #elif !defined(_MSC_VER) - void to_variant( long long int s, variant& v ); - void to_variant( unsigned long long int s, variant& v ); + void to_variant( long long int s, variant& v, uint32_t max_depth = 1 ); + void to_variant( unsigned long long int s, variant& v, uint32_t max_depth = 1 ); #endif - void to_variant( const std::string& s, variant& v ); + void to_variant( const std::string& s, variant& v, uint32_t max_depth = 1 ); template - void to_variant( const std::shared_ptr& var, variant& vo ); + void to_variant( const std::shared_ptr& var, variant& vo, uint32_t max_depth ); template - void from_variant( const variant& var, std::shared_ptr& vo ); + void from_variant( const variant& var, std::shared_ptr& vo, uint32_t max_depth ); typedef std::vector variants; template - void to_variant( const std::pair& t, variant& v ); + void to_variant( const std::pair& t, variant& v, uint32_t max_depth ); template - void from_variant( const variant& v, std::pair& p ); - - + void from_variant( const variant& v, std::pair& p, uint32_t max_depth ); /** * @brief stores null, int64, uint64, double, bool, string, std::vector, @@ -184,31 +198,31 @@ namespace fc /// Constructs a null_type variant variant(); /// Constructs a null_type variant - variant( nullptr_t ); + variant( nullptr_t, uint32_t max_depth = 1 ); /// @param str - UTF8 string - variant( const char* str ); - variant( char* str ); - variant( wchar_t* str ); - variant( const wchar_t* str ); - variant( float val ); - variant( uint8_t val ); - variant( int8_t val ); - variant( uint16_t val ); - variant( int16_t val ); - variant( uint32_t val ); - variant( int32_t val ); - variant( uint64_t val ); - variant( int64_t val ); - variant( double val ); - variant( bool val ); - variant( blob val ); - variant( fc::string val ); - variant( variant_object ); - variant( mutable_variant_object ); - variant( variants ); - variant( const variant& ); - variant( variant&& ); + variant( const char* str, uint32_t max_depth = 1 ); + variant( char* str, uint32_t max_depth = 1 ); + variant( wchar_t* str, uint32_t max_depth = 1 ); + variant( const wchar_t* str, uint32_t max_depth = 1 ); + variant( float val, uint32_t max_depth = 1 ); + variant( uint8_t val, uint32_t max_depth = 1 ); + variant( int8_t val, uint32_t max_depth = 1 ); + variant( uint16_t val, uint32_t max_depth = 1 ); + variant( int16_t val, uint32_t max_depth = 1 ); + variant( uint32_t val, uint32_t max_depth = 1 ); + variant( int32_t val, uint32_t max_depth = 1 ); + variant( uint64_t val, uint32_t max_depth = 1 ); + variant( int64_t val, uint32_t max_depth = 1 ); + variant( double val, uint32_t max_depth = 1 ); + variant( bool val, uint32_t max_depth = 1 ); + variant( blob val, uint32_t max_depth = 1 ); + variant( fc::string val, uint32_t max_depth = 1 ); + variant( variant_object, uint32_t max_depth = 1 ); + variant( mutable_variant_object, uint32_t max_depth = 1 ); + variant( variants, uint32_t max_depth = 1 ); + variant( const variant&, uint32_t max_depth = 1 ); + variant( variant&&, uint32_t max_depth = 1 ); ~variant(); /** @@ -292,7 +306,7 @@ namespace fc * following method to implement conversion from variant to T. * * - * void from_variant( const Variant& var, T& val ) + * void from_variant( const Variant& var, T& val, uint32_t max_depth ) * * * The above form is not always convienant, so the this templated @@ -300,17 +314,17 @@ namespace fc * types. */ template - T as()const + T as( uint32_t max_depth )const { T tmp; - from_variant( *this, tmp ); + from_variant( *this, tmp, max_depth ); return tmp; } template - void as( T& v )const + void as( T& v, uint32_t max_depth )const { - from_variant( *this, v ); + from_variant( *this, v, max_depth ); } variant& operator=( variant&& v ); @@ -323,14 +337,15 @@ namespace fc } template - variant( const optional& v ) + variant( const optional& v, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); memset( this, 0, sizeof(*this) ); - if( v.valid() ) *this = variant(*v); + if( v.valid() ) *this = variant( *v, max_depth - 1 ); } template - explicit variant( const T& val ); + variant( const T& val, uint32_t max_depth ); void clear(); @@ -342,200 +357,213 @@ namespace fc typedef optional ovariant; /** @ingroup Serializable */ - void from_variant( const variant& var, string& vo ); + void from_variant( const variant& var, string& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, variants& vo ); - void from_variant( const variant& var, variant& vo ); + void from_variant( const variant& var, variants& vo, uint32_t max_depth ); + void from_variant( const variant& var, variant& vo, uint32_t max_depth ); /** @ingroup Serializable */ - void from_variant( const variant& var, int64_t& vo ); + void from_variant( const variant& var, int64_t& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, uint64_t& vo ); + void from_variant( const variant& var, uint64_t& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, bool& vo ); + void from_variant( const variant& var, bool& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, double& vo ); + void from_variant( const variant& var, double& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, float& vo ); - /** @ingroup Serializable */ - void from_variant( const variant& var, int32_t& vo ); - /** @ingroup Serializable */ - void from_variant( const variant& var, uint32_t& vo ); + void from_variant( const variant& var, float& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ template - void from_variant( const variant& var, optional& vo ) + void from_variant( const variant& var, optional& vo, uint32_t max_depth ) { if( var.is_null() ) vo = optional(); else { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); vo = T(); - from_variant( var, *vo ); + from_variant( var, *vo, max_depth - 1 ); } } template - void to_variant( const std::unordered_set& var, variant& vo ) + void to_variant( const std::unordered_set& var, variant& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); std::vector vars(var.size()); size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = variant(*itr); + for( const auto& item : var ) + vars[i++] = variant( item, max_depth - 1 ); vo = vars; } template - void from_variant( const variant& var, std::unordered_set& vo ) + void from_variant( const variant& var, std::unordered_set& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); vo.reserve( vars.size() ); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as() ); + for( const auto& item : vars ) + vo.insert( item.as( max_depth - 1 ) ); } template - void to_variant( const std::unordered_map& var, variant& vo ) + void to_variant( const std::unordered_map& var, variant& vo, uint32_t max_depth ) { - std::vector< variant > vars(var.size()); - size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = fc::variant(*itr); - vo = vars; + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector< variant > vars(var.size()); + size_t i = 0; + for( const auto& key_value : var ) + vars[i++] = fc::variant( key_value, max_depth - 1 ); + vo = vars; } template - void from_variant( const variant& var, std::unordered_map& vo ) + void from_variant( const variant& var, std::unordered_map& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as< std::pair >() ); - + vo.reserve( vars.size() ); + for( const auto& item : vars ) + vo.insert( item.as< std::pair >( max_depth - 1 ) ); } template - void to_variant( const std::map& var, variant& vo ) + void to_variant( const std::map& var, variant& vo, uint32_t max_depth ) { - std::vector< variant > vars(var.size()); - size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = fc::variant(*itr); - vo = vars; + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector< variant > vars(var.size()); + size_t i = 0; + for( const auto& key_value : var ) + vars[i++] = fc::variant( key_value, max_depth - 1 ); + vo = vars; } template - void from_variant( const variant& var, std::map& vo ) + void from_variant( const variant& var, std::map& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as< std::pair >() ); + for( auto item : vars ) + vo.insert( item.as< std::pair >( max_depth - 1 ) ); } template - void to_variant( const std::multimap& var, variant& vo ) + void to_variant( const std::multimap& var, variant& vo, uint32_t max_depth ) { - std::vector< variant > vars(var.size()); - size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = fc::variant(*itr); - vo = vars; + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector< variant > vars(var.size()); + size_t i = 0; + for( const auto& key_value : var ) + vars[i++] = fc::variant( key_value, max_depth - 1 ); + vo = vars; } template - void from_variant( const variant& var, std::multimap& vo ) + void from_variant( const variant& var, std::multimap& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as< std::pair >() ); + for( auto item : vars ) + vo.insert( item.as< std::pair >( max_depth - 1 ) ); } template - void to_variant( const std::set& var, variant& vo ) + void to_variant( const std::set& var, variant& vo, uint32_t max_depth ) { - std::vector vars(var.size()); - size_t i = 0; - for( auto itr = var.begin(); itr != var.end(); ++itr, ++i ) - vars[i] = variant(*itr); - vo = vars; + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector vars(var.size()); + size_t i = 0; + for( const auto& item : var ) + vars[i++] = fc::variant( item, max_depth - 1 ); + vo = vars; } template - void from_variant( const variant& var, std::set& vo ) + void from_variant( const variant& var, std::set& vo, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); vo.clear(); - //vo.reserve( vars.size() ); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - vo.insert( itr->as() ); + for( const auto& item : vars ) + vo.insert( item.as( max_depth - 1 ) ); } /** @ingroup Serializable */ template - void from_variant( const variant& var, std::deque& tmp ) + void from_variant( const variant& var, std::deque& dest, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); - tmp.clear(); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - tmp.push_back( itr->as() ); + dest.clear(); + dest.resize( vars.size() ); + for( const auto& item : vars ) + dest.push_back( item.as( max_depth - 1 ) ); } /** @ingroup Serializable */ template - void to_variant( const std::deque& t, variant& v ) + void to_variant( const std::deque& src, variant& v, uint32_t max_depth ) { - std::vector vars(t.size()); - for( size_t i = 0; i < t.size(); ++i ) - vars[i] = variant(t[i]); + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector vars(src.size()); + for( size_t i = 0; i < src.size(); ++i ) + vars[i] = variant( src[i], max_depth - 1 ); v = std::move(vars); } /** @ingroup Serializable */ template - void from_variant( const variant& var, std::vector& tmp ) + void from_variant( const variant& var, std::vector& dest, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = var.get_array(); - tmp.clear(); - tmp.reserve( vars.size() ); - for( auto itr = vars.begin(); itr != vars.end(); ++itr ) - tmp.push_back( itr->as() ); + dest.clear(); + dest.reserve( vars.size() ); + for( const auto& item : vars ) + dest.push_back( item.as( max_depth - 1 ) ); } /** @ingroup Serializable */ template - void to_variant( const std::vector& t, variant& v ) + void to_variant( const std::vector& t, variant& v, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); std::vector vars(t.size()); - for( size_t i = 0; i < t.size(); ++i ) - vars[i] = variant(t[i]); - v = std::move(vars); + for( size_t i = 0; i < t.size(); ++i ) + vars[i] = variant( t[i], max_depth - 1 ); + v = std::move(vars); } /** @ingroup Serializable */ template - void to_variant( const std::pair& t, variant& v ) + void to_variant( const std::pair& t, variant& v, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); std::vector vars(2); - vars[0] = variant(t.first); - vars[1] = variant(t.second); - v = vars; + vars[0] = variant( t.first, max_depth - 1 ); + vars[1] = variant( t.second, max_depth - 1 ); + v = vars; } template - void from_variant( const variant& v, std::pair& p ) + void from_variant( const variant& v, std::pair& p, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = v.get_array(); if( vars.size() > 0 ) - p.first = vars[0].as(); + p.first = vars[0].as( max_depth - 1 ); if( vars.size() > 1 ) - p.second = vars[1].as(); + p.second = vars[1].as( max_depth - 1 ); } template - variant::variant( const T& val ) + variant::variant( const T& val, uint32_t max_depth ) { memset( this, 0, sizeof(*this) ); - to_variant( val, *this ); + to_variant( val, *this, max_depth ); } #ifdef __APPLE__ - inline void to_variant( size_t s, variant& v ) { v = variant(uint64_t(s)); } + inline void to_variant( size_t s, variant& v, uint32_t max_depth = 1 ) { v = variant(uint64_t(s)); } #endif #ifdef _MSC_VER @@ -543,68 +571,90 @@ namespace fc #endif template - void to_variant( const std::shared_ptr& var, variant& vo ) + void to_variant( const std::shared_ptr& var, variant& vo, uint32_t max_depth ) { - if( var ) to_variant( *var, vo ); + if( var ) + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + to_variant( *var, vo, max_depth - 1 ); + } else vo = nullptr; } template - void from_variant( const variant& var, std::shared_ptr& vo ) + void from_variant( const variant& var, std::shared_ptr& vo, uint32_t max_depth ) { if( var.is_null() ) vo = nullptr; - else if( vo ) from_variant( var, *vo ); - else { - vo = std::make_shared(); - from_variant( var, *vo ); + else + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + if( !vo ) vo = std::make_shared(); + from_variant( var, *vo, max_depth - 1 ); } } template - void to_variant( const std::unique_ptr& var, variant& vo ) + void to_variant( const std::unique_ptr& var, variant& vo, uint32_t max_depth ) { - if( var ) to_variant( *var, vo ); + if( var ) + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + to_variant( *var, vo, max_depth - 1 ); + } else vo = nullptr; } template - void from_variant( const variant& var, std::unique_ptr& vo ) + void from_variant( const variant& var, std::unique_ptr& vo, uint32_t max_depth ) { if( var.is_null() ) vo.reset(); - else if( vo ) from_variant( var, *vo ); - else { - vo.reset( new T() ); - from_variant( var, *vo ); + else + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + if( !vo ) vo.reset( new T() ); + from_variant( var, *vo, max_depth - 1 ); } } template - void to_variant( const safe& s, variant& v ) { v = s.value; } - - template - void from_variant( const variant& v, safe& s ) { s.value = v.as_uint64(); } - - template - void to_variant( const smart_ref& s, variant& v ) { v = *s; } - - template - void from_variant( const variant& v, smart_ref& s ) { from_variant( v, *s ); } - - template void to_variant( const boost::multi_index_container& c, variant& v ) - { - std::vector vars; - vars.reserve( c.size() ); - for( const auto& item : c ) - vars.emplace_back( variant(item) ); - v = std::move(vars); + void to_variant( const safe& s, variant& v, uint32_t max_depth ) { + to_variant( s.value, v, max_depth ); } - template void from_variant( const variant& v, boost::multi_index_container& c ) + template + void from_variant( const variant& v, safe& s, uint32_t max_depth ) { + s.value = v.as( max_depth ); + } + + template + void to_variant( const smart_ref& s, variant& v, uint32_t max_depth ) { + to_variant( *s, v, max_depth ); + } + + template + void from_variant( const variant& v, smart_ref& s, uint32_t max_depth ) { + from_variant( v, *s, max_depth ); + } + + template + void to_variant( const boost::multi_index_container& c, variant& v, uint32_t max_depth ) { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + std::vector vars; + vars.reserve( c.size() ); + for( const auto& item : c ) + vars.emplace_back( variant( item, max_depth - 1 ) ); + v = std::move(vars); + } + + template + void from_variant( const variant& v, boost::multi_index_container& c, uint32_t max_depth ) + { + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); const variants& vars = v.get_array(); c.clear(); for( const auto& item : vars ) - c.insert( item.as() ); + c.insert( item.as( max_depth - 1 ) ); } variant operator + ( const variant& a, const variant& b ); diff --git a/include/fc/variant_object.hpp b/include/fc/variant_object.hpp index bd68791..596950c 100755 --- a/include/fc/variant_object.hpp +++ b/include/fc/variant_object.hpp @@ -90,9 +90,9 @@ namespace fc friend class mutable_variant_object; }; /** @ingroup Serializable */ - void to_variant( const variant_object& var, variant& vo ); + void to_variant( const variant_object& var, variant& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, variant_object& vo ); + void from_variant( const variant& var, variant_object& vo, uint32_t max_depth = 1 ); /** @@ -169,11 +169,12 @@ namespace fc * * @return *this; */ - mutable_variant_object& operator()( string key, variant var ); + mutable_variant_object& operator()( string key, variant var, uint32_t max_depth = 1 ); template - mutable_variant_object& operator()( string key, T&& var ) + mutable_variant_object& operator()( string key, T&& var, uint32_t max_depth ) { - set(std::move(key), variant( fc::forward(var) ) ); + _FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + set( std::move(key), variant( fc::forward(var), max_depth - 1 ) ); return *this; } /** @@ -216,9 +217,27 @@ namespace fc std::unique_ptr< std::vector< entry > > _key_value; friend class variant_object; }; + + class limited_mutable_variant_object : public mutable_variant_object + { + public: + limited_mutable_variant_object( uint32_t max_depth ); + + template + limited_mutable_variant_object& operator()( string key, T&& var ) + { + set( std::move(key), variant( fc::forward(var), _max_depth ) ); + return *this; + } + limited_mutable_variant_object& operator()( const variant_object& vo ); + + private: + const uint32_t _max_depth; + }; + /** @ingroup Serializable */ - void to_variant( const mutable_variant_object& var, variant& vo ); + void to_variant( const mutable_variant_object& var, variant& vo, uint32_t max_depth = 1 ); /** @ingroup Serializable */ - void from_variant( const variant& var, mutable_variant_object& vo ); + void from_variant( const variant& var, mutable_variant_object& vo, uint32_t max_depth = 1 ); } // namespace fc diff --git a/src/crypto/bigint.cpp b/src/crypto/bigint.cpp index 5bc96d4..478f949 100755 --- a/src/crypto/bigint.cpp +++ b/src/crypto/bigint.cpp @@ -128,14 +128,14 @@ namespace fc { } bigint bigint::operator / ( const bigint& a ) const { BN_CTX* ctx = BN_CTX_new(); - bigint tmp;//(*this); + bigint tmp; BN_div( tmp.n, NULL, n, a.n, ctx ); BN_CTX_free(ctx); return tmp; } bigint bigint::operator % ( const bigint& a ) const { BN_CTX* ctx = BN_CTX_new(); - bigint tmp;//(*this); + bigint tmp; BN_mod( tmp.n, n, a.n, ctx ); BN_CTX_free(ctx); return tmp; @@ -143,7 +143,7 @@ namespace fc { bigint bigint::operator /= ( const bigint& a ) { BN_CTX* ctx = BN_CTX_new(); - bigint tmp;//*this); + bigint tmp; BN_div( tmp.n, NULL, n, a.n, ctx ); fc_swap( tmp.n, n ); BN_CTX_free(ctx); @@ -188,6 +188,8 @@ namespace fc { bigint& bigint::operator = ( bigint&& a ) { + if( &a == this ) + return *this; fc_swap( a.n, n ); return *this; } @@ -208,14 +210,14 @@ namespace fc { } /** encodes the big int as base64 string, or a number */ - void to_variant( const bigint& bi, variant& v ) + void to_variant( const bigint& bi, variant& v, uint32_t max_depth ) { std::vector ve = bi; v = fc::variant(base64_encode((unsigned char*)ve.data(),ve.size())); } /** decodes the big int as base64 string, or a number */ - void from_variant( const variant& v, bigint& bi ) + void from_variant( const variant& v, bigint& bi, uint32_t max_depth ) { if( v.is_numeric() ) bi = bigint( static_cast(v.as_uint64()) ); else diff --git a/src/crypto/elliptic_common.cpp b/src/crypto/elliptic_common.cpp index 16a57cb..4eb95fb 100755 --- a/src/crypto/elliptic_common.cpp +++ b/src/crypto/elliptic_common.cpp @@ -381,27 +381,27 @@ namespace fc { namespace ecc { } } -void to_variant( const ecc::private_key& var, variant& vo ) +void to_variant( const ecc::private_key& var, variant& vo, uint32_t max_depth ) { - vo = var.get_secret(); + to_variant( var.get_secret(), vo, max_depth ); } -void from_variant( const variant& var, ecc::private_key& vo ) +void from_variant( const variant& var, ecc::private_key& vo, uint32_t max_depth ) { fc::sha256 sec; - from_variant( var, sec ); + from_variant( var, sec, max_depth ); vo = ecc::private_key::regenerate(sec); } -void to_variant( const ecc::public_key& var, variant& vo ) +void to_variant( const ecc::public_key& var, variant& vo, uint32_t max_depth ) { - vo = var.serialize(); + to_variant( var.serialize(), vo, max_depth ); } -void from_variant( const variant& var, ecc::public_key& vo ) +void from_variant( const variant& var, ecc::public_key& vo, uint32_t max_depth ) { ecc::public_key_data dat; - from_variant( var, dat ); + from_variant( var, dat, max_depth ); vo = ecc::public_key(dat); } diff --git a/src/crypto/pke.cpp b/src/crypto/pke.cpp index a425621..3ec0199 100755 --- a/src/crypto/pke.cpp +++ b/src/crypto/pke.cpp @@ -338,28 +338,28 @@ namespace fc { } /** encodes the big int as base64 string, or a number */ - void to_variant( const public_key& bi, variant& v ) + void to_variant( const public_key& bi, variant& v, uint32_t max_depth ) { v = bi.serialize(); } /** decodes the big int as base64 string, or a number */ - void from_variant( const variant& v, public_key& bi ) + void from_variant( const variant& v, public_key& bi, uint32_t max_depth ) { - bi = public_key( v.as >() ); + bi = public_key( v.as >(max_depth) ); } /** encodes the big int as base64 string, or a number */ - void to_variant( const private_key& bi, variant& v ) + void to_variant( const private_key& bi, variant& v, uint32_t max_depth ) { v = bi.serialize(); } /** decodes the big int as base64 string, or a number */ - void from_variant( const variant& v, private_key& bi ) + void from_variant( const variant& v, private_key& bi, uint32_t max_depth ) { - bi = private_key( v.as >() ); + bi = private_key( v.as >(max_depth) ); } } // fc diff --git a/src/crypto/ripemd160.cpp b/src/crypto/ripemd160.cpp index e336b39..3e96048 100755 --- a/src/crypto/ripemd160.cpp +++ b/src/crypto/ripemd160.cpp @@ -26,7 +26,8 @@ ripemd160::operator string()const { return str(); } char* ripemd160::data()const { return (char*)&_hash[0]; } -struct ripemd160::encoder::impl { +class ripemd160::encoder::impl { +public: impl() { memset( (char*)&ctx, 0, sizeof(ctx) ); @@ -98,19 +99,16 @@ bool operator == ( const ripemd160& h1, const ripemd160& h2 ) { return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; } - void to_variant( const ripemd160& bi, variant& v ) - { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); - } - void from_variant( const variant& v, ripemd160& bi ) - { - std::vector ve = v.as< std::vector >(); - if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + void to_variant( const ripemd160& bi, variant& v, uint32_t max_depth ) + { + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); + } + void from_variant( const variant& v, ripemd160& bi, uint32_t max_depth ) + { + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } } // fc diff --git a/src/crypto/sha1.cpp b/src/crypto/sha1.cpp index 88107db..f509f00 100755 --- a/src/crypto/sha1.cpp +++ b/src/crypto/sha1.cpp @@ -83,19 +83,16 @@ bool operator == ( const sha1& h1, const sha1& h2 ) { return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; } - void to_variant( const sha1& bi, variant& v ) + void to_variant( const sha1& bi, variant& v, uint32_t max_depth ) { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); } - void from_variant( const variant& v, sha1& bi ) + void from_variant( const variant& v, sha1& bi, uint32_t max_depth ) { - std::vector ve = v.as< std::vector >(); + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } } // fc diff --git a/src/crypto/sha224.cpp b/src/crypto/sha224.cpp index 0ae1707..4015f90 100755 --- a/src/crypto/sha224.cpp +++ b/src/crypto/sha224.cpp @@ -60,7 +60,7 @@ namespace fc { sha224 operator ^ ( const sha224& h1, const sha224& h2 ) { sha224 result; for( uint32_t i = 0; i < 7; ++i ) - result._hash[i] = h1._hash[i] ^ h2._hash[i]; + result._hash[i] = h1._hash[i] ^ h2._hash[i]; return result; } bool operator >= ( const sha224& h1, const sha224& h2 ) { @@ -79,19 +79,16 @@ namespace fc { return memcmp( h1._hash, h2._hash, sizeof(sha224) ) == 0; } - void to_variant( const sha224& bi, variant& v ) - { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); - } - void from_variant( const variant& v, sha224& bi ) - { - std::vector ve = v.as< std::vector >(); - if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + void to_variant( const sha224& bi, variant& v, uint32_t max_depth ) + { + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); + } + void from_variant( const variant& v, sha224& bi, uint32_t max_depth ) + { + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } template<> diff --git a/src/crypto/sha256.cpp b/src/crypto/sha256.cpp index c1b8235..e27fd60 100755 --- a/src/crypto/sha256.cpp +++ b/src/crypto/sha256.cpp @@ -148,7 +148,6 @@ namespace fc { } else (*this) = (*this) << (nzbits - 0x18); - return; } double sha256::inverse_approx_log_32_double( uint32_t x ) @@ -194,19 +193,16 @@ namespace fc { return lzbits; } - void to_variant( const sha256& bi, variant& v ) - { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); - } - void from_variant( const variant& v, sha256& bi ) - { - std::vector ve = v.as< std::vector >(); - if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + void to_variant( const sha256& bi, variant& v, uint32_t max_depth ) + { + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); + } + void from_variant( const variant& v, sha256& bi, uint32_t max_depth ) + { + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } uint64_t hash64(const char* buf, size_t len) diff --git a/src/crypto/sha512.cpp b/src/crypto/sha512.cpp index 7e0315c..49bc8d9 100755 --- a/src/crypto/sha512.cpp +++ b/src/crypto/sha512.cpp @@ -85,19 +85,16 @@ namespace fc { return memcmp( h1._hash, h2._hash, sizeof(h1._hash) ) == 0; } - void to_variant( const sha512& bi, variant& v ) - { - v = std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ); - } - void from_variant( const variant& v, sha512& bi ) - { - std::vector ve = v.as< std::vector >(); - if( ve.size() ) - { - memcpy(&bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); - } - else - memset( &bi, char(0), sizeof(bi) ); + void to_variant( const sha512& bi, variant& v, uint32_t max_depth ) + { + to_variant( std::vector( (const char*)&bi, ((const char*)&bi) + sizeof(bi) ), v, max_depth ); + } + void from_variant( const variant& v, sha512& bi, uint32_t max_depth ) + { + std::vector ve = v.as< std::vector >( max_depth ); + memset( &bi, char(0), sizeof(bi) ); + if( ve.size() ) + memcpy( &bi, ve.data(), fc::min(ve.size(),sizeof(bi)) ); } template<> diff --git a/src/exception.cpp b/src/exception.cpp index e173be4..1f84286 100755 --- a/src/exception.cpp +++ b/src/exception.cpp @@ -123,19 +123,25 @@ namespace fc exception::~exception(){} - void to_variant( const exception& e, variant& v ) + void to_variant( const exception& e, variant& v, uint32_t max_depth ) { - v = mutable_variant_object( "code", e.code() ) - ( "name", e.name() ) - ( "message", e.what() ) - ( "stack", e.get_log() ); + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); + variant v_log; + to_variant( e.get_log(), v_log, max_depth - 1 ); + mutable_variant_object tmp; + tmp( "code", e.code() ) + ( "name", e.name() ) + ( "message", e.what() ) + ( "stack", v_log ); + v = variant( tmp, max_depth ); } - void from_variant( const variant& v, exception& ll ) + void from_variant( const variant& v, exception& ll, uint32_t max_depth ) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); auto obj = v.get_object(); if( obj.contains( "stack" ) ) - ll.my->_elog = obj["stack"].as(); + ll.my->_elog = obj["stack"].as( max_depth - 1 ); if( obj.contains( "code" ) ) ll.my->_code = obj["code"].as_int64(); if( obj.contains( "name" ) ) @@ -161,7 +167,7 @@ namespace fc ss << variant(my->_code).as_string() <<" " << my->_name << ": " <_what<<"\n"; for( auto itr = my->_elog.begin(); itr != my->_elog.end(); ) { - ss << itr->get_message() <<"\n"; //fc::format_string( itr->get_format(), itr->get_data() ) <<"\n"; + ss << itr->get_message() <<"\n"; try { ss << " " << json::to_string( itr->get_data() )<<"\n"; @@ -188,7 +194,6 @@ namespace fc { if( itr->get_format().size() ) ss << " " << fc::format_string( itr->get_format(), itr->get_data() ); - // ss << " " << itr->get_context().to_string() <<"\n"; } return ss.str(); } @@ -251,6 +256,11 @@ namespace fc return *this; } + void throw_assertion_failure( const std::string& message ) + { + FC_THROW_EXCEPTION( fc::assert_exception, message ); + } + void record_assert_trip( const char* filename, uint32_t lineno, diff --git a/src/filesystem.cpp b/src/filesystem.cpp index 3046d56..74f69de 100755 --- a/src/filesystem.cpp +++ b/src/filesystem.cpp @@ -27,19 +27,15 @@ namespace fc { // when converting to and from a variant, store utf-8 in the variant - void to_variant( const fc::path& path_to_convert, variant& variant_output ) + void to_variant( const fc::path& path_to_convert, variant& variant_output, uint32_t max_depth ) { std::wstring wide_string = path_to_convert.generic_wstring(); std::string utf8_string; fc::encodeUtf8(wide_string, &utf8_string); variant_output = utf8_string; - - //std::string path = t.to_native_ansi_path(); - //std::replace(path.begin(), path.end(), '\\', '/'); - //v = path; } - void from_variant( const fc::variant& variant_to_convert, fc::path& path_output ) + void from_variant( const fc::variant& variant_to_convert, fc::path& path_output, uint32_t max_depth ) { std::wstring wide_string; fc::decodeUtf8(variant_to_convert.as_string(), &wide_string); diff --git a/src/io/varint.cpp b/src/io/varint.cpp index a3eaac2..6d5df6c 100755 --- a/src/io/varint.cpp +++ b/src/io/varint.cpp @@ -3,8 +3,8 @@ namespace fc { -void to_variant( const signed_int& var, variant& vo ) { vo = var.value; } -void from_variant( const variant& var, signed_int& vo ) { vo.value = static_cast(var.as_int64()); } -void to_variant( const unsigned_int& var, variant& vo ) { vo = var.value; } -void from_variant( const variant& var, unsigned_int& vo ) { vo.value = static_cast(var.as_uint64()); } +void to_variant( const signed_int& var, variant& vo, uint32_t max_depth ) { vo = var.value; } +void from_variant( const variant& var, signed_int& vo, uint32_t max_depth ) { vo.value = static_cast(var.as_int64()); } +void to_variant( const unsigned_int& var, variant& vo, uint32_t max_depth ) { vo = var.value; } +void from_variant( const variant& var, unsigned_int& vo, uint32_t max_depth ) { vo.value = static_cast(var.as_uint64()); } } diff --git a/src/log/console_appender.cpp b/src/log/console_appender.cpp index 9c55ff0..af35564 100755 --- a/src/log/console_appender.cpp +++ b/src/log/console_appender.cpp @@ -31,7 +31,7 @@ namespace fc { console_appender::console_appender( const variant& args ) :my(new impl) { - configure( args.as() ); + configure( args.as( FC_MAX_LOG_OBJECT_DEPTH ) ); } console_appender::console_appender( const config& cfg ) @@ -89,12 +89,9 @@ namespace fc { } void console_appender::log( const log_message& m ) { - //fc::string message = fc::format_string( m.get_format(), m.get_data() ); - //fc::variant lmsg(m); FILE* out = stream::std_error ? stderr : stdout; - //fc::string fmt_str = fc::format_string( cfg.format, mutable_variant_object(m.get_context())( "message", message) ); std::stringstream file_line; file_line << m.get_context().get_file() <<":"<cfg.max_object_depth ); + line << message; fc::unique_lock lock(log_mutex()); @@ -141,7 +138,7 @@ namespace fc { #endif if( text.size() ) - fprintf( out, "%s", text.c_str() ); //fmt_str.c_str() ); + fprintf( out, "%s", text.c_str() ); #ifdef WIN32 if (my->console_handle != INVALID_HANDLE_VALUE) diff --git a/src/log/file_appender.cpp b/src/log/file_appender.cpp index dabdf3f..d62e15c 100755 --- a/src/log/file_appender.cpp +++ b/src/log/file_appender.cpp @@ -175,7 +175,7 @@ namespace fc { {} file_appender::file_appender( const variant& args ) : - my( new impl( args.as() ) ) + my( new impl( args.as( FC_MAX_LOG_OBJECT_DEPTH ) ) ) { try { @@ -221,13 +221,9 @@ namespace fc { } line << "] "; - fc::string message = fc::format_string( m.get_format(), m.get_data() ); + fc::string message = fc::format_string( m.get_format(), m.get_data(), my->cfg.max_object_depth ); line << message.c_str(); - //fc::variant lmsg(m); - - // fc::string fmt_str = fc::format_string( my->cfg.format, mutable_variant_object(m.get_context())( "message", message) ); - { fc::scoped_lock lock( my->slock ); my->out << line.str() << "\t\t\t" << m.get_context().get_file() << ":" << m.get_context().get_line_number() << "\n"; diff --git a/src/log/gelf_appender.cpp b/src/log/gelf_appender.cpp index 2f14d78..2d7f78a 100755 --- a/src/log/gelf_appender.cpp +++ b/src/log/gelf_appender.cpp @@ -38,7 +38,7 @@ namespace fc }; gelf_appender::gelf_appender(const variant& args) : - my(new impl(args.as())) + my( new impl( args.as( FC_MAX_LOG_OBJECT_DEPTH ) ) ) { try { @@ -94,7 +94,7 @@ namespace fc mutable_variant_object gelf_message; gelf_message["version"] = "1.1"; gelf_message["host"] = my->cfg.host; - gelf_message["short_message"] = format_string(message.get_format(), message.get_data()); + gelf_message["short_message"] = format_string( message.get_format(), message.get_data(), my->cfg.max_object_depth ); gelf_message["timestamp"] = context.get_timestamp().time_since_epoch().count() / 1000000.; diff --git a/src/log/log_message.cpp b/src/log/log_message.cpp index 09b6815..cf8d27a 100755 --- a/src/log/log_message.cpp +++ b/src/log/log_message.cpp @@ -58,11 +58,11 @@ namespace fc my->task_name = current_task_desc ? current_task_desc : "?unnamed?"; } - log_context::log_context( const variant& v ) + log_context::log_context( const variant& v, uint32_t max_depth ) :my( std::make_shared() ) { auto obj = v.get_object(); - my->level = obj["level"].as(); + my->level = obj["level"].as(max_depth); my->file = obj["file"].as_string(); my->line = obj["line"].as_uint64(); my->method = obj["method"].as_string(); @@ -70,9 +70,9 @@ namespace fc my->thread_name = obj["thread_name"].as_string(); if (obj.contains("task_name")) my->task_name = obj["task_name"].as_string(); - my->timestamp = obj["timestamp"].as(); + my->timestamp = obj["timestamp"].as(max_depth); if( obj.contains( "context" ) ) - my->context = obj["context"].as(); + my->context = obj["context"].as(max_depth); } fc::string log_context::to_string()const @@ -91,26 +91,26 @@ namespace fc log_context::~log_context(){} - void to_variant( const log_context& l, variant& v ) + void to_variant( const log_context& l, variant& v, uint32_t max_depth ) { - v = l.to_variant(); + v = l.to_variant(max_depth); } - void from_variant( const variant& l, log_context& c ) + void from_variant( const variant& l, log_context& c, uint32_t max_depth ) { - c = log_context(l); + c = log_context(l, max_depth); } - void from_variant( const variant& l, log_message& c ) + void from_variant( const variant& l, log_message& c, uint32_t max_depth ) { - c = log_message(l); + c = log_message(l, max_depth); } - void to_variant( const log_message& m, variant& v ) + void to_variant( const log_message& m, variant& v, uint32_t max_depth ) { - v = m.to_variant(); + v = m.to_variant( max_depth ); } - void to_variant( log_level e, variant& v ) + void to_variant( log_level e, variant& v, uint32_t max_depth ) { switch( e ) { @@ -134,7 +134,7 @@ namespace fc return; } } - void from_variant( const variant& v, log_level& e ) + void from_variant( const variant& v, log_level& e, uint32_t max_depth ) { try { @@ -163,16 +163,16 @@ namespace fc string log_context::get_context()const { return my->context; } - variant log_context::to_variant()const + variant log_context::to_variant(uint32_t max_depth)const { mutable_variant_object o; - o( "level", variant(my->level) ) + o( "level", variant(my->level, max_depth) ) ( "file", my->file ) ( "line", my->line ) ( "method", my->method ) ( "hostname", my->hostname ) ( "thread_name", my->thread_name ) - ( "timestamp", variant(my->timestamp) ); + ( "timestamp", variant(my->timestamp, max_depth) ); if( my->context.size() ) o( "context", my->context ); @@ -191,22 +191,23 @@ namespace fc my->args = std::move(args); } - log_message::log_message( const variant& v ) - :my( std::make_shared( log_context( v.get_object()["context"] ) ) ) + log_message::log_message( const variant& v, uint32_t max_depth ) + :my( std::make_shared( log_context( v.get_object()["context"], max_depth ) ) ) { my->format = v.get_object()["format"].as_string(); my->args = v.get_object()["data"].get_object(); } - variant log_message::to_variant()const + variant log_message::to_variant(uint32_t max_depth)const { - return mutable_variant_object( "context", my->context ) + return limited_mutable_variant_object(max_depth) + ( "context", my->context ) ( "format", my->format ) ( "data", my->args ); } - log_context log_message::get_context()const { return my->context; } - string log_message::get_format()const { return my->format; } + log_context log_message::get_context()const { return my->context; } + string log_message::get_format()const { return my->format; } variant_object log_message::get_data()const { return my->args; } string log_message::get_message()const diff --git a/src/log/logger_config.cpp b/src/log/logger_config.cpp index 92dde24..3e35c28 100755 --- a/src/log/logger_config.cpp +++ b/src/log/logger_config.cpp @@ -27,7 +27,6 @@ namespace fc { get_logger_map().clear(); get_appender_map().clear(); - //slog( "\n%s", fc::json::to_pretty_string(cfg).c_str() ); for( size_t i = 0; i < cfg.appenders.size(); ++i ) { appender::create( cfg.appenders[i].name, cfg.appenders[i].type, cfg.appenders[i].args ); // TODO... process enabled diff --git a/src/network/ip.cpp b/src/network/ip.cpp index 1961659..570a621 100755 --- a/src/network/ip.cpp +++ b/src/network/ip.cpp @@ -137,20 +137,20 @@ namespace fc { namespace ip { } // namespace ip - void to_variant( const ip::endpoint& var, variant& vo ) + void to_variant( const ip::endpoint& var, variant& vo, uint32_t max_depth ) { vo = fc::string(var); } - void from_variant( const variant& var, ip::endpoint& vo ) + void from_variant( const variant& var, ip::endpoint& vo, uint32_t max_depth ) { vo = ip::endpoint::from_string(var.as_string()); } - void to_variant( const ip::address& var, variant& vo ) + void to_variant( const ip::address& var, variant& vo, uint32_t max_depth ) { vo = fc::string(var); } - void from_variant( const variant& var, ip::address& vo ) + void from_variant( const variant& var, ip::address& vo, uint32_t max_depth ) { vo = ip::address(var.as_string()); } diff --git a/src/network/url.cpp b/src/network/url.cpp index d7d6339..9e59867 100755 --- a/src/network/url.cpp +++ b/src/network/url.cpp @@ -89,11 +89,11 @@ namespace fc }; } - void to_variant( const url& u, fc::variant& v ) + void to_variant( const url& u, fc::variant& v, uint32_t max_depth ) { v = fc::string(u); } - void from_variant( const fc::variant& v, url& u ) + void from_variant( const fc::variant& v, url& u, uint32_t max_depth ) { u = url( v.as_string() ); } diff --git a/src/real128.cpp b/src/real128.cpp index c83336e..f941359 100755 --- a/src/real128.cpp +++ b/src/real128.cpp @@ -118,11 +118,11 @@ namespace fc return result; } - void to_variant( const real128& var, variant& vo ) + void to_variant( const real128& var, variant& vo, uint32_t max_depth ) { vo = std::string(var); } - void from_variant( const variant& var, real128& vo ) + void from_variant( const variant& var, real128& vo, uint32_t max_depth ) { vo = real128(var.as_string()); } diff --git a/src/rpc/http_api.cpp b/src/rpc/http_api.cpp index c9571a2..b8a299a 100755 --- a/src/rpc/http_api.cpp +++ b/src/rpc/http_api.cpp @@ -7,7 +7,8 @@ http_api_connection::~http_api_connection() { } -http_api_connection::http_api_connection() +http_api_connection::http_api_connection(uint32_t max_depth) +:api_connection(max_depth) { _rpc_state.add_method( "call", [this]( const variants& args ) -> variant { @@ -88,25 +89,27 @@ void http_api_connection::on_request( const fc::http::request& req, const fc::ht { resp.add_header( "Content-Type", "application/json" ); std::string req_body( req.body.begin(), req.body.end() ); - auto var = fc::json::from_string( req_body ); + auto var = fc::json::from_string( req_body, fc::json::legacy_parser, _max_conversion_depth ); const auto& var_obj = var.get_object(); if( var_obj.contains( "method" ) ) { - auto call = var.as(); + auto call = var.as(_max_conversion_depth); try { try { - auto result = _rpc_state.local_call( call.method, call.params ); - resp_body = fc::json::to_string( fc::rpc::response( *call.id, result ) ); + fc::variant result( _rpc_state.local_call( call.method, call.params ), _max_conversion_depth ); + resp_body = fc::json::to_string( fc::variant( fc::rpc::response( *call.id, result ), _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); resp_status = http::reply::OK; } FC_CAPTURE_AND_RETHROW( (call.method)(call.params) ); } catch ( const fc::exception& e ) { - resp_body = fc::json::to_string( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e)} ) ); + resp_body = fc::json::to_string( fc::variant( fc::rpc::response( *call.id, error_object{ 1, e.to_detail_string(), fc::variant(e, _max_conversion_depth)} ), _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); resp_status = http::reply::InternalServerError; } } diff --git a/src/rpc/json_connection.cpp b/src/rpc/json_connection.cpp index bde046a..fd19f27 100755 --- a/src/rpc/json_connection.cpp +++ b/src/rpc/json_connection.cpp @@ -14,8 +14,8 @@ namespace fc { namespace rpc { class json_connection_impl { public: - json_connection_impl( fc::buffered_istream_ptr&& in, fc::buffered_ostream_ptr&& out ) - :_in(fc::move(in)),_out(fc::move(out)),_eof(false),_next_id(0),_logger("json_connection"){} + json_connection_impl( fc::buffered_istream_ptr&& in, fc::buffered_ostream_ptr&& out, uint32_t max_depth ) + :_in(fc::move(in)),_out(fc::move(out)),_eof(false),_next_id(0),_logger("json_connection"),_max_depth(max_depth){} fc::buffered_istream_ptr _in; fc::buffered_ostream_ptr _out; @@ -33,6 +33,7 @@ namespace fc { namespace rpc { std::function _on_close; logger _logger; + uint32_t _max_depth; void send_result( variant id, variant result ) { @@ -40,9 +41,9 @@ namespace fc { namespace rpc { { fc::scoped_lock lock(_write_mutex); *_out << "{\"id\":"; - json::to_stream( *_out, id ); + json::to_stream( *_out, id, json::stringify_large_ints_and_doubles, _max_depth ); *_out << ",\"result\":"; - json::to_stream( *_out, result); + json::to_stream( *_out, result, json::stringify_large_ints_and_doubles, _max_depth ); *_out << "}\n"; _out->flush(); } @@ -54,11 +55,11 @@ namespace fc { namespace rpc { { fc::scoped_lock lock(_write_mutex); *_out << "{\"id\":"; - json::to_stream( *_out, id ); + json::to_stream( *_out, id, json::stringify_large_ints_and_doubles, _max_depth ); *_out << ",\"error\":{\"message\":"; json::to_stream( *_out, fc::string(e.what()) ); *_out <<",\"code\":0,\"data\":"; - json::to_stream( *_out, variant(e)); + json::to_stream( *_out, variant(e, _max_depth), json::stringify_large_ints_and_doubles, _max_depth ); *_out << "}}\n"; _out->flush(); } @@ -165,10 +166,7 @@ namespace fc { namespace rpc { auto err = e->value().get_object(); auto data = err.find( "data" ); if( data != err.end() ) - { - //wlog( "exception: ${except}", ("except", data->value() ) ); - await->second->set_exception( data->value().as().dynamic_copy_exception() ); - } + await->second->set_exception( data->value().as(_max_depth).dynamic_copy_exception() ); else await->second->set_exception( exception_ptr(new FC_EXCEPTION( exception, "${error}", ("error",e->value()) ) ) ); } @@ -207,7 +205,7 @@ namespace fc { namespace rpc { fc::string line; while( !_done.canceled() ) { - variant v = json::from_stream(*_in); + variant v = json::from_stream( *_in, json::legacy_parser, _max_depth ); ///ilog( "input: ${in}", ("in", v ) ); //wlog( "recv: ${line}", ("line", line) ); _handle_message_future = fc::async([=](){ handle_message(v.get_object()); }, "json_connection handle_message"); @@ -242,8 +240,8 @@ namespace fc { namespace rpc { }; }//namespace detail - json_connection::json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out ) - :my( new detail::json_connection_impl(fc::move(in),fc::move(out)) ) + json_connection::json_connection( fc::buffered_istream_ptr in, fc::buffered_ostream_ptr out, uint32_t max_depth ) + :_max_conversion_depth(max_depth),my( new detail::json_connection_impl(fc::move(in),fc::move(out),max_depth) ) {} json_connection::~json_connection() diff --git a/src/rpc/websocket_api.cpp b/src/rpc/websocket_api.cpp index 8c60614..ae4e26e 100755 --- a/src/rpc/websocket_api.cpp +++ b/src/rpc/websocket_api.cpp @@ -7,8 +7,8 @@ websocket_api_connection::~websocket_api_connection() { } -websocket_api_connection::websocket_api_connection( fc::http::websocket_connection& c ) - : _connection(c) +websocket_api_connection::websocket_api_connection( fc::http::websocket_connection& c, uint32_t max_depth ) + : api_connection(max_depth),_connection(c) { _rpc_state.add_method( "call", [this]( const variants& args ) -> variant { @@ -58,7 +58,8 @@ variant websocket_api_connection::send_call( variants args /* = variants() */ ) { auto request = _rpc_state.start_remote_call( "call", {api_id, std::move(method_name), std::move(args) } ); - _connection.send_message( fc::json::to_string(request) ); + _connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); return _rpc_state.wait_for_response( *request.id ); } @@ -67,7 +68,8 @@ variant websocket_api_connection::send_callback( variants args /* = variants() */ ) { auto request = _rpc_state.start_remote_call( "callback", {callback_id, std::move(args) } ); - _connection.send_message( fc::json::to_string(request) ); + _connection.send_message( fc::json::to_string(fc::variant(request, _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); return _rpc_state.wait_for_response( *request.id ); } @@ -76,7 +78,8 @@ void websocket_api_connection::send_notice( variants args /* = variants() */ ) { fc::rpc::request req{ optional(), "notice", {callback_id, std::move(args)}}; - _connection.send_message( fc::json::to_string(req) ); + _connection.send_message( fc::json::to_string(fc::variant(req, _max_conversion_depth), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ) ); } std::string websocket_api_connection::on_message( @@ -85,12 +88,12 @@ std::string websocket_api_connection::on_message( { try { - auto var = fc::json::from_string(message); + auto var = fc::json::from_string(message, fc::json::legacy_parser, _max_conversion_depth); const auto& var_obj = var.get_object(); if( var_obj.contains( "method" ) ) { - auto call = var.as(); + auto call = var.as(_max_conversion_depth); exception_ptr optexcept; try { @@ -113,7 +116,7 @@ std::string websocket_api_connection::on_message( if( call.id ) { - auto reply = fc::json::to_string( response( *call.id, result, "2.0" ) ); + auto reply = fc::json::to_string( response( *call.id, result, "2.0" ), fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); if( send_message ) _connection.send_message( reply ); return reply; @@ -130,7 +133,8 @@ std::string websocket_api_connection::on_message( } if( optexcept ) { - auto reply = fc::json::to_string( response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept)}, "2.0" ) ); + auto reply = fc::json::to_string( variant(response( *call.id, error_object{ 1, optexcept->to_string(), fc::variant(*optexcept, _max_conversion_depth)}, "2.0" ), _max_conversion_depth ), + fc::json::stringify_large_ints_and_doubles, _max_conversion_depth ); if( send_message ) _connection.send_message( reply ); @@ -139,7 +143,7 @@ std::string websocket_api_connection::on_message( } else { - auto reply = var.as(); + auto reply = var.as(_max_conversion_depth); _rpc_state.handle_reply( reply ); } } diff --git a/src/string.cpp b/src/string.cpp index e04f439..2432360 100755 --- a/src/string.cpp +++ b/src/string.cpp @@ -258,7 +258,7 @@ namespace fc { } } - string format_string( const string& format, const variant_object& args ) + string format_string( const string& format, const variant_object& args, uint32_t max_object_depth ) { stringstream ss; size_t prev = 0; @@ -291,7 +291,7 @@ namespace fc { { try { - ss << json::to_string( val->value() ); + ss << json::to_string( val->value(), json::stringify_large_ints_and_doubles, max_object_depth ); } catch( const fc::assert_exception& e ) { diff --git a/src/time.cpp b/src/time.cpp index 27dd848..bf8857f 100755 --- a/src/time.cpp +++ b/src/time.cpp @@ -54,16 +54,16 @@ namespace fc { return time_point( time_point_sec::from_iso_string( s ) ); } FC_RETHROW_EXCEPTIONS( warn, "unable to convert ISO-formatted string to fc::time_point" ) } - void to_variant( const fc::time_point& t, variant& v ) { - v = fc::string( t ); + void to_variant( const fc::time_point& t, variant& v, uint32_t max_depth ) { + to_variant( fc::string( t ), v, max_depth ); } - void from_variant( const fc::variant& v, fc::time_point& t ) { + void from_variant( const fc::variant& v, fc::time_point& t, uint32_t max_depth ) { t = fc::time_point::from_iso_string( v.as_string() ); } - void to_variant( const fc::time_point_sec& t, variant& v ) { - v = fc::string( t ); + void to_variant( const fc::time_point_sec& t, variant& v, uint32_t max_depth ) { + to_variant( fc::string( t ), v, max_depth ); } - void from_variant( const fc::variant& v, fc::time_point_sec& t ) { + void from_variant( const fc::variant& v, fc::time_point_sec& t, uint32_t max_depth ) { t = fc::time_point_sec::from_iso_string( v.as_string() ); } @@ -134,11 +134,11 @@ namespace fc { return get_approximate_relative_time_string(time_point_sec(event_time), time_point_sec(relative_to_time), ago); } - void to_variant( const microseconds& input_microseconds, variant& output_variant ) + void to_variant( const microseconds& input_microseconds, variant& output_variant, uint32_t max_depth ) { output_variant = input_microseconds.count(); } - void from_variant( const variant& input_variant, microseconds& output_microseconds ) + void from_variant( const variant& input_variant, microseconds& output_microseconds, uint32_t max_depth ) { output_microseconds = microseconds(input_variant.as_int64()); } diff --git a/src/uint128.cpp b/src/uint128.cpp index 66128ce..5b12a4d 100755 --- a/src/uint128.cpp +++ b/src/uint128.cpp @@ -13,7 +13,7 @@ namespace fc template static void divide(const T &numerator, const T &denominator, T "ient, T &remainder) { - static const int bits = sizeof(T) * 8;//CHAR_BIT; + static const int bits = sizeof(T) * 8; if(denominator == 0) { throw std::domain_error("divide by zero"); @@ -228,22 +228,6 @@ namespace fc self /= other; hi = static_cast(self >> 64); lo = static_cast((self << 64 ) >> 64); - - /* - uint128 remainder; - divide(*this, b, *this, remainder ); //, *this); - if( tmp.hi != hi || tmp.lo != lo ) { - std::cerr << tmp.hi << " " << hi <<"\n"; - std::cerr << tmp.lo << " " << lo << "\n"; - exit(1); - } - */ - - /* - const auto& b128 = std::reinterpret_cast(b); - auto& this128 = std::reinterpret_cast(*this); - this128 /= b128; - */ return *this; } @@ -344,8 +328,6 @@ namespace fc result_hi = uint128( y[3], y[2] ); result_lo = uint128( y[1], y[0] ); - - return; } static uint8_t _popcount_64( uint64_t x ) @@ -374,8 +356,14 @@ namespace fc return _popcount_64( lo ) + _popcount_64( hi ); } - void to_variant( const uint128& var, variant& vo ) { vo = std::string(var); } - void from_variant( const variant& var, uint128& vo ){ vo = uint128(var.as_string()); } + void to_variant( const uint128& var, variant& vo, uint32_t max_depth ) + { + vo = std::string(var); + } + void from_variant( const variant& var, uint128& vo, uint32_t max_depth ) + { + vo = uint128(var.as_string()); + } } // namespace fc diff --git a/src/variant.cpp b/src/variant.cpp index 5d9416a..ef28bc5 100755 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -27,140 +27,139 @@ variant::variant() set_variant_type( this, null_type ); } -variant::variant( fc::nullptr_t ) +variant::variant( fc::nullptr_t, uint32_t max_depth ) { set_variant_type( this, null_type ); } -variant::variant( uint8_t val ) +variant::variant( uint8_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } -variant::variant( int8_t val ) +variant::variant( int8_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } -variant::variant( uint16_t val ) +variant::variant( uint16_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } -variant::variant( int16_t val ) +variant::variant( int16_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } -variant::variant( uint32_t val ) +variant::variant( uint32_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } -variant::variant( int32_t val ) +variant::variant( int32_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } -variant::variant( uint64_t val ) +variant::variant( uint64_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, uint64_type ); } -variant::variant( int64_t val ) +variant::variant( int64_t val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, int64_type ); } -variant::variant( float val ) +variant::variant( float val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, double_type ); } -variant::variant( double val ) +variant::variant( double val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, double_type ); } -variant::variant( bool val ) +variant::variant( bool val, uint32_t max_depth ) { *reinterpret_cast(this) = val; set_variant_type( this, bool_type ); } -variant::variant( char* str ) +variant::variant( char* str, uint32_t max_depth ) { *reinterpret_cast(this) = new string( str ); set_variant_type( this, string_type ); } -variant::variant( const char* str ) +variant::variant( const char* str, uint32_t max_depth ) { *reinterpret_cast(this) = new string( str ); set_variant_type( this, string_type ); } // TODO: do a proper conversion to utf8 -variant::variant( wchar_t* str ) +variant::variant( wchar_t* str, uint32_t max_depth ) { size_t len = wcslen(str); boost::scoped_array buffer(new char[len]); for (unsigned i = 0; i < len; ++i) - buffer[i] = (char)str[i]; + buffer[i] = (char)str[i]; *reinterpret_cast(this) = new string(buffer.get(), len); set_variant_type( this, string_type ); } // TODO: do a proper conversion to utf8 -variant::variant( const wchar_t* str ) +variant::variant( const wchar_t* str, uint32_t max_depth ) { size_t len = wcslen(str); boost::scoped_array buffer(new char[len]); for (unsigned i = 0; i < len; ++i) - buffer[i] = (char)str[i]; + buffer[i] = (char)str[i]; *reinterpret_cast(this) = new string(buffer.get(), len); set_variant_type( this, string_type ); } -variant::variant( fc::string val ) +variant::variant( fc::string val, uint32_t max_depth ) { *reinterpret_cast(this) = new string( fc::move(val) ); set_variant_type( this, string_type ); } -variant::variant( blob val ) +variant::variant( blob val, uint32_t max_depth ) { *reinterpret_cast(this) = new blob( fc::move(val) ); set_variant_type( this, blob_type ); } -variant::variant( variant_object obj) +variant::variant( variant_object obj, uint32_t max_depth ) { - *reinterpret_cast(this) = new variant_object(fc::move(obj)); + *reinterpret_cast(this) = new variant_object(fc::move(obj)); set_variant_type(this, object_type ); } -variant::variant( mutable_variant_object obj) +variant::variant( mutable_variant_object obj, uint32_t max_depth ) { - *reinterpret_cast(this) = new variant_object(fc::move(obj)); + *reinterpret_cast(this) = new variant_object(fc::move(obj)); set_variant_type(this, object_type ); } -variant::variant( variants arr ) +variant::variant( variants arr, uint32_t max_depth ) { *reinterpret_cast(this) = new variants(fc::move(arr)); set_variant_type(this, array_type ); } - typedef const variant_object* const_variant_object_ptr; typedef const variants* const_variants_ptr; typedef const blob* const_blob_ptr; @@ -185,7 +184,7 @@ void variant::clear() set_variant_type( this, null_type ); } -variant::variant( const variant& v ) +variant::variant( const variant& v, uint32_t max_depth ) { switch( v.get_type() ) { @@ -209,7 +208,7 @@ variant::variant( const variant& v ) } } -variant::variant( variant&& v ) +variant::variant( variant&& v, uint32_t max_depth ) { memcpy( this, &v, sizeof(v) ); set_variant_type( &v, null_type ); @@ -575,88 +574,85 @@ const variant_object& variant::get_object()const FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from type '${type}' to Object", ("type",get_type()) ); } -void from_variant( const variant& var, variants& vo ) +void from_variant( const variant& var, variants& vo, uint32_t max_depth ) { vo = var.get_array(); } -//void from_variant( const variant& var, variant_object& vo ) -//{ -// vo = var.get_object(); -//} +void from_variant( const variant& var, variant& vo, uint32_t max_depth ) { vo = var; } -void from_variant( const variant& var, variant& vo ) { vo = var; } - -void to_variant( const uint8_t& var, variant& vo ) { vo = uint64_t(var); } +void to_variant( const uint8_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); } // TODO: warn on overflow? -void from_variant( const variant& var, uint8_t& vo ){ vo = static_cast(var.as_uint64()); } +void from_variant( const variant& var, uint8_t& vo, uint32_t max_depth ){ vo = static_cast(var.as_uint64()); } -void to_variant( const int8_t& var, variant& vo ) { vo = int64_t(var); } +void to_variant( const int8_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); } // TODO: warn on overflow? -void from_variant( const variant& var, int8_t& vo ){ vo = static_cast(var.as_int64()); } +void from_variant( const variant& var, int8_t& vo, uint32_t max_depth ) { vo = static_cast(var.as_int64()); } -void to_variant( const uint16_t& var, variant& vo ) { vo = uint64_t(var); } +void to_variant( const uint16_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); } // TODO: warn on overflow? -void from_variant( const variant& var, uint16_t& vo ){ vo = static_cast(var.as_uint64()); } +void from_variant( const variant& var, uint16_t& vo, uint32_t max_depth ){ vo = static_cast(var.as_uint64()); } -void to_variant( const int16_t& var, variant& vo ) { vo = int64_t(var); } +void to_variant( const int16_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); } // TODO: warn on overflow? -void from_variant( const variant& var, int16_t& vo ){ vo = static_cast(var.as_int64()); } +void from_variant( const variant& var, int16_t& vo, uint32_t max_depth ){ vo = static_cast(var.as_int64()); } -void to_variant( const uint32_t& var, variant& vo ) { vo = uint64_t(var); } -void from_variant( const variant& var, uint32_t& vo ) +void to_variant( const uint32_t& var, variant& vo, uint32_t max_depth ) { vo = uint64_t(var); } +void from_variant( const variant& var, uint32_t& vo, uint32_t max_depth ) { vo = static_cast(var.as_uint64()); } -void to_variant( const int32_t& var, variant& vo ) { vo = int64_t(var); } -void from_variant( const variant& var, int32_t& vo ) +void to_variant( const int32_t& var, variant& vo, uint32_t max_depth ) { vo = int64_t(var); } +void from_variant( const variant& var,int32_t& vo, uint32_t max_depth ) { vo = static_cast(var.as_int64()); } -void from_variant( const variant& var, int64_t& vo ) +void to_variant( const int64_t& var, variant& vo, uint32_t max_depth ) { vo = var; } +void from_variant( const variant& var, int64_t& vo, uint32_t max_depth ) { vo = var.as_int64(); } -void from_variant( const variant& var, uint64_t& vo ) +void to_variant( const uint64_t& var, variant& vo, uint32_t max_depth ) { vo = var; } +void from_variant( const variant& var, uint64_t& vo, uint32_t max_depth ) { vo = var.as_uint64(); } -void from_variant( const variant& var, bool& vo ) +void from_variant( const variant& var, bool& vo, uint32_t max_depth ) { vo = var.as_bool(); } -void from_variant( const variant& var, double& vo ) +void from_variant( const variant& var, double& vo, uint32_t max_depth ) { vo = var.as_double(); } -void from_variant( const variant& var, float& vo ) +void from_variant( const variant& var, float& vo, uint32_t max_depth ) { vo = static_cast(var.as_double()); } -void to_variant( const std::string& s, variant& v ) +void to_variant( const std::string& s, variant& v, uint32_t max_depth ) { - v = variant( fc::string(s) ); + v = variant( fc::string(s), max_depth ); } -void from_variant( const variant& var, string& vo ) +void from_variant( const variant& var, string& vo, uint32_t max_depth ) { vo = var.as_string(); } -void to_variant( const std::vector& var, variant& vo ) +void to_variant( const std::vector& var, variant& vo, uint32_t max_depth ) { if( var.size() ) vo = variant(to_hex(var.data(),var.size())); else vo = ""; } -void from_variant( const variant& var, std::vector& vo ) +void from_variant( const variant& var, std::vector& vo, uint32_t max_depth ) { auto str = var.as_string(); vo.resize( str.size() / 2 ); @@ -665,15 +661,13 @@ void from_variant( const variant& var, std::vector& vo ) size_t r = from_hex( str, vo.data(), vo.size() ); FC_ASSERT( r == vo.size() ); } -// std::string b64 = base64_decode( var.as_string() ); -// vo = std::vector( b64.c_str(), b64.c_str() + b64.size() ); } - #ifdef __APPLE__ - #elif !defined(_MSC_VER) - void to_variant( long long int s, variant& v ) { v = variant( int64_t(s) ); } - void to_variant( unsigned long long int s, variant& v ) { v = variant( uint64_t(s)); } - #endif +#ifdef __APPLE__ +#elif !defined(_MSC_VER) + void to_variant( long long int s, variant& v, uint32_t max_depth ) { v = variant( int64_t(s) ); } + void to_variant( unsigned long long int s, variant& v, uint32_t max_depth ) { v = variant( uint64_t(s)); } +#endif variant operator == ( const variant& a, const variant& b ) { diff --git a/src/variant_object.cpp b/src/variant_object.cpp index 6f3b1dc..55c3181 100755 --- a/src/variant_object.cpp +++ b/src/variant_object.cpp @@ -103,7 +103,6 @@ namespace fc variant_object::variant_object( string key, variant val ) : _key_value(std::make_shared>()) { - //_key_value->push_back(entry(fc::move(key), fc::move(val))); _key_value->emplace_back(entry(fc::move(key), fc::move(val))); } @@ -163,12 +162,12 @@ namespace fc return *this; } - void to_variant( const variant_object& var, variant& vo ) + void to_variant( const variant_object& var, variant& vo, uint32_t max_depth ) { vo = variant(var); } - void from_variant( const variant& var, variant_object& vo ) + void from_variant( const variant& var, variant_object& vo, uint32_t max_depth ) { vo = var.get_object(); } @@ -344,7 +343,7 @@ namespace fc /** Appends \a key and \a var without checking for duplicates, designed to * simplify construction of dictionaries using (key,val)(key2,val2) syntax */ - mutable_variant_object& mutable_variant_object::operator()( string key, variant var ) + mutable_variant_object& mutable_variant_object::operator()( string key, variant var, uint32_t max_depth ) { _key_value->push_back( entry( fc::move(key), fc::move(var) ) ); return *this; @@ -366,12 +365,24 @@ namespace fc return *this; } - void to_variant( const mutable_variant_object& var, variant& vo ) + limited_mutable_variant_object::limited_mutable_variant_object( uint32_t m ) + : mutable_variant_object(), _max_depth(m - 1) + { + FC_ASSERT( m > 0, "Recursion depth exceeded!" ); + } + + limited_mutable_variant_object& limited_mutable_variant_object::operator()( const variant_object& vo ) + { + mutable_variant_object::operator()( vo ); + return *this; + } + + void to_variant( const mutable_variant_object& var, variant& vo, uint32_t max_depth ) { vo = variant(var); } - void from_variant( const variant& var, mutable_variant_object& vo ) + void from_variant( const variant& var, mutable_variant_object& vo, uint32_t max_depth ) { vo = var.get_object(); } diff --git a/tests/api.cpp b/tests/api.cpp index 4fcd8b5..e0514c3 100755 --- a/tests/api.cpp +++ b/tests/api.cpp @@ -52,6 +52,8 @@ class variant_calculator using namespace fc::http; using namespace fc::rpc; +#define MAX_DEPTH 10 + int main( int argc, char** argv ) { try { @@ -59,7 +61,7 @@ int main( int argc, char** argv ) fc::http::websocket_server server; server.on_connection([&]( const websocket_connection_ptr& c ){ - auto wsc = std::make_shared(*c); + auto wsc = std::make_shared(*c, MAX_DEPTH); auto login = std::make_shared(); login->calc = calc_api; wsc->register_api(fc::api(login)); @@ -74,7 +76,7 @@ int main( int argc, char** argv ) try { fc::http::websocket_client client; auto con = client.connect( "ws://localhost:8090" ); - auto apic = std::make_shared(*con); + auto apic = std::make_shared(*con, MAX_DEPTH); auto remote_login_api = apic->get_remote_api(); auto remote_calc = remote_login_api->get_calc(); remote_calc->on_result( []( uint32_t r ) { elog( "callback result ${r}", ("r",r) ); } ); @@ -167,8 +169,8 @@ int main( int argc, char** argv ) fc::api napi(&napi_impl); - auto client_side = std::make_shared(); - auto server_side = std::make_shared(); + auto client_side = std::make_shared(MAX_DEPTH); + auto server_side = std::make_shared(MAX_DEPTH); server_side->set_remote_connection( client_side ); client_side->set_remote_connection( server_side ); diff --git a/tests/crypto/sha_tests.cpp b/tests/crypto/sha_tests.cpp index 850c2f8..675d0db 100755 --- a/tests/crypto/sha_tests.cpp +++ b/tests/crypto/sha_tests.cpp @@ -65,8 +65,8 @@ void test_big( const std::string& expected ) { H hash2( expected ); fc::variant v; - to_variant( hash2, v ); - from_variant( v, hash ); + to_variant( hash2, v, 5 ); + from_variant( v, hash, 5 ); BOOST_CHECK( hash == hash2 ); H hash3( expected.substr(15) + "000000000000000" ); diff --git a/tests/io/json_tests.cpp b/tests/io/json_tests.cpp index 42af936..e06f51b 100644 --- a/tests/io/json_tests.cpp +++ b/tests/io/json_tests.cpp @@ -128,9 +128,9 @@ static bool equal( const fc::variant& a, const fc::variant& b ) { auto a_type = a.get_type(); auto b_type = b.get_type(); - if( a_type == fc::variant::type_id::int64_type && a.as() > 0 ) + if( a_type == fc::variant::type_id::int64_type && a.as(1) > 0 ) a_type = fc::variant::type_id::uint64_type; - if( b_type == fc::variant::type_id::int64_type && b.as() > 0 ) + if( b_type == fc::variant::type_id::int64_type && b.as(1) > 0 ) b_type = fc::variant::type_id::uint64_type; if( a_type != b_type ) { @@ -138,17 +138,17 @@ static bool equal( const fc::variant& a, const fc::variant& b ) && b_type == fc::variant::type_id::string_type ) || ( a_type == fc::variant::type_id::string_type && b_type == fc::variant::type_id::double_type ) ) - return a.as() == b.as(); + return a.as(1) == b.as(1); return false; } switch( a_type ) { case fc::variant::type_id::null_type: return true; - case fc::variant::type_id::int64_type: return a.as() == b.as(); - case fc::variant::type_id::uint64_type: return a.as() == b.as(); - case fc::variant::type_id::double_type: return a.as() == b.as(); - case fc::variant::type_id::bool_type: return a.as() == b.as(); - case fc::variant::type_id::string_type: return a.as() == b.as(); + case fc::variant::type_id::int64_type: return a.as(1) == b.as(1); + case fc::variant::type_id::uint64_type: return a.as(1) == b.as(1); + case fc::variant::type_id::double_type: return a.as(1) == b.as(1); + case fc::variant::type_id::bool_type: return a.as(1) == b.as(1); + case fc::variant::type_id::string_type: return a.as(1) == b.as(1); case fc::variant::type_id::array_type: if( a.get_array().size() != b.get_array().size() ) return false; else @@ -311,8 +311,8 @@ BOOST_AUTO_TEST_CASE(structured_test) BOOST_AUTO_TEST_CASE(precision_test) { - BOOST_CHECK_EQUAL( "\"4294967296\"", fc::json::to_string( fc::variant( 0x100000000LL ) ) ); - BOOST_CHECK_EQUAL( "\"-4294967296\"", fc::json::to_string( fc::variant( -0x100000000LL ) ) ); + BOOST_CHECK_EQUAL( "\"4294967296\"", fc::json::to_string( fc::variant( int64_t(0x100000000LL) ) ) ); + BOOST_CHECK_EQUAL( "\"-4294967296\"", fc::json::to_string( fc::variant( int64_t(-0x100000000LL) ) ) ); std::string half = fc::json::to_string( fc::variant( 0.5 ) ); BOOST_CHECK_EQUAL( '"', half.front() ); BOOST_CHECK_EQUAL( '"', half.back() ); diff --git a/tests/network/http/websocket_test.cpp b/tests/network/http/websocket_test.cpp index 03bfdd1..d377bc7 100755 --- a/tests/network/http/websocket_test.cpp +++ b/tests/network/http/websocket_test.cpp @@ -64,6 +64,10 @@ BOOST_AUTO_TEST_CASE(websocket_test) BOOST_FAIL("expected assertion failure"); } catch (const fc::assert_exception& e) { std::cerr << e.to_string() << "\n"; + } catch (const fc::exception& e) { + BOOST_FAIL("Unexpected exception: " + e.to_string()); + } catch (const std::exception& e) { + BOOST_FAIL("Unexpected exception: " + std::string(e.what())); } }