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, unsigned char>::value,
529  sizeof(T) < sizeof(long long)> = traits::sfinae> inline
530  void loadValue( T & value )
531  {
532  value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
533  }
534 
536  template <class T, traits::EnableIf<std::is_unsigned<T>::value,
537  !std::is_same<T, bool>::value,
538  sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
539  void loadValue( T & value )
540  {
541  value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
542  }
543 
545  template <class T, traits::EnableIf<std::is_signed<T>::value,
546  !std::is_same<T, char>::value,
547  sizeof(T) <= sizeof(int)> = traits::sfinae> inline
548  void loadValue( T & value )
549  {
550  value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
551  }
552 
554  template <class T, traits::EnableIf<std::is_signed<T>::value,
555  (sizeof(T) > sizeof(int)),
556  sizeof(T) <= sizeof(long)> = traits::sfinae> inline
557  void loadValue( T & value )
558  {
559  value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
560  }
561 
563  template <class T, traits::EnableIf<std::is_signed<T>::value,
564  (sizeof(T) > sizeof(long)),
565  sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
566  void loadValue( T & value )
567  {
568  value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
569  }
570 
572  void loadValue( float & value )
573  {
574  try
575  {
576  value = std::stof( itsNodes.top().node->value() );
577  }
578  catch( std::out_of_range const & )
579  {
580  // special case for denormalized values
581  std::istringstream is( itsNodes.top().node->value() );
582  is >> value;
583  if( std::fpclassify( value ) != FP_SUBNORMAL )
584  throw;
585  }
586  }
587 
589  void loadValue( double & value )
590  {
591  try
592  {
593  value = std::stod( itsNodes.top().node->value() );
594  }
595  catch( std::out_of_range const & )
596  {
597  // special case for denormalized values
598  std::istringstream is( itsNodes.top().node->value() );
599  is >> value;
600  if( std::fpclassify( value ) != FP_SUBNORMAL )
601  throw;
602  }
603  }
604 
606  void loadValue( long double & value )
607  {
608  try
609  {
610  value = std::stold( itsNodes.top().node->value() );
611  }
612  catch( std::out_of_range const & )
613  {
614  // special case for denormalized values
615  std::istringstream is( itsNodes.top().node->value() );
616  is >> value;
617  if( std::fpclassify( value ) != FP_SUBNORMAL )
618  throw;
619  }
620  }
621 
623  template<class CharT, class Traits, class Alloc> inline
624  void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
625  {
626  std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
627 
628  str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
629  std::istreambuf_iterator<CharT, Traits>() );
630  }
631 
633  template <class T> inline
634  void loadSize( T & value )
635  {
636  value = getNumChildren( itsNodes.top().node );
637  }
638 
639  protected:
641  static size_t getNumChildren( rapidxml::xml_node<> * node )
642  {
643  size_t size = 0;
644  node = node->first_node(); // get first child
645 
646  while( node != nullptr )
647  {
648  ++size;
649  node = node->next_sibling();
650  }
651 
652  return size;
653  }
654 
656 
658  struct NodeInfo
659  {
660  NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
661  node( n ),
662  child( n->first_node() ),
664  name( nullptr )
665  { }
666 
668 
669  void advance()
670  {
671  if( size > 0 )
672  {
673  --size;
674  child = child->next_sibling();
675  }
676  }
677 
679 
681  rapidxml::xml_node<> * search( const char * searchName )
682  {
683  if( searchName )
684  {
685  size_t new_size = XMLInputArchive::getNumChildren( node );
686  const size_t name_size = rapidxml::internal::measure( searchName );
687 
688  for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
689  {
690  if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
691  {
692  size = new_size;
693  child = new_child;
694 
695  return new_child;
696  }
697  --new_size;
698  }
699  }
700 
701  return nullptr;
702  }
703 
704  rapidxml::xml_node<> * node;
705  rapidxml::xml_node<> * child;
706  size_t size;
707  const char * name;
708  }; // NodeInfo
709 
711 
712  private:
713  std::vector<char> itsData;
714  rapidxml::xml_document<> itsXML;
715  std::stack<NodeInfo> itsNodes;
716  };
717 
718  // ######################################################################
719  // XMLArchive prologue and epilogue functions
720  // ######################################################################
721 
722  // ######################################################################
724 
725  template <class T> inline
726  void prologue( XMLOutputArchive &, NameValuePair<T> const & )
727  { }
728 
730  template <class T> inline
731  void prologue( XMLInputArchive &, NameValuePair<T> const & )
732  { }
733 
734  // ######################################################################
736 
737  template <class T> inline
738  void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
739  { }
740 
742  template <class T> inline
743  void epilogue( XMLInputArchive &, NameValuePair<T> const & )
744  { }
745 
746  // ######################################################################
748 
749  template <class T> inline
750  void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
751  {
752  ar.appendAttribute( "size", "dynamic" );
753  }
754 
755  template <class T> inline
756  void prologue( XMLInputArchive &, SizeTag<T> const & )
757  { }
758 
760 
761  template <class T> inline
762  void epilogue( XMLOutputArchive &, SizeTag<T> const & )
763  { }
764 
765  template <class T> inline
766  void epilogue( XMLInputArchive &, SizeTag<T> const & )
767  { }
768 
769  // ######################################################################
771 
775  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
776  traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
777  void prologue( XMLOutputArchive & ar, T const & )
778  {
779  ar.startNode();
780  ar.insertType<T>();
781  }
782 
784  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
785  traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
786  void prologue( XMLInputArchive & ar, T const & )
787  {
788  ar.startNode();
789  }
790 
791  // ######################################################################
793 
796  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
797  traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
798  void epilogue( XMLOutputArchive & ar, T const & )
799  {
800  ar.finishNode();
801  }
802 
804  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
805  traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
806  void epilogue( XMLInputArchive & ar, T const & )
807  {
808  ar.finishNode();
809  }
810 
811  // ######################################################################
812  // Common XMLArchive serialization functions
813  // ######################################################################
814 
816  template <class T> inline
817  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
818  {
819  ar.setNextName( t.name );
820  ar( t.value );
821  }
822 
824  template <class T> inline
825  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
826  {
827  ar.setNextName( t.name );
828  ar( t.value );
829  }
830 
831  // ######################################################################
833  template <class T> inline
834  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
835  { }
836 
838  template <class T> inline
839  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
840  {
841  ar.loadSize( st.size );
842  }
843 
844  // ######################################################################
846  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
847  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
848  {
849  ar.saveValue( t );
850  }
851 
853  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
854  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
855  {
856  ar.loadValue( t );
857  }
858 
859  // ######################################################################
861  template<class CharT, class Traits, class Alloc> inline
862  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
863  {
864  ar.saveValue( str );
865  }
866 
868  template<class CharT, class Traits, class Alloc> inline
869  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
870  {
871  ar.loadValue( str );
872  }
873 } // namespace cereal
874 
875 // register archives for polymorphic support
877 CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
878 
879 // tie input and output archives together
880 CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
881 
882 #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
rapidxml::xml_node * child
A pointer to its current child.
Definition: xml.hpp:705
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:624
size_t size
The remaining number of children for this node.
Definition: xml.hpp:706
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:704
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:669
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:658
rapidxml::xml_node * search(const char *searchName)
Searches for a child with the given name in this node.
Definition: xml.hpp:681
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:606
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:707
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:634
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:599
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:641
#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 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