29#ifndef CEREAL_ARCHIVES_JSON_HPP_
30#define CEREAL_ARCHIVES_JSON_HPP_
44#ifndef RAPIDJSON_ASSERT_THROWS
45#define RAPIDJSON_ASSERT_THROWS
49#ifndef RAPIDJSON_ASSERT
50#define RAPIDJSON_ASSERT(x) if(!(x)){ \
51 throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); }
55#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
56#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
60#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
61#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag
64#include "rapidjson/prettywriter.h"
65#include "rapidjson/ostreamwrapper.h"
66#include "rapidjson/istreamwrapper.h"
67#include "rapidjson/document.h"
68#include "cereal/external/base64.hpp"
108 enum class NodeType { StartObject, InObject, StartArray, InArray };
110 using WriteStream = RAPIDJSON_NAMESPACE::OStreamWrapper;
111 using JSONWriter = RAPIDJSON_NAMESPACE::PrettyWriter<WriteStream>;
134 carriage_return =
'\r'
142 explicit Options(
int precision = JSONWriter::kDefaultMaxDecimalPlaces,
144 unsigned int indentLength = 4 ) :
145 itsPrecision( precision ),
146 itsIndentChar( static_cast<char>(indentChar) ),
147 itsIndentLength( indentLength ) { }
153 unsigned int itsIndentLength;
162 itsWriteStream(stream),
163 itsWriter(itsWriteStream),
166 itsWriter.SetMaxDecimalPlaces( options.itsPrecision );
167 itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
168 itsNameCounter.push(0);
169 itsNodeStack.push(NodeType::StartObject);
175 if (itsNodeStack.top() == NodeType::InObject)
176 itsWriter.EndObject();
177 else if (itsNodeStack.top() == NodeType::InArray)
178 itsWriter.EndArray();
189 auto base64string = base64::encode(
reinterpret_cast<const unsigned char *
>( data ), size );
207 itsNodeStack.push(NodeType::StartObject);
208 itsNameCounter.push(0);
219 switch(itsNodeStack.top())
221 case NodeType::StartArray:
222 itsWriter.StartArray();
224 case NodeType::InArray:
225 itsWriter.EndArray();
227 case NodeType::StartObject:
228 itsWriter.StartObject();
230 case NodeType::InObject:
231 itsWriter.EndObject();
236 itsNameCounter.pop();
258 void saveValue(std::string
const & s) { itsWriter.String(s.c_str(),
static_cast<RAPIDJSON_NAMESPACE::SizeType
>( s.size() )); }
270 std::is_signed<T>::value> = traits::sfinae>
inline
271 void saveLong(T l){
saveValue(
static_cast<std::int32_t
>( l ) ); }
275 std::is_signed<T>::value> = traits::sfinae>
inline
276 void saveLong(T l){
saveValue(
static_cast<std::int64_t
>( l ) ); }
280 std::is_unsigned<T>::value> = traits::sfinae>
inline
281 void saveLong(T lu){
saveValue(
static_cast<std::uint32_t
>( lu ) ); }
285 std::is_unsigned<T>::value> = traits::sfinae>
inline
286 void saveLong(T lu){
saveValue(
static_cast<std::uint64_t
>( lu ) ); }
289#if defined(_MSC_VER) && _MSC_VER < 1916
291 void saveValue(
unsigned long lu ){ saveLong( lu ); };
294 template <class T, traits::EnableIf<std::is_same<T, long>::value,
295 !std::is_same<T, int>::value,
296 !std::is_same<T, std::int64_t>::value> = traits::sfinae>
inline
300 template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
301 !std::is_same<T, unsigned>::value,
302 !std::is_same<T, std::uint64_t>::value> = traits::sfinae>
inline
308 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
309 !std::is_same<T, long>::value,
310 !std::is_same<T, unsigned long>::value,
311 !std::is_same<T, std::int64_t>::value,
312 !std::is_same<T, std::uint64_t>::value,
313 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
inline
316 std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
336 NodeType
const & nodeType = itsNodeStack.top();
339 if(nodeType == NodeType::StartArray)
341 itsWriter.StartArray();
342 itsNodeStack.top() = NodeType::InArray;
344 else if(nodeType == NodeType::StartObject)
346 itsNodeStack.top() = NodeType::InObject;
347 itsWriter.StartObject();
351 if(nodeType == NodeType::InArray)
return;
353 if(itsNextName ==
nullptr)
355 std::string name =
"value" + std::to_string( itsNameCounter.top()++ ) +
"\0";
361 itsNextName =
nullptr;
368 itsNodeStack.top() = NodeType::StartArray;
374 WriteStream itsWriteStream;
375 JSONWriter itsWriter;
376 char const * itsNextName;
377 std::stack<uint32_t> itsNameCounter;
378 std::stack<NodeType> itsNodeStack;
422 using ReadStream = RAPIDJSON_NAMESPACE::IStreamWrapper;
423 typedef RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<>> JSONValue;
424 typedef JSONValue::ConstMemberIterator MemberIterator;
425 typedef JSONValue::ConstValueIterator ValueIterator;
426 typedef RAPIDJSON_NAMESPACE::Document::GenericValue GenericValue;
437 itsNextName( nullptr ),
438 itsReadStream(stream)
440 itsDocument.ParseStream<>(itsReadStream);
441 if (itsDocument.IsArray())
442 itsIteratorStack.emplace_back(itsDocument.Begin(), itsDocument.End());
444 itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
461 auto decoded = base64::decode( encoded );
463 if( size != decoded.size() )
464 throw Exception(
"Decoded binary data size does not match specified size");
466 std::memcpy( data, decoded.data(), decoded.size() );
467 itsNextName =
nullptr;
483 Iterator() : itsIndex( 0 ), itsType(Null_) {}
485 Iterator(MemberIterator begin, MemberIterator end) :
486 itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Member)
492 Iterator(ValueIterator begin, ValueIterator end) :
493 itsValueItBegin(begin), itsIndex(0), itsSize(std::distance(begin, end)), itsType(Value)
500 Iterator & operator++()
507 GenericValue
const & value()
509 if( itsIndex >= itsSize )
514 case Value :
return itsValueItBegin[itsIndex];
515 case Member:
return itsMemberItBegin[itsIndex].value;
516 default:
throw cereal::Exception(
"JSONInputArchive internal error: null or empty iterator to object or array!");
521 const char * name()
const
523 if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
524 return itsMemberItBegin[itsIndex].name.GetString();
531 inline void search(
const char * searchName )
533 const auto len = std::strlen( searchName );
535 for(
auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
537 const auto currentName = it->name.GetString();
538 if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
539 ( std::strlen( currentName ) == len ) )
546 throw Exception(
"JSON Parsing failed - provided NVP (" + std::string(searchName) +
") not found");
550 MemberIterator itsMemberItBegin, itsMemberItEnd;
551 ValueIterator itsValueItBegin;
552 size_t itsIndex, itsSize;
553 enum Type {Value, Member, Null_} itsType;
568 auto localNextName = itsNextName;
569 itsNextName =
nullptr;
575 auto const actualName = itsIteratorStack.back().name();
578 if( !actualName || std::strcmp( localNextName, actualName ) != 0 )
579 itsIteratorStack.back().search( localNextName );
598 if(itsIteratorStack.back().value().IsArray())
599 itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
601 itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
607 itsIteratorStack.pop_back();
608 ++itsIteratorStack.back();
615 return itsIteratorStack.back().name();
625 template <class T, traits::EnableIf<std::is_signed<T>::value,
626 sizeof(T) <
sizeof(int64_t)> = traits::sfinae>
inline
631 val =
static_cast<T
>( itsIteratorStack.back().value().GetInt() );
632 ++itsIteratorStack.back();
636 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
637 sizeof(T) <
sizeof(uint64_t),
638 !std::is_same<bool, T>::value> = traits::sfinae>
inline
643 val =
static_cast<T
>( itsIteratorStack.back().value().GetUint() );
644 ++itsIteratorStack.back();
648 void loadValue(
bool & val) { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
650 void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
652 void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
654 void loadValue(
float & val) { search(); val =
static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
656 void loadValue(
double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
658 void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
660 void loadValue(std::nullptr_t&) { search(); RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
667 template <
class T>
inline
668 typename std::enable_if<
sizeof(T) ==
sizeof(std::int32_t) && std::is_signed<T>::value,
void>::type
669 loadLong(T & l){
loadValue(
reinterpret_cast<std::int32_t&
>( l ) ); }
672 template <
class T>
inline
673 typename std::enable_if<
sizeof(T) ==
sizeof(std::int64_t) && std::is_signed<T>::value,
void>::type
674 loadLong(T & l){
loadValue(
reinterpret_cast<std::int64_t&
>( l ) ); }
677 template <
class T>
inline
678 typename std::enable_if<
sizeof(T) ==
sizeof(std::uint32_t) && !std::is_signed<T>::value,
void>::type
679 loadLong(T & lu){
loadValue(
reinterpret_cast<std::uint32_t&
>( lu ) ); }
682 template <
class T>
inline
683 typename std::enable_if<
sizeof(T) ==
sizeof(std::uint64_t) && !std::is_signed<T>::value,
void>::type
684 loadLong(T & lu){
loadValue(
reinterpret_cast<std::uint64_t&
>( lu ) ); }
688 template <
class T>
inline
689 typename std::enable_if<std::is_same<T, long>::value &&
690 sizeof(T) >=
sizeof(std::int64_t) &&
691 !std::is_same<T, std::int64_t>::value,
void>::type
695 template <
class T>
inline
696 typename std::enable_if<std::is_same<T, unsigned long>::value &&
697 sizeof(T) >=
sizeof(std::uint64_t) &&
698 !std::is_same<T, std::uint64_t>::value,
void>::type
704 void stringToNumber( std::string
const & str,
long long & val ) { val = std::stoll( str ); }
706 void stringToNumber( std::string
const & str,
unsigned long long & val ) { val = std::stoull( str ); }
708 void stringToNumber( std::string
const & str,
long double & val ) { val = std::stold( str ); }
712 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
713 !std::is_same<T, long>::value,
714 !std::is_same<T, unsigned long>::value,
715 !std::is_same<T, std::int64_t>::value,
716 !std::is_same<T, std::uint64_t>::value,
717 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
722 stringToNumber( encoded, val );
728 if (itsIteratorStack.size() == 1)
729 size = itsDocument.Size();
731 size = (itsIteratorStack.rbegin() + 1)->value().Size();
737 const char * itsNextName;
738 ReadStream itsReadStream;
739 std::vector<Iterator> itsIteratorStack;
740 RAPIDJSON_NAMESPACE::Document itsDocument;
750 template <
class T>
inline
755 template <
class T>
inline
762 template <
class T>
inline
768 template <
class T>
inline
775 template <
class T>
inline
780 template <
class T>
inline
787 template <
class T>
inline
793 template <
class T>
inline
801 template <
class T>
inline
808 template <
class T>
inline
815 template <
class T>
inline
820 template <
class T>
inline
830 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
831 !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
832 !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
839 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
840 !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
841 !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
852 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
853 !traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, JSONOutputArchive>::value,
854 !traits::has_minimal_output_serialization<T, JSONOutputArchive>::value> = traits::sfinae>
861 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
862 !traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, JSONInputArchive>::value,
863 !traits::has_minimal_input_serialization<T, JSONInputArchive>::value> = traits::sfinae>
895 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
896 void prologue( JSONOutputArchive & ar, T
const & )
902 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
903 void prologue( JSONInputArchive &, T
const & )
908 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
909 void epilogue( JSONOutputArchive &, T
const & )
913 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
914 void epilogue( JSONInputArchive &, T
const & )
919 template<
class CharT,
class Traits,
class Alloc>
inline
926 template<
class CharT,
class Traits,
class Alloc>
inline
932 template<
class CharT,
class Traits,
class Alloc>
inline
937 template<
class CharT,
class Traits,
class Alloc>
inline
945 template <
class T>
inline
952 template <
class T>
inline
955 ar.setNextName( t.name );
974 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
981 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline
988 template<
class CharT,
class Traits,
class Alloc>
inline
995 template<
class CharT,
class Traits,
class Alloc>
inline
1003 template <
class T>
inline
1010 template <
class T>
inline
Main cereal functionality.
A wrapper around data that should be serialized after all non-deferred data.
Definition: helpers.hpp:233
A class containing various advanced options for the JSON archive.
Definition: json.hpp:120
static Options NoIndent()
Default options with no indentation.
Definition: json.hpp:126
Options(int precision=JSONWriter::kDefaultMaxDecimalPlaces, IndentChar indentChar=IndentChar::space, unsigned int indentLength=4)
Specify specific options for the JSONOutputArchive.
Definition: json.hpp:142
static Options Default()
Default options.
Definition: json.hpp:123
IndentChar
The character to use for indenting.
Definition: json.hpp:130
An output archive designed to save data to JSON.
Definition: json.hpp:107
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:184
void saveValue(bool b)
Saves a bool to the current node.
Definition: json.hpp:246
void finishNode()
Designates the most recently added node as finished.
Definition: json.hpp:212
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:240
void writeName()
Write the name of the upcoming node and prepare object/array state.
Definition: json.hpp:334
void makeArray()
Designates that the current node should be output as an array, not an object.
Definition: json.hpp:366
void saveValue(int64_t i64)
Saves an int64 to the current node.
Definition: json.hpp:252
void saveValue(T t)
Serialize a long if it would not be caught otherwise.
Definition: json.hpp:297
void saveValue(int i)
Saves an int to the current node.
Definition: json.hpp:248
~JSONOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the JSON.
Definition: json.hpp:173
void saveValue(std::nullptr_t)
Saves a nullptr to the current node.
Definition: json.hpp:262
JSONOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: json.hpp:160
void saveValue(double d)
Saves a double to the current node.
Definition: json.hpp:256
void saveValue(unsigned u)
Saves a uint to the current node.
Definition: json.hpp:250
void saveValue(T const &t)
Save exotic arithmetic as strings to current node.
Definition: json.hpp:314
void startNode()
Starts a new node in the JSON output.
Definition: json.hpp:204
void saveValue(char const *s)
Saves a const char * to the current node.
Definition: json.hpp:260
void saveValue(std::string const &s)
Saves a string to the current node.
Definition: json.hpp:258
void saveValue(uint64_t u64)
Saves a uint64 to the current node.
Definition: json.hpp:254
For holding name value pairs.
Definition: helpers.hpp:140
The base output archive class.
Definition: cereal.hpp:319
A wrapper around size metadata.
Definition: helpers.hpp:313
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
CEREAL_SIZE_TYPE size_type
The size type used by cereal.
Definition: helpers.hpp:61
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:763
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:751
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:92
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:49
An exception thrown when rapidjson fails an internal assertion.
Definition: json.hpp:40
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1321
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
typename detail::EnableIfHelper< Conditions... >::type EnableIf
Provides a way to enable a function if conditions are met.
Definition: traits.hpp:116