xml.hpp
Go to the documentation of this file.
/*
Copyright (c) 2014, Randolph Voorhies, Shane Grant
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CEREAL_ARCHIVES_XML_HPP_
#define CEREAL_ARCHIVES_XML_HPP_
#include "cereal/cereal.hpp"
#include "cereal/details/util.hpp"
#include "cereal/external/rapidxml/rapidxml.hpp"
#include "cereal/external/rapidxml/rapidxml_print.hpp"
#include "cereal/external/base64.hpp"
#include <sstream>
#include <stack>
#include <vector>
#include <limits>
#include <string>
#include <cstring>
#include <cmath>
namespace cereal
{
namespace xml_detail
{
#ifndef CEREAL_XML_STRING_VALUE
#define CEREAL_XML_STRING_VALUE "cereal"
#endif // CEREAL_XML_STRING_VALUE
static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
inline bool isWhitespace( char c )
{
return c == ' ' || c == '\t' || c == '\n' || c == '\r';
}
}
// ######################################################################
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
{
public:
class Options
{
public:
static Options Default(){ return Options(); }
explicit Options( int precision_ = std::numeric_limits<double>::max_digits10,
bool indent_ = true,
bool outputType_ = false,
bool sizeAttributes_ = true ) :
itsPrecision( precision_ ),
itsIndent( indent_ ),
itsOutputType( outputType_ ),
itsSizeAttributes( sizeAttributes_ )
{ }
Options & precision( int value ){ itsPrecision = value; return * this; }
Options & indent( bool enable ){ itsIndent = enable; return *this; }
Options & outputType( bool enable ){ itsOutputType = enable; return *this; }
Options & sizeAttributes( bool enable ){ itsSizeAttributes = enable; return *this; }
private:
friend class XMLOutputArchive;
int itsPrecision;
bool itsIndent;
bool itsOutputType;
bool itsSizeAttributes;
};
XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
OutputArchive<XMLOutputArchive>(this),
itsStream(stream),
itsOutputType( options.itsOutputType ),
itsIndent( options.itsIndent ),
itsSizeAttributes(options.itsSizeAttributes)
{
// rapidxml will delete all allocations when xml_document is cleared
auto node = itsXML.allocate_node( rapidxml::node_declaration );
node->append_attribute( itsXML.allocate_attribute( "version", "1.0" ) );
node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) );
itsXML.append_node( node );
// allocate root node
auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
itsXML.append_node( root );
itsNodes.emplace( root );
// set attributes on the streams
itsStream << std::boolalpha;
itsStream.precision( options.itsPrecision );
itsOS << std::boolalpha;
itsOS.precision( options.itsPrecision );
}
~XMLOutputArchive() CEREAL_NOEXCEPT
{
const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
rapidxml::print( itsStream, itsXML, flags );
itsXML.clear();
}
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
{
itsNodes.top().name = name;
startNode();
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
saveValue( base64string );
if( itsOutputType )
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
finishNode();
}
void startNode()
{
// generate a name for this new node
const auto nameString = itsNodes.top().getValueName();
// allocate strings for all of the data in the XML object
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
// insert into the XML
auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
itsNodes.top().node->append_node( node );
itsNodes.emplace( node );
}
void finishNode()
{
itsNodes.pop();
}
void setNextName( const char * name )
{
itsNodes.top().name = name;
}
template <class T> inline
void saveValue( T const & value )
{
itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
itsOS << value << std::ends;
auto strValue = itsOS.str();
// itsOS.str() may contain data from previous calls after the first '\0' that was just inserted
// and this data is counted in the length call. We make sure to remove that section so that the
// whitespace validation is done properly
strValue.resize(std::strlen(strValue.c_str()));
// If the first or last character is a whitespace, add xml:space attribute
const auto len = strValue.length();
if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) )
{
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
}
// allocate strings for all of the data in the XML object
auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 );
// insert into the XML
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
}
void saveValue( uint8_t const & value )
{
saveValue( static_cast<uint32_t>( value ) );
}
void saveValue( int8_t const & value )
{
saveValue( static_cast<int32_t>( value ) );
}
template <class T> inline
void insertType()
{
if( !itsOutputType )
return;
// generate a name for this new node
const auto nameString = util::demangledName<T>();
// allocate strings for all of the data in the XML object
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
}
void appendAttribute( const char * name, const char * value )
{
auto namePtr = itsXML.allocate_string( name );
auto valuePtr = itsXML.allocate_string( value );
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
}
bool hasSizeAttributes() const { return itsSizeAttributes; }
protected:
struct NodeInfo
{
NodeInfo( rapidxml::xml_node<> * n = nullptr,
const char * nm = nullptr ) :
node( n ),
counter( 0 ),
name( nm )
{ }
rapidxml::xml_node<> * node;
size_t counter;
const char * name;
std::string getValueName()
{
if( name )
{
auto n = name;
name = nullptr;
return {n};
}
else
return "value" + std::to_string( counter++ ) + "\0";
}
}; // NodeInfo
private:
std::ostream & itsStream;
rapidxml::xml_document<> itsXML;
std::stack<NodeInfo> itsNodes;
std::ostringstream itsOS;
bool itsOutputType;
bool itsIndent;
bool itsSizeAttributes;
}; // XMLOutputArchive
// ######################################################################
class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
{
public:
XMLInputArchive( std::istream & stream ) :
InputArchive<XMLInputArchive>( this ),
itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
{
try
{
itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
}
catch( rapidxml::parse_error const & )
{
//std::cerr << "-----Original-----" << std::endl;
//stream.seekg(0);
//std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
//std::cerr << "-----Error-----" << std::endl;
//std::cerr << e.what() << std::endl;
//std::cerr << e.where<char>() << std::endl;
throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
}
// Parse the root
auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
if( root == nullptr )
throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
else
itsNodes.emplace( root );
}
~XMLInputArchive() CEREAL_NOEXCEPT = default;
void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
{
setNextName( name );
startNode();
std::string encoded;
loadValue( encoded );
auto decoded = base64::decode( encoded );
if( size != decoded.size() )
throw Exception("Decoded binary data size does not match specified size");
std::memcpy( data, decoded.data(), decoded.size() );
finishNode();
}
void startNode()
{
auto next = itsNodes.top().child; // By default we would move to the next child node
auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
// If we were given an NVP name, look for it in the current level of the document.
// We only need to do this if either we have exhausted the siblings of the current level or
// the NVP name does not match the name of the node we would normally read next
if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
{
next = itsNodes.top().search( expectedName );
if( next == nullptr )
throw Exception("XML Parsing failed - provided NVP (" + std::string(expectedName) + ") not found");
}
itsNodes.emplace( next );
}
void finishNode()
{
// remove current
itsNodes.pop();
// advance parent
itsNodes.top().advance();
// Reset name
itsNodes.top().name = nullptr;
}
const char * getNodeName() const
{
return itsNodes.top().getChildName();
}
void setNextName( const char * name )
{
itsNodes.top().name = name;
}
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
std::is_same<T, bool>::value> = traits::sfinae> inline
void loadValue( T & value )
{
std::istringstream is( itsNodes.top().node->value() );
is.setf( std::ios::boolalpha );
is >> value;
}
template <class T, traits::EnableIf<std::is_integral<T>::value,
!std::is_same<T, bool>::value,
sizeof(T) == sizeof(char)> = traits::sfinae> inline
void loadValue( T & value )
{
value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
}
void loadValue( int8_t & value )
{
int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
}
void loadValue( uint8_t & value )
{
uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
}
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
!std::is_same<T, bool>::value,
!std::is_same<T, char>::value,
!std::is_same<T, unsigned char>::value,
sizeof(T) < sizeof(long long)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
}
template <class T, traits::EnableIf<std::is_unsigned<T>::value,
!std::is_same<T, bool>::value,
sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
}
template <class T, traits::EnableIf<std::is_signed<T>::value,
!std::is_same<T, char>::value,
sizeof(T) <= sizeof(int)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
}
template <class T, traits::EnableIf<std::is_signed<T>::value,
(sizeof(T) > sizeof(int)),
sizeof(T) <= sizeof(long)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
}
template <class T, traits::EnableIf<std::is_signed<T>::value,
(sizeof(T) > sizeof(long)),
sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
void loadValue( T & value )
{
value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
}
void loadValue( float & value )
{
try
{
value = std::stof( itsNodes.top().node->value() );
}
catch( std::out_of_range const & )
{
// special case for denormalized values
std::istringstream is( itsNodes.top().node->value() );
is >> value;
if( std::fpclassify( value ) != FP_SUBNORMAL )
throw;
}
}
void loadValue( double & value )
{
try
{
value = std::stod( itsNodes.top().node->value() );
}
catch( std::out_of_range const & )
{
// special case for denormalized values
std::istringstream is( itsNodes.top().node->value() );
is >> value;
if( std::fpclassify( value ) != FP_SUBNORMAL )
throw;
}
}
void loadValue( long double & value )
{
try
{
value = std::stold( itsNodes.top().node->value() );
}
catch( std::out_of_range const & )
{
// special case for denormalized values
std::istringstream is( itsNodes.top().node->value() );
is >> value;
if( std::fpclassify( value ) != FP_SUBNORMAL )
throw;
}
}
template<class CharT, class Traits, class Alloc> inline
void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
{
std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
std::istreambuf_iterator<CharT, Traits>() );
}
template <class T> inline
void loadSize( T & value )
{
value = getNumChildren( itsNodes.top().node );
}
protected:
static size_t getNumChildren( rapidxml::xml_node<> * node )
{
size_t size = 0;
node = node->first_node(); // get first child
while( node != nullptr )
{
++size;
node = node->next_sibling();
}
return size;
}
struct NodeInfo
{
NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
node( n ),
child( n->first_node() ),
size( XMLInputArchive::getNumChildren( n ) ),
name( nullptr )
{ }
void advance()
{
if( size > 0 )
{
--size;
child = child->next_sibling();
}
}
rapidxml::xml_node<> * search( const char * searchName )
{
if( searchName )
{
size_t new_size = XMLInputArchive::getNumChildren( node );
const size_t name_size = rapidxml::internal::measure( searchName );
for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
{
if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
{
size = new_size;
child = new_child;
return new_child;
}
--new_size;
}
}
return nullptr;
}
const char * getChildName() const
{
return child ? child->name() : nullptr;
}
rapidxml::xml_node<> * node;
rapidxml::xml_node<> * child;
size_t size;
const char * name;
}; // NodeInfo
private:
std::vector<char> itsData;
rapidxml::xml_document<> itsXML;
std::stack<NodeInfo> itsNodes;
};
// ######################################################################
// XMLArchive prologue and epilogue functions
// ######################################################################
// ######################################################################
template <class T> inline
void prologue( XMLOutputArchive &, NameValuePair<T> const & )
{ }
template <class T> inline
void prologue( XMLInputArchive &, NameValuePair<T> const & )
{ }
// ######################################################################
template <class T> inline
void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
{ }
template <class T> inline
void epilogue( XMLInputArchive &, NameValuePair<T> const & )
{ }
// ######################################################################
template <class T> inline
void prologue( XMLOutputArchive &, DeferredData<T> const & )
{ }
template <class T> inline
void prologue( XMLInputArchive &, DeferredData<T> const & )
{ }
// ######################################################################
template <class T> inline
void epilogue( XMLOutputArchive &, DeferredData<T> const & )
{ }
template <class T> inline
void epilogue( XMLInputArchive &, DeferredData<T> const & )
{ }
// ######################################################################
template <class T> inline
void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
{
if (ar.hasSizeAttributes())
{
ar.appendAttribute("size", "dynamic");
}
}
template <class T> inline
void prologue( XMLInputArchive &, SizeTag<T> const & )
{ }
template <class T> inline
void epilogue( XMLOutputArchive &, SizeTag<T> const & )
{ }
template <class T> inline
void epilogue( XMLInputArchive &, SizeTag<T> const & )
{ }
// ######################################################################
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
void prologue( XMLOutputArchive & ar, T const & )
{
ar.startNode();
ar.insertType<T>();
}
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
void prologue( XMLInputArchive & ar, T const & )
{
ar.startNode();
}
// ######################################################################
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
void epilogue( XMLOutputArchive & ar, T const & )
{
ar.finishNode();
}
template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
void epilogue( XMLInputArchive & ar, T const & )
{
ar.finishNode();
}
// ######################################################################
// Common XMLArchive serialization functions
// ######################################################################
template <class T> inline
void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
{
ar.setNextName( t.name );
ar( t.value );
}
template <class T> inline
void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
{
ar.setNextName( t.name );
ar( t.value );
}
// ######################################################################
template <class T> inline
void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
{ }
template <class T> inline
void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
{
ar.loadSize( st.size );
}
// ######################################################################
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
{
ar.saveValue( t );
}
template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
{
ar.loadValue( t );
}
// ######################################################################
template<class CharT, class Traits, class Alloc> inline
void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
{
ar.saveValue( str );
}
template<class CharT, class Traits, class Alloc> inline
void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
{
ar.loadValue( str );
}
} // namespace cereal
// register archives for polymorphic support
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
// tie input and output archives together
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
#endif // CEREAL_ARCHIVES_XML_HPP_
cereal::InputArchive
The base input archive class.
Definition: cereal.hpp:710
cereal::XMLOutputArchive::appendAttribute
void appendAttribute(const char *name, const char *value)
Appends an attribute to the current top level node.
Definition: xml.hpp:313
cereal::XMLInputArchive::loadValue
void loadValue(long double &value)
Loads a type best represented as a long double from the current top node.
Definition: xml.hpp:646
cereal::XMLInputArchive::NodeInfo::name
const char * name
The NVP name for next child node.
Definition: xml.hpp:753
cereal::XMLInputArchive::loadValue
void loadValue(uint8_t &value)
Load a uint8_t from the current top node (ensures we parse entire number)
Definition: xml.hpp:559
cereal::prologue
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:751
cereal::XMLOutputArchive::NodeInfo::getValueName
std::string getValueName()
Gets the name for the next child node created from this node.
Definition: xml.hpp:341
cereal::XMLInputArchive::loadValue
void loadValue(T &value)
Loads a bool from the current top node.
Definition: xml.hpp:536
cereal::XMLOutputArchive::Options::Options
Options(int precision_=std::numeric_limits< double >::max_digits10, bool indent_=true, bool outputType_=false, bool sizeAttributes_=true)
Specify specific options for the XMLOutputArchive.
Definition: xml.hpp:117
cereal::XMLInputArchive::NodeInfo::getChildName
const char * getChildName() const
Returns the actual name of the next child node, if it exists.
Definition: xml.hpp:745
cereal::XMLInputArchive::loadBinaryValue
void loadBinaryValue(void *data, size_t size, const char *name=nullptr)
Loads some binary data, encoded as a base64 string, optionally specified by some name.
Definition: xml.hpp:454
cereal::XMLInputArchive::XMLInputArchive
XMLInputArchive(std::istream &stream)
Construct, reading in from the provided stream.
Definition: xml.hpp:417
cereal::XMLInputArchive::NodeInfo::search
rapidxml::xml_node * search(const char *searchName)
Searches for a child with the given name in this node.
Definition: xml.hpp:721
CEREAL_XML_STRING_VALUE
#define CEREAL_XML_STRING_VALUE
The default name for the root node in a cereal xml archive.
Definition: xml.hpp:54
cereal::XMLOutputArchive::XMLOutputArchive
XMLOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream upon destruction.
Definition: xml.hpp:163
cereal::XMLOutputArchive::Options
A class containing various advanced options for the XML archive.
Definition: xml.hpp:106
cereal::XMLInputArchive::value
value
Loads a type best represented as an int from the current top node.
Definition: xml.hpp:639
cereal::XMLInputArchive::getNumChildren
static size_t getNumChildren(rapidxml::xml_node<> *node)
Gets the number of children (usually interpreted as size) for the specified node.
Definition: xml.hpp:681
cereal::XMLInputArchive::loadValue
void loadValue(std::basic_string< CharT, Traits, Alloc > &str)
Loads a string from the current node from the current top node.
Definition: xml.hpp:664
cereal::XMLInputArchive::getNodeName
const char * getNodeName() const
Definition: xml.hpp:522
cereal::XMLOutputArchive::Options::outputType
Options & outputType(bool enable)
Whether to output the type of each serialized object as an attribute.
Definition: xml.hpp:144
cereal::XMLInputArchive::NodeInfo
A struct that contains metadata about a node.
Definition: xml.hpp:698
cereal::XMLOutputArchive::Options::precision
Options & precision(int value)
Sets the precision used for floaing point numbers.
Definition: xml.hpp:140
cereal::XMLOutputArchive::saveValue
void saveValue(int8_t const &value)
Overload for int8_t prevents them from being serialized as characters.
Definition: xml.hpp:291
cereal::XMLOutputArchive::saveBinaryValue
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: xml.hpp:200
cereal::XMLOutputArchive::NodeInfo
A struct that contains metadata about a node.
Definition: xml.hpp:324
CEREAL_LOAD_FUNCTION_NAME
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
cereal::XMLOutputArchive::saveValue
void saveValue(T const &value)
Saves some data, encoded as a string, into the current top level node.
Definition: xml.hpp:258
CEREAL_REGISTER_ARCHIVE
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
cereal::NameValuePair
For holding name value pairs.
Definition: helpers.hpp:139
cereal::XMLOutputArchive::insertType
void insertType()
Causes the type to be appended as an attribute to the most recently made node if output type is set t...
Definition: xml.hpp:298
cereal::traits::TextArchive
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1321
cereal::OutputArchive
The base output archive class.
Definition: cereal.hpp:318
cereal::XMLInputArchive::finishNode
void finishNode()
Finishes reading the current node.
Definition: xml.hpp:508
cereal::XMLOutputArchive::NodeInfo::node
rapidxml::xml_node * node
A pointer to this node.
Definition: xml.hpp:333
cereal::XMLOutputArchive::finishNode
void finishNode()
Designates the most recently added node as finished.
Definition: xml.hpp:242
CEREAL_SAVE_FUNCTION_NAME
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:92
cereal::XMLInputArchive
An output archive designed to load data from XML.
Definition: xml.hpp:405
cereal::XMLInputArchive::NodeInfo::size
size_t size
The remaining number of children for this node.
Definition: xml.hpp:752
CEREAL_SETUP_ARCHIVE_TRAITS
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
cereal::XMLInputArchive::loadSize
void loadSize(T &value)
Loads the size of the current top node.
Definition: xml.hpp:674
CEREAL_NOEXCEPT
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
cereal::XMLInputArchive::NodeInfo::child
rapidxml::xml_node * child
A pointer to its current child.
Definition: xml.hpp:751
cereal::XMLOutputArchive::NodeInfo::name
const char * name
The name for the next child node.
Definition: xml.hpp:335
cereal::XMLOutputArchive::setNextName
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:248
cereal::epilogue
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:763
cereal::XMLInputArchive::NodeInfo::advance
void advance()
Advances to the next sibling node of the child.
Definition: xml.hpp:709
cereal::XMLInputArchive::setNextName
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:528
cereal::XMLOutputArchive::saveValue
void saveValue(uint8_t const &value)
Overload for uint8_t prevents them from being serialized as characters.
Definition: xml.hpp:285
cereal.hpp
Main cereal functionality.
cereal::SizeTag
A wrapper around size metadata.
Definition: helpers.hpp:312
cereal::Exception
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48
cereal::XMLInputArchive::startNode
void startNode()
Prepares to start reading the next node.
Definition: xml.hpp:488
cereal::XMLOutputArchive::Options::sizeAttributes
Options & sizeAttributes(bool enable)
Whether dynamically sized containers (e.g. vector) output the size=dynamic attribute.
Definition: xml.hpp:146
cereal::DeferredData
A wrapper around data that should be serialized after all non-deferred data.
Definition: helpers.hpp:232
cereal::XMLInputArchive::NodeInfo::node
rapidxml::xml_node * node
A pointer to this node.
Definition: xml.hpp:750
cereal::XMLInputArchive::loadValue
void loadValue(int8_t &value)
Load an int8_t from the current top node (ensures we parse entire number)
Definition: xml.hpp:553
cereal::xml_detail::isWhitespace
bool isWhitespace(char c)
Returns true if the character is whitespace.
Definition: xml.hpp:61
cereal::XMLOutputArchive::Options::indent
Options & indent(bool enable)
Whether to indent each line of XML.
Definition: xml.hpp:142
cereal::XMLOutputArchive::startNode
void startNode()
Creates a new node that is a child of the node at the top of the stack.
Definition: xml.hpp:227
cereal::XMLOutputArchive
An output archive designed to save data to XML.
Definition: xml.hpp:96
cereal::XMLOutputArchive::NodeInfo::counter
size_t counter
The counter for naming child nodes.
Definition: xml.hpp:334
util.hpp
Internal misc utilities.
cereal::XMLOutputArchive::Options::Default
static Options Default()
Default options.
Definition: xml.hpp:110
cereal::XMLOutputArchive::~XMLOutputArchive
~XMLOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the XML.
Definition: xml.hpp:189