git repos / blockattack-game

blame: source/code/Libs/include/cereal/archives/xml.hpp

normal view · raw

7a956470 sago007 2016-02-14 17:09 1
/*! \file xml.hpp
7a956470 sago007 2016-02-14 17:09 2
    \brief XML input and output archives */
7a956470 sago007 2016-02-14 17:09 3
/*
7a956470 sago007 2016-02-14 17:09 4
  Copyright (c) 2014, Randolph Voorhies, Shane Grant
7a956470 sago007 2016-02-14 17:09 5
  All rights reserved.
7a956470 sago007 2016-02-14 17:09 6
7a956470 sago007 2016-02-14 17:09 7
  Redistribution and use in source and binary forms, with or without
7a956470 sago007 2016-02-14 17:09 8
  modification, are permitted provided that the following conditions are met:
7a956470 sago007 2016-02-14 17:09 9
      * Redistributions of source code must retain the above copyright
7a956470 sago007 2016-02-14 17:09 10
        notice, this list of conditions and the following disclaimer.
7a956470 sago007 2016-02-14 17:09 11
      * Redistributions in binary form must reproduce the above copyright
7a956470 sago007 2016-02-14 17:09 12
        notice, this list of conditions and the following disclaimer in the
7a956470 sago007 2016-02-14 17:09 13
        documentation and/or other materials provided with the distribution.
7a956470 sago007 2016-02-14 17:09 14
      * Neither the name of cereal nor the
7a956470 sago007 2016-02-14 17:09 15
        names of its contributors may be used to endorse or promote products
7a956470 sago007 2016-02-14 17:09 16
        derived from this software without specific prior written permission.
7a956470 sago007 2016-02-14 17:09 17
7a956470 sago007 2016-02-14 17:09 18
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
7a956470 sago007 2016-02-14 17:09 19
  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7a956470 sago007 2016-02-14 17:09 20
  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7a956470 sago007 2016-02-14 17:09 21
  DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
7a956470 sago007 2016-02-14 17:09 22
  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7a956470 sago007 2016-02-14 17:09 23
  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7a956470 sago007 2016-02-14 17:09 24
  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
7a956470 sago007 2016-02-14 17:09 25
  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7a956470 sago007 2016-02-14 17:09 26
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
7a956470 sago007 2016-02-14 17:09 27
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7a956470 sago007 2016-02-14 17:09 28
*/
7a956470 sago007 2016-02-14 17:09 29
#ifndef CEREAL_ARCHIVES_XML_HPP_
7a956470 sago007 2016-02-14 17:09 30
#define CEREAL_ARCHIVES_XML_HPP_
7a956470 sago007 2016-02-14 17:09 31
#include <cereal/cereal.hpp>
7a956470 sago007 2016-02-14 17:09 32
#include <cereal/details/util.hpp>
7a956470 sago007 2016-02-14 17:09 33
7a956470 sago007 2016-02-14 17:09 34
#include <cereal/external/rapidxml/rapidxml.hpp>
7a956470 sago007 2016-02-14 17:09 35
#include <cereal/external/rapidxml/rapidxml_print.hpp>
7a956470 sago007 2016-02-14 17:09 36
#include <cereal/external/base64.hpp>
7a956470 sago007 2016-02-14 17:09 37
7a956470 sago007 2016-02-14 17:09 38
#include <sstream>
7a956470 sago007 2016-02-14 17:09 39
#include <stack>
7a956470 sago007 2016-02-14 17:09 40
#include <vector>
7a956470 sago007 2016-02-14 17:09 41
#include <limits>
7a956470 sago007 2016-02-14 17:09 42
#include <string>
7a956470 sago007 2016-02-14 17:09 43
#include <cstring>
7a956470 sago007 2016-02-14 17:09 44
#include <cmath>
7a956470 sago007 2016-02-14 17:09 45
7a956470 sago007 2016-02-14 17:09 46
namespace cereal
7a956470 sago007 2016-02-14 17:09 47
{
7a956470 sago007 2016-02-14 17:09 48
  namespace xml_detail
7a956470 sago007 2016-02-14 17:09 49
  {
7a956470 sago007 2016-02-14 17:09 50
    #ifndef CEREAL_XML_STRING_VALUE
7a956470 sago007 2016-02-14 17:09 51
    //! The default name for the root node in a cereal xml archive.
7a956470 sago007 2016-02-14 17:09 52
    /*! You can define CEREAL_XML_STRING_VALUE to be different assuming you do so
7a956470 sago007 2016-02-14 17:09 53
        before this file is included. */
7a956470 sago007 2016-02-14 17:09 54
    #define CEREAL_XML_STRING_VALUE "cereal"
7a956470 sago007 2016-02-14 17:09 55
    #endif // CEREAL_XML_STRING_VALUE
7a956470 sago007 2016-02-14 17:09 56
7a956470 sago007 2016-02-14 17:09 57
    //! The name given to the root node in a cereal xml archive
7a956470 sago007 2016-02-14 17:09 58
    static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
7a956470 sago007 2016-02-14 17:09 59
7a956470 sago007 2016-02-14 17:09 60
    //! Returns true if the character is whitespace
7a956470 sago007 2016-02-14 17:09 61
    inline bool isWhitespace( char c )
7a956470 sago007 2016-02-14 17:09 62
    {
7a956470 sago007 2016-02-14 17:09 63
      return c == ' ' || c == '\t' || c == '\n' || c == '\r';
7a956470 sago007 2016-02-14 17:09 64
    }
7a956470 sago007 2016-02-14 17:09 65
  }
7a956470 sago007 2016-02-14 17:09 66
7a956470 sago007 2016-02-14 17:09 67
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 68
  //! An output archive designed to save data to XML
7a956470 sago007 2016-02-14 17:09 69
  /*! This archive uses RapidXML to build an in memory XML tree of the
7a956470 sago007 2016-02-14 17:09 70
      data it serializes before outputting it to its stream upon destruction.
7a956470 sago007 2016-02-14 17:09 71
      The envisioned way of using this archive is in an RAII fashion, letting
7a956470 sago007 2016-02-14 17:09 72
      the automatic destruction of the object cause the flush to its stream.
7a956470 sago007 2016-02-14 17:09 73
7a956470 sago007 2016-02-14 17:09 74
      XML archives provides a human readable output but at decreased
7a956470 sago007 2016-02-14 17:09 75
      performance (both in time and space) compared to binary archives.
7a956470 sago007 2016-02-14 17:09 76
7a956470 sago007 2016-02-14 17:09 77
      XML benefits greatly from name-value pairs, which if present, will
7a956470 sago007 2016-02-14 17:09 78
      name the nodes in the output.  If these are not present, each level
7a956470 sago007 2016-02-14 17:09 79
      of the output tree will be given an automatically generated delimited name.
7a956470 sago007 2016-02-14 17:09 80
7a956470 sago007 2016-02-14 17:09 81
      The precision of the output archive controls the number of decimals output
7a956470 sago007 2016-02-14 17:09 82
      for floating point numbers and should be sufficiently large (i.e. at least 20)
7a956470 sago007 2016-02-14 17:09 83
      if there is a desire to have binary equality between the numbers output and
7a956470 sago007 2016-02-14 17:09 84
      those read in.  In general you should expect a loss of precision when going
7a956470 sago007 2016-02-14 17:09 85
      from floating point to text and back.
7a956470 sago007 2016-02-14 17:09 86
7a956470 sago007 2016-02-14 17:09 87
      XML archives can optionally print the type of everything they serialize, which
7a956470 sago007 2016-02-14 17:09 88
      adds an attribute to each node.
7a956470 sago007 2016-02-14 17:09 89
7a956470 sago007 2016-02-14 17:09 90
      XML archives do not output the size information for any dynamically sized structure
7a956470 sago007 2016-02-14 17:09 91
      and instead infer it from the number of children for a node.  This means that data
7a956470 sago007 2016-02-14 17:09 92
      can be hand edited for dynamic sized structures and will still be readable.  This
7a956470 sago007 2016-02-14 17:09 93
      is accomplished through the cereal::SizeTag object, which will also add an attribute
7a956470 sago007 2016-02-14 17:09 94
      to its parent field.
7a956470 sago007 2016-02-14 17:09 95
      \ingroup Archives */
7a956470 sago007 2016-02-14 17:09 96
  class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
7a956470 sago007 2016-02-14 17:09 97
  {
7a956470 sago007 2016-02-14 17:09 98
    public:
7a956470 sago007 2016-02-14 17:09 99
      /*! @name Common Functionality
7a956470 sago007 2016-02-14 17:09 100
          Common use cases for directly interacting with an XMLOutputArchive */
7a956470 sago007 2016-02-14 17:09 101
      //! @{
7a956470 sago007 2016-02-14 17:09 102
7a956470 sago007 2016-02-14 17:09 103
      //! A class containing various advanced options for the XML archive
7a956470 sago007 2016-02-14 17:09 104
      class Options
7a956470 sago007 2016-02-14 17:09 105
      {
7a956470 sago007 2016-02-14 17:09 106
        public:
7a956470 sago007 2016-02-14 17:09 107
          //! Default options
7a956470 sago007 2016-02-14 17:09 108
          static Options Default(){ return Options(); }
7a956470 sago007 2016-02-14 17:09 109
7a956470 sago007 2016-02-14 17:09 110
          //! Default options with no indentation
7a956470 sago007 2016-02-14 17:09 111
          static Options NoIndent(){ return Options( std::numeric_limits<double>::max_digits10, false ); }
7a956470 sago007 2016-02-14 17:09 112
7a956470 sago007 2016-02-14 17:09 113
          //! Specify specific options for the XMLOutputArchive
7a956470 sago007 2016-02-14 17:09 114
          /*! @param precision The precision used for floating point numbers
7a956470 sago007 2016-02-14 17:09 115
              @param indent Whether to indent each line of XML
7a956470 sago007 2016-02-14 17:09 116
              @param outputType Whether to output the type of each serialized object as an attribute */
7a956470 sago007 2016-02-14 17:09 117
          explicit Options( int precision = std::numeric_limits<double>::max_digits10,
7a956470 sago007 2016-02-14 17:09 118
                            bool indent = true,
7a956470 sago007 2016-02-14 17:09 119
                            bool outputType = false ) :
7a956470 sago007 2016-02-14 17:09 120
            itsPrecision( precision ),
7a956470 sago007 2016-02-14 17:09 121
            itsIndent( indent ),
7a956470 sago007 2016-02-14 17:09 122
            itsOutputType( outputType ) { }
7a956470 sago007 2016-02-14 17:09 123
7a956470 sago007 2016-02-14 17:09 124
        private:
7a956470 sago007 2016-02-14 17:09 125
          friend class XMLOutputArchive;
7a956470 sago007 2016-02-14 17:09 126
          int itsPrecision;
7a956470 sago007 2016-02-14 17:09 127
          bool itsIndent;
7a956470 sago007 2016-02-14 17:09 128
          bool itsOutputType;
7a956470 sago007 2016-02-14 17:09 129
      };
7a956470 sago007 2016-02-14 17:09 130
7a956470 sago007 2016-02-14 17:09 131
      //! Construct, outputting to the provided stream upon destruction
7a956470 sago007 2016-02-14 17:09 132
      /*! @param stream  The stream to output to.  Note that XML is only guaranteed to flush
7a956470 sago007 2016-02-14 17:09 133
                         its output to the stream upon destruction.
7a956470 sago007 2016-02-14 17:09 134
          @param options The XML specific options to use.  See the Options struct
7a956470 sago007 2016-02-14 17:09 135
                         for the values of default parameters */
7a956470 sago007 2016-02-14 17:09 136
      XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
7a956470 sago007 2016-02-14 17:09 137
        OutputArchive<XMLOutputArchive>(this),
7a956470 sago007 2016-02-14 17:09 138
        itsStream(stream),
7a956470 sago007 2016-02-14 17:09 139
        itsOutputType( options.itsOutputType ),
7a956470 sago007 2016-02-14 17:09 140
        itsIndent( options.itsIndent )
7a956470 sago007 2016-02-14 17:09 141
      {
7a956470 sago007 2016-02-14 17:09 142
        // rapidxml will delete all allocations when xml_document is cleared
7a956470 sago007 2016-02-14 17:09 143
        auto node = itsXML.allocate_node( rapidxml::node_declaration );
7a956470 sago007 2016-02-14 17:09 144
        node->append_attribute( itsXML.allocate_attribute( "version", "1.0" ) );
7a956470 sago007 2016-02-14 17:09 145
        node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) );
7a956470 sago007 2016-02-14 17:09 146
        itsXML.append_node( node );
7a956470 sago007 2016-02-14 17:09 147
7a956470 sago007 2016-02-14 17:09 148
        // allocate root node
7a956470 sago007 2016-02-14 17:09 149
        auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
7a956470 sago007 2016-02-14 17:09 150
        itsXML.append_node( root );
7a956470 sago007 2016-02-14 17:09 151
        itsNodes.emplace( root );
7a956470 sago007 2016-02-14 17:09 152
7a956470 sago007 2016-02-14 17:09 153
        // set attributes on the streams
7a956470 sago007 2016-02-14 17:09 154
        itsStream << std::boolalpha;
7a956470 sago007 2016-02-14 17:09 155
        itsStream.precision( options.itsPrecision );
7a956470 sago007 2016-02-14 17:09 156
        itsOS << std::boolalpha;
7a956470 sago007 2016-02-14 17:09 157
        itsOS.precision( options.itsPrecision );
7a956470 sago007 2016-02-14 17:09 158
      }
7a956470 sago007 2016-02-14 17:09 159
7a956470 sago007 2016-02-14 17:09 160
      //! Destructor, flushes the XML
7a956470 sago007 2016-02-14 17:09 161
      ~XMLOutputArchive()
7a956470 sago007 2016-02-14 17:09 162
      {
7a956470 sago007 2016-02-14 17:09 163
        const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
7a956470 sago007 2016-02-14 17:09 164
        rapidxml::print( itsStream, itsXML, flags );
7a956470 sago007 2016-02-14 17:09 165
        itsXML.clear();
7a956470 sago007 2016-02-14 17:09 166
      }
7a956470 sago007 2016-02-14 17:09 167
7a956470 sago007 2016-02-14 17:09 168
      //! Saves some binary data, encoded as a base64 string, with an optional name
7a956470 sago007 2016-02-14 17:09 169
      /*! This can be called directly by users and it will automatically create a child node for
7a956470 sago007 2016-02-14 17:09 170
          the current XML node, populate it with a base64 encoded string, and optionally name
7a956470 sago007 2016-02-14 17:09 171
          it.  The node will be finished after it has been populated.  */
7a956470 sago007 2016-02-14 17:09 172
      void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
7a956470 sago007 2016-02-14 17:09 173
      {
7a956470 sago007 2016-02-14 17:09 174
        itsNodes.top().name = name;
7a956470 sago007 2016-02-14 17:09 175
7a956470 sago007 2016-02-14 17:09 176
        startNode();
7a956470 sago007 2016-02-14 17:09 177
7a956470 sago007 2016-02-14 17:09 178
        auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
7a956470 sago007 2016-02-14 17:09 179
        saveValue( base64string );
7a956470 sago007 2016-02-14 17:09 180
7a956470 sago007 2016-02-14 17:09 181
        if( itsOutputType )
7a956470 sago007 2016-02-14 17:09 182
          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
7a956470 sago007 2016-02-14 17:09 183
7a956470 sago007 2016-02-14 17:09 184
        finishNode();
7a956470 sago007 2016-02-14 17:09 185
      };
7a956470 sago007 2016-02-14 17:09 186
7a956470 sago007 2016-02-14 17:09 187
      //! @}
7a956470 sago007 2016-02-14 17:09 188
      /*! @name Internal Functionality
7a956470 sago007 2016-02-14 17:09 189
          Functionality designed for use by those requiring control over the inner mechanisms of
7a956470 sago007 2016-02-14 17:09 190
          the XMLOutputArchive */
7a956470 sago007 2016-02-14 17:09 191
      //! @{
7a956470 sago007 2016-02-14 17:09 192
7a956470 sago007 2016-02-14 17:09 193
      //! Creates a new node that is a child of the node at the top of the stack
7a956470 sago007 2016-02-14 17:09 194
      /*! Nodes will be given a name that has either been pre-set by a name value pair,
7a956470 sago007 2016-02-14 17:09 195
          or generated based upon a counter unique to the parent node.  If you want to
7a956470 sago007 2016-02-14 17:09 196
          give a node a specific name, use setNextName prior to calling startNode.
7a956470 sago007 2016-02-14 17:09 197
7a956470 sago007 2016-02-14 17:09 198
          The node will then be pushed onto the node stack. */
7a956470 sago007 2016-02-14 17:09 199
      void startNode()
7a956470 sago007 2016-02-14 17:09 200
      {
7a956470 sago007 2016-02-14 17:09 201
        // generate a name for this new node
7a956470 sago007 2016-02-14 17:09 202
        const auto nameString = itsNodes.top().getValueName();
7a956470 sago007 2016-02-14 17:09 203
7a956470 sago007 2016-02-14 17:09 204
        // allocate strings for all of the data in the XML object
7a956470 sago007 2016-02-14 17:09 205
        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
7a956470 sago007 2016-02-14 17:09 206
7a956470 sago007 2016-02-14 17:09 207
        // insert into the XML
7a956470 sago007 2016-02-14 17:09 208
        auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
7a956470 sago007 2016-02-14 17:09 209
        itsNodes.top().node->append_node( node );
7a956470 sago007 2016-02-14 17:09 210
        itsNodes.emplace( node );
7a956470 sago007 2016-02-14 17:09 211
      }
7a956470 sago007 2016-02-14 17:09 212
7a956470 sago007 2016-02-14 17:09 213
      //! Designates the most recently added node as finished
7a956470 sago007 2016-02-14 17:09 214
      void finishNode()
7a956470 sago007 2016-02-14 17:09 215
      {
7a956470 sago007 2016-02-14 17:09 216
        itsNodes.pop();
7a956470 sago007 2016-02-14 17:09 217
      }
7a956470 sago007 2016-02-14 17:09 218
7a956470 sago007 2016-02-14 17:09 219
      //! Sets the name for the next node created with startNode
7a956470 sago007 2016-02-14 17:09 220
      void setNextName( const char * name )
7a956470 sago007 2016-02-14 17:09 221
      {
7a956470 sago007 2016-02-14 17:09 222
        itsNodes.top().name = name;
7a956470 sago007 2016-02-14 17:09 223
      }
7a956470 sago007 2016-02-14 17:09 224
7a956470 sago007 2016-02-14 17:09 225
      //! Saves some data, encoded as a string, into the current top level node
7a956470 sago007 2016-02-14 17:09 226
      /*! The data will be be named with the most recent name if one exists,
7a956470 sago007 2016-02-14 17:09 227
          otherwise it will be given some default delimited value that depends upon
7a956470 sago007 2016-02-14 17:09 228
          the parent node */
7a956470 sago007 2016-02-14 17:09 229
      template <class T> inline
7a956470 sago007 2016-02-14 17:09 230
      void saveValue( T const & value )
7a956470 sago007 2016-02-14 17:09 231
      {
7a956470 sago007 2016-02-14 17:09 232
        itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
7a956470 sago007 2016-02-14 17:09 233
        itsOS << value << std::ends;
7a956470 sago007 2016-02-14 17:09 234
7a956470 sago007 2016-02-14 17:09 235
        const auto strValue = itsOS.str();
7a956470 sago007 2016-02-14 17:09 236
7a956470 sago007 2016-02-14 17:09 237
        // If the first or last character is a whitespace, add xml:space attribute
7a956470 sago007 2016-02-14 17:09 238
        // the string always contains a '\0' added by std::ends, so the last character is at len-2 and an 'empty' 
7a956470 sago007 2016-02-14 17:09 239
        // string has a length of 1 or lower
7a956470 sago007 2016-02-14 17:09 240
        const auto len = strValue.length();
7a956470 sago007 2016-02-14 17:09 241
        if ( len > 1 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 2] ) ) )
7a956470 sago007 2016-02-14 17:09 242
        {
7a956470 sago007 2016-02-14 17:09 243
          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
7a956470 sago007 2016-02-14 17:09 244
        }
7a956470 sago007 2016-02-14 17:09 245
7a956470 sago007 2016-02-14 17:09 246
        // allocate strings for all of the data in the XML object
7a956470 sago007 2016-02-14 17:09 247
        auto dataPtr = itsXML.allocate_string( itsOS.str().c_str(), itsOS.str().length() + 1 );
7a956470 sago007 2016-02-14 17:09 248
7a956470 sago007 2016-02-14 17:09 249
        // insert into the XML
7a956470 sago007 2016-02-14 17:09 250
        itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
7a956470 sago007 2016-02-14 17:09 251
      }
7a956470 sago007 2016-02-14 17:09 252
7a956470 sago007 2016-02-14 17:09 253
      //! Overload for uint8_t prevents them from being serialized as characters
7a956470 sago007 2016-02-14 17:09 254
      void saveValue( uint8_t const & value )
7a956470 sago007 2016-02-14 17:09 255
      {
7a956470 sago007 2016-02-14 17:09 256
        saveValue( static_cast<uint32_t>( value ) );
7a956470 sago007 2016-02-14 17:09 257
      }
7a956470 sago007 2016-02-14 17:09 258
7a956470 sago007 2016-02-14 17:09 259
      //! Overload for int8_t prevents them from being serialized as characters
7a956470 sago007 2016-02-14 17:09 260
      void saveValue( int8_t const & value )
7a956470 sago007 2016-02-14 17:09 261
      {
7a956470 sago007 2016-02-14 17:09 262
        saveValue( static_cast<int32_t>( value ) );
7a956470 sago007 2016-02-14 17:09 263
      }
7a956470 sago007 2016-02-14 17:09 264
7a956470 sago007 2016-02-14 17:09 265
      //! Causes the type to be appended as an attribute to the most recently made node if output type is set to true
7a956470 sago007 2016-02-14 17:09 266
      template <class T> inline
7a956470 sago007 2016-02-14 17:09 267
      void insertType()
7a956470 sago007 2016-02-14 17:09 268
      {
7a956470 sago007 2016-02-14 17:09 269
        if( !itsOutputType )
7a956470 sago007 2016-02-14 17:09 270
          return;
7a956470 sago007 2016-02-14 17:09 271
7a956470 sago007 2016-02-14 17:09 272
        // generate a name for this new node
7a956470 sago007 2016-02-14 17:09 273
        const auto nameString = util::demangledName<T>();
7a956470 sago007 2016-02-14 17:09 274
7a956470 sago007 2016-02-14 17:09 275
        // allocate strings for all of the data in the XML object
7a956470 sago007 2016-02-14 17:09 276
        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
7a956470 sago007 2016-02-14 17:09 277
7a956470 sago007 2016-02-14 17:09 278
        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
7a956470 sago007 2016-02-14 17:09 279
      }
7a956470 sago007 2016-02-14 17:09 280
7a956470 sago007 2016-02-14 17:09 281
      //! Appends an attribute to the current top level node
7a956470 sago007 2016-02-14 17:09 282
      void appendAttribute( const char * name, const char * value )
7a956470 sago007 2016-02-14 17:09 283
      {
7a956470 sago007 2016-02-14 17:09 284
        auto namePtr =  itsXML.allocate_string( name );
7a956470 sago007 2016-02-14 17:09 285
        auto valuePtr = itsXML.allocate_string( value );
7a956470 sago007 2016-02-14 17:09 286
        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
7a956470 sago007 2016-02-14 17:09 287
      }
7a956470 sago007 2016-02-14 17:09 288
7a956470 sago007 2016-02-14 17:09 289
    protected:
7a956470 sago007 2016-02-14 17:09 290
      //! A struct that contains metadata about a node
7a956470 sago007 2016-02-14 17:09 291
      struct NodeInfo
7a956470 sago007 2016-02-14 17:09 292
      {
7a956470 sago007 2016-02-14 17:09 293
        NodeInfo( rapidxml::xml_node<> * n = nullptr,
7a956470 sago007 2016-02-14 17:09 294
                  const char * nm = nullptr ) :
7a956470 sago007 2016-02-14 17:09 295
          node( n ),
7a956470 sago007 2016-02-14 17:09 296
          counter( 0 ),
7a956470 sago007 2016-02-14 17:09 297
          name( nm )
7a956470 sago007 2016-02-14 17:09 298
        { }
7a956470 sago007 2016-02-14 17:09 299
7a956470 sago007 2016-02-14 17:09 300
        rapidxml::xml_node<> * node; //!< A pointer to this node
7a956470 sago007 2016-02-14 17:09 301
        size_t counter;              //!< The counter for naming child nodes
7a956470 sago007 2016-02-14 17:09 302
        const char * name;           //!< The name for the next child node
7a956470 sago007 2016-02-14 17:09 303
7a956470 sago007 2016-02-14 17:09 304
        //! Gets the name for the next child node created from this node
7a956470 sago007 2016-02-14 17:09 305
        /*! The name will be automatically generated using the counter if
7a956470 sago007 2016-02-14 17:09 306
            a name has not been previously set.  If a name has been previously
7a956470 sago007 2016-02-14 17:09 307
            set, that name will be returned only once */
7a956470 sago007 2016-02-14 17:09 308
        std::string getValueName()
7a956470 sago007 2016-02-14 17:09 309
        {
7a956470 sago007 2016-02-14 17:09 310
          if( name )
7a956470 sago007 2016-02-14 17:09 311
          {
7a956470 sago007 2016-02-14 17:09 312
            auto n = name;
7a956470 sago007 2016-02-14 17:09 313
            name = nullptr;
7a956470 sago007 2016-02-14 17:09 314
            return {n};
7a956470 sago007 2016-02-14 17:09 315
          }
7a956470 sago007 2016-02-14 17:09 316
          else
7a956470 sago007 2016-02-14 17:09 317
            return "value" + std::to_string( counter++ ) + "\0";
7a956470 sago007 2016-02-14 17:09 318
        }
7a956470 sago007 2016-02-14 17:09 319
      }; // NodeInfo
7a956470 sago007 2016-02-14 17:09 320
7a956470 sago007 2016-02-14 17:09 321
      //! @}
7a956470 sago007 2016-02-14 17:09 322
7a956470 sago007 2016-02-14 17:09 323
    private:
7a956470 sago007 2016-02-14 17:09 324
      std::ostream & itsStream;        //!< The output stream
7a956470 sago007 2016-02-14 17:09 325
      rapidxml::xml_document<> itsXML; //!< The XML document
7a956470 sago007 2016-02-14 17:09 326
      std::stack<NodeInfo> itsNodes;   //!< A stack of nodes added to the document
7a956470 sago007 2016-02-14 17:09 327
      std::ostringstream itsOS;        //!< Used to format strings internally
7a956470 sago007 2016-02-14 17:09 328
      bool itsOutputType;              //!< Controls whether type information is printed
7a956470 sago007 2016-02-14 17:09 329
      bool itsIndent;                  //!< Controls whether indenting is used
7a956470 sago007 2016-02-14 17:09 330
  }; // XMLOutputArchive
7a956470 sago007 2016-02-14 17:09 331
7a956470 sago007 2016-02-14 17:09 332
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 333
  //! An output archive designed to load data from XML
7a956470 sago007 2016-02-14 17:09 334
  /*! This archive uses RapidXML to build an in memory XML tree of the
7a956470 sago007 2016-02-14 17:09 335
      data in the stream it is given before loading any types serialized.
7a956470 sago007 2016-02-14 17:09 336
7a956470 sago007 2016-02-14 17:09 337
      Input XML should have been produced by the XMLOutputArchive.  Data can
7a956470 sago007 2016-02-14 17:09 338
      only be added to dynamically sized containers - the input archive will
7a956470 sago007 2016-02-14 17:09 339
      determine their size by looking at the number of child nodes.  Data that
7a956470 sago007 2016-02-14 17:09 340
      did not originate from an XMLOutputArchive is not officially supported,
7a956470 sago007 2016-02-14 17:09 341
      but may be possible to use if properly formatted.
7a956470 sago007 2016-02-14 17:09 342
7a956470 sago007 2016-02-14 17:09 343
      The XMLInputArchive does not require that nodes are loaded in the same
7a956470 sago007 2016-02-14 17:09 344
      order they were saved by XMLOutputArchive.  Using name value pairs (NVPs),
7a956470 sago007 2016-02-14 17:09 345
      it is possible to load in an out of order fashion or otherwise skip/select
7a956470 sago007 2016-02-14 17:09 346
      specific nodes to load.
7a956470 sago007 2016-02-14 17:09 347
7a956470 sago007 2016-02-14 17:09 348
      The default behavior of the input archive is to read sequentially starting
7a956470 sago007 2016-02-14 17:09 349
      with the first node and exploring its children.  When a given NVP does
7a956470 sago007 2016-02-14 17:09 350
      not match the read in name for a node, the archive will search for that
7a956470 sago007 2016-02-14 17:09 351
      node at the current level and load it if it exists.  After loading an out of
7a956470 sago007 2016-02-14 17:09 352
      order node, the archive will then proceed back to loading sequentially from
7a956470 sago007 2016-02-14 17:09 353
      its new position.
7a956470 sago007 2016-02-14 17:09 354
7a956470 sago007 2016-02-14 17:09 355
      Consider this simple example where loading of some data is skipped:
7a956470 sago007 2016-02-14 17:09 356
7a956470 sago007 2016-02-14 17:09 357
      @code{cpp}
7a956470 sago007 2016-02-14 17:09 358
      // imagine the input file has someData(1-9) saved in order at the top level node
7a956470 sago007 2016-02-14 17:09 359
      ar( someData1, someData2, someData3 );        // XML loads in the order it sees in the file
7a956470 sago007 2016-02-14 17:09 360
      ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
7a956470 sago007 2016-02-14 17:09 361
                                                    // match expected NVP name, so we search
7a956470 sago007 2016-02-14 17:09 362
                                                    // for the given NVP and load that value
7a956470 sago007 2016-02-14 17:09 363
      ar( someData7, someData8, someData9 );        // with no NVP given, loading resumes at its
7a956470 sago007 2016-02-14 17:09 364
                                                    // current location, proceeding sequentially
7a956470 sago007 2016-02-14 17:09 365
      @endcode
7a956470 sago007 2016-02-14 17:09 366
7a956470 sago007 2016-02-14 17:09 367
      \ingroup Archives */
7a956470 sago007 2016-02-14 17:09 368
  class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
7a956470 sago007 2016-02-14 17:09 369
  {
7a956470 sago007 2016-02-14 17:09 370
    public:
7a956470 sago007 2016-02-14 17:09 371
      /*! @name Common Functionality
7a956470 sago007 2016-02-14 17:09 372
          Common use cases for directly interacting with an XMLInputArchive */
7a956470 sago007 2016-02-14 17:09 373
      //! @{
7a956470 sago007 2016-02-14 17:09 374
7a956470 sago007 2016-02-14 17:09 375
      //! Construct, reading in from the provided stream
7a956470 sago007 2016-02-14 17:09 376
      /*! Reads in an entire XML document from some stream and parses it as soon
7a956470 sago007 2016-02-14 17:09 377
          as serialization starts
7a956470 sago007 2016-02-14 17:09 378
7a956470 sago007 2016-02-14 17:09 379
          @param stream The stream to read from.  Can be a stringstream or a file. */
7a956470 sago007 2016-02-14 17:09 380
      XMLInputArchive( std::istream & stream ) :
7a956470 sago007 2016-02-14 17:09 381
        InputArchive<XMLInputArchive>( this ),
7a956470 sago007 2016-02-14 17:09 382
        itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
7a956470 sago007 2016-02-14 17:09 383
      {
7a956470 sago007 2016-02-14 17:09 384
        try
7a956470 sago007 2016-02-14 17:09 385
        {
7a956470 sago007 2016-02-14 17:09 386
          itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
7a956470 sago007 2016-02-14 17:09 387
          itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
7a956470 sago007 2016-02-14 17:09 388
        }
7a956470 sago007 2016-02-14 17:09 389
        catch( rapidxml::parse_error const & )
7a956470 sago007 2016-02-14 17:09 390
        {
7a956470 sago007 2016-02-14 17:09 391
          //std::cerr << "-----Original-----" << std::endl;
7a956470 sago007 2016-02-14 17:09 392
          //stream.seekg(0);
7a956470 sago007 2016-02-14 17:09 393
          //std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
7a956470 sago007 2016-02-14 17:09 394
7a956470 sago007 2016-02-14 17:09 395
          //std::cerr << "-----Error-----" << std::endl;
7a956470 sago007 2016-02-14 17:09 396
          //std::cerr << e.what() << std::endl;
7a956470 sago007 2016-02-14 17:09 397
          //std::cerr << e.where<char>() << std::endl;
7a956470 sago007 2016-02-14 17:09 398
          throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
7a956470 sago007 2016-02-14 17:09 399
        }
7a956470 sago007 2016-02-14 17:09 400
7a956470 sago007 2016-02-14 17:09 401
        // Parse the root
7a956470 sago007 2016-02-14 17:09 402
        auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
7a956470 sago007 2016-02-14 17:09 403
        if( root == nullptr )
7a956470 sago007 2016-02-14 17:09 404
          throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
7a956470 sago007 2016-02-14 17:09 405
        else
7a956470 sago007 2016-02-14 17:09 406
          itsNodes.emplace( root );
7a956470 sago007 2016-02-14 17:09 407
      }
7a956470 sago007 2016-02-14 17:09 408
7a956470 sago007 2016-02-14 17:09 409
      //! Loads some binary data, encoded as a base64 string, optionally specified by some name
7a956470 sago007 2016-02-14 17:09 410
      /*! This will automatically start and finish a node to load the data, and can be called directly by
7a956470 sago007 2016-02-14 17:09 411
          users.
7a956470 sago007 2016-02-14 17:09 412
7a956470 sago007 2016-02-14 17:09 413
          Note that this follows the same ordering rules specified in the class description in regards
7a956470 sago007 2016-02-14 17:09 414
          to loading in/out of order */
7a956470 sago007 2016-02-14 17:09 415
      void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
7a956470 sago007 2016-02-14 17:09 416
      {
7a956470 sago007 2016-02-14 17:09 417
        setNextName( name );
7a956470 sago007 2016-02-14 17:09 418
        startNode();
7a956470 sago007 2016-02-14 17:09 419
7a956470 sago007 2016-02-14 17:09 420
        std::string encoded;
7a956470 sago007 2016-02-14 17:09 421
        loadValue( encoded );
7a956470 sago007 2016-02-14 17:09 422
7a956470 sago007 2016-02-14 17:09 423
        auto decoded = base64::decode( encoded );
7a956470 sago007 2016-02-14 17:09 424
7a956470 sago007 2016-02-14 17:09 425
        if( size != decoded.size() )
7a956470 sago007 2016-02-14 17:09 426
          throw Exception("Decoded binary data size does not match specified size");
7a956470 sago007 2016-02-14 17:09 427
7a956470 sago007 2016-02-14 17:09 428
        std::memcpy( data, decoded.data(), decoded.size() );
7a956470 sago007 2016-02-14 17:09 429
7a956470 sago007 2016-02-14 17:09 430
        finishNode();
7a956470 sago007 2016-02-14 17:09 431
      };
7a956470 sago007 2016-02-14 17:09 432
7a956470 sago007 2016-02-14 17:09 433
      //! @}
7a956470 sago007 2016-02-14 17:09 434
      /*! @name Internal Functionality
7a956470 sago007 2016-02-14 17:09 435
          Functionality designed for use by those requiring control over the inner mechanisms of
7a956470 sago007 2016-02-14 17:09 436
          the XMLInputArchive */
7a956470 sago007 2016-02-14 17:09 437
      //! @{
7a956470 sago007 2016-02-14 17:09 438
7a956470 sago007 2016-02-14 17:09 439
      //! Prepares to start reading the next node
7a956470 sago007 2016-02-14 17:09 440
      /*! This places the next node to be parsed onto the nodes stack.
7a956470 sago007 2016-02-14 17:09 441
7a956470 sago007 2016-02-14 17:09 442
          By default our strategy is to start with the document root node and then
7a956470 sago007 2016-02-14 17:09 443
          recursively iterate through all children in the order they show up in the document.
7a956470 sago007 2016-02-14 17:09 444
          We don't need to know NVPs do to this; we'll just blindly load in the order things appear in.
7a956470 sago007 2016-02-14 17:09 445
7a956470 sago007 2016-02-14 17:09 446
          We check to see if the specified NVP matches what the next automatically loaded node is.  If they
7a956470 sago007 2016-02-14 17:09 447
          match, we just continue as normal, going in order.  If they don't match, we attempt to find a node
7a956470 sago007 2016-02-14 17:09 448
          named after the NVP that is being loaded.  If that NVP does not exist, we throw an exception. */
7a956470 sago007 2016-02-14 17:09 449
      void startNode()
7a956470 sago007 2016-02-14 17:09 450
      {
7a956470 sago007 2016-02-14 17:09 451
        auto next = itsNodes.top().child; // By default we would move to the next child node
7a956470 sago007 2016-02-14 17:09 452
        auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
7a956470 sago007 2016-02-14 17:09 453
7a956470 sago007 2016-02-14 17:09 454
        // If we were given an NVP name, look for it in the current level of the document.
7a956470 sago007 2016-02-14 17:09 455
        //    We only need to do this if either we have exhausted the siblings of the current level or
7a956470 sago007 2016-02-14 17:09 456
        //    the NVP name does not match the name of the node we would normally read next
7a956470 sago007 2016-02-14 17:09 457
        if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
7a956470 sago007 2016-02-14 17:09 458
        {
7a956470 sago007 2016-02-14 17:09 459
          next = itsNodes.top().search( expectedName );
7a956470 sago007 2016-02-14 17:09 460
7a956470 sago007 2016-02-14 17:09 461
          if( next == nullptr )
7a956470 sago007 2016-02-14 17:09 462
            throw Exception("XML Parsing failed - provided NVP not found");
7a956470 sago007 2016-02-14 17:09 463
        }
7a956470 sago007 2016-02-14 17:09 464
7a956470 sago007 2016-02-14 17:09 465
        itsNodes.emplace( next );
7a956470 sago007 2016-02-14 17:09 466
      }
7a956470 sago007 2016-02-14 17:09 467
7a956470 sago007 2016-02-14 17:09 468
      //! Finishes reading the current node
7a956470 sago007 2016-02-14 17:09 469
      void finishNode()
7a956470 sago007 2016-02-14 17:09 470
      {
7a956470 sago007 2016-02-14 17:09 471
        // remove current
7a956470 sago007 2016-02-14 17:09 472
        itsNodes.pop();
7a956470 sago007 2016-02-14 17:09 473
7a956470 sago007 2016-02-14 17:09 474
        // advance parent
7a956470 sago007 2016-02-14 17:09 475
        itsNodes.top().advance();
7a956470 sago007 2016-02-14 17:09 476
7a956470 sago007 2016-02-14 17:09 477
        // Reset name
7a956470 sago007 2016-02-14 17:09 478
        itsNodes.top().name = nullptr;
7a956470 sago007 2016-02-14 17:09 479
      }
7a956470 sago007 2016-02-14 17:09 480
7a956470 sago007 2016-02-14 17:09 481
      //! Retrieves the current node name
7a956470 sago007 2016-02-14 17:09 482
      //! will return @c nullptr if the node does not have a name
7a956470 sago007 2016-02-14 17:09 483
      const char * getNodeName() const
7a956470 sago007 2016-02-14 17:09 484
      {
7a956470 sago007 2016-02-14 17:09 485
        return itsNodes.top().node->name();
7a956470 sago007 2016-02-14 17:09 486
      }
7a956470 sago007 2016-02-14 17:09 487
7a956470 sago007 2016-02-14 17:09 488
      //! Sets the name for the next node created with startNode
7a956470 sago007 2016-02-14 17:09 489
      void setNextName( const char * name )
7a956470 sago007 2016-02-14 17:09 490
      {
7a956470 sago007 2016-02-14 17:09 491
        itsNodes.top().name = name;
7a956470 sago007 2016-02-14 17:09 492
      }
7a956470 sago007 2016-02-14 17:09 493
7a956470 sago007 2016-02-14 17:09 494
      //! Loads a bool from the current top node
7a956470 sago007 2016-02-14 17:09 495
      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
7a956470 sago007 2016-02-14 17:09 496
                                          std::is_same<T, bool>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 497
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 498
      {
7a956470 sago007 2016-02-14 17:09 499
        std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 500
        is.setf( std::ios::boolalpha );
7a956470 sago007 2016-02-14 17:09 501
        is >> value;
7a956470 sago007 2016-02-14 17:09 502
      }
7a956470 sago007 2016-02-14 17:09 503
7a956470 sago007 2016-02-14 17:09 504
      //! Loads a char (signed or unsigned) from the current top node
7a956470 sago007 2016-02-14 17:09 505
      template <class T, traits::EnableIf<std::is_integral<T>::value,
7a956470 sago007 2016-02-14 17:09 506
                                          !std::is_same<T, bool>::value,
7a956470 sago007 2016-02-14 17:09 507
                                          sizeof(T) == sizeof(char)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 508
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 509
      {
7a956470 sago007 2016-02-14 17:09 510
        value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 511
      }
7a956470 sago007 2016-02-14 17:09 512
7a956470 sago007 2016-02-14 17:09 513
      //! Load an int8_t from the current top node (ensures we parse entire number)
7a956470 sago007 2016-02-14 17:09 514
      void loadValue( int8_t & value )
7a956470 sago007 2016-02-14 17:09 515
      {
7a956470 sago007 2016-02-14 17:09 516
        int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
7a956470 sago007 2016-02-14 17:09 517
      }
7a956470 sago007 2016-02-14 17:09 518
7a956470 sago007 2016-02-14 17:09 519
      //! Load a uint8_t from the current top node (ensures we parse entire number)
7a956470 sago007 2016-02-14 17:09 520
      void loadValue( uint8_t & value )
7a956470 sago007 2016-02-14 17:09 521
      {
7a956470 sago007 2016-02-14 17:09 522
        uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
7a956470 sago007 2016-02-14 17:09 523
      }
7a956470 sago007 2016-02-14 17:09 524
7a956470 sago007 2016-02-14 17:09 525
      //! Loads a type best represented as an unsigned long from the current top node
7a956470 sago007 2016-02-14 17:09 526
      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
7a956470 sago007 2016-02-14 17:09 527
                                          !std::is_same<T, bool>::value,
7a956470 sago007 2016-02-14 17:09 528
                                          !std::is_same<T, unsigned char>::value,
7a956470 sago007 2016-02-14 17:09 529
                                          sizeof(T) < sizeof(long long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 530
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 531
      {
7a956470 sago007 2016-02-14 17:09 532
        value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 533
      }
7a956470 sago007 2016-02-14 17:09 534
7a956470 sago007 2016-02-14 17:09 535
      //! Loads a type best represented as an unsigned long long from the current top node
7a956470 sago007 2016-02-14 17:09 536
      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
7a956470 sago007 2016-02-14 17:09 537
                                          !std::is_same<T, bool>::value,
7a956470 sago007 2016-02-14 17:09 538
                                          sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 539
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 540
      {
7a956470 sago007 2016-02-14 17:09 541
        value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 542
      }
7a956470 sago007 2016-02-14 17:09 543
7a956470 sago007 2016-02-14 17:09 544
      //! Loads a type best represented as an int from the current top node
7a956470 sago007 2016-02-14 17:09 545
      template <class T, traits::EnableIf<std::is_signed<T>::value,
7a956470 sago007 2016-02-14 17:09 546
                                          !std::is_same<T, char>::value,
7a956470 sago007 2016-02-14 17:09 547
                                          sizeof(T) <= sizeof(int)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 548
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 549
      {
7a956470 sago007 2016-02-14 17:09 550
        value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 551
      }
7a956470 sago007 2016-02-14 17:09 552
7a956470 sago007 2016-02-14 17:09 553
      //! Loads a type best represented as a long from the current top node
7a956470 sago007 2016-02-14 17:09 554
      template <class T, traits::EnableIf<std::is_signed<T>::value,
7a956470 sago007 2016-02-14 17:09 555
                                          (sizeof(T) > sizeof(int)),
7a956470 sago007 2016-02-14 17:09 556
                                          sizeof(T) <= sizeof(long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 557
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 558
      {
7a956470 sago007 2016-02-14 17:09 559
        value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 560
      }
7a956470 sago007 2016-02-14 17:09 561
7a956470 sago007 2016-02-14 17:09 562
      //! Loads a type best represented as a long long from the current top node
7a956470 sago007 2016-02-14 17:09 563
      template <class T, traits::EnableIf<std::is_signed<T>::value,
7a956470 sago007 2016-02-14 17:09 564
                                          (sizeof(T) > sizeof(long)),
7a956470 sago007 2016-02-14 17:09 565
                                          sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 566
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 567
      {
7a956470 sago007 2016-02-14 17:09 568
        value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 569
      }
7a956470 sago007 2016-02-14 17:09 570
7a956470 sago007 2016-02-14 17:09 571
      //! Loads a type best represented as a float from the current top node
7a956470 sago007 2016-02-14 17:09 572
      void loadValue( float & value )
7a956470 sago007 2016-02-14 17:09 573
      {
7a956470 sago007 2016-02-14 17:09 574
        try
7a956470 sago007 2016-02-14 17:09 575
        {
7a956470 sago007 2016-02-14 17:09 576
          value = std::stof( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 577
        }
7a956470 sago007 2016-02-14 17:09 578
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 579
        {
7a956470 sago007 2016-02-14 17:09 580
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 581
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 582
          is >> value;
7a956470 sago007 2016-02-14 17:09 583
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 584
            throw;
7a956470 sago007 2016-02-14 17:09 585
        }
7a956470 sago007 2016-02-14 17:09 586
      }
7a956470 sago007 2016-02-14 17:09 587
7a956470 sago007 2016-02-14 17:09 588
      //! Loads a type best represented as a double from the current top node
7a956470 sago007 2016-02-14 17:09 589
      void loadValue( double & value )
7a956470 sago007 2016-02-14 17:09 590
      {
7a956470 sago007 2016-02-14 17:09 591
        try
7a956470 sago007 2016-02-14 17:09 592
        {
7a956470 sago007 2016-02-14 17:09 593
          value = std::stod( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 594
        }
7a956470 sago007 2016-02-14 17:09 595
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 596
        {
7a956470 sago007 2016-02-14 17:09 597
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 598
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 599
          is >> value;
7a956470 sago007 2016-02-14 17:09 600
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 601
            throw;
7a956470 sago007 2016-02-14 17:09 602
        }
7a956470 sago007 2016-02-14 17:09 603
      }
7a956470 sago007 2016-02-14 17:09 604
7a956470 sago007 2016-02-14 17:09 605
      //! Loads a type best represented as a long double from the current top node
7a956470 sago007 2016-02-14 17:09 606
      void loadValue( long double & value )
7a956470 sago007 2016-02-14 17:09 607
      {
7a956470 sago007 2016-02-14 17:09 608
        try
7a956470 sago007 2016-02-14 17:09 609
        {
7a956470 sago007 2016-02-14 17:09 610
          value = std::stold( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 611
        }
7a956470 sago007 2016-02-14 17:09 612
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 613
        {
7a956470 sago007 2016-02-14 17:09 614
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 615
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 616
          is >> value;
7a956470 sago007 2016-02-14 17:09 617
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 618
            throw;
7a956470 sago007 2016-02-14 17:09 619
        }
7a956470 sago007 2016-02-14 17:09 620
      }
7a956470 sago007 2016-02-14 17:09 621
7a956470 sago007 2016-02-14 17:09 622
      //! Loads a string from the current node from the current top node
7a956470 sago007 2016-02-14 17:09 623
      template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 624
      void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
7a956470 sago007 2016-02-14 17:09 625
      {
7a956470 sago007 2016-02-14 17:09 626
        std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 627
7a956470 sago007 2016-02-14 17:09 628
        str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
7a956470 sago007 2016-02-14 17:09 629
                    std::istreambuf_iterator<CharT, Traits>() );
7a956470 sago007 2016-02-14 17:09 630
      }
7a956470 sago007 2016-02-14 17:09 631
7a956470 sago007 2016-02-14 17:09 632
      //! Loads the size of the current top node
7a956470 sago007 2016-02-14 17:09 633
      template <class T> inline
7a956470 sago007 2016-02-14 17:09 634
      void loadSize( T & value )
7a956470 sago007 2016-02-14 17:09 635
      {
7a956470 sago007 2016-02-14 17:09 636
        value = getNumChildren( itsNodes.top().node );
7a956470 sago007 2016-02-14 17:09 637
      }
7a956470 sago007 2016-02-14 17:09 638
7a956470 sago007 2016-02-14 17:09 639
    protected:
7a956470 sago007 2016-02-14 17:09 640
      //! Gets the number of children (usually interpreted as size) for the specified node
7a956470 sago007 2016-02-14 17:09 641
      static size_t getNumChildren( rapidxml::xml_node<> * node )
7a956470 sago007 2016-02-14 17:09 642
      {
7a956470 sago007 2016-02-14 17:09 643
        size_t size = 0;
7a956470 sago007 2016-02-14 17:09 644
        node = node->first_node(); // get first child
7a956470 sago007 2016-02-14 17:09 645
7a956470 sago007 2016-02-14 17:09 646
        while( node != nullptr )
7a956470 sago007 2016-02-14 17:09 647
        {
7a956470 sago007 2016-02-14 17:09 648
          ++size;
7a956470 sago007 2016-02-14 17:09 649
          node = node->next_sibling();
7a956470 sago007 2016-02-14 17:09 650
        }
7a956470 sago007 2016-02-14 17:09 651
7a956470 sago007 2016-02-14 17:09 652
        return size;
7a956470 sago007 2016-02-14 17:09 653
      }
7a956470 sago007 2016-02-14 17:09 654
7a956470 sago007 2016-02-14 17:09 655
      //! A struct that contains metadata about a node
7a956470 sago007 2016-02-14 17:09 656
      /*! Keeps track of some top level node, its number of
7a956470 sago007 2016-02-14 17:09 657
          remaining children, and the current active child node */
7a956470 sago007 2016-02-14 17:09 658
      struct NodeInfo
7a956470 sago007 2016-02-14 17:09 659
      {
7a956470 sago007 2016-02-14 17:09 660
        NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
7a956470 sago007 2016-02-14 17:09 661
          node( n ),
7a956470 sago007 2016-02-14 17:09 662
          child( n->first_node() ),
7a956470 sago007 2016-02-14 17:09 663
          size( XMLInputArchive::getNumChildren( n ) ),
7a956470 sago007 2016-02-14 17:09 664
          name( nullptr )
7a956470 sago007 2016-02-14 17:09 665
        { }
7a956470 sago007 2016-02-14 17:09 666
7a956470 sago007 2016-02-14 17:09 667
        //! Advances to the next sibling node of the child
7a956470 sago007 2016-02-14 17:09 668
        /*! If this is the last sibling child will be null after calling */
7a956470 sago007 2016-02-14 17:09 669
        void advance()
7a956470 sago007 2016-02-14 17:09 670
        {
7a956470 sago007 2016-02-14 17:09 671
          if( size > 0 )
7a956470 sago007 2016-02-14 17:09 672
          {
7a956470 sago007 2016-02-14 17:09 673
            --size;
7a956470 sago007 2016-02-14 17:09 674
            child = child->next_sibling();
7a956470 sago007 2016-02-14 17:09 675
          }
7a956470 sago007 2016-02-14 17:09 676
        }
7a956470 sago007 2016-02-14 17:09 677
7a956470 sago007 2016-02-14 17:09 678
        //! Searches for a child with the given name in this node
7a956470 sago007 2016-02-14 17:09 679
        /*! @param searchName The name to search for (must be null terminated)
7a956470 sago007 2016-02-14 17:09 680
            @return The node if found, nullptr otherwise */
7a956470 sago007 2016-02-14 17:09 681
        rapidxml::xml_node<> * search( const char * searchName )
7a956470 sago007 2016-02-14 17:09 682
        {
7a956470 sago007 2016-02-14 17:09 683
          if( searchName )
7a956470 sago007 2016-02-14 17:09 684
          {
7a956470 sago007 2016-02-14 17:09 685
            size_t new_size = XMLInputArchive::getNumChildren( node );
7a956470 sago007 2016-02-14 17:09 686
            const size_t name_size = rapidxml::internal::measure( searchName );
7a956470 sago007 2016-02-14 17:09 687
7a956470 sago007 2016-02-14 17:09 688
            for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
7a956470 sago007 2016-02-14 17:09 689
            {
7a956470 sago007 2016-02-14 17:09 690
              if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
7a956470 sago007 2016-02-14 17:09 691
              {
7a956470 sago007 2016-02-14 17:09 692
                size = new_size;
7a956470 sago007 2016-02-14 17:09 693
                child = new_child;
7a956470 sago007 2016-02-14 17:09 694
7a956470 sago007 2016-02-14 17:09 695
                return new_child;
7a956470 sago007 2016-02-14 17:09 696
              }
7a956470 sago007 2016-02-14 17:09 697
              --new_size;
7a956470 sago007 2016-02-14 17:09 698
            }
7a956470 sago007 2016-02-14 17:09 699
          }
7a956470 sago007 2016-02-14 17:09 700
7a956470 sago007 2016-02-14 17:09 701
          return nullptr;
7a956470 sago007 2016-02-14 17:09 702
        }
7a956470 sago007 2016-02-14 17:09 703
7a956470 sago007 2016-02-14 17:09 704
        rapidxml::xml_node<> * node;  //!< A pointer to this node
7a956470 sago007 2016-02-14 17:09 705
        rapidxml::xml_node<> * child; //!< A pointer to its current child
7a956470 sago007 2016-02-14 17:09 706
        size_t size;                  //!< The remaining number of children for this node
7a956470 sago007 2016-02-14 17:09 707
        const char * name;            //!< The NVP name for next next child node
7a956470 sago007 2016-02-14 17:09 708
      }; // NodeInfo
7a956470 sago007 2016-02-14 17:09 709
7a956470 sago007 2016-02-14 17:09 710
      //! @}
7a956470 sago007 2016-02-14 17:09 711
7a956470 sago007 2016-02-14 17:09 712
    private:
7a956470 sago007 2016-02-14 17:09 713
      std::vector<char> itsData;       //!< The raw data loaded
7a956470 sago007 2016-02-14 17:09 714
      rapidxml::xml_document<> itsXML; //!< The XML document
7a956470 sago007 2016-02-14 17:09 715
      std::stack<NodeInfo> itsNodes;   //!< A stack of nodes read from the document
7a956470 sago007 2016-02-14 17:09 716
  };
7a956470 sago007 2016-02-14 17:09 717
7a956470 sago007 2016-02-14 17:09 718
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 719
  // XMLArchive prologue and epilogue functions
7a956470 sago007 2016-02-14 17:09 720
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 721
7a956470 sago007 2016-02-14 17:09 722
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 723
  //! Prologue for NVPs for XML output archives
7a956470 sago007 2016-02-14 17:09 724
  /*! NVPs do not start or finish nodes - they just set up the names */
7a956470 sago007 2016-02-14 17:09 725
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 726
  void prologue( XMLOutputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 727
  { }
7a956470 sago007 2016-02-14 17:09 728
7a956470 sago007 2016-02-14 17:09 729
  //! Prologue for NVPs for XML input archives
7a956470 sago007 2016-02-14 17:09 730
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 731
  void prologue( XMLInputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 732
  { }
7a956470 sago007 2016-02-14 17:09 733
7a956470 sago007 2016-02-14 17:09 734
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 735
  //! Epilogue for NVPs for XML output archives
7a956470 sago007 2016-02-14 17:09 736
  /*! NVPs do not start or finish nodes - they just set up the names */
7a956470 sago007 2016-02-14 17:09 737
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 738
  void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 739
  { }
7a956470 sago007 2016-02-14 17:09 740
7a956470 sago007 2016-02-14 17:09 741
  //! Epilogue for NVPs for XML input archives
7a956470 sago007 2016-02-14 17:09 742
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 743
  void epilogue( XMLInputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 744
  { }
7a956470 sago007 2016-02-14 17:09 745
7a956470 sago007 2016-02-14 17:09 746
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 747
  //! Prologue for SizeTags for XML output archives
7a956470 sago007 2016-02-14 17:09 748
  /*! SizeTags do not start or finish nodes */
7a956470 sago007 2016-02-14 17:09 749
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 750
  void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 751
  {
7a956470 sago007 2016-02-14 17:09 752
    ar.appendAttribute( "size", "dynamic" );
7a956470 sago007 2016-02-14 17:09 753
  }
7a956470 sago007 2016-02-14 17:09 754
7a956470 sago007 2016-02-14 17:09 755
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 756
  void prologue( XMLInputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 757
  { }
7a956470 sago007 2016-02-14 17:09 758
7a956470 sago007 2016-02-14 17:09 759
  //! Epilogue for SizeTags for XML output archives
7a956470 sago007 2016-02-14 17:09 760
  /*! SizeTags do not start or finish nodes */
7a956470 sago007 2016-02-14 17:09 761
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 762
  void epilogue( XMLOutputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 763
  { }
7a956470 sago007 2016-02-14 17:09 764
7a956470 sago007 2016-02-14 17:09 765
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 766
  void epilogue( XMLInputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 767
  { }
7a956470 sago007 2016-02-14 17:09 768
7a956470 sago007 2016-02-14 17:09 769
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 770
  //! Prologue for all other types for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 771
  /*! Starts a new node, named either automatically or by some NVP,
7a956470 sago007 2016-02-14 17:09 772
      that may be given data by the type about to be archived
7a956470 sago007 2016-02-14 17:09 773
7a956470 sago007 2016-02-14 17:09 774
      Minimal types do not start or end nodes */
7a956470 sago007 2016-02-14 17:09 775
  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
7a956470 sago007 2016-02-14 17:09 776
                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 777
  void prologue( XMLOutputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 778
  {
7a956470 sago007 2016-02-14 17:09 779
    ar.startNode();
7a956470 sago007 2016-02-14 17:09 780
    ar.insertType<T>();
7a956470 sago007 2016-02-14 17:09 781
  }
7a956470 sago007 2016-02-14 17:09 782
7a956470 sago007 2016-02-14 17:09 783
  //! Prologue for all other types for XML input archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 784
  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
7a956470 sago007 2016-02-14 17:09 785
                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 786
  void prologue( XMLInputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 787
  {
7a956470 sago007 2016-02-14 17:09 788
    ar.startNode();
7a956470 sago007 2016-02-14 17:09 789
  }
7a956470 sago007 2016-02-14 17:09 790
7a956470 sago007 2016-02-14 17:09 791
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 792
  //! Epilogue for all other types other for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 793
  /*! Finishes the node created in the prologue
7a956470 sago007 2016-02-14 17:09 794
7a956470 sago007 2016-02-14 17:09 795
      Minimal types do not start or end nodes */
7a956470 sago007 2016-02-14 17:09 796
  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
7a956470 sago007 2016-02-14 17:09 797
                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 798
  void epilogue( XMLOutputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 799
  {
7a956470 sago007 2016-02-14 17:09 800
    ar.finishNode();
7a956470 sago007 2016-02-14 17:09 801
  }
7a956470 sago007 2016-02-14 17:09 802
7a956470 sago007 2016-02-14 17:09 803
  //! Epilogue for all other types other for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 804
  template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
7a956470 sago007 2016-02-14 17:09 805
                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 806
  void epilogue( XMLInputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 807
  {
7a956470 sago007 2016-02-14 17:09 808
    ar.finishNode();
7a956470 sago007 2016-02-14 17:09 809
  }
7a956470 sago007 2016-02-14 17:09 810
7a956470 sago007 2016-02-14 17:09 811
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 812
  // Common XMLArchive serialization functions
7a956470 sago007 2016-02-14 17:09 813
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 814
7a956470 sago007 2016-02-14 17:09 815
  //! Saving NVP types to XML
7a956470 sago007 2016-02-14 17:09 816
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 817
  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
7a956470 sago007 2016-02-14 17:09 818
  {
7a956470 sago007 2016-02-14 17:09 819
    ar.setNextName( t.name );
7a956470 sago007 2016-02-14 17:09 820
    ar( t.value );
7a956470 sago007 2016-02-14 17:09 821
  }
7a956470 sago007 2016-02-14 17:09 822
7a956470 sago007 2016-02-14 17:09 823
  //! Loading NVP types from XML
7a956470 sago007 2016-02-14 17:09 824
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 825
  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
7a956470 sago007 2016-02-14 17:09 826
  {
7a956470 sago007 2016-02-14 17:09 827
    ar.setNextName( t.name );
7a956470 sago007 2016-02-14 17:09 828
    ar( t.value );
7a956470 sago007 2016-02-14 17:09 829
  }
7a956470 sago007 2016-02-14 17:09 830
7a956470 sago007 2016-02-14 17:09 831
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 832
  //! Saving SizeTags to XML
7a956470 sago007 2016-02-14 17:09 833
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 834
  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 835
  { }
7a956470 sago007 2016-02-14 17:09 836
7a956470 sago007 2016-02-14 17:09 837
  //! Loading SizeTags from XML
7a956470 sago007 2016-02-14 17:09 838
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 839
  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
7a956470 sago007 2016-02-14 17:09 840
  {
7a956470 sago007 2016-02-14 17:09 841
    ar.loadSize( st.size );
7a956470 sago007 2016-02-14 17:09 842
  }
7a956470 sago007 2016-02-14 17:09 843
7a956470 sago007 2016-02-14 17:09 844
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 845
  //! Saving for POD types to xml
7a956470 sago007 2016-02-14 17:09 846
  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 847
  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
7a956470 sago007 2016-02-14 17:09 848
  {
7a956470 sago007 2016-02-14 17:09 849
    ar.saveValue( t );
7a956470 sago007 2016-02-14 17:09 850
  }
7a956470 sago007 2016-02-14 17:09 851
7a956470 sago007 2016-02-14 17:09 852
  //! Loading for POD types from xml
7a956470 sago007 2016-02-14 17:09 853
  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 854
  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
7a956470 sago007 2016-02-14 17:09 855
  {
7a956470 sago007 2016-02-14 17:09 856
    ar.loadValue( t );
7a956470 sago007 2016-02-14 17:09 857
  }
7a956470 sago007 2016-02-14 17:09 858
7a956470 sago007 2016-02-14 17:09 859
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 860
  //! saving string to xml
7a956470 sago007 2016-02-14 17:09 861
  template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 862
  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
7a956470 sago007 2016-02-14 17:09 863
  {
7a956470 sago007 2016-02-14 17:09 864
    ar.saveValue( str );
7a956470 sago007 2016-02-14 17:09 865
  }
7a956470 sago007 2016-02-14 17:09 866
7a956470 sago007 2016-02-14 17:09 867
  //! loading string from xml
7a956470 sago007 2016-02-14 17:09 868
  template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 869
  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
7a956470 sago007 2016-02-14 17:09 870
  {
7a956470 sago007 2016-02-14 17:09 871
    ar.loadValue( str );
7a956470 sago007 2016-02-14 17:09 872
  }
7a956470 sago007 2016-02-14 17:09 873
} // namespace cereal
7a956470 sago007 2016-02-14 17:09 874
7a956470 sago007 2016-02-14 17:09 875
// register archives for polymorphic support
7a956470 sago007 2016-02-14 17:09 876
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
7a956470 sago007 2016-02-14 17:09 877
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
7a956470 sago007 2016-02-14 17:09 878
7a956470 sago007 2016-02-14 17:09 879
// tie input and output archives together
7a956470 sago007 2016-02-14 17:09 880
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
7a956470 sago007 2016-02-14 17:09 881
7a956470 sago007 2016-02-14 17:09 882
#endif // CEREAL_ARCHIVES_XML_HPP_
1970-01-01 00:00 883