diff --git a/libretroshare/src/serialiser/rstypeserializer.cc b/libretroshare/src/serialiser/rstypeserializer.cc index 1ea3add9a..7cf799d0f 100644 --- a/libretroshare/src/serialiser/rstypeserializer.cc +++ b/libretroshare/src/serialiser/rstypeserializer.cc @@ -503,8 +503,16 @@ bool RsTypeSerializer::from_JSON( const std::string& /*memberName*/, // Binary blocks // //============================================================================// +#if __cplusplus < 201703L +/* Solve weird undefined reference error with C++ < 17 see: + * https://stackoverflow.com/questions/8016780/undefined-reference-to-static-constexpr-char + */ +/*static*/ decltype(RsTypeSerializer::RawMemoryWrapper::base64_key) constexpr +RsTypeSerializer::RawMemoryWrapper::base64_key; + /*static*/ /* without this Android compilation breaks */ constexpr uint32_t RsTypeSerializer::RawMemoryWrapper::MAX_SERIALIZED_CHUNK_SIZE; +#endif /*static*/ void RsTypeSerializer::RawMemoryWrapper::serial_process( @@ -542,18 +550,7 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( ctx.mOffset += second; break; case RsGenericSerializer::DESERIALIZE: - if(first || second) - { - /* Items are created anew before deserialization so buffer pointer - * must be null and size 0 at this point */ - - RsWarn() << __PRETTY_FUNCTION__ << " DESERIALIZE got uninitialized " - << " or pre-allocated buffer! Buffer pointer: " << first - << " must be null and size: " << second << " must be 0 at " - << "this point. Does your item costructor initialize them " - << "properly?" << std::endl; - print_stacktrace(); - } + freshMemCheck(); RS_SERIAL_PROCESS(second); if(!ctx.mOk) break; @@ -597,44 +594,33 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( if(!ctx.mOk) break; std::string encodedValue; RsBase64::encode(first, second, encodedValue, true, false); - ctx.mJson.SetString( - encodedValue.data(), - static_cast(encodedValue.length()), - ctx.mJson.GetAllocator()); + ctx.mOk = ctx.mOk && + RsTypeSerializer::to_JSON(base64_key, encodedValue, ctx.mJson); break; } case RsGenericSerializer::FROM_JSON: { - const bool yelding = !!( - RsSerializationFlags::YIELDING & ctx.mFlags ); - if(!(ctx.mOk || yelding)) - { - clear(); - break; - } - if(!ctx.mJson.IsString()) - { - RsErr() << __PRETTY_FUNCTION__ << " " - << std::errc::invalid_argument << std::endl; - print_stacktrace(); + freshMemCheck(); - ctx.mOk = false; - clear(); - break; - } - if( ctx.mJson.GetStringLength() > + const auto failure = [&]() -> void { ctx.mOk = false; clear(); }; + const bool yielding = !!( + RsSerializationFlags::YIELDING & ctx.mFlags ); + if(!(ctx.mOk || yielding)) return failure(); + + std::string encodedValue; + if(!RsTypeSerializer::from_JSON( + base64_key, encodedValue, ctx.mJson )) return failure(); + + if( encodedValue.length() > RsBase64::encodedSize(MAX_SERIALIZED_CHUNK_SIZE, true) ) { RsErr() << __PRETTY_FUNCTION__ << " " << std::errc::message_size << std::endl; print_stacktrace(); - ctx.mOk = false; - clear(); - break; + return failure(); } - std::string encodedValue = ctx.mJson.GetString(); std::vector decoded; auto ec = RsBase64::decode(encodedValue, decoded); if(ec) @@ -642,9 +628,7 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( RsErr() << __PRETTY_FUNCTION__ << " " << ec << std::endl; print_stacktrace(); - ctx.mOk = false; - clear(); - break; + return failure(); } const auto decodedSize = decoded.size(); @@ -655,11 +639,8 @@ void RsTypeSerializer::RawMemoryWrapper::serial_process( break; } - if(decodedSize != second) - { - first = reinterpret_cast(realloc(first, decodedSize)); - second = static_cast(decodedSize); - } + first = reinterpret_cast(malloc(decodedSize)); + second = static_cast(decodedSize); memcpy(first, decoded.data(), second); break; @@ -675,6 +656,24 @@ void RsTypeSerializer::RawMemoryWrapper::clear() second = 0; } +bool RsTypeSerializer::RawMemoryWrapper::freshMemCheck() +{ + if(first || second) + { + /* Items are created anew before deserialization so buffer pointer + * must be null and size 0 at this point */ + + RsWarn() << __PRETTY_FUNCTION__ << " got uninitialized " + << " or pre-allocated buffer! Buffer pointer: " << first + << " must be null and size: " << second << " must be 0 at " + << "this point. Does your item costructor initialize them " + << "properly?" << std::endl; + print_stacktrace(); + return false; + } + return true; +} + //============================================================================// // std::error_condition // //============================================================================// diff --git a/libretroshare/src/serialiser/rstypeserializer.h b/libretroshare/src/serialiser/rstypeserializer.h index d72280bb3..3c8af510e 100644 --- a/libretroshare/src/serialiser/rstypeserializer.h +++ b/libretroshare/src/serialiser/rstypeserializer.h @@ -59,12 +59,17 @@ struct RsTypeSerializer /// Maximum supported size 10MB static constexpr uint32_t MAX_SERIALIZED_CHUNK_SIZE = 10*1024*1024; + /** Key used for JSON serialization. + * @note Changing this value breaks JSON API retro-compatibility */ + static constexpr char base64_key[] = "base64"; + /// @see RsSerializable void serial_process( RsGenericSerializer::SerializeJob j, RsGenericSerializer::SerializeContext& ctx ) override; private: void clear(); + bool freshMemCheck(); }; /// Most types are not valid sequence containers @@ -777,9 +782,9 @@ struct RsTypeSerializer { if(!yielding) { - std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName - << "\" not found in JSON:" << std::endl - << jDoc << std::endl << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " \"" << memberName + << "\" not found in JSON:" << std::endl + << jDoc << std::endl << std::endl; print_stacktrace(); } ctx.mOk = false; @@ -790,9 +795,9 @@ struct RsTypeSerializer if(!v.IsObject()) { - std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName - << "\" has wrong type in JSON, object expected, got:" - << std::endl << jDoc << std::endl << std::endl; + RsErr() << __PRETTY_FUNCTION__ << " \"" << memberName + << "\" has wrong type in JSON, object expected, got:" + << std::endl << jDoc << std::endl << std::endl; print_stacktrace(); ctx.mOk = false; break; diff --git a/libretroshare/src/util/rsdebug.h b/libretroshare/src/util/rsdebug.h index c333bd255..01a8b94df 100644 --- a/libretroshare/src/util/rsdebug.h +++ b/libretroshare/src/util/rsdebug.h @@ -32,6 +32,8 @@ std::ostream &operator<<(std::ostream& out, const std::error_condition& err); # include # include +# include "util/rsjson.h" + enum class RsLoggerCategories { DEBUG = ANDROID_LOG_DEBUG, @@ -55,6 +57,10 @@ struct t_RsLogger inline stream_type& operator<<(const T& val) { ostr << val; return *this; } + template + inline stream_type& operator<<(const RsJson& val) + { ostr << val; return *this; } + /// needed for manipulators and things like std::endl stream_type& operator<<(std::ostream& (*pf)(std::ostream&)) { @@ -111,7 +117,7 @@ struct t_RsLogger const auto now = system_clock::now(); const auto sec = time_point_cast(now); const auto msec = duration_cast(now - sec); - std::stringstream tstream; + std::ostringstream tstream; tstream << static_cast(CATEGORY) << " " << sec.time_since_epoch().count() << "." << std::setfill('0') << std::setw(3) << msec.count() diff --git a/libretroshare/src/util/rsjson.h b/libretroshare/src/util/rsjson.h index db864a73f..13073f3b2 100644 --- a/libretroshare/src/util/rsjson.h +++ b/libretroshare/src/util/rsjson.h @@ -29,7 +29,7 @@ typedef rapidjson::Document RsJson; /** - * Print out RsJson to a stream, use std::stringstream to get the string + * Print out RsJson to a stream, use std::ostringstream to get the string * @param[out] out output stream * @param[in] jDoc JSON document to print * @return same output stream passed as out parameter