Change raw memory JSON representation

Fix bug reported by b1rdG
The new way permits to add more formats in the future without breaking
  retro-compatibility again.
Add support for RsJson in rsdebug for Android
This commit is contained in:
Gioacchino Mazzurco 2020-05-28 23:01:04 +02:00
parent 968f234bfd
commit c1c303218c
No known key found for this signature in database
GPG Key ID: A1FBCA3872E87051
4 changed files with 63 additions and 53 deletions

View File

@ -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<rapidjson::SizeType>(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<uint8_t> 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<uint8_t*>(realloc(first, decodedSize));
first = reinterpret_cast<uint8_t*>(malloc(decodedSize));
second = static_cast<uint32_t>(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 //
//============================================================================//

View File

@ -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,7 +782,7 @@ struct RsTypeSerializer
{
if(!yielding)
{
std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName
RsErr() << __PRETTY_FUNCTION__ << " \"" << memberName
<< "\" not found in JSON:" << std::endl
<< jDoc << std::endl << std::endl;
print_stacktrace();
@ -790,7 +795,7 @@ struct RsTypeSerializer
if(!v.IsObject())
{
std::cerr << __PRETTY_FUNCTION__ << " \"" << memberName
RsErr() << __PRETTY_FUNCTION__ << " \"" << memberName
<< "\" has wrong type in JSON, object expected, got:"
<< std::endl << jDoc << std::endl << std::endl;
print_stacktrace();

View File

@ -32,6 +32,8 @@ std::ostream &operator<<(std::ostream& out, const std::error_condition& err);
# include <sstream>
# include <string>
# 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<typename T>
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<seconds>(now);
const auto msec = duration_cast<milliseconds>(now - sec);
std::stringstream tstream;
std::ostringstream tstream;
tstream << static_cast<char>(CATEGORY) << " "
<< sec.time_since_epoch().count() << "."
<< std::setfill('0') << std::setw(3) << msec.count()

View File

@ -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