29#ifndef CEREAL_ARCHIVES_XML_HPP_ 
   30#define CEREAL_ARCHIVES_XML_HPP_ 
   34#include "cereal/external/rapidxml/rapidxml.hpp" 
   35#include "cereal/external/rapidxml/rapidxml_print.hpp" 
   36#include "cereal/external/base64.hpp" 
   50    #ifndef CEREAL_XML_STRING_VALUE 
   54    #define CEREAL_XML_STRING_VALUE "cereal" 
   63      return c == 
' ' || c == 
'\t' || c == 
'\n' || c == 
'\r';
 
  117          explicit Options( 
int precision_ = std::numeric_limits<double>::max_digits10,
 
  119                            bool outputType_ = 
false,
 
  120                            bool sizeAttributes_ = 
true ) :
 
  121            itsPrecision( precision_ ),
 
  122            itsIndent( indent_ ),
 
  123            itsOutputType( outputType_ ),
 
  124            itsSizeAttributes( sizeAttributes_ )
 
  155          bool itsSizeAttributes;
 
  166        itsOutputType( options.itsOutputType ),
 
  167        itsIndent( options.itsIndent ),
 
  168        itsSizeAttributes(options.itsSizeAttributes)
 
  171        auto node = itsXML.allocate_node( rapidxml::node_declaration );
 
  172        node->append_attribute( itsXML.allocate_attribute( 
"version", 
"1.0" ) );
 
  173        node->append_attribute( itsXML.allocate_attribute( 
"encoding", 
"utf-8" ) );
 
  174        itsXML.append_node( node );
 
  177        auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
 
  178        itsXML.append_node( root );
 
  179        itsNodes.emplace( root );
 
  182        itsStream << std::boolalpha;
 
  183        itsStream.precision( options.itsPrecision );
 
  184        itsOS << std::boolalpha;
 
  185        itsOS.precision( options.itsPrecision );
 
  191        const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
 
  192        rapidxml::print( itsStream, itsXML, flags );
 
  202        itsNodes.top().name = name;
 
  206        auto base64string = base64::encode( 
reinterpret_cast<const unsigned char *
>( data ), size );
 
  210          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( 
"type", 
"cereal binary data" ) );
 
  230        const auto nameString = itsNodes.top().getValueName();
 
  233        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
 
  236        auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, 
nullptr, nameString.size() );
 
  237        itsNodes.top().node->append_node( node );
 
  238        itsNodes.emplace( node );
 
  250        itsNodes.top().name = name;
 
  257      template <
class T> 
inline 
  260        itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
 
  261        itsOS << value << std::ends;
 
  263        auto strValue = itsOS.str();
 
  268        strValue.resize(std::strlen(strValue.c_str()));
 
  271        const auto len = strValue.length();
 
  272        if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) )
 
  274          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( 
"xml:space", 
"preserve" ) );
 
  278        auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 );
 
  281        itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, 
nullptr, dataPtr ) );
 
  287        saveValue( 
static_cast<uint32_t
>( value ) );
 
  293        saveValue( 
static_cast<int32_t
>( value ) );
 
  297      template <
class T> 
inline 
  304        const auto nameString = util::demangledName<T>();
 
  307        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
 
  309        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( 
"type", namePtr ) );
 
  315        auto namePtr =  itsXML.allocate_string( name );
 
  316        auto valuePtr = itsXML.allocate_string( value );
 
  317        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
 
  320      bool hasSizeAttributes()
 const { 
return itsSizeAttributes; }
 
  326        NodeInfo( rapidxml::xml_node<> * n = 
nullptr,
 
  327                  const char * nm = 
nullptr ) :
 
  350            return "value" + std::to_string( 
counter++ ) + 
"\0";
 
  357      std::ostream & itsStream;        
 
  358      rapidxml::xml_document<> itsXML; 
 
  359      std::stack<NodeInfo> itsNodes;   
 
  360      std::ostringstream itsOS;        
 
  363      bool itsSizeAttributes;          
 
  419        itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
 
  423          itsData.push_back(
'\0'); 
 
  424          itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( 
reinterpret_cast<char *
>( itsData.data() ) );
 
  426        catch( rapidxml::parse_error 
const & )
 
  435          throw Exception(
"XML Parsing failed - likely due to invalid characters or invalid naming");
 
  439        auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
 
  440        if( root == 
nullptr )
 
  441          throw Exception(
"Could not detect cereal root node - likely due to empty or invalid input");
 
  443          itsNodes.emplace( root );
 
  462        auto decoded = base64::decode( encoded );
 
  464        if( size != decoded.size() )
 
  465          throw Exception(
"Decoded binary data size does not match specified size");
 
  467        std::memcpy( data, decoded.data(), decoded.size() );
 
  490        auto next = itsNodes.top().child; 
 
  491        auto const expectedName = itsNodes.top().name; 
 
  496        if( expectedName && ( next == 
nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
 
  498          next = itsNodes.top().search( expectedName );
 
  500          if( next == 
nullptr )
 
  501            throw Exception(
"XML Parsing failed - provided NVP (" + std::string(expectedName) + 
") not found");
 
  504        itsNodes.emplace( next );
 
  514        itsNodes.top().advance();
 
  517        itsNodes.top().name = 
nullptr;
 
  524        return itsNodes.top().getChildName();
 
  530        itsNodes.top().name = name;
 
  534      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
 
  535                                          std::is_same<T, bool>::value> = traits::sfinae> 
inline 
  538        std::istringstream is( itsNodes.top().node->value() );
 
  539        is.setf( std::ios::boolalpha );
 
  544      template <class T, traits::EnableIf<std::is_integral<T>::value,
 
  545                                          !std::is_same<T, bool>::value,
 
  546                                          sizeof(T) == 
sizeof(
char)> = traits::sfinae> 
inline 
  549        value = *
reinterpret_cast<T*
>( itsNodes.top().node->value() );
 
  555        int32_t val; 
loadValue( val ); 
value = 
static_cast<int8_t
>( val );
 
  561        uint32_t val; 
loadValue( val ); 
value = 
static_cast<uint8_t
>( val );
 
  565      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
 
  566                                          !std::is_same<T, bool>::value,
 
  567                                          !std::is_same<T, char>::value,
 
  568                                          !std::is_same<T, unsigned char>::value,
 
  569                                          sizeof(T) < 
sizeof(
long long)> = traits::sfinae> 
inline 
  572        value = 
static_cast<T
>( std::stoul( itsNodes.top().node->value() ) );
 
  576      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
 
  577                                          !std::is_same<T, bool>::value,
 
  578                                          sizeof(T) >= 
sizeof(
long long)> = traits::sfinae> 
inline 
  581        value = 
static_cast<T
>( std::stoull( itsNodes.top().node->value() ) );
 
  585      template <class T, traits::EnableIf<std::is_signed<T>::value,
 
  586                                          !std::is_same<T, char>::value,
 
  587                                          sizeof(T) <= 
sizeof(
int)> = traits::sfinae> 
inline 
  590        value = 
static_cast<T
>( std::stoi( itsNodes.top().node->value() ) );
 
  594      template <class T, traits::EnableIf<std::is_signed<T>::value,
 
  595                                          (
sizeof(T) > 
sizeof(
int)),
 
  596                                          sizeof(T) <= 
sizeof(long)> = traits::sfinae> 
inline 
  599        value = 
static_cast<T
>( std::stol( itsNodes.top().node->value() ) );
 
  603      template <class T, traits::EnableIf<std::is_signed<T>::value,
 
  604                                          (
sizeof(T) > 
sizeof(
long)),
 
  605                                          sizeof(T) <= 
sizeof(
long long)> = traits::sfinae> 
inline 
  608        value = 
static_cast<T
>( std::stoll( itsNodes.top().node->value() ) );
 
  616          value = std::stof( itsNodes.top().node->value() );
 
  618        catch( std::out_of_range 
const & )
 
  621          std::istringstream is( itsNodes.top().node->value() );
 
  623          if( std::fpclassify( 
value ) != FP_SUBNORMAL )
 
  633          value = std::stod( itsNodes.top().node->value() );
 
  635        catch( std::out_of_range 
const & )
 
  638          std::istringstream is( itsNodes.top().node->value() );
 
  640          if( std::fpclassify( 
value ) != FP_SUBNORMAL )
 
  650          value = std::stold( itsNodes.top().node->value() );
 
  652        catch( std::out_of_range 
const & )
 
  655          std::istringstream is( itsNodes.top().node->value() );
 
  657          if( std::fpclassify( 
value ) != FP_SUBNORMAL )
 
  663      template<
class CharT, 
class Traits, 
class Alloc> 
inline 
  664      void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
 
  666        std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
 
  668        str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
 
  669                    std::istreambuf_iterator<CharT, Traits>() );
 
  673      template <
class T> 
inline 
  684        node = node->first_node(); 
 
  686        while( node != 
nullptr )
 
  689          node = node->next_sibling();
 
  700        NodeInfo( rapidxml::xml_node<> * n = 
nullptr ) :
 
  702          child( n->first_node() ),
 
  721        rapidxml::xml_node<> * 
search( 
const char * searchName )
 
  726            const size_t name_size = rapidxml::internal::measure( searchName );
 
  728            for( 
auto new_child = 
node->first_node(); new_child != 
nullptr; new_child = new_child->next_sibling() )
 
  730              if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, 
true ) )
 
  759      std::vector<char> itsData;       
 
  760      rapidxml::xml_document<> itsXML; 
 
  761      std::stack<NodeInfo> itsNodes;   
 
  771  template <
class T> 
inline 
  776  template <
class T> 
inline 
  783  template <
class T> 
inline 
  788  template <
class T> 
inline 
  795  template <
class T> 
inline 
  800  template <
class T> 
inline 
  807  template <
class T> 
inline 
  813  template <
class T> 
inline 
  820  template <
class T> 
inline 
  823      if (ar.hasSizeAttributes())
 
  829  template <
class T> 
inline 
  830  void prologue( XMLInputArchive &, SizeTag<T> 
const & )
 
  835  template <
class T> 
inline 
  839  template <
class T> 
inline 
  840  void epilogue( XMLInputArchive &, SizeTag<T> 
const & )
 
  849  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
 
  850                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> 
inline 
  858  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
 
  859                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> 
inline 
  870  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
 
  871                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> 
inline 
  878  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
 
  879                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> 
inline 
  890  template <
class T> 
inline 
  898  template <
class T> 
inline 
  907  template <
class T> 
inline 
  912  template <
class T> 
inline 
  920  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> 
inline 
  927  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> 
inline 
  935  template<
class CharT, 
class Traits, 
class Alloc> 
inline 
  942  template<
class CharT, 
class Traits, 
class Alloc> 
inline 
Main cereal functionality.
 
A wrapper around data that should be serialized after all non-deferred data.
Definition: helpers.hpp:233
 
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
 
A class containing various advanced options for the XML archive.
Definition: xml.hpp:107
 
Options & precision(int value)
Sets the precision used for floaing point numbers.
Definition: xml.hpp:140
 
Options & sizeAttributes(bool enable)
Whether dynamically sized containers (e.g. vector) output the size=dynamic attribute.
Definition: xml.hpp:146
 
Options & outputType(bool enable)
Whether to output the type of each serialized object as an attribute.
Definition: xml.hpp:144
 
static Options Default()
Default options.
Definition: xml.hpp:110
 
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
 
Options & indent(bool enable)
Whether to indent each line of XML.
Definition: xml.hpp:142
 
An output archive designed to save data to XML.
Definition: xml.hpp:97
 
void saveValue(int8_t const &value)
Overload for int8_t prevents them from being serialized as characters.
Definition: xml.hpp:291
 
~XMLOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the XML.
Definition: xml.hpp:189
 
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
 
void saveValue(uint8_t const &value)
Overload for uint8_t prevents them from being serialized as characters.
Definition: xml.hpp:285
 
XMLOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream upon destruction.
Definition: xml.hpp:163
 
void startNode()
Creates a new node that is a child of the node at the top of the stack.
Definition: xml.hpp:227
 
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
 
void saveValue(T const &value)
Saves some data, encoded as a string, into the current top level node.
Definition: xml.hpp:258
 
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:248
 
void finishNode()
Designates the most recently added node as finished.
Definition: xml.hpp:242
 
void appendAttribute(const char *name, const char *value)
Appends an attribute to the current top level node.
Definition: xml.hpp:313
 
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
 
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
 
A struct that contains metadata about a node.
Definition: xml.hpp:325
 
rapidxml::xml_node * node
A pointer to this node.
Definition: xml.hpp:333
 
std::string getValueName()
Gets the name for the next child node created from this node.
Definition: xml.hpp:341
 
const char * name
The name for the next child node.
Definition: xml.hpp:335
 
size_t counter
The counter for naming child nodes.
Definition: xml.hpp:334
 
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
 
#define CEREAL_XML_STRING_VALUE
The default name for the root node in a cereal xml archive.
Definition: xml.hpp:54
 
bool isWhitespace(char c)
Returns true if the character is whitespace.
Definition: xml.hpp:61