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