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  auto strValue = itsOS.str();
236 
237  // itsOS.str() may contain data from previous calls after the first '\0' that was just inserted
238  // and this data is counted in the length call. We make sure to remove that section so that the
239  // whitespace validation is done properly
240  strValue.resize(std::strlen(strValue.c_str()));
241 
242  // If the first or last character is a whitespace, add xml:space attribute
243  const auto len = strValue.length();
244  if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) )
245  {
246  itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
247  }
248 
249  // allocate strings for all of the data in the XML object
250  auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 );
251 
252  // insert into the XML
253  itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
254  }
255 
257  void saveValue( uint8_t const & value )
258  {
259  saveValue( static_cast<uint32_t>( value ) );
260  }
261 
263  void saveValue( int8_t const & value )
264  {
265  saveValue( static_cast<int32_t>( value ) );
266  }
267 
269  template <class T> inline
270  void insertType()
271  {
272  if( !itsOutputType )
273  return;
274 
275  // generate a name for this new node
276  const auto nameString = util::demangledName<T>();
277 
278  // allocate strings for all of the data in the XML object
279  auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
280 
281  itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
282  }
283 
285  void appendAttribute( const char * name, const char * value )
286  {
287  auto namePtr = itsXML.allocate_string( name );
288  auto valuePtr = itsXML.allocate_string( value );
289  itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
290  }
291 
292  protected:
294  struct NodeInfo
295  {
296  NodeInfo( rapidxml::xml_node<> * n = nullptr,
297  const char * nm = nullptr ) :
298  node( n ),
299  counter( 0 ),
300  name( nm )
301  { }
302 
303  rapidxml::xml_node<> * node;
304  size_t counter;
305  const char * name;
306 
308 
311  std::string getValueName()
312  {
313  if( name )
314  {
315  auto n = name;
316  name = nullptr;
317  return {n};
318  }
319  else
320  return "value" + std::to_string( counter++ ) + "\0";
321  }
322  }; // NodeInfo
323 
325 
326  private:
327  std::ostream & itsStream;
328  rapidxml::xml_document<> itsXML;
329  std::stack<NodeInfo> itsNodes;
330  std::ostringstream itsOS;
331  bool itsOutputType;
332  bool itsIndent;
333  }; // XMLOutputArchive
334 
335  // ######################################################################
337 
374  class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
375  {
376  public:
379 
382 
386  XMLInputArchive( std::istream & stream ) :
387  InputArchive<XMLInputArchive>( this ),
388  itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
389  {
390  try
391  {
392  itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
393  itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
394  }
395  catch( rapidxml::parse_error const & )
396  {
397  //std::cerr << "-----Original-----" << std::endl;
398  //stream.seekg(0);
399  //std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
400 
401  //std::cerr << "-----Error-----" << std::endl;
402  //std::cerr << e.what() << std::endl;
403  //std::cerr << e.where<char>() << std::endl;
404  throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
405  }
406 
407  // Parse the root
408  auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
409  if( root == nullptr )
410  throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
411  else
412  itsNodes.emplace( root );
413  }
414 
415  ~XMLInputArchive() CEREAL_NOEXCEPT = default;
416 
418 
423  void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
424  {
425  setNextName( name );
426  startNode();
427 
428  std::string encoded;
429  loadValue( encoded );
430 
431  auto decoded = base64::decode( encoded );
432 
433  if( size != decoded.size() )
434  throw Exception("Decoded binary data size does not match specified size");
435 
436  std::memcpy( data, decoded.data(), decoded.size() );
437 
438  finishNode();
439  };
440 
442 
445 
448 
457  void startNode()
458  {
459  auto next = itsNodes.top().child; // By default we would move to the next child node
460  auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
461 
462  // If we were given an NVP name, look for it in the current level of the document.
463  // We only need to do this if either we have exhausted the siblings of the current level or
464  // the NVP name does not match the name of the node we would normally read next
465  if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
466  {
467  next = itsNodes.top().search( expectedName );
468 
469  if( next == nullptr )
470  throw Exception("XML Parsing failed - provided NVP (" + std::string(expectedName) + ") not found");
471  }
472 
473  itsNodes.emplace( next );
474  }
475 
477  void finishNode()
478  {
479  // remove current
480  itsNodes.pop();
481 
482  // advance parent
483  itsNodes.top().advance();
484 
485  // Reset name
486  itsNodes.top().name = nullptr;
487  }
488 
491  const char * getNodeName() const
492  {
493  return itsNodes.top().getChildName();
494  }
495 
497  void setNextName( const char * name )
498  {
499  itsNodes.top().name = name;
500  }
501 
503  template <class T, traits::EnableIf<std::is_unsigned<T>::value,
504  std::is_same<T, bool>::value> = traits::sfinae> inline
505  void loadValue( T & value )
506  {
507  std::istringstream is( itsNodes.top().node->value() );
508  is.setf( std::ios::boolalpha );
509  is >> value;
510  }
511 
513  template <class T, traits::EnableIf<std::is_integral<T>::value,
514  !std::is_same<T, bool>::value,
515  sizeof(T) == sizeof(char)> = traits::sfinae> inline
516  void loadValue( T & value )
517  {
518  value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
519  }
520 
522  void loadValue( int8_t & value )
523  {
524  int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
525  }
526 
528  void loadValue( uint8_t & value )
529  {
530  uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
531  }
532 
534  template <class T, traits::EnableIf<std::is_unsigned<T>::value,
535  !std::is_same<T, bool>::value,
536  !std::is_same<T, char>::value,
537  !std::is_same<T, unsigned char>::value,
538  sizeof(T) < sizeof(long long)> = traits::sfinae> inline
539  void loadValue( T & value )
540  {
541  value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
542  }
543 
545  template <class T, traits::EnableIf<std::is_unsigned<T>::value,
546  !std::is_same<T, bool>::value,
547  sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
548  void loadValue( T & value )
549  {
550  value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
551  }
552 
554  template <class T, traits::EnableIf<std::is_signed<T>::value,
555  !std::is_same<T, char>::value,
556  sizeof(T) <= sizeof(int)> = traits::sfinae> inline
557  void loadValue( T & value )
558  {
559  value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
560  }
561 
563  template <class T, traits::EnableIf<std::is_signed<T>::value,
564  (sizeof(T) > sizeof(int)),
565  sizeof(T) <= sizeof(long)> = traits::sfinae> inline
566  void loadValue( T & value )
567  {
568  value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
569  }
570 
572  template <class T, traits::EnableIf<std::is_signed<T>::value,
573  (sizeof(T) > sizeof(long)),
574  sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
575  void loadValue( T & value )
576  {
577  value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
578  }
579 
581  void loadValue( float & value )
582  {
583  try
584  {
585  value = std::stof( itsNodes.top().node->value() );
586  }
587  catch( std::out_of_range const & )
588  {
589  // special case for denormalized values
590  std::istringstream is( itsNodes.top().node->value() );
591  is >> value;
592  if( std::fpclassify( value ) != FP_SUBNORMAL )
593  throw;
594  }
595  }
596 
598  void loadValue( double & value )
599  {
600  try
601  {
602  value = std::stod( itsNodes.top().node->value() );
603  }
604  catch( std::out_of_range const & )
605  {
606  // special case for denormalized values
607  std::istringstream is( itsNodes.top().node->value() );
608  is >> value;
609  if( std::fpclassify( value ) != FP_SUBNORMAL )
610  throw;
611  }
612  }
613 
615  void loadValue( long double & value )
616  {
617  try
618  {
619  value = std::stold( itsNodes.top().node->value() );
620  }
621  catch( std::out_of_range const & )
622  {
623  // special case for denormalized values
624  std::istringstream is( itsNodes.top().node->value() );
625  is >> value;
626  if( std::fpclassify( value ) != FP_SUBNORMAL )
627  throw;
628  }
629  }
630 
632  template<class CharT, class Traits, class Alloc> inline
633  void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
634  {
635  std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
636 
637  str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
638  std::istreambuf_iterator<CharT, Traits>() );
639  }
640 
642  template <class T> inline
643  void loadSize( T & value )
644  {
645  value = getNumChildren( itsNodes.top().node );
646  }
647 
648  protected:
650  static size_t getNumChildren( rapidxml::xml_node<> * node )
651  {
652  size_t size = 0;
653  node = node->first_node(); // get first child
654 
655  while( node != nullptr )
656  {
657  ++size;
658  node = node->next_sibling();
659  }
660 
661  return size;
662  }
663 
665 
667  struct NodeInfo
668  {
669  NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
670  node( n ),
671  child( n->first_node() ),
673  name( nullptr )
674  { }
675 
677 
678  void advance()
679  {
680  if( size > 0 )
681  {
682  --size;
683  child = child->next_sibling();
684  }
685  }
686 
688 
690  rapidxml::xml_node<> * search( const char * searchName )
691  {
692  if( searchName )
693  {
694  size_t new_size = XMLInputArchive::getNumChildren( node );
695  const size_t name_size = rapidxml::internal::measure( searchName );
696 
697  for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
698  {
699  if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
700  {
701  size = new_size;
702  child = new_child;
703 
704  return new_child;
705  }
706  --new_size;
707  }
708  }
709 
710  return nullptr;
711  }
712 
714  const char * getChildName() const
715  {
716  return child ? child->name() : nullptr;
717  }
718 
719  rapidxml::xml_node<> * node;
720  rapidxml::xml_node<> * child;
721  size_t size;
722  const char * name;
723  }; // NodeInfo
724 
726 
727  private:
728  std::vector<char> itsData;
729  rapidxml::xml_document<> itsXML;
730  std::stack<NodeInfo> itsNodes;
731  };
732 
733  // ######################################################################
734  // XMLArchive prologue and epilogue functions
735  // ######################################################################
736 
737  // ######################################################################
739 
740  template <class T> inline
741  void prologue( XMLOutputArchive &, NameValuePair<T> const & )
742  { }
743 
745  template <class T> inline
746  void prologue( XMLInputArchive &, NameValuePair<T> const & )
747  { }
748 
749  // ######################################################################
751 
752  template <class T> inline
753  void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
754  { }
755 
757  template <class T> inline
758  void epilogue( XMLInputArchive &, NameValuePair<T> const & )
759  { }
760 
761  // ######################################################################
763 
764  template <class T> inline
765  void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
766  {
767  ar.appendAttribute( "size", "dynamic" );
768  }
769 
770  template <class T> inline
771  void prologue( XMLInputArchive &, SizeTag<T> const & )
772  { }
773 
775 
776  template <class T> inline
777  void epilogue( XMLOutputArchive &, SizeTag<T> const & )
778  { }
779 
780  template <class T> inline
781  void epilogue( XMLInputArchive &, SizeTag<T> const & )
782  { }
783 
784  // ######################################################################
786 
790  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
791  traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
792  void prologue( XMLOutputArchive & ar, T const & )
793  {
794  ar.startNode();
795  ar.insertType<T>();
796  }
797 
799  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
800  traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
801  void prologue( XMLInputArchive & ar, T const & )
802  {
803  ar.startNode();
804  }
805 
806  // ######################################################################
808 
811  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
812  traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
813  void epilogue( XMLOutputArchive & ar, T const & )
814  {
815  ar.finishNode();
816  }
817 
819  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
820  traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
821  void epilogue( XMLInputArchive & ar, T const & )
822  {
823  ar.finishNode();
824  }
825 
826  // ######################################################################
827  // Common XMLArchive serialization functions
828  // ######################################################################
829 
831  template <class T> inline
832  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
833  {
834  ar.setNextName( t.name );
835  ar( t.value );
836  }
837 
839  template <class T> inline
840  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
841  {
842  ar.setNextName( t.name );
843  ar( t.value );
844  }
845 
846  // ######################################################################
848  template <class T> inline
849  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
850  { }
851 
853  template <class T> inline
854  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
855  {
856  ar.loadSize( st.size );
857  }
858 
859  // ######################################################################
861  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
862  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
863  {
864  ar.saveValue( t );
865  }
866 
868  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
869  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
870  {
871  ar.loadValue( t );
872  }
873 
874  // ######################################################################
876  template<class CharT, class Traits, class Alloc> inline
877  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
878  {
879  ar.saveValue( str );
880  }
881 
883  template<class CharT, class Traits, class Alloc> inline
884  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
885  {
886  ar.loadValue( str );
887  }
888 } // namespace cereal
889 
890 // register archives for polymorphic support
892 CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
893 
894 // tie input and output archives together
895 CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
896 
897 #endif // CEREAL_ARCHIVES_XML_HPP_
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:220
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:720
XMLInputArchive(std::istream &stream)
Construct, reading in from the provided stream.
Definition: xml.hpp:386
void loadValue(std::basic_string< CharT, Traits, Alloc > &str)
Loads a string from the current node from the current top node.
Definition: xml.hpp:633
size_t size
The remaining number of children for this node.
Definition: xml.hpp:721
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:719
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1299
The base input archive class.
Definition: cereal.hpp:599
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:491
const char * getChildName() const
Returns the actual name of the next child node, if it exists.
Definition: xml.hpp:714
void advance()
Advances to the next sibling node of the child.
Definition: xml.hpp:678
A struct that contains metadata about a node.
Definition: xml.hpp:294
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:270
A struct that contains metadata about a node.
Definition: xml.hpp:667
rapidxml::xml_node * search(const char *searchName)
Searches for a child with the given name in this node.
Definition: xml.hpp:690
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:497
std::string getValueName()
Gets the name for the next child node created from this node.
Definition: xml.hpp:311
void loadValue(long double &value)
Loads a type best represented as a long double from the current top node.
Definition: xml.hpp:615
void loadValue(int8_t &value)
Load an int8_t from the current top node (ensures we parse entire number)
Definition: xml.hpp:522
void saveValue(int8_t const &value)
Overload for int8_t prevents them from being serialized as characters.
Definition: xml.hpp:263
rapidxml::xml_node * node
A pointer to this node.
Definition: xml.hpp:303
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:304
An output archive designed to save data to XML.
Definition: xml.hpp:96
const char * name
The NVP name for next child node.
Definition: xml.hpp:722
Definition: access.hpp:40
#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:374
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:137
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
void loadSize(T &value)
Loads the size of the current top node.
Definition: xml.hpp:643
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
void finishNode()
Designates the most recently added node as finished.
Definition: xml.hpp:214
void finishNode()
Finishes reading the current node.
Definition: xml.hpp:477
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:608
void appendAttribute(const char *name, const char *value)
Appends an attribute to the current top level node.
Definition: xml.hpp:285
static size_t getNumChildren(rapidxml::xml_node<> *node)
Gets the number of children (usually interpreted as size) for the specified node. ...
Definition: xml.hpp:650
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:92
static Options Default()
Default options.
Definition: xml.hpp:108
void startNode()
Prepares to start reading the next node.
Definition: xml.hpp:457
const char * name
The name for the next child node.
Definition: xml.hpp:305
void loadValue(T &value)
Loads a bool from the current top node.
Definition: xml.hpp:505
~XMLOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the XML.
Definition: xml.hpp:161
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:423
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:528
void saveValue(uint8_t const &value)
Overload for uint8_t prevents them from being serialized as characters.
Definition: xml.hpp:257
XMLOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream upon destruction.
Definition: xml.hpp:136