29 #ifndef CEREAL_ARCHIVES_JSON_HPP_ 30 #define CEREAL_ARCHIVES_JSON_HPP_ 44 #ifndef CEREAL_RAPIDJSON_ASSERT 45 #define CEREAL_RAPIDJSON_ASSERT(x) if(!(x)){ \ 46 throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); } 47 #endif // RAPIDJSON_ASSERT 50 #define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag 51 #define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag 53 #include "cereal/external/rapidjson/prettywriter.h" 54 #include "cereal/external/rapidjson/ostreamwrapper.h" 55 #include "cereal/external/rapidjson/istreamwrapper.h" 56 #include "cereal/external/rapidjson/document.h" 57 #include "cereal/external/base64.hpp" 97 enum class NodeType { StartObject, InObject, StartArray, InArray };
99 using WriteStream = CEREAL_RAPIDJSON_NAMESPACE::OStreamWrapper;
100 using JSONWriter = CEREAL_RAPIDJSON_NAMESPACE::PrettyWriter<WriteStream>;
123 carriage_return =
'\r' 131 explicit Options(
int precision = JSONWriter::kDefaultMaxDecimalPlaces,
133 unsigned int indentLength = 4 ) :
134 itsPrecision( precision ),
135 itsIndentChar( static_cast<char>(indentChar) ),
136 itsIndentLength( indentLength ) { }
142 unsigned int itsIndentLength;
151 itsWriteStream(stream),
152 itsWriter(itsWriteStream),
155 itsWriter.SetMaxDecimalPlaces( options.itsPrecision );
156 itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
157 itsNameCounter.push(0);
158 itsNodeStack.push(NodeType::StartObject);
164 if (itsNodeStack.top() == NodeType::InObject)
165 itsWriter.EndObject();
166 else if (itsNodeStack.top() == NodeType::InArray)
167 itsWriter.EndArray();
178 auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
179 saveValue( base64string );
196 itsNodeStack.push(NodeType::StartObject);
197 itsNameCounter.push(0);
208 switch(itsNodeStack.top())
210 case NodeType::StartArray:
211 itsWriter.StartArray();
212 case NodeType::InArray:
213 itsWriter.EndArray();
215 case NodeType::StartObject:
216 itsWriter.StartObject();
217 case NodeType::InObject:
218 itsWriter.EndObject();
223 itsNameCounter.pop();
245 void saveValue(std::string
const & s) { itsWriter.String(s.c_str(),
static_cast<CEREAL_RAPIDJSON_NAMESPACE::SizeType
>( s.size() )); }
257 std::is_signed<T>::value> = traits::sfinae>
inline 258 void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
262 std::is_signed<T>::value> = traits::sfinae>
inline 263 void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
267 std::is_unsigned<T>::value> = traits::sfinae>
inline 268 void saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
272 std::is_unsigned<T>::value> = traits::sfinae>
inline 273 void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
277 void saveValue(
unsigned long lu ){ saveLong( lu ); };
280 template <class T, traits::EnableIf<std::is_same<T, long>::value,
282 !std::is_same<T, std::int32_t>::value,
283 !std::is_same<T, std::int64_t>::value> = traits::sfinae>
inline 287 template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
288 !std::is_same<T, std::uint32_t>::value,
289 !std::is_same<T, std::uint64_t>::value> = traits::sfinae>
inline 295 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
296 !std::is_same<T, long>::value,
297 !std::is_same<T, unsigned long>::value,
298 !std::is_same<T, std::int64_t>::value,
299 !std::is_same<T, std::uint64_t>::value,
300 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
inline 303 std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
305 saveValue( ss.str() );
323 NodeType
const & nodeType = itsNodeStack.top();
326 if(nodeType == NodeType::StartArray)
328 itsWriter.StartArray();
329 itsNodeStack.top() = NodeType::InArray;
331 else if(nodeType == NodeType::StartObject)
333 itsNodeStack.top() = NodeType::InObject;
334 itsWriter.StartObject();
338 if(nodeType == NodeType::InArray)
return;
340 if(itsNextName ==
nullptr)
342 std::string name =
"value" + std::to_string( itsNameCounter.top()++ ) +
"\0";
347 saveValue(itsNextName);
348 itsNextName =
nullptr;
355 itsNodeStack.top() = NodeType::StartArray;
361 WriteStream itsWriteStream;
362 JSONWriter itsWriter;
363 char const * itsNextName;
364 std::stack<uint32_t> itsNameCounter;
365 std::stack<NodeType> itsNodeStack;
409 using ReadStream = CEREAL_RAPIDJSON_NAMESPACE::IStreamWrapper;
410 typedef CEREAL_RAPIDJSON_NAMESPACE::GenericValue<CEREAL_RAPIDJSON_NAMESPACE::UTF8<>> JSONValue;
411 typedef JSONValue::ConstMemberIterator MemberIterator;
412 typedef JSONValue::ConstValueIterator ValueIterator;
413 typedef CEREAL_RAPIDJSON_NAMESPACE::Document::GenericValue GenericValue;
424 itsNextName( nullptr ),
425 itsReadStream(stream)
427 itsDocument.ParseStream<>(itsReadStream);
428 if (itsDocument.IsArray())
429 itsIteratorStack.emplace_back(itsDocument.Begin(), itsDocument.End());
431 itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
447 loadValue( encoded );
448 auto decoded = base64::decode( encoded );
450 if( size != decoded.size() )
451 throw Exception(
"Decoded binary data size does not match specified size");
453 std::memcpy( data, decoded.data(), decoded.size() );
454 itsNextName =
nullptr;
470 Iterator() : itsIndex( 0 ), itsType(Null_) {}
472 Iterator(MemberIterator begin, MemberIterator end) :
473 itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member)
475 if( std::distance( begin, end ) == 0 )
479 Iterator(ValueIterator begin, ValueIterator end) :
480 itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
482 if( std::distance( begin, end ) == 0 )
487 Iterator & operator++()
494 GenericValue
const & value()
498 case Value :
return itsValueItBegin[itsIndex];
499 case Member:
return itsMemberItBegin[itsIndex].value;
500 default:
throw cereal::Exception(
"JSONInputArchive internal error: null or empty iterator to object or array!");
505 const char * name()
const 507 if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
508 return itsMemberItBegin[itsIndex].name.GetString();
515 inline void search(
const char * searchName )
517 const auto len = std::strlen( searchName );
519 for(
auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
521 const auto currentName = it->name.GetString();
522 if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
523 ( std::strlen( currentName ) == len ) )
530 throw Exception(
"JSON Parsing failed - provided NVP (" + std::string(searchName) +
") not found");
534 MemberIterator itsMemberItBegin, itsMemberItEnd;
535 ValueIterator itsValueItBegin, itsValueItEnd;
537 enum Type {Value, Member, Null_} itsType;
555 auto const actualName = itsIteratorStack.back().name();
558 if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
559 itsIteratorStack.back().search( itsNextName );
562 itsNextName =
nullptr;
580 if(itsIteratorStack.back().value().IsArray())
581 itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
583 itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
589 itsIteratorStack.pop_back();
590 ++itsIteratorStack.back();
597 return itsIteratorStack.back().name();
607 template <class T, traits::EnableIf<std::is_signed<T>::value,
608 sizeof(T) <
sizeof(int64_t)> = traits::sfinae>
inline 609 void loadValue(T & val)
613 val =
static_cast<T
>( itsIteratorStack.back().value().GetInt() );
614 ++itsIteratorStack.back();
618 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
619 sizeof(T) <
sizeof(uint64_t),
620 !std::is_same<bool, T>::value> = traits::sfinae>
inline 621 void loadValue(T & val)
625 val =
static_cast<T
>( itsIteratorStack.back().value().GetUint() );
626 ++itsIteratorStack.back();
630 void loadValue(
bool & val) { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
632 void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
634 void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
636 void loadValue(
float & val) { search(); val =
static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
638 void loadValue(
double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
640 void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
642 void loadValue(std::nullptr_t&) { search(); CEREAL_RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
649 template <
class T>
inline 650 typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value,
void>::type
651 loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
654 template <
class T>
inline 655 typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value,
void>::type
656 loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
659 template <
class T>
inline 660 typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value,
void>::type
661 loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
664 template <
class T>
inline 665 typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value,
void>::type
666 loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
670 template <
class T>
inline 671 typename std::enable_if<std::is_same<T, long>::value &&
672 sizeof(T) >=
sizeof(std::int64_t) &&
673 !std::is_same<T, std::int64_t>::value,
void>::type
674 loadValue( T & t ){ loadLong(t); }
677 template <
class T>
inline 678 typename std::enable_if<std::is_same<T, unsigned long>::value &&
679 sizeof(T) >=
sizeof(std::uint64_t) &&
680 !std::is_same<T, std::uint64_t>::value,
void>::type
686 void stringToNumber( std::string
const & str,
long long & val ) { val = std::stoll( str ); }
688 void stringToNumber( std::string
const & str,
unsigned long long & val ) { val = std::stoull( str ); }
690 void stringToNumber( std::string
const & str,
long double & val ) { val = std::stold( str ); }
694 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
695 !std::is_same<T, long>::value,
696 !std::is_same<T, unsigned long>::value,
697 !std::is_same<T, std::int64_t>::value,
698 !std::is_same<T, std::uint64_t>::value,
699 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
703 loadValue( encoded );
704 stringToNumber( encoded, val );
710 if (itsIteratorStack.size() == 1)
711 size = itsDocument.Size();
713 size = (itsIteratorStack.rbegin() + 1)->value().Size();
719 const char * itsNextName;
720 ReadStream itsReadStream;
721 std::vector<Iterator> itsIteratorStack;
722 CEREAL_RAPIDJSON_NAMESPACE::Document itsDocument;
732 template <
class T>
inline 737 template <
class T>
inline 744 template <
class T>
inline 750 template <
class T>
inline 758 template <
class T>
inline 765 template <
class T>
inline 772 template <
class T>
inline 777 template <
class T>
inline 787 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
796 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
809 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
818 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
852 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 859 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 865 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 870 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 876 template<
class CharT,
class Traits,
class Alloc>
inline 883 template<
class CharT,
class Traits,
class Alloc>
inline 889 template<
class CharT,
class Traits,
class Alloc>
inline 894 template<
class CharT,
class Traits,
class Alloc>
inline 902 template <
class T>
inline 909 template <
class T>
inline 931 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 938 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 945 template<
class CharT,
class Traits,
class Alloc>
inline 952 template<
class CharT,
class Traits,
class Alloc>
inline 960 template <
class T>
inline 967 template <
class T>
inline 981 #endif // CEREAL_ARCHIVES_JSON_HPP_ void saveValue(T t)
Serialize a long if it would not be caught otherwise.
Definition: json.hpp:284
static Options Default()
Default options.
Definition: json.hpp:112
void saveValue(int64_t i64)
Saves an int64 to the current node.
Definition: json.hpp:239
An exception thrown when rapidjson fails an internal assertion.
Definition: json.hpp:39
void startNode()
Starts a new node in the JSON output.
Definition: json.hpp:193
void saveValue(std::string const &s)
Saves a string to the current node.
Definition: json.hpp:245
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
void saveValue(uint64_t u64)
Saves a uint64 to the current node.
Definition: json.hpp:241
void saveValue(int i)
Saves an int to the current node.
Definition: json.hpp:235
A wrapper around size metadata.
Definition: helpers.hpp:273
void finishNode()
Designates the most recently added node as finished.
Definition: json.hpp:201
A class containing various advanced options for the JSON archive.
Definition: json.hpp:108
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:733
typename detail::EnableIfHelper< Conditions... >::type EnableIf
Provides a way to enable a function if conditions are met.
Definition: traits.hpp:116
void writeName()
Write the name of the upcoming node and prepare object/array state.
Definition: json.hpp:321
Checks to see if the base class used in a cast has a minimal serialization.
Definition: traits.hpp:1173
void saveValue(std::nullptr_t)
Saves a nullptr to the current node.
Definition: json.hpp:249
void saveValue(char const *s)
Saves a const char * to the current node.
Definition: json.hpp:247
Options(int precision=JSONWriter::kDefaultMaxDecimalPlaces, IndentChar indentChar=IndentChar::space, unsigned int indentLength=4)
Specify specific options for the JSONOutputArchive.
Definition: json.hpp:131
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1299
static Options NoIndent()
Default options with no indentation.
Definition: json.hpp:115
An output archive designed to save data to JSON.
Definition: json.hpp:95
void saveValue(double d)
Saves a double to the current node.
Definition: json.hpp:243
Definition: traits.hpp:1044
Definition: access.hpp:40
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:141
void makeArray()
Designates that the current node should be output as an array, not an object.
Definition: json.hpp:353
void saveValue(T const &t)
Save exotic arithmetic as strings to current node.
Definition: json.hpp:301
Main cereal functionality.
~JSONOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the JSON.
Definition: json.hpp:162
For holding name value pairs.
Definition: helpers.hpp:137
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:227
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
void saveValue(unsigned u)
Saves a uint to the current node.
Definition: json.hpp:237
The base output archive class.
Definition: cereal.hpp:234
CEREAL_SIZE_TYPE size_type
The size type used by cereal.
Definition: helpers.hpp:61
void saveValue(bool b)
Saves a bool to the current node.
Definition: json.hpp:233
IndentChar
The character to use for indenting.
Definition: json.hpp:118
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:92
void saveBinaryValue(const void *data, size_t size, const char *name=nullptr)
Saves some binary data, encoded as a base64 string, with an optional name.
Definition: json.hpp:173
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:745
JSONOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: json.hpp:149
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48