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 = rapidjson::OStreamWrapper;
100 using JSONWriter = rapidjson::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<rapidjson::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 = rapidjson::IStreamWrapper;
410 typedef rapidjson::GenericValue<rapidjson::UTF8<>> JSONValue;
411 typedef JSONValue::ConstMemberIterator MemberIterator;
412 typedef JSONValue::ConstValueIterator ValueIterator;
413 typedef rapidjson::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)
476 Iterator(ValueIterator begin, ValueIterator end) :
477 itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
481 Iterator & operator++()
488 GenericValue
const & value()
492 case Value :
return itsValueItBegin[itsIndex];
493 case Member:
return itsMemberItBegin[itsIndex].value;
499 const char * name()
const 501 if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
502 return itsMemberItBegin[itsIndex].name.GetString();
509 inline void search(
const char * searchName )
511 const auto len = std::strlen( searchName );
513 for(
auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
515 const auto currentName = it->name.GetString();
516 if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
517 ( std::strlen( currentName ) == len ) )
524 throw Exception(
"JSON Parsing failed - provided NVP (" + std::string(searchName) +
") not found");
528 MemberIterator itsMemberItBegin, itsMemberItEnd;
529 ValueIterator itsValueItBegin, itsValueItEnd;
531 enum Type {Value, Member, Null_} itsType;
549 auto const actualName = itsIteratorStack.back().name();
552 if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
553 itsIteratorStack.back().search( itsNextName );
556 itsNextName =
nullptr;
574 if(itsIteratorStack.back().value().IsArray())
575 itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
577 itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
583 itsIteratorStack.pop_back();
584 ++itsIteratorStack.back();
591 return itsIteratorStack.back().name();
601 template <class T, traits::EnableIf<std::is_signed<T>::value,
602 sizeof(T) <
sizeof(int64_t)> = traits::sfinae>
inline 603 void loadValue(T & val)
607 val =
static_cast<T
>( itsIteratorStack.back().value().GetInt() );
608 ++itsIteratorStack.back();
612 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
613 sizeof(T) <
sizeof(uint64_t),
614 !std::is_same<bool, T>::value> = traits::sfinae>
inline 615 void loadValue(T & val)
619 val =
static_cast<T
>( itsIteratorStack.back().value().GetUint() );
620 ++itsIteratorStack.back();
624 void loadValue(
bool & val) { search(); val = itsIteratorStack.back().value().GetBool(); ++itsIteratorStack.back(); }
626 void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
628 void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
630 void loadValue(
float & val) { search(); val =
static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
632 void loadValue(
double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
634 void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
636 void loadValue(std::nullptr_t&) { search(); CEREAL_RAPIDJSON_ASSERT(itsIteratorStack.back().value().IsNull()); ++itsIteratorStack.back(); }
643 template <
class T>
inline 644 typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value,
void>::type
645 loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
648 template <
class T>
inline 649 typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value,
void>::type
650 loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
653 template <
class T>
inline 654 typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value,
void>::type
655 loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
658 template <
class T>
inline 659 typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value,
void>::type
660 loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
664 template <
class T>
inline 665 typename std::enable_if<std::is_same<T, long>::value &&
666 sizeof(T) >=
sizeof(std::int64_t) &&
667 !std::is_same<T, std::int64_t>::value,
void>::type
668 loadValue( T & t ){ loadLong(t); }
671 template <
class T>
inline 672 typename std::enable_if<std::is_same<T, unsigned long>::value &&
673 sizeof(T) >=
sizeof(std::uint64_t) &&
674 !std::is_same<T, std::uint64_t>::value,
void>::type
680 void stringToNumber( std::string
const & str,
long long & val ) { val = std::stoll( str ); }
682 void stringToNumber( std::string
const & str,
unsigned long long & val ) { val = std::stoull( str ); }
684 void stringToNumber( std::string
const & str,
long double & val ) { val = std::stold( str ); }
688 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
689 !std::is_same<T, long>::value,
690 !std::is_same<T, unsigned long>::value,
691 !std::is_same<T, std::int64_t>::value,
692 !std::is_same<T, std::uint64_t>::value,
693 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
697 loadValue( encoded );
698 stringToNumber( encoded, val );
704 if (itsIteratorStack.size() == 1)
705 size = itsDocument.Size();
707 size = (itsIteratorStack.rbegin() + 1)->value().Size();
713 const char * itsNextName;
714 ReadStream itsReadStream;
715 std::vector<Iterator> itsIteratorStack;
716 rapidjson::Document itsDocument;
726 template <
class T>
inline 731 template <
class T>
inline 738 template <
class T>
inline 744 template <
class T>
inline 752 template <
class T>
inline 759 template <
class T>
inline 766 template <
class T>
inline 771 template <
class T>
inline 781 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
790 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
803 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
812 template <class T, traits::EnableIf<!std::is_arithmetic<T>::value,
846 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 853 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 864 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 870 template<
class CharT,
class Traits,
class Alloc>
inline 877 template<
class CharT,
class Traits,
class Alloc>
inline 883 template<
class CharT,
class Traits,
class Alloc>
inline 888 template<
class CharT,
class Traits,
class Alloc>
inline 896 template <
class T>
inline 903 template <
class T>
inline 925 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 932 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 939 template<
class CharT,
class Traits,
class Alloc>
inline 946 template<
class CharT,
class Traits,
class Alloc>
inline 954 template <
class T>
inline 961 template <
class T>
inline 975 #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:271
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:727
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
uint64_t size_type
The size type used by cereal.
Definition: helpers.hpp:59
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:135
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:71
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:116
void saveValue(unsigned u)
Saves a uint to the current node.
Definition: json.hpp:237
The base output archive class.
Definition: cereal.hpp:234
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:78
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:739
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