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
8f94a7f5 sago007 2020-05-10 10:26 104
      /*! Options can either be directly passed to the constructor, or chained using the
8f94a7f5 sago007 2020-05-10 10:26 105
          modifier functions for an interface analogous to named parameters */
7a956470 sago007 2016-02-14 17:09 106
      class Options
7a956470 sago007 2016-02-14 17:09 107
      {
7a956470 sago007 2016-02-14 17:09 108
        public:
7a956470 sago007 2016-02-14 17:09 109
          //! Default options
7a956470 sago007 2016-02-14 17:09 110
          static Options Default(){ return Options(); }
7a956470 sago007 2016-02-14 17:09 111
7a956470 sago007 2016-02-14 17:09 112
          //! Specify specific options for the XMLOutputArchive
8f94a7f5 sago007 2020-05-10 10:26 113
          /*! @param precision_ The precision used for floating point numbers
8f94a7f5 sago007 2020-05-10 10:26 114
              @param indent_ Whether to indent each line of XML
8f94a7f5 sago007 2020-05-10 10:26 115
              @param outputType_ Whether to output the type of each serialized object as an attribute
8f94a7f5 sago007 2020-05-10 10:26 116
              @param sizeAttributes_ Whether dynamically sized containers output the size=dynamic attribute */
8f94a7f5 sago007 2020-05-10 10:26 117
          explicit Options( int precision_ = std::numeric_limits<double>::max_digits10,
8f94a7f5 sago007 2020-05-10 10:26 118
                            bool indent_ = true,
8f94a7f5 sago007 2020-05-10 10:26 119
                            bool outputType_ = false,
8f94a7f5 sago007 2020-05-10 10:26 120
                            bool sizeAttributes_ = true ) :
8f94a7f5 sago007 2020-05-10 10:26 121
            itsPrecision( precision_ ),
8f94a7f5 sago007 2020-05-10 10:26 122
            itsIndent( indent_ ),
8f94a7f5 sago007 2020-05-10 10:26 123
            itsOutputType( outputType_ ),
8f94a7f5 sago007 2020-05-10 10:26 124
            itsSizeAttributes( sizeAttributes_ )
8f94a7f5 sago007 2020-05-10 10:26 125
          { }
8f94a7f5 sago007 2020-05-10 10:26 126
8f94a7f5 sago007 2020-05-10 10:26 127
          /*! @name Option Modifiers
8f94a7f5 sago007 2020-05-10 10:26 128
              An interface for setting option settings analogous to named parameters.
8f94a7f5 sago007 2020-05-10 10:26 129
8f94a7f5 sago007 2020-05-10 10:26 130
              @code{cpp}
8f94a7f5 sago007 2020-05-10 10:26 131
              cereal::XMLOutputArchive ar( myStream,
8f94a7f5 sago007 2020-05-10 10:26 132
                                           cereal::XMLOutputArchive::Options()
8f94a7f5 sago007 2020-05-10 10:26 133
                                           .indent(true)
8f94a7f5 sago007 2020-05-10 10:26 134
                                           .sizeAttributes(false) );
8f94a7f5 sago007 2020-05-10 10:26 135
              @endcode
8f94a7f5 sago007 2020-05-10 10:26 136
              */
8f94a7f5 sago007 2020-05-10 10:26 137
          //! @{
8f94a7f5 sago007 2020-05-10 10:26 138
8f94a7f5 sago007 2020-05-10 10:26 139
          //! Sets the precision used for floaing point numbers
8f94a7f5 sago007 2020-05-10 10:26 140
          Options & precision( int value ){ itsPrecision = value; return * this; }
8f94a7f5 sago007 2020-05-10 10:26 141
          //! Whether to indent each line of XML
8f94a7f5 sago007 2020-05-10 10:26 142
          Options & indent( bool enable ){ itsIndent = enable; return *this; }
8f94a7f5 sago007 2020-05-10 10:26 143
          //! Whether to output the type of each serialized object as an attribute
8f94a7f5 sago007 2020-05-10 10:26 144
          Options & outputType( bool enable ){ itsOutputType = enable; return *this; }
8f94a7f5 sago007 2020-05-10 10:26 145
          //! Whether dynamically sized containers (e.g. vector) output the size=dynamic attribute
8f94a7f5 sago007 2020-05-10 10:26 146
          Options & sizeAttributes( bool enable ){ itsSizeAttributes = enable; return *this; }
8f94a7f5 sago007 2020-05-10 10:26 147
8f94a7f5 sago007 2020-05-10 10:26 148
          //! @}
7a956470 sago007 2016-02-14 17:09 149
7a956470 sago007 2016-02-14 17:09 150
        private:
7a956470 sago007 2016-02-14 17:09 151
          friend class XMLOutputArchive;
7a956470 sago007 2016-02-14 17:09 152
          int itsPrecision;
7a956470 sago007 2016-02-14 17:09 153
          bool itsIndent;
7a956470 sago007 2016-02-14 17:09 154
          bool itsOutputType;
8f94a7f5 sago007 2020-05-10 10:26 155
          bool itsSizeAttributes;
7a956470 sago007 2016-02-14 17:09 156
      };
7a956470 sago007 2016-02-14 17:09 157
7a956470 sago007 2016-02-14 17:09 158
      //! Construct, outputting to the provided stream upon destruction
7a956470 sago007 2016-02-14 17:09 159
      /*! @param stream  The stream to output to.  Note that XML is only guaranteed to flush
7a956470 sago007 2016-02-14 17:09 160
                         its output to the stream upon destruction.
7a956470 sago007 2016-02-14 17:09 161
          @param options The XML specific options to use.  See the Options struct
7a956470 sago007 2016-02-14 17:09 162
                         for the values of default parameters */
7a956470 sago007 2016-02-14 17:09 163
      XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
7a956470 sago007 2016-02-14 17:09 164
        OutputArchive<XMLOutputArchive>(this),
7a956470 sago007 2016-02-14 17:09 165
        itsStream(stream),
7a956470 sago007 2016-02-14 17:09 166
        itsOutputType( options.itsOutputType ),
8f94a7f5 sago007 2020-05-10 10:26 167
        itsIndent( options.itsIndent ),
8f94a7f5 sago007 2020-05-10 10:26 168
        itsSizeAttributes(options.itsSizeAttributes)
7a956470 sago007 2016-02-14 17:09 169
      {
7a956470 sago007 2016-02-14 17:09 170
        // rapidxml will delete all allocations when xml_document is cleared
7a956470 sago007 2016-02-14 17:09 171
        auto node = itsXML.allocate_node( rapidxml::node_declaration );
7a956470 sago007 2016-02-14 17:09 172
        node->append_attribute( itsXML.allocate_attribute( "version", "1.0" ) );
7a956470 sago007 2016-02-14 17:09 173
        node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) );
7a956470 sago007 2016-02-14 17:09 174
        itsXML.append_node( node );
7a956470 sago007 2016-02-14 17:09 175
7a956470 sago007 2016-02-14 17:09 176
        // allocate root node
7a956470 sago007 2016-02-14 17:09 177
        auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
7a956470 sago007 2016-02-14 17:09 178
        itsXML.append_node( root );
7a956470 sago007 2016-02-14 17:09 179
        itsNodes.emplace( root );
7a956470 sago007 2016-02-14 17:09 180
7a956470 sago007 2016-02-14 17:09 181
        // set attributes on the streams
7a956470 sago007 2016-02-14 17:09 182
        itsStream << std::boolalpha;
7a956470 sago007 2016-02-14 17:09 183
        itsStream.precision( options.itsPrecision );
7a956470 sago007 2016-02-14 17:09 184
        itsOS << std::boolalpha;
7a956470 sago007 2016-02-14 17:09 185
        itsOS.precision( options.itsPrecision );
7a956470 sago007 2016-02-14 17:09 186
      }
7a956470 sago007 2016-02-14 17:09 187
7a956470 sago007 2016-02-14 17:09 188
      //! Destructor, flushes the XML
6c5f2c01 sago007 2017-03-15 17:56 189
      ~XMLOutputArchive() CEREAL_NOEXCEPT
7a956470 sago007 2016-02-14 17:09 190
      {
7a956470 sago007 2016-02-14 17:09 191
        const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
7a956470 sago007 2016-02-14 17:09 192
        rapidxml::print( itsStream, itsXML, flags );
7a956470 sago007 2016-02-14 17:09 193
        itsXML.clear();
7a956470 sago007 2016-02-14 17:09 194
      }
7a956470 sago007 2016-02-14 17:09 195
7a956470 sago007 2016-02-14 17:09 196
      //! Saves some binary data, encoded as a base64 string, with an optional name
7a956470 sago007 2016-02-14 17:09 197
      /*! This can be called directly by users and it will automatically create a child node for
7a956470 sago007 2016-02-14 17:09 198
          the current XML node, populate it with a base64 encoded string, and optionally name
7a956470 sago007 2016-02-14 17:09 199
          it.  The node will be finished after it has been populated.  */
7a956470 sago007 2016-02-14 17:09 200
      void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
7a956470 sago007 2016-02-14 17:09 201
      {
7a956470 sago007 2016-02-14 17:09 202
        itsNodes.top().name = name;
7a956470 sago007 2016-02-14 17:09 203
7a956470 sago007 2016-02-14 17:09 204
        startNode();
7a956470 sago007 2016-02-14 17:09 205
7a956470 sago007 2016-02-14 17:09 206
        auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
7a956470 sago007 2016-02-14 17:09 207
        saveValue( base64string );
7a956470 sago007 2016-02-14 17:09 208
7a956470 sago007 2016-02-14 17:09 209
        if( itsOutputType )
7a956470 sago007 2016-02-14 17:09 210
          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
7a956470 sago007 2016-02-14 17:09 211
7a956470 sago007 2016-02-14 17:09 212
        finishNode();
8f94a7f5 sago007 2020-05-10 10:26 213
      }
7a956470 sago007 2016-02-14 17:09 214
7a956470 sago007 2016-02-14 17:09 215
      //! @}
7a956470 sago007 2016-02-14 17:09 216
      /*! @name Internal Functionality
7a956470 sago007 2016-02-14 17:09 217
          Functionality designed for use by those requiring control over the inner mechanisms of
7a956470 sago007 2016-02-14 17:09 218
          the XMLOutputArchive */
7a956470 sago007 2016-02-14 17:09 219
      //! @{
7a956470 sago007 2016-02-14 17:09 220
7a956470 sago007 2016-02-14 17:09 221
      //! Creates a new node that is a child of the node at the top of the stack
7a956470 sago007 2016-02-14 17:09 222
      /*! Nodes will be given a name that has either been pre-set by a name value pair,
7a956470 sago007 2016-02-14 17:09 223
          or generated based upon a counter unique to the parent node.  If you want to
7a956470 sago007 2016-02-14 17:09 224
          give a node a specific name, use setNextName prior to calling startNode.
7a956470 sago007 2016-02-14 17:09 225
7a956470 sago007 2016-02-14 17:09 226
          The node will then be pushed onto the node stack. */
7a956470 sago007 2016-02-14 17:09 227
      void startNode()
7a956470 sago007 2016-02-14 17:09 228
      {
7a956470 sago007 2016-02-14 17:09 229
        // generate a name for this new node
7a956470 sago007 2016-02-14 17:09 230
        const auto nameString = itsNodes.top().getValueName();
7a956470 sago007 2016-02-14 17:09 231
7a956470 sago007 2016-02-14 17:09 232
        // allocate strings for all of the data in the XML object
7a956470 sago007 2016-02-14 17:09 233
        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
7a956470 sago007 2016-02-14 17:09 234
7a956470 sago007 2016-02-14 17:09 235
        // insert into the XML
7a956470 sago007 2016-02-14 17:09 236
        auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
7a956470 sago007 2016-02-14 17:09 237
        itsNodes.top().node->append_node( node );
7a956470 sago007 2016-02-14 17:09 238
        itsNodes.emplace( node );
7a956470 sago007 2016-02-14 17:09 239
      }
7a956470 sago007 2016-02-14 17:09 240
7a956470 sago007 2016-02-14 17:09 241
      //! Designates the most recently added node as finished
7a956470 sago007 2016-02-14 17:09 242
      void finishNode()
7a956470 sago007 2016-02-14 17:09 243
      {
7a956470 sago007 2016-02-14 17:09 244
        itsNodes.pop();
7a956470 sago007 2016-02-14 17:09 245
      }
7a956470 sago007 2016-02-14 17:09 246
7a956470 sago007 2016-02-14 17:09 247
      //! Sets the name for the next node created with startNode
7a956470 sago007 2016-02-14 17:09 248
      void setNextName( const char * name )
7a956470 sago007 2016-02-14 17:09 249
      {
7a956470 sago007 2016-02-14 17:09 250
        itsNodes.top().name = name;
7a956470 sago007 2016-02-14 17:09 251
      }
7a956470 sago007 2016-02-14 17:09 252
7a956470 sago007 2016-02-14 17:09 253
      //! Saves some data, encoded as a string, into the current top level node
7a956470 sago007 2016-02-14 17:09 254
      /*! The data will be be named with the most recent name if one exists,
7a956470 sago007 2016-02-14 17:09 255
          otherwise it will be given some default delimited value that depends upon
7a956470 sago007 2016-02-14 17:09 256
          the parent node */
7a956470 sago007 2016-02-14 17:09 257
      template <class T> inline
7a956470 sago007 2016-02-14 17:09 258
      void saveValue( T const & value )
7a956470 sago007 2016-02-14 17:09 259
      {
7a956470 sago007 2016-02-14 17:09 260
        itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
7a956470 sago007 2016-02-14 17:09 261
        itsOS << value << std::ends;
7a956470 sago007 2016-02-14 17:09 262
6c5f2c01 sago007 2017-03-15 17:56 263
        auto strValue = itsOS.str();
6c5f2c01 sago007 2017-03-15 17:56 264
6c5f2c01 sago007 2017-03-15 17:56 265
        // itsOS.str() may contain data from previous calls after the first '\0' that was just inserted
6c5f2c01 sago007 2017-03-15 17:56 266
        // 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 267
        // whitespace validation is done properly
6c5f2c01 sago007 2017-03-15 17:56 268
        strValue.resize(std::strlen(strValue.c_str()));
7a956470 sago007 2016-02-14 17:09 269
7a956470 sago007 2016-02-14 17:09 270
        // If the first or last character is a whitespace, add xml:space attribute
7a956470 sago007 2016-02-14 17:09 271
        const auto len = strValue.length();
6c5f2c01 sago007 2017-03-15 17:56 272
        if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) )
7a956470 sago007 2016-02-14 17:09 273
        {
7a956470 sago007 2016-02-14 17:09 274
          itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
7a956470 sago007 2016-02-14 17:09 275
        }
7a956470 sago007 2016-02-14 17:09 276
7a956470 sago007 2016-02-14 17:09 277
        // allocate strings for all of the data in the XML object
6c5f2c01 sago007 2017-03-15 17:56 278
        auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 );
7a956470 sago007 2016-02-14 17:09 279
7a956470 sago007 2016-02-14 17:09 280
        // insert into the XML
7a956470 sago007 2016-02-14 17:09 281
        itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
7a956470 sago007 2016-02-14 17:09 282
      }
7a956470 sago007 2016-02-14 17:09 283
7a956470 sago007 2016-02-14 17:09 284
      //! Overload for uint8_t prevents them from being serialized as characters
7a956470 sago007 2016-02-14 17:09 285
      void saveValue( uint8_t const & value )
7a956470 sago007 2016-02-14 17:09 286
      {
7a956470 sago007 2016-02-14 17:09 287
        saveValue( static_cast<uint32_t>( value ) );
7a956470 sago007 2016-02-14 17:09 288
      }
7a956470 sago007 2016-02-14 17:09 289
7a956470 sago007 2016-02-14 17:09 290
      //! Overload for int8_t prevents them from being serialized as characters
7a956470 sago007 2016-02-14 17:09 291
      void saveValue( int8_t const & value )
7a956470 sago007 2016-02-14 17:09 292
      {
7a956470 sago007 2016-02-14 17:09 293
        saveValue( static_cast<int32_t>( value ) );
7a956470 sago007 2016-02-14 17:09 294
      }
7a956470 sago007 2016-02-14 17:09 295
7a956470 sago007 2016-02-14 17:09 296
      //! 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 297
      template <class T> inline
7a956470 sago007 2016-02-14 17:09 298
      void insertType()
7a956470 sago007 2016-02-14 17:09 299
      {
7a956470 sago007 2016-02-14 17:09 300
        if( !itsOutputType )
7a956470 sago007 2016-02-14 17:09 301
          return;
7a956470 sago007 2016-02-14 17:09 302
7a956470 sago007 2016-02-14 17:09 303
        // generate a name for this new node
7a956470 sago007 2016-02-14 17:09 304
        const auto nameString = util::demangledName<T>();
7a956470 sago007 2016-02-14 17:09 305
7a956470 sago007 2016-02-14 17:09 306
        // allocate strings for all of the data in the XML object
7a956470 sago007 2016-02-14 17:09 307
        auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
7a956470 sago007 2016-02-14 17:09 308
7a956470 sago007 2016-02-14 17:09 309
        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
7a956470 sago007 2016-02-14 17:09 310
      }
7a956470 sago007 2016-02-14 17:09 311
7a956470 sago007 2016-02-14 17:09 312
      //! Appends an attribute to the current top level node
7a956470 sago007 2016-02-14 17:09 313
      void appendAttribute( const char * name, const char * value )
7a956470 sago007 2016-02-14 17:09 314
      {
7a956470 sago007 2016-02-14 17:09 315
        auto namePtr =  itsXML.allocate_string( name );
7a956470 sago007 2016-02-14 17:09 316
        auto valuePtr = itsXML.allocate_string( value );
7a956470 sago007 2016-02-14 17:09 317
        itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
7a956470 sago007 2016-02-14 17:09 318
      }
7a956470 sago007 2016-02-14 17:09 319
8f94a7f5 sago007 2020-05-10 10:26 320
      bool hasSizeAttributes() const { return itsSizeAttributes; }
8f94a7f5 sago007 2020-05-10 10:26 321
7a956470 sago007 2016-02-14 17:09 322
    protected:
7a956470 sago007 2016-02-14 17:09 323
      //! A struct that contains metadata about a node
7a956470 sago007 2016-02-14 17:09 324
      struct NodeInfo
7a956470 sago007 2016-02-14 17:09 325
      {
7a956470 sago007 2016-02-14 17:09 326
        NodeInfo( rapidxml::xml_node<> * n = nullptr,
7a956470 sago007 2016-02-14 17:09 327
                  const char * nm = nullptr ) :
7a956470 sago007 2016-02-14 17:09 328
          node( n ),
7a956470 sago007 2016-02-14 17:09 329
          counter( 0 ),
7a956470 sago007 2016-02-14 17:09 330
          name( nm )
7a956470 sago007 2016-02-14 17:09 331
        { }
7a956470 sago007 2016-02-14 17:09 332
7a956470 sago007 2016-02-14 17:09 333
        rapidxml::xml_node<> * node; //!< A pointer to this node
7a956470 sago007 2016-02-14 17:09 334
        size_t counter;              //!< The counter for naming child nodes
7a956470 sago007 2016-02-14 17:09 335
        const char * name;           //!< The name for the next child node
7a956470 sago007 2016-02-14 17:09 336
7a956470 sago007 2016-02-14 17:09 337
        //! Gets the name for the next child node created from this node
7a956470 sago007 2016-02-14 17:09 338
        /*! The name will be automatically generated using the counter if
7a956470 sago007 2016-02-14 17:09 339
            a name has not been previously set.  If a name has been previously
7a956470 sago007 2016-02-14 17:09 340
            set, that name will be returned only once */
7a956470 sago007 2016-02-14 17:09 341
        std::string getValueName()
7a956470 sago007 2016-02-14 17:09 342
        {
7a956470 sago007 2016-02-14 17:09 343
          if( name )
7a956470 sago007 2016-02-14 17:09 344
          {
7a956470 sago007 2016-02-14 17:09 345
            auto n = name;
7a956470 sago007 2016-02-14 17:09 346
            name = nullptr;
7a956470 sago007 2016-02-14 17:09 347
            return {n};
7a956470 sago007 2016-02-14 17:09 348
          }
7a956470 sago007 2016-02-14 17:09 349
          else
7a956470 sago007 2016-02-14 17:09 350
            return "value" + std::to_string( counter++ ) + "\0";
7a956470 sago007 2016-02-14 17:09 351
        }
7a956470 sago007 2016-02-14 17:09 352
      }; // NodeInfo
7a956470 sago007 2016-02-14 17:09 353
7a956470 sago007 2016-02-14 17:09 354
      //! @}
7a956470 sago007 2016-02-14 17:09 355
7a956470 sago007 2016-02-14 17:09 356
    private:
7a956470 sago007 2016-02-14 17:09 357
      std::ostream & itsStream;        //!< The output stream
7a956470 sago007 2016-02-14 17:09 358
      rapidxml::xml_document<> itsXML; //!< The XML document
7a956470 sago007 2016-02-14 17:09 359
      std::stack<NodeInfo> itsNodes;   //!< A stack of nodes added to the document
7a956470 sago007 2016-02-14 17:09 360
      std::ostringstream itsOS;        //!< Used to format strings internally
7a956470 sago007 2016-02-14 17:09 361
      bool itsOutputType;              //!< Controls whether type information is printed
7a956470 sago007 2016-02-14 17:09 362
      bool itsIndent;                  //!< Controls whether indenting is used
8f94a7f5 sago007 2020-05-10 10:26 363
      bool itsSizeAttributes;          //!< Controls whether lists have a size attribute
7a956470 sago007 2016-02-14 17:09 364
  }; // XMLOutputArchive
7a956470 sago007 2016-02-14 17:09 365
7a956470 sago007 2016-02-14 17:09 366
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 367
  //! An output archive designed to load data from XML
7a956470 sago007 2016-02-14 17:09 368
  /*! This archive uses RapidXML to build an in memory XML tree of the
7a956470 sago007 2016-02-14 17:09 369
      data in the stream it is given before loading any types serialized.
7a956470 sago007 2016-02-14 17:09 370
6c5f2c01 sago007 2017-03-15 17:56 371
      As with the output XML archive, the preferred way to use this archive is in
6c5f2c01 sago007 2017-03-15 17:56 372
      an RAII fashion, ensuring its destruction after all data has been read.
6c5f2c01 sago007 2017-03-15 17:56 373
7a956470 sago007 2016-02-14 17:09 374
      Input XML should have been produced by the XMLOutputArchive.  Data can
7a956470 sago007 2016-02-14 17:09 375
      only be added to dynamically sized containers - the input archive will
7a956470 sago007 2016-02-14 17:09 376
      determine their size by looking at the number of child nodes.  Data that
7a956470 sago007 2016-02-14 17:09 377
      did not originate from an XMLOutputArchive is not officially supported,
7a956470 sago007 2016-02-14 17:09 378
      but may be possible to use if properly formatted.
7a956470 sago007 2016-02-14 17:09 379
7a956470 sago007 2016-02-14 17:09 380
      The XMLInputArchive does not require that nodes are loaded in the same
7a956470 sago007 2016-02-14 17:09 381
      order they were saved by XMLOutputArchive.  Using name value pairs (NVPs),
7a956470 sago007 2016-02-14 17:09 382
      it is possible to load in an out of order fashion or otherwise skip/select
7a956470 sago007 2016-02-14 17:09 383
      specific nodes to load.
7a956470 sago007 2016-02-14 17:09 384
7a956470 sago007 2016-02-14 17:09 385
      The default behavior of the input archive is to read sequentially starting
7a956470 sago007 2016-02-14 17:09 386
      with the first node and exploring its children.  When a given NVP does
7a956470 sago007 2016-02-14 17:09 387
      not match the read in name for a node, the archive will search for that
7a956470 sago007 2016-02-14 17:09 388
      node at the current level and load it if it exists.  After loading an out of
7a956470 sago007 2016-02-14 17:09 389
      order node, the archive will then proceed back to loading sequentially from
7a956470 sago007 2016-02-14 17:09 390
      its new position.
7a956470 sago007 2016-02-14 17:09 391
7a956470 sago007 2016-02-14 17:09 392
      Consider this simple example where loading of some data is skipped:
7a956470 sago007 2016-02-14 17:09 393
7a956470 sago007 2016-02-14 17:09 394
      @code{cpp}
7a956470 sago007 2016-02-14 17:09 395
      // imagine the input file has someData(1-9) saved in order at the top level node
7a956470 sago007 2016-02-14 17:09 396
      ar( someData1, someData2, someData3 );        // XML loads in the order it sees in the file
7a956470 sago007 2016-02-14 17:09 397
      ar( cereal::make_nvp( "hello", someData6 ) ); // NVP given does not
7a956470 sago007 2016-02-14 17:09 398
                                                    // match expected NVP name, so we search
7a956470 sago007 2016-02-14 17:09 399
                                                    // for the given NVP and load that value
7a956470 sago007 2016-02-14 17:09 400
      ar( someData7, someData8, someData9 );        // with no NVP given, loading resumes at its
7a956470 sago007 2016-02-14 17:09 401
                                                    // current location, proceeding sequentially
7a956470 sago007 2016-02-14 17:09 402
      @endcode
7a956470 sago007 2016-02-14 17:09 403
7a956470 sago007 2016-02-14 17:09 404
      \ingroup Archives */
7a956470 sago007 2016-02-14 17:09 405
  class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
7a956470 sago007 2016-02-14 17:09 406
  {
7a956470 sago007 2016-02-14 17:09 407
    public:
7a956470 sago007 2016-02-14 17:09 408
      /*! @name Common Functionality
7a956470 sago007 2016-02-14 17:09 409
          Common use cases for directly interacting with an XMLInputArchive */
7a956470 sago007 2016-02-14 17:09 410
      //! @{
7a956470 sago007 2016-02-14 17:09 411
7a956470 sago007 2016-02-14 17:09 412
      //! Construct, reading in from the provided stream
7a956470 sago007 2016-02-14 17:09 413
      /*! Reads in an entire XML document from some stream and parses it as soon
7a956470 sago007 2016-02-14 17:09 414
          as serialization starts
7a956470 sago007 2016-02-14 17:09 415
7a956470 sago007 2016-02-14 17:09 416
          @param stream The stream to read from.  Can be a stringstream or a file. */
7a956470 sago007 2016-02-14 17:09 417
      XMLInputArchive( std::istream & stream ) :
7a956470 sago007 2016-02-14 17:09 418
        InputArchive<XMLInputArchive>( this ),
7a956470 sago007 2016-02-14 17:09 419
        itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
7a956470 sago007 2016-02-14 17:09 420
      {
7a956470 sago007 2016-02-14 17:09 421
        try
7a956470 sago007 2016-02-14 17:09 422
        {
7a956470 sago007 2016-02-14 17:09 423
          itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
7a956470 sago007 2016-02-14 17:09 424
          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 425
        }
7a956470 sago007 2016-02-14 17:09 426
        catch( rapidxml::parse_error const & )
7a956470 sago007 2016-02-14 17:09 427
        {
7a956470 sago007 2016-02-14 17:09 428
          //std::cerr << "-----Original-----" << std::endl;
7a956470 sago007 2016-02-14 17:09 429
          //stream.seekg(0);
7a956470 sago007 2016-02-14 17:09 430
          //std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
7a956470 sago007 2016-02-14 17:09 431
7a956470 sago007 2016-02-14 17:09 432
          //std::cerr << "-----Error-----" << std::endl;
7a956470 sago007 2016-02-14 17:09 433
          //std::cerr << e.what() << std::endl;
7a956470 sago007 2016-02-14 17:09 434
          //std::cerr << e.where<char>() << std::endl;
7a956470 sago007 2016-02-14 17:09 435
          throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
7a956470 sago007 2016-02-14 17:09 436
        }
7a956470 sago007 2016-02-14 17:09 437
7a956470 sago007 2016-02-14 17:09 438
        // Parse the root
7a956470 sago007 2016-02-14 17:09 439
        auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
7a956470 sago007 2016-02-14 17:09 440
        if( root == nullptr )
7a956470 sago007 2016-02-14 17:09 441
          throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
7a956470 sago007 2016-02-14 17:09 442
        else
7a956470 sago007 2016-02-14 17:09 443
          itsNodes.emplace( root );
7a956470 sago007 2016-02-14 17:09 444
      }
7a956470 sago007 2016-02-14 17:09 445
6c5f2c01 sago007 2017-03-15 17:56 446
      ~XMLInputArchive() CEREAL_NOEXCEPT = default;
6c5f2c01 sago007 2017-03-15 17:56 447
7a956470 sago007 2016-02-14 17:09 448
      //! Loads some binary data, encoded as a base64 string, optionally specified by some name
7a956470 sago007 2016-02-14 17:09 449
      /*! 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 450
          users.
7a956470 sago007 2016-02-14 17:09 451
7a956470 sago007 2016-02-14 17:09 452
          Note that this follows the same ordering rules specified in the class description in regards
7a956470 sago007 2016-02-14 17:09 453
          to loading in/out of order */
7a956470 sago007 2016-02-14 17:09 454
      void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
7a956470 sago007 2016-02-14 17:09 455
      {
7a956470 sago007 2016-02-14 17:09 456
        setNextName( name );
7a956470 sago007 2016-02-14 17:09 457
        startNode();
7a956470 sago007 2016-02-14 17:09 458
7a956470 sago007 2016-02-14 17:09 459
        std::string encoded;
7a956470 sago007 2016-02-14 17:09 460
        loadValue( encoded );
7a956470 sago007 2016-02-14 17:09 461
7a956470 sago007 2016-02-14 17:09 462
        auto decoded = base64::decode( encoded );
7a956470 sago007 2016-02-14 17:09 463
7a956470 sago007 2016-02-14 17:09 464
        if( size != decoded.size() )
7a956470 sago007 2016-02-14 17:09 465
          throw Exception("Decoded binary data size does not match specified size");
7a956470 sago007 2016-02-14 17:09 466
7a956470 sago007 2016-02-14 17:09 467
        std::memcpy( data, decoded.data(), decoded.size() );
7a956470 sago007 2016-02-14 17:09 468
7a956470 sago007 2016-02-14 17:09 469
        finishNode();
8f94a7f5 sago007 2020-05-10 10:26 470
      }
7a956470 sago007 2016-02-14 17:09 471
7a956470 sago007 2016-02-14 17:09 472
      //! @}
7a956470 sago007 2016-02-14 17:09 473
      /*! @name Internal Functionality
7a956470 sago007 2016-02-14 17:09 474
          Functionality designed for use by those requiring control over the inner mechanisms of
7a956470 sago007 2016-02-14 17:09 475
          the XMLInputArchive */
7a956470 sago007 2016-02-14 17:09 476
      //! @{
7a956470 sago007 2016-02-14 17:09 477
7a956470 sago007 2016-02-14 17:09 478
      //! Prepares to start reading the next node
7a956470 sago007 2016-02-14 17:09 479
      /*! This places the next node to be parsed onto the nodes stack.
7a956470 sago007 2016-02-14 17:09 480
7a956470 sago007 2016-02-14 17:09 481
          By default our strategy is to start with the document root node and then
7a956470 sago007 2016-02-14 17:09 482
          recursively iterate through all children in the order they show up in the document.
7a956470 sago007 2016-02-14 17:09 483
          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 484
7a956470 sago007 2016-02-14 17:09 485
          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 486
          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 487
          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 488
      void startNode()
7a956470 sago007 2016-02-14 17:09 489
      {
7a956470 sago007 2016-02-14 17:09 490
        auto next = itsNodes.top().child; // By default we would move to the next child node
7a956470 sago007 2016-02-14 17:09 491
        auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
7a956470 sago007 2016-02-14 17:09 492
7a956470 sago007 2016-02-14 17:09 493
        // If we were given an NVP name, look for it in the current level of the document.
7a956470 sago007 2016-02-14 17:09 494
        //    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 495
        //    the NVP name does not match the name of the node we would normally read next
7a956470 sago007 2016-02-14 17:09 496
        if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
7a956470 sago007 2016-02-14 17:09 497
        {
7a956470 sago007 2016-02-14 17:09 498
          next = itsNodes.top().search( expectedName );
7a956470 sago007 2016-02-14 17:09 499
7a956470 sago007 2016-02-14 17:09 500
          if( next == nullptr )
6c5f2c01 sago007 2017-03-15 17:56 501
            throw Exception("XML Parsing failed - provided NVP (" + std::string(expectedName) + ") not found");
7a956470 sago007 2016-02-14 17:09 502
        }
7a956470 sago007 2016-02-14 17:09 503
7a956470 sago007 2016-02-14 17:09 504
        itsNodes.emplace( next );
7a956470 sago007 2016-02-14 17:09 505
      }
7a956470 sago007 2016-02-14 17:09 506
7a956470 sago007 2016-02-14 17:09 507
      //! Finishes reading the current node
7a956470 sago007 2016-02-14 17:09 508
      void finishNode()
7a956470 sago007 2016-02-14 17:09 509
      {
7a956470 sago007 2016-02-14 17:09 510
        // remove current
7a956470 sago007 2016-02-14 17:09 511
        itsNodes.pop();
7a956470 sago007 2016-02-14 17:09 512
7a956470 sago007 2016-02-14 17:09 513
        // advance parent
7a956470 sago007 2016-02-14 17:09 514
        itsNodes.top().advance();
7a956470 sago007 2016-02-14 17:09 515
7a956470 sago007 2016-02-14 17:09 516
        // Reset name
7a956470 sago007 2016-02-14 17:09 517
        itsNodes.top().name = nullptr;
7a956470 sago007 2016-02-14 17:09 518
      }
7a956470 sago007 2016-02-14 17:09 519
7a956470 sago007 2016-02-14 17:09 520
      //! Retrieves the current node name
7a956470 sago007 2016-02-14 17:09 521
      //! will return @c nullptr if the node does not have a name
7a956470 sago007 2016-02-14 17:09 522
      const char * getNodeName() const
7a956470 sago007 2016-02-14 17:09 523
      {
6c5f2c01 sago007 2017-03-15 17:56 524
        return itsNodes.top().getChildName();
7a956470 sago007 2016-02-14 17:09 525
      }
7a956470 sago007 2016-02-14 17:09 526
7a956470 sago007 2016-02-14 17:09 527
      //! Sets the name for the next node created with startNode
7a956470 sago007 2016-02-14 17:09 528
      void setNextName( const char * name )
7a956470 sago007 2016-02-14 17:09 529
      {
7a956470 sago007 2016-02-14 17:09 530
        itsNodes.top().name = name;
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 bool 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> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 536
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 537
      {
7a956470 sago007 2016-02-14 17:09 538
        std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 539
        is.setf( std::ios::boolalpha );
7a956470 sago007 2016-02-14 17:09 540
        is >> value;
7a956470 sago007 2016-02-14 17:09 541
      }
7a956470 sago007 2016-02-14 17:09 542
7a956470 sago007 2016-02-14 17:09 543
      //! Loads a char (signed or unsigned) from the current top node
7a956470 sago007 2016-02-14 17:09 544
      template <class T, traits::EnableIf<std::is_integral<T>::value,
7a956470 sago007 2016-02-14 17:09 545
                                          !std::is_same<T, bool>::value,
7a956470 sago007 2016-02-14 17:09 546
                                          sizeof(T) == sizeof(char)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 547
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 548
      {
7a956470 sago007 2016-02-14 17:09 549
        value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 550
      }
7a956470 sago007 2016-02-14 17:09 551
7a956470 sago007 2016-02-14 17:09 552
      //! Load an int8_t from the current top node (ensures we parse entire number)
7a956470 sago007 2016-02-14 17:09 553
      void loadValue( int8_t & value )
7a956470 sago007 2016-02-14 17:09 554
      {
7a956470 sago007 2016-02-14 17:09 555
        int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
7a956470 sago007 2016-02-14 17:09 556
      }
7a956470 sago007 2016-02-14 17:09 557
7a956470 sago007 2016-02-14 17:09 558
      //! Load a uint8_t from the current top node (ensures we parse entire number)
7a956470 sago007 2016-02-14 17:09 559
      void loadValue( uint8_t & value )
7a956470 sago007 2016-02-14 17:09 560
      {
7a956470 sago007 2016-02-14 17:09 561
        uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
7a956470 sago007 2016-02-14 17:09 562
      }
7a956470 sago007 2016-02-14 17:09 563
7a956470 sago007 2016-02-14 17:09 564
      //! Loads a type best represented as an unsigned long from the current top node
7a956470 sago007 2016-02-14 17:09 565
      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
7a956470 sago007 2016-02-14 17:09 566
                                          !std::is_same<T, bool>::value,
6c5f2c01 sago007 2017-03-15 17:56 567
                                          !std::is_same<T, char>::value,
7a956470 sago007 2016-02-14 17:09 568
                                          !std::is_same<T, unsigned char>::value,
7a956470 sago007 2016-02-14 17:09 569
                                          sizeof(T) < sizeof(long long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 570
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 571
      {
7a956470 sago007 2016-02-14 17:09 572
        value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 573
      }
7a956470 sago007 2016-02-14 17:09 574
7a956470 sago007 2016-02-14 17:09 575
      //! Loads a type best represented as an unsigned long long from the current top node
7a956470 sago007 2016-02-14 17:09 576
      template <class T, traits::EnableIf<std::is_unsigned<T>::value,
7a956470 sago007 2016-02-14 17:09 577
                                          !std::is_same<T, bool>::value,
7a956470 sago007 2016-02-14 17:09 578
                                          sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 579
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 580
      {
7a956470 sago007 2016-02-14 17:09 581
        value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 582
      }
7a956470 sago007 2016-02-14 17:09 583
7a956470 sago007 2016-02-14 17:09 584
      //! Loads a type best represented as an int from the current top node
7a956470 sago007 2016-02-14 17:09 585
      template <class T, traits::EnableIf<std::is_signed<T>::value,
7a956470 sago007 2016-02-14 17:09 586
                                          !std::is_same<T, char>::value,
7a956470 sago007 2016-02-14 17:09 587
                                          sizeof(T) <= sizeof(int)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 588
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 589
      {
7a956470 sago007 2016-02-14 17:09 590
        value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 591
      }
7a956470 sago007 2016-02-14 17:09 592
7a956470 sago007 2016-02-14 17:09 593
      //! Loads a type best represented as a long from the current top node
7a956470 sago007 2016-02-14 17:09 594
      template <class T, traits::EnableIf<std::is_signed<T>::value,
7a956470 sago007 2016-02-14 17:09 595
                                          (sizeof(T) > sizeof(int)),
7a956470 sago007 2016-02-14 17:09 596
                                          sizeof(T) <= sizeof(long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 597
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 598
      {
7a956470 sago007 2016-02-14 17:09 599
        value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 600
      }
7a956470 sago007 2016-02-14 17:09 601
7a956470 sago007 2016-02-14 17:09 602
      //! Loads a type best represented as a long long from the current top node
7a956470 sago007 2016-02-14 17:09 603
      template <class T, traits::EnableIf<std::is_signed<T>::value,
7a956470 sago007 2016-02-14 17:09 604
                                          (sizeof(T) > sizeof(long)),
7a956470 sago007 2016-02-14 17:09 605
                                          sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 606
      void loadValue( T & value )
7a956470 sago007 2016-02-14 17:09 607
      {
7a956470 sago007 2016-02-14 17:09 608
        value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
7a956470 sago007 2016-02-14 17:09 609
      }
7a956470 sago007 2016-02-14 17:09 610
7a956470 sago007 2016-02-14 17:09 611
      //! Loads a type best represented as a float from the current top node
7a956470 sago007 2016-02-14 17:09 612
      void loadValue( float & value )
7a956470 sago007 2016-02-14 17:09 613
      {
7a956470 sago007 2016-02-14 17:09 614
        try
7a956470 sago007 2016-02-14 17:09 615
        {
7a956470 sago007 2016-02-14 17:09 616
          value = std::stof( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 617
        }
7a956470 sago007 2016-02-14 17:09 618
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 619
        {
7a956470 sago007 2016-02-14 17:09 620
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 621
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 622
          is >> value;
7a956470 sago007 2016-02-14 17:09 623
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 624
            throw;
7a956470 sago007 2016-02-14 17:09 625
        }
7a956470 sago007 2016-02-14 17:09 626
      }
7a956470 sago007 2016-02-14 17:09 627
7a956470 sago007 2016-02-14 17:09 628
      //! Loads a type best represented as a double from the current top node
7a956470 sago007 2016-02-14 17:09 629
      void loadValue( double & value )
7a956470 sago007 2016-02-14 17:09 630
      {
7a956470 sago007 2016-02-14 17:09 631
        try
7a956470 sago007 2016-02-14 17:09 632
        {
7a956470 sago007 2016-02-14 17:09 633
          value = std::stod( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 634
        }
7a956470 sago007 2016-02-14 17:09 635
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 636
        {
7a956470 sago007 2016-02-14 17:09 637
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 638
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 639
          is >> value;
7a956470 sago007 2016-02-14 17:09 640
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 641
            throw;
7a956470 sago007 2016-02-14 17:09 642
        }
7a956470 sago007 2016-02-14 17:09 643
      }
7a956470 sago007 2016-02-14 17:09 644
7a956470 sago007 2016-02-14 17:09 645
      //! Loads a type best represented as a long double from the current top node
7a956470 sago007 2016-02-14 17:09 646
      void loadValue( long double & value )
7a956470 sago007 2016-02-14 17:09 647
      {
7a956470 sago007 2016-02-14 17:09 648
        try
7a956470 sago007 2016-02-14 17:09 649
        {
7a956470 sago007 2016-02-14 17:09 650
          value = std::stold( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 651
        }
7a956470 sago007 2016-02-14 17:09 652
        catch( std::out_of_range const & )
7a956470 sago007 2016-02-14 17:09 653
        {
7a956470 sago007 2016-02-14 17:09 654
          // special case for denormalized values
7a956470 sago007 2016-02-14 17:09 655
          std::istringstream is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 656
          is >> value;
7a956470 sago007 2016-02-14 17:09 657
          if( std::fpclassify( value ) != FP_SUBNORMAL )
7a956470 sago007 2016-02-14 17:09 658
            throw;
7a956470 sago007 2016-02-14 17:09 659
        }
7a956470 sago007 2016-02-14 17:09 660
      }
7a956470 sago007 2016-02-14 17:09 661
7a956470 sago007 2016-02-14 17:09 662
      //! Loads a string from the current node from the current top node
7a956470 sago007 2016-02-14 17:09 663
      template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 664
      void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
7a956470 sago007 2016-02-14 17:09 665
      {
7a956470 sago007 2016-02-14 17:09 666
        std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
7a956470 sago007 2016-02-14 17:09 667
7a956470 sago007 2016-02-14 17:09 668
        str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
7a956470 sago007 2016-02-14 17:09 669
                    std::istreambuf_iterator<CharT, Traits>() );
7a956470 sago007 2016-02-14 17:09 670
      }
7a956470 sago007 2016-02-14 17:09 671
7a956470 sago007 2016-02-14 17:09 672
      //! Loads the size of the current top node
7a956470 sago007 2016-02-14 17:09 673
      template <class T> inline
7a956470 sago007 2016-02-14 17:09 674
      void loadSize( T & value )
7a956470 sago007 2016-02-14 17:09 675
      {
7a956470 sago007 2016-02-14 17:09 676
        value = getNumChildren( itsNodes.top().node );
7a956470 sago007 2016-02-14 17:09 677
      }
7a956470 sago007 2016-02-14 17:09 678
7a956470 sago007 2016-02-14 17:09 679
    protected:
7a956470 sago007 2016-02-14 17:09 680
      //! Gets the number of children (usually interpreted as size) for the specified node
7a956470 sago007 2016-02-14 17:09 681
      static size_t getNumChildren( rapidxml::xml_node<> * node )
7a956470 sago007 2016-02-14 17:09 682
      {
7a956470 sago007 2016-02-14 17:09 683
        size_t size = 0;
7a956470 sago007 2016-02-14 17:09 684
        node = node->first_node(); // get first child
7a956470 sago007 2016-02-14 17:09 685
7a956470 sago007 2016-02-14 17:09 686
        while( node != nullptr )
7a956470 sago007 2016-02-14 17:09 687
        {
7a956470 sago007 2016-02-14 17:09 688
          ++size;
7a956470 sago007 2016-02-14 17:09 689
          node = node->next_sibling();
7a956470 sago007 2016-02-14 17:09 690
        }
7a956470 sago007 2016-02-14 17:09 691
7a956470 sago007 2016-02-14 17:09 692
        return size;
7a956470 sago007 2016-02-14 17:09 693
      }
7a956470 sago007 2016-02-14 17:09 694
7a956470 sago007 2016-02-14 17:09 695
      //! A struct that contains metadata about a node
7a956470 sago007 2016-02-14 17:09 696
      /*! Keeps track of some top level node, its number of
7a956470 sago007 2016-02-14 17:09 697
          remaining children, and the current active child node */
7a956470 sago007 2016-02-14 17:09 698
      struct NodeInfo
7a956470 sago007 2016-02-14 17:09 699
      {
7a956470 sago007 2016-02-14 17:09 700
        NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
7a956470 sago007 2016-02-14 17:09 701
          node( n ),
7a956470 sago007 2016-02-14 17:09 702
          child( n->first_node() ),
7a956470 sago007 2016-02-14 17:09 703
          size( XMLInputArchive::getNumChildren( n ) ),
7a956470 sago007 2016-02-14 17:09 704
          name( nullptr )
7a956470 sago007 2016-02-14 17:09 705
        { }
7a956470 sago007 2016-02-14 17:09 706
7a956470 sago007 2016-02-14 17:09 707
        //! Advances to the next sibling node of the child
7a956470 sago007 2016-02-14 17:09 708
        /*! If this is the last sibling child will be null after calling */
7a956470 sago007 2016-02-14 17:09 709
        void advance()
7a956470 sago007 2016-02-14 17:09 710
        {
7a956470 sago007 2016-02-14 17:09 711
          if( size > 0 )
7a956470 sago007 2016-02-14 17:09 712
          {
7a956470 sago007 2016-02-14 17:09 713
            --size;
7a956470 sago007 2016-02-14 17:09 714
            child = child->next_sibling();
7a956470 sago007 2016-02-14 17:09 715
          }
7a956470 sago007 2016-02-14 17:09 716
        }
7a956470 sago007 2016-02-14 17:09 717
7a956470 sago007 2016-02-14 17:09 718
        //! Searches for a child with the given name in this node
7a956470 sago007 2016-02-14 17:09 719
        /*! @param searchName The name to search for (must be null terminated)
7a956470 sago007 2016-02-14 17:09 720
            @return The node if found, nullptr otherwise */
7a956470 sago007 2016-02-14 17:09 721
        rapidxml::xml_node<> * search( const char * searchName )
7a956470 sago007 2016-02-14 17:09 722
        {
7a956470 sago007 2016-02-14 17:09 723
          if( searchName )
7a956470 sago007 2016-02-14 17:09 724
          {
7a956470 sago007 2016-02-14 17:09 725
            size_t new_size = XMLInputArchive::getNumChildren( node );
7a956470 sago007 2016-02-14 17:09 726
            const size_t name_size = rapidxml::internal::measure( searchName );
7a956470 sago007 2016-02-14 17:09 727
7a956470 sago007 2016-02-14 17:09 728
            for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
7a956470 sago007 2016-02-14 17:09 729
            {
7a956470 sago007 2016-02-14 17:09 730
              if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
7a956470 sago007 2016-02-14 17:09 731
              {
7a956470 sago007 2016-02-14 17:09 732
                size = new_size;
7a956470 sago007 2016-02-14 17:09 733
                child = new_child;
7a956470 sago007 2016-02-14 17:09 734
7a956470 sago007 2016-02-14 17:09 735
                return new_child;
7a956470 sago007 2016-02-14 17:09 736
              }
7a956470 sago007 2016-02-14 17:09 737
              --new_size;
7a956470 sago007 2016-02-14 17:09 738
            }
7a956470 sago007 2016-02-14 17:09 739
          }
7a956470 sago007 2016-02-14 17:09 740
7a956470 sago007 2016-02-14 17:09 741
          return nullptr;
7a956470 sago007 2016-02-14 17:09 742
        }
7a956470 sago007 2016-02-14 17:09 743
6c5f2c01 sago007 2017-03-15 17:56 744
        //! Returns the actual name of the next child node, if it exists
6c5f2c01 sago007 2017-03-15 17:56 745
        const char * getChildName() const
6c5f2c01 sago007 2017-03-15 17:56 746
        {
6c5f2c01 sago007 2017-03-15 17:56 747
          return child ? child->name() : nullptr;
6c5f2c01 sago007 2017-03-15 17:56 748
        }
6c5f2c01 sago007 2017-03-15 17:56 749
7a956470 sago007 2016-02-14 17:09 750
        rapidxml::xml_node<> * node;  //!< A pointer to this node
7a956470 sago007 2016-02-14 17:09 751
        rapidxml::xml_node<> * child; //!< A pointer to its current child
7a956470 sago007 2016-02-14 17:09 752
        size_t size;                  //!< The remaining number of children for this node
6c5f2c01 sago007 2017-03-15 17:56 753
        const char * name;            //!< The NVP name for next child node
7a956470 sago007 2016-02-14 17:09 754
      }; // NodeInfo
7a956470 sago007 2016-02-14 17:09 755
7a956470 sago007 2016-02-14 17:09 756
      //! @}
7a956470 sago007 2016-02-14 17:09 757
7a956470 sago007 2016-02-14 17:09 758
    private:
7a956470 sago007 2016-02-14 17:09 759
      std::vector<char> itsData;       //!< The raw data loaded
7a956470 sago007 2016-02-14 17:09 760
      rapidxml::xml_document<> itsXML; //!< The XML document
7a956470 sago007 2016-02-14 17:09 761
      std::stack<NodeInfo> itsNodes;   //!< A stack of nodes read from the document
7a956470 sago007 2016-02-14 17:09 762
  };
7a956470 sago007 2016-02-14 17:09 763
7a956470 sago007 2016-02-14 17:09 764
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 765
  // XMLArchive prologue and epilogue functions
7a956470 sago007 2016-02-14 17:09 766
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 767
7a956470 sago007 2016-02-14 17:09 768
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 769
  //! Prologue for NVPs for XML output archives
7a956470 sago007 2016-02-14 17:09 770
  /*! NVPs do not start or finish nodes - they just set up the names */
7a956470 sago007 2016-02-14 17:09 771
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 772
  void prologue( XMLOutputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 773
  { }
7a956470 sago007 2016-02-14 17:09 774
7a956470 sago007 2016-02-14 17:09 775
  //! Prologue for NVPs for XML input archives
7a956470 sago007 2016-02-14 17:09 776
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 777
  void prologue( XMLInputArchive &, NameValuePair<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
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 781
  //! Epilogue for NVPs for XML output archives
7a956470 sago007 2016-02-14 17:09 782
  /*! NVPs do not start or finish nodes - they just set up the names */
7a956470 sago007 2016-02-14 17:09 783
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 784
  void epilogue( XMLOutputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 785
  { }
7a956470 sago007 2016-02-14 17:09 786
7a956470 sago007 2016-02-14 17:09 787
  //! Epilogue for NVPs for XML input archives
7a956470 sago007 2016-02-14 17:09 788
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 789
  void epilogue( XMLInputArchive &, NameValuePair<T> const & )
7a956470 sago007 2016-02-14 17:09 790
  { }
7a956470 sago007 2016-02-14 17:09 791
7a956470 sago007 2016-02-14 17:09 792
  // ######################################################################
8f94a7f5 sago007 2020-05-10 10:26 793
  //! Prologue for deferred data for XML archives
8f94a7f5 sago007 2020-05-10 10:26 794
  /*! Do nothing for the defer wrapper */
8f94a7f5 sago007 2020-05-10 10:26 795
  template <class T> inline
8f94a7f5 sago007 2020-05-10 10:26 796
  void prologue( XMLOutputArchive &, DeferredData<T> const & )
8f94a7f5 sago007 2020-05-10 10:26 797
  { }
8f94a7f5 sago007 2020-05-10 10:26 798
8f94a7f5 sago007 2020-05-10 10:26 799
  //! Prologue for deferred data for XML archives
8f94a7f5 sago007 2020-05-10 10:26 800
  template <class T> inline
8f94a7f5 sago007 2020-05-10 10:26 801
  void prologue( XMLInputArchive &, DeferredData<T> const & )
8f94a7f5 sago007 2020-05-10 10:26 802
  { }
8f94a7f5 sago007 2020-05-10 10:26 803
8f94a7f5 sago007 2020-05-10 10:26 804
  // ######################################################################
8f94a7f5 sago007 2020-05-10 10:26 805
  //! Epilogue for deferred for XML archives
8f94a7f5 sago007 2020-05-10 10:26 806
  /*! NVPs do not start or finish nodes - they just set up the names */
8f94a7f5 sago007 2020-05-10 10:26 807
  template <class T> inline
8f94a7f5 sago007 2020-05-10 10:26 808
  void epilogue( XMLOutputArchive &, DeferredData<T> const & )
8f94a7f5 sago007 2020-05-10 10:26 809
  { }
8f94a7f5 sago007 2020-05-10 10:26 810
8f94a7f5 sago007 2020-05-10 10:26 811
  //! Epilogue for deferred for XML archives
8f94a7f5 sago007 2020-05-10 10:26 812
  /*! Do nothing for the defer wrapper */
8f94a7f5 sago007 2020-05-10 10:26 813
  template <class T> inline
8f94a7f5 sago007 2020-05-10 10:26 814
  void epilogue( XMLInputArchive &, DeferredData<T> const & )
8f94a7f5 sago007 2020-05-10 10:26 815
  { }
8f94a7f5 sago007 2020-05-10 10:26 816
8f94a7f5 sago007 2020-05-10 10:26 817
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 818
  //! Prologue for SizeTags for XML output archives
7a956470 sago007 2016-02-14 17:09 819
  /*! SizeTags do not start or finish nodes */
7a956470 sago007 2016-02-14 17:09 820
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 821
  void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 822
  {
8f94a7f5 sago007 2020-05-10 10:26 823
      if (ar.hasSizeAttributes())
8f94a7f5 sago007 2020-05-10 10:26 824
      {
8f94a7f5 sago007 2020-05-10 10:26 825
          ar.appendAttribute("size", "dynamic");
8f94a7f5 sago007 2020-05-10 10:26 826
      }
7a956470 sago007 2016-02-14 17:09 827
  }
7a956470 sago007 2016-02-14 17:09 828
7a956470 sago007 2016-02-14 17:09 829
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 830
  void prologue( XMLInputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 831
  { }
7a956470 sago007 2016-02-14 17:09 832
7a956470 sago007 2016-02-14 17:09 833
  //! Epilogue for SizeTags for XML output archives
7a956470 sago007 2016-02-14 17:09 834
  /*! SizeTags do not start or finish nodes */
7a956470 sago007 2016-02-14 17:09 835
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 836
  void epilogue( XMLOutputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 837
  { }
7a956470 sago007 2016-02-14 17:09 838
7a956470 sago007 2016-02-14 17:09 839
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 840
  void epilogue( XMLInputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 841
  { }
7a956470 sago007 2016-02-14 17:09 842
7a956470 sago007 2016-02-14 17:09 843
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 844
  //! Prologue for all other types for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 845
  /*! Starts a new node, named either automatically or by some NVP,
7a956470 sago007 2016-02-14 17:09 846
      that may be given data by the type about to be archived
7a956470 sago007 2016-02-14 17:09 847
7a956470 sago007 2016-02-14 17:09 848
      Minimal types do not start or end nodes */
7a956470 sago007 2016-02-14 17:09 849
  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 850
                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 851
  void prologue( XMLOutputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 852
  {
7a956470 sago007 2016-02-14 17:09 853
    ar.startNode();
7a956470 sago007 2016-02-14 17:09 854
    ar.insertType<T>();
7a956470 sago007 2016-02-14 17:09 855
  }
7a956470 sago007 2016-02-14 17:09 856
7a956470 sago007 2016-02-14 17:09 857
  //! Prologue for all other types for XML input archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 858
  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 859
                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 860
  void prologue( XMLInputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 861
  {
7a956470 sago007 2016-02-14 17:09 862
    ar.startNode();
7a956470 sago007 2016-02-14 17:09 863
  }
7a956470 sago007 2016-02-14 17:09 864
7a956470 sago007 2016-02-14 17:09 865
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 866
  //! Epilogue for all other types other for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 867
  /*! Finishes the node created in the prologue
7a956470 sago007 2016-02-14 17:09 868
7a956470 sago007 2016-02-14 17:09 869
      Minimal types do not start or end nodes */
7a956470 sago007 2016-02-14 17:09 870
  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 871
                                       traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 872
  void epilogue( XMLOutputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 873
  {
7a956470 sago007 2016-02-14 17:09 874
    ar.finishNode();
7a956470 sago007 2016-02-14 17:09 875
  }
7a956470 sago007 2016-02-14 17:09 876
7a956470 sago007 2016-02-14 17:09 877
  //! Epilogue for all other types other for XML output archives (except minimal types)
7a956470 sago007 2016-02-14 17:09 878
  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 879
                                       traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 880
  void epilogue( XMLInputArchive & ar, T const & )
7a956470 sago007 2016-02-14 17:09 881
  {
7a956470 sago007 2016-02-14 17:09 882
    ar.finishNode();
7a956470 sago007 2016-02-14 17:09 883
  }
7a956470 sago007 2016-02-14 17:09 884
7a956470 sago007 2016-02-14 17:09 885
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 886
  // Common XMLArchive serialization functions
7a956470 sago007 2016-02-14 17:09 887
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 888
7a956470 sago007 2016-02-14 17:09 889
  //! Saving NVP types to XML
7a956470 sago007 2016-02-14 17:09 890
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 891
  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive & ar, NameValuePair<T> const & t )
7a956470 sago007 2016-02-14 17:09 892
  {
7a956470 sago007 2016-02-14 17:09 893
    ar.setNextName( t.name );
7a956470 sago007 2016-02-14 17:09 894
    ar( t.value );
7a956470 sago007 2016-02-14 17:09 895
  }
7a956470 sago007 2016-02-14 17:09 896
7a956470 sago007 2016-02-14 17:09 897
  //! Loading NVP types from XML
7a956470 sago007 2016-02-14 17:09 898
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 899
  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, NameValuePair<T> & t )
7a956470 sago007 2016-02-14 17:09 900
  {
7a956470 sago007 2016-02-14 17:09 901
    ar.setNextName( t.name );
7a956470 sago007 2016-02-14 17:09 902
    ar( t.value );
7a956470 sago007 2016-02-14 17:09 903
  }
7a956470 sago007 2016-02-14 17:09 904
7a956470 sago007 2016-02-14 17:09 905
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 906
  //! Saving SizeTags to XML
7a956470 sago007 2016-02-14 17:09 907
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 908
  void CEREAL_SAVE_FUNCTION_NAME( XMLOutputArchive &, SizeTag<T> const & )
7a956470 sago007 2016-02-14 17:09 909
  { }
7a956470 sago007 2016-02-14 17:09 910
7a956470 sago007 2016-02-14 17:09 911
  //! Loading SizeTags from XML
7a956470 sago007 2016-02-14 17:09 912
  template <class T> inline
7a956470 sago007 2016-02-14 17:09 913
  void CEREAL_LOAD_FUNCTION_NAME( XMLInputArchive & ar, SizeTag<T> & st )
7a956470 sago007 2016-02-14 17:09 914
  {
7a956470 sago007 2016-02-14 17:09 915
    ar.loadSize( st.size );
7a956470 sago007 2016-02-14 17:09 916
  }
7a956470 sago007 2016-02-14 17:09 917
7a956470 sago007 2016-02-14 17:09 918
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 919
  //! Saving for POD types to xml
7a956470 sago007 2016-02-14 17:09 920
  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 921
  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, T const & t)
7a956470 sago007 2016-02-14 17:09 922
  {
7a956470 sago007 2016-02-14 17:09 923
    ar.saveValue( t );
7a956470 sago007 2016-02-14 17:09 924
  }
7a956470 sago007 2016-02-14 17:09 925
7a956470 sago007 2016-02-14 17:09 926
  //! Loading for POD types from xml
7a956470 sago007 2016-02-14 17:09 927
  template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
7a956470 sago007 2016-02-14 17:09 928
  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, T & t)
7a956470 sago007 2016-02-14 17:09 929
  {
7a956470 sago007 2016-02-14 17:09 930
    ar.loadValue( t );
7a956470 sago007 2016-02-14 17:09 931
  }
7a956470 sago007 2016-02-14 17:09 932
7a956470 sago007 2016-02-14 17:09 933
  // ######################################################################
7a956470 sago007 2016-02-14 17:09 934
  //! saving string to xml
7a956470 sago007 2016-02-14 17:09 935
  template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 936
  void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
7a956470 sago007 2016-02-14 17:09 937
  {
7a956470 sago007 2016-02-14 17:09 938
    ar.saveValue( str );
7a956470 sago007 2016-02-14 17:09 939
  }
7a956470 sago007 2016-02-14 17:09 940
7a956470 sago007 2016-02-14 17:09 941
  //! loading string from xml
7a956470 sago007 2016-02-14 17:09 942
  template<class CharT, class Traits, class Alloc> inline
7a956470 sago007 2016-02-14 17:09 943
  void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
7a956470 sago007 2016-02-14 17:09 944
  {
7a956470 sago007 2016-02-14 17:09 945
    ar.loadValue( str );
7a956470 sago007 2016-02-14 17:09 946
  }
7a956470 sago007 2016-02-14 17:09 947
} // namespace cereal
7a956470 sago007 2016-02-14 17:09 948
7a956470 sago007 2016-02-14 17:09 949
// register archives for polymorphic support
7a956470 sago007 2016-02-14 17:09 950
CEREAL_REGISTER_ARCHIVE(cereal::XMLOutputArchive)
7a956470 sago007 2016-02-14 17:09 951
CEREAL_REGISTER_ARCHIVE(cereal::XMLInputArchive)
7a956470 sago007 2016-02-14 17:09 952
7a956470 sago007 2016-02-14 17:09 953
// tie input and output archives together
7a956470 sago007 2016-02-14 17:09 954
CEREAL_SETUP_ARCHIVE_TRAITS(cereal::XMLInputArchive, cereal::XMLOutputArchive)
7a956470 sago007 2016-02-14 17:09 955
7a956470 sago007 2016-02-14 17:09 956
#endif // CEREAL_ARCHIVES_XML_HPP_
1970-01-01 00:00 957