Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:50:17

0001 // ----------------------------------------------------------------------------
0002 // Copyright (C) 2006, 2009 Marcin Kalicinski
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. 
0005 // (See accompanying file LICENSE_1_0.txt or copy at 
0006 // http://www.boost.org/LICENSE_1_0.txt)
0007 //
0008 // For more information, see www.boost.org
0009 // ----------------------------------------------------------------------------
0010 #ifndef BOOST_PROPERTY_TREE_RAPIDXML_HPP_INCLUDED
0011 #define BOOST_PROPERTY_TREE_RAPIDXML_HPP_INCLUDED
0012 
0013 //! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation
0014 
0015 #include <boost/config.hpp>
0016 #include <boost/assert.hpp>
0017 #include <cstddef>      // For std::size_t
0018 #include <new>          // For placement new
0019 
0020 // On MSVC, disable "conditional expression is constant" warning (level 4). 
0021 // This warning is almost impossible to avoid with certain types of templated code
0022 #ifdef _MSC_VER
0023     #pragma warning(push)
0024     #pragma warning(disable:4127)   // Conditional expression is constant
0025 #endif
0026 
0027 ///////////////////////////////////////////////////////////////////////////
0028 // BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR
0029     
0030 #include <exception>    // For std::exception
0031 
0032 #define BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where)
0033 
0034 namespace boost { namespace property_tree { namespace detail {namespace rapidxml
0035 {
0036 
0037     //! Parse error exception. 
0038     //! This exception is thrown by the parser when an error occurs. 
0039     //! Use what() function to get human-readable error message. 
0040     //! Use where() function to get a pointer to position within source text where error was detected.
0041     //! <br><br>
0042     //! If throwing exceptions by the parser is undesirable, 
0043     //! it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro before rapidxml.hpp is included.
0044     //! This will cause the parser to call rapidxml::parse_error_handler() function instead of throwing an exception.
0045     //! This function must be defined by the user.
0046     //! <br><br>
0047     //! This class derives from <code>std::exception</code> class.
0048     class parse_error: public std::exception
0049     {
0050     
0051     public:
0052     
0053         //! Constructs parse error
0054         parse_error(const char *wa, void *we)
0055             : m_what(wa)
0056             , m_where(we)
0057         {
0058         }
0059 
0060         //! Gets human readable description of error.
0061         //! \return Pointer to null terminated description of the error.
0062         const char *what() const throw() BOOST_OVERRIDE
0063         {
0064             return m_what;
0065         }
0066 
0067         //! Gets pointer to character data where error happened.
0068         //! Ch should be the same as char type of xml_document that produced the error.
0069         //! \return Pointer to location within the parsed string where error occurred.
0070         template<class Ch>
0071         Ch *where() const
0072         {
0073             return reinterpret_cast<Ch *>(m_where);
0074         }
0075 
0076     private:  
0077 
0078         const char *m_what;
0079         void *m_where;
0080 
0081     };
0082 }}}}
0083 
0084 ///////////////////////////////////////////////////////////////////////////
0085 // Pool sizes
0086 
0087 #ifndef BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE
0088     // Size of static memory block of memory_pool.
0089     // Define BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
0090     // No dynamic memory allocations are performed by memory_pool until static memory is exhausted.
0091     #define BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
0092 #endif
0093 
0094 #ifndef BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE
0095     // Size of dynamic memory block of memory_pool.
0096     // Define BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
0097     // After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool.
0098     #define BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
0099 #endif
0100 
0101 #ifndef BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT
0102     // Memory allocation alignment.
0103     // Define BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size of pointer.
0104     // All memory allocations for nodes, attributes and strings will be aligned to this value.
0105     // This must be a power of 2 and at least 1, otherwise memory_pool will not work.
0106     #define BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT sizeof(void *)
0107 #endif
0108 
0109 namespace boost { namespace property_tree { namespace detail {namespace rapidxml
0110 {
0111     // Forward declarations
0112     template<class Ch> class xml_node;
0113     template<class Ch> class xml_attribute;
0114     template<class Ch> class xml_document;
0115     
0116     //! Enumeration listing all node types produced by the parser.
0117     //! Use xml_node::type() function to query node type.
0118     enum node_type
0119     {
0120         node_document,      //!< A document node. Name and value are empty.
0121         node_element,       //!< An element node. Name contains element name. Value contains text of first data node.
0122         node_data,          //!< A data node. Name is empty. Value contains data text.
0123         node_cdata,         //!< A CDATA node. Name is empty. Value contains data text.
0124         node_comment,       //!< A comment node. Name is empty. Value contains comment text.
0125         node_declaration,   //!< A declaration node. Name and value are empty. Declaration parameters (version, encoding and standalone) are in node attributes.
0126         node_doctype,       //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
0127         node_pi             //!< A PI node. Name contains target. Value contains instructions.
0128     };
0129 
0130     ///////////////////////////////////////////////////////////////////////
0131     // Parsing flags
0132 
0133     //! Parse flag instructing the parser to not create data nodes. 
0134     //! Text of first data node will still be placed in value of parent element, unless rapidxml::parse_no_element_values flag is also specified.
0135     //! Can be combined with other flags by use of | operator.
0136     //! <br><br>
0137     //! See xml_document::parse() function.
0138     const int parse_no_data_nodes = 0x1;            
0139 
0140     //! Parse flag instructing the parser to not use text of first data node as a value of parent element.
0141     //! Can be combined with other flags by use of | operator.
0142     //! Note that child data nodes of element node take precedence over its value when printing.
0143     //! That is, if element has one or more child data nodes <em>and</em> a value, the value will be ignored.
0144     //! Use rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you want to manipulate data using values of elements.
0145     //! <br><br>
0146     //! See xml_document::parse() function.
0147     const int parse_no_element_values = 0x2;
0148     
0149     //! Parse flag instructing the parser to not place zero terminators after strings in the source text.
0150     //! By default zero terminators are placed, modifying source text.
0151     //! Can be combined with other flags by use of | operator.
0152     //! <br><br>
0153     //! See xml_document::parse() function.
0154     const int parse_no_string_terminators = 0x4;
0155     
0156     //! Parse flag instructing the parser to not translate entities in the source text.
0157     //! By default entities are translated, modifying source text.
0158     //! Can be combined with other flags by use of | operator.
0159     //! <br><br>
0160     //! See xml_document::parse() function.
0161     const int parse_no_entity_translation = 0x8;
0162     
0163     //! Parse flag instructing the parser to disable UTF-8 handling and assume plain 8 bit characters.
0164     //! By default, UTF-8 handling is enabled.
0165     //! Can be combined with other flags by use of | operator.
0166     //! <br><br>
0167     //! See xml_document::parse() function.
0168     const int parse_no_utf8 = 0x10;
0169     
0170     //! Parse flag instructing the parser to create XML declaration node.
0171     //! By default, declaration node is not created.
0172     //! Can be combined with other flags by use of | operator.
0173     //! <br><br>
0174     //! See xml_document::parse() function.
0175     const int parse_declaration_node = 0x20;
0176     
0177     //! Parse flag instructing the parser to create comments nodes.
0178     //! By default, comment nodes are not created.
0179     //! Can be combined with other flags by use of | operator.
0180     //! <br><br>
0181     //! See xml_document::parse() function.
0182     const int parse_comment_nodes = 0x40;
0183     
0184     //! Parse flag instructing the parser to create DOCTYPE node.
0185     //! By default, doctype node is not created.
0186     //! Although W3C specification allows at most one DOCTYPE node, RapidXml will silently accept documents with more than one.
0187     //! Can be combined with other flags by use of | operator.
0188     //! <br><br>
0189     //! See xml_document::parse() function.
0190     const int parse_doctype_node = 0x80;
0191     
0192     //! Parse flag instructing the parser to create PI nodes.
0193     //! By default, PI nodes are not created.
0194     //! Can be combined with other flags by use of | operator.
0195     //! <br><br>
0196     //! See xml_document::parse() function.
0197     const int parse_pi_nodes = 0x100;
0198     
0199     //! Parse flag instructing the parser to validate closing tag names. 
0200     //! If not set, name inside closing tag is irrelevant to the parser.
0201     //! By default, closing tags are not validated.
0202     //! Can be combined with other flags by use of | operator.
0203     //! <br><br>
0204     //! See xml_document::parse() function.
0205     const int parse_validate_closing_tags = 0x200;
0206     
0207     //! Parse flag instructing the parser to trim all leading and trailing whitespace of data nodes.
0208     //! By default, whitespace is not trimmed. 
0209     //! This flag does not cause the parser to modify source text.
0210     //! Can be combined with other flags by use of | operator.
0211     //! <br><br>
0212     //! See xml_document::parse() function.
0213     const int parse_trim_whitespace = 0x400;
0214 
0215     //! Parse flag instructing the parser to condense all whitespace runs of data nodes to a single space character.
0216     //! Trimming of leading and trailing whitespace of data is controlled by rapidxml::parse_trim_whitespace flag.
0217     //! By default, whitespace is not normalized. 
0218     //! If this flag is specified, source text will be modified.
0219     //! Can be combined with other flags by use of | operator.
0220     //! <br><br>
0221     //! See xml_document::parse() function.
0222     const int parse_normalize_whitespace = 0x800;
0223 
0224     // Compound flags
0225     
0226     //! Parse flags which represent default behaviour of the parser. 
0227     //! This is always equal to 0, so that all other flags can be simply ored together.
0228     //! Normally there is no need to inconveniently disable flags by anding with their negated (~) values.
0229     //! This also means that meaning of each flag is a <i>negation</i> of the default setting. 
0230     //! For example, if flag name is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by default,
0231     //! and using the flag will disable it.
0232     //! <br><br>
0233     //! See xml_document::parse() function.
0234     const int parse_default = 0;
0235     
0236     //! A combination of parse flags that forbids any modifications of the source text. 
0237     //! This also results in faster parsing. However, note that the following will occur:
0238     //! <ul>
0239     //! <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>
0240     //! <li>entities will not be translated</li>
0241     //! <li>whitespace will not be normalized</li>
0242     //! </ul>
0243     //! See xml_document::parse() function.
0244     const int parse_non_destructive = parse_no_string_terminators | parse_no_entity_translation;
0245     
0246     //! A combination of parse flags resulting in fastest possible parsing, without sacrificing important data.
0247     //! <br><br>
0248     //! See xml_document::parse() function.
0249     const int parse_fastest = parse_non_destructive | parse_no_data_nodes;
0250     
0251     //! A combination of parse flags resulting in largest amount of data being extracted. 
0252     //! This usually results in slowest parsing.
0253     //! <br><br>
0254     //! See xml_document::parse() function.
0255     const int parse_full = parse_declaration_node | parse_comment_nodes | parse_doctype_node | parse_pi_nodes | parse_validate_closing_tags;
0256 
0257     ///////////////////////////////////////////////////////////////////////
0258     // Internals
0259 
0260     //! \cond internal
0261     namespace internal
0262     {
0263 
0264         // Struct that contains lookup tables for the parser
0265         // It must be a template to allow correct linking (because it has static data members, which are defined in a header file).
0266         template<int Dummy>
0267         struct lookup_tables
0268         {
0269             static const unsigned char lookup_whitespace[256];              // Whitespace table
0270             static const unsigned char lookup_node_name[256];               // Node name table
0271             static const unsigned char lookup_text[256];                    // Text table
0272             static const unsigned char lookup_text_pure_no_ws[256];         // Text table
0273             static const unsigned char lookup_text_pure_with_ws[256];       // Text table
0274             static const unsigned char lookup_attribute_name[256];          // Attribute name table
0275             static const unsigned char lookup_attribute_data_1[256];        // Attribute data table with single quote
0276             static const unsigned char lookup_attribute_data_1_pure[256];   // Attribute data table with single quote
0277             static const unsigned char lookup_attribute_data_2[256];        // Attribute data table with double quotes
0278             static const unsigned char lookup_attribute_data_2_pure[256];   // Attribute data table with double quotes
0279             static const unsigned char lookup_digits[256];                  // Digits
0280             static const unsigned char lookup_upcase[256];                  // To uppercase conversion table for ASCII characters
0281         };
0282 
0283         // Find length of the string
0284         template<class Ch>
0285         inline std::size_t measure(const Ch *p)
0286         {
0287             const Ch *tmp = p;
0288             while (*tmp) 
0289                 ++tmp;
0290             return tmp - p;
0291         }
0292 
0293         // Compare strings for equality
0294         template<class Ch>
0295         inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2, std::size_t size2, bool case_sensitive)
0296         {
0297             if (size1 != size2)
0298                 return false;
0299             if (case_sensitive)
0300             {
0301                 for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
0302                     if (*p1 != *p2)
0303                         return false;
0304             }
0305             else
0306             {
0307                 for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
0308                     if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] != lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)])
0309                         return false;
0310             }
0311             return true;
0312         }
0313 
0314         template<class Ch>
0315         inline size_t get_index(const Ch c)
0316         {
0317             // If not ASCII char, its semantic is same as plain 'z'.
0318             // char could be signed, so first stretch and make unsigned.
0319             unsigned n = c;
0320             if (n > 127)
0321             {
0322                 return 'z';
0323             }
0324             return c;
0325         }
0326     }
0327     //! \endcond
0328 
0329     ///////////////////////////////////////////////////////////////////////
0330     // Memory pool
0331     
0332     //! This class is used by the parser to create new nodes and attributes, without overheads of dynamic memory allocation.
0333     //! In most cases, you will not need to use this class directly. 
0334     //! However, if you need to create nodes manually or modify names/values of nodes, 
0335     //! you are encouraged to use memory_pool of relevant xml_document to allocate the memory. 
0336     //! Not only is this faster than allocating them by using <code>new</code> operator, 
0337     //! but also their lifetime will be tied to the lifetime of document, 
0338     //! possibly simplifying memory management.
0339     //! <br><br>
0340     //! Call allocate_node() or allocate_attribute() functions to obtain new nodes or attributes from the pool. 
0341     //! You can also call allocate_string() function to allocate strings.
0342     //! Such strings can then be used as names or values of nodes without worrying about their lifetime.
0343     //! Note that there is no <code>free()</code> function -- all allocations are freed at once when clear() function is called, 
0344     //! or when the pool is destroyed.
0345     //! <br><br>
0346     //! It is also possible to create a standalone memory_pool, and use it 
0347     //! to allocate nodes, whose lifetime will not be tied to any document.
0348     //! <br><br>
0349     //! Pool maintains <code>BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically allocated memory. 
0350     //! Until static memory is exhausted, no dynamic memory allocations are done.
0351     //! When static memory is exhausted, pool allocates additional blocks of memory of size <code>BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE</code> each,
0352     //! by using global <code>new[]</code> and <code>delete[]</code> operators. 
0353     //! This behaviour can be changed by setting custom allocation routines. 
0354     //! Use set_allocator() function to set them.
0355     //! <br><br>
0356     //! Allocations for nodes, attributes and strings are aligned at <code>BOOST_PROPERTY_TREE_RAPIDXML_ALIGNMENT</code> bytes.
0357     //! This value defaults to the size of pointer on target architecture.
0358     //! <br><br>
0359     //! To obtain absolutely top performance from the parser,
0360     //! it is important that all nodes are allocated from a single, contiguous block of memory.
0361     //! Otherwise, cache misses when jumping between two (or more) disjoint blocks of memory can slow down parsing quite considerably.
0362     //! 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> 
0363     //! to obtain best wasted memory to performance compromise.
0364     //! To do it, define their values before rapidxml.hpp file is included.
0365     //! \param Ch Character type of created nodes. 
0366     template<class Ch = char>
0367     class memory_pool
0368     {
0369         
0370     public:
0371 
0372         //! \cond internal
0373         // Prefixed names to work around weird MSVC lookup bug.
0374         typedef void *(boost_ptree_raw_alloc_func)(std::size_t);       // Type of user-defined function used to allocate memory
0375         typedef void (boost_ptree_raw_free_func)(void *);              // Type of user-defined function used to free memory
0376         //! \endcond
0377         
0378         //! Constructs empty pool with default allocator functions.
0379         memory_pool()
0380             : m_alloc_func(0)
0381             , m_free_func(0)
0382         {
0383             init();
0384         }
0385 
0386         //! Destroys pool and frees all the memory. 
0387         //! This causes memory occupied by nodes allocated by the pool to be freed.
0388         //! Nodes allocated from the pool are no longer valid.
0389         ~memory_pool()
0390         {
0391             clear();
0392         }
0393 
0394         //! Allocates a new node from the pool, and optionally assigns name and value to it. 
0395         //! If the allocation request cannot be accommodated, this function will throw <code>std::bad_alloc</code>.
0396         //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
0397         //! will call rapidxml::parse_error_handler() function.
0398         //! \param type Type of node to create.
0399         //! \param name Name to assign to the node, or 0 to assign no name.
0400         //! \param value Value to assign to the node, or 0 to assign no value.
0401         //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
0402         //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
0403         //! \return Pointer to allocated node. This pointer will never be NULL.
0404         xml_node<Ch> *allocate_node(node_type type, 
0405                                     const Ch *name = 0, const Ch *value = 0, 
0406                                     std::size_t name_size = 0, std::size_t value_size = 0)
0407         {
0408             void *memory = allocate_aligned(sizeof(xml_node<Ch>));
0409             xml_node<Ch> *node = new(memory) xml_node<Ch>(type);
0410             if (name)
0411             {
0412                 if (name_size > 0)
0413                     node->name(name, name_size);
0414                 else
0415                     node->name(name);
0416             }
0417             if (value)
0418             {
0419                 if (value_size > 0)
0420                     node->value(value, value_size);
0421                 else
0422                     node->value(value);
0423             }
0424             return node;
0425         }
0426 
0427         //! Allocates a new attribute from the pool, and optionally assigns name and value to it.
0428         //! If the allocation request cannot be accommodated, this function will throw <code>std::bad_alloc</code>.
0429         //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
0430         //! will call rapidxml::parse_error_handler() function.
0431         //! \param name Name to assign to the attribute, or 0 to assign no name.
0432         //! \param value Value to assign to the attribute, or 0 to assign no value.
0433         //! \param name_size Size of name to assign, or 0 to automatically calculate size from name string.
0434         //! \param value_size Size of value to assign, or 0 to automatically calculate size from value string.
0435         //! \return Pointer to allocated attribute. This pointer will never be NULL.
0436         xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0, 
0437                                               std::size_t name_size = 0, std::size_t value_size = 0)
0438         {
0439             void *memory = allocate_aligned(sizeof(xml_attribute<Ch>));
0440             xml_attribute<Ch> *attribute = new(memory) xml_attribute<Ch>;
0441             if (name)
0442             {
0443                 if (name_size > 0)
0444                     attribute->name(name, name_size);
0445                 else
0446                     attribute->name(name);
0447             }
0448             if (value)
0449             {
0450                 if (value_size > 0)
0451                     attribute->value(value, value_size);
0452                 else
0453                     attribute->value(value);
0454             }
0455             return attribute;
0456         }
0457 
0458         //! Allocates a char array of given size from the pool, and optionally copies a given string to it.
0459         //! If the allocation request cannot be accommodated, this function will throw <code>std::bad_alloc</code>.
0460         //! If exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS, this function
0461         //! will call rapidxml::parse_error_handler() function.
0462         //! \param source String to initialize the allocated memory with, or 0 to not initialize it.
0463         //! \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.
0464         //! \return Pointer to allocated char array. This pointer will never be NULL.
0465         Ch *allocate_string(const Ch *source = 0, std::size_t size = 0)
0466         {
0467             BOOST_ASSERT(source || size);     // Either source or size (or both) must be specified
0468             if (size == 0)
0469                 size = internal::measure(source) + 1;
0470             Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch)));
0471             if (source)
0472                 for (std::size_t i = 0; i < size; ++i)
0473                     result[i] = source[i];
0474             return result;
0475         }
0476 
0477         //! Clones an xml_node and its hierarchy of child nodes and attributes.
0478         //! Nodes and attributes are allocated from this memory pool.
0479         //! Names and values are not cloned, they are shared between the clone and the source.
0480         //! Result node can be optionally specified as a second parameter, 
0481         //! in which case its contents will be replaced with cloned source node.
0482         //! This is useful when you want to clone entire document.
0483         //! \param source Node to clone.
0484         //! \param result Node to put results in, or 0 to automatically allocate result node
0485         //! \return Pointer to cloned node. This pointer will never be NULL.
0486         xml_node<Ch> *clone_node(const xml_node<Ch> *source, xml_node<Ch> *result = 0)
0487         {
0488             // Prepare result node
0489             if (result)
0490             {
0491                 result->remove_all_attributes();
0492                 result->remove_all_nodes();
0493                 result->type(source->type());
0494             }
0495             else
0496                 result = allocate_node(source->type());
0497 
0498             // Clone name and value
0499             result->name(source->name(), source->name_size());
0500             result->value(source->value(), source->value_size());
0501 
0502             // Clone child nodes and attributes
0503             for (xml_node<Ch> *child = source->first_node(); child; child = child->next_sibling())
0504                 result->append_node(clone_node(child));
0505             for (xml_attribute<Ch> *attr = source->first_attribute(); attr; attr = attr->next_attribute())
0506                 result->append_attribute(allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size()));
0507 
0508             return result;
0509         }
0510 
0511         //! Clears the pool. 
0512         //! This causes memory occupied by nodes allocated by the pool to be freed.
0513         //! Any nodes or strings allocated from the pool will no longer be valid.
0514         void clear()
0515         {
0516             while (m_begin != m_static_memory)
0517             {
0518                 char *previous_begin = reinterpret_cast<header *>(align(m_begin))->previous_begin;
0519                 if (m_free_func)
0520                     m_free_func(m_begin);
0521                 else
0522                     delete[] m_begin;
0523                 m_begin = previous_begin;
0524             }
0525             init();
0526         }
0527 
0528         //! Sets or resets the user-defined memory allocation functions for the pool.
0529         //! This can only be called when no memory is allocated from the pool yet, otherwise results are undefined.
0530         //! Allocation function must not return invalid pointer on failure. It should either throw,
0531         //! stop the program, or use <code>longjmp()</code> function to pass control to other place of program. 
0532         //! If it returns invalid pointer, results are undefined.
0533         //! <br><br>
0534         //! User defined allocation functions must have the following forms:
0535         //! <br><code>
0536         //! <br>void *allocate(std::size_t size);
0537         //! <br>void free(void *pointer);
0538         //! </code><br>
0539         //! \param af Allocation function, or 0 to restore default function
0540         //! \param ff Free function, or 0 to restore default function
0541         void set_allocator(boost_ptree_raw_alloc_func *af, boost_ptree_raw_free_func *ff)
0542         {
0543             BOOST_ASSERT(m_begin == m_static_memory && m_ptr == align(m_begin));    // Verify that no memory is allocated yet
0544             m_alloc_func = af;
0545             m_free_func = ff;
0546         }
0547 
0548     private:
0549 
0550         struct header
0551         {
0552             char *previous_begin;
0553         };
0554 
0555         void init()
0556         {
0557             m_begin = m_static_memory;
0558             m_ptr = align(m_begin);
0559             m_end = m_static_memory + sizeof(m_static_memory);
0560         }
0561         
0562         char *align(char *ptr)
0563         {
0564             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));
0565             return ptr + alignment;
0566         }
0567         
0568         char *allocate_raw(std::size_t size)
0569         {
0570             // Allocate
0571             void *memory;   
0572             if (m_alloc_func)   // Allocate memory using either user-specified allocation function or global operator new[]
0573             {
0574                 memory = m_alloc_func(size);
0575                 BOOST_ASSERT(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the program or use longjmp
0576             }
0577             else
0578             {
0579                 memory = new char[size];
0580             }
0581             return static_cast<char *>(memory);
0582         }
0583         
0584         void *allocate_aligned(std::size_t size)
0585         {
0586             // Calculate aligned pointer
0587             char *result = align(m_ptr);
0588 
0589             // If not enough memory left in current pool, allocate a new pool
0590             if (result + size > m_end)
0591             {
0592                 // Calculate required pool size (may be bigger than BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE)
0593                 std::size_t pool_size = BOOST_PROPERTY_TREE_RAPIDXML_DYNAMIC_POOL_SIZE;
0594                 if (pool_size < size)
0595                     pool_size = size;
0596                 
0597                 // Allocate
0598                 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
0599                 char *raw_memory = allocate_raw(alloc_size);
0600                     
0601                 // Setup new pool in allocated memory
0602                 char *pool = align(raw_memory);
0603                 header *new_header = reinterpret_cast<header *>(pool);
0604                 new_header->previous_begin = m_begin;
0605                 m_begin = raw_memory;
0606                 m_ptr = pool + sizeof(header);
0607                 m_end = raw_memory + alloc_size;
0608 
0609                 // Calculate aligned pointer again using new pool
0610                 result = align(m_ptr);
0611             }
0612 
0613             // Update pool and return aligned pointer
0614             m_ptr = result + size;
0615             return result;
0616         }
0617 
0618         char *m_begin;                                      // Start of raw memory making up current pool
0619         char *m_ptr;                                        // First free byte in current pool
0620         char *m_end;                                        // One past last available byte in current pool
0621         char m_static_memory[BOOST_PROPERTY_TREE_RAPIDXML_STATIC_POOL_SIZE];    // Static raw memory
0622         boost_ptree_raw_alloc_func *m_alloc_func;           // Allocator function, or 0 if default is to be used
0623         boost_ptree_raw_free_func *m_free_func;             // Free function, or 0 if default is to be used
0624     };
0625 
0626     ///////////////////////////////////////////////////////////////////////////
0627     // XML base
0628 
0629     //! Base class for xml_node and xml_attribute implementing common functions: 
0630     //! name(), name_size(), value(), value_size() and parent().
0631     //! \param Ch Character type to use
0632     template<class Ch = char>
0633     class xml_base
0634     {
0635 
0636     public:
0637         
0638         ///////////////////////////////////////////////////////////////////////////
0639         // Construction & destruction
0640     
0641         // Construct a base with empty name, value and parent
0642         xml_base()
0643             : m_name(0)
0644             , m_value(0)
0645             , m_parent(0)
0646         {
0647         }
0648 
0649         ///////////////////////////////////////////////////////////////////////////
0650         // Node data access
0651     
0652         //! Gets name of the node. 
0653         //! Interpretation of name depends on type of node.
0654         //! Note that name will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
0655         //! <br><br>
0656         //! Use name_size() function to determine length of the name.
0657         //! \return Name of node, or empty string if node has no name.
0658         Ch *name() const
0659         {
0660             return m_name ? m_name : nullstr();
0661         }
0662 
0663         //! Gets size of node name, not including terminator character.
0664         //! This function works correctly irrespective of whether name is or is not zero terminated.
0665         //! \return Size of node name, in characters.
0666         std::size_t name_size() const
0667         {
0668             return m_name ? m_name_size : 0;
0669         }
0670 
0671         //! Gets value of node. 
0672         //! Interpretation of value depends on type of node.
0673         //! Note that value will not be zero-terminated if rapidxml::parse_no_string_terminators option was selected during parse.
0674         //! <br><br>
0675         //! Use value_size() function to determine length of the value.
0676         //! \return Value of node, or empty string if node has no value.
0677         Ch *value() const
0678         {
0679             return m_value ? m_value : nullstr();
0680         }
0681 
0682         //! Gets size of node value, not including terminator character.
0683         //! This function works correctly irrespective of whether value is or is not zero terminated.
0684         //! \return Size of node value, in characters.
0685         std::size_t value_size() const
0686         {
0687             return m_value ? m_value_size : 0;
0688         }
0689 
0690         ///////////////////////////////////////////////////////////////////////////
0691         // Node modification
0692     
0693         //! Sets name of node to a non zero-terminated string.
0694         //! See \ref ownership_of_strings.
0695         //! <br><br>
0696         //! Note that node does not own its name or value, it only stores a pointer to it. 
0697         //! It will not delete or otherwise free the pointer on destruction.
0698         //! It is responsibility of the user to properly manage lifetime of the string.
0699         //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
0700         //! on destruction of the document the string will be automatically freed.
0701         //! <br><br>
0702         //! Size of name must be specified separately, because name does not have to be zero terminated.
0703         //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).
0704         //! \param n Name of node to set. Does not have to be zero terminated.
0705         //! \param size Size of name, in characters. This does not include zero terminator, if one is present.
0706         void name(const Ch *n, std::size_t size)
0707         {
0708             m_name = const_cast<Ch *>(n);
0709             m_name_size = size;
0710         }
0711 
0712         //! Sets name of node to a zero-terminated string.
0713         //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t).
0714         //! \param n Name of node to set. Must be zero terminated.
0715         void name(const Ch *n)
0716         {
0717             name(n, internal::measure(n));
0718         }
0719 
0720         //! Sets value of node to a non zero-terminated string.
0721         //! See \ref ownership_of_strings.
0722         //! <br><br>
0723         //! Note that node does not own its name or value, it only stores a pointer to it. 
0724         //! It will not delete or otherwise free the pointer on destruction.
0725         //! It is responsibility of the user to properly manage lifetime of the string.
0726         //! The easiest way to achieve it is to use memory_pool of the document to allocate the string -
0727         //! on destruction of the document the string will be automatically freed.
0728         //! <br><br>
0729         //! Size of value must be specified separately, because it does not have to be zero terminated.
0730         //! Use value(const Ch *) function to have the length automatically calculated (string must be zero terminated).
0731         //! <br><br>
0732         //! If an element has a child node of type node_data, it will take precedence over element value when printing.
0733         //! 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.
0734         //! \param val Value of node to set. Does not have to be zero terminated.
0735         //! \param size Size of value, in characters. This does not include zero terminator, if one is present.
0736         void value(const Ch *val, std::size_t size)
0737         {
0738             m_value = const_cast<Ch *>(val);
0739             m_value_size = size;
0740         }
0741 
0742         //! Sets value of node to a zero-terminated string.
0743         //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t).
0744         //! \param val Name of node to set. Must be zero terminated.
0745         void value(const Ch *val)
0746         {
0747             this->value(val, internal::measure(val));
0748         }
0749 
0750         ///////////////////////////////////////////////////////////////////////////
0751         // Related nodes access
0752     
0753         //! Gets node parent.
0754         //! \return Pointer to parent node, or 0 if there is no parent.
0755         xml_node<Ch> *parent() const
0756         {
0757             return m_parent;
0758         }
0759 
0760     protected:
0761 
0762         // Return empty string
0763         static Ch *nullstr()
0764         {
0765             static Ch zero = Ch('\0');
0766             return &zero;
0767         }
0768 
0769         Ch *m_name;                         // Name of node, or 0 if no name
0770         Ch *m_value;                        // Value of node, or 0 if no value
0771         std::size_t m_name_size;            // Length of node name, or undefined of no name
0772         std::size_t m_value_size;           // Length of node value, or undefined if no value
0773         xml_node<Ch> *m_parent;             // Pointer to parent node, or 0 if none
0774 
0775     };
0776 
0777     //! Class representing attribute node of XML document. 
0778     //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base).
0779     //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing. 
0780     //! Thus, this text must persist in memory for the lifetime of attribute.
0781     //! \param Ch Character type to use.
0782     template<class Ch = char>
0783     class xml_attribute: public xml_base<Ch>
0784     {
0785 
0786         friend class xml_node<Ch>;
0787     
0788     public:
0789 
0790         ///////////////////////////////////////////////////////////////////////////
0791         // Construction & destruction
0792     
0793         //! Constructs an empty attribute with the specified type. 
0794         //! Consider using memory_pool of appropriate xml_document if allocating attributes manually.
0795         xml_attribute()
0796         {
0797         }
0798 
0799         ///////////////////////////////////////////////////////////////////////////
0800         // Related nodes access
0801     
0802         //! Gets document of which attribute is a child.
0803         //! \return Pointer to document that contains this attribute, or 0 if there is no parent document.
0804         xml_document<Ch> *document() const
0805         {
0806             if (xml_node<Ch> *node = this->parent())
0807             {
0808                 while (node->parent())
0809                     node = node->parent();
0810                 return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
0811             }
0812             else
0813                 return 0;
0814         }
0815 
0816         //! Gets previous attribute, optionally matching attribute name. 
0817         //! \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
0818         //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
0819         //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
0820         //! \return Pointer to found attribute, or 0 if not found.
0821         xml_attribute<Ch> *previous_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
0822         {
0823             if (n)
0824             {
0825                 if (nsize == 0)
0826                     nsize = internal::measure(n);
0827                 for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute; attribute = attribute->m_prev_attribute)
0828                     if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive))
0829                         return attribute;
0830                 return 0;
0831             }
0832             else
0833                 return this->m_parent ? m_prev_attribute : 0;
0834         }
0835 
0836         //! Gets next attribute, optionally matching attribute name. 
0837         //! \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
0838         //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
0839         //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
0840         //! \return Pointer to found attribute, or 0 if not found.
0841         xml_attribute<Ch> *next_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
0842         {
0843             if (n)
0844             {
0845                 if (nsize == 0)
0846                     nsize = internal::measure(n);
0847                 for (xml_attribute<Ch> *attribute = m_next_attribute; attribute; attribute = attribute->m_next_attribute)
0848                     if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive))
0849                         return attribute;
0850                 return 0;
0851             }
0852             else
0853                 return this->m_parent ? m_next_attribute : 0;
0854         }
0855 
0856     private:
0857 
0858         xml_attribute<Ch> *m_prev_attribute;        // Pointer to previous sibling of attribute, or 0 if none; only valid if parent is non-zero
0859         xml_attribute<Ch> *m_next_attribute;        // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero
0860     
0861     };
0862 
0863     ///////////////////////////////////////////////////////////////////////////
0864     // XML node
0865 
0866     //! Class representing a node of XML document. 
0867     //! Each node may have associated name and value strings, which are available through name() and value() functions. 
0868     //! Interpretation of name and value depends on type of the node.
0869     //! Type of node can be determined by using type() function.
0870     //! <br><br>
0871     //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing. 
0872     //! Thus, this text must persist in the memory for the lifetime of node.
0873     //! \param Ch Character type to use.
0874     template<class Ch = char>
0875     class xml_node: public xml_base<Ch>
0876     {
0877 
0878     public:
0879 
0880         ///////////////////////////////////////////////////////////////////////////
0881         // Construction & destruction
0882     
0883         //! Constructs an empty node with the specified type. 
0884         //! Consider using memory_pool of appropriate document to allocate nodes manually.
0885         //! \param t Type of node to construct.
0886         xml_node(node_type t)
0887             : m_type(t)
0888             , m_first_node(0)
0889             , m_first_attribute(0)
0890         {
0891         }
0892 
0893         ///////////////////////////////////////////////////////////////////////////
0894         // Node data access
0895     
0896         //! Gets type of node.
0897         //! \return Type of node.
0898         node_type type() const
0899         {
0900             return m_type;
0901         }
0902 
0903         ///////////////////////////////////////////////////////////////////////////
0904         // Related nodes access
0905     
0906         //! Gets document of which node is a child.
0907         //! \return Pointer to document that contains this node, or 0 if there is no parent document.
0908         xml_document<Ch> *document() const
0909         {
0910             xml_node<Ch> *node = const_cast<xml_node<Ch> *>(this);
0911             while (node->parent())
0912                 node = node->parent();
0913             return node->type() == node_document ? static_cast<xml_document<Ch> *>(node) : 0;
0914         }
0915 
0916         //! Gets first child node, optionally matching node name.
0917         //! \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
0918         //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
0919         //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
0920         //! \return Pointer to found child, or 0 if not found.
0921         xml_node<Ch> *first_node(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
0922         {
0923             if (n)
0924             {
0925                 if (nsize == 0)
0926                     nsize = internal::measure(n);
0927                 for (xml_node<Ch> *child = m_first_node; child; child = child->next_sibling())
0928                     if (internal::compare(child->name(), child->name_size(), n, nsize, case_sensitive))
0929                         return child;
0930                 return 0;
0931             }
0932             else
0933                 return m_first_node;
0934         }
0935 
0936         //! Gets last child node, optionally matching node name. 
0937         //! Behaviour is undefined if node has no children.
0938         //! Use first_node() to test if node has children.
0939         //! \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
0940         //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
0941         //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
0942         //! \return Pointer to found child, or 0 if not found.
0943         xml_node<Ch> *last_node(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
0944         {
0945             BOOST_ASSERT(m_first_node);  // Cannot query for last child if node has no children
0946             if (n)
0947             {
0948                 if (nsize == 0)
0949                     nsize = internal::measure(n);
0950                 for (xml_node<Ch> *child = m_last_node; child; child = child->previous_sibling())
0951                     if (internal::compare(child->name(), child->name_size(), n, nsize, case_sensitive))
0952                         return child;
0953                 return 0;
0954             }
0955             else
0956                 return m_last_node;
0957         }
0958 
0959         //! Gets previous sibling node, optionally matching node name. 
0960         //! Behaviour is undefined if node has no parent.
0961         //! Use parent() to test if node has a parent.
0962         //! \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
0963         //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
0964         //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
0965         //! \return Pointer to found sibling, or 0 if not found.
0966         xml_node<Ch> *previous_sibling(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
0967         {
0968             BOOST_ASSERT(this->m_parent);     // Cannot query for siblings if node has no parent
0969             if (n)
0970             {
0971                 if (nsize == 0)
0972                     nsize = internal::measure(n);
0973                 for (xml_node<Ch> *sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling)
0974                     if (internal::compare(sibling->name(), sibling->name_size(), n, nsize, case_sensitive))
0975                         return sibling;
0976                 return 0;
0977             }
0978             else
0979                 return m_prev_sibling;
0980         }
0981 
0982         //! Gets next sibling node, optionally matching node name. 
0983         //! Behaviour is undefined if node has no parent.
0984         //! Use parent() to test if node has a parent.
0985         //! \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
0986         //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
0987         //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
0988         //! \return Pointer to found sibling, or 0 if not found.
0989         xml_node<Ch> *next_sibling(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
0990         {
0991             BOOST_ASSERT(this->m_parent);     // Cannot query for siblings if node has no parent
0992             if (n)
0993             {
0994                 if (nsize == 0)
0995                     nsize = internal::measure(n);
0996                 for (xml_node<Ch> *sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
0997                     if (internal::compare(sibling->name(), sibling->name_size(), n, nsize, case_sensitive))
0998                         return sibling;
0999                 return 0;
1000             }
1001             else
1002                 return m_next_sibling;
1003         }
1004 
1005         //! Gets first attribute of node, optionally matching attribute name.
1006         //! \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
1007         //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
1008         //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
1009         //! \return Pointer to found attribute, or 0 if not found.
1010         xml_attribute<Ch> *first_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
1011         {
1012             if (n)
1013             {
1014                 if (nsize == 0)
1015                     nsize = internal::measure(n);
1016                 for (xml_attribute<Ch> *attribute = m_first_attribute; attribute; attribute = attribute->m_next_attribute)
1017                     if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive))
1018                         return attribute;
1019                 return 0;
1020             }
1021             else
1022                 return m_first_attribute;
1023         }
1024 
1025         //! Gets last attribute of node, optionally matching attribute name.
1026         //! \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
1027         //! \param nsize Size of name, in characters, or 0 to have size calculated automatically from string
1028         //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
1029         //! \return Pointer to found attribute, or 0 if not found.
1030         xml_attribute<Ch> *last_attribute(const Ch *n = 0, std::size_t nsize = 0, bool case_sensitive = true) const
1031         {
1032             if (n)
1033             {
1034                 if (nsize == 0)
1035                     nsize = internal::measure(n);
1036                 for (xml_attribute<Ch> *attribute = m_last_attribute; attribute; attribute = attribute->m_prev_attribute)
1037                     if (internal::compare(attribute->name(), attribute->name_size(), n, nsize, case_sensitive))
1038                         return attribute;
1039                 return 0;
1040             }
1041             else
1042                 return m_first_attribute ? m_last_attribute : 0;
1043         }
1044 
1045         ///////////////////////////////////////////////////////////////////////////
1046         // Node modification
1047     
1048         //! Sets type of node.
1049         //! \param t Type of node to set.
1050         void type(node_type t)
1051         {
1052             m_type = t;
1053         }
1054 
1055         ///////////////////////////////////////////////////////////////////////////
1056         // Node manipulation
1057 
1058         //! Prepends a new child node.
1059         //! The prepended child becomes the first child, and all existing children are moved one position back.
1060         //! \param child Node to prepend.
1061         void prepend_node(xml_node<Ch> *child)
1062         {
1063             BOOST_ASSERT(child && !child->parent() && child->type() != node_document);
1064             if (first_node())
1065             {
1066                 child->m_next_sibling = m_first_node;
1067                 m_first_node->m_prev_sibling = child;
1068             }
1069             else
1070             {
1071                 child->m_next_sibling = 0;
1072                 m_last_node = child;
1073             }
1074             m_first_node = child;
1075             child->m_parent = this;
1076             child->m_prev_sibling = 0;
1077         }
1078 
1079         //! Appends a new child node. 
1080         //! The appended child becomes the last child.
1081         //! \param child Node to append.
1082         void append_node(xml_node<Ch> *child)
1083         {
1084             BOOST_ASSERT(child && !child->parent() && child->type() != node_document);
1085             if (first_node())
1086             {
1087                 child->m_prev_sibling = m_last_node;
1088                 m_last_node->m_next_sibling = child;
1089             }
1090             else
1091             {
1092                 child->m_prev_sibling = 0;
1093                 m_first_node = child;
1094             }
1095             m_last_node = child;
1096             child->m_parent = this;
1097             child->m_next_sibling = 0;
1098         }
1099 
1100         //! Inserts a new child node at specified place inside the node. 
1101         //! All children after and including the specified node are moved one position back.
1102         //! \param where Place where to insert the child, or 0 to insert at the back.
1103         //! \param child Node to insert.
1104         void insert_node(xml_node<Ch> *where, xml_node<Ch> *child)
1105         {
1106             BOOST_ASSERT(!where || where->parent() == this);
1107             BOOST_ASSERT(child && !child->parent() && child->type() != node_document);
1108             if (where == m_first_node)
1109                 prepend_node(child);
1110             else if (where == 0)
1111                 append_node(child);
1112             else
1113             {
1114                 child->m_prev_sibling = where->m_prev_sibling;
1115                 child->m_next_sibling = where;
1116                 where->m_prev_sibling->m_next_sibling = child;
1117                 where->m_prev_sibling = child;
1118                 child->m_parent = this;
1119             }
1120         }
1121 
1122         //! Removes first child node. 
1123         //! If node has no children, behaviour is undefined.
1124         //! Use first_node() to test if node has children.
1125         void remove_first_node()
1126         {
1127             BOOST_ASSERT(first_node());
1128             xml_node<Ch> *child = m_first_node;
1129             m_first_node = child->m_next_sibling;
1130             if (child->m_next_sibling)
1131                 child->m_next_sibling->m_prev_sibling = 0;
1132             else
1133                 m_last_node = 0;
1134             child->m_parent = 0;
1135         }
1136 
1137         //! Removes last child of the node. 
1138         //! If node has no children, behaviour is undefined.
1139         //! Use first_node() to test if node has children.
1140         void remove_last_node()
1141         {
1142             BOOST_ASSERT(first_node());
1143             xml_node<Ch> *child = m_last_node;
1144             if (child->m_prev_sibling)
1145             {
1146                 m_last_node = child->m_prev_sibling;
1147                 child->m_prev_sibling->m_next_sibling = 0;
1148             }
1149             else
1150                 m_first_node = 0;
1151             child->m_parent = 0;
1152         }
1153 
1154         //! Removes specified child from the node
1155         // \param where Pointer to child to be removed.
1156         void remove_node(xml_node<Ch> *where)
1157         {
1158             BOOST_ASSERT(where && where->parent() == this);
1159             BOOST_ASSERT(first_node());
1160             if (where == m_first_node)
1161                 remove_first_node();
1162             else if (where == m_last_node)
1163                 remove_last_node();
1164             else
1165             {
1166                 where->m_prev_sibling->m_next_sibling = where->m_next_sibling;
1167                 where->m_next_sibling->m_prev_sibling = where->m_prev_sibling;
1168                 where->m_parent = 0;
1169             }
1170         }
1171 
1172         //! Removes all child nodes (but not attributes).
1173         void remove_all_nodes()
1174         {
1175             for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling)
1176                 node->m_parent = 0;
1177             m_first_node = 0;
1178         }
1179 
1180         //! Prepends a new attribute to the node.
1181         //! \param attribute Attribute to prepend.
1182         void prepend_attribute(xml_attribute<Ch> *attribute)
1183         {
1184             BOOST_ASSERT(attribute && !attribute->parent());
1185             if (first_attribute())
1186             {
1187                 attribute->m_next_attribute = m_first_attribute;
1188                 m_first_attribute->m_prev_attribute = attribute;
1189             }
1190             else
1191             {
1192                 attribute->m_next_attribute = 0;
1193                 m_last_attribute = attribute;
1194             }
1195             m_first_attribute = attribute;
1196             attribute->m_parent = this;
1197             attribute->m_prev_attribute = 0;
1198         }
1199 
1200         //! Appends a new attribute to the node.
1201         //! \param attribute Attribute to append.
1202         void append_attribute(xml_attribute<Ch> *attribute)
1203         {
1204             BOOST_ASSERT(attribute && !attribute->parent());
1205             if (first_attribute())
1206             {
1207                 attribute->m_prev_attribute = m_last_attribute;
1208                 m_last_attribute->m_next_attribute = attribute;
1209             }
1210             else
1211             {
1212                 attribute->m_prev_attribute = 0;
1213                 m_first_attribute = attribute;
1214             }
1215             m_last_attribute = attribute;
1216             attribute->m_parent = this;
1217             attribute->m_next_attribute = 0;
1218         }
1219 
1220         //! Inserts a new attribute at specified place inside the node. 
1221         //! All attributes after and including the specified attribute are moved one position back.
1222         //! \param where Place where to insert the attribute, or 0 to insert at the back.
1223         //! \param attribute Attribute to insert.
1224         void insert_attribute(xml_attribute<Ch> *where, xml_attribute<Ch> *attribute)
1225         {
1226             BOOST_ASSERT(!where || where->parent() == this);
1227             BOOST_ASSERT(attribute && !attribute->parent());
1228             if (where == m_first_attribute)
1229                 prepend_attribute(attribute);
1230             else if (where == 0)
1231                 append_attribute(attribute);
1232             else
1233             {
1234                 attribute->m_prev_attribute = where->m_prev_attribute;
1235                 attribute->m_next_attribute = where;
1236                 where->m_prev_attribute->m_next_attribute = attribute;
1237                 where->m_prev_attribute = attribute;
1238                 attribute->m_parent = this;
1239             }
1240         }
1241 
1242         //! Removes first attribute of the node. 
1243         //! If node has no attributes, behaviour is undefined.
1244         //! Use first_attribute() to test if node has attributes.
1245         void remove_first_attribute()
1246         {
1247             BOOST_ASSERT(first_attribute());
1248             xml_attribute<Ch> *attribute = m_first_attribute;
1249             if (attribute->m_next_attribute)
1250             {
1251                 attribute->m_next_attribute->m_prev_attribute = 0;
1252             }
1253             else
1254                 m_last_attribute = 0;
1255             attribute->m_parent = 0;
1256             m_first_attribute = attribute->m_next_attribute;
1257         }
1258 
1259         //! Removes last attribute of the node. 
1260         //! If node has no attributes, behaviour is undefined.
1261         //! Use first_attribute() to test if node has attributes.
1262         void remove_last_attribute()
1263         {
1264             BOOST_ASSERT(first_attribute());
1265             xml_attribute<Ch> *attribute = m_last_attribute;
1266             if (attribute->m_prev_attribute)
1267             {
1268                 attribute->m_prev_attribute->m_next_attribute = 0;
1269                 m_last_attribute = attribute->m_prev_attribute;
1270             }
1271             else
1272                 m_first_attribute = 0;
1273             attribute->m_parent = 0;
1274         }
1275 
1276         //! Removes specified attribute from node.
1277         //! \param where Pointer to attribute to be removed.
1278         void remove_attribute(xml_attribute<Ch> *where)
1279         {
1280             BOOST_ASSERT(first_attribute() && where->parent() == this);
1281             if (where == m_first_attribute)
1282                 remove_first_attribute();
1283             else if (where == m_last_attribute)
1284                 remove_last_attribute();
1285             else
1286             {
1287                 where->m_prev_attribute->m_next_attribute = where->m_next_attribute;
1288                 where->m_next_attribute->m_prev_attribute = where->m_prev_attribute;
1289                 where->m_parent = 0;
1290             }
1291         }
1292 
1293         //! Removes all attributes of node.
1294         void remove_all_attributes()
1295         {
1296             for (xml_attribute<Ch> *attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute)
1297                 attribute->m_parent = 0;
1298             m_first_attribute = 0;
1299         }
1300         
1301     private:
1302 
1303         ///////////////////////////////////////////////////////////////////////////
1304         // Restrictions
1305 
1306         // No copying
1307         xml_node(const xml_node &);
1308         void operator =(const xml_node &);
1309     
1310         ///////////////////////////////////////////////////////////////////////////
1311         // Data members
1312     
1313         // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0.
1314         // This is required for maximum performance, as it allows the parser to omit initialization of 
1315         // unneeded/redundant values.
1316         //
1317         // The rules are as follows:
1318         // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes respectively
1319         // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively, otherwise they contain garbage
1320         // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage
1321 
1322         node_type m_type;                       // Type of node; always valid
1323         xml_node<Ch> *m_first_node;             // Pointer to first child node, or 0 if none; always valid
1324         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
1325         xml_attribute<Ch> *m_first_attribute;   // Pointer to first attribute of node, or 0 if none; always valid
1326         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
1327         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
1328         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
1329 
1330     };
1331 
1332     ///////////////////////////////////////////////////////////////////////////
1333     // XML document
1334     
1335     //! This class represents root of the DOM hierarchy. 
1336     //! It is also an xml_node and a memory_pool through public inheritance.
1337     //! Use parse() function to build a DOM tree from a zero-terminated XML text string.
1338     //! parse() function allocates memory for nodes and attributes by using functions of xml_document, 
1339     //! which are inherited from memory_pool.
1340     //! To access root node of the document, use the document itself, as if it was an xml_node.
1341     //! \param Ch Character type to use.
1342     template<class Ch = char>
1343     class xml_document: public xml_node<Ch>, public memory_pool<Ch>
1344     {
1345     
1346     public:
1347 
1348         //! Constructs empty XML document
1349         xml_document()
1350             : xml_node<Ch>(node_document)
1351         {
1352         }
1353 
1354         //! Parses zero-terminated XML string according to given flags.
1355         //! Passed string will be modified by the parser, unless rapidxml::parse_non_destructive flag is used.
1356         //! The string must persist for the lifetime of the document.
1357         //! In case of error, rapidxml::parse_error exception will be thrown.
1358         //! <br><br>
1359         //! If you want to parse contents of a file, you must first load the file into the memory, and pass pointer to its beginning.
1360         //! Make sure that data is zero-terminated.
1361         //! <br><br>
1362         //! Document can be parsed into multiple times. 
1363         //! Each new call to parse removes previous nodes and attributes (if any), but does not clear memory pool.
1364         //! \param text XML data to parse; pointer is non-const to denote fact that this data may be modified by the parser.
1365         template<int Flags>
1366         void parse(Ch *text)
1367         {
1368             BOOST_ASSERT(text);
1369             
1370             // Remove current contents
1371             this->remove_all_nodes();
1372             this->remove_all_attributes();
1373             
1374             // Parse BOM, if any
1375             parse_bom<Flags>(text);
1376             
1377             // Parse children
1378             while (true)
1379             {
1380                 // Skip whitespace before node
1381                 skip<whitespace_pred, Flags>(text);
1382                 if (*text == 0)
1383                     break;
1384 
1385                 // Parse and append new child
1386                 if (*text == Ch('<'))
1387                 {
1388                     ++text;     // Skip '<'
1389                     if (xml_node<Ch> *node = parse_node<Flags>(text))
1390                         this->append_node(node);
1391                 }
1392                 else
1393                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected <", text);
1394             }
1395 
1396         }
1397 
1398         //! Clears the document by deleting all nodes and clearing the memory pool.
1399         //! All nodes owned by document pool are destroyed.
1400         void clear()
1401         {
1402             this->remove_all_nodes();
1403             this->remove_all_attributes();
1404             memory_pool<Ch>::clear();
1405         }
1406         
1407     private:
1408 
1409         ///////////////////////////////////////////////////////////////////////
1410         // Internal character utility functions
1411         
1412         // Detect whitespace character
1413         struct whitespace_pred
1414         {
1415             static unsigned char test(Ch ch)
1416             {
1417                 return internal::lookup_tables<0>::lookup_whitespace[internal::get_index(ch)];
1418             }
1419         };
1420 
1421         // Detect node name character
1422         struct node_name_pred
1423         {
1424             static unsigned char test(Ch ch)
1425             {
1426                 return internal::lookup_tables<0>::lookup_node_name[internal::get_index(ch)];
1427             }
1428         };
1429 
1430         // Detect attribute name character
1431         struct attribute_name_pred
1432         {
1433             static unsigned char test(Ch ch)
1434             {
1435                 return internal::lookup_tables<0>::lookup_attribute_name[internal::get_index(ch)];
1436             }
1437         };
1438 
1439         // Detect text character (PCDATA)
1440         struct text_pred
1441         {
1442             static unsigned char test(Ch ch)
1443             {
1444                 return internal::lookup_tables<0>::lookup_text[internal::get_index(ch)];
1445             }
1446         };
1447 
1448         // Detect text character (PCDATA) that does not require processing
1449         struct text_pure_no_ws_pred
1450         {
1451             static unsigned char test(Ch ch)
1452             {
1453                 return internal::lookup_tables<0>::lookup_text_pure_no_ws[internal::get_index(ch)];
1454             }
1455         };
1456 
1457         // Detect text character (PCDATA) that does not require processing
1458         struct text_pure_with_ws_pred
1459         {
1460             static unsigned char test(Ch ch)
1461             {
1462                 return internal::lookup_tables<0>::lookup_text_pure_with_ws[internal::get_index(ch)];
1463             }
1464         };
1465 
1466         // Detect attribute value character
1467         template<Ch Quote>
1468         struct attribute_value_pred
1469         {
1470             static unsigned char test(Ch ch)
1471             {
1472                 if (Quote == Ch('\''))
1473                     return internal::lookup_tables<0>::lookup_attribute_data_1[internal::get_index(ch)];
1474                 if (Quote == Ch('\"'))
1475                     return internal::lookup_tables<0>::lookup_attribute_data_2[internal::get_index(ch)];
1476                 return 0;       // Should never be executed, to avoid warnings on Comeau
1477             }
1478         };
1479 
1480         // Detect attribute value character
1481         template<Ch Quote>
1482         struct attribute_value_pure_pred
1483         {
1484             static unsigned char test(Ch ch)
1485             {
1486                 if (Quote == Ch('\''))
1487                     return internal::lookup_tables<0>::lookup_attribute_data_1_pure[internal::get_index(ch)];
1488                 if (Quote == Ch('\"'))
1489                     return internal::lookup_tables<0>::lookup_attribute_data_2_pure[internal::get_index(ch)];
1490                 return 0;       // Should never be executed, to avoid warnings on Comeau
1491             }
1492         };
1493 
1494         // Insert coded character, using UTF8 or 8-bit ASCII
1495         template<int Flags>
1496         static void insert_coded_character(Ch *&text, unsigned long code)
1497         {
1498             if (Flags & parse_no_utf8)
1499             {
1500                 // Insert 8-bit ASCII character
1501                 // Todo: possibly verify that code is less than 256 and use replacement char otherwise?
1502                 text[0] = static_cast<unsigned char>(code);
1503                 text += 1;
1504             }
1505             else
1506             {
1507                 // Insert UTF8 sequence
1508                 if (code < 0x80)    // 1 byte sequence
1509                 {
1510                     text[0] = static_cast<unsigned char>(code);
1511                     text += 1;
1512                 }
1513                 else if (code < 0x800)  // 2 byte sequence
1514                 {
1515                     text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1516                     text[0] = static_cast<unsigned char>(code | 0xC0);
1517                     text += 2;
1518                 }
1519                 else if (code < 0x10000)    // 3 byte sequence
1520                 {
1521                     text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1522                     text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1523                     text[0] = static_cast<unsigned char>(code | 0xE0);
1524                     text += 3;
1525                 }
1526                 else if (code < 0x110000)   // 4 byte sequence
1527                 {
1528                     text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1529                     text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1530                     text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1531                     text[0] = static_cast<unsigned char>(code | 0xF0);
1532                     text += 4;
1533                 }
1534                 else    // Invalid, only codes up to 0x10FFFF are allowed in Unicode
1535                 {
1536                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
1537                 }
1538             }
1539         }
1540 
1541         // Skip characters until predicate evaluates to true
1542         template<class StopPred, int Flags>
1543         static void skip(Ch *&text)
1544         {
1545             Ch *tmp = text;
1546             while (StopPred::test(*tmp))
1547                 ++tmp;
1548             text = tmp;
1549         }
1550 
1551         // Skip characters until predicate evaluates to true while doing the following:
1552         // - replacing XML character entity references with proper characters (&apos; &amp; &quot; &lt; &gt; &#...;)
1553         // - condensing whitespace sequences to single space character
1554         template<class StopPred, class StopPredPure, int Flags>
1555         static Ch *skip_and_expand_character_refs(Ch *&text)
1556         {
1557             // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
1558             if (Flags & parse_no_entity_translation && 
1559                 !(Flags & parse_normalize_whitespace) &&
1560                 !(Flags & parse_trim_whitespace))
1561             {
1562                 skip<StopPred, Flags>(text);
1563                 return text;
1564             }
1565             
1566             // Use simple skip until first modification is detected
1567             skip<StopPredPure, Flags>(text);
1568 
1569             // Use translation skip
1570             Ch *src = text;
1571             Ch *dest = src;
1572             while (StopPred::test(*src))
1573             {
1574                 // If entity translation is enabled    
1575                 if (!(Flags & parse_no_entity_translation))
1576                 {
1577                     // Test if replacement is needed
1578                     if (src[0] == Ch('&'))
1579                     {
1580                         switch (src[1])
1581                         {
1582 
1583                         // &amp; &apos;
1584                         case Ch('a'): 
1585                             if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';'))
1586                             {
1587                                 *dest = Ch('&');
1588                                 ++dest;
1589                                 src += 5;
1590                                 continue;
1591                             }
1592                             if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';'))
1593                             {
1594                                 *dest = Ch('\'');
1595                                 ++dest;
1596                                 src += 6;
1597                                 continue;
1598                             }
1599                             break;
1600 
1601                         // &quot;
1602                         case Ch('q'): 
1603                             if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';'))
1604                             {
1605                                 *dest = Ch('"');
1606                                 ++dest;
1607                                 src += 6;
1608                                 continue;
1609                             }
1610                             break;
1611 
1612                         // &gt;
1613                         case Ch('g'): 
1614                             if (src[2] == Ch('t') && src[3] == Ch(';'))
1615                             {
1616                                 *dest = Ch('>');
1617                                 ++dest;
1618                                 src += 4;
1619                                 continue;
1620                             }
1621                             break;
1622 
1623                         // &lt;
1624                         case Ch('l'): 
1625                             if (src[2] == Ch('t') && src[3] == Ch(';'))
1626                             {
1627                                 *dest = Ch('<');
1628                                 ++dest;
1629                                 src += 4;
1630                                 continue;
1631                             }
1632                             break;
1633 
1634                         // &#...; - assumes ASCII
1635                         case Ch('#'): 
1636                             if (src[2] == Ch('x'))
1637                             {
1638                                 unsigned long code = 0;
1639                                 src += 3;   // Skip &#x
1640                                 while (true)
1641                                 {
1642                                     unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
1643                                     if (digit == 0xFF)
1644                                         break;
1645                                     code = code * 16 + digit;
1646                                     ++src;
1647                                 }
1648                                 insert_coded_character<Flags>(dest, code);    // Put character in output
1649                             }
1650                             else
1651                             {
1652                                 unsigned long code = 0;
1653                                 src += 2;   // Skip &#
1654                                 while (true)
1655                                 {
1656                                     unsigned char digit = internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
1657                                     if (digit == 0xFF)
1658                                         break;
1659                                     code = code * 10 + digit;
1660                                     ++src;
1661                                 }
1662                                 insert_coded_character<Flags>(dest, code);    // Put character in output
1663                             }
1664                             if (*src == Ch(';'))
1665                                 ++src;
1666                             else
1667                                 BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected ;", src);
1668                             continue;
1669 
1670                         // Something else
1671                         default:
1672                             // Ignore, just copy '&' verbatim
1673                             break;
1674 
1675                         }
1676                     }
1677                 }
1678                 
1679                 // If whitespace condensing is enabled
1680                 if (Flags & parse_normalize_whitespace)
1681                 {
1682                     // Test if condensing is needed                 
1683                     if (whitespace_pred::test(*src))
1684                     {
1685                         *dest = Ch(' '); ++dest;    // Put single space in dest
1686                         ++src;                      // Skip first whitespace char
1687                         // Skip remaining whitespace chars
1688                         while (whitespace_pred::test(*src))
1689                             ++src;
1690                         continue;
1691                     }
1692                 }
1693 
1694                 // No replacement, only copy character
1695                 *dest++ = *src++;
1696 
1697             }
1698 
1699             // Return new end
1700             text = src;
1701             return dest;
1702 
1703         }
1704 
1705         ///////////////////////////////////////////////////////////////////////
1706         // Internal parsing functions
1707         
1708         // Parse UTF-8 BOM, if any
1709         template<int Flags>
1710         void parse_bom(char *&text)
1711         {
1712             if (static_cast<unsigned char>(text[0]) == 0xEF && 
1713                 static_cast<unsigned char>(text[1]) == 0xBB && 
1714                 static_cast<unsigned char>(text[2]) == 0xBF)
1715             {
1716                 text += 3;
1717             }
1718         }
1719         
1720         // Parse UTF-16/32 BOM, if any
1721         template<int Flags>
1722         void parse_bom(wchar_t *&text)
1723         {
1724             const wchar_t bom = 0xFEFF;
1725             if (text[0] == bom)
1726             {
1727                 ++text;
1728             }
1729         }
1730 
1731         // Parse XML declaration (<?xml...)
1732         template<int Flags>
1733         xml_node<Ch> *parse_xml_declaration(Ch *&text)
1734         {
1735             // If parsing of declaration is disabled
1736             if (!(Flags & parse_declaration_node))
1737             {
1738                 // Skip until end of declaration
1739                 while (text[0] != Ch('?') || text[1] != Ch('>'))
1740                 {
1741                     if (!text[0])
1742                         BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1743                     ++text;
1744                 }
1745                 text += 2;    // Skip '?>'
1746                 return 0;
1747             }
1748 
1749             // Create declaration
1750             xml_node<Ch> *declaration = this->allocate_node(node_declaration);
1751 
1752             // Skip whitespace before attributes or ?>
1753             skip<whitespace_pred, Flags>(text);
1754 
1755             // Parse declaration attributes
1756             parse_node_attributes<Flags>(text, declaration);
1757             
1758             // Skip ?>
1759             if (text[0] != Ch('?') || text[1] != Ch('>'))
1760                 BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected ?>", text);
1761             text += 2;
1762             
1763             return declaration;
1764         }
1765 
1766         // Parse XML comment (<!--...)
1767         template<int Flags>
1768         xml_node<Ch> *parse_comment(Ch *&text)
1769         {
1770             // If parsing of comments is disabled
1771             if (!(Flags & parse_comment_nodes))
1772             {
1773                 // Skip until end of comment
1774                 while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
1775                 {
1776                     if (!text[0])
1777                         BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1778                     ++text;
1779                 }
1780                 text += 3;     // Skip '-->'
1781                 return 0;      // Do not produce comment node
1782             }
1783 
1784             // Remember value start
1785             Ch *val = text;
1786 
1787             // Skip until end of comment
1788             while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
1789             {
1790                 if (!text[0])
1791                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1792                 ++text;
1793             }
1794 
1795             // Create comment node
1796             xml_node<Ch> *comment = this->allocate_node(node_comment);
1797             comment->value(val, text - val);
1798             
1799             // Place zero terminator after comment value
1800             if (!(Flags & parse_no_string_terminators))
1801                 *text = Ch('\0');
1802             
1803             text += 3;     // Skip '-->'
1804             return comment;
1805         }
1806 
1807         // Parse DOCTYPE
1808         template<int Flags>
1809         xml_node<Ch> *parse_doctype(Ch *&text)
1810         {
1811             // Remember value start
1812             Ch *val = text;
1813 
1814             // Skip to >
1815             while (*text != Ch('>'))
1816             {
1817                 // Determine character type
1818                 switch (*text)
1819                 {
1820                 
1821                 // If '[' encountered, scan for matching ending ']' using naive algorithm with depth
1822                 // This works for all W3C test files except for 2 most wicked
1823                 case Ch('['):
1824                 {
1825                     ++text;     // Skip '['
1826                     int depth = 1;
1827                     while (depth > 0)
1828                     {
1829                         switch (*text)
1830                         {
1831                             case Ch('['): ++depth; break;
1832                             case Ch(']'): --depth; break;
1833                             case 0: BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1834                             default: break;
1835                         }
1836                         ++text;
1837                     }
1838                     break;
1839                 }
1840                 
1841                 // Error on end of text
1842                 case Ch('\0'):
1843                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1844                 
1845                 // Other character, skip it
1846                 default:
1847                     ++text;
1848 
1849                 }
1850             }
1851             
1852             // If DOCTYPE nodes enabled
1853             if (Flags & parse_doctype_node)
1854             {
1855                 // Create a new doctype node
1856                 xml_node<Ch> *doctype = this->allocate_node(node_doctype);
1857                 doctype->value(val, text - val);
1858                 
1859                 // Place zero terminator after value
1860                 if (!(Flags & parse_no_string_terminators))
1861                     *text = Ch('\0');
1862 
1863                 text += 1;      // skip '>'
1864                 return doctype;
1865             }
1866             else
1867             {
1868                 text += 1;      // skip '>'
1869                 return 0;
1870             }
1871 
1872         }
1873 
1874         // Parse PI
1875         template<int Flags>
1876         xml_node<Ch> *parse_pi(Ch *&text)
1877         {
1878             // If creation of PI nodes is enabled
1879             if (Flags & parse_pi_nodes)
1880             {
1881                 // Create pi node
1882                 xml_node<Ch> *pi = this->allocate_node(node_pi);
1883 
1884                 // Extract PI target name
1885                 Ch *n = text;
1886                 skip<node_name_pred, Flags>(text);
1887                 if (text == n)
1888                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected PI target", text);
1889                 pi->name(n, text - n);
1890                 
1891                 // Skip whitespace between pi target and pi
1892                 skip<whitespace_pred, Flags>(text);
1893 
1894                 // Remember start of pi
1895                 Ch *val = text;
1896                 
1897                 // Skip to '?>'
1898                 while (text[0] != Ch('?') || text[1] != Ch('>'))
1899                 {
1900                     if (*text == Ch('\0'))
1901                         BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1902                     ++text;
1903                 }
1904 
1905                 // Set pi value (verbatim, no entity expansion or whitespace normalization)
1906                 pi->value(val, text - val);
1907 
1908                 // Place zero terminator after name and value
1909                 if (!(Flags & parse_no_string_terminators))
1910                 {
1911                     pi->name()[pi->name_size()] = Ch('\0');
1912                     pi->value()[pi->value_size()] = Ch('\0');
1913                 }
1914                 
1915                 text += 2;                          // Skip '?>'
1916                 return pi;
1917             }
1918             else
1919             {
1920                 // Skip to '?>'
1921                 while (text[0] != Ch('?') || text[1] != Ch('>'))
1922                 {
1923                     if (*text == Ch('\0'))
1924                         BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1925                     ++text;
1926                 }
1927                 text += 2;    // Skip '?>'
1928                 return 0;
1929             }
1930         }
1931 
1932         // Parse and append data
1933         // Return character that ends data.
1934         // This is necessary because this character might have been overwritten by a terminating 0
1935         template<int Flags>
1936         Ch parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start)
1937         {
1938             // Backup to contents start if whitespace trimming is disabled
1939             if (!(Flags & parse_trim_whitespace))
1940                 text = contents_start;     
1941             
1942             // Skip until end of data
1943             Ch *val = text, *end;
1944             if (Flags & parse_normalize_whitespace)
1945                 end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text);   
1946             else
1947                 end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text);
1948 
1949             // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
1950             if (Flags & parse_trim_whitespace)
1951             {
1952                 if (Flags & parse_normalize_whitespace)
1953                 {
1954                     // Whitespace is already condensed to single space characters by skipping function, so just trim 1 char off the end
1955                     if (*(end - 1) == Ch(' '))
1956                         --end;
1957                 }
1958                 else
1959                 {
1960                     // Backup until non-whitespace character is found
1961                     while (whitespace_pred::test(*(end - 1)))
1962                         --end;
1963                 }
1964             }
1965             
1966             // If characters are still left between end and value (this test is only necessary if normalization is enabled)
1967             // Create new data node
1968             if (!(Flags & parse_no_data_nodes))
1969             {
1970                 xml_node<Ch> *data = this->allocate_node(node_data);
1971                 data->value(val, end - val);
1972                 node->append_node(data);
1973             }
1974 
1975             // Add data to parent node if no data exists yet
1976             if (!(Flags & parse_no_element_values)) 
1977                 if (*node->value() == Ch('\0'))
1978                     node->value(val, end - val);
1979 
1980             // Place zero terminator after value
1981             if (!(Flags & parse_no_string_terminators))
1982             {
1983                 Ch ch = *text;
1984                 *end = Ch('\0');
1985                 return ch;      // Return character that ends data; this is required because zero terminator overwritten it
1986             }
1987 
1988             // Return character that ends data
1989             return *text;
1990         }
1991 
1992         // Parse CDATA
1993         template<int Flags>
1994         xml_node<Ch> *parse_cdata(Ch *&text)
1995         {
1996             // If CDATA is disabled
1997             if (Flags & parse_no_data_nodes)
1998             {
1999                 // Skip until end of cdata
2000                 while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
2001                 {
2002                     if (!text[0])
2003                         BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2004                     ++text;
2005                 }
2006                 text += 3;      // Skip ]]>
2007                 return 0;       // Do not produce CDATA node
2008             }
2009 
2010             // Skip until end of cdata
2011             Ch *val = text;
2012             while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
2013             {
2014                 if (!text[0])
2015                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2016                 ++text;
2017             }
2018 
2019             // Create new cdata node
2020             xml_node<Ch> *cdata = this->allocate_node(node_cdata);
2021             cdata->value(val, text - val);
2022 
2023             // Place zero terminator after value
2024             if (!(Flags & parse_no_string_terminators))
2025                 *text = Ch('\0');
2026 
2027             text += 3;      // Skip ]]>
2028             return cdata;
2029         }
2030         
2031         // Parse element node
2032         template<int Flags>
2033         xml_node<Ch> *parse_element(Ch *&text)
2034         {
2035             // Create element node
2036             xml_node<Ch> *element = this->allocate_node(node_element);
2037 
2038             // Extract element name
2039             Ch *n = text;
2040             skip<node_name_pred, Flags>(text);
2041             if (text == n)
2042                 BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected element name", text);
2043             element->name(n, text - n);
2044             
2045             // Skip whitespace between element name and attributes or >
2046             skip<whitespace_pred, Flags>(text);
2047 
2048             // Parse attributes, if any
2049             parse_node_attributes<Flags>(text, element);
2050 
2051             // Determine ending type
2052             if (*text == Ch('>'))
2053             {
2054                 ++text;
2055                 parse_node_contents<Flags>(text, element);
2056             }
2057             else if (*text == Ch('/'))
2058             {
2059                 ++text;
2060                 if (*text != Ch('>'))
2061                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected >", text);
2062                 ++text;
2063             }
2064             else
2065                 BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected >", text);
2066 
2067             // Place zero terminator after name
2068             if (!(Flags & parse_no_string_terminators))
2069                 element->name()[element->name_size()] = Ch('\0');
2070 
2071             // Return parsed element
2072             return element;
2073         }
2074 
2075         // Determine node type, and parse it
2076         template<int Flags>
2077         xml_node<Ch> *parse_node(Ch *&text)
2078         {
2079             // Parse proper node type
2080             switch (text[0])
2081             {
2082 
2083             // <...
2084             default: 
2085                 // Parse and append element node
2086                 return parse_element<Flags>(text);
2087 
2088             // <?...
2089             case Ch('?'): 
2090                 ++text;     // Skip ?
2091                 if ((text[0] == Ch('x') || text[0] == Ch('X')) &&
2092                     (text[1] == Ch('m') || text[1] == Ch('M')) && 
2093                     (text[2] == Ch('l') || text[2] == Ch('L')) &&
2094                     whitespace_pred::test(text[3]))
2095                 {
2096                     // '<?xml ' - xml declaration
2097                     text += 4;      // Skip 'xml '
2098                     return parse_xml_declaration<Flags>(text);
2099                 }
2100                 else
2101                 {
2102                     // Parse PI
2103                     return parse_pi<Flags>(text);
2104                 }
2105             
2106             // <!...
2107             case Ch('!'): 
2108 
2109                 // Parse proper subset of <! node
2110                 switch (text[1])    
2111                 {
2112                 
2113                 // <!-
2114                 case Ch('-'):
2115                     if (text[2] == Ch('-'))
2116                     {
2117                         // '<!--' - xml comment
2118                         text += 3;     // Skip '!--'
2119                         return parse_comment<Flags>(text);
2120                     }
2121                     break;
2122 
2123                 // <![
2124                 case Ch('['):
2125                     if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') && 
2126                         text[5] == Ch('T') && text[6] == Ch('A') && text[7] == Ch('['))
2127                     {
2128                         // '<![CDATA[' - cdata
2129                         text += 8;     // Skip '![CDATA['
2130                         return parse_cdata<Flags>(text);
2131                     }
2132                     break;
2133 
2134                 // <!D
2135                 case Ch('D'):
2136                     if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') && 
2137                         text[5] == Ch('Y') && text[6] == Ch('P') && text[7] == Ch('E') && 
2138                         whitespace_pred::test(text[8]))
2139                     {
2140                         // '<!DOCTYPE ' - doctype
2141                         text += 9;      // skip '!DOCTYPE '
2142                         return parse_doctype<Flags>(text);
2143                     }
2144                     break;
2145 
2146                 default: break;
2147 
2148                 }   // switch
2149 
2150                 // Attempt to skip other, unrecognized node types starting with <!
2151                 ++text;     // Skip !
2152                 while (*text != Ch('>'))
2153                 {
2154                     if (*text == 0)
2155                         BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2156                     ++text;
2157                 }
2158                 ++text;     // Skip '>'
2159                 return 0;   // No node recognized
2160 
2161             }
2162         }
2163 
2164         // Parse contents of the node - children, data etc.
2165         template<int Flags>
2166         void parse_node_contents(Ch *&text, xml_node<Ch> *node)
2167         {
2168             // For all children and text
2169             while (true)
2170             {
2171                 // Skip whitespace between > and node contents
2172                 Ch *contents_start = text;      // Store start of node contents before whitespace is skipped
2173                 if (Flags & parse_trim_whitespace)
2174                     skip<whitespace_pred, Flags>(text);
2175                 Ch next_char = *text;
2176 
2177             // After data nodes, instead of continuing the loop, control jumps here.
2178             // This is because zero termination inside parse_and_append_data() function
2179             // would wreak havoc with the above code.
2180             // Also, skipping whitespace after data nodes is unnecessary.
2181             after_data_node:    
2182                 
2183                 // Determine what comes next: node closing, child node, data node, or 0?
2184                 switch (next_char)
2185                 {
2186                 
2187                 // Node closing or child node
2188                 case Ch('<'):
2189                     if (text[1] == Ch('/'))
2190                     {
2191                         // Node closing
2192                         text += 2;      // Skip '</'
2193                         if (Flags & parse_validate_closing_tags)
2194                         {
2195                             // Skip and validate closing tag name
2196                             Ch *closing_name = text;
2197                             skip<node_name_pred, Flags>(text);
2198                             if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true))
2199                                 BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
2200                         }
2201                         else
2202                         {
2203                             // No validation, just skip name
2204                             skip<node_name_pred, Flags>(text);
2205                         }
2206                         // Skip remaining whitespace after node name
2207                         skip<whitespace_pred, Flags>(text);
2208                         if (*text != Ch('>'))
2209                             BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected >", text);
2210                         ++text;     // Skip '>'
2211                         return;     // Node closed, finished parsing contents
2212                     }
2213                     else
2214                     {
2215                         // Child node
2216                         ++text;     // Skip '<'
2217                         if (xml_node<Ch> *child = parse_node<Flags>(text))
2218                             node->append_node(child);
2219                     }
2220                     break;
2221 
2222                 // End of data - error
2223                 case Ch('\0'):
2224                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2225 
2226                 // Data node
2227                 default:
2228                     next_char = parse_and_append_data<Flags>(node, text, contents_start);
2229                     goto after_data_node;   // Bypass regular processing after data nodes
2230 
2231                 }
2232             }
2233         }
2234         
2235         // Parse XML attributes of the node
2236         template<int Flags>
2237         void parse_node_attributes(Ch *&text, xml_node<Ch> *node)
2238         {
2239             // For all attributes 
2240             while (attribute_name_pred::test(*text))
2241             {
2242                 // Extract attribute name
2243                 Ch *n = text;
2244                 ++text;     // Skip first character of attribute name
2245                 skip<attribute_name_pred, Flags>(text);
2246                 if (text == n)
2247                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected attribute name", n);
2248 
2249                 // Create new attribute
2250                 xml_attribute<Ch> *attribute = this->allocate_attribute();
2251                 attribute->name(n, text - n);
2252                 node->append_attribute(attribute);
2253 
2254                 // Skip whitespace after attribute name
2255                 skip<whitespace_pred, Flags>(text);
2256 
2257                 // Skip =
2258                 if (*text != Ch('='))
2259                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected =", text);
2260                 ++text;
2261 
2262                 // Add terminating zero after name
2263                 if (!(Flags & parse_no_string_terminators))
2264                     attribute->name()[attribute->name_size()] = 0;
2265 
2266                 // Skip whitespace after =
2267                 skip<whitespace_pred, Flags>(text);
2268 
2269                 // Skip quote and remember if it was ' or "
2270                 Ch quote = *text;
2271                 if (quote != Ch('\'') && quote != Ch('"'))
2272                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected ' or \"", text);
2273                 ++text;
2274 
2275                 // Extract attribute value and expand char refs in it
2276                 Ch *val = text, *end;
2277                 const int AttFlags = Flags & ~parse_normalize_whitespace;   // No whitespace normalization in attributes
2278                 if (quote == Ch('\''))
2279                     end = skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>, attribute_value_pure_pred<Ch('\'')>, AttFlags>(text);
2280                 else
2281                     end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text);
2282                 
2283                 // Set attribute value
2284                 attribute->value(val, end - val);
2285                 
2286                 // Make sure that end quote is present
2287                 if (*text != quote)
2288                     BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR("expected ' or \"", text);
2289                 ++text;     // Skip quote
2290 
2291                 // Add terminating zero after value
2292                 if (!(Flags & parse_no_string_terminators))
2293                     attribute->value()[attribute->value_size()] = 0;
2294 
2295                 // Skip whitespace after attribute value
2296                 skip<whitespace_pred, Flags>(text);
2297             }
2298         }
2299 
2300     };
2301 
2302     //! \cond internal
2303     namespace internal
2304     {
2305 
2306         // Whitespace (space \n \r \t)
2307         template<int Dummy>
2308         const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] = 
2309         {
2310           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2311              0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  1,  0,  0,  // 0
2312              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 1
2313              1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 2
2314              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 3
2315              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 4
2316              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 5
2317              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 6
2318              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 7
2319              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 8
2320              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 9
2321              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // A
2322              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // B
2323              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // C
2324              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // D
2325              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // E
2326              0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0   // F
2327         };
2328 
2329         // Node name (anything but space \n \r \t / > ? \0)
2330         template<int Dummy>
2331         const unsigned char lookup_tables<Dummy>::lookup_node_name[256] = 
2332         {
2333           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2334              0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
2335              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2336              0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
2337              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  // 3
2338              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2339              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2340              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2341              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2342              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2343              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2344              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2345              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2346              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2347              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2348              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2349              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2350         };
2351 
2352         // Text (i.e. PCDATA) (anything but < \0)
2353         template<int Dummy>
2354         const unsigned char lookup_tables<Dummy>::lookup_text[256] = 
2355         {
2356           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2357              0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
2358              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2359              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
2360              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
2361              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2362              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2363              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2364              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2365              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2366              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2367              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2368              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2369              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2370              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2371              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2372              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2373         };
2374 
2375         // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled 
2376         // (anything but < \0 &)
2377         template<int Dummy>
2378         const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] = 
2379         {
2380           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2381              0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
2382              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2383              1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
2384              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
2385              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2386              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2387              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2388              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2389              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2390              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2391              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2392              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2393              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2394              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2395              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2396              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2397         };
2398 
2399         // Text (i.e. PCDATA) that does not require processing when ws normalizations is enabled
2400         // (anything but < \0 & space \n \r \t)
2401         template<int Dummy>
2402         const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] = 
2403         {
2404           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2405              0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
2406              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2407              0,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
2408              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
2409              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2410              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2411              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2412              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2413              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2414              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2415              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2416              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2417              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2418              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2419              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2420              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2421         };
2422 
2423         // Attribute name (anything but space \n \r \t / < > = ? ! \0)
2424         template<int Dummy>
2425         const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] = 
2426         {
2427           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2428              0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
2429              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2430              0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
2431              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  // 3
2432              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2433              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2434              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2435              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2436              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2437              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2438              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2439              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2440              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2441              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2442              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2443              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2444         };
2445 
2446         // Attribute data with single quote (anything but ' \0)
2447         template<int Dummy>
2448         const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] = 
2449         {
2450           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2451              0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
2452              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2453              1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
2454              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
2455              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2456              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2457              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2458              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2459              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2460              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2461              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2462              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2463              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2464              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2465              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2466              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2467         };
2468 
2469         // Attribute data with single quote that does not require processing (anything but ' \0 &)
2470         template<int Dummy>
2471         const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] = 
2472         {
2473           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2474              0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
2475              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2476              1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
2477              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
2478              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2479              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2480              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2481              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2482              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2483              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2484              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2485              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2486              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2487              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2488              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2489              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2490         };
2491 
2492         // Attribute data with double quote (anything but " \0)
2493         template<int Dummy>
2494         const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] = 
2495         {
2496           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2497              0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
2498              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2499              1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
2500              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
2501              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2502              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2503              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2504              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2505              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2506              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2507              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2508              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2509              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2510              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2511              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2512              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2513         };
2514 
2515         // Attribute data with double quote that does not require processing (anything but " \0 &)
2516         template<int Dummy>
2517         const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] = 
2518         {
2519           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2520              0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
2521              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
2522              1,  1,  0,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
2523              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
2524              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
2525              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
2526              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
2527              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
2528              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
2529              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
2530              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
2531              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
2532              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
2533              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
2534              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
2535              1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
2536         };
2537 
2538         // Digits (dec and hex, 255 denotes end of numeric character reference)
2539         template<int Dummy>
2540         const unsigned char lookup_tables<Dummy>::lookup_digits[256] = 
2541         {
2542           // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
2543            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 0
2544            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 1
2545            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 2
2546              0,  1,  2,  3,  4,  5,  6,  7,  8,  9,255,255,255,255,255,255,  // 3
2547            255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,  // 4
2548            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 5
2549            255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,  // 6
2550            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 7
2551            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 8
2552            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 9
2553            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // A
2554            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // B
2555            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // C
2556            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // D
2557            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // E
2558            255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255   // F
2559         };
2560     
2561         // Upper case conversion
2562         template<int Dummy>
2563         const unsigned char lookup_tables<Dummy>::lookup_upcase[256] = 
2564         {
2565           // 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  A   B   C   D   E   F
2566            0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,   // 0
2567            16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,   // 1
2568            32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,   // 2
2569            48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,   // 3
2570            64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   // 4
2571            80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,   // 5
2572            96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   // 6
2573            80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127,  // 7
2574            128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,  // 8
2575            144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,  // 9
2576            160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,  // A
2577            176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,  // B
2578            192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,  // C
2579            208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,  // D
2580            224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,  // E
2581            240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255   // F
2582         };
2583     }
2584     //! \endcond
2585 
2586 }}}}
2587 
2588 // Undefine internal macros
2589 #undef BOOST_PROPERTY_TREE_RAPIDXML_PARSE_ERROR
2590 
2591 // On MSVC, restore warnings state
2592 #ifdef _MSC_VER
2593     #pragma warning(pop)
2594 #endif
2595 
2596 #endif