cereal
A C++11 library for serialization
xml.hpp
Go to the documentation of this file.
1 
3 /*
4  Copyright (c) 2014, Randolph Voorhies, Shane Grant
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without
8  modification, are permitted provided that the following conditions are met:
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  * Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in the
13  documentation and/or other materials provided with the distribution.
14  * Neither the name of cereal nor the
15  names of its contributors may be used to endorse or promote products
16  derived from this software without specific prior written permission.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef CEREAL_ARCHIVES_XML_HPP_
30 #define CEREAL_ARCHIVES_XML_HPP_
31 #include <cereal/cereal.hpp>
32 #include <cereal/details/util.hpp>
33 
34 #include <cereal/external/rapidxml/rapidxml.hpp>
35 #include <cereal/external/rapidxml/rapidxml_print.hpp>
36 #include <cereal/external/base64.hpp>
37 
38 #include <sstream>
39 #include <stack>
40 #include <vector>
41 #include <limits>
42 #include <string>
43 #include <cstring>
44 #include <cmath>
45 
46 namespace cereal
47 {
48  namespace xml_detail
49  {
50  #ifndef CEREAL_XML_STRING_VALUE
51 
54  #define CEREAL_XML_STRING_VALUE "cereal"
55  #endif // CEREAL_XML_STRING_VALUE
56 
58  static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
59 
61  inline bool isWhitespace( char c )
62  {
63  return c == ' ' || c == '\t' || c == '\n' || c == '\r';
64  }
65  }
66 
67  // ######################################################################
69 
96  class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
97  {
98  public:
101 
104  class Options
105  {
106  public:
108  static Options Default(){ return Options(); }
109 
111  static Options NoIndent(){ return Options( std::numeric_limits<double>::max_digits10, false ); }
112 
114 
117  explicit Options( int precision = std::numeric_limits<double>::max_digits10,
118  bool indent = true,
119  bool outputType = false ) :
120  itsPrecision( precision ),
121  itsIndent( indent ),
122  itsOutputType( outputType ) { }
123 
124  private:
125  friend class XMLOutputArchive;
126  int itsPrecision;
127  bool itsIndent;
128  bool itsOutputType;
129  };
130 
132 
136  XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
138  itsStream(stream),
139  itsOutputType( options.itsOutputType ),
140  itsIndent( options.itsIndent )
141  {
142  // rapidxml will delete all allocations when xml_document is cleared
143  auto node = itsXML.allocate_node( rapidxml::node_declaration );
144  node->append_attribute( itsXML.allocate_attribute( "version", "1.0" ) );
145  node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) );
146  itsXML.append_node( node );
147 
148  // allocate root node
149  auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
150  itsXML.append_node( root );
151  itsNodes.emplace( root );
152 
153  // set attributes on the streams
154  itsStream << std::boolalpha;
155  itsStream.precision( options.itsPrecision );
156  itsOS << std::boolalpha;
157  itsOS.precision( options.itsPrecision );
158  }
159 
162  {
163  const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
164  rapidxml::print( itsStream, itsXML, flags );
165  itsXML.clear();
166  }
167 
169 
172  void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
173  {
174  itsNodes.top().name = name;
175 
176  startNode();
177 
178  auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
179  saveValue( base64string );
180 
181  if( itsOutputType )
182  itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
183 
184  finishNode();
185  };
186 
188 
191 
194 
199  void startNode()
200  {
201  // generate a name for this new node
202  const auto nameString = itsNodes.top().getValueName();
203 
204  // allocate strings for all of the data in the XML object
205  auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
206 
207  // insert into the XML
208  auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
209  itsNodes.top().node->append_node( node );
210  itsNodes.emplace( node );
211  }
212 
214  void finishNode()
215  {
216  itsNodes.pop();
217  }
218 
220  void setNextName( const char * name )
221  {
222  itsNodes.top().name = name;
223  }
224 
226 
229  template <class T> inline
230  void saveValue( T const & value )
231  {
232  itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
233  itsOS << value << std::ends;
234 
235  const auto strValue = itsOS.str();
236 
237  // If the first or last character is a whitespace, add xml:space attribute
238  // the string always contains a '\0' added by std::ends, so the last character is at len-2 and an 'empty'
239  // string has a length of 1 or lower
240  const auto len = strValue.length();
241  if ( len > 1 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 2] ) ) )
242  {
243  itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
244  }
245 
246  // allocate strings for all of the data in the XML object
247  auto dataPtr = itsXML.allocate_string( itsOS.str().c_str(), itsOS.str().length() + 1 );
248 
249  // insert into the XML
250  itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
251  }
252 
254  void saveValue( uint8_t const & value )
255  {
256  saveValue( static_cast<uint32_t>( value ) );
257  }
258 
260  void saveValue( int8_t const & value )
261  {
262  saveValue( static_cast<int32_t>( value ) );
263  }
264 
266  template <class T> inline
267  void insertType()
268  {
269  if( !itsOutputType )
270  return;
271 
272  // generate a name for this new node
273  const auto nameString = util::demangledName<T>();
274 
275  // allocate strings for all of the data in the XML object
276  auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
277 
278  itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
279  }
280 
282  void appendAttribute( const char * name, const char * value )
283  {
284  auto namePtr = itsXML.allocate_string( name );
285  auto valuePtr = itsXML.allocate_string( value );
286  itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
287  }
288 
289  protected:
291  struct NodeInfo
292  {
293  NodeInfo( rapidxml::xml_node<> * n = nullptr,
294  const char * nm = nullptr ) :
295  node( n ),
296  counter( 0 ),
297  name( nm )
298  { }
299 
300  rapidxml::xml_node<> * node;
301  size_t counter;
302  const char * name;
303 
305 
308  std::string getValueName()
309  {
310  if( name )
311  {
312  auto n = name;
313  name = nullptr;
314  return {n};
315  }
316  else
317  return "value" + std::to_string( counter++ ) + "\0";
318  }
319  }; // NodeInfo
320 
322 
323  private:
324  std::ostream & itsStream;
325  rapidxml::xml_document<> itsXML;
326  std::stack<NodeInfo> itsNodes;
327  std::ostringstream itsOS;
328  bool itsOutputType;
329  bool itsIndent;
330  }; // XMLOutputArchive
331 
332  // ######################################################################
334 
368  class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
369  {
370  public:
373 
376 
380  XMLInputArchive( std::istream & stream ) :
381  InputArchive<XMLInputArchive>( this ),
382  itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
383  {
384  try
385  {
386  itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
387  itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
388  }
389  catch( rapidxml::parse_error const & )
390  {
391  //std::cerr << "-----Original-----" << std::endl;
392  //stream.seekg(0);
393  //std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
394 
395  //std::cerr << "-----Error-----" << std::endl;
396  //std::cerr << e.what() << std::endl;
397  //std::cerr << e.where<char>() << std::endl;
398  throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
399  }
400 
401  // Parse the root
402  auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
403  if( root == nullptr )
404  throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
405  else
406  itsNodes.emplace( root );
407  }
408 
410 
415  void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
416  {
417  setNextName( name );
418  startNode();
419 
420  std::string encoded;
421  loadValue( encoded );
422 
423  auto decoded = base64::decode( encoded );
424 
425  if( size != decoded.size() )
426  throw Exception("Decoded binary data size does not match specified size");
427 
428  std::memcpy( data, decoded.data(), decoded.size() );
429 
430  finishNode();
431  };
432 
434 
437 
440 
449  void startNode()
450  {
451  auto next = itsNodes.top().child; // By default we would move to the next child node
452  auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
453 
454  // If we were given an NVP name, look for it in the current level of the document.
455  // We only need to do this if either we have exhausted the siblings of the current level or
456  // the NVP name does not match the name of the node we would normally read next
457  if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
458  {
459  next = itsNodes.top().search( expectedName );
460 
461  if( next == nullptr )
462  throw Exception("XML Parsing failed - provided NVP not found");
463  }
464 
465  itsNodes.emplace( next );
466  }
467 
469  void finishNode()
470  {
471  // remove current
472  itsNodes.pop();
473 
474  // advance parent
475  itsNodes.top().advance();
476 
477  // Reset name
478  itsNodes.top().name = nullptr;
479  }
480 
483  const char * getNodeName() const
484  {
485  return itsNodes.top().node->name();
486  }
487 
489  void setNextName( const char * name )
490  {
491  itsNodes.top().name = name;
492  }
493 
495  template <class T, traits::EnableIf<std::is_unsigned<T>::value,
496  std::is_same<T, bool>::value> = traits::sfinae> inline
497  void loadValue( T & value )
498  {
499  std::istringstream is( itsNodes.top().node->value() );
500  is.setf( std::ios::boolalpha );
501  is >> value;
502  }
503 
505  template <class T, traits::EnableIf<std::is_integral<T>::value,
506  !std::is_same<T, bool>::value,
507  sizeof(T) == sizeof(char)> = traits::sfinae> inline
508  void loadValue( T & value )
509  {
510  value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
511  }
512 
514  void loadValue( int8_t & value )
515  {
516  int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
517  }
518 
520  void loadValue( uint8_t & value )
521  {
522  uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
523  }
524 
526  template <class T, traits::EnableIf<std::is_unsigned<T>::value,
527  !std::is_same<T, bool>::value,
528  !std::is_same<T, char>::value,
529  !std::is_same<T, unsigned char>::value,
530  sizeof(T) < sizeof(long long)> = traits::sfinae> inline
531  void loadValue( T & value )
532  {
533  value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
534  }
535 
537  template <class T, traits::EnableIf<std::is_unsigned<T>::value,
538  !std::is_same<T, bool>::value,
539  sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
540  void loadValue( T & value )
541  {
542  value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
543  }
544 
546  template <class T, traits::EnableIf<std::is_signed<T>::value,
547  !std::is_same<T, char>::value,
548  sizeof(T) <= sizeof(int)> = traits::sfinae> inline
549  void loadValue( T & value )
550  {
551  value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
552  }
553 
555  template <class T, traits::EnableIf<std::is_signed<T>::value,
556  (sizeof(T) > sizeof(int)),
557  sizeof(T) <= sizeof(long)> = traits::sfinae> inline
558  void loadValue( T & value )
559  {
560  value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
561  }
562 
564  template <class T, traits::EnableIf<std::is_signed<T>::value,
565  (sizeof(T) > sizeof(long)),
566  sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
567  void loadValue( T & value )
568  {
569  value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
570  }
571 
573  void loadValue( float & value )
574  {
575  try
576  {
577  value = std::stof( itsNodes.top().node->value() );
578  }
579  catch( std::out_of_range const & )
580  {
581  // special case for denormalized values
582  std::istringstream is( itsNodes.top().node->value() );
583  is >> value;
584  if( std::fpclassify( value ) != FP_SUBNORMAL )
585  throw;
586  }
587  }
588 
590  void loadValue( double & value )
591  {
592  try
593  {
594  value = std::stod( itsNodes.top().node->value() );
595  }
596  catch( std::out_of_range const & )
597  {
598  // special case for denormalized values
599  std::istringstream is( itsNodes.top().node->value() );
600  is >> value;
601  if( std::fpclassify( value ) != FP_SUBNORMAL )
602  throw;
603  }
604  }
605 
607  void loadValue( long double & value )
608  {
609  try
610  {
611  value = std::stold( itsNodes.top().node->value() );
612  }
613  catch( std::out_of_range const & )
614  {
615  // special case for denormalized values
616  std::istringstream is( itsNodes.top().node->value() );
617  is >> value;
618  if( std::fpclassify( value ) != FP_SUBNORMAL )
619  throw;
620  }
621  }
622 
624  template<class CharT, class Traits, class Alloc> inline
625  void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
626  {
627  std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
628 
629  str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
630  std::istreambuf_iterator<CharT, Traits>() );
631  }
632 
634  template <class T> inline
635  void loadSize( T & value )
636  {
637  value = getNumChildren( itsNodes.top().node );
638  }
639 
640  protected:
642  static size_t getNumChildren( rapidxml::xml_node<> * node )
643  {
644  size_t size = 0;
645  node = node->first_node(); // get first child
646 
647  while( node != nullptr )
648  {
649  ++size;
650  node = node->next_sibling();
651  }
652 
653  return size;
654  }
655 
657 
659  struct NodeInfo
660  {
661  NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
662  node( n ),
663  child( n->first_node() ),
664  size( XMLInputArchive::getNumChildren( n ) ),
665  name( nullptr )
666  { }
667 
669 
670  void advance()
671  {
672  if( size > 0 )
673  {
674  --size;
675  child = child->next_sibling();
676  }
677  }
678 
680 
682  rapidxml::xml_node<> * search( const char * searchName )
683  {
684  if( searchName )
685  {
686  size_t new_size = XMLInputArchive::getNumChildren( node );
687  const size_t name_size = rapidxml::internal::measure( searchName );
688 
689  for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
690  {
691  if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
692  {
693  size = new_size;
694  child = new_child;
695 
696  return new_child;
697  }
698  --new_size;
699  }
700  }
701 
702  return nullptr;
703  }
704 
705  rapidxml::xml_node<> * node;
706  rapidxml::xml_node<> * child;
707  size_t size;
708  const char * name;
709  }; // NodeInfo
710 
712 
713  private:
714  std::vector<char> itsData;
715  rapidxml::xml_document<> itsXML;
716  std::stack<NodeInfo> itsNodes;
717  };
718 
719  // ######################################################################
720  // XMLArchive prologue and epilogue functions
721  // ######################################################################
722 
723  // ######################################################################
725 
726  template <class T> inline
728  { }
729 
731  template <class T> inline
733  { }
734 
735  // ######################################################################
737 
738  template <class T> inline
740  { }
741 
743  template <class T> inline
745  { }
746 
747  // ######################################################################
749 
750  template <class T> inline
751  void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
752  {
753  ar.appendAttribute( "size", "dynamic" );
754  }
755 
756  template <class T> inline
757  void prologue( XMLInputArchive &, SizeTag<T> const & )
758  { }
759 
761 
762  template <class T> inline
764  { }
765 
766  template <class T> inline
767  void epilogue( XMLInputArchive &, SizeTag<T> const & )
768  { }
769 
770  // ######################################################################
772 
776  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
778  void prologue( XMLOutputArchive & ar, T const & )
779  {
780  ar.startNode();
781  ar.insertType<T>();
782  }
783 
785  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
787  void prologue( XMLInputArchive & ar, T const & )
788  {
789  ar.startNode();
790  }
791 
792  // ######################################################################
794 
797  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
799  void epilogue( XMLOutputArchive & ar, T const & )
800  {
801  ar.finishNode();
802  }
803 
805  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
807  void epilogue( XMLInputArchive & ar, T const & )
808  {
809  ar.finishNode();
810  }
811 
812  // ######################################################################
813  // Common XMLArchive serialization functions
814  // ######################################################################
815 
817  template <class T> inline
819  {
820  ar.setNextName( t.name );
821  ar( t.value );
822  }
823 
825  template <class T> inline
827  {
828  ar.setNextName( t.name );
829  ar( t.value );
830  }
831 
832  // ######################################################################
834  template <class T> inline
836  { }
837 
839  template <class T> inline
841  {
842  ar.loadSize( st.size );
843  }
844 
845  // ######################################################################
847  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
849  {
850  ar.saveValue( t );
851  }
852 
854  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
856  {
857  ar.loadValue( t );
858  }
859 
860  // ######################################################################
862  template<class CharT, class Traits, class Alloc> inline
863  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
864  {
865  ar.saveValue( str );
866  }
867 
869  template<class CharT, class Traits, class Alloc> inline
870  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
871  {
872  ar.loadValue( str );
873  }
874 } // namespace cereal
875 
876 // register archives for polymorphic support
879 
880 // tie input and output archives together
882 
883 #endif // CEREAL_ARCHIVES_XML_HPP_
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:220
~XMLOutputArchive()
Destructor, flushes the XML.
Definition: xml.hpp:161
Options(int precision=std::numeric_limits< double >::max_digits10, bool indent=true, bool outputType=false)
Specify specific options for the XMLOutputArchive.
Definition: xml.hpp:117
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
bool isWhitespace(char c)
Returns true if the character is whitespace.
Definition: xml.hpp:61
rapidxml::xml_node * child
A pointer to its current child.
Definition: xml.hpp:706
A wrapper around size metadata.
Definition: helpers.hpp:250
XMLInputArchive(std::istream &stream)
Construct, reading in from the provided stream.
Definition: xml.hpp:380
void loadValue(std::basic_string< CharT, Traits, Alloc > &str)
Loads a string from the current node from the current top node.
Definition: xml.hpp:625
size_t size
The remaining number of children for this node.
Definition: xml.hpp:707
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:702
static Options NoIndent()
Default options with no indentation.
Definition: xml.hpp:111
#define CEREAL_XML_STRING_VALUE
The default name for the root node in a cereal xml archive.
Definition: xml.hpp:54
STL namespace.
rapidxml::xml_node * node
A pointer to this node.
Definition: xml.hpp:705
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1266
The base input archive class.
Definition: cereal.hpp:584
void saveValue(T const &value)
Saves some data, encoded as a string, into the current top level node.
Definition: xml.hpp:230
const char * getNodeName() const
Definition: xml.hpp:483
void advance()
Advances to the next sibling node of the child.
Definition: xml.hpp:670
A struct that contains metadata about a node.
Definition: xml.hpp:291
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:267
A struct that contains metadata about a node.
Definition: xml.hpp:659
rapidxml::xml_node * search(const char *searchName)
Searches for a child with the given name in this node.
Definition: xml.hpp:682
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:489
std::string getValueName()
Gets the name for the next child node created from this node.
Definition: xml.hpp:308
void loadValue(long double &value)
Loads a type best represented as a long double from the current top node.
Definition: xml.hpp:607
void loadValue(int8_t &value)
Load an int8_t from the current top node (ensures we parse entire number)
Definition: xml.hpp:514
void saveValue(int8_t const &value)
Overload for int8_t prevents them from being serialized as characters.
Definition: xml.hpp:260
rapidxml::xml_node * node
A pointer to this node.
Definition: xml.hpp:300
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:172
size_t counter
The counter for naming child nodes.
Definition: xml.hpp:301
An output archive designed to save data to XML.
Definition: xml.hpp:96
const char * name
The NVP name for next next child node.
Definition: xml.hpp:708
Definition: access.hpp:39
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:141
An output archive designed to load data from XML.
Definition: xml.hpp:368
void startNode()
Creates a new node that is a child of the node at the top of the stack.
Definition: xml.hpp:199
Internal misc utilities.
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
void loadSize(T &value)
Loads the size of the current top node.
Definition: xml.hpp:635
void finishNode()
Designates the most recently added node as finished.
Definition: xml.hpp:214
void finishNode()
Finishes reading the current node.
Definition: xml.hpp:469
The base output archive class.
Definition: cereal.hpp:234
value
Loads a type best represented as an int from the current top node.
Definition: xml.hpp:600
void appendAttribute(const char *name, const char *value)
Appends an attribute to the current top level node.
Definition: xml.hpp:282
static size_t getNumChildren(rapidxml::xml_node<> *node)
Gets the number of children (usually interpreted as size) for the specified node. ...
Definition: xml.hpp:642
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:65
static Options Default()
Default options.
Definition: xml.hpp:108
void startNode()
Prepares to start reading the next node.
Definition: xml.hpp:449
const char * name
The name for the next child node.
Definition: xml.hpp:302
void loadValue(T &value)
Loads a bool from the current top node.
Definition: xml.hpp:497
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:714
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:415
A class containing various advanced options for the XML archive.
Definition: xml.hpp:104
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:48
void loadValue(uint8_t &value)
Load a uint8_t from the current top node (ensures we parse entire number)
Definition: xml.hpp:520
void saveValue(uint8_t const &value)
Overload for uint8_t prevents them from being serialized as characters.
Definition: xml.hpp:254
XMLOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream upon destruction.
Definition: xml.hpp:136