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
parse_error(const char * what_,void * where_)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.
what() const88         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>
where() const97         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>
measure(const Ch * p)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>
compare(const Ch * p1,std::size_t size1,const Ch * p2,std::size_t size2,bool case_sensitive)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>
preserve_space(xml_node<Ch> * node)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.
memory_pool()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.
~memory_pool()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.
allocate_node(node_type type,const Ch * name=0,const Ch * value=0,std::size_t name_size=0,std::size_t value_size=0)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.
allocate_attribute(const Ch * name=0,const Ch * value=0,std::size_t name_size=0,std::size_t value_size=0)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.
allocate_string(const Ch * source=0,std::size_t size=0)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.
clone_node(const xml_node<Ch> * source,xml_node<Ch> * result=0)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.
clear()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
set_allocator(alloc_func * af,free_func * ff)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 
init()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 
align(char * ptr)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 
allocate_raw(std::size_t size)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 
allocate_aligned(std::size_t size)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
xml_base()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.
name() const686         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.
name_size() const694         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.
value() const705         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.
value_size() const713         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.
name(const Ch * name_,std::size_t size)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.
name(const Ch * name_)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.
value(const Ch * value_,std::size_t size)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.
value(const Ch * value_)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.
parent() const783         xml_node<Ch> *parent() const
784         {
785             return m_parent;
786         }
787 
788     protected:
789 
790         // Return empty string
nullstr()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.
xml_attribute()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.
document() const832         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.
previous_attribute(const Ch * name=0,std::size_t name_size=0,bool case_sensitive=true) const849         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.
next_attribute(const Ch * name_=0,std::size_t name_size_=0,bool case_sensitive=true) const869         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.
xml_node(node_type type_)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.
type() const926         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.
document() const936         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.
first_node(const Ch * name_=0,std::size_t name_size_=0,bool case_sensitive=true) const949         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.
last_node(const Ch * name=0,std::size_t name_size=0,bool case_sensitive=true) const971         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.
previous_sibling(const Ch * name=0,std::size_t name_size=0,bool case_sensitive=true) const994         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.
next_sibling(const Ch * name_=0,std::size_t name_size_=0,bool case_sensitive=true) const1017         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.
first_attribute(const Ch * name_=0,std::size_t name_size_=0,bool case_sensitive=true) const1038         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.
last_attribute(const Ch * name=0,std::size_t name_size=0,bool case_sensitive=true) const1058         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.
type(node_type type_)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.
prepend_node(xml_node<Ch> * child)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.
append_node(xml_node<Ch> * child)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.
insert_node(xml_node<Ch> * where,xml_node<Ch> * child)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.
remove_first_node()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.
remove_last_node()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.
remove_node(xml_node<Ch> * where)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).
remove_all_nodes()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.
prepend_attribute(xml_attribute<Ch> * attribute)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.
append_attribute(xml_attribute<Ch> * attribute)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.
insert_attribute(xml_attribute<Ch> * where,xml_attribute<Ch> * attribute)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.
remove_first_attribute()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.
remove_last_attribute()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.
remove_attribute(xml_attribute<Ch> * where)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.
remove_all_attributes()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
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>
parse(Ch * text)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.
clear()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         {
testcereal::rapidxml::xml_document::whitespace_pred1443             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         {
testcereal::rapidxml::xml_document::node_name_pred1452             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         {
testcereal::rapidxml::xml_document::attribute_name_pred1461             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         {
testcereal::rapidxml::xml_document::text_pred1470             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         {
testcereal::rapidxml::xml_document::text_pure_no_ws_pred1479             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         {
testcereal::rapidxml::xml_document::text_pure_with_ws_pred1488             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         {
testcereal::rapidxml::xml_document::attribute_value_pred1498             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         {
testcereal::rapidxml::xml_document::attribute_value_pure_pred1512             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>
insert_coded_character(Ch * & text,unsigned long code)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>
skip(Ch * & text)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>
skip_and_expand_character_refs(Ch * & text,bool preserve_space)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>
parse_bom(Ch * & text)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>
parse_xml_declaration(Ch * & text)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>
parse_comment(Ch * & text)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>
parse_doctype(Ch * & text)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>
parse_pi(Ch * & text)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>
parse_and_append_data(xml_node<Ch> * node,Ch * & text,Ch * contents_start)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>
parse_cdata(Ch * & text)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>
parse_element(Ch * & text)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>
parse_node(Ch * & text)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>
parse_node_contents(Ch * & text,xml_node<Ch> * node)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>
parse_node_attributes(Ch * & text,xml_node<Ch> * node)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
2625