isotree 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/LICENSE.txt +2 -2
  4. data/README.md +22 -1
  5. data/ext/isotree/ext.cpp +26 -0
  6. data/ext/isotree/extconf.rb +3 -3
  7. data/lib/isotree.rb +1 -0
  8. data/lib/isotree/isolation_forest.rb +86 -1
  9. data/lib/isotree/version.rb +1 -1
  10. data/vendor/cereal/LICENSE +24 -0
  11. data/vendor/cereal/README.md +85 -0
  12. data/vendor/cereal/include/cereal/access.hpp +351 -0
  13. data/vendor/cereal/include/cereal/archives/adapters.hpp +163 -0
  14. data/vendor/cereal/include/cereal/archives/binary.hpp +169 -0
  15. data/vendor/cereal/include/cereal/archives/json.hpp +1019 -0
  16. data/vendor/cereal/include/cereal/archives/portable_binary.hpp +334 -0
  17. data/vendor/cereal/include/cereal/archives/xml.hpp +956 -0
  18. data/vendor/cereal/include/cereal/cereal.hpp +1089 -0
  19. data/vendor/cereal/include/cereal/details/helpers.hpp +422 -0
  20. data/vendor/cereal/include/cereal/details/polymorphic_impl.hpp +796 -0
  21. data/vendor/cereal/include/cereal/details/polymorphic_impl_fwd.hpp +65 -0
  22. data/vendor/cereal/include/cereal/details/static_object.hpp +127 -0
  23. data/vendor/cereal/include/cereal/details/traits.hpp +1411 -0
  24. data/vendor/cereal/include/cereal/details/util.hpp +84 -0
  25. data/vendor/cereal/include/cereal/external/base64.hpp +134 -0
  26. data/vendor/cereal/include/cereal/external/rapidjson/allocators.h +284 -0
  27. data/vendor/cereal/include/cereal/external/rapidjson/cursorstreamwrapper.h +78 -0
  28. data/vendor/cereal/include/cereal/external/rapidjson/document.h +2652 -0
  29. data/vendor/cereal/include/cereal/external/rapidjson/encodedstream.h +299 -0
  30. data/vendor/cereal/include/cereal/external/rapidjson/encodings.h +716 -0
  31. data/vendor/cereal/include/cereal/external/rapidjson/error/en.h +74 -0
  32. data/vendor/cereal/include/cereal/external/rapidjson/error/error.h +161 -0
  33. data/vendor/cereal/include/cereal/external/rapidjson/filereadstream.h +99 -0
  34. data/vendor/cereal/include/cereal/external/rapidjson/filewritestream.h +104 -0
  35. data/vendor/cereal/include/cereal/external/rapidjson/fwd.h +151 -0
  36. data/vendor/cereal/include/cereal/external/rapidjson/internal/biginteger.h +290 -0
  37. data/vendor/cereal/include/cereal/external/rapidjson/internal/diyfp.h +271 -0
  38. data/vendor/cereal/include/cereal/external/rapidjson/internal/dtoa.h +245 -0
  39. data/vendor/cereal/include/cereal/external/rapidjson/internal/ieee754.h +78 -0
  40. data/vendor/cereal/include/cereal/external/rapidjson/internal/itoa.h +308 -0
  41. data/vendor/cereal/include/cereal/external/rapidjson/internal/meta.h +186 -0
  42. data/vendor/cereal/include/cereal/external/rapidjson/internal/pow10.h +55 -0
  43. data/vendor/cereal/include/cereal/external/rapidjson/internal/regex.h +740 -0
  44. data/vendor/cereal/include/cereal/external/rapidjson/internal/stack.h +232 -0
  45. data/vendor/cereal/include/cereal/external/rapidjson/internal/strfunc.h +69 -0
  46. data/vendor/cereal/include/cereal/external/rapidjson/internal/strtod.h +290 -0
  47. data/vendor/cereal/include/cereal/external/rapidjson/internal/swap.h +46 -0
  48. data/vendor/cereal/include/cereal/external/rapidjson/istreamwrapper.h +128 -0
  49. data/vendor/cereal/include/cereal/external/rapidjson/memorybuffer.h +70 -0
  50. data/vendor/cereal/include/cereal/external/rapidjson/memorystream.h +71 -0
  51. data/vendor/cereal/include/cereal/external/rapidjson/msinttypes/inttypes.h +316 -0
  52. data/vendor/cereal/include/cereal/external/rapidjson/msinttypes/stdint.h +300 -0
  53. data/vendor/cereal/include/cereal/external/rapidjson/ostreamwrapper.h +81 -0
  54. data/vendor/cereal/include/cereal/external/rapidjson/pointer.h +1414 -0
  55. data/vendor/cereal/include/cereal/external/rapidjson/prettywriter.h +277 -0
  56. data/vendor/cereal/include/cereal/external/rapidjson/rapidjson.h +656 -0
  57. data/vendor/cereal/include/cereal/external/rapidjson/reader.h +2230 -0
  58. data/vendor/cereal/include/cereal/external/rapidjson/schema.h +2497 -0
  59. data/vendor/cereal/include/cereal/external/rapidjson/stream.h +223 -0
  60. data/vendor/cereal/include/cereal/external/rapidjson/stringbuffer.h +121 -0
  61. data/vendor/cereal/include/cereal/external/rapidjson/writer.h +709 -0
  62. data/vendor/cereal/include/cereal/external/rapidxml/license.txt +52 -0
  63. data/vendor/cereal/include/cereal/external/rapidxml/manual.html +406 -0
  64. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml.hpp +2624 -0
  65. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_iterators.hpp +175 -0
  66. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_print.hpp +428 -0
  67. data/vendor/cereal/include/cereal/external/rapidxml/rapidxml_utils.hpp +123 -0
  68. data/vendor/cereal/include/cereal/macros.hpp +154 -0
  69. data/vendor/cereal/include/cereal/specialize.hpp +139 -0
  70. data/vendor/cereal/include/cereal/types/array.hpp +79 -0
  71. data/vendor/cereal/include/cereal/types/atomic.hpp +55 -0
  72. data/vendor/cereal/include/cereal/types/base_class.hpp +203 -0
  73. data/vendor/cereal/include/cereal/types/bitset.hpp +176 -0
  74. data/vendor/cereal/include/cereal/types/boost_variant.hpp +164 -0
  75. data/vendor/cereal/include/cereal/types/chrono.hpp +72 -0
  76. data/vendor/cereal/include/cereal/types/common.hpp +129 -0
  77. data/vendor/cereal/include/cereal/types/complex.hpp +56 -0
  78. data/vendor/cereal/include/cereal/types/concepts/pair_associative_container.hpp +73 -0
  79. data/vendor/cereal/include/cereal/types/deque.hpp +62 -0
  80. data/vendor/cereal/include/cereal/types/forward_list.hpp +68 -0
  81. data/vendor/cereal/include/cereal/types/functional.hpp +43 -0
  82. data/vendor/cereal/include/cereal/types/list.hpp +62 -0
  83. data/vendor/cereal/include/cereal/types/map.hpp +36 -0
  84. data/vendor/cereal/include/cereal/types/memory.hpp +425 -0
  85. data/vendor/cereal/include/cereal/types/optional.hpp +66 -0
  86. data/vendor/cereal/include/cereal/types/polymorphic.hpp +483 -0
  87. data/vendor/cereal/include/cereal/types/queue.hpp +132 -0
  88. data/vendor/cereal/include/cereal/types/set.hpp +103 -0
  89. data/vendor/cereal/include/cereal/types/stack.hpp +76 -0
  90. data/vendor/cereal/include/cereal/types/string.hpp +61 -0
  91. data/vendor/cereal/include/cereal/types/tuple.hpp +123 -0
  92. data/vendor/cereal/include/cereal/types/unordered_map.hpp +36 -0
  93. data/vendor/cereal/include/cereal/types/unordered_set.hpp +99 -0
  94. data/vendor/cereal/include/cereal/types/utility.hpp +47 -0
  95. data/vendor/cereal/include/cereal/types/valarray.hpp +89 -0
  96. data/vendor/cereal/include/cereal/types/variant.hpp +109 -0
  97. data/vendor/cereal/include/cereal/types/vector.hpp +112 -0
  98. data/vendor/cereal/include/cereal/version.hpp +52 -0
  99. data/vendor/isotree/LICENSE +1 -1
  100. data/vendor/isotree/README.md +2 -1
  101. data/vendor/isotree/src/RcppExports.cpp +44 -4
  102. data/vendor/isotree/src/Rwrapper.cpp +141 -51
  103. data/vendor/isotree/src/crit.cpp +1 -1
  104. data/vendor/isotree/src/dealloc.cpp +1 -1
  105. data/vendor/isotree/src/dist.cpp +6 -6
  106. data/vendor/isotree/src/extended.cpp +5 -5
  107. data/vendor/isotree/src/fit_model.cpp +30 -19
  108. data/vendor/isotree/src/helpers_iforest.cpp +26 -11
  109. data/vendor/isotree/src/impute.cpp +7 -7
  110. data/vendor/isotree/src/isoforest.cpp +7 -7
  111. data/vendor/isotree/src/isotree.hpp +27 -5
  112. data/vendor/isotree/src/merge_models.cpp +1 -1
  113. data/vendor/isotree/src/mult.cpp +1 -1
  114. data/vendor/isotree/src/predict.cpp +20 -16
  115. data/vendor/isotree/src/serialize.cpp +1 -1
  116. data/vendor/isotree/src/sql.cpp +545 -0
  117. data/vendor/isotree/src/utils.cpp +36 -44
  118. metadata +98 -92
@@ -0,0 +1,2624 @@
1
+ #ifndef CEREAL_RAPIDXML_HPP_INCLUDED
2
+ #define CEREAL_RAPIDXML_HPP_INCLUDED
3
+
4
+ // Copyright (C) 2006, 2009 Marcin Kalicinski
5
+ // Version 1.13
6
+ // Revision $DateTime: 2009/05/13 01:46:17 $
7
+
8
+ // If standard library is disabled, user must provide implementations of required functions and typedefs
9
+ #if !defined(CEREAL_RAPIDXML_NO_STDLIB)
10
+ #include <cstdlib> // For std::size_t
11
+ #include <cassert> // For assert
12
+ #include <new> // For placement new
13
+ #endif
14
+
15
+ // On MSVC, disable "conditional expression is constant" warning (level 4).
16
+ // This warning is almost impossible to avoid with certain types of templated code
17
+ #ifdef _MSC_VER
18
+ #pragma warning(push)
19
+ #pragma warning(disable:4127) // Conditional expression is constant
20
+ #pragma warning(disable:4100) // unreferenced formal parameter
21
+ #endif
22
+
23
+ ///////////////////////////////////////////////////////////////////////////
24
+ // CEREAL_RAPIDXML_PARSE_ERROR
25
+
26
+ #if defined(CEREAL_RAPIDXML_NO_EXCEPTIONS)
27
+
28
+ #define CEREAL_RAPIDXML_PARSE_ERROR(what, where) { parse_error_handler(what, where); assert(0); }
29
+
30
+ namespace cereal {
31
+ namespace rapidxml
32
+ {
33
+ //! When exceptions are disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS,
34
+ //! this function is called to notify user about the error.
35
+ //! It must be defined by the user.
36
+ //! <br><br>
37
+ //! This function cannot return. If it does, the results are undefined.
38
+ //! <br><br>
39
+ //! A very simple definition might look like that:
40
+ //! <pre>
41
+ //! void %rapidxml::%parse_error_handler(const char *what, void *where)
42
+ //! {
43
+ //! std::cout << "Parse error: " << what << "\n";
44
+ //! std::abort();
45
+ //! }
46
+ //! </pre>
47
+ //! \param what Human readable description of the error.
48
+ //! \param where Pointer to character data where error was detected.
49
+ void parse_error_handler(const char *what, void *where);
50
+ }
51
+ } // end namespace cereal
52
+
53
+ #else
54
+
55
+ #include <exception> // For std::exception
56
+
57
+ #define CEREAL_RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where)
58
+
59
+ namespace cereal {
60
+ namespace rapidxml
61
+ {
62
+
63
+ //! Parse error exception.
64
+ //! This exception is thrown by the parser when an error occurs.
65
+ //! Use what() function to get human-readable error message.
66
+ //! Use where() function to get a pointer to position within source text where error was detected.
67
+ //! <br><br>
68
+ //! If throwing exceptions by the parser is undesirable,
69
+ //! it can be disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included.
70
+ //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception.
71
+ //! This function must be defined by the user.
72
+ //! <br><br>
73
+ //! This class derives from <code>std::exception</code> class.
74
+ class parse_error: public std::exception
75
+ {
76
+
77
+ public:
78
+
79
+ //! Constructs parse error
80
+ parse_error(const char *what_, void *where_)
81
+ : m_what(what_)
82
+ , m_where(where_)
83
+ {
84
+ }
85
+
86
+ //! Gets human readable description of error.
87
+ //! \return Pointer to null terminated description of the error.
88
+ virtual const char *what() const CEREAL_NOEXCEPT override
89
+ {
90
+ return m_what;
91
+ }
92
+
93
+ //! Gets pointer to character data where error happened.
94
+ //! Ch should be the same as char type of xml_document that produced the error.
95
+ //! \return Pointer to location within the parsed string where error occured.
96
+ template<class Ch>
97
+ Ch *where() const
98
+ {
99
+ return reinterpret_cast<Ch *>(m_where);
100
+ }
101
+
102
+ private:
103
+
104
+ const char *m_what;
105
+ void *m_where;
106
+
107
+ };
108
+ }
109
+ } // end namespace cereal
110
+
111
+ #endif
112
+
113
+ ///////////////////////////////////////////////////////////////////////////
114
+ // Pool sizes
115
+
116
+ #ifndef CEREAL_RAPIDXML_STATIC_POOL_SIZE
117
+ // Size of static memory block of memory_pool.
118
+ // Define CEREAL_RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
119
+ // No dynamic memory allocations are performed by memory_pool until static memory is exhausted.
120
+ #define CEREAL_RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
121
+ #endif
122
+
123
+ #ifndef CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE
124
+ // Size of dynamic memory block of memory_pool.
125
+ // Define CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
126
+ // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool.
127
+ #define CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
128
+ #endif
129
+
130
+ #ifndef CEREAL_RAPIDXML_ALIGNMENT
131
+ // Memory allocation alignment.
132
+ // Define CEREAL_RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer.
133
+ // All memory allocations for nodes, attributes and strings will be aligned to this value.
134
+ // This must be a power of 2 and at least 1, otherwise memory_pool will not work.
135
+ #define CEREAL_RAPIDXML_ALIGNMENT sizeof(void *)
136
+ #endif
137
+
138
+ namespace cereal {
139
+ namespace rapidxml
140
+ {
141
+ // Forward declarations
142
+ template<class Ch> class xml_node;
143
+ template<class Ch> class xml_attribute;
144
+ template<class Ch> class xml_document;
145
+
146
+ //! Enumeration listing all node types produced by the parser.
147
+ //! Use xml_node::type() function to query node type.
148
+ enum node_type
149
+ {
150
+ node_document, //!< A document node. Name and value are empty.
151
+ node_element, //!< An element node. Name contains element name. Value contains text of first data node.
152
+ node_data, //!< A data node. Name is empty. Value contains data text.
153
+ node_cdata, //!< A CDATA node. Name is empty. Value contains data text.
154
+ node_comment, //!< A comment node. Name is empty. Value contains comment text.
155
+ node_declaration, //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
156
+ node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
157
+ node_pi //!< A PI node. Name contains target. Value contains instructions.
158
+ };
159
+
160
+ ///////////////////////////////////////////////////////////////////////
161
+ // Parsing flags
162
+
163
+ //! Parse flag instructing the parser to not create data nodes.
164
+ //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified.
165
+ //! Can be combined with other flags by use of | operator.
166
+ //! <br><br>
167
+ //! See xml_document::parse() function.
168
+ const int parse_no_data_nodes = 0x1;
169
+
170
+ //! Parse flag instructing the parser to not use text of first data node as a value of parent element.
171
+ //! Can be combined with other flags by use of | operator.
172
+ //! Note that child data nodes of element node take precendence over its value when printing.
173
+ //! That is, if element has one or more child data nodes <em>and</em> a value, the value will be ignored.
174
+ //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.
175
+ //! <br><br>
176
+ //! See xml_document::parse() function.
177
+ const int parse_no_element_values = 0x2;
178
+
179
+ //! Parse flag instructing the parser to not place zero terminators after strings in the source text.
180
+ //! By default zero terminators are placed, modifying source text.
181
+ //! Can be combined with other flags by use of | operator.
182
+ //! <br><br>
183
+ //! See xml_document::parse() function.
184
+ const int parse_no_string_terminators = 0x4;
185
+
186
+ //! Parse flag instructing the parser to not translate entities in the source text.
187
+ //! By default entities are translated, modifying source text.
188
+ //! Can be combined with other flags by use of | operator.
189
+ //! <br><br>
190
+ //! See xml_document::parse() function.
191
+ const int parse_no_entity_translation = 0x8;
192
+
193
+ //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters.
194
+ //! By default, UTF-8 handling is enabled.
195
+ //! Can be combined with other flags by use of | operator.
196
+ //! <br><br>
197
+ //! See xml_document::parse() function.
198
+ const int parse_no_utf8 = 0x10;
199
+
200
+ //! Parse flag instructing the parser to create XML declaration node.
201
+ //! By default, declaration node is not created.
202
+ //! Can be combined with other flags by use of | operator.
203
+ //! <br><br>
204
+ //! See xml_document::parse() function.
205
+ const int parse_declaration_node = 0x20;
206
+
207
+ //! Parse flag instructing the parser to create comments nodes.
208
+ //! By default, comment nodes are not created.
209
+ //! Can be combined with other flags by use of | operator.
210
+ //! <br><br>
211
+ //! See xml_document::parse() function.
212
+ const int parse_comment_nodes = 0x40;
213
+
214
+ //! Parse flag instructing the parser to create DOCTYPE node.
215
+ //! By default, doctype node is not created.
216
+ //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one.
217
+ //! Can be combined with other flags by use of | operator.
218
+ //! <br><br>
219
+ //! See xml_document::parse() function.
220
+ const int parse_doctype_node = 0x80;
221
+
222
+ //! Parse flag instructing the parser to create PI nodes.
223
+ //! By default, PI nodes are not created.
224
+ //! Can be combined with other flags by use of | operator.
225
+ //! <br><br>
226
+ //! See xml_document::parse() function.
227
+ const int parse_pi_nodes = 0x100;
228
+
229
+ //! Parse flag instructing the parser to validate closing tag names.
230
+ //! If not set, name inside closing tag is irrelevant to the parser.
231
+ //! By default, closing tags are not validated.
232
+ //! Can be combined with other flags by use of | operator.
233
+ //! <br><br>
234
+ //! See xml_document::parse() function.
235
+ const int parse_validate_closing_tags = 0x200;
236
+
237
+ //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes.
238
+ //! By default, whitespace is not trimmed.
239
+ //! This flag does not cause the parser to modify source text.
240
+ //! Can be combined with other flags by use of | operator.
241
+ //! <br><br>
242
+ //! See xml_document::parse() function.
243
+ const int parse_trim_whitespace = 0x400;
244
+
245
+ //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character.
246
+ //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag.
247
+ //! By default, whitespace is not normalized.
248
+ //! If this flag is specified, source text will be modified.
249
+ //! Can be combined with other flags by use of | operator.
250
+ //! <br><br>
251
+ //! See xml_document::parse() function.
252
+ const int parse_normalize_whitespace = 0x800;
253
+
254
+ // Compound flags
255
+
256
+ //! Parse flags which represent default behaviour of the parser.
257
+ //! This is always equal to 0, so that all other flags can be simply ored together.
258
+ //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values.
259
+ //! This also means that meaning of each flag is a <i>negation</i> of the default setting.
260
+ //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by default,
261
+ //! and using the flag will disable it.
262
+ //! <br><br>
263
+ //! See xml_document::parse() function.
264
+ const int parse_default = 0;
265
+
266
+ //! A combination of parse flags that forbids any modifications of the source text.
267
+ //! This also results in faster parsing. However, note that the following will occur:
268
+ //! <ul>
269
+ //! <li>names and values of nodes will not be zero terminated, you have to use xml_base::name_size() and xml_base::value_size() functions to determine where name and value ends</li>
270
+ //! <li>entities will not be translated</li>
271
+ //! <li>whitespace will not be normalized</li>
272
+ //! </ul>
273
+ //! See xml_document::parse() function.
274
+ const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation;
275
+
276
+ //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.
277
+ //! <br><br>
278
+ //! See xml_document::parse() function.
279
+ const int parse_fastest = parse_non_destructive | parse_no_data_nodes;
280
+
281
+ //! A combination of parse flags resulting in largest amount of data being extracted.
282
+ //! This usually results in slowest parsing.
283
+ //! <br><br>
284
+ //! See xml_document::parse() function.
285
+ const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags;
286
+
287
+ ///////////////////////////////////////////////////////////////////////
288
+ // Internals
289
+
290
+ //! \cond internal
291
+ namespace internal
292
+ {
293
+
294
+ // Struct that contains lookup tables for the parser
295
+ // It must be a template to allow correct linking (because it has static data members, which are defined in a header file).
296
+ template<int Dummy>
297
+ struct lookup_tables
298
+ {
299
+ static const unsigned char lookup_whitespace[256]; // Whitespace table
300
+ static const unsigned char lookup_node_name[256]; // Node name table
301
+ static const unsigned char lookup_text[256]; // Text table
302
+ static const unsigned char lookup_text_pure_no_ws[256]; // Text table
303
+ static const unsigned char lookup_text_pure_with_ws[256]; // Text table
304
+ static const unsigned char lookup_attribute_name[256]; // Attribute name table
305
+ static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote
306
+ static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote
307
+ static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes
308
+ static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes
309
+ static const unsigned char lookup_digits[256]; // Digits
310
+ static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters
311
+ };
312
+
313
+ // Find length of the string
314
+ template<class Ch>
315
+ inline std::size_t measure(const Ch *p)
316
+ {
317
+ const Ch *tmp = p;
318
+ while (*tmp)
319
+ ++tmp;
320
+ return static_cast<std::size_t>(tmp - p);
321
+ }
322
+
323
+ // Compare strings for equality
324
+ template<class Ch>
325
+ inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive)
326
+ {
327
+ if (size1 != size2)
328
+ return false;
329
+ if (case_sensitive)
330
+ {
331
+ for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
332
+ if (*p1 != *p2)
333
+ return false;
334
+ }
335
+ else
336
+ {
337
+ for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
338
+ if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] != lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)])
339
+ return false;
340
+ }
341
+ return true;
342
+ }
343
+
344
+ template<class Ch>
345
+ inline bool preserve_space(xml_node<Ch>* node)
346
+ {
347
+ const Ch preserve_value[] = { Ch('p'), Ch('r'), Ch('e'), Ch('s'), Ch('e'), Ch('r'), Ch('v'), Ch('e') };
348
+ const xml_attribute<Ch>* space = node->first_attribute("xml:space");
349
+ return space && internal::compare(space->value(), space->value_size(), preserve_value, sizeof(preserve_value) / sizeof(Ch), true);
350
+ }
351
+ }
352
+ //! \endcond
353
+
354
+ ///////////////////////////////////////////////////////////////////////
355
+ // Memory pool
356
+
357
+ //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation.
358
+ //! In most cases, you will not need to use this class directly.
359
+ //! However, if you need to create nodes manually or modify names/values of nodes,
360
+ //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory.
361
+ //! Not only is this faster than allocating them by using <code>new</code> operator,
362
+ //! but also their lifetime will be tied to the lifetime of document,
363
+ //! possibly simplyfing memory management.
364
+ //! <br><br>
365
+ //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool.
366
+ //! You can also call allocate_string() function to allocate strings.
367
+ //! Such strings can then be used as names or values of nodes without worrying about their lifetime.
368
+ //! Note that there is no <code>free()</code> function -- all allocations are freed at once when clear() function is called,
369
+ //! or when the pool is destroyed.
370
+ //! <br><br>
371
+ //! It is also possible to create a standalone memory_pool, and use it
372
+ //! to allocate nodes, whose lifetime will not be tied to any document.
373
+ //! <br><br>
374
+ //! Pool maintains <code>CEREAL_RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory.
375
+ //! Until static memory is exhausted, no dynamic memory allocations are done.
376
+ //! When static memory is exhausted, pool allocates additional blocks of memory of size <code>CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE</code> each,
377
+ //! by using global <code>new[]</code> and <code>delete[]</code> operators.
378
+ //! This behaviour can be changed by setting custom allocation routines.
379
+ //! Use set_allocator() function to set them.
380
+ //! <br><br>
381
+ //! Allocations for nodes, attributes and strings are aligned at <code>CEREAL_RAPIDXML_ALIGNMENT</code> bytes.
382
+ //! This value defaults to the size of pointer on target architecture.
383
+ //! <br><br>
384
+ //! To obtain absolutely top performance from the parser,
385
+ //! it is important that all nodes are allocated from a single, contiguous block of memory.
386
+ //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably.
387
+ //! If required, you can tweak <code>CEREAL_RAPIDXML_STATIC_POOL_SIZE</code>, <code>CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>CEREAL_RAPIDXML_ALIGNMENT</code>
388
+ //! to obtain best wasted memory to performance compromise.
389
+ //! To do it, define their values before rapidxml.hpp file is included.
390
+ //! \tparam Ch Character type of created nodes.
391
+ template<class Ch = char>
392
+ class memory_pool
393
+ {
394
+
395
+ public:
396
+
397
+ //! \cond internal
398
+ typedef void *(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory
399
+ typedef void (free_func)(void *); // Type of user-defined function used to free memory
400
+ //! \endcond
401
+
402
+ //! Constructs empty pool with default allocator functions.
403
+ memory_pool()
404
+ : m_alloc_func(0)
405
+ , m_free_func(0)
406
+ {
407
+ init();
408
+ }
409
+
410
+ //! Destroys pool and frees all the memory.
411
+ //! This causes memory occupied by nodes allocated by the pool to be freed.
412
+ //! Nodes allocated from the pool are no longer valid.
413
+ ~memory_pool()
414
+ {
415
+ clear();
416
+ }
417
+
418
+ //! Allocates a new node from the pool, and optionally assigns name and value to it.
419
+ //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
420
+ //! If exceptions are disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS, this function
421
+ //! will call rapidxml::parse_error_handler() function.
422
+ //! \param type Type of node to create.
423
+ //! \param name Name to assign to the node, or 0 to assign no name.
424
+ //! \param value Value to assign to the node, or 0 to assign no value.
425
+ //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
426
+ //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
427
+ //! \return Pointer to allocated node. This pointer will never be NULL.
428
+ xml_node<Ch> *allocate_node(node_type type,
429
+ const Ch *name = 0, const Ch *value = 0,
430
+ std::size_t name_size = 0, std::size_t value_size = 0)
431
+ {
432
+ void *memory = allocate_aligned(sizeof(xml_node<Ch>));
433
+ xml_node<Ch> *node = new(memory) xml_node<Ch>(type);
434
+ if (name)
435
+ {
436
+ if (name_size > 0)
437
+ node->name(name, name_size);
438
+ else
439
+ node->name(name);
440
+ }
441
+ if (value)
442
+ {
443
+ if (value_size > 0)
444
+ node->value(value, value_size);
445
+ else
446
+ node->value(value);
447
+ }
448
+ return node;
449
+ }
450
+
451
+ //! Allocates a new attribute from the pool, and optionally assigns name and value to it.
452
+ //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
453
+ //! If exceptions are disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS, this function
454
+ //! will call rapidxml::parse_error_handler() function.
455
+ //! \param name Name to assign to the attribute, or 0 to assign no name.
456
+ //! \param value Value to assign to the attribute, or 0 to assign no value.
457
+ //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
458
+ //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
459
+ //! \return Pointer to allocated attribute. This pointer will never be NULL.
460
+ xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0,
461
+ std::size_t name_size = 0, std::size_t value_size = 0)
462
+ {
463
+ void *memory = allocate_aligned(sizeof(xml_attribute<Ch>));
464
+ xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>;
465
+ if (name)
466
+ {
467
+ if (name_size > 0)
468
+ attribute->name(name, name_size);
469
+ else
470
+ attribute->name(name);
471
+ }
472
+ if (value)
473
+ {
474
+ if (value_size > 0)
475
+ attribute->value(value, value_size);
476
+ else
477
+ attribute->value(value);
478
+ }
479
+ return attribute;
480
+ }
481
+
482
+ //! Allocates a char array of given size from the pool, and optionally copies a given string to it.
483
+ //! If the allocation request cannot be accomodated, this function will throw <code>std::bad_alloc</code>.
484
+ //! If exceptions are disabled by defining CEREAL_RAPIDXML_NO_EXCEPTIONS, this function
485
+ //! will call rapidxml::parse_error_handler() function.
486
+ //! \param source String to initialize the allocated memory with, or 0 to not initialize it.
487
+ //! \param size Number of characters to allocate, or zero to calculate it automatically from source string length; if size is 0, source string must be specified and null terminated.
488
+ //! \return Pointer to allocated char array. This pointer will never be NULL.
489
+ Ch *allocate_string(const Ch *source = 0, std::size_t size = 0)
490
+ {
491
+ assert(source || size); // Either source or size (or both) must be specified
492
+ if (size == 0)
493
+ size = internal::measure(source) + 1;
494
+ Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch)));
495
+ if (source)
496
+ for (std::size_t i = 0; i < size; ++i)
497
+ result[i] = source[i];
498
+ return result;
499
+ }
500
+
501
+ //! Clones an xml_node and its hierarchy of child nodes and attributes.
502
+ //! Nodes and attributes are allocated from this memory pool.
503
+ //! Names and values are not cloned, they are shared between the clone and the source.
504
+ //! Result node can be optionally specified as a second parameter,
505
+ //! in which case its contents will be replaced with cloned source node.
506
+ //! This is useful when you want to clone entire document.
507
+ //! \param source Node to clone.
508
+ //! \param result Node to put results in, or 0 to automatically allocate result node
509
+ //! \return Pointer to cloned node. This pointer will never be NULL.
510
+ xml_node<Ch> *clone_node(const xml_node<Ch> *source, xml_node<Ch> *result = 0)
511
+ {
512
+ // Prepare result node
513
+ if (result)
514
+ {
515
+ result->remove_all_attributes();
516
+ result->remove_all_nodes();
517
+ result->type(source->type());
518
+ }
519
+ else
520
+ result = allocate_node(source->type());
521
+
522
+ // Clone name and value
523
+ result->name(source->name(), source->name_size());
524
+ result->value(source->value(), source->value_size());
525
+
526
+ // Clone child nodes and attributes
527
+ for (xml_node<Ch> *child = source->first_node(); child; child = child->next_sibling())
528
+ result->append_node(clone_node(child));
529
+ for (xml_attribute<Ch> *attr = source->first_attribute(); attr; attr = attr->next_attribute())
530
+ result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size()));
531
+
532
+ return result;
533
+ }
534
+
535
+ //! Clears the pool.
536
+ //! This causes memory occupied by nodes allocated by the pool to be freed.
537
+ //! Any nodes or strings allocated from the pool will no longer be valid.
538
+ void clear()
539
+ {
540
+ while (m_begin != m_static_memory)
541
+ {
542
+ char *previous_begin = reinterpret_cast<header *>(align(m_begin))->previous_begin;
543
+ if (m_free_func)
544
+ m_free_func(m_begin);
545
+ else
546
+ delete[] m_begin;
547
+ m_begin = previous_begin;
548
+ }
549
+ init();
550
+ }
551
+
552
+ //! Sets or resets the user-defined memory allocation functions for the pool.
553
+ //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined.
554
+ //! Allocation function must not return invalid pointer on failure. It should either throw,
555
+ //! stop the program, or use <code>longjmp()</code> function to pass control to other place of program.
556
+ //! If it returns invalid pointer, results are undefined.
557
+ //! <br><br>
558
+ //! User defined allocation functions must have the following forms:
559
+ //! <br><code>
560
+ //! <br>void *allocate(std::size_t size);
561
+ //! <br>void free(void *pointer);
562
+ //! </code><br>
563
+ //! \param af Allocation function, or 0 to restore default function
564
+ //! \param ff Free function, or 0 to restore default function
565
+ void set_allocator(alloc_func *af, free_func *ff)
566
+ {
567
+ assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet
568
+ m_alloc_func = af;
569
+ m_free_func = ff;
570
+ }
571
+
572
+ private:
573
+
574
+ struct header
575
+ {
576
+ char *previous_begin;
577
+ };
578
+
579
+ void init()
580
+ {
581
+ m_begin = m_static_memory;
582
+ m_ptr = align(m_begin);
583
+ m_end = m_static_memory + sizeof(m_static_memory);
584
+ }
585
+
586
+ char *align(char *ptr)
587
+ {
588
+ std::size_t alignment = ((CEREAL_RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (CEREAL_RAPIDXML_ALIGNMENT - 1))) & (CEREAL_RAPIDXML_ALIGNMENT - 1));
589
+ return ptr + alignment;
590
+ }
591
+
592
+ char *allocate_raw(std::size_t size)
593
+ {
594
+ // Allocate
595
+ void *memory;
596
+ if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator new[]
597
+ {
598
+ memory = m_alloc_func(size);
599
+ assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp
600
+ }
601
+ else
602
+ {
603
+ memory = new char[size];
604
+ #ifdef CEREAL_RAPIDXML_NO_EXCEPTIONS
605
+ if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to throw bad_alloc
606
+ CEREAL_RAPIDXML_PARSE_ERROR("out of memory", 0);
607
+ #endif
608
+ }
609
+ return static_cast<char *>(memory);
610
+ }
611
+
612
+ void *allocate_aligned(std::size_t size)
613
+ {
614
+ // Calculate aligned pointer
615
+ char *result = align(m_ptr);
616
+
617
+ // If not enough memory left in current pool, allocate a new pool
618
+ if (result + size > m_end)
619
+ {
620
+ // Calculate required pool size (may be bigger than CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE)
621
+ std::size_t pool_size = CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE;
622
+ if (pool_size < size)
623
+ pool_size = size;
624
+
625
+ // Allocate
626
+ std::size_t alloc_size = sizeof(header) + (2 * CEREAL_RAPIDXML_ALIGNMENT - 2) + pool_size; // 2 alignments required in worst case: one for header, one for actual allocation
627
+ char *raw_memory = allocate_raw(alloc_size);
628
+
629
+ // Setup new pool in allocated memory
630
+ char *pool = align(raw_memory);
631
+ header *new_header = reinterpret_cast<header *>(pool);
632
+ new_header->previous_begin = m_begin;
633
+ m_begin = raw_memory;
634
+ m_ptr = pool + sizeof(header);
635
+ m_end = raw_memory + alloc_size;
636
+
637
+ // Calculate aligned pointer again using new pool
638
+ result = align(m_ptr);
639
+ }
640
+
641
+ // Update pool and return aligned pointer
642
+ m_ptr = result + size;
643
+ return result;
644
+ }
645
+
646
+ char *m_begin; // Start of raw memory making up current pool
647
+ char *m_ptr; // First free byte in current pool
648
+ char *m_end; // One past last available byte in current pool
649
+ char m_static_memory[CEREAL_RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory
650
+ alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used
651
+ free_func *m_free_func; // Free function, or 0 if default is to be used
652
+ };
653
+
654
+ ///////////////////////////////////////////////////////////////////////////
655
+ // XML base
656
+
657
+ //! Base class for xml_node and xml_attribute implementing common functions:
658
+ //! name(), name_size(), value(), value_size() and parent().
659
+ //! \tparam Ch Character type to use
660
+ template<class Ch = char>
661
+ class xml_base
662
+ {
663
+
664
+ public:
665
+
666
+ ///////////////////////////////////////////////////////////////////////////
667
+ // Construction & destruction
668
+
669
+ // Construct a base with empty name, value and parent
670
+ xml_base()
671
+ : m_name(0)
672
+ , m_value(0)
673
+ , m_parent(0)
674
+ {
675
+ }
676
+
677
+ ///////////////////////////////////////////////////////////////////////////
678
+ // Node data access
679
+
680
+ //! Gets name of the node.
681
+ //! Interpretation of name depends on type of node.
682
+ //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
683
+ //! <br><br>
684
+ //! Use name_size() function to determine length of the name.
685
+ //! \return Name of node, or empty string if node has no name.
686
+ Ch *name() const
687
+ {
688
+ return m_name ? m_name : nullstr();
689
+ }
690
+
691
+ //! Gets size of node name, not including terminator character.
692
+ //! This function works correctly irrespective of whether name is or is not zero terminated.
693
+ //! \return Size of node name, in characters.
694
+ std::size_t name_size() const
695
+ {
696
+ return m_name ? m_name_size : 0;
697
+ }
698
+
699
+ //! Gets value of node.
700
+ //! Interpretation of value depends on type of node.
701
+ //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
702
+ //! <br><br>
703
+ //! Use value_size() function to determine length of the value.
704
+ //! \return Value of node, or empty string if node has no value.
705
+ Ch *value() const
706
+ {
707
+ return m_value ? m_value : nullstr();
708
+ }
709
+
710
+ //! Gets size of node value, not including terminator character.
711
+ //! This function works correctly irrespective of whether value is or is not zero terminated.
712
+ //! \return Size of node value, in characters.
713
+ std::size_t value_size() const
714
+ {
715
+ return m_value ? m_value_size : 0;
716
+ }
717
+
718
+ ///////////////////////////////////////////////////////////////////////////
719
+ // Node modification
720
+
721
+ //! Sets name of node to a non zero-terminated string.
722
+ //! See \ref ownership_of_strings.
723
+ //! <br><br>
724
+ //! Note that node does not own its name or value, it only stores a pointer to it.
725
+ //! It will not delete or otherwise free the pointer on destruction.
726
+ //! It is reponsibility of the user to properly manage lifetime of the string.
727
+ //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
728
+ //! on destruction of the document the string will be automatically freed.
729
+ //! <br><br>
730
+ //! Size of name must be specified separately, because name does not have to be zero terminated.
731
+ //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).
732
+ //! \param name_ Name of node to set. Does not have to be zero terminated.
733
+ //! \param size Size of name, in characters. This does not include zero terminator, if one is present.
734
+ void name(const Ch *name_, std::size_t size)
735
+ {
736
+ m_name = const_cast<Ch *>(name_);
737
+ m_name_size = size;
738
+ }
739
+
740
+ //! Sets name of node to a zero-terminated string.
741
+ //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t).
742
+ //! \param name_ Name of node to set. Must be zero terminated.
743
+ void name(const Ch *name_)
744
+ {
745
+ this->name(name_, internal::measure(name_));
746
+ }
747
+
748
+ //! Sets value of node to a non zero-terminated string.
749
+ //! See \ref ownership_of_strings.
750
+ //! <br><br>
751
+ //! Note that node does not own its name or value, it only stores a pointer to it.
752
+ //! It will not delete or otherwise free the pointer on destruction.
753
+ //! It is reponsibility of the user to properly manage lifetime of the string.
754
+ //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
755
+ //! on destruction of the document the string will be automatically freed.
756
+ //! <br><br>
757
+ //! Size of value must be specified separately, because it does not have to be zero terminated.
758
+ //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).
759
+ //! <br><br>
760
+ //! If an element has a child node of type node_data, it will take precedence over element value when printing.
761
+ //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.
762
+ //! \param value_ value of node to set. Does not have to be zero terminated.
763
+ //! \param size Size of value, in characters. This does not include zero terminator, if one is present.
764
+ void value(const Ch *value_, std::size_t size)
765
+ {
766
+ m_value = const_cast<Ch *>(value_);
767
+ m_value_size = size;
768
+ }
769
+
770
+ //! Sets value of node to a zero-terminated string.
771
+ //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t).
772
+ //! \param value_ Vame of node to set. Must be zero terminated.
773
+ void value(const Ch *value_)
774
+ {
775
+ this->value(value_, internal::measure(value_));
776
+ }
777
+
778
+ ///////////////////////////////////////////////////////////////////////////
779
+ // Related nodes access
780
+
781
+ //! Gets node parent.
782
+ //! \return Pointer to parent node, or 0 if there is no parent.
783
+ xml_node<Ch> *parent() const
784
+ {
785
+ return m_parent;
786
+ }
787
+
788
+ protected:
789
+
790
+ // Return empty string
791
+ static Ch *nullstr()
792
+ {
793
+ static Ch zero = Ch('\0');
794
+ return &zero;
795
+ }
796
+
797
+ Ch *m_name; // Name of node, or 0 if no name
798
+ Ch *m_value; // Value of node, or 0 if no value
799
+ std::size_t m_name_size; // Length of node name, or undefined of no name
800
+ std::size_t m_value_size; // Length of node value, or undefined if no value
801
+ xml_node<Ch> *m_parent; // Pointer to parent node, or 0 if none
802
+
803
+ };
804
+
805
+ //! Class representing attribute node of XML document.
806
+ //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base).
807
+ //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing.
808
+ //! Thus, this text must persist in memory for the lifetime of attribute.
809
+ //! \tparam Ch Character type to use.
810
+ template<class Ch = char>
811
+ class xml_attribute: public xml_base<Ch>
812
+ {
813
+
814
+ friend class xml_node<Ch>;
815
+
816
+ public:
817
+
818
+ ///////////////////////////////////////////////////////////////////////////
819
+ // Construction & destruction
820
+
821
+ //! Constructs an empty attribute with the specified type.
822
+ //! Consider using memory_pool of appropriate xml_document if allocating attributes manually.
823
+ xml_attribute()
824
+ {
825
+ }
826
+
827
+ ///////////////////////////////////////////////////////////////////////////
828
+ // Related nodes access
829
+
830
+ //! Gets document of which attribute is a child.
831
+ //! \return Pointer to document that contains this attribute, or 0 if there is no parent document.
832
+ xml_document<Ch> *document() const
833
+ {
834
+ if (xml_node<Ch> *node = this->parent())
835
+ {
836
+ while (node->parent())
837
+ node = node->parent();
838
+ return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
839
+ }
840
+ else
841
+ return 0;
842
+ }
843
+
844
+ //! Gets previous attribute, optionally matching attribute name.
845
+ //! \param name Name of attribute to find, or 0 to return previous attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
846
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
847
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
848
+ //! \return Pointer to found attribute, or 0 if not found.
849
+ xml_attribute<Ch> *previous_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
850
+ {
851
+ if (name)
852
+ {
853
+ if (name_size == 0)
854
+ name_size = internal::measure(name);
855
+ for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute)
856
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
857
+ return attribute;
858
+ return 0;
859
+ }
860
+ else
861
+ return this->m_parent ? m_prev_attribute : 0;
862
+ }
863
+
864
+ //! Gets next attribute, optionally matching attribute name.
865
+ //! \param name_ Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
866
+ //! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
867
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
868
+ //! \return Pointer to found attribute, or 0 if not found.
869
+ xml_attribute<Ch> *next_attribute(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
870
+ {
871
+ if (name_)
872
+ {
873
+ if (name_size_ == 0)
874
+ name_size_ = internal::measure(name_);
875
+ for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute)
876
+ if (internal::compare(attribute->name(), attribute->name_size(), name_, name_size_, case_sensitive))
877
+ return attribute;
878
+ return 0;
879
+ }
880
+ else
881
+ return this->m_parent ? m_next_attribute : 0;
882
+ }
883
+
884
+ private:
885
+
886
+ xml_attribute<Ch> *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero
887
+ xml_attribute<Ch> *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero
888
+
889
+ };
890
+
891
+ ///////////////////////////////////////////////////////////////////////////
892
+ // XML node
893
+
894
+ //! Class representing a node of XML document.
895
+ //! Each node may have associated name and value strings, which are available through name() and value() functions.
896
+ //! Interpretation of name and value depends on type of the node.
897
+ //! Type of node can be determined by using type() function.
898
+ //! <br><br>
899
+ //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing.
900
+ //! Thus, this text must persist in the memory for the lifetime of node.
901
+ //! \tparam Ch Character type to use.
902
+ template<class Ch = char>
903
+ class xml_node: public xml_base<Ch>
904
+ {
905
+
906
+ public:
907
+
908
+ ///////////////////////////////////////////////////////////////////////////
909
+ // Construction & destruction
910
+
911
+ //! Constructs an empty node with the specified type.
912
+ //! Consider using memory_pool of appropriate document to allocate nodes manually.
913
+ //! \param type_ Type of node to construct.
914
+ xml_node(node_type type_)
915
+ : m_type(type_)
916
+ , m_first_node(0)
917
+ , m_first_attribute(0)
918
+ {
919
+ }
920
+
921
+ ///////////////////////////////////////////////////////////////////////////
922
+ // Node data access
923
+
924
+ //! Gets type of node.
925
+ //! \return Type of node.
926
+ node_type type() const
927
+ {
928
+ return m_type;
929
+ }
930
+
931
+ ///////////////////////////////////////////////////////////////////////////
932
+ // Related nodes access
933
+
934
+ //! Gets document of which node is a child.
935
+ //! \return Pointer to document that contains this node, or 0 if there is no parent document.
936
+ xml_document<Ch> *document() const
937
+ {
938
+ xml_node<Ch> *node = const_cast<xml_node<Ch> *>(this);
939
+ while (node->parent())
940
+ node = node->parent();
941
+ return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
942
+ }
943
+
944
+ //! Gets first child node, optionally matching node name.
945
+ //! \param name_ Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
946
+ //! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
947
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
948
+ //! \return Pointer to found child, or 0 if not found.
949
+ xml_node<Ch> *first_node(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
950
+ {
951
+ if (name_)
952
+ {
953
+ if (name_size_ == 0)
954
+ name_size_ = internal::measure(name_);
955
+ for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling())
956
+ if (internal::compare(child->name(), child->name_size(), name_, name_size_, case_sensitive))
957
+ return child;
958
+ return 0;
959
+ }
960
+ else
961
+ return m_first_node;
962
+ }
963
+
964
+ //! Gets last child node, optionally matching node name.
965
+ //! Behaviour is undefined if node has no children.
966
+ //! Use first_node() to test if node has children.
967
+ //! \param name Name of child to find, or 0 to return last child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
968
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
969
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
970
+ //! \return Pointer to found child, or 0 if not found.
971
+ xml_node<Ch> *last_node(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
972
+ {
973
+ assert(m_first_node); // Cannot query for last child if node has no children
974
+ if (name)
975
+ {
976
+ if (name_size == 0)
977
+ name_size = internal::measure(name);
978
+ for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling())
979
+ if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
980
+ return child;
981
+ return 0;
982
+ }
983
+ else
984
+ return m_last_node;
985
+ }
986
+
987
+ //! Gets previous sibling node, optionally matching node name.
988
+ //! Behaviour is undefined if node has no parent.
989
+ //! Use parent() to test if node has a parent.
990
+ //! \param name Name of sibling to find, or 0 to return previous sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
991
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
992
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
993
+ //! \return Pointer to found sibling, or 0 if not found.
994
+ xml_node<Ch> *previous_sibling(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
995
+ {
996
+ assert(this->m_parent); // Cannot query for siblings if node has no parent
997
+ if (name)
998
+ {
999
+ if (name_size == 0)
1000
+ name_size = internal::measure(name);
1001
+ for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling)
1002
+ if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
1003
+ return sibling;
1004
+ return 0;
1005
+ }
1006
+ else
1007
+ return m_prev_sibling;
1008
+ }
1009
+
1010
+ //! Gets next sibling node, optionally matching node name.
1011
+ //! Behaviour is undefined if node has no parent.
1012
+ //! Use parent() to test if node has a parent.
1013
+ //! \param name_ Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
1014
+ //! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
1015
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
1016
+ //! \return Pointer to found sibling, or 0 if not found.
1017
+ xml_node<Ch> *next_sibling(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
1018
+ {
1019
+ assert(this->m_parent); // Cannot query for siblings if node has no parent
1020
+ if (name_)
1021
+ {
1022
+ if (name_size_ == 0)
1023
+ name_size_ = internal::measure(name_);
1024
+ for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
1025
+ if (internal::compare(sibling->name(), sibling->name_size(), name_, name_size_, case_sensitive))
1026
+ return sibling;
1027
+ return 0;
1028
+ }
1029
+ else
1030
+ return m_next_sibling;
1031
+ }
1032
+
1033
+ //! Gets first attribute of node, optionally matching attribute name.
1034
+ //! \param name_ Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
1035
+ //! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
1036
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
1037
+ //! \return Pointer to found attribute, or 0 if not found.
1038
+ xml_attribute<Ch> *first_attribute(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
1039
+ {
1040
+ if (name_)
1041
+ {
1042
+ if (name_size_ == 0)
1043
+ name_size_ = internal::measure(name_);
1044
+ for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute)
1045
+ if (internal::compare(attribute->name(), attribute->name_size(), name_, name_size_, case_sensitive))
1046
+ return attribute;
1047
+ return 0;
1048
+ }
1049
+ else
1050
+ return m_first_attribute;
1051
+ }
1052
+
1053
+ //! Gets last attribute of node, optionally matching attribute name.
1054
+ //! \param name Name of attribute to find, or 0 to return last attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
1055
+ //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
1056
+ //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
1057
+ //! \return Pointer to found attribute, or 0 if not found.
1058
+ xml_attribute<Ch> *last_attribute(const Ch *name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
1059
+ {
1060
+ if (name)
1061
+ {
1062
+ if (name_size == 0)
1063
+ name_size = internal::measure(name);
1064
+ for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute)
1065
+ if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
1066
+ return attribute;
1067
+ return 0;
1068
+ }
1069
+ else
1070
+ return m_first_attribute ? m_last_attribute : 0;
1071
+ }
1072
+
1073
+ ///////////////////////////////////////////////////////////////////////////
1074
+ // Node modification
1075
+
1076
+ //! Sets type of node.
1077
+ //! \param type_ Type of node to set.
1078
+ void type(node_type type_)
1079
+ {
1080
+ m_type = type_;
1081
+ }
1082
+
1083
+ ///////////////////////////////////////////////////////////////////////////
1084
+ // Node manipulation
1085
+
1086
+ //! Prepends a new child node.
1087
+ //! The prepended child becomes the first child, and all existing children are moved one position back.
1088
+ //! \param child Node to prepend.
1089
+ void prepend_node(xml_node<Ch> *child)
1090
+ {
1091
+ assert(child && !child->parent() && child->type() != node_document);
1092
+ if (first_node())
1093
+ {
1094
+ child->m_next_sibling = m_first_node;
1095
+ m_first_node->m_prev_sibling = child;
1096
+ }
1097
+ else
1098
+ {
1099
+ child->m_next_sibling = 0;
1100
+ m_last_node = child;
1101
+ }
1102
+ m_first_node = child;
1103
+ child->m_parent = this;
1104
+ child->m_prev_sibling = 0;
1105
+ }
1106
+
1107
+ //! Appends a new child node.
1108
+ //! The appended child becomes the last child.
1109
+ //! \param child Node to append.
1110
+ void append_node(xml_node<Ch> *child)
1111
+ {
1112
+ assert(child && !child->parent() && child->type() != node_document);
1113
+ if (first_node())
1114
+ {
1115
+ child->m_prev_sibling = m_last_node;
1116
+ m_last_node->m_next_sibling = child;
1117
+ }
1118
+ else
1119
+ {
1120
+ child->m_prev_sibling = 0;
1121
+ m_first_node = child;
1122
+ }
1123
+ m_last_node = child;
1124
+ child->m_parent = this;
1125
+ child->m_next_sibling = 0;
1126
+ }
1127
+
1128
+ //! Inserts a new child node at specified place inside the node.
1129
+ //! All children after and including the specified node are moved one position back.
1130
+ //! \param where Place where to insert the child, or 0 to insert at the back.
1131
+ //! \param child Node to insert.
1132
+ void insert_node(xml_node<Ch> *where, xml_node<Ch> *child)
1133
+ {
1134
+ assert(!where || where->parent() == this);
1135
+ assert(child && !child->parent() && child->type() != node_document);
1136
+ if (where == m_first_node)
1137
+ prepend_node(child);
1138
+ else if (where == 0)
1139
+ append_node(child);
1140
+ else
1141
+ {
1142
+ child->m_prev_sibling = where->m_prev_sibling;
1143
+ child->m_next_sibling = where;
1144
+ where->m_prev_sibling->m_next_sibling = child;
1145
+ where->m_prev_sibling = child;
1146
+ child->m_parent = this;
1147
+ }
1148
+ }
1149
+
1150
+ //! Removes first child node.
1151
+ //! If node has no children, behaviour is undefined.
1152
+ //! Use first_node() to test if node has children.
1153
+ void remove_first_node()
1154
+ {
1155
+ assert(first_node());
1156
+ xml_node<Ch> *child = m_first_node;
1157
+ m_first_node = child->m_next_sibling;
1158
+ if (child->m_next_sibling)
1159
+ child->m_next_sibling->m_prev_sibling = 0;
1160
+ else
1161
+ m_last_node = 0;
1162
+ child->m_parent = 0;
1163
+ }
1164
+
1165
+ //! Removes last child of the node.
1166
+ //! If node has no children, behaviour is undefined.
1167
+ //! Use first_node() to test if node has children.
1168
+ void remove_last_node()
1169
+ {
1170
+ assert(first_node());
1171
+ xml_node<Ch> *child = m_last_node;
1172
+ if (child->m_prev_sibling)
1173
+ {
1174
+ m_last_node = child->m_prev_sibling;
1175
+ child->m_prev_sibling->m_next_sibling = 0;
1176
+ }
1177
+ else
1178
+ m_first_node = 0;
1179
+ child->m_parent = 0;
1180
+ }
1181
+
1182
+ //! Removes specified child from the node
1183
+ // \param where Pointer to child to be removed.
1184
+ void remove_node(xml_node<Ch> *where)
1185
+ {
1186
+ assert(where && where->parent() == this);
1187
+ assert(first_node());
1188
+ if (where == m_first_node)
1189
+ remove_first_node();
1190
+ else if (where == m_last_node)
1191
+ remove_last_node();
1192
+ else
1193
+ {
1194
+ where->m_prev_sibling->m_next_sibling = where->m_next_sibling;
1195
+ where->m_next_sibling->m_prev_sibling = where->m_prev_sibling;
1196
+ where->m_parent = 0;
1197
+ }
1198
+ }
1199
+
1200
+ //! Removes all child nodes (but not attributes).
1201
+ void remove_all_nodes()
1202
+ {
1203
+ for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling)
1204
+ node->m_parent = 0;
1205
+ m_first_node = 0;
1206
+ }
1207
+
1208
+ //! Prepends a new attribute to the node.
1209
+ //! \param attribute Attribute to prepend.
1210
+ void prepend_attribute(xml_attribute<Ch> *attribute)
1211
+ {
1212
+ assert(attribute && !attribute->parent());
1213
+ if (first_attribute())
1214
+ {
1215
+ attribute->m_next_attribute = m_first_attribute;
1216
+ m_first_attribute->m_prev_attribute = attribute;
1217
+ }
1218
+ else
1219
+ {
1220
+ attribute->m_next_attribute = 0;
1221
+ m_last_attribute = attribute;
1222
+ }
1223
+ m_first_attribute = attribute;
1224
+ attribute->m_parent = this;
1225
+ attribute->m_prev_attribute = 0;
1226
+ }
1227
+
1228
+ //! Appends a new attribute to the node.
1229
+ //! \param attribute Attribute to append.
1230
+ void append_attribute(xml_attribute<Ch> *attribute)
1231
+ {
1232
+ assert(attribute && !attribute->parent());
1233
+ if (first_attribute())
1234
+ {
1235
+ attribute->m_prev_attribute = m_last_attribute;
1236
+ m_last_attribute->m_next_attribute = attribute;
1237
+ }
1238
+ else
1239
+ {
1240
+ attribute->m_prev_attribute = 0;
1241
+ m_first_attribute = attribute;
1242
+ }
1243
+ m_last_attribute = attribute;
1244
+ attribute->m_parent = this;
1245
+ attribute->m_next_attribute = 0;
1246
+ }
1247
+
1248
+ //! Inserts a new attribute at specified place inside the node.
1249
+ //! All attributes after and including the specified attribute are moved one position back.
1250
+ //! \param where Place where to insert the attribute, or 0 to insert at the back.
1251
+ //! \param attribute Attribute to insert.
1252
+ void insert_attribute(xml_attribute<Ch> *where, xml_attribute<Ch> *attribute)
1253
+ {
1254
+ assert(!where || where->parent() == this);
1255
+ assert(attribute && !attribute->parent());
1256
+ if (where == m_first_attribute)
1257
+ prepend_attribute(attribute);
1258
+ else if (where == 0)
1259
+ append_attribute(attribute);
1260
+ else
1261
+ {
1262
+ attribute->m_prev_attribute = where->m_prev_attribute;
1263
+ attribute->m_next_attribute = where;
1264
+ where->m_prev_attribute->m_next_attribute = attribute;
1265
+ where->m_prev_attribute = attribute;
1266
+ attribute->m_parent = this;
1267
+ }
1268
+ }
1269
+
1270
+ //! Removes first attribute of the node.
1271
+ //! If node has no attributes, behaviour is undefined.
1272
+ //! Use first_attribute() to test if node has attributes.
1273
+ void remove_first_attribute()
1274
+ {
1275
+ assert(first_attribute());
1276
+ xml_attribute<Ch> *attribute = m_first_attribute;
1277
+ if (attribute->m_next_attribute)
1278
+ {
1279
+ attribute->m_next_attribute->m_prev_attribute = 0;
1280
+ }
1281
+ else
1282
+ m_last_attribute = 0;
1283
+ attribute->m_parent = 0;
1284
+ m_first_attribute = attribute->m_next_attribute;
1285
+ }
1286
+
1287
+ //! Removes last attribute of the node.
1288
+ //! If node has no attributes, behaviour is undefined.
1289
+ //! Use first_attribute() to test if node has attributes.
1290
+ void remove_last_attribute()
1291
+ {
1292
+ assert(first_attribute());
1293
+ xml_attribute<Ch> *attribute = m_last_attribute;
1294
+ if (attribute->m_prev_attribute)
1295
+ {
1296
+ attribute->m_prev_attribute->m_next_attribute = 0;
1297
+ m_last_attribute = attribute->m_prev_attribute;
1298
+ }
1299
+ else
1300
+ m_first_attribute = 0;
1301
+ attribute->m_parent = 0;
1302
+ }
1303
+
1304
+ //! Removes specified attribute from node.
1305
+ //! \param where Pointer to attribute to be removed.
1306
+ void remove_attribute(xml_attribute<Ch> *where)
1307
+ {
1308
+ assert(first_attribute() && where->parent() == this);
1309
+ if (where == m_first_attribute)
1310
+ remove_first_attribute();
1311
+ else if (where == m_last_attribute)
1312
+ remove_last_attribute();
1313
+ else
1314
+ {
1315
+ where->m_prev_attribute->m_next_attribute = where->m_next_attribute;
1316
+ where->m_next_attribute->m_prev_attribute = where->m_prev_attribute;
1317
+ where->m_parent = 0;
1318
+ }
1319
+ }
1320
+
1321
+ //! Removes all attributes of node.
1322
+ void remove_all_attributes()
1323
+ {
1324
+ for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute)
1325
+ attribute->m_parent = 0;
1326
+ m_first_attribute = 0;
1327
+ }
1328
+
1329
+ private:
1330
+
1331
+ ///////////////////////////////////////////////////////////////////////////
1332
+ // Restrictions
1333
+
1334
+ // No copying
1335
+ xml_node(const xml_node &);
1336
+ void operator =(const xml_node &);
1337
+
1338
+ ///////////////////////////////////////////////////////////////////////////
1339
+ // Data members
1340
+
1341
+ // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0.
1342
+ // This is required for maximum performance, as it allows the parser to omit initialization of
1343
+ // unneded/redundant values.
1344
+ //
1345
+ // The rules are as follows:
1346
+ // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively
1347
+ // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage
1348
+ // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage
1349
+
1350
+ node_type m_type; // Type of node; always valid
1351
+ xml_node<Ch> *m_first_node; // Pointer to first child node, or 0 if none; always valid
1352
+ xml_node<Ch> *m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node is non-zero
1353
+ xml_attribute<Ch> *m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid
1354
+ xml_attribute<Ch> *m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only valid if m_first_attribute is non-zero
1355
+ xml_node<Ch> *m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if m_parent is non-zero
1356
+ xml_node<Ch> *m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if m_parent is non-zero
1357
+
1358
+ };
1359
+
1360
+ ///////////////////////////////////////////////////////////////////////////
1361
+ // XML document
1362
+
1363
+ //! This class represents root of the DOM hierarchy.
1364
+ //! It is also an xml_node and a memory_pool through public inheritance.
1365
+ //! Use parse() function to build a DOM tree from a zero-terminated XML text string.
1366
+ //! parse() function allocates memory for nodes and attributes by using functions of xml_document,
1367
+ //! which are inherited from memory_pool.
1368
+ //! To access root node of the document, use the document itself, as if it was an xml_node.
1369
+ //! \tparam Ch Character type to use.
1370
+ template<class Ch = char>
1371
+ class xml_document: public xml_node<Ch>, public memory_pool<Ch>
1372
+ {
1373
+
1374
+ public:
1375
+
1376
+ //! Constructs empty XML document
1377
+ xml_document()
1378
+ : xml_node<Ch>(node_document)
1379
+ {
1380
+ }
1381
+
1382
+ //! Parses zero-terminated XML string according to given flags.
1383
+ //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used.
1384
+ //! The string must persist for the lifetime of the document.
1385
+ //! In case of error, rapidxml::parse_error exception will be thrown.
1386
+ //! <br><br>
1387
+ //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning.
1388
+ //! Make sure that data is zero-terminated.
1389
+ //! <br><br>
1390
+ //! Document can be parsed into multiple times.
1391
+ //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.
1392
+ //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.
1393
+ template<int Flags>
1394
+ void parse(Ch *text)
1395
+ {
1396
+ assert(text);
1397
+
1398
+ // Remove current contents
1399
+ this->remove_all_nodes();
1400
+ this->remove_all_attributes();
1401
+
1402
+ // Parse BOM, if any
1403
+ parse_bom<Flags>(text);
1404
+
1405
+ // Parse children
1406
+ while (1)
1407
+ {
1408
+ // Skip whitespace before node
1409
+ skip<whitespace_pred, Flags>(text);
1410
+ if (*text == 0)
1411
+ break;
1412
+
1413
+ // Parse and append new child
1414
+ if (*text == Ch('<'))
1415
+ {
1416
+ ++text; // Skip '<'
1417
+ if (xml_node<Ch> *node = parse_node<Flags>(text))
1418
+ this->append_node(node);
1419
+ }
1420
+ else
1421
+ CEREAL_RAPIDXML_PARSE_ERROR("expected <", text);
1422
+ }
1423
+
1424
+ }
1425
+
1426
+ //! Clears the document by deleting all nodes and clearing the memory pool.
1427
+ //! All nodes owned by document pool are destroyed.
1428
+ void clear()
1429
+ {
1430
+ this->remove_all_nodes();
1431
+ this->remove_all_attributes();
1432
+ memory_pool<Ch>::clear();
1433
+ }
1434
+
1435
+ private:
1436
+
1437
+ ///////////////////////////////////////////////////////////////////////
1438
+ // Internal character utility functions
1439
+
1440
+ // Detect whitespace character
1441
+ struct whitespace_pred
1442
+ {
1443
+ static unsigned char test(Ch ch)
1444
+ {
1445
+ return internal::lookup_tables<0>::lookup_whitespace[static_cast<unsigned char>(ch)];
1446
+ }
1447
+ };
1448
+
1449
+ // Detect node name character
1450
+ struct node_name_pred
1451
+ {
1452
+ static unsigned char test(Ch ch)
1453
+ {
1454
+ return internal::lookup_tables<0>::lookup_node_name[static_cast<unsigned char>(ch)];
1455
+ }
1456
+ };
1457
+
1458
+ // Detect attribute name character
1459
+ struct attribute_name_pred
1460
+ {
1461
+ static unsigned char test(Ch ch)
1462
+ {
1463
+ return internal::lookup_tables<0>::lookup_attribute_name[static_cast<unsigned char>(ch)];
1464
+ }
1465
+ };
1466
+
1467
+ // Detect text character (PCDATA)
1468
+ struct text_pred
1469
+ {
1470
+ static unsigned char test(Ch ch)
1471
+ {
1472
+ return internal::lookup_tables<0>::lookup_text[static_cast<unsigned char>(ch)];
1473
+ }
1474
+ };
1475
+
1476
+ // Detect text character (PCDATA) that does not require processing
1477
+ struct text_pure_no_ws_pred
1478
+ {
1479
+ static unsigned char test(Ch ch)
1480
+ {
1481
+ return internal::lookup_tables<0>::lookup_text_pure_no_ws[static_cast<unsigned char>(ch)];
1482
+ }
1483
+ };
1484
+
1485
+ // Detect text character (PCDATA) that does not require processing
1486
+ struct text_pure_with_ws_pred
1487
+ {
1488
+ static unsigned char test(Ch ch)
1489
+ {
1490
+ return internal::lookup_tables<0>::lookup_text_pure_with_ws[static_cast<unsigned char>(ch)];
1491
+ }
1492
+ };
1493
+
1494
+ // Detect attribute value character
1495
+ template<Ch Quote>
1496
+ struct attribute_value_pred
1497
+ {
1498
+ static unsigned char test(Ch ch)
1499
+ {
1500
+ if (Quote == Ch('\''))
1501
+ return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast<unsigned char>(ch)];
1502
+ if (Quote == Ch('\"'))
1503
+ return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast<unsigned char>(ch)];
1504
+ return 0; // Should never be executed, to avoid warnings on Comeau
1505
+ }
1506
+ };
1507
+
1508
+ // Detect attribute value character
1509
+ template<Ch Quote>
1510
+ struct attribute_value_pure_pred
1511
+ {
1512
+ static unsigned char test(Ch ch)
1513
+ {
1514
+ if (Quote == Ch('\''))
1515
+ return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)];
1516
+ if (Quote == Ch('\"'))
1517
+ return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)];
1518
+ return 0; // Should never be executed, to avoid warnings on Comeau
1519
+ }
1520
+ };
1521
+
1522
+ // Insert coded character, using UTF8 or 8-bit ASCII
1523
+ template<int Flags>
1524
+ static void insert_coded_character(Ch *&text, unsigned long code)
1525
+ {
1526
+ if (Flags & parse_no_utf8)
1527
+ {
1528
+ // Insert 8-bit ASCII character
1529
+ // Todo: possibly verify that code is less than 256 and use replacement char otherwise?
1530
+ text[0] = static_cast<Ch>(code);
1531
+ text += 1;
1532
+ }
1533
+ else
1534
+ {
1535
+ // Insert UTF8 sequence
1536
+ if (code < 0x80) // 1 byte sequence
1537
+ {
1538
+ text[0] = static_cast<Ch>(code);
1539
+ text += 1;
1540
+ }
1541
+ else if (code < 0x800) // 2 byte sequence
1542
+ {
1543
+ text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1544
+ text[0] = static_cast<Ch>(code | 0xC0);
1545
+ text += 2;
1546
+ }
1547
+ else if (code < 0x10000) // 3 byte sequence
1548
+ {
1549
+ text[2] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1550
+ text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1551
+ text[0] = static_cast<Ch>(code | 0xE0);
1552
+ text += 3;
1553
+ }
1554
+ else if (code < 0x110000) // 4 byte sequence
1555
+ {
1556
+ text[3] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1557
+ text[2] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1558
+ text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1559
+ text[0] = static_cast<Ch>(code | 0xF0);
1560
+ text += 4;
1561
+ }
1562
+ else // Invalid, only codes up to 0x10FFFF are allowed in Unicode
1563
+ {
1564
+ CEREAL_RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
1565
+ }
1566
+ }
1567
+ }
1568
+
1569
+ // Skip characters until predicate evaluates to true
1570
+ template<class StopPred, int Flags>
1571
+ static void skip(Ch *&text)
1572
+ {
1573
+ Ch *tmp = text;
1574
+ while (StopPred::test(*tmp))
1575
+ ++tmp;
1576
+ text = tmp;
1577
+ }
1578
+
1579
+ // Skip characters until predicate evaluates to true while doing the following:
1580
+ // - replacing XML character entity references with proper characters (&apos; &amp; &quot; &lt; &gt; &#...;)
1581
+ // - condensing whitespace sequences to single space character
1582
+ template<class StopPred, class StopPredPure, int Flags>
1583
+ static Ch *skip_and_expand_character_refs(Ch *&text, bool preserve_space)
1584
+ {
1585
+ // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
1586
+ if (Flags & parse_no_entity_translation &&
1587
+ !(Flags & parse_normalize_whitespace) &&
1588
+ !(Flags & parse_trim_whitespace))
1589
+ {
1590
+ skip<StopPred, Flags>(text);
1591
+ return text;
1592
+ }
1593
+
1594
+ // Use simple skip until first modification is detected
1595
+ skip<StopPredPure, Flags>(text);
1596
+
1597
+ // Use translation skip
1598
+ Ch *src = text;
1599
+ Ch *dest = src;
1600
+ while (StopPred::test(*src))
1601
+ {
1602
+ // If entity translation is enabled
1603
+ if (!(Flags & parse_no_entity_translation))
1604
+ {
1605
+ // Test if replacement is needed
1606
+ if (src[0] == Ch('&'))
1607
+ {
1608
+ switch (src[1])
1609
+ {
1610
+
1611
+ // &amp; &apos;
1612
+ case Ch('a'):
1613
+ if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';'))
1614
+ {
1615
+ *dest = Ch('&');
1616
+ ++dest;
1617
+ src += 5;
1618
+ continue;
1619
+ }
1620
+ if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';'))
1621
+ {
1622
+ *dest = Ch('\'');
1623
+ ++dest;
1624
+ src += 6;
1625
+ continue;
1626
+ }
1627
+ break;
1628
+
1629
+ // &quot;
1630
+ case Ch('q'):
1631
+ if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';'))
1632
+ {
1633
+ *dest = Ch('"');
1634
+ ++dest;
1635
+ src += 6;
1636
+ continue;
1637
+ }
1638
+ break;
1639
+
1640
+ // &gt;
1641
+ case Ch('g'):
1642
+ if (src[2] == Ch('t') && src[3] == Ch(';'))
1643
+ {
1644
+ *dest = Ch('>');
1645
+ ++dest;
1646
+ src += 4;
1647
+ continue;
1648
+ }
1649
+ break;
1650
+
1651
+ // &lt;
1652
+ case Ch('l'):
1653
+ if (src[2] == Ch('t') && src[3] == Ch(';'))
1654
+ {
1655
+ *dest = Ch('<');
1656
+ ++dest;
1657
+ src += 4;
1658
+ continue;
1659
+ }
1660
+ break;
1661
+
1662
+ // &#...; - assumes ASCII
1663
+ case Ch('#'):
1664
+ if (src[2] == Ch('x'))
1665
+ {
1666
+ unsigned long code = 0;
1667
+ src += 3; // Skip &#x
1668
+ while (1)
1669
+ {
1670
+ unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
1671
+ if (digit == 0xFF)
1672
+ break;
1673
+ code = code * 16 + digit;
1674
+ ++src;
1675
+ }
1676
+ insert_coded_character<Flags>(dest, code); // Put character in output
1677
+ }
1678
+ else
1679
+ {
1680
+ unsigned long code = 0;
1681
+ src += 2; // Skip &#
1682
+ while (1)
1683
+ {
1684
+ unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
1685
+ if (digit == 0xFF)
1686
+ break;
1687
+ code = code * 10 + digit;
1688
+ ++src;
1689
+ }
1690
+ insert_coded_character<Flags>(dest, code); // Put character in output
1691
+ }
1692
+ if (*src == Ch(';'))
1693
+ ++src;
1694
+ else
1695
+ CEREAL_RAPIDXML_PARSE_ERROR("expected ;", src);
1696
+ continue;
1697
+
1698
+ // Something else
1699
+ default:
1700
+ // Ignore, just copy '&' verbatim
1701
+ break;
1702
+
1703
+ }
1704
+ }
1705
+ }
1706
+
1707
+ // If whitespace condensing is enabled
1708
+ if ((Flags & parse_normalize_whitespace) && !preserve_space)
1709
+ {
1710
+ // Test if condensing is needed
1711
+ if (whitespace_pred::test(*src))
1712
+ {
1713
+ *dest = Ch(' '); ++dest; // Put single space in dest
1714
+ ++src; // Skip first whitespace char
1715
+ // Skip remaining whitespace chars
1716
+ while (whitespace_pred::test(*src))
1717
+ ++src;
1718
+ continue;
1719
+ }
1720
+ }
1721
+
1722
+ // No replacement, only copy character
1723
+ *dest++ = *src++;
1724
+
1725
+ }
1726
+
1727
+ // Return new end
1728
+ text = src;
1729
+ return dest;
1730
+
1731
+ }
1732
+
1733
+ ///////////////////////////////////////////////////////////////////////
1734
+ // Internal parsing functions
1735
+
1736
+ // Parse BOM, if any
1737
+ template<int Flags>
1738
+ void parse_bom(Ch *&text)
1739
+ {
1740
+ // UTF-8?
1741
+ if (static_cast<unsigned char>(text[0]) == 0xEF &&
1742
+ static_cast<unsigned char>(text[1]) == 0xBB &&
1743
+ static_cast<unsigned char>(text[2]) == 0xBF)
1744
+ {
1745
+ text += 3; // Skup utf-8 bom
1746
+ }
1747
+ }
1748
+
1749
+ // Parse XML declaration (<?xml...)
1750
+ template<int Flags>
1751
+ xml_node<Ch> *parse_xml_declaration(Ch *&text)
1752
+ {
1753
+ // If parsing of declaration is disabled
1754
+ if (!(Flags & parse_declaration_node))
1755
+ {
1756
+ // Skip until end of declaration
1757
+ while (text[0] != Ch('?') || text[1] != Ch('>'))
1758
+ {
1759
+ if (!text[0])
1760
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1761
+ ++text;
1762
+ }
1763
+ text += 2; // Skip '?>'
1764
+ return 0;
1765
+ }
1766
+
1767
+ // Create declaration
1768
+ xml_node<Ch> *declaration = this->allocate_node(node_declaration);
1769
+
1770
+ // Skip whitespace before attributes or ?>
1771
+ skip<whitespace_pred, Flags>(text);
1772
+
1773
+ // Parse declaration attributes
1774
+ parse_node_attributes<Flags>(text, declaration);
1775
+
1776
+ // Skip ?>
1777
+ if (text[0] != Ch('?') || text[1] != Ch('>'))
1778
+ CEREAL_RAPIDXML_PARSE_ERROR("expected ?>", text);
1779
+ text += 2;
1780
+
1781
+ return declaration;
1782
+ }
1783
+
1784
+ // Parse XML comment (<!--...)
1785
+ template<int Flags>
1786
+ xml_node<Ch> *parse_comment(Ch *&text)
1787
+ {
1788
+ // If parsing of comments is disabled
1789
+ if (!(Flags & parse_comment_nodes))
1790
+ {
1791
+ // Skip until end of comment
1792
+ while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
1793
+ {
1794
+ if (!text[0])
1795
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1796
+ ++text;
1797
+ }
1798
+ text += 3; // Skip '-->'
1799
+ return 0; // Do not produce comment node
1800
+ }
1801
+
1802
+ // Remember value start
1803
+ Ch *value_ = text;
1804
+
1805
+ // Skip until end of comment
1806
+ while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
1807
+ {
1808
+ if (!text[0])
1809
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1810
+ ++text;
1811
+ }
1812
+
1813
+ // Create comment node
1814
+ xml_node<Ch> *comment = this->allocate_node(node_comment);
1815
+ comment->value(value_, static_cast<std::size_t>(text - value_));
1816
+
1817
+ // Place zero terminator after comment value
1818
+ if (!(Flags & parse_no_string_terminators))
1819
+ *text = Ch('\0');
1820
+
1821
+ text += 3; // Skip '-->'
1822
+ return comment;
1823
+ }
1824
+
1825
+ // Parse DOCTYPE
1826
+ template<int Flags>
1827
+ xml_node<Ch> *parse_doctype(Ch *&text)
1828
+ {
1829
+ // Remember value start
1830
+ Ch *value_ = text;
1831
+
1832
+ // Skip to >
1833
+ while (*text != Ch('>'))
1834
+ {
1835
+ // Determine character type
1836
+ switch (*text)
1837
+ {
1838
+
1839
+ // If '[' encountered, scan for matching ending ']' using naive algorithm with depth
1840
+ // This works for all W3C test files except for 2 most wicked
1841
+ case Ch('['):
1842
+ {
1843
+ ++text; // Skip '['
1844
+ int depth = 1;
1845
+ while (depth > 0)
1846
+ {
1847
+ switch (*text)
1848
+ {
1849
+ case Ch('['): ++depth; break;
1850
+ case Ch(']'): --depth; break;
1851
+ case 0: CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1852
+ }
1853
+ ++text;
1854
+ }
1855
+ break;
1856
+ }
1857
+
1858
+ // Error on end of text
1859
+ case Ch('\0'):
1860
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1861
+
1862
+ // Other character, skip it
1863
+ default:
1864
+ ++text;
1865
+
1866
+ }
1867
+ }
1868
+
1869
+ // If DOCTYPE nodes enabled
1870
+ if (Flags & parse_doctype_node)
1871
+ {
1872
+ // Create a new doctype node
1873
+ xml_node<Ch> *doctype = this->allocate_node(node_doctype);
1874
+ doctype->value(value_, static_cast<std::size_t>(text - value_));
1875
+
1876
+ // Place zero terminator after value
1877
+ if (!(Flags & parse_no_string_terminators))
1878
+ *text = Ch('\0');
1879
+
1880
+ text += 1; // skip '>'
1881
+ return doctype;
1882
+ }
1883
+ else
1884
+ {
1885
+ text += 1; // skip '>'
1886
+ return 0;
1887
+ }
1888
+
1889
+ }
1890
+
1891
+ // Parse PI
1892
+ template<int Flags>
1893
+ xml_node<Ch> *parse_pi(Ch *&text)
1894
+ {
1895
+ // If creation of PI nodes is enabled
1896
+ if (Flags & parse_pi_nodes)
1897
+ {
1898
+ // Create pi node
1899
+ xml_node<Ch> *pi = this->allocate_node(node_pi);
1900
+
1901
+ // Extract PI target name
1902
+ Ch *name_ = text;
1903
+ skip<node_name_pred, Flags>(text);
1904
+ if (text == name_)
1905
+ CEREAL_RAPIDXML_PARSE_ERROR("expected PI target", text);
1906
+ pi->name(name_, static_cast<std::size_t>(text - name_));
1907
+
1908
+ // Skip whitespace between pi target and pi
1909
+ skip<whitespace_pred, Flags>(text);
1910
+
1911
+ // Remember start of pi
1912
+ Ch *value_ = text;
1913
+
1914
+ // Skip to '?>'
1915
+ while (text[0] != Ch('?') || text[1] != Ch('>'))
1916
+ {
1917
+ if (*text == Ch('\0'))
1918
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1919
+ ++text;
1920
+ }
1921
+
1922
+ // Set pi value (verbatim, no entity expansion or whitespace normalization)
1923
+ pi->value(value_, static_cast<std::size_t>(text - value_));
1924
+
1925
+ // Place zero terminator after name and value
1926
+ if (!(Flags & parse_no_string_terminators))
1927
+ {
1928
+ pi->name()[pi->name_size()] = Ch('\0');
1929
+ pi->value()[pi->value_size()] = Ch('\0');
1930
+ }
1931
+
1932
+ text += 2; // Skip '?>'
1933
+ return pi;
1934
+ }
1935
+ else
1936
+ {
1937
+ // Skip to '?>'
1938
+ while (text[0] != Ch('?') || text[1] != Ch('>'))
1939
+ {
1940
+ if (*text == Ch('\0'))
1941
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1942
+ ++text;
1943
+ }
1944
+ text += 2; // Skip '?>'
1945
+ return 0;
1946
+ }
1947
+ }
1948
+
1949
+ // Parse and append data
1950
+ // Return character that ends data.
1951
+ // This is necessary because this character might have been overwritten by a terminating 0
1952
+ template<int Flags>
1953
+ Ch parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start)
1954
+ {
1955
+ // Backup to contents start if whitespace trimming is disabled
1956
+ if (!(Flags & parse_trim_whitespace))
1957
+ text = contents_start;
1958
+
1959
+ const bool preserve_space = internal::preserve_space(node);
1960
+
1961
+ // Skip until end of data
1962
+ Ch *value_ = text, *end;
1963
+ if ((Flags & parse_normalize_whitespace) && !preserve_space)
1964
+ end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text, false);
1965
+ else
1966
+ end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text, preserve_space);
1967
+
1968
+ // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
1969
+ if ((Flags & parse_trim_whitespace) && !preserve_space)
1970
+ {
1971
+ if (Flags & parse_normalize_whitespace)
1972
+ {
1973
+ // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end
1974
+ if (*(end - 1) == Ch(' '))
1975
+ --end;
1976
+ }
1977
+ else
1978
+ {
1979
+ // Backup until non-whitespace character is found
1980
+ while (whitespace_pred::test(*(end - 1)))
1981
+ --end;
1982
+ }
1983
+ }
1984
+
1985
+ // If characters are still left between end and value (this test is only necessary if normalization is enabled)
1986
+ // Create new data node
1987
+ if (!(Flags & parse_no_data_nodes))
1988
+ {
1989
+ xml_node<Ch> *data = this->allocate_node(node_data);
1990
+ data->value(value_, static_cast<std::size_t>(end - value_));
1991
+ node->append_node(data);
1992
+ }
1993
+
1994
+ // Add data to parent node if no data exists yet
1995
+ if (!(Flags & parse_no_element_values))
1996
+ if (*node->value() == Ch('\0'))
1997
+ node->value(value_, static_cast<std::size_t>(end - value_));
1998
+
1999
+ // Place zero terminator after value
2000
+ if (!(Flags & parse_no_string_terminators))
2001
+ {
2002
+ Ch ch = *text;
2003
+ *end = Ch('\0');
2004
+ return ch; // Return character that ends data; this is required because zero terminator overwritten it
2005
+ }
2006
+
2007
+ // Return character that ends data
2008
+ return *text;
2009
+ }
2010
+
2011
+ // Parse CDATA
2012
+ template<int Flags>
2013
+ xml_node<Ch> *parse_cdata(Ch *&text)
2014
+ {
2015
+ // If CDATA is disabled
2016
+ if (Flags & parse_no_data_nodes)
2017
+ {
2018
+ // Skip until end of cdata
2019
+ while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
2020
+ {
2021
+ if (!text[0])
2022
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2023
+ ++text;
2024
+ }
2025
+ text += 3; // Skip ]]>
2026
+ return 0; // Do not produce CDATA node
2027
+ }
2028
+
2029
+ // Skip until end of cdata
2030
+ Ch *value_ = text;
2031
+ while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
2032
+ {
2033
+ if (!text[0])
2034
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2035
+ ++text;
2036
+ }
2037
+
2038
+ // Create new cdata node
2039
+ xml_node<Ch> *cdata = this->allocate_node(node_cdata);
2040
+ cdata->value(value_, static_cast<std::size_t>(text - value_));
2041
+
2042
+ // Place zero terminator after value
2043
+ if (!(Flags & parse_no_string_terminators))
2044
+ *text = Ch('\0');
2045
+
2046
+ text += 3; // Skip ]]>
2047
+ return cdata;
2048
+ }
2049
+
2050
+ // Parse element node
2051
+ template<int Flags>
2052
+ xml_node<Ch> *parse_element(Ch *&text)
2053
+ {
2054
+ // Create element node
2055
+ xml_node<Ch> *element = this->allocate_node(node_element);
2056
+
2057
+ // Extract element name
2058
+ Ch *name_ = text;
2059
+ skip<node_name_pred, Flags>(text);
2060
+ if (text == name_)
2061
+ CEREAL_RAPIDXML_PARSE_ERROR("expected element name", text);
2062
+ element->name(name_, static_cast<std::size_t>(text - name_));
2063
+
2064
+ // Skip whitespace between element name and attributes or >
2065
+ skip<whitespace_pred, Flags>(text);
2066
+
2067
+ // Parse attributes, if any
2068
+ parse_node_attributes<Flags>(text, element);
2069
+
2070
+ // Determine ending type
2071
+ if (*text == Ch('>'))
2072
+ {
2073
+ ++text;
2074
+ parse_node_contents<Flags>(text, element);
2075
+ }
2076
+ else if (*text == Ch('/'))
2077
+ {
2078
+ ++text;
2079
+ if (*text != Ch('>'))
2080
+ CEREAL_RAPIDXML_PARSE_ERROR("expected >", text);
2081
+ ++text;
2082
+ }
2083
+ else
2084
+ CEREAL_RAPIDXML_PARSE_ERROR("expected >", text);
2085
+
2086
+ // Place zero terminator after name
2087
+ if (!(Flags & parse_no_string_terminators))
2088
+ element->name()[element->name_size()] = Ch('\0');
2089
+
2090
+ // Return parsed element
2091
+ return element;
2092
+ }
2093
+
2094
+ // Determine node type, and parse it
2095
+ template<int Flags>
2096
+ xml_node<Ch> *parse_node(Ch *&text)
2097
+ {
2098
+ // Parse proper node type
2099
+ switch (text[0])
2100
+ {
2101
+
2102
+ // <...
2103
+ default:
2104
+ // Parse and append element node
2105
+ return parse_element<Flags>(text);
2106
+
2107
+ // <?...
2108
+ case Ch('?'):
2109
+ ++text; // Skip ?
2110
+ if ((text[0] == Ch('x') || text[0] == Ch('X')) &&
2111
+ (text[1] == Ch('m') || text[1] == Ch('M')) &&
2112
+ (text[2] == Ch('l') || text[2] == Ch('L')) &&
2113
+ whitespace_pred::test(text[3]))
2114
+ {
2115
+ // '<?xml ' - xml declaration
2116
+ text += 4; // Skip 'xml '
2117
+ return parse_xml_declaration<Flags>(text);
2118
+ }
2119
+ else
2120
+ {
2121
+ // Parse PI
2122
+ return parse_pi<Flags>(text);
2123
+ }
2124
+
2125
+ // <!...
2126
+ case Ch('!'):
2127
+
2128
+ // Parse proper subset of <! node
2129
+ switch (text[1])
2130
+ {
2131
+
2132
+ // <!-
2133
+ case Ch('-'):
2134
+ if (text[2] == Ch('-'))
2135
+ {
2136
+ // '<!--' - xml comment
2137
+ text += 3; // Skip '!--'
2138
+ return parse_comment<Flags>(text);
2139
+ }
2140
+ break;
2141
+
2142
+ // <![
2143
+ case Ch('['):
2144
+ if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') &&
2145
+ text[5] == Ch('T') && text[6] == Ch('A') && text[7] == Ch('['))
2146
+ {
2147
+ // '<![CDATA[' - cdata
2148
+ text += 8; // Skip '![CDATA['
2149
+ return parse_cdata<Flags>(text);
2150
+ }
2151
+ break;
2152
+
2153
+ // <!D
2154
+ case Ch('D'):
2155
+ if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') &&
2156
+ text[5] == Ch('Y') && text[6] == Ch('P') && text[7] == Ch('E') &&
2157
+ whitespace_pred::test(text[8]))
2158
+ {
2159
+ // '<!DOCTYPE ' - doctype
2160
+ text += 9; // skip '!DOCTYPE '
2161
+ return parse_doctype<Flags>(text);
2162
+ }
2163
+
2164
+ } // switch
2165
+
2166
+ // Attempt to skip other, unrecognized node types starting with <!
2167
+ ++text; // Skip !
2168
+ while (*text != Ch('>'))
2169
+ {
2170
+ if (*text == 0)
2171
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2172
+ ++text;
2173
+ }
2174
+ ++text; // Skip '>'
2175
+ return 0; // No node recognized
2176
+
2177
+ }
2178
+ }
2179
+
2180
+ // Parse contents of the node - children, data etc.
2181
+ template<int Flags>
2182
+ void parse_node_contents(Ch *&text, xml_node<Ch> *node)
2183
+ {
2184
+ // For all children and text
2185
+ while (1)
2186
+ {
2187
+ // Skip whitespace between > and node contents
2188
+ Ch *contents_start = text; // Store start of node contents before whitespace is skipped
2189
+ skip<whitespace_pred, Flags>(text);
2190
+ Ch next_char = *text;
2191
+
2192
+ // After data nodes, instead of continuing the loop, control jumps here.
2193
+ // This is because zero termination inside parse_and_append_data() function
2194
+ // would wreak havoc with the above code.
2195
+ // Also, skipping whitespace after data nodes is unnecessary.
2196
+ after_data_node:
2197
+
2198
+ // Determine what comes next: node closing, child node, data node, or 0?
2199
+ switch (next_char)
2200
+ {
2201
+
2202
+ // Node closing or child node
2203
+ case Ch('<'):
2204
+ if (text[1] == Ch('/'))
2205
+ {
2206
+ Ch *contents_end = 0;
2207
+ if (internal::preserve_space(node))
2208
+ {
2209
+ contents_end = text;
2210
+ }
2211
+
2212
+ // Node closing
2213
+ text += 2; // Skip '</'
2214
+ if (Flags & parse_validate_closing_tags)
2215
+ {
2216
+ // Skip and validate closing tag name
2217
+ Ch *closing_name = text;
2218
+ skip<node_name_pred, Flags>(text);
2219
+ if (!internal::compare(node->name(), node->name_size(), closing_name, static_cast<std::size_t>(text - closing_name), true))
2220
+ CEREAL_RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
2221
+ }
2222
+ else
2223
+ {
2224
+ // No validation, just skip name
2225
+ skip<node_name_pred, Flags>(text);
2226
+ }
2227
+ // Skip remaining whitespace after node name
2228
+ skip<whitespace_pred, Flags>(text);
2229
+ if (*text != Ch('>'))
2230
+ CEREAL_RAPIDXML_PARSE_ERROR("expected >", text);
2231
+ ++text; // Skip '>'
2232
+
2233
+ if (contents_end && contents_end != contents_start)
2234
+ {
2235
+ node->value(contents_start, static_cast<std::size_t>(contents_end - contents_start));
2236
+ node->value()[node->value_size()] = Ch('\0');
2237
+ }
2238
+ return; // Node closed, finished parsing contents
2239
+ }
2240
+ else
2241
+ {
2242
+ // Child node
2243
+ ++text; // Skip '<'
2244
+ if (xml_node<Ch> *child = parse_node<Flags>(text))
2245
+ node->append_node(child);
2246
+ }
2247
+ break;
2248
+
2249
+ // End of data - error
2250
+ case Ch('\0'):
2251
+ CEREAL_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2252
+
2253
+ // Data node
2254
+ default:
2255
+ next_char = parse_and_append_data<Flags>(node, text, contents_start);
2256
+ goto after_data_node; // Bypass regular processing after data nodes
2257
+
2258
+ }
2259
+ }
2260
+ }
2261
+
2262
+ // Parse XML attributes of the node
2263
+ template<int Flags>
2264
+ void parse_node_attributes(Ch *&text, xml_node<Ch> *node)
2265
+ {
2266
+ // For all attributes
2267
+ while (attribute_name_pred::test(*text))
2268
+ {
2269
+ // Extract attribute name
2270
+ Ch *name_ = text;
2271
+ ++text; // Skip first character of attribute name
2272
+ skip<attribute_name_pred, Flags>(text);
2273
+ if (text == name_)
2274
+ CEREAL_RAPIDXML_PARSE_ERROR("expected attribute name", name_);
2275
+
2276
+ // Create new attribute
2277
+ xml_attribute<Ch> *attribute = this->allocate_attribute();
2278
+ attribute->name(name_, static_cast<std::size_t>(text - name_));
2279
+ node->append_attribute(attribute);
2280
+
2281
+ // Skip whitespace after attribute name
2282
+ skip<whitespace_pred, Flags>(text);
2283
+
2284
+ // Skip =
2285
+ if (*text != Ch('='))
2286
+ CEREAL_RAPIDXML_PARSE_ERROR("expected =", text);
2287
+ ++text;
2288
+
2289
+ // Add terminating zero after name
2290
+ if (!(Flags & parse_no_string_terminators))
2291
+ attribute->name()[attribute->name_size()] = 0;
2292
+
2293
+ // Skip whitespace after =
2294
+ skip<whitespace_pred, Flags>(text);
2295
+
2296
+ // Skip quote and remember if it was ' or "
2297
+ Ch quote = *text;
2298
+ if (quote != Ch('\'') && quote != Ch('"'))
2299
+ CEREAL_RAPIDXML_PARSE_ERROR("expected ' or \"", text);
2300
+ ++text;
2301
+
2302
+ // Extract attribute value and expand char refs in it
2303
+ Ch *value_ = text, *end;
2304
+ const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes
2305
+ if (quote == Ch('\''))
2306
+ end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text, false);
2307
+ else
2308
+ end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text, false);
2309
+
2310
+ // Set attribute value
2311
+ attribute->value(value_, static_cast<std::size_t>(end - value_));
2312
+
2313
+ // Make sure that end quote is present
2314
+ if (*text != quote)
2315
+ CEREAL_RAPIDXML_PARSE_ERROR("expected ' or \"", text);
2316
+ ++text; // Skip quote
2317
+
2318
+ // Add terminating zero after value
2319
+ if (!(Flags & parse_no_string_terminators))
2320
+ attribute->value()[attribute->value_size()] = 0;
2321
+
2322
+ // Skip whitespace after attribute value
2323
+ skip<whitespace_pred, Flags>(text);
2324
+ }
2325
+ }
2326
+
2327
+ };
2328
+
2329
+ //! \cond internal
2330
+ namespace internal
2331
+ {
2332
+
2333
+ // Whitespace (space \n \r \t)
2334
+ template<int Dummy>
2335
+ const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] =
2336
+ {
2337
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2338
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0
2339
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
2340
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
2341
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
2342
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
2343
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
2344
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
2345
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
2346
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
2347
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
2348
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
2349
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
2350
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
2351
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
2352
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
2353
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
2354
+ };
2355
+
2356
+ // Node name (anything but space \n \r \t / > ? \0)
2357
+ template<int Dummy>
2358
+ const unsigned char lookup_tables<Dummy>::lookup_node_name[256] =
2359
+ {
2360
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2361
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
2362
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2363
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
2364
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3
2365
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2366
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2367
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2368
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2369
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2370
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2371
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2372
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2373
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2374
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2375
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2376
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2377
+ };
2378
+
2379
+ // Text (i.e. PCDATA) (anything but < \0)
2380
+ template<int Dummy>
2381
+ const unsigned char lookup_tables<Dummy>::lookup_text[256] =
2382
+ {
2383
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2384
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2385
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2386
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2387
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
2388
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2389
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2390
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2391
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2392
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2393
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2394
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2395
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2396
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2397
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2398
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2399
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2400
+ };
2401
+
2402
+ // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled
2403
+ // (anything but < \0 &)
2404
+ template<int Dummy>
2405
+ const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] =
2406
+ {
2407
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2408
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2409
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2410
+ 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2411
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
2412
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2413
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2414
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2415
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2416
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2417
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2418
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2419
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2420
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2421
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2422
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2423
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2424
+ };
2425
+
2426
+ // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled
2427
+ // (anything but < \0 & space \n \r \t)
2428
+ template<int Dummy>
2429
+ const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] =
2430
+ {
2431
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2432
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
2433
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2434
+ 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2435
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
2436
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2437
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2438
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2439
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2440
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2441
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2442
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2443
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2444
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2445
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2446
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2447
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2448
+ };
2449
+
2450
+ // Attribute name (anything but space \n \r \t / < > = ? ! \0)
2451
+ template<int Dummy>
2452
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] =
2453
+ {
2454
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2455
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
2456
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2457
+ 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
2458
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3
2459
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2460
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2461
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2462
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2463
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2464
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2465
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2466
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2467
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2468
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2469
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2470
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2471
+ };
2472
+
2473
+ // Attribute data with single quote (anything but ' \0)
2474
+ template<int Dummy>
2475
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] =
2476
+ {
2477
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2478
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2479
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2480
+ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2481
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
2482
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2483
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2484
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2485
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2486
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2487
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2488
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2489
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2490
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2491
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2492
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2493
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2494
+ };
2495
+
2496
+ // Attribute data with single quote that does not require processing (anything but ' \0 &)
2497
+ template<int Dummy>
2498
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] =
2499
+ {
2500
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2501
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2502
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2503
+ 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2504
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
2505
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2506
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2507
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2508
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2509
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2510
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2511
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2512
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2513
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2514
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2515
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2516
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2517
+ };
2518
+
2519
+ // Attribute data with double quote (anything but " \0)
2520
+ template<int Dummy>
2521
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] =
2522
+ {
2523
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2524
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2525
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2526
+ 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2527
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
2528
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2529
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2530
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2531
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2532
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2533
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2534
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2535
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2536
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2537
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2538
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2539
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2540
+ };
2541
+
2542
+ // Attribute data with double quote that does not require processing (anything but " \0 &)
2543
+ template<int Dummy>
2544
+ const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] =
2545
+ {
2546
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2547
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2548
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2549
+ 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2550
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
2551
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2552
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2553
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2554
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2555
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2556
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2557
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2558
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2559
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2560
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2561
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2562
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2563
+ };
2564
+
2565
+ // Digits (dec and hex, 255 denotes end of numeric character reference)
2566
+ template<int Dummy>
2567
+ const unsigned char lookup_tables<Dummy>::lookup_digits[256] =
2568
+ {
2569
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2570
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 0
2571
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 1
2572
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 2
2573
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,255,255,255,255,255,255, // 3
2574
+ 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 4
2575
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 5
2576
+ 255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255, // 6
2577
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 7
2578
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 8
2579
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // 9
2580
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // A
2581
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // B
2582
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // C
2583
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // D
2584
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, // E
2585
+ 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 // F
2586
+ };
2587
+
2588
+ // Upper case conversion
2589
+ template<int Dummy>
2590
+ const unsigned char lookup_tables<Dummy>::lookup_upcase[256] =
2591
+ {
2592
+ // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F
2593
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0
2594
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1
2595
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2
2596
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3
2597
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4
2598
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5
2599
+ 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6
2600
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127, // 7
2601
+ 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, // 8
2602
+ 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159, // 9
2603
+ 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175, // A
2604
+ 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191, // B
2605
+ 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207, // C
2606
+ 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223, // D
2607
+ 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239, // E
2608
+ 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255 // F
2609
+ };
2610
+ }
2611
+ //! \endcond
2612
+
2613
+ }
2614
+ } // end namespace cereal
2615
+
2616
+ // Undefine internal macros
2617
+ #undef CEREAL_RAPIDXML_PARSE_ERROR
2618
+
2619
+ // On MSVC, restore warnings state
2620
+ #ifdef _MSC_VER
2621
+ #pragma warning(pop)
2622
+ #endif
2623
+
2624
+ #endif