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