diff --git a/include/fc/crypto/base64.hpp b/include/fc/crypto/base64.hpp index ee92618..012a19f 100644 --- a/include/fc/crypto/base64.hpp +++ b/include/fc/crypto/base64.hpp @@ -3,6 +3,7 @@ namespace fc { std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len); +inline std::string base64_encode(char const* bytes_to_encode, unsigned int in_len) { return base64_encode( (unsigned char const*)bytes_to_encode, in_len); } std::string base64_encode( const std::string& enc ); std::string base64_decode( const std::string& encoded_string); } // namespace fc diff --git a/include/fc/variant.hpp b/include/fc/variant.hpp index 553c96c..c9c2d29 100644 --- a/include/fc/variant.hpp +++ b/include/fc/variant.hpp @@ -31,6 +31,11 @@ namespace fc class time_point_sec; class microseconds; + 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 uint8_t& var, variant& vo ); void from_variant( const variant& var, uint8_t& vo ); void to_variant( const int8_t& var, variant& vo ); @@ -105,6 +110,7 @@ namespace fc template void from_variant( const variant& v, std::pair& p ); + /** * @brief stores null, int64, uint64, double, bool, string, std::vector, * and variant_object's. @@ -126,7 +132,8 @@ namespace fc bool_type = 4, string_type = 5, array_type = 6, - object_type = 7 + object_type = 7, + blob_type = 8 }; /// Constructs a null_type variant @@ -150,6 +157,7 @@ namespace fc variant( int64_t val ); variant( double val ); variant( bool val ); + variant( blob val ); variant( fc::string val ); variant( variant_object ); variant( mutable_variant_object ); @@ -188,16 +196,25 @@ namespace fc bool is_double()const; bool is_object()const; bool is_array()const; + bool is_blob()const; /** * int64, uint64, double,bool */ bool is_numeric()const; + /** + * int64, uint64, bool + */ + bool is_integer()const; int64_t as_int64()const; uint64_t as_uint64()const; bool as_bool()const; double as_double()const; + blob& get_blob(); + const blob& get_blob()const; + blob as_blob()const; + /** Convert's double, ints, bools, etc to a string * @throw if get_type() == array_type | get_type() == object_type */ @@ -464,8 +481,18 @@ namespace fc } } + variant operator + ( const variant& a, const variant& b ); + variant operator - ( const variant& a, const variant& b ); + variant operator * ( const variant& a, const variant& b ); + variant operator / ( const variant& a, const variant& b ); + variant operator == ( const variant& a, const variant& b ); + variant operator != ( const variant& a, const variant& b ); + variant operator < ( const variant& a, const variant& b ); + variant operator > ( const variant& a, const variant& b ); + variant operator ! ( const variant& a ); } // namespace fc #include FC_REFLECT_TYPENAME( fc::variant ) -FC_REFLECT_ENUM( fc::variant::type_id, (null_type)(int64_type)(uint64_type)(double_type)(bool_type)(string_type)(array_type)(object_type) ) +FC_REFLECT_ENUM( fc::variant::type_id, (null_type)(int64_type)(uint64_type)(double_type)(bool_type)(string_type)(array_type)(object_type)(blob_type) ) +FC_REFLECT( fc::blob, (data) ); diff --git a/src/io/json.cpp b/src/io/json.cpp index c25b0be..226bee1 100644 --- a/src/io/json.cpp +++ b/src/io/json.cpp @@ -534,6 +534,9 @@ namespace fc case variant::string_type: escape_string( v.get_string(), os ); return; + case variant::blob_type: + escape_string( v.as_string(), os ); + return; case variant::array_type: { const variants& a = v.get_array(); diff --git a/src/variant.cpp b/src/variant.cpp index a72dbd5..df5d716 100644 --- a/src/variant.cpp +++ b/src/variant.cpp @@ -5,7 +5,7 @@ #include #include #include -//#include +#include #include #include #include @@ -136,6 +136,11 @@ variant::variant( fc::string val ) *reinterpret_cast(this) = new string( fc::move(val) ); set_variant_type( this, string_type ); } +variant::variant( blob val ) +{ + *reinterpret_cast(this) = new blob( fc::move(val) ); + set_variant_type( this, blob_type ); +} variant::variant( variant_object obj) { @@ -157,6 +162,7 @@ variant::variant( variants arr ) typedef const variant_object* const_variant_object_ptr; typedef const variants* const_variants_ptr; +typedef const blob* const_blob_ptr; typedef const string* const_string_ptr; void variant::clear() @@ -313,6 +319,19 @@ bool variant::is_int64()const return get_type() == int64_type; } +bool variant::is_integer()const +{ + switch( get_type() ) + { + case int64_type: + case uint64_type: + case bool_type: + return true; + default: + return false; + } + return false; +} bool variant::is_numeric()const { switch( get_type() ) @@ -337,6 +356,10 @@ bool variant::is_array()const { return get_type() == array_type; } +bool variant::is_blob()const +{ + return get_type() == blob_type; +} int64_t variant::as_int64()const { @@ -437,6 +460,10 @@ string variant::as_string()const return to_string(*reinterpret_cast(this)); case bool_type: return *reinterpret_cast(this) ? "true" : "false"; + case blob_type: + if( get_blob().data.size() ) + return base64_encode( get_blob().data.data(), get_blob().data.size() ) + "="; + return string(); case null_type: return string(); default: @@ -453,6 +480,45 @@ variants& variant::get_array() FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Array", ("type",get_type()) ); } +blob& variant::get_blob() +{ + if( get_type() == blob_type ) + return **reinterpret_cast(this); + + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) ); +} +const blob& variant::get_blob()const +{ + if( get_type() == blob_type ) + return **reinterpret_cast(this); + + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) ); +} + +blob variant::as_blob()const +{ + switch( get_type() ) + { + case null_type: return blob(); + case blob_type: return get_blob(); + case string_type: + { + const string& str = get_string(); + if( str.size() == 0 ) return blob(); + if( str.back() == '=' ) + { + std::string b64 = base64_decode( get_string() ); + return blob( { std::vector( b64.begin(), b64.end() ) } ); + } + return blob( { std::vector( str.begin(), str.end() ) } ); + } + case object_type: + case array_type: + FC_THROW_EXCEPTION( bad_cast_exception, "Invalid cast from ${type} to Blob", ("type",get_type()) ); + default: + return blob( { std::vector( (char*)&_data, (char*)&_data + sizeof(_data) ) } ); + } +} /// @throw if get_type() != array_type @@ -579,7 +645,6 @@ void from_variant( const variant& var, string& vo ) void to_variant( const std::vector& var, variant& vo ) { if( var.size() ) - //vo = variant(base64_encode((unsigned char*)var.data(),var.size())); vo = variant(to_hex(var.data(),var.size())); else vo = ""; } @@ -662,4 +727,158 @@ string format_string( const string& format, const variant_object& args ) void to_variant( unsigned long long int s, variant& v ) { v = variant( uint16_t(s)); } #endif + variant operator == ( const variant& a, const variant& b ) + { + if( a.is_string() || b.is_string() ) return a.as_string() == b.as_string(); + if( a.is_double() || b.is_double() ) return a.as_double() == b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() == b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() == b.as_uint64(); + return false; + } + + variant operator != ( const variant& a, const variant& b ) + { + if( a.is_string() || b.is_string() ) return a.as_string() != b.as_string(); + if( a.is_double() || b.is_double() ) return a.as_double() != b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() != b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() != b.as_uint64(); + return false; + } + + variant operator ! ( const variant& a ) + { + return !a.as_bool(); + } + + variant operator < ( const variant& a, const variant& b ) + { + if( a.is_string() || b.is_string() ) return a.as_string() < b.as_string(); + if( a.is_double() || b.is_double() ) return a.as_double() < b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() < b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() < b.as_uint64(); + FC_ASSERT( false, "Invalid operation" ); + } + + variant operator > ( const variant& a, const variant& b ) + { + if( a.is_string() || b.is_string() ) return a.as_string() > b.as_string(); + if( a.is_double() || b.is_double() ) return a.as_double() > b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() > b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() > b.as_uint64(); + FC_ASSERT( false, "Invalid operation" ); + } + + variant operator <= ( const variant& a, const variant& b ) + { + if( a.is_string() || b.is_string() ) return a.as_string() <= b.as_string(); + if( a.is_double() || b.is_double() ) return a.as_double() <= b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() <= b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() <= b.as_uint64(); + FC_ASSERT( false, "Invalid operation" ); + } + + + variant operator + ( const variant& a, const variant& b ) + { + if( a.is_array() && b.is_array() ) + { + const variants& aa = a.get_array(); + const variants& ba = b.get_array(); + variants result; + result.reserve( std::max(aa.size(),ba.size()) ); + auto num = std::max(aa.size(),ba.size()); + for( uint64_t i = 0; i < num; ++i ) + { + if( aa.size() > i && ba.size() > i ) + result[i] = aa[i] + ba[i]; + else if( aa.size() > i ) + result[i] = aa[i]; + else + result[i] = ba[i]; + } + return result; + } + if( a.is_string() || b.is_string() ) return a.as_string() + b.as_string(); + if( a.is_double() || b.is_double() ) return a.as_double() + b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() + b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() + b.as_uint64(); + FC_ASSERT( false, "invalid operation ${a} + ${b}", ("a",a)("b",b) ); + } + + variant operator - ( const variant& a, const variant& b ) + { + if( a.is_array() && b.is_array() ) + { + const variants& aa = a.get_array(); + const variants& ba = b.get_array(); + variants result; + result.reserve( std::max(aa.size(),ba.size()) ); + auto num = std::max(aa.size(),ba.size()); + for( uint64_t i = 0; i < num; --i ) + { + if( aa.size() > i && ba.size() > i ) + result[i] = aa[i] - ba[i]; + else if( aa.size() > i ) + result[i] = aa[i]; + else + result[i] = ba[i]; + } + return result; + } + if( a.is_string() || b.is_string() ) return a.as_string() - b.as_string(); + if( a.is_double() || b.is_double() ) return a.as_double() - b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() - b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() - b.as_uint64(); + FC_ASSERT( false, "invalid operation ${a} + ${b}", ("a",a)("b",b) ); + } + variant operator * ( const variant& a, const variant& b ) + { + if( a.is_double() || b.is_double() ) return a.as_double() * b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() * b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() * b.as_uint64(); + if( a.is_array() && b.is_array() ) + { + const variants& aa = a.get_array(); + const variants& ba = b.get_array(); + variants result; + result.reserve( std::max(aa.size(),ba.size()) ); + auto num = std::max(aa.size(),ba.size()); + for( uint64_t i = 0; i < num; ++i ) + { + if( aa.size() > i && ba.size() > i ) + result[i] = aa[i] * ba[i]; + else if( aa.size() > i ) + result[i] = aa[i]; + else + result[i] = ba[i]; + } + return result; + } + FC_ASSERT( false, "invalid operation ${a} * ${b}", ("a",a)("b",b) ); + } + variant operator / ( const variant& a, const variant& b ) + { + if( a.is_double() || b.is_double() ) return a.as_double() / b.as_double(); + if( a.is_int64() || b.is_int64() ) return a.as_int64() / b.as_int64(); + if( a.is_uint64() || b.is_uint64() ) return a.as_uint64() / b.as_uint64(); + if( a.is_array() && b.is_array() ) + { + const variants& aa = a.get_array(); + const variants& ba = b.get_array(); + variants result; + result.reserve( std::max(aa.size(),ba.size()) ); + auto num = std::max(aa.size(),ba.size()); + for( uint64_t i = 0; i < num; ++i ) + { + if( aa.size() > i && ba.size() > i ) + result[i] = aa[i] / ba[i]; + else if( aa.size() > i ) + result[i] = aa[i]; + else + result[i] = ba[i]; + } + return result; + } + FC_ASSERT( false, "invalid operation ${a} / ${b}", ("a",a)("b",b) ); + } } // namespace fc