29 #ifndef CEREAL_ARCHIVES_JSON_HPP_ 30 #define CEREAL_ARCHIVES_JSON_HPP_ 44 #ifndef RAPIDJSON_ASSERT 45 #define RAPIDJSON_ASSERT(x) if(!(x)){ \ 46 throw ::cereal::RapidJSONException("rapidjson internal assertion failure: " #x); } 47 #endif // RAPIDJSON_ASSERT 49 #include <cereal/external/rapidjson/prettywriter.h> 50 #include <cereal/external/rapidjson/genericstream.h> 51 #include <cereal/external/rapidjson/reader.h> 52 #include <cereal/external/rapidjson/document.h> 53 #include <cereal/external/base64.hpp> 90 enum class NodeType { StartObject, InObject, StartArray, InArray };
92 typedef rapidjson::GenericWriteStream WriteStream;
93 typedef rapidjson::PrettyWriter<WriteStream> JSONWriter;
116 carriage_return =
'\r' 124 explicit Options(
int precision = std::numeric_limits<double>::max_digits10,
126 unsigned int indentLength = 4 ) :
127 itsPrecision( precision ),
128 itsIndentChar( static_cast<char>(indentChar) ),
129 itsIndentLength( indentLength ) { }
135 unsigned int itsIndentLength;
144 itsWriteStream(stream),
145 itsWriter(itsWriteStream, options.itsPrecision),
148 itsWriter.SetIndent( options.itsIndentChar, options.itsIndentLength );
149 itsNameCounter.push(0);
150 itsNodeStack.push(NodeType::StartObject);
156 if (itsNodeStack.top() == NodeType::InObject)
157 itsWriter.EndObject();
168 auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
169 saveValue( base64string );
186 itsNodeStack.push(NodeType::StartObject);
187 itsNameCounter.push(0);
198 switch(itsNodeStack.top())
200 case NodeType::StartArray:
201 itsWriter.StartArray();
202 case NodeType::InArray:
203 itsWriter.EndArray();
205 case NodeType::StartObject:
206 itsWriter.StartObject();
207 case NodeType::InObject:
208 itsWriter.EndObject();
213 itsNameCounter.pop();
235 void saveValue(std::string
const & s) { itsWriter.String(s.c_str(),
static_cast<rapidjson::SizeType
>( s.size() )); }
245 std::is_signed<T>::value> = traits::sfinae>
inline 246 void saveLong(T l){ saveValue( static_cast<std::int32_t>( l ) ); }
250 std::is_signed<T>::value> = traits::sfinae>
inline 251 void saveLong(T l){ saveValue( static_cast<std::int64_t>( l ) ); }
255 std::is_unsigned<T>::value> = traits::sfinae>
inline 256 void saveLong(T lu){ saveValue( static_cast<std::uint32_t>( lu ) ); }
260 std::is_unsigned<T>::value> = traits::sfinae>
inline 261 void saveLong(T lu){ saveValue( static_cast<std::uint64_t>( lu ) ); }
265 void saveValue(
unsigned long lu ){ saveLong( lu ); };
268 template <class T, traits::EnableIf<std::is_same<T, long>::value,
270 !std::is_same<T, std::int32_t>::value,
271 !std::is_same<T, std::int64_t>::value> = traits::sfinae>
inline 275 template <class T, traits::EnableIf<std::is_same<T, unsigned long>::value,
276 !std::is_same<T, std::uint32_t>::value,
277 !std::is_same<T, std::uint64_t>::value> = traits::sfinae>
inline 283 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
284 !std::is_same<T, long>::value,
285 !std::is_same<T, unsigned long>::value,
286 !std::is_same<T, std::int64_t>::value,
287 !std::is_same<T, std::uint64_t>::value,
288 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
inline 291 std::stringstream ss; ss.precision( std::numeric_limits<long double>::max_digits10 );
293 saveValue( ss.str() );
311 NodeType
const & nodeType = itsNodeStack.top();
314 if(nodeType == NodeType::StartArray)
316 itsWriter.StartArray();
317 itsNodeStack.top() = NodeType::InArray;
319 else if(nodeType == NodeType::StartObject)
321 itsNodeStack.top() = NodeType::InObject;
322 itsWriter.StartObject();
326 if(nodeType == NodeType::InArray)
return;
328 if(itsNextName ==
nullptr)
330 std::string name =
"value" + std::to_string( itsNameCounter.top()++ ) +
"\0";
335 saveValue(itsNextName);
336 itsNextName =
nullptr;
343 itsNodeStack.top() = NodeType::StartArray;
349 WriteStream itsWriteStream;
350 JSONWriter itsWriter;
351 char const * itsNextName;
352 std::stack<uint32_t> itsNameCounter;
353 std::stack<NodeType> itsNodeStack;
394 typedef rapidjson::GenericReadStream ReadStream;
395 typedef rapidjson::GenericValue<rapidjson::UTF8<>> JSONValue;
396 typedef JSONValue::ConstMemberIterator MemberIterator;
397 typedef JSONValue::ConstValueIterator ValueIterator;
398 typedef rapidjson::Document::GenericValue GenericValue;
409 itsNextName( nullptr ),
410 itsReadStream(stream)
412 itsDocument.ParseStream<0>(itsReadStream);
413 itsIteratorStack.emplace_back(itsDocument.MemberBegin(), itsDocument.MemberEnd());
427 loadValue( encoded );
428 auto decoded = base64::decode( encoded );
430 if( size != decoded.size() )
431 throw Exception(
"Decoded binary data size does not match specified size");
433 std::memcpy( data, decoded.data(), decoded.size() );
434 itsNextName =
nullptr;
450 Iterator() : itsIndex( 0 ), itsType(Null_) {}
452 Iterator(MemberIterator begin, MemberIterator end) :
453 itsMemberItBegin(begin), itsMemberItEnd(end), itsIndex(0), itsType(Member)
456 Iterator(ValueIterator begin, ValueIterator end) :
457 itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
461 Iterator & operator++()
468 GenericValue
const & value()
472 case Value :
return itsValueItBegin[itsIndex];
473 case Member:
return itsMemberItBegin[itsIndex].value;
479 const char * name()
const 481 if( itsType == Member && (itsMemberItBegin + itsIndex) != itsMemberItEnd )
482 return itsMemberItBegin[itsIndex].name.GetString();
489 inline void search(
const char * searchName )
491 const auto len = std::strlen( searchName );
493 for(
auto it = itsMemberItBegin; it != itsMemberItEnd; ++it, ++index )
495 const auto currentName = it->name.GetString();
496 if( ( std::strncmp( searchName, currentName, len ) == 0 ) &&
497 ( std::strlen( currentName ) == len ) )
504 throw Exception(
"JSON Parsing failed - provided NVP not found");
508 MemberIterator itsMemberItBegin, itsMemberItEnd;
509 ValueIterator itsValueItBegin, itsValueItEnd;
511 enum Type {Value, Member, Null_} itsType;
529 auto const actualName = itsIteratorStack.back().name();
532 if( !actualName || std::strcmp( itsNextName, actualName ) != 0 )
533 itsIteratorStack.back().search( itsNextName );
536 itsNextName =
nullptr;
554 if(itsIteratorStack.back().value().IsArray())
555 itsIteratorStack.emplace_back(itsIteratorStack.back().value().Begin(), itsIteratorStack.back().value().End());
557 itsIteratorStack.emplace_back(itsIteratorStack.back().value().MemberBegin(), itsIteratorStack.back().value().MemberEnd());
563 itsIteratorStack.pop_back();
564 ++itsIteratorStack.back();
571 return itsIteratorStack.back().name();
581 template <class T, traits::EnableIf<std::is_signed<T>::value,
582 sizeof(T) <
sizeof(int64_t)> = traits::sfinae>
inline 583 void loadValue(T & val)
587 val =
static_cast<T
>( itsIteratorStack.back().value().GetInt() );
588 ++itsIteratorStack.back();
592 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
593 sizeof(T) <
sizeof(uint64_t),
594 !std::is_same<bool, T>::value> = traits::sfinae>
inline 595 void loadValue(T & val)
599 val =
static_cast<T
>( itsIteratorStack.back().value().GetUint() );
600 ++itsIteratorStack.back();
604 void loadValue(
bool & val) { search(); val = itsIteratorStack.back().value().GetBool_(); ++itsIteratorStack.back(); }
606 void loadValue(int64_t & val) { search(); val = itsIteratorStack.back().value().GetInt64(); ++itsIteratorStack.back(); }
608 void loadValue(uint64_t & val) { search(); val = itsIteratorStack.back().value().GetUint64(); ++itsIteratorStack.back(); }
610 void loadValue(
float & val) { search(); val =
static_cast<float>(itsIteratorStack.back().value().GetDouble()); ++itsIteratorStack.back(); }
612 void loadValue(
double & val) { search(); val = itsIteratorStack.back().value().GetDouble(); ++itsIteratorStack.back(); }
614 void loadValue(std::string & val) { search(); val = itsIteratorStack.back().value().GetString(); ++itsIteratorStack.back(); }
621 template <
class T>
inline 622 typename std::enable_if<sizeof(T) == sizeof(std::int32_t) && std::is_signed<T>::value,
void>::type
623 loadLong(T & l){ loadValue( reinterpret_cast<std::int32_t&>( l ) ); }
626 template <
class T>
inline 627 typename std::enable_if<sizeof(T) == sizeof(std::int64_t) && std::is_signed<T>::value,
void>::type
628 loadLong(T & l){ loadValue( reinterpret_cast<std::int64_t&>( l ) ); }
631 template <
class T>
inline 632 typename std::enable_if<sizeof(T) == sizeof(std::uint32_t) && !std::is_signed<T>::value,
void>::type
633 loadLong(T & lu){ loadValue( reinterpret_cast<std::uint32_t&>( lu ) ); }
636 template <
class T>
inline 637 typename std::enable_if<sizeof(T) == sizeof(std::uint64_t) && !std::is_signed<T>::value,
void>::type
638 loadLong(T & lu){ loadValue( reinterpret_cast<std::uint64_t&>( lu ) ); }
642 template <
class T>
inline 643 typename std::enable_if<std::is_same<T, long>::value &&
644 sizeof(T) >=
sizeof(std::int64_t) &&
645 !std::is_same<T, std::int64_t>::value,
void>::type
646 loadValue( T & t ){ loadLong(t); }
649 template <
class T>
inline 650 typename std::enable_if<std::is_same<T, unsigned long>::value &&
651 sizeof(T) >=
sizeof(std::uint64_t) &&
652 !std::is_same<T, std::uint64_t>::value,
void>::type
658 void stringToNumber( std::string
const & str,
long long & val ) { val = std::stoll( str ); }
660 void stringToNumber( std::string
const & str,
unsigned long long & val ) { val = std::stoull( str ); }
662 void stringToNumber( std::string
const & str,
long double & val ) { val = std::stold( str ); }
666 template <class T, traits::EnableIf<std::is_arithmetic<T>::value,
667 !std::is_same<T, long>::value,
668 !std::is_same<T, unsigned long>::value,
669 !std::is_same<T, std::int64_t>::value,
670 !std::is_same<T, std::uint64_t>::value,
671 (
sizeof(T) >=
sizeof(
long double) ||
sizeof(T) >=
sizeof(
long long))> = traits::sfinae>
675 loadValue( encoded );
676 stringToNumber( encoded, val );
682 size = (itsIteratorStack.rbegin() + 1)->value().Size();
688 const char * itsNextName;
689 ReadStream itsReadStream;
690 std::vector<Iterator> itsIteratorStack;
691 rapidjson::Document itsDocument;
701 template <
class T>
inline 706 template <
class T>
inline 713 template <
class T>
inline 719 template <
class T>
inline 727 template <
class T>
inline 734 template <
class T>
inline 741 template <
class T>
inline 746 template <
class T>
inline 756 template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
765 template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
778 template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
787 template <class T, traits::DisableIf<std::is_arithmetic<T>::value ||
797 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 804 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 810 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 815 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 821 template<
class CharT,
class Traits,
class Alloc>
inline 828 template<
class CharT,
class Traits,
class Alloc>
inline 834 template<
class CharT,
class Traits,
class Alloc>
inline 839 template<
class CharT,
class Traits,
class Alloc>
inline 847 template <
class T>
inline 854 template <
class T>
inline 862 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae>
inline 869 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 891 template <
class T>
inline 898 template <
class T>
inline 912 #endif // CEREAL_ARCHIVES_JSON_HPP_ void saveValue(T t)
Serialize a long if it would not be caught otherwise.
Definition: json.hpp:272
static Options Default()
Default options.
Definition: json.hpp:105
void saveValue(int64_t i64)
Saves an int64 to the current node.
Definition: json.hpp:229
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:183
void saveValue(std::string const &s)
Saves a string to the current node.
Definition: json.hpp:235
#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:231
void saveValue(int i)
Saves an int to the current node.
Definition: json.hpp:225
A wrapper around size metadata.
Definition: helpers.hpp:250
void finishNode()
Designates the most recently added node as finished.
Definition: json.hpp:191
A class containing various advanced options for the JSON archive.
Definition: json.hpp:101
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:702
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:309
Checks to see if the base class used in a cast has a minimal serialization.
Definition: traits.hpp:1119
void saveValue(char const *s)
Saves a const char * to the current node.
Definition: json.hpp:237
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1266
static Options NoIndent()
Default options with no indentation.
Definition: json.hpp:108
An output archive designed to save data to JSON.
Definition: json.hpp:88
void saveValue(double d)
Saves a double to the current node.
Definition: json.hpp:233
uint64_t size_type
The size type used by cereal.
Definition: helpers.hpp:59
Definition: traits.hpp:990
Definition: access.hpp:39
#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:341
void saveValue(T const &t)
Save exotic arithmetic as strings to current node.
Definition: json.hpp:289
Main cereal functionality.
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:58
Options(int precision=std::numeric_limits< double >::max_digits10, IndentChar indentChar=IndentChar::space, unsigned int indentLength=4)
Specify specific options for the JSONOutputArchive.
Definition: json.hpp:124
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: json.hpp:217
void saveValue(unsigned u)
Saves a uint to the current node.
Definition: json.hpp:227
~JSONOutputArchive()
Destructor, flushes the JSON.
Definition: json.hpp:154
The base output archive class.
Definition: cereal.hpp:234
void saveValue(bool b)
Saves a bool to the current node.
Definition: json.hpp:223
IndentChar
The character to use for indenting.
Definition: json.hpp:111
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:65
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:163
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:714
JSONOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream.
Definition: json.hpp:142
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48