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_
6c5f2c01 sago007 2017-03-15 17:56 31
#include "cereal/cereal.hpp"
6c5f2c01 sago007 2017-03-15 17:56 32
#include "cereal/details/util.hpp"
7a956470 sago007 2016-02-14 17:09 33
6c5f2c01 sago007 2017-03-15 17:56 34
#include "cereal/external/rapidxml/rapidxml.hpp"
6c5f2c01 sago007 2017-03-15 17:56 35
#include "cereal/external/rapidxml/rapidxml_print.hpp"
6c5f2c01 sago007 2017-03-15 17:56 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.
6c5f2c01 sago007 2017-03-15 17:56 71
      This archive should be used 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
6c5f2c01 sago007 2017-03-15 17:56 161
      ~XMLOutputArchive() CEREAL_NOEXCEPT
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
6c5f2c01 sago007 2017-03-15 17:56 235
        auto strValue = itsOS.str();
6c5f2c01 sago007 2017-03-15 17:56 236
6c5f2c01 sago007 2017-03-15 17:56 237
        // itsOS.str() may contain data from previous calls after the first '\0' that was just inserted
6c5f2c01 sago007 2017-03-15 17:56 238
        // and this data is counted in the length call. We make sure to remove that section so that the
6c5f2c01 sago007 2017-03-15 17:56 239
        // whitespace validation is done properly
6c5f2c01 sago007 2017-03-15 17:56 240
        strValue.resize(std::strlen(strValue.c_str()));
7a956470 sago007 2016-02-14 17:09 241
7a956470 sago007 2016-02-14 17:09 242
        // If the first or last character is a whitespace, add xml:space attribute
7a956470 sago007 2016-02-14 17:09 243
        const auto len = strValue.length();
6c5f2c01 sago007 2017-03-15 17:56 244
        if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) )
7a956470 sago007 2016-02-14 17:09 245
        {
7a956470 sago007 2016-02-14 17:09 246
          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
7a956470 sago007 2016-02-14 17:09 247
        }
7a956470 sago007 2016-02-14 17:09 248
7a956470 sago007 2016-02-14 17:09 249
        // allocate strings for all of the data in the XML object
6c5f2c01 sago007 2017-03-15 17:56 250
        auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 );
7a956470 sago007 2016-02-14 17:09 251
7a956470 sago007 2016-02-14 17:09 252
        // insert into the XML
7a956470 sago007 2016-02-14 17:09 253
        itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
7a956470 sago007 2016-02-14 17:09 254
      }
7a956470 sago007 2016-02-14 17:09 255
7a956470 sago007 2016-02-14 17:09 256
      //! Overload for uint8_t prevents them from being serialized as characters
7a956470 sago007 2016-02-14 17:09 257
      void saveValue( uint8_t const & value )
7a956470 sago007 2016-02-14 17:09 258
      {
7a956470 sago007 2016-02-14 17:09 259
        saveValue( static_cast<uint32_t>( value ) );
7a956470 sago007 2016-02-14 17:09 260
      }
7a956470 sago007 2016-02-14 17:09 261
7a956470 sago007 2016-02-14 17:09 262
      //! Overload for int8_t prevents them from being serialized as characters
7a956470 sago007 2016-02-14 17:09 263
      void saveValue( int8_t const & value )
7a956470 sago007 2016-02-14 17:09 264
      {
7a956470 sago007 2016-02-14 17:09 265
        saveValue( static_cast<int32_t>( value ) );
7a956470 sago007 2016-02-14 17:09 266
      }
7a956470 sago007 2016-02-14 17:09 267
7a956470 sago007 2016-02-14 17:09 268
      //! 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 269
      template <class T> inline
7a956470 sago007 2016-02-14 17:09 270
      void insertType()
7a956470 sago007 2016-02-14 17:09 271
      {
7a956470 sago007 2016-02-14 17:09 272
        if( !itsOutputType )
7a956470 sago007 2016-02-14 17:09 273
          return;
7a956470 sago007 2016-02-14 17:09 274
7a956470 sago007 2016-02-14 17:09 275
        // generate a name for this new node
7a956470 sago007 2016-02-14 17:09 276
        const auto nameString = util::demangledName<T>();
7a956470 sago007 2016-02-14 17:09 277
7a956470 sago007 2016-02-14 17:09 278
        // allocate strings for all of the data in the XML object
7a956470 sago007 2016-02-14 17:09 279
        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
7a956470 sago007 2016-02-14 17:09 280
7a956470 sago007 2016-02-14 17:09 281
        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
7a956470 sago007 2016-02-14 17:09 282
      }
7a956470 sago007 2016-02-14 17:09 283
7a956470 sago007 2016-02-14 17:09 284
      //! Appends an attribute to the current top level node
7a956470 sago007 2016-02-14 17:09 285
      void appendAttribute( const char * name, const char * value )
7a956470 sago007 2016-02-14 17:09 286
      {
7a956470 sago007 2016-02-14 17:09 287
        auto namePtr =  itsXML.allocate_string( name );
7a956470 sago007 2016-02-14 17:09 288
        auto valuePtr = itsXML.allocate_string( value );
7a956470 sago007 2016-02-14 17:09 289
        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
7a956470 sago007 2016-02-14 17:09 290
      }
7a956470 sago007 2016-02-14 17:09 291
7a956470 sago007 2016-02-14 17:09 292
    protected:
7a956470 sago007 2016-02-14 17:09 293
      //! A struct that contains metadata about a node
7a956470 sago007 2016-02-14 17:09 294
      struct NodeInfo
7a956470 sago007 2016-02-14 17:09 295
      {
7a956470 sago007 2016-02-14 17:09 296
        NodeInfo( rapidxml::xml_node<> * n = nullptr,
7a956470 sago007 2016-02-14 17:09 297
                  const char * nm = nullptr ) :
7a956470 sago007 2016-02-14 17:09 298
          node( n ),
7a956470 sago007 2016-02-14 17:09 299
          counter( 0 ),
7a956470 sago007 2016-02-14 17:09 300
          name( nm )
7a956470 sago007 2016-02-14 17:09 301
        { }
7a956470 sago007 2016-02-14 17:09 302
7a956470 sago007 2016-02-14 17:09 303
        rapidxml::xml_node<> * node; //!< A pointer to this node
7a956470 sago007 2016-02-14 17:09 304
        size_t counter;              //!< The counter for naming child nodes
7a956470 sago007 2016-02-14 17:09 305
        const char * name;           //!< The name for the next child node
7a956470 sago007 2016-02-14 17:09 306
7a956470 sago007 2016-02-14 17:09 307
        //! Gets the name for the next child node created from this node
7a956470 sago007 2016-02-14 17:09 308
        /*! The name will be automatically generated using the counter if
7a956470 sago007 2016-02-14 17:09 309
            a name has not been previously set.  If a name has been previously
7a956470 sago007 2016-02-14 17:09 310
            set, that name will be returned only once */
7a956470 sago007 2016-02-14 17:09 311
        std::string getValueName()
7a956470 sago007 2016-02-14 17:09 312
        {
7a956470 sago007 2016-02-14 17:09 313
          if( name )
7a956470 sago007 2016-02-14 17:09 314
          {
7a956470 sago007 2016-02-14 17:09 315
            auto n = name;
7a956470 sago007 2016-02-14 17:09 316
            name = nullptr;
7a956470 sago007 2016-02-14 17:09 317
            return {n};
7a956470 sago007 2016-02-14 17:09 318
          }
7a956470 sago007 2016-02-14 17:09 319
          else
7a956470 sago007 2016-02-14 17:09 320
            return "value" + std::to_string( counter++ ) + "\0";
7a956470 sago007 2016-02-14 17:09 321
        }
7a956470 sago007 2016-02-14 17:09 322
      }; // NodeInfo
7a956470 sago007 2016-02-14 17:09 323
7a956470 sago007 2016-02-14 17:09 324
      //! @}
7a956470 sago007 2016-02-14 17:09 325
7a956470 sago007 2016-02-14 17:09 326
    private:
7a956470 sago007 2016-02-14 17:09 327
      std::ostream & itsStream;        //!< The output stream
7a956470 sago007 2016-02-14 17:09 328
      rapidxml::xml_document<> itsXML; //!< The XML document
7a956470 sago007 2016-02-14 17:09 329
      std::stack<NodeInfo> itsNodes;   //!< A stack of nodes added to the document
7a956470 sago007 2016-02-14 17:09 330
      std::ostringstream itsOS;        //!< Used to format strings internally
7a956470 sago007 2016-02-14 17:09 331
      bool itsOutputType;              //!< Controls whether type information is printed
7a956470 sago007 2016-02-14 17:09 332
      bool itsIndent;                  //!< Controls whether indenting is used
7a956470 sago007 2016-02-14 17:09 333
  }; // XMLOutputArchive
7a956470 sago007 2016-02-14 17:09 334
7a956470 sago007 2016-02-14 17:09 335
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 336
  //! An output archive designed to load data from XML
7a956470 sago007 2016-02-14 17:09 337
  /*! This archive uses RapidXML to build an in memory XML tree of the
7a956470 sago007 2016-02-14 17:09 338
      data in the stream it is given before loading any types serialized.
7a956470 sago007 2016-02-14 17:09 339
6c5f2c01 sago007 2017-03-15 17:56 340
      As with the output XML archive, the preferred way to use this archive is in
6c5f2c01 sago007 2017-03-15 17:56 341
      an RAII fashion, ensuring its destruction after all data has been read.
6c5f2c01 sago007 2017-03-15 17:56 342
7a956470 sago007 2016-02-14 17:09 343
      Input XML should have been produced by the XMLOutputArchive.  Data can
7a956470 sago007 2016-02-14 17:09 344
      only be added to dynamically sized containers - the input archive will
7a956470 sago007 2016-02-14 17:09 345
      determine their size by looking at the number of child nodes.  Data that
7a956470 sago007 2016-02-14 17:09 346
      did not originate from an XMLOutputArchive is not officially supported,
7a956470 sago007 2016-02-14 17:09 347
      but may be possible to use if properly formatted.
7a956470 sago007 2016-02-14 17:09 348
7a956470 sago007 2016-02-14 17:09 349
      The XMLInputArchive does not require that nodes are loaded in the same
7a956470 sago007 2016-02-14 17:09 350
      order they were saved by XMLOutputArchive.  Using name value pairs (NVPs),
7a956470 sago007 2016-02-14 17:09 351
      it is possible to load in an out of order fashion or otherwise skip/select
7a956470 sago007 2016-02-14 17:09 352
      specific nodes to load.
7a956470 sago007 2016-02-14 17:09 353
7a956470 sago007 2016-02-14 17:09 354
      The default behavior of the input archive is to read sequentially starting
7a956470 sago007 2016-02-14 17:09 355
      with the first node and exploring its children.  When a given NVP does
7a956470 sago007 2016-02-14 17:09 356
      not match the read in name for a node, the archive will search for that
7a956470 sago007 2016-02-14 17:09 357
      node at the current level and load it if it exists.  After loading an out of
7a956470 sago007 2016-02-14 17:09 358
      order node, the archive will then proceed back to loading sequentially from
7a956470 sago007 2016-02-14 17:09 359
      its new position.
7a956470 sago007 2016-02-14 17:09 360
7a956470 sago007 2016-02-14 17:09 361
      Consider this simple example where loading of some data is skipped:
7a956470 sago007 2016-02-14 17:09 362
7a956470 sago007 2016-02-14 17:09 363
      @code{cpp}
7a956470 sago007 2016-02-14 17:09 364
      // imagine the input file has someData(1-9) saved in order at the top level node
7a956470 sago007 2016-02-14 17:09 365
      ar( someData1, someData2, someData3 );        // XML loads in the order it sees in the file
7a956470 sago007 2016-02-14 17:09 366
      ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
7a956470 sago007 2016-02-14 17:09 367
                                                    // match expected NVP name, so we search
7a956470 sago007 2016-02-14 17:09 368
                                                    // for the given NVP and load that value
7a956470 sago007 2016-02-14 17:09 369
      ar( someData7, someData8, someData9 );        // with no NVP given, loading resumes at its
7a956470 sago007 2016-02-14 17:09 370
                                                    // current location, proceeding sequentially
7a956470 sago007 2016-02-14 17:09 371
      @endcode
7a956470 sago007 2016-02-14 17:09 372
7a956470 sago007 2016-02-14 17:09 373
      \ingroup Archives */
7a956470 sago007 2016-02-14 17:09 374
  class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
7a956470 sago007 2016-02-14 17:09 375
  {
7a956470 sago007 2016-02-14 17:09 376
    public:
7a956470 sago007 2016-02-14 17:09 377
      /*! @name Common Functionality
7a956470 sago007 2016-02-14 17:09 378
          Common use cases for directly interacting with an XMLInputArchive */
7a956470 sago007 2016-02-14 17:09 379
      //! @{
7a956470 sago007 2016-02-14 17:09 380
7a956470 sago007 2016-02-14 17:09 381
      //! Construct, reading in from the provided stream
7a956470 sago007 2016-02-14 17:09 382
      /*! Reads in an entire XML document from some stream and parses it as soon
7a956470 sago007 2016-02-14 17:09 383
          as serialization starts
7a956470 sago007 2016-02-14 17:09 384
7a956470 sago007 2016-02-14 17:09 385
          @param stream The stream to read from.  Can be a stringstream or a file. */
7a956470 sago007 2016-02-14 17:09 386
      XMLInputArchive( std::istream & stream ) :
7a956470 sago007 2016-02-14 17:09 387
        InputArchive<XMLInputArchive>( this ),
7a956470 sago007 2016-02-14 17:09 388
        itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
7a956470 sago007 2016-02-14 17:09 389
      {
7a956470 sago007 2016-02-14 17:09 390
        try
7a956470 sago007 2016-02-14 17:09 391
        {
7a956470 sago007 2016-02-14 17:09 392
          itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
7a956470 sago007 2016-02-14 17:09 393
          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 394
        }
7a956470 sago007 2016-02-14 17:09 395
        catch( rapidxml::parse_error const & )
7a956470 sago007 2016-02-14 17:09 396
        {
7a956470 sago007 2016-02-14 17:09 397
          //std::cerr << "-----Original-----" << std::endl;
7a956470 sago007 2016-02-14 17:09 398
          //stream.seekg(0);
7a956470 sago007 2016-02-14 17:09 399
          //std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
7a956470 sago007 2016-02-14 17:09 400
7a956470 sago007 2016-02-14 17:09 401
          //std::cerr << "-----Error-----" << std::endl;
7a956470 sago007 2016-02-14 17:09 402
          //std::cerr << e.what() << std::endl;
7a956470 sago007 2016-02-14 17:09 403
          //std::cerr << e.where<char>() << std::endl;
7a956470 sago007 2016-02-14 17:09 404
          throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
7a956470 sago007 2016-02-14 17:09 405
        }
7a956470 sago007 2016-02-14 17:09 406
7a956470 sago007 2016-02-14 17:09 407
        // Parse the root
7a956470 sago007 2016-02-14 17:09 408
        auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
7a956470 sago007 2016-02-14 17:09 409
        if( root == nullptr )
7a956470 sago007 2016-02-14 17:09 410
          throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
7a956470 sago007 2016-02-14 17:09 411
        else
7a956470 sago007 2016-02-14 17:09 412
          itsNodes.emplace( root );
7a956470 sago007 2016-02-14 17:09 413
      }
7a956470 sago007 2016-02-14 17:09 414
6c5f2c01 sago007 2017-03-15 17:56 415
      ~XMLInputArchive() CEREAL_NOEXCEPT = default;
6c5f2c01 sago007 2017-03-15 17:56 416
7a956470 sago007 2016-02-14 17:09 417
      //! Loads some binary data, encoded as a base64 string, optionally specified by some name
7a956470 sago007 2016-02-14 17:09 418
      /*! 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 419
          users.
7a956470 sago007 2016-02-14 17:09 420
7a956470 sago007 2016-02-14 17:09 421
          Note that this follows the same ordering rules specified in the class description in regards
7a956470 sago007 2016-02-14 17:09 422
          to loading in/out of order */
7a956470 sago007 2016-02-14 17:09 423
      void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
7a956470 sago007 2016-02-14 17:09 424
      {
7a956470 sago007 2016-02-14 17:09 425
        setNextName( name );
7a956470 sago007 2016-02-14 17:09 426
        startNode();
7a956470 sago007 2016-02-14 17:09 427
7a956470 sago007 2016-02-14 17:09 428
        std::string encoded;
7a956470 sago007 2016-02-14 17:09 429
        loadValue( encoded );
7a956470 sago007 2016-02-14 17:09 430
7a956470 sago007 2016-02-14 17:09 431
        auto decoded = base64::decode( encoded );
7a956470 sago007 2016-02-14 17:09 432
7a956470 sago007 2016-02-14 17:09 433
        if( size != decoded.size() )
7a956470 sago007 2016-02-14 17:09 434
          throw Exception("Decoded binary data size does not match specified size");
7a956470 sago007 2016-02-14 17:09 435
7a956470 sago007 2016-02-14 17:09 436
        std::memcpy( data, decoded.data(), decoded.size() );
7a956470 sago007 2016-02-14 17:09 437
7a956470 sago007 2016-02-14 17:09 438
        finishNode();
7a956470 sago007 2016-02-14 17:09 439
      };
7a956470 sago007 2016-02-14 17:09 440
7a956470 sago007 2016-02-14 17:09 441
      //! @}
7a956470 sago007 2016-02-14 17:09 442
      /*! @name Internal Functionality
7a956470 sago007 2016-02-14 17:09 443
          Functionality designed for use by those requiring control over the inner mechanisms of
7a956470 sago007 2016-02-14 17:09 444
          the XMLInputArchive */
7a956470 sago007 2016-02-14 17:09 445
      //! @{
7a956470 sago007 2016-02-14 17:09 446
7a956470 sago007 2016-02-14 17:09 447
      //! Prepares to start reading the next node
7a956470 sago007 2016-02-14 17:09 448
      /*! This places the next node to be parsed onto the nodes stack.
7a956470 sago007 2016-02-14 17:09 449
7a956470 sago007 2016-02-14 17:09 450
          By default our strategy is to start with the document root node and then
7a956470 sago007 2016-02-14 17:09 451
          recursively iterate through all children in the order they show up in the document.
7a956470 sago007 2016-02-14 17:09 452
          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 453
7a956470 sago007 2016-02-14 17:09 454
          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 455
          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 456
          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 457
      void startNode()
7a956470 sago007 2016-02-14 17:09 458
      {
7a956470 sago007 2016-02-14 17:09 459
        auto next = itsNodes.top().child; // By default we would move to the next child node
7a956470 sago007 2016-02-14 17:09 460
        auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
7a956470 sago007 2016-02-14 17:09 461
7a956470 sago007 2016-02-14 17:09 462
        // If we were given an NVP name, look for it in the current level of the document.
7a956470 sago007 2016-02-14 17:09 463
        //    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 464
        //    the NVP name does not match the name of the node we would normally read next
7a956470 sago007 2016-02-14 17:09 465
        if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
7a956470 sago007 2016-02-14 17:09 466
        {
7a956470 sago007 2016-02-14 17:09 467
          next = itsNodes.top().search( expectedName );
7a956470 sago007 2016-02-14 17:09 468
7a956470 sago007 2016-02-14 17:09 469
          if( next == nullptr )
6c5f2c01 sago007 2017-03-15 17:56 470
            throw Exception("XML Parsing failed - provided NVP (" + std::string(expectedName) + ") not found");
7a956470 sago007 2016-02-14 17:09 471
        }
7a956470 sago007 2016-02-14 17:09 472
7a956470 sago007 2016-02-14 17:09 473
        itsNodes.emplace( next );
7a956470 sago007 2016-02-14 17:09 474
      }
7a956470 sago007 2016-02-14 17:09 475
7a956470 sago007 2016-02-14 17:09 476
      //! Finishes reading the current node
7a956470 sago007 2016-02-14 17:09 477
      void finishNode()
7a956470 sago007 2016-02-14 17:09 478
      {
7a956470 sago007 2016-02-14 17:09 479
        // remove current
7a956470 sago007 2016-02-14 17:09 480
        itsNodes.pop();
7a956470 sago007 2016-02-14 17:09 481
7a956470 sago007 2016-02-14 17:09 482
        // advance parent
7a956470 sago007 2016-02-14 17:09 483
        itsNodes.top().advance();
7a956470 sago007 2016-02-14 17:09 484
7a956470 sago007 2016-02-14 17:09 485
        // Reset name
7a956470 sago007 2016-02-14 17:09 486
        itsNodes.top().name = nullptr;
7a956470 sago007 2016-02-14 17:09 487
      }
7a956470 sago007 2016-02-14 17:09 488
7a956470 sago007 2016-02-14 17:09 489
      //! Retrieves the current node name
7a956470 sago007 2016-02-14 17:09 490
      //! will return @c nullptr if the node does not have a name
7a956470 sago007 2016-02-14 17:09 491
      const char * getNodeName() const
7a956470 sago007 2016-02-14 17:09 492
      {
6c5f2c01 sago007 2017-03-15 17:56 493
        return itsNodes.top().getChildName();
7a956470 sago007 2016-02-14 17:09 494
      }
7a956470 sago007 2016-02-14 17:09 495
7a956470 sago007 2016-02-14 17:09 496
      //! Sets the name for the next node created with startNode
7a956470 sago007 2016-02-14 17:09 497
      void setNextName( const char * name )
7a956470 sago007 2016-02-14 17:09 498
      {
7a956470 sago007 2016-02-14 17:09 499
        itsNodes.top().name = name;
7a956470 sago007 2016-02-14 17:09 500
      }
7a956470 sago007 2016-02-14 17:09 501
7a956470 sago007 2016-02-14 17:09 502
      //! Loads a bool from the current top node
7a956470 sago007 2016-02-14 17:09 503
      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
7a956470 sago007 2016-02-14 17:09 504
                                          std::is_same<T, bool>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 505
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 506
      {
7a956470 sago007 2016-02-14 17:09 507
        std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 508
        is.setf( std::ios::boolalpha );
7a956470 sago007 2016-02-14 17:09 509
        is >> value;
7a956470 sago007 2016-02-14 17:09 510
      }
7a956470 sago007 2016-02-14 17:09 511
7a956470 sago007 2016-02-14 17:09 512
      //! Loads a char (signed or unsigned) from the current top node
7a956470 sago007 2016-02-14 17:09 513
      template <class T, traits::EnableIf<std::is_integral<T>::value,
7a956470 sago007 2016-02-14 17:09 514
                                          !std::is_same<T, bool>::value,
7a956470 sago007 2016-02-14 17:09 515
                                          sizeof(T) == sizeof(char)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 516
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 517
      {
7a956470 sago007 2016-02-14 17:09 518
        value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 519
      }
7a956470 sago007 2016-02-14 17:09 520
7a956470 sago007 2016-02-14 17:09 521
      //! Load an int8_t from the current top node (ensures we parse entire number)
7a956470 sago007 2016-02-14 17:09 522
      void loadValue( int8_t & value )
7a956470 sago007 2016-02-14 17:09 523
      {
7a956470 sago007 2016-02-14 17:09 524
        int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
7a956470 sago007 2016-02-14 17:09 525
      }
7a956470 sago007 2016-02-14 17:09 526
7a956470 sago007 2016-02-14 17:09 527
      //! Load a uint8_t from the current top node (ensures we parse entire number)
7a956470 sago007 2016-02-14 17:09 528
      void loadValue( uint8_t & value )
7a956470 sago007 2016-02-14 17:09 529
      {
7a956470 sago007 2016-02-14 17:09 530
        uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
7a956470 sago007 2016-02-14 17:09 531
      }
7a956470 sago007 2016-02-14 17:09 532
7a956470 sago007 2016-02-14 17:09 533
      //! Loads a type best represented as an unsigned long from the current top node
7a956470 sago007 2016-02-14 17:09 534
      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
7a956470 sago007 2016-02-14 17:09 535
                                          !std::is_same<T, bool>::value,
6c5f2c01 sago007 2017-03-15 17:56 536
                                          !std::is_same<T, char>::value,
7a956470 sago007 2016-02-14 17:09 537
                                          !std::is_same<T, unsigned char>::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::stoul( 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 unsigned long long from the current top node
7a956470 sago007 2016-02-14 17:09 545
      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
7a956470 sago007 2016-02-14 17:09 546
                                          !std::is_same<T, bool>::value,
7a956470 sago007 2016-02-14 17:09 547
                                          sizeof(T) >= sizeof(long long)> = 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::stoull( 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 an int 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
                                          !std::is_same<T, char>::value,
7a956470 sago007 2016-02-14 17:09 556
                                          sizeof(T) <= sizeof(int)> = 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::stoi( 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 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(int)),
7a956470 sago007 2016-02-14 17:09 565
                                          sizeof(T) <= sizeof(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::stol( 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 long long from the current top node
7a956470 sago007 2016-02-14 17:09 572
      template <class T, traits::EnableIf<std::is_signed<T>::value,
7a956470 sago007 2016-02-14 17:09 573
                                          (sizeof(T) > sizeof(long)),
7a956470 sago007 2016-02-14 17:09 574
                                          sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 575
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 576
      {
7a956470 sago007 2016-02-14 17:09 577
        value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 578
      }
7a956470 sago007 2016-02-14 17:09 579
7a956470 sago007 2016-02-14 17:09 580
      //! Loads a type best represented as a float from the current top node
7a956470 sago007 2016-02-14 17:09 581
      void loadValue( float & value )
7a956470 sago007 2016-02-14 17:09 582
      {
7a956470 sago007 2016-02-14 17:09 583
        try
7a956470 sago007 2016-02-14 17:09 584
        {
7a956470 sago007 2016-02-14 17:09 585
          value = std::stof( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 586
        }
7a956470 sago007 2016-02-14 17:09 587
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 588
        {
7a956470 sago007 2016-02-14 17:09 589
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 590
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 591
          is >> value;
7a956470 sago007 2016-02-14 17:09 592
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 593
            throw;
7a956470 sago007 2016-02-14 17:09 594
        }
7a956470 sago007 2016-02-14 17:09 595
      }
7a956470 sago007 2016-02-14 17:09 596
7a956470 sago007 2016-02-14 17:09 597
      //! Loads a type best represented as a double from the current top node
7a956470 sago007 2016-02-14 17:09 598
      void loadValue( double & value )
7a956470 sago007 2016-02-14 17:09 599
      {
7a956470 sago007 2016-02-14 17:09 600
        try
7a956470 sago007 2016-02-14 17:09 601
        {
7a956470 sago007 2016-02-14 17:09 602
          value = std::stod( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 603
        }
7a956470 sago007 2016-02-14 17:09 604
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 605
        {
7a956470 sago007 2016-02-14 17:09 606
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 607
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 608
          is >> value;
7a956470 sago007 2016-02-14 17:09 609
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 610
            throw;
7a956470 sago007 2016-02-14 17:09 611
        }
7a956470 sago007 2016-02-14 17:09 612
      }
7a956470 sago007 2016-02-14 17:09 613
7a956470 sago007 2016-02-14 17:09 614
      //! Loads a type best represented as a long double from the current top node
7a956470 sago007 2016-02-14 17:09 615
      void loadValue( long double & value )
7a956470 sago007 2016-02-14 17:09 616
      {
7a956470 sago007 2016-02-14 17:09 617
        try
7a956470 sago007 2016-02-14 17:09 618
        {
7a956470 sago007 2016-02-14 17:09 619
          value = std::stold( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 620
        }
7a956470 sago007 2016-02-14 17:09 621
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 622
        {
7a956470 sago007 2016-02-14 17:09 623
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 624
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 625
          is >> value;
7a956470 sago007 2016-02-14 17:09 626
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 627
            throw;
7a956470 sago007 2016-02-14 17:09 628
        }
7a956470 sago007 2016-02-14 17:09 629
      }
7a956470 sago007 2016-02-14 17:09 630
7a956470 sago007 2016-02-14 17:09 631
      //! Loads a string from the current node from the current top node
7a956470 sago007 2016-02-14 17:09 632
      template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 633
      void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
7a956470 sago007 2016-02-14 17:09 634
      {
7a956470 sago007 2016-02-14 17:09 635
        std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 636
7a956470 sago007 2016-02-14 17:09 637
        str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
7a956470 sago007 2016-02-14 17:09 638
                    std::istreambuf_iterator<CharT, Traits>() );
7a956470 sago007 2016-02-14 17:09 639
      }
7a956470 sago007 2016-02-14 17:09 640
7a956470 sago007 2016-02-14 17:09 641
      //! Loads the size of the current top node
7a956470 sago007 2016-02-14 17:09 642
      template <class T> inline
7a956470 sago007 2016-02-14 17:09 643
      void loadSize( T & value )
7a956470 sago007 2016-02-14 17:09 644
      {
7a956470 sago007 2016-02-14 17:09 645
        value = getNumChildren( itsNodes.top().node );
7a956470 sago007 2016-02-14 17:09 646
      }
7a956470 sago007 2016-02-14 17:09 647
7a956470 sago007 2016-02-14 17:09 648
    protected:
7a956470 sago007 2016-02-14 17:09 649
      //! Gets the number of children (usually interpreted as size) for the specified node
7a956470 sago007 2016-02-14 17:09 650
      static size_t getNumChildren( rapidxml::xml_node<> * node )
7a956470 sago007 2016-02-14 17:09 651
      {
7a956470 sago007 2016-02-14 17:09 652
        size_t size = 0;
7a956470 sago007 2016-02-14 17:09 653
        node = node->first_node(); // get first child
7a956470 sago007 2016-02-14 17:09 654
7a956470 sago007 2016-02-14 17:09 655
        while( node != nullptr )
7a956470 sago007 2016-02-14 17:09 656
        {
7a956470 sago007 2016-02-14 17:09 657
          ++size;
7a956470 sago007 2016-02-14 17:09 658
          node = node->next_sibling();
7a956470 sago007 2016-02-14 17:09 659
        }
7a956470 sago007 2016-02-14 17:09 660
7a956470 sago007 2016-02-14 17:09 661
        return size;
7a956470 sago007 2016-02-14 17:09 662
      }
7a956470 sago007 2016-02-14 17:09 663
7a956470 sago007 2016-02-14 17:09 664
      //! A struct that contains metadata about a node
7a956470 sago007 2016-02-14 17:09 665
      /*! Keeps track of some top level node, its number of
7a956470 sago007 2016-02-14 17:09 666
          remaining children, and the current active child node */
7a956470 sago007 2016-02-14 17:09 667
      struct NodeInfo
7a956470 sago007 2016-02-14 17:09 668
      {
7a956470 sago007 2016-02-14 17:09 669
        NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
7a956470 sago007 2016-02-14 17:09 670
          node( n ),
7a956470 sago007 2016-02-14 17:09 671
          child( n->first_node() ),
7a956470 sago007 2016-02-14 17:09 672
          size( XMLInputArchive::getNumChildren( n ) ),
7a956470 sago007 2016-02-14 17:09 673
          name( nullptr )
7a956470 sago007 2016-02-14 17:09 674
        { }
7a956470 sago007 2016-02-14 17:09 675
7a956470 sago007 2016-02-14 17:09 676
        //! Advances to the next sibling node of the child
7a956470 sago007 2016-02-14 17:09 677
        /*! If this is the last sibling child will be null after calling */
7a956470 sago007 2016-02-14 17:09 678
        void advance()
7a956470 sago007 2016-02-14 17:09 679
        {
7a956470 sago007 2016-02-14 17:09 680
          if( size > 0 )
7a956470 sago007 2016-02-14 17:09 681
          {
7a956470 sago007 2016-02-14 17:09 682
            --size;
7a956470 sago007 2016-02-14 17:09 683
            child = child->next_sibling();
7a956470 sago007 2016-02-14 17:09 684
          }
7a956470 sago007 2016-02-14 17:09 685
        }
7a956470 sago007 2016-02-14 17:09 686
7a956470 sago007 2016-02-14 17:09 687
        //! Searches for a child with the given name in this node
7a956470 sago007 2016-02-14 17:09 688
        /*! @param searchName The name to search for (must be null terminated)
7a956470 sago007 2016-02-14 17:09 689
            @return The node if found, nullptr otherwise */
7a956470 sago007 2016-02-14 17:09 690
        rapidxml::xml_node<> * search( const char * searchName )
7a956470 sago007 2016-02-14 17:09 691
        {
7a956470 sago007 2016-02-14 17:09 692
          if( searchName )
7a956470 sago007 2016-02-14 17:09 693
          {
7a956470 sago007 2016-02-14 17:09 694
            size_t new_size = XMLInputArchive::getNumChildren( node );
7a956470 sago007 2016-02-14 17:09 695
            const size_t name_size = rapidxml::internal::measure( searchName );
7a956470 sago007 2016-02-14 17:09 696
7a956470 sago007 2016-02-14 17:09 697
            for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
7a956470 sago007 2016-02-14 17:09 698
            {
7a956470 sago007 2016-02-14 17:09 699
              if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
7a956470 sago007 2016-02-14 17:09 700
              {
7a956470 sago007 2016-02-14 17:09 701
                size = new_size;
7a956470 sago007 2016-02-14 17:09 702
                child = new_child;
7a956470 sago007 2016-02-14 17:09 703
7a956470 sago007 2016-02-14 17:09 704
                return new_child;
7a956470 sago007 2016-02-14 17:09 705
              }
7a956470 sago007 2016-02-14 17:09 706
              --new_size;
7a956470 sago007 2016-02-14 17:09 707
            }
7a956470 sago007 2016-02-14 17:09 708
          }
7a956470 sago007 2016-02-14 17:09 709
7a956470 sago007 2016-02-14 17:09 710
          return nullptr;
7a956470 sago007 2016-02-14 17:09 711
        }
7a956470 sago007 2016-02-14 17:09 712
6c5f2c01 sago007 2017-03-15 17:56 713
        //! Returns the actual name of the next child node, if it exists
6c5f2c01 sago007 2017-03-15 17:56 714
        const char * getChildName() const
6c5f2c01 sago007 2017-03-15 17:56 715
        {
6c5f2c01 sago007 2017-03-15 17:56 716
          return child ? child->name() : nullptr;
6c5f2c01 sago007 2017-03-15 17:56 717
        }
6c5f2c01 sago007 2017-03-15 17:56 718
7a956470 sago007 2016-02-14 17:09 719
        rapidxml::xml_node<> * node;  //!< A pointer to this node
7a956470 sago007 2016-02-14 17:09 720
        rapidxml::xml_node<> * child; //!< A pointer to its current child
7a956470 sago007 2016-02-14 17:09 721
        size_t size;                  //!< The remaining number of children for this node
6c5f2c01 sago007 2017-03-15 17:56 722
        const char * name;            //!< The NVP name for next child node
7a956470 sago007 2016-02-14 17:09 723
      }; // NodeInfo
7a956470 sago007 2016-02-14 17:09 724
7a956470 sago007 2016-02-14 17:09 725
      //! @}
7a956470 sago007 2016-02-14 17:09 726
7a956470 sago007 2016-02-14 17:09 727
    private:
7a956470 sago007 2016-02-14 17:09 728
      std::vector<char> itsData;       //!< The raw data loaded
7a956470 sago007 2016-02-14 17:09 729
      rapidxml::xml_document<> itsXML; //!< The XML document
7a956470 sago007 2016-02-14 17:09 730
      std::stack<NodeInfo> itsNodes;   //!< A stack of nodes read from the document
7a956470 sago007 2016-02-14 17:09 731
  };
7a956470 sago007 2016-02-14 17:09 732
7a956470 sago007 2016-02-14 17:09 733
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 734
  // XMLArchive prologue and epilogue functions
7a956470 sago007 2016-02-14 17:09 735
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 736
7a956470 sago007 2016-02-14 17:09 737
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 738
  //! Prologue for NVPs for XML output archives
7a956470 sago007 2016-02-14 17:09 739
  /*! NVPs do not start or finish nodes - they just set up the names */
7a956470 sago007 2016-02-14 17:09 740
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 741
  void prologue( XMLOutputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 742
  { }
7a956470 sago007 2016-02-14 17:09 743
7a956470 sago007 2016-02-14 17:09 744
  //! Prologue for NVPs for XML input archives
7a956470 sago007 2016-02-14 17:09 745
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 746
  void prologue( XMLInputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 747
  { }
7a956470 sago007 2016-02-14 17:09 748
7a956470 sago007 2016-02-14 17:09 749
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 750
  //! Epilogue for NVPs for XML output archives
7a956470 sago007 2016-02-14 17:09 751
  /*! NVPs do not start or finish nodes - they just set up the names */
7a956470 sago007 2016-02-14 17:09 752
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 753
  void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 754
  { }
7a956470 sago007 2016-02-14 17:09 755
7a956470 sago007 2016-02-14 17:09 756
  //! Epilogue for NVPs for XML input archives
7a956470 sago007 2016-02-14 17:09 757
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 758
  void epilogue( XMLInputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 759
  { }
7a956470 sago007 2016-02-14 17:09 760
7a956470 sago007 2016-02-14 17:09 761
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 762
  //! Prologue for SizeTags for XML output archives
7a956470 sago007 2016-02-14 17:09 763
  /*! SizeTags do not start or finish nodes */
7a956470 sago007 2016-02-14 17:09 764
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 765
  void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 766
  {
7a956470 sago007 2016-02-14 17:09 767
    ar.appendAttribute( "size", "dynamic" );
7a956470 sago007 2016-02-14 17:09 768
  }
7a956470 sago007 2016-02-14 17:09 769
7a956470 sago007 2016-02-14 17:09 770
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 771
  void prologue( XMLInputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 772
  { }
7a956470 sago007 2016-02-14 17:09 773
7a956470 sago007 2016-02-14 17:09 774
  //! Epilogue for SizeTags for XML output archives
7a956470 sago007 2016-02-14 17:09 775
  /*! SizeTags do not start or finish nodes */
7a956470 sago007 2016-02-14 17:09 776
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 777
  void epilogue( XMLOutputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 778
  { }
7a956470 sago007 2016-02-14 17:09 779
7a956470 sago007 2016-02-14 17:09 780
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 781
  void epilogue( XMLInputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 782
  { }
7a956470 sago007 2016-02-14 17:09 783
7a956470 sago007 2016-02-14 17:09 784
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 785
  //! Prologue for all other types for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 786
  /*! Starts a new node, named either automatically or by some NVP,
7a956470 sago007 2016-02-14 17:09 787
      that may be given data by the type about to be archived
7a956470 sago007 2016-02-14 17:09 788
7a956470 sago007 2016-02-14 17:09 789
      Minimal types do not start or end nodes */
7a956470 sago007 2016-02-14 17:09 790
  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 791
                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 792
  void prologue( XMLOutputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 793
  {
7a956470 sago007 2016-02-14 17:09 794
    ar.startNode();
7a956470 sago007 2016-02-14 17:09 795
    ar.insertType<T>();
7a956470 sago007 2016-02-14 17:09 796
  }
7a956470 sago007 2016-02-14 17:09 797
7a956470 sago007 2016-02-14 17:09 798
  //! Prologue for all other types for XML input archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 799
  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 800
                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 801
  void prologue( XMLInputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 802
  {
7a956470 sago007 2016-02-14 17:09 803
    ar.startNode();
7a956470 sago007 2016-02-14 17:09 804
  }
7a956470 sago007 2016-02-14 17:09 805
7a956470 sago007 2016-02-14 17:09 806
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 807
  //! Epilogue for all other types other for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 808
  /*! Finishes the node created in the prologue
7a956470 sago007 2016-02-14 17:09 809
7a956470 sago007 2016-02-14 17:09 810
      Minimal types do not start or end nodes */
7a956470 sago007 2016-02-14 17:09 811
  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 812
                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 813
  void epilogue( XMLOutputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 814
  {
7a956470 sago007 2016-02-14 17:09 815
    ar.finishNode();
7a956470 sago007 2016-02-14 17:09 816
  }
7a956470 sago007 2016-02-14 17:09 817
7a956470 sago007 2016-02-14 17:09 818
  //! Epilogue for all other types other for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 819
  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 820
                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 821
  void epilogue( XMLInputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 822
  {
7a956470 sago007 2016-02-14 17:09 823
    ar.finishNode();
7a956470 sago007 2016-02-14 17:09 824
  }
7a956470 sago007 2016-02-14 17:09 825
7a956470 sago007 2016-02-14 17:09 826
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 827
  // Common XMLArchive serialization functions
7a956470 sago007 2016-02-14 17:09 828
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 829
7a956470 sago007 2016-02-14 17:09 830
  //! Saving NVP types to XML
7a956470 sago007 2016-02-14 17:09 831
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 832
  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
7a956470 sago007 2016-02-14 17:09 833
  {
7a956470 sago007 2016-02-14 17:09 834
    ar.setNextName( t.name );
7a956470 sago007 2016-02-14 17:09 835
    ar( t.value );
7a956470 sago007 2016-02-14 17:09 836
  }
7a956470 sago007 2016-02-14 17:09 837
7a956470 sago007 2016-02-14 17:09 838
  //! Loading NVP types from XML
7a956470 sago007 2016-02-14 17:09 839
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 840
  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
7a956470 sago007 2016-02-14 17:09 841
  {
7a956470 sago007 2016-02-14 17:09 842
    ar.setNextName( t.name );
7a956470 sago007 2016-02-14 17:09 843
    ar( t.value );
7a956470 sago007 2016-02-14 17:09 844
  }
7a956470 sago007 2016-02-14 17:09 845
7a956470 sago007 2016-02-14 17:09 846
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 847
  //! Saving SizeTags to XML
7a956470 sago007 2016-02-14 17:09 848
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 849
  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
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 SizeTags from XML
7a956470 sago007 2016-02-14 17:09 853
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 854
  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
7a956470 sago007 2016-02-14 17:09 855
  {
7a956470 sago007 2016-02-14 17:09 856
    ar.loadSize( st.size );
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 for POD types to xml
7a956470 sago007 2016-02-14 17:09 861
  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 862
  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
7a956470 sago007 2016-02-14 17:09 863
  {
7a956470 sago007 2016-02-14 17:09 864
    ar.saveValue( t );
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 for POD types from xml
7a956470 sago007 2016-02-14 17:09 868
  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 869
  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
7a956470 sago007 2016-02-14 17:09 870
  {
7a956470 sago007 2016-02-14 17:09 871
    ar.loadValue( t );
7a956470 sago007 2016-02-14 17:09 872
  }
7a956470 sago007 2016-02-14 17:09 873
7a956470 sago007 2016-02-14 17:09 874
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 875
  //! saving string to xml
7a956470 sago007 2016-02-14 17:09 876
  template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 877
  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
7a956470 sago007 2016-02-14 17:09 878
  {
7a956470 sago007 2016-02-14 17:09 879
    ar.saveValue( str );
7a956470 sago007 2016-02-14 17:09 880
  }
7a956470 sago007 2016-02-14 17:09 881
7a956470 sago007 2016-02-14 17:09 882
  //! loading string from xml
7a956470 sago007 2016-02-14 17:09 883
  template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 884
  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
7a956470 sago007 2016-02-14 17:09 885
  {
7a956470 sago007 2016-02-14 17:09 886
    ar.loadValue( str );
7a956470 sago007 2016-02-14 17:09 887
  }
7a956470 sago007 2016-02-14 17:09 888
} // namespace cereal
7a956470 sago007 2016-02-14 17:09 889
7a956470 sago007 2016-02-14 17:09 890
// register archives for polymorphic support
7a956470 sago007 2016-02-14 17:09 891
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
7a956470 sago007 2016-02-14 17:09 892
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
7a956470 sago007 2016-02-14 17:09 893
7a956470 sago007 2016-02-14 17:09 894
// tie input and output archives together
7a956470 sago007 2016-02-14 17:09 895
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
7a956470 sago007 2016-02-14 17:09 896
7a956470 sago007 2016-02-14 17:09 897
#endif // CEREAL_ARCHIVES_XML_HPP_
1970-01-01 00:00 898