#ifndef RAPIDXML_HPP_INCLUDED
#define RAPIDXML_HPP_INCLUDED

// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml.hpp This file contains rapidxml parser and DOM implementation

// If standard library is disabled, user must provide implementations of
// required functions and typedefs
#if !defined(RAPIDXML_NO_STDLIB)
#include <cassert> // For assert
#include <cstdlib> // For std::size_t
#include <new>     // For placement new
#endif

// On MSVC, disable "conditional expression is constant" warning (level 4).
// This warning is almost impossible to avoid with certain types of templated
// code
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4127) // Conditional expression is constant
#endif

///////////////////////////////////////////////////////////////////////////
// RAPIDXML_PARSE_ERROR

#if defined(RAPIDXML_NO_EXCEPTIONS)

#define RAPIDXML_PARSE_ERROR(what, where)                                      \
  {                                                                            \
    parse_error_handler(what, where);                                          \
    assert(0);                                                                 \
  }
#define RAPIDXML_EOF_ERROR(what, where)                                        \
  {                                                                            \
    parse_error_handler(what, where);                                          \
    assert(0);                                                                 \
  }

namespace rapidxml {
//! When exceptions are disabled by defining RAPIDXML_NO_EXCEPTIONS,
//! this function is called to notify user about the error.
//! It must be defined by the user.
//! <br><br>
//! This function cannot return. If it does, the results are undefined.
//! <br><br>
//! A very simple definition might look like that:
//! <pre>
//! void %rapidxml::%parse_error_handler(const char *what, void *where)
//! {
//!     std::cout << "Parse error: " << what << "\n";
//!     std::abort();
//! }
//! </pre>
//! \param what Human readable description of the error.
//! \param where Pointer to character data where error was detected.
void parse_error_handler(const char *what, void *where);
} // namespace rapidxml

#else

#include <stdexcept> // For std::runtime_error

#define RAPIDXML_PARSE_ERROR(what, where)                                      \
  {                                                                            \
    if (*where == Ch(0))                                                       \
      throw eof_error(what, where);                                            \
    else                                                                       \
      throw parse_error(what, where);                                          \
  }                                                                            \
  (void)0
#define RAPIDXML_EOF_ERROR(what, where) throw eof_error(what, where)

namespace rapidxml {

//! Parse error exception.
//! This exception is thrown by the parser when an error occurs.
//! Use what() function to get human-readable error message.
//! Use where() function to get a pointer to position within source text where
//! error was detected. <br><br> If throwing exceptions by the parser is
//! undesirable, it can be disabled by defining RAPIDXML_NO_EXCEPTIONS macro
//! before rapidxml.hpp is included. This will cause the parser to call
//! rapidxml::parse_error_handler() function instead of throwing an exception.
//! This function must be defined by the user.
//! <br><br>
//! This class derives from <code>std::exception</code> class.
class parse_error : public std::runtime_error {

public:
  //! Constructs parse error
  parse_error(const char *what, void *where)
      : std::runtime_error(what), m_where(where) {}

  //! Gets pointer to character data where error happened.
  //! Ch should be the same as char type of xml_document that produced the
  //! error. \return Pointer to location within the parsed string where error
  //! occured.
  template <class Ch> Ch *where() const {
    return reinterpret_cast<Ch *>(m_where);
  }

private:
  void *m_where;
};

class eof_error : public parse_error {
public:
  eof_error(const char *what, void *where) : parse_error(what, where) {}
};

class validation_error : public std::runtime_error {
public:
  validation_error(const char *what) : std::runtime_error(what) {}
};
} // namespace rapidxml

#endif

///////////////////////////////////////////////////////////////////////////
// Pool sizes

#ifndef RAPIDXML_STATIC_POOL_SIZE
  // Size of static memory block of memory_pool.
// Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to
// override the default value. No dynamic memory allocations are performed by
// memory_pool until static memory is exhausted.
#define RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
#endif

#ifndef RAPIDXML_DYNAMIC_POOL_SIZE
  // Size of dynamic memory block of memory_pool.
// Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want
// to override the default value. After the static block is exhausted, dynamic
// blocks with approximately this size are allocated by memory_pool.
#define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
#endif

#ifndef RAPIDXML_ALIGNMENT
  // Memory allocation alignment.
// Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to
// override the default value, which is the size of pointer. All memory
// allocations for nodes, attributes and strings will be aligned to this value.
// This must be a power of 2 and at least 1, otherwise memory_pool will not
// work.
#define RAPIDXML_ALIGNMENT sizeof(void *)
#endif

namespace rapidxml {
// Forward declarations
template <class Ch> class xml_node;
template <class Ch> class xml_attribute;
template <class Ch> class xml_document;

//! Enumeration listing all node types produced by the parser.
//! Use xml_node::type() function to query node type.
enum node_type {
  node_document, //!< A document node. Name and value are empty.
  node_element, //!< An element node. Name contains element name. Value contains
                //!< text of first data node.
  node_data,    //!< A data node. Name is empty. Value contains data text.
  node_cdata,   //!< A CDATA node. Name is empty. Value contains data text.
  node_comment, //!< A comment node. Name is empty. Value contains comment text.
  node_declaration, //!< A declaration node. Name and value are empty.
                    //!< Declaration parameters (version, encoding and
                    //!< standalone) are in node attributes.
  node_doctype, //!< A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
  node_pi, //!< A PI node. Name contains target. Value contains instructions.
  node_literal //!< Value is unencoded text (used for inserting pre-rendered
               //!< XML).
};

///////////////////////////////////////////////////////////////////////
// Parsing flags

//! Parse flag instructing the parser to not create data nodes.
//! Text of first data node will still be placed in value of parent element,
//! unless rapidxml::parse_no_element_values flag is also specified. Can be
//! combined with other flags by use of | operator. <br><br> See
//! xml_document::parse() function.
const int parse_no_data_nodes = 0x1;

//! Parse flag instructing the parser to not use text of first data node as a
//! value of parent element. Can be combined with other flags by use of |
//! operator. Note that child data nodes of element node take precendence over
//! its value when printing. That is, if element has one or more child data
//! nodes <em>and</em> a value, the value will be ignored. Use
//! rapidxml::parse_no_data_nodes flag to prevent creation of data nodes if you
//! want to manipulate data using values of elements. <br><br> See
//! xml_document::parse() function.
const int parse_no_element_values = 0x2;

//! Parse flag instructing the parser to not place zero terminators after
//! strings in the source text. By default zero terminators are placed,
//! modifying source text. Can be combined with other flags by use of |
//! operator. <br><br> See xml_document::parse() function.
const int parse_no_string_terminators = 0x4;

//! Parse flag instructing the parser to not translate entities in the source
//! text. By default entities are translated, modifying source text. Can be
//! combined with other flags by use of | operator. <br><br> See
//! xml_document::parse() function.
const int parse_no_entity_translation = 0x8;

//! Parse flag instructing the parser to disable UTF-8 handling and assume plain
//! 8 bit characters. By default, UTF-8 handling is enabled. Can be combined
//! with other flags by use of | operator. <br><br> See xml_document::parse()
//! function.
const int parse_no_utf8 = 0x10;

//! Parse flag instructing the parser to create XML declaration node.
//! By default, declaration node is not created.
//! Can be combined with other flags by use of | operator.
//! <br><br>
//! See xml_document::parse() function.
const int parse_declaration_node = 0x20;

//! Parse flag instructing the parser to create comments nodes.
//! By default, comment nodes are not created.
//! Can be combined with other flags by use of | operator.
//! <br><br>
//! See xml_document::parse() function.
const int parse_comment_nodes = 0x40;

//! Parse flag instructing the parser to create DOCTYPE node.
//! By default, doctype node is not created.
//! Although W3C specification allows at most one DOCTYPE node, RapidXml will
//! silently accept documents with more than one. Can be combined with other
//! flags by use of | operator. <br><br> See xml_document::parse() function.
const int parse_doctype_node = 0x80;

//! Parse flag instructing the parser to create PI nodes.
//! By default, PI nodes are not created.
//! Can be combined with other flags by use of | operator.
//! <br><br>
//! See xml_document::parse() function.
const int parse_pi_nodes = 0x100;

//! Parse flag instructing the parser to validate closing tag names.
//! If not set, name inside closing tag is irrelevant to the parser.
//! By default, closing tags are not validated.
//! Can be combined with other flags by use of | operator.
//! <br><br>
//! See xml_document::parse() function.
const int parse_validate_closing_tags = 0x200;

//! Parse flag instructing the parser to trim all leading and trailing
//! whitespace of data nodes. By default, whitespace is not trimmed. This flag
//! does not cause the parser to modify source text. Can be combined with other
//! flags by use of | operator. <br><br> See xml_document::parse() function.
const int parse_trim_whitespace = 0x400;

//! Parse flag instructing the parser to condense all whitespace runs of data
//! nodes to a single space character. Trimming of leading and trailing
//! whitespace of data is controlled by rapidxml::parse_trim_whitespace flag. By
//! default, whitespace is not normalized. If this flag is specified, source
//! text will be modified. Can be combined with other flags by use of |
//! operator. <br><br> See xml_document::parse() function.
const int parse_normalize_whitespace = 0x800;

//! Parse flag to say "Parse only the initial element opening."
//! Useful for XMLstreams used in XMPP.
const int parse_open_only = 0x1000;

//! Parse flag to say "Toss the children of the top node and parse off
//! one element.
//! Useful for parsing off XMPP top-level elements.
const int parse_parse_one = 0x2000;

//! Parse flag to say "Validate XML namespaces fully."
//! This will generate additional errors, including unbound prefixes
//! and duplicate attributes (with different prefices)
const int parse_validate_xmlns = 0x4000;

// Compound flags

//! Parse flags which represent default behaviour of the parser.
//! This is always equal to 0, so that all other flags can be simply ored
//! together. Normally there is no need to inconveniently disable flags by
//! anding with their negated (~) values. This also means that meaning of each
//! flag is a <i>negation</i> of the default setting. For example, if flag name
//! is rapidxml::parse_no_utf8, it means that utf-8 is <i>enabled</i> by
//! default, and using the flag will disable it. <br><br> See
//! xml_document::parse() function.
const int parse_default = 0;

//! A combination of parse flags that forbids any modifications of the source
//! text. This also results in faster parsing. However, note that the following
//! will occur: <ul> <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> <li>entities will not be
//! translated</li> <li>whitespace will not be normalized</li>
//! </ul>
//! See xml_document::parse() function.
const int parse_non_destructive =
    parse_no_string_terminators | parse_no_entity_translation;

//! A combination of parse flags resulting in fastest possible parsing, without
//! sacrificing important data. <br><br> See xml_document::parse() function.
const int parse_fastest = parse_non_destructive | parse_no_data_nodes;

//! A combination of parse flags resulting in largest amount of data being
//! extracted. This usually results in slowest parsing. <br><br> See
//! xml_document::parse() function.
const int parse_full = parse_declaration_node | parse_comment_nodes |
                       parse_doctype_node | parse_pi_nodes |
                       parse_validate_closing_tags;

///////////////////////////////////////////////////////////////////////
// Internals

//! \cond internal
namespace internal {

// Struct that contains lookup tables for the parser
// It must be a template to allow correct linking (because it has static data
// members, which are defined in a header file).
template <int Dummy> struct lookup_tables {
  static const unsigned char lookup_whitespace[256];      // Whitespace table
  static const unsigned char lookup_node_name[256];       // Node name table
  static const unsigned char lookup_element_name[256];    // Element name table
  static const unsigned char lookup_text[256];            // Text table
  static const unsigned char lookup_text_pure_no_ws[256]; // Text table
  static const unsigned char lookup_text_pure_with_ws[256]; // Text table
  static const unsigned char lookup_attribute_name[256]; // Attribute name table
  static const unsigned char
      lookup_attribute_data_1[256]; // Attribute data table with single quote
  static const unsigned char
      lookup_attribute_data_1_pure[256]; // Attribute data table with single
                                         // quote
  static const unsigned char
      lookup_attribute_data_2[256]; // Attribute data table with double quotes
  static const unsigned char
      lookup_attribute_data_2_pure[256]; // Attribute data table with double
                                         // quotes
  static const unsigned char lookup_digits[256]; // Digits
  static const unsigned char
      lookup_upcase[256]; // To uppercase conversion table for ASCII characters
};

// Find length of the string
template <class Ch> inline std::size_t measure(const Ch *p) {
  const Ch *tmp = p;
  while (*tmp)
    ++tmp;
  return tmp - p;
}

// Compare strings for equality
template <class Ch>
inline bool compare(const Ch *p1, std::size_t size1, const Ch *p2,
                    std::size_t size2, bool case_sensitive) {
  if (size1 != size2)
    return false;
  if (case_sensitive) {
    for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
      if (*p1 != *p2)
        return false;
  } else {
    for (const Ch *end = p1 + size1; p1 < end; ++p1, ++p2)
      if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] !=
          lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)])
        return false;
  }
  return true;
}
} // namespace internal
//! \endcond

///////////////////////////////////////////////////////////////////////
// Memory pool

//! This class is used by the parser to create new nodes and attributes, without
//! overheads of dynamic memory allocation. In most cases, you will not need to
//! use this class directly. However, if you need to create nodes manually or
//! modify names/values of nodes, you are encouraged to use memory_pool of
//! relevant xml_document to allocate the memory. Not only is this faster than
//! allocating them by using <code>new</code> operator, but also their lifetime
//! will be tied to the lifetime of document, possibly simplyfing memory
//! management. <br><br> Call allocate_node() or allocate_attribute() functions
//! to obtain new nodes or attributes from the pool. You can also call
//! allocate_string() function to allocate strings. Such strings can then be
//! used as names or values of nodes without worrying about their lifetime. Note
//! that there is no <code>free()</code> function -- all allocations are freed
//! at once when clear() function is called, or when the pool is destroyed.
//! <br><br>
//! It is also possible to create a standalone memory_pool, and use it
//! to allocate nodes, whose lifetime will not be tied to any document.
//! <br><br>
//! Pool maintains <code>RAPIDXML_STATIC_POOL_SIZE</code> bytes of statically
//! allocated memory. Until static memory is exhausted, no dynamic memory
//! allocations are done. When static memory is exhausted, pool allocates
//! additional blocks of memory of size <code>RAPIDXML_DYNAMIC_POOL_SIZE</code>
//! each, by using global <code>new[]</code> and <code>delete[]</code>
//! operators. This behaviour can be changed by setting custom allocation
//! routines. Use set_allocator() function to set them. <br><br> Allocations for
//! nodes, attributes and strings are aligned at <code>RAPIDXML_ALIGNMENT</code>
//! bytes. This value defaults to the size of pointer on target architecture.
//! <br><br>
//! To obtain absolutely top performance from the parser,
//! it is important that all nodes are allocated from a single, contiguous block
//! of memory. Otherwise, cache misses when jumping between two (or more)
//! disjoint blocks of memory can slow down parsing quite considerably. If
//! required, you can tweak <code>RAPIDXML_STATIC_POOL_SIZE</code>,
//! <code>RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>RAPIDXML_ALIGNMENT</code>
//! to obtain best wasted memory to performance compromise.
//! To do it, define their values before rapidxml.hpp file is included.
//! \param Ch Character type of created nodes.
template <class Ch = char> class memory_pool {

public:
  //! \cond internal
  typedef void *(alloc_func)(
      std::size_t); // Type of user-defined function used to allocate memory
  typedef void(free_func)(
      void *); // Type of user-defined function used to free memory
  //! \endcond

  //! Constructs empty pool with default allocator functions.
  memory_pool() : m_alloc_func(0), m_free_func(0) { init(); }

  //! Destroys pool and frees all the memory.
  //! This causes memory occupied by nodes allocated by the pool to be freed.
  //! Nodes allocated from the pool are no longer valid.
  ~memory_pool() { clear(); }

  //! Allocates a new node from the pool, and optionally assigns name and value
  //! to it. If the allocation request cannot be accomodated, this function will
  //! throw <code>std::bad_alloc</code>. If exceptions are disabled by defining
  //! RAPIDXML_NO_EXCEPTIONS, this function will call
  //! rapidxml::parse_error_handler() function. \param type Type of node to
  //! create. \param name Name to assign to the node, or 0 to assign no name.
  //! \param value Value to assign to the node, or 0 to assign no value.
  //! \param name_size Size of name to assign, or 0 to automatically calculate
  //! size from name string. \param value_size Size of value to assign, or 0 to
  //! automatically calculate size from value string. \return Pointer to
  //! allocated node. This pointer will never be NULL.
  xml_node<Ch> *allocate_node(node_type type, const Ch *name = 0,
                              const Ch *value = 0, std::size_t name_size = 0,
                              std::size_t value_size = 0) {
    void *memory = allocate_aligned(sizeof(xml_node<Ch>));
    xml_node<Ch> *node = new (memory) xml_node<Ch>(type);
    if (name) {
      if (name_size > 0)
        node->name(name, name_size);
      else
        node->name(name);
    } else {
      node->name(this->nullstr(), 0);
    }
    if (value) {
      if (value_size > 0)
        node->value(value, value_size);
      else
        node->value(value);
    } else {
      node->value(this->nullstr(), 0);
    }
    return node;
  }

  //! Allocates a new attribute from the pool, and optionally assigns name and
  //! value to it. If the allocation request cannot be accomodated, this
  //! function will throw <code>std::bad_alloc</code>. If exceptions are
  //! disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call
  //! rapidxml::parse_error_handler() function. \param name Name to assign to
  //! the attribute, or 0 to assign no name. \param value Value to assign to the
  //! attribute, or 0 to assign no value. \param name_size Size of name to
  //! assign, or 0 to automatically calculate size from name string. \param
  //! value_size Size of value to assign, or 0 to automatically calculate size
  //! from value string. \return Pointer to allocated attribute. This pointer
  //! will never be NULL.
  xml_attribute<Ch> *allocate_attribute(const Ch *name = 0, const Ch *value = 0,
                                        std::size_t name_size = 0,
                                        std::size_t value_size = 0) {
    void *memory = allocate_aligned(sizeof(xml_attribute<Ch>));
    xml_attribute<Ch> *attribute = new (memory) xml_attribute<Ch>;
    if (name) {
      if (name_size > 0)
        attribute->name(name, name_size);
      else
        attribute->name(name);
    }
    if (value) {
      if (value_size > 0)
        attribute->value(value, value_size);
      else
        attribute->value(value);
    }
    return attribute;
  }

  //! Allocates a char array of given size from the pool, and optionally copies
  //! a given string to it. If the allocation request cannot be accomodated,
  //! this function will throw <code>std::bad_alloc</code>. If exceptions are
  //! disabled by defining RAPIDXML_NO_EXCEPTIONS, this function will call
  //! rapidxml::parse_error_handler() function. \param source String to
  //! initialize the allocated memory with, or 0 to not initialize it. \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. \return Pointer to allocated char array.
  //! This pointer will never be NULL.
  template <typename Sch>
  Ch *allocate_string(const Sch *source = 0, std::size_t size = 0) {
    assert(source || size); // Either source or size (or both) must be specified
    if (size == 0)
      size = internal::measure(source) + 1;
    Ch *result = static_cast<Ch *>(allocate_aligned(size * sizeof(Ch)));
    if (source)
      for (std::size_t i = 0; i < size; ++i)
        result[i] = source[i];
    return result;
  }

  Ch *nullstr() {
    if (!m_nullstr)
      m_nullstr = allocate_string("");
    return m_nullstr;
  }
  Ch *xmlns_xml(std::size_t &xmlns_size) {
    if (!m_xmlns_xml)
      m_xmlns_xml = allocate_string("http://www.w3.org/XML/1998/namespace");
    xmlns_size = internal::measure(m_xmlns_xml);
    return m_xmlns_xml;
  }
  Ch *xmlns_xmlns(std::size_t &xmlns_size) {
    if (!m_xmlns_xmlns)
      m_xmlns_xmlns = allocate_string("http://www.w3.org/2000/xmlns/");
    xmlns_size = internal::measure(m_xmlns_xmlns);
    return m_xmlns_xmlns;
  }

  //! Clones an xml_node and its hierarchy of child nodes and attributes.
  //! Nodes and attributes are allocated from this memory pool.
  //! Names and values are not cloned, they are shared between the clone and the
  //! source. Result node can be optionally specified as a second parameter, in
  //! which case its contents will be replaced with cloned source node. This is
  //! useful when you want to clone entire document. \param source Node to
  //! clone. \param result Node to put results in, or 0 to automatically
  //! allocate result node \return Pointer to cloned node. This pointer will
  //! never be NULL.
  xml_node<Ch> *clone_node(const xml_node<Ch> *source,
                           xml_node<Ch> *result = 0) {
    // Prepare result node
    if (result) {
      result->remove_all_attributes();
      result->remove_all_nodes();
      result->type(source->type());
    } else
      result = allocate_node(source->type());

    // Clone name and value
    result->name(source->name(), source->name_size());
    result->value(source->value(), source->value_size());

    // Clone child nodes and attributes
    for (xml_node<Ch> *child = source->first_node(); child;
         child = child->next_sibling())
      result->append_node(clone_node(child));
    for (xml_attribute<Ch> *attr = source->first_attribute(); attr;
         attr = attr->next_attribute())
      result->append_attribute(allocate_attribute(
          attr->name(), attr->value(), attr->name_size(), attr->value_size()));

    return result;
  }

  //! Clears the pool.
  //! This causes memory occupied by nodes allocated by the pool to be freed.
  //! Any nodes or strings allocated from the pool will no longer be valid.
  void clear() {
    while (m_begin != m_static_memory) {
      char *previous_begin =
          reinterpret_cast<header *>(align(m_begin))->previous_begin;
      if (m_free_func)
        m_free_func(m_begin);
      else
        delete[] m_begin;
      m_begin = previous_begin;
    }
    init();
  }

  //! Sets or resets the user-defined memory allocation functions for the pool.
  //! This can only be called when no memory is allocated from the pool yet,
  //! otherwise results are undefined. Allocation function must not return
  //! invalid pointer on failure. It should either throw, stop the program, or
  //! use <code>longjmp()</code> function to pass control to other place of
  //! program. If it returns invalid pointer, results are undefined. <br><br>
  //! User defined allocation functions must have the following forms:
  //! <br><code>
  //! <br>void *allocate(std::size_t size);
  //! <br>void free(void *pointer);
  //! </code><br>
  //! \param af Allocation function, or 0 to restore default function
  //! \param ff Free function, or 0 to restore default function
  void set_allocator(alloc_func *af, free_func *ff) {
    assert(m_begin == m_static_memory &&
           m_ptr == align(m_begin)); // Verify that no memory is allocated yet
    m_alloc_func = af;
    m_free_func = ff;
  }

private:
  struct header {
    char *previous_begin;
  };

  void init() {
    m_begin = m_static_memory;
    m_ptr = align(m_begin);
    m_end = m_static_memory + sizeof(m_static_memory);
    m_nullstr = 0;
    m_xmlns_xml = 0;
    m_xmlns_xmlns = 0;
  }

  char *align(char *ptr) {
    std::size_t alignment =
        ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) &
         (RAPIDXML_ALIGNMENT - 1));
    return ptr + alignment;
  }

  char *allocate_raw(std::size_t size) {
    // Allocate
    void *memory;
    if (m_alloc_func) // Allocate memory using either user-specified allocation
                      // function or global operator new[]
    {
      memory = m_alloc_func(size);
      assert(memory); // Allocator is not allowed to return 0, on failure it
                      // must either throw, stop the program or use longjmp
    } else {
      memory = new char[size];
#ifdef RAPIDXML_NO_EXCEPTIONS
      if (!memory) // If exceptions are disabled, verify memory allocation,
                   // because new will not be able to throw bad_alloc
        RAPIDXML_PARSE_ERROR("out of memory", 0);
#endif
    }
    return static_cast<char *>(memory);
  }

  void *allocate_aligned(std::size_t size) {
    // Calculate aligned pointer
    char *result = align(m_ptr);

    // If not enough memory left in current pool, allocate a new pool
    if (result + size > m_end) {
      // Calculate required pool size (may be bigger than
      // RAPIDXML_DYNAMIC_POOL_SIZE)
      std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE;
      if (pool_size < size)
        pool_size = size;

      // Allocate
      std::size_t alloc_size =
          sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) +
          pool_size; // 2 alignments required in worst case: one for header, one
                     // for actual allocation
      char *raw_memory = allocate_raw(alloc_size);

      // Setup new pool in allocated memory
      char *pool = align(raw_memory);
      header *new_header = reinterpret_cast<header *>(pool);
      new_header->previous_begin = m_begin;
      m_begin = raw_memory;
      m_ptr = pool + sizeof(header);
      m_end = raw_memory + alloc_size;

      // Calculate aligned pointer again using new pool
      result = align(m_ptr);
    }

    // Update pool and return aligned pointer
    m_ptr = result + size;
    return result;
  }

  char *m_begin; // Start of raw memory making up current pool
  char *m_ptr;   // First free byte in current pool
  char *m_end;   // One past last available byte in current pool
  char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory
  alloc_func *m_alloc_func; // Allocator function, or 0 if default is to be used
  free_func *m_free_func;   // Free function, or 0 if default is to be used
  Ch *m_nullstr;
  Ch *m_xmlns_xml;
  Ch *m_xmlns_xmlns;
};

///////////////////////////////////////////////////////////////////////////
// XML base

//! Base class for xml_node and xml_attribute implementing common functions:
//! name(), name_size(), value(), value_size() and parent().
//! \param Ch Character type to use
template <class Ch = char> class xml_base {

public:
  ///////////////////////////////////////////////////////////////////////////
  // Construction & destruction

  // Construct a base with empty name, value and parent
  xml_base()
      : m_name(0), m_value(0), m_name_size(0), m_value_size(0), m_parent(0) {}

  ///////////////////////////////////////////////////////////////////////////
  // Node data access

  //! Gets name of the node.
  //! Interpretation of name depends on type of node.
  //! Note that name will not be zero-terminated if
  //! rapidxml::parse_no_string_terminators option was selected during parse.
  //! <br><br>
  //! Use name_size() function to determine length of the name.
  //! \return Name of node, or empty string if node has no name.
  Ch *name() const { return m_name; }

  //! Gets size of node name, not including terminator character.
  //! This function works correctly irrespective of whether name is or is not
  //! zero terminated. \return Size of node name, in characters.
  std::size_t name_size() const { return m_name ? m_name_size : 0; }

  //! Gets value of node.
  //! Interpretation of value depends on type of node.
  //! Note that value will not be zero-terminated if
  //! rapidxml::parse_no_string_terminators option was selected during parse.
  //! <br><br>
  //! Use value_size() function to determine length of the value.
  //! \return Value of node, or empty string if node has no value.
  Ch *value() const { return m_value; }

  //! Gets size of node value, not including terminator character.
  //! This function works correctly irrespective of whether value is or is not
  //! zero terminated. \return Size of node value, in characters.
  std::size_t value_size() const { return m_value ? m_value_size : 0; }
  ///////////////////////////////////////////////////////////////////////////
  // Node modification

  //! Sets name of node to a non zero-terminated string.
  //! See \ref ownership_of_strings.
  //! <br><br>
  //! Note that node does not own its name or value, it only stores a pointer to
  //! it. It will not delete or otherwise free the pointer on destruction. It is
  //! reponsibility of the user to properly manage lifetime of the string. The
  //! easiest way to achieve it is to use memory_pool of the document to
  //! allocate the string - on destruction of the document the string will be
  //! automatically freed. <br><br> Size of name must be specified separately,
  //! because name does not have to be zero terminated. Use name(const Ch *)
  //! function to have the length automatically calculated (string must be zero
  //! terminated). \param name Name of node to set. Does not have to be zero
  //! terminated. \param size Size of name, in characters. This does not include
  //! zero terminator, if one is present.
  void name(const Ch *name, std::size_t size) {
    m_name = const_cast<Ch *>(name);
    m_name_size = size;
  }

  //! Sets name of node to a zero-terminated string.
  //! See also \ref ownership_of_strings and xml_node::name(const Ch *,
  //! std::size_t). \param name Name of node to set. Must be zero terminated.
  void name(const Ch *name) { this->name(name, internal::measure(name)); }

  //! Sets value of node to a non zero-terminated string.
  //! See \ref ownership_of_strings.
  //! <br><br>
  //! Note that node does not own its name or value, it only stores a pointer to
  //! it. It will not delete or otherwise free the pointer on destruction. It is
  //! reponsibility of the user to properly manage lifetime of the string. The
  //! easiest way to achieve it is to use memory_pool of the document to
  //! allocate the string - on destruction of the document the string will be
  //! automatically freed. <br><br> Size of value must be specified separately,
  //! because it does not have to be zero terminated. Use value(const Ch *)
  //! function to have the length automatically calculated (string must be zero
  //! terminated). <br><br> If an element has a child node of type node_data, it
  //! will take precedence over element value when printing. 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. \param value value of node to set. Does not have to be zero
  //! terminated. \param size Size of value, in characters. This does not
  //! include zero terminator, if one is present.
  void value(const Ch *value, std::size_t size) {
    m_value = const_cast<Ch *>(value);
    m_value_size = size;
  }

  //! Sets value of node to a zero-terminated string.
  //! See also \ref ownership_of_strings and xml_node::value(const Ch *,
  //! std::size_t). \param value Vame of node to set. Must be zero terminated.
  void value(const Ch *value) { this->value(value, internal::measure(value)); }
  ///////////////////////////////////////////////////////////////////////////
  // Related nodes access

  //! Gets node parent.
  //! \return Pointer to parent node, or 0 if there is no parent.
  xml_node<Ch> *parent() const { return m_parent; }

protected:
  Ch *m_name;               // Name of node, or 0 if no name
  Ch *m_value;              // Value of node, or 0 if no value
  std::size_t m_name_size;  // Length of node name, or undefined of no name
  std::size_t m_value_size; // Length of node value, or undefined if no value
  xml_node<Ch> *m_parent;   // Pointer to parent node, or 0 if none
};

//! Class representing attribute node of XML document.
//! Each attribute has name and value strings, which are available through
//! name() and value() functions (inherited from xml_base). Note that after
//! parse, both name and value of attribute will point to interior of source
//! text used for parsing. Thus, this text must persist in memory for the
//! lifetime of attribute. \param Ch Character type to use.
template <class Ch = char> class xml_attribute : public xml_base<Ch> {

  friend class xml_node<Ch>;

public:
  ///////////////////////////////////////////////////////////////////////////
  // Construction & destruction

  //! Constructs an empty attribute with the specified type.
  //! Consider using memory_pool of appropriate xml_document if allocating
  //! attributes manually.
  xml_attribute()
      : m_prev_attribute(0), m_next_attribute(0), m_xmlns(0), m_xmlns_size(0),
        m_local_name(0) {}

  ///////////////////////////////////////////////////////////////////////////
  // Related nodes access

  //! Gets document of which attribute is a child.
  //! \return Pointer to document that contains this attribute, or 0 if there is
  //! no parent document.
  xml_document<Ch> *document() const {
    if (xml_node<Ch> *node = this->parent()) {
      while (node->parent())
        node = node->parent();
      return node->type() == node_document
                 ? static_cast<xml_document<Ch> *>(node)
                 : 0;
    } else
      return 0;
  }

  Ch *xmlns() const {
    if (m_xmlns)
      return m_xmlns;
    Ch *p;
    Ch *name = this->name();
    for (p = name; *p && *p != ':'; ++p)
      if ((p - name) >= this->name_size())
        break;
    if (!*p || ((p - name) >= this->name_size())) {
      m_xmlns = document()->nullstr();
      m_xmlns_size = 0;
      return m_xmlns;
    }
    xml_node<Ch> *element = this->parent();
    if (element)
      element->xmlns_lookup(m_xmlns, m_xmlns_size, name, p - name);
    return m_xmlns;
  }
  std::size_t xmlns_size() const { return this->xmlns() ? m_xmlns_size : 0; }
  //! Gets previous attribute, optionally matching attribute name.
  //! \param name Name of attribute to find, or 0 to return previous attribute
  //! regardless of its name; this string doesn't have to be zero-terminated if
  //! name_size is non-zero \param name_size Size of name, in characters, or 0
  //! to have size calculated automatically from string \param case_sensitive
  //! Should name comparison be case-sensitive; non case-sensitive comparison
  //! works properly only for ASCII characters \return Pointer to found
  //! attribute, or 0 if not found.
  xml_attribute<Ch> *previous_attribute(const Ch *name = 0,
                                        std::size_t name_size = 0,
                                        bool case_sensitive = true) const {
    if (name) {
      if (name_size == 0)
        name_size = internal::measure(name);
      for (xml_attribute<Ch> *attribute = m_prev_attribute; attribute;
           attribute = attribute->m_prev_attribute)
        if (internal::compare(attribute->name(), attribute->name_size(), name,
                              name_size, case_sensitive))
          return attribute;
      return 0;
    } else
      return this->m_parent ? m_prev_attribute : 0;
  }

  //! Gets next attribute, optionally matching attribute name.
  //! \param name Name of attribute to find, or 0 to return next attribute
  //! regardless of its name; this string doesn't have to be zero-terminated if
  //! name_size is non-zero \param name_size Size of name, in characters, or 0
  //! to have size calculated automatically from string \param case_sensitive
  //! Should name comparison be case-sensitive; non case-sensitive comparison
  //! works properly only for ASCII characters \return Pointer to found
  //! attribute, or 0 if not found.
  xml_attribute<Ch> *next_attribute(const Ch *name = 0,
                                    std::size_t name_size = 0,
                                    bool case_sensitive = true) const {
    if (name) {
      if (name_size == 0)
        name_size = internal::measure(name);
      for (xml_attribute<Ch> *attribute = m_next_attribute; attribute;
           attribute = attribute->m_next_attribute)
        if (internal::compare(attribute->name(), attribute->name_size(), name,
                              name_size, case_sensitive))
          return attribute;
      return 0;
    } else
      return this->m_parent ? m_next_attribute : 0;
  }

  Ch *local_name() const {
    if (m_local_name)
      return m_local_name;
    Ch *p = this->name();
    for (; *p && *p != Ch(':'); ++p)
      ;
    if (*p)
      m_local_name = p + 1;
    else
      m_local_name = this->name();
    return m_local_name;
  }

  std::size_t local_name_size() const {
    return this->name_size() - (this->local_name() - this->name());
  }

private:
  xml_attribute<Ch>
      *m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if
                         // none; only valid if parent is non-zero
  xml_attribute<Ch>
      *m_next_attribute; // Pointer to next sibling of attribute, or 0 if none;
                         // only valid if parent is non-zero
  mutable Ch *m_xmlns;
  mutable std::size_t m_xmlns_size;
  mutable Ch *m_local_name; // ATTN: points inside m_name.
};

///////////////////////////////////////////////////////////////////////////
// XML node

//! Class representing a node of XML document.
//! Each node may have associated name and value strings, which are available
//! through name() and value() functions. Interpretation of name and value
//! depends on type of the node. Type of node can be determined by using type()
//! function. <br><br> Note that after parse, both name and value of node, if
//! any, will point interior of source text used for parsing. Thus, this text
//! must persist in the memory for the lifetime of node. \param Ch Character
//! type to use.
template <class Ch = char> class xml_node : public xml_base<Ch> {

public:
  ///////////////////////////////////////////////////////////////////////////
  // Construction & destruction

  //! Constructs an empty node with the specified type.
  //! Consider using memory_pool of appropriate document to allocate nodes
  //! manually. \param type Type of node to construct.
  xml_node(node_type type)
      : m_prefix(0), m_xmlns(0), m_prefix_size(0), m_xmlns_size(0),
        m_type(type), m_first_node(0), m_last_node(0), m_first_attribute(0),
        m_last_attribute(0), m_prev_sibling(0), m_next_sibling(0),
        m_contents(0), m_contents_size(0) {}

  ///////////////////////////////////////////////////////////////////////////
  // Node data access

  //! Gets type of node.
  //! \return Type of node.
  node_type type() const { return m_type; }

  void prefix(const Ch *prefix, std::size_t size) {
    m_prefix = const_cast<Ch *>(prefix);
    m_prefix_size = size;
  }
  void prefix(const Ch *prefix) {
    this->prefix(prefix, internal::measure(prefix));
  }

  Ch *prefix() const { return m_prefix; }

  std::size_t prefix_size() const { return m_prefix ? m_prefix_size : 0; }

  void contents(Ch const *contents, std::size_t contents_size) {
    m_contents = contents;
    m_contents_size = contents_size;
  }
  Ch const *contents() const { return m_contents; }
  std::size_t contents_size() const { return m_contents ? m_contents_size : 0; }

  Ch *xmlns() const {
    if (m_xmlns)
      return m_xmlns;
    xmlns_lookup(m_xmlns, m_xmlns_size, m_prefix, m_prefix_size);
    return m_xmlns;
  }

  void xmlns_lookup(Ch *&xmlns, size_t &xmlns_size, Ch *prefix,
                    size_t prefix_size) const {
    Ch *freeme = 0;
    Ch *attrname;
    if (prefix) {
      // Check if the prefix begins "xml".
      if (prefix_size >= 3 && prefix[0] == Ch('x') && prefix[1] == Ch('m') &&
          prefix[2] == Ch('l')) {
        if (prefix_size == 3) {
          xmlns = this->document()->xmlns_xml(xmlns_size);
          return;
        } else if (prefix_size == 5 && prefix[3] == Ch('n') &&
                   prefix[4] == Ch('s')) {
          xmlns = this->document()->xmlns_xmlns(xmlns_size);
          return;
        }
      }
      freeme = attrname = new Ch[prefix_size + 7];
      const char *p1 = "xmlns";
      while (*p1)
        *attrname++ = *p1++;
      Ch *p = prefix;
      *attrname++ = Ch(':');
      while (*p) {
        *attrname++ = *p++;
        if ((attrname - freeme) >= std::ptrdiff_t(prefix_size + 6))
          break;
      }
      *attrname = Ch(0);
      attrname = freeme;
    } else {
      freeme = attrname = new Ch[6];
      const char *p1 = "xmlns";
      while (*p1)
        *attrname++ = *p1++;
      *attrname = Ch(0);
      attrname = freeme;
    }
    for (const xml_node<Ch> *node = this; node; node = node->parent()) {
      const xml_attribute<Ch> *attr = node->first_attribute(attrname);
      if (attr) {
        xmlns = attr->value();
        if (xmlns) {
          xmlns_size = attr->value_size();
        }
        break;
      }
    }
    if (!xmlns) {
      if (!prefix) {
        xmlns = document()->nullstr();
        xmlns_size = 0;
      }
    }
    if (freeme)
      delete[] freeme;
  }

  std::size_t xmlns_size() const {
    if (m_xmlns)
      return m_xmlns_size;
    this->xmlns();
    return m_xmlns_size;
  }

  ///////////////////////////////////////////////////////////////////////////
  // Related nodes access

  //! Gets document of which node is a child.
  //! \return Pointer to document that contains this node, or 0 if there is no
  //! parent document.
  xml_document<Ch> *document() const {
    xml_node<Ch> *node = const_cast<xml_node<Ch> *>(this);
    while (node->parent())
      node = node->parent();
    return node->type() == node_document ? static_cast<xml_document<Ch> *>(node)
                                         : 0;
  }

  //! Gets first child node, optionally matching node name.
  //! \param name Name of child to find, or 0 to return first child regardless
  //! of its name; this string doesn't have to be zero-terminated if name_size
  //! is non-zero \param name_size Size of name, in characters, or 0 to have
  //! size calculated automatically from string \param case_sensitive Should
  //! name comparison be case-sensitive; non case-sensitive comparison works
  //! properly only for ASCII characters \return Pointer to found child, or 0 if
  //! not found.
  xml_node<Ch> *first_node(const Ch *name = 0, const Ch *xmlns = 0,
                           std::size_t name_size = 0,
                           std::size_t xmlns_size = 0,
                           bool case_sensitive = true) const {
    if (name && !name_size)
      name_size = internal::measure(name);
    if (xmlns && !xmlns_size)
      xmlns_size = internal::measure(xmlns);
    if (!xmlns && name) {
      // No XMLNS asked for, but a name is present.
      // Assume "same XMLNS".
      xmlns = this->xmlns();
      xmlns_size = this->xmlns_size();
    }
    for (xml_node<Ch> *child = m_first_node; child;
         child = child->next_sibling())
      if ((!name || internal::compare(child->name(), child->name_size(), name,
                                      name_size, case_sensitive)) &&
          (!xmlns || internal::compare(child->xmlns(), child->xmlns_size(),
                                       xmlns, xmlns_size, case_sensitive)))
        return child;
    return 0;
  }

  //! Gets last child node, optionally matching node name.
  //! Behaviour is undefined if node has no children.
  //! Use first_node() to test if node has children.
  //! \param name Name of child to find, or 0 to return last child regardless of
  //! its name; this string doesn't have to be zero-terminated if name_size is
  //! non-zero \param name_size Size of name, in characters, or 0 to have size
  //! calculated automatically from string \param case_sensitive Should name
  //! comparison be case-sensitive; non case-sensitive comparison works properly
  //! only for ASCII characters \return Pointer to found child, or 0 if not
  //! found.
  xml_node<Ch> *last_node(const Ch *name = 0, const Ch *xmlns = 0,
                          std::size_t name_size = 0, std::size_t xmlns_size = 0,
                          bool case_sensitive = true) const {
    assert(m_first_node); // Cannot query for last child if node has no children
    if (name && !name_size)
      name_size = internal::measure(name);
    if (xmlns && !xmlns_size)
      xmlns_size = internal::measure(xmlns);
    if (!xmlns && name) {
      // No XMLNS asked for, but a name is present.
      // Assume "same XMLNS".
      xmlns = this->xmlns();
      xmlns_size = this->xmlns_size();
    }
    for (xml_node<Ch> *child = m_last_node; child;
         child = child->previous_sibling())
      if ((!name || internal::compare(child->name(), child->name_size(), name,
                                      name_size, case_sensitive)) &&
          (!xmlns || internal::compare(child->xmlns(), child->xmlns_size(),
                                       xmlns, xmlns_size, case_sensitive)))
        return child;
    return 0;
  }

  //! Gets previous sibling node, optionally matching node name.
  //! Behaviour is undefined if node has no parent.
  //! Use parent() to test if node has a parent.
  //! \param name Name of sibling to find, or 0 to return previous sibling
  //! regardless of its name; this string doesn't have to be zero-terminated if
  //! name_size is non-zero \param name_size Size of name, in characters, or 0
  //! to have size calculated automatically from string \param case_sensitive
  //! Should name comparison be case-sensitive; non case-sensitive comparison
  //! works properly only for ASCII characters \return Pointer to found sibling,
  //! or 0 if not found.
  xml_node<Ch> *previous_sibling(const Ch *name = 0, const Ch *xmlns = 0,
                                 std::size_t name_size = 0,
                                 std::size_t xmlns_size = 0,
                                 bool case_sensitive = true) const {
    assert(this->m_parent); // Cannot query for siblings if node has no parent
    if (name) {
      if (name_size == 0)
        name_size = internal::measure(name);
      if (xmlns && !xmlns_size)
        xmlns_size = internal::measure(xmlns);
      if (!xmlns && name) {
        // No XMLNS asked for, but a name is present.
        // Assume "same XMLNS".
        xmlns = this->xmlns();
        xmlns_size = this->xmlns_size();
      }
      for (xml_node<Ch> *sibling = m_prev_sibling; sibling;
           sibling = sibling->m_prev_sibling)
        if ((!name || internal::compare(sibling->name(), sibling->name_size(),
                                        name, name_size, case_sensitive)) &&
            (!xmlns ||
             internal::compare(sibling->xmlns(), sibling->xmlns_size(), xmlns,
                               xmlns_size, case_sensitive)))
          return sibling;
      return 0;
    } else
      return m_prev_sibling;
  }

  //! Gets next sibling node, optionally matching node name.
  //! Behaviour is undefined if node has no parent.
  //! Use parent() to test if node has a parent.
  //! \param name Name of sibling to find, or 0 to return next sibling
  //! regardless of its name; this string doesn't have to be zero-terminated if
  //! name_size is non-zero \param name_size Size of name, in characters, or 0
  //! to have size calculated automatically from string \param case_sensitive
  //! Should name comparison be case-sensitive; non case-sensitive comparison
  //! works properly only for ASCII characters \return Pointer to found sibling,
  //! or 0 if not found.
  xml_node<Ch> *next_sibling(const Ch *name = 0, const Ch *xmlns = 0,
                             std::size_t name_size = 0,
                             std::size_t xmlns_size = 0,
                             bool case_sensitive = true) const {
    assert(this->m_parent); // Cannot query for siblings if node has no parent
    if (name) {
      if (name_size == 0)
        name_size = internal::measure(name);
      if (xmlns && !xmlns_size)
        xmlns_size = internal::measure(xmlns);
      if (!xmlns && name) {
        // No XMLNS asked for, but a name is present.
        // Assume "same XMLNS".
        xmlns = this->xmlns();
        xmlns_size = this->xmlns_size();
      }
      for (xml_node<Ch> *sibling = m_next_sibling; sibling;
           sibling = sibling->m_next_sibling)
        if ((!name || internal::compare(sibling->name(), sibling->name_size(),
                                        name, name_size, case_sensitive)) &&
            (!xmlns ||
             internal::compare(sibling->xmlns(), sibling->xmlns_size(), xmlns,
                               xmlns_size, case_sensitive)))
          return sibling;
      return 0;
    } else
      return m_next_sibling;
  }

  //! Gets first attribute of node, optionally matching attribute name.
  //! \param name Name of attribute to find, or 0 to return first attribute
  //! regardless of its name; this string doesn't have to be zero-terminated if
  //! name_size is non-zero \param name_size Size of name, in characters, or 0
  //! to have size calculated automatically from string \param case_sensitive
  //! Should name comparison be case-sensitive; non case-sensitive comparison
  //! works properly only for ASCII characters \return Pointer to found
  //! attribute, or 0 if not found.
  xml_attribute<Ch> *first_attribute(const Ch *name = 0,
                                     std::size_t name_size = 0,
                                     bool case_sensitive = true) const {
    if (name) {
      if (name_size == 0)
        name_size = internal::measure(name);
      for (xml_attribute<Ch> *attribute = m_first_attribute; attribute;
           attribute = attribute->m_next_attribute)
        if (internal::compare(attribute->name(), attribute->name_size(), name,
                              name_size, case_sensitive))
          return attribute;
      return 0;
    } else
      return m_first_attribute;
  }

  //! Gets last attribute of node, optionally matching attribute name.
  //! \param name Name of attribute to find, or 0 to return last attribute
  //! regardless of its name; this string doesn't have to be zero-terminated if
  //! name_size is non-zero \param name_size Size of name, in characters, or 0
  //! to have size calculated automatically from string \param case_sensitive
  //! Should name comparison be case-sensitive; non case-sensitive comparison
  //! works properly only for ASCII characters \return Pointer to found
  //! attribute, or 0 if not found.
  xml_attribute<Ch> *last_attribute(const Ch *name = 0,
                                    std::size_t name_size = 0,
                                    bool case_sensitive = true) const {
    if (name) {
      if (name_size == 0)
        name_size = internal::measure(name);
      for (xml_attribute<Ch> *attribute = m_last_attribute; attribute;
           attribute = attribute->m_prev_attribute)
        if (internal::compare(attribute->name(), attribute->name_size(), name,
                              name_size, case_sensitive))
          return attribute;
      return 0;
    } else
      return m_first_attribute ? m_last_attribute : 0;
  }

  ///////////////////////////////////////////////////////////////////////////
  // Node modification

  //! Sets type of node.
  //! \param type Type of node to set.
  void type(node_type type) { m_type = type; }

  ///////////////////////////////////////////////////////////////////////////
  // Node manipulation

  //! Prepends a new child node.
  //! The prepended child becomes the first child, and all existing children are
  //! moved one position back. \param child Node to prepend.
  void prepend_node(xml_node<Ch> *child) {
    assert(child && !child->parent() && child->type() != node_document);
    if (first_node()) {
      child->m_next_sibling = m_first_node;
      m_first_node->m_prev_sibling = child;
    } else {
      child->m_next_sibling = 0;
      m_last_node = child;
    }
    m_first_node = child;
    child->m_parent = this;
    child->m_prev_sibling = 0;
  }

  //! Appends a new child node.
  //! The appended child becomes the last child.
  //! \param child Node to append.
  void append_node(xml_node<Ch> *child) {
    assert(child && !child->parent() && child->type() != node_document);
    if (first_node()) {
      child->m_prev_sibling = m_last_node;
      m_last_node->m_next_sibling = child;
    } else {
      child->m_prev_sibling = 0;
      m_first_node = child;
    }
    m_last_node = child;
    child->m_parent = this;
    child->m_next_sibling = 0;
  }

  //! Inserts a new child node at specified place inside the node.
  //! All children after and including the specified node are moved one position
  //! back. \param where Place where to insert the child, or 0 to insert at the
  //! back. \param child Node to insert.
  void insert_node(xml_node<Ch> *where, xml_node<Ch> *child) {
    assert(!where || where->parent() == this);
    assert(child && !child->parent() && child->type() != node_document);
    if (where == m_first_node)
      prepend_node(child);
    else if (where == 0)
      append_node(child);
    else {
      child->m_prev_sibling = where->m_prev_sibling;
      child->m_next_sibling = where;
      where->m_prev_sibling->m_next_sibling = child;
      where->m_prev_sibling = child;
      child->m_parent = this;
    }
  }

  //! Removes first child node.
  //! If node has no children, behaviour is undefined.
  //! Use first_node() to test if node has children.
  void remove_first_node() {
    assert(first_node());
    xml_node<Ch> *child = m_first_node;
    m_first_node = child->m_next_sibling;
    if (child->m_next_sibling)
      child->m_next_sibling->m_prev_sibling = 0;
    else
      m_last_node = 0;
    child->m_parent = 0;
  }

  //! Removes last child of the node.
  //! If node has no children, behaviour is undefined.
  //! Use first_node() to test if node has children.
  void remove_last_node() {
    assert(first_node());
    xml_node<Ch> *child = m_last_node;
    if (child->m_prev_sibling) {
      m_last_node = child->m_prev_sibling;
      child->m_prev_sibling->m_next_sibling = 0;
    } else
      m_first_node = 0;
    child->m_parent = 0;
  }

  //! Removes specified child from the node
  // \param where Pointer to child to be removed.
  void remove_node(xml_node<Ch> *where) {
    assert(where && where->parent() == this);
    assert(first_node());
    if (where == m_first_node)
      remove_first_node();
    else if (where == m_last_node)
      remove_last_node();
    else {
      where->m_prev_sibling->m_next_sibling = where->m_next_sibling;
      where->m_next_sibling->m_prev_sibling = where->m_prev_sibling;
      where->m_parent = 0;
    }
  }

  //! Removes all child nodes (but not attributes).
  void remove_all_nodes() {
    for (xml_node<Ch> *node = first_node(); node; node = node->m_next_sibling)
      node->m_parent = 0;
    m_first_node = 0;
  }

  //! Prepends a new attribute to the node.
  //! \param attribute Attribute to prepend.
  void prepend_attribute(xml_attribute<Ch> *attribute) {
    assert(attribute && !attribute->parent());
    if (first_attribute()) {
      attribute->m_next_attribute = m_first_attribute;
      m_first_attribute->m_prev_attribute = attribute;
    } else {
      attribute->m_next_attribute = 0;
      m_last_attribute = attribute;
    }
    m_first_attribute = attribute;
    attribute->m_parent = this;
    attribute->m_prev_attribute = 0;
  }

  //! Appends a new attribute to the node.
  //! \param attribute Attribute to append.
  void append_attribute(xml_attribute<Ch> *attribute) {
    assert(attribute && !attribute->parent());
    if (first_attribute()) {
      attribute->m_prev_attribute = m_last_attribute;
      m_last_attribute->m_next_attribute = attribute;
    } else {
      attribute->m_prev_attribute = 0;
      m_first_attribute = attribute;
    }
    m_last_attribute = attribute;
    attribute->m_parent = this;
    attribute->m_next_attribute = 0;
  }

  //! Inserts a new attribute at specified place inside the node.
  //! All attributes after and including the specified attribute are moved one
  //! position back. \param where Place where to insert the attribute, or 0 to
  //! insert at the back. \param attribute Attribute to insert.
  void insert_attribute(xml_attribute<Ch> *where,
                        xml_attribute<Ch> *attribute) {
    assert(!where || where->parent() == this);
    assert(attribute && !attribute->parent());
    if (where == m_first_attribute)
      prepend_attribute(attribute);
    else if (where == 0)
      append_attribute(attribute);
    else {
      attribute->m_prev_attribute = where->m_prev_attribute;
      attribute->m_next_attribute = where;
      where->m_prev_attribute->m_next_attribute = attribute;
      where->m_prev_attribute = attribute;
      attribute->m_parent = this;
    }
  }

  //! Removes first attribute of the node.
  //! If node has no attributes, behaviour is undefined.
  //! Use first_attribute() to test if node has attributes.
  void remove_first_attribute() {
    assert(first_attribute());
    xml_attribute<Ch> *attribute = m_first_attribute;
    if (attribute->m_next_attribute) {
      attribute->m_next_attribute->m_prev_attribute = 0;
    } else
      m_last_attribute = 0;
    attribute->m_parent = 0;
    m_first_attribute = attribute->m_next_attribute;
  }

  //! Removes last attribute of the node.
  //! If node has no attributes, behaviour is undefined.
  //! Use first_attribute() to test if node has attributes.
  void remove_last_attribute() {
    assert(first_attribute());
    xml_attribute<Ch> *attribute = m_last_attribute;
    if (attribute->m_prev_attribute) {
      attribute->m_prev_attribute->m_next_attribute = 0;
      m_last_attribute = attribute->m_prev_attribute;
    } else
      m_first_attribute = 0;
    attribute->m_parent = 0;
  }

  //! Removes specified attribute from node.
  //! \param where Pointer to attribute to be removed.
  void remove_attribute(xml_attribute<Ch> *where) {
    assert(first_attribute() && where->parent() == this);
    if (where == m_first_attribute)
      remove_first_attribute();
    else if (where == m_last_attribute)
      remove_last_attribute();
    else {
      where->m_prev_attribute->m_next_attribute = where->m_next_attribute;
      where->m_next_attribute->m_prev_attribute = where->m_prev_attribute;
      where->m_parent = 0;
    }
  }

  //! Removes all attributes of node.
  void remove_all_attributes() {
    for (xml_attribute<Ch> *attribute = first_attribute(); attribute;
         attribute = attribute->m_next_attribute)
      attribute->m_parent = 0;
    m_first_attribute = 0;
  }

  void validate() const {
    if (this->xmlns() == 0)
      throw validation_error("Element XMLNS unbound");
    for (xml_node<Ch> *child = this->first_node(); child;
         child = child->next_sibling()) {
      child->validate();
    }
    for (xml_attribute<Ch> *attribute = first_attribute(); attribute;
         attribute = attribute->m_next_attribute) {
      if (attribute->xmlns() == 0)
        throw validation_error("Attribute XMLNS unbound");
      for (xml_attribute<Ch> *otherattr = first_attribute();
           otherattr != attribute; otherattr = otherattr->m_next_attribute) {
        if (internal::compare(attribute->name(), attribute->name_size(),
                              otherattr->name(), otherattr->name_size(),
                              true)) {
          throw validation_error("Attribute doubled");
        }
        if (internal::compare(
                attribute->local_name(), attribute->local_name_size(),
                otherattr->local_name(), otherattr->local_name_size(), true) &&
            internal::compare(attribute->xmlns(), attribute->xmlns_size(),
                              otherattr->xmlns(), otherattr->xmlns_size(),
                              true))
          throw validation_error("Attribute XMLNS doubled");
      }
    }
  }

private:
  ///////////////////////////////////////////////////////////////////////////
  // Restrictions

  // No copying
  xml_node(const xml_node &);
  void operator=(const xml_node &);

  ///////////////////////////////////////////////////////////////////////////
  // Data members

  // Note that some of the pointers below have UNDEFINED values if certain other
  // pointers are 0. This is required for maximum performance, as it allows the
  // parser to omit initialization of unneded/redundant values.
  //
  // The rules are as follows:
  // 1. first_node and first_attribute contain valid pointers, or 0 if node has
  // no children/attributes respectively
  // 2. last_node and last_attribute are valid only if node has at least one
  // child/attribute respectively, otherwise they contain garbage
  // 3. prev_sibling and next_sibling are valid only if node has a parent,
  // otherwise they contain garbage

  Ch *m_prefix;
  mutable Ch *m_xmlns; // Cache
  std::size_t m_prefix_size;
  mutable std::size_t m_xmlns_size;
  node_type m_type; // Type of node; always valid
  xml_node<Ch>
      *m_first_node; // Pointer to first child node, or 0 if none; always valid
  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
  xml_attribute<Ch> *m_first_attribute; // Pointer to first attribute of node,
                                        // or 0 if none; always valid
  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
  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
  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
  Ch const *m_contents; // Pointer to original contents in buffer.
  std::size_t m_contents_size;
};

///////////////////////////////////////////////////////////////////////////
// XML document

//! This class represents root of the DOM hierarchy.
//! It is also an xml_node and a memory_pool through public inheritance.
//! Use parse() function to build a DOM tree from a zero-terminated XML text
//! string. parse() function allocates memory for nodes and attributes by using
//! functions of xml_document, which are inherited from memory_pool. To access
//! root node of the document, use the document itself, as if it was an
//! xml_node. \param Ch Character type to use.
template <class Ch = char>
class xml_document : public xml_node<Ch>, public memory_pool<Ch> {

public:
  //! Constructs empty XML document
  xml_document() : xml_node<Ch>(node_document) {}

  //! Parses zero-terminated XML string according to given flags.
  //! Passed string will be modified by the parser, unless
  //! rapidxml::parse_non_destructive flag is used. The string must persist for
  //! the lifetime of the document. In case of error, rapidxml::parse_error
  //! exception will be thrown. <br><br> If you want to parse contents of a
  //! file, you must first load the file into the memory, and pass pointer to
  //! its beginning. Make sure that data is zero-terminated. <br><br> Document
  //! can be parsed into multiple times. Each new call to parse removes previous
  //! nodes and attributes (if any), but does not clear memory pool. \param text
  //! XML data to parse; pointer is non-const to denote fact that this data may
  //! be modified by the parser.
  template <int Flags> Ch *parse(Ch *text, xml_document<Ch> *parent = 0) {
    assert(text);

    // Remove current contents
    this->remove_all_nodes();
    this->remove_all_attributes();
    this->m_parent = parent ? parent->first_node() : 0;

    // Parse BOM, if any
    parse_bom<Flags>(text);

    // Parse children
    while (1) {
      // Skip whitespace before node
      skip<whitespace_pred, Flags>(text);
      if (*text == 0)
        break;

      // Parse and append new child
      if (*text == Ch('<')) {
        ++text; // Skip '<'
        if (xml_node<Ch> *node = parse_node<Flags>(text)) {
          this->append_node(node);
          if (Flags & (parse_open_only | parse_parse_one)) {
            if (node->type() == node_element)
              break;
          }
        }
      } else
        RAPIDXML_PARSE_ERROR("expected <", text);
    }
    if (!this->first_node())
      RAPIDXML_PARSE_ERROR("no root element", text);
    return text;
  }
  template <int Flags> Ch *parse(Ch *text, xml_document<Ch> &parent) {
    return parse<Flags>(text, &parent);
  }

  //! Clears the document by deleting all nodes and clearing the memory pool.
  //! All nodes owned by document pool are destroyed.
  void clear() {
    this->remove_all_nodes();
    this->remove_all_attributes();
    memory_pool<Ch>::clear();
  }

  //! Terminates and/or decodes existing parsed tree,
  //! optionally recursively.
  template <int Flags> void fixup(xml_node<Ch> *element, bool recurse) {
    // Check the type.
    if (element->type() == node_element) {
      // Terminate name and attributes
      if (!(Flags & parse_no_string_terminators))
        element->name()[element->name_size()] = 0;
      for (xml_attribute<Ch> *attr = element->first_attribute(); attr;
           attr = attr->next_attribute()) {
        if (!(Flags & parse_no_string_terminators))
          attr->name()[attr->name_size()] = 0;
        Ch *value = attr->value();
        Ch *p = value;
        Ch *end;
        const int AttFlags =
            Flags & ~parse_normalize_whitespace; // No whitespace normalization
                                                 // in attributes
        Ch quote = value[-1];
        if (quote == Ch('\''))
          end = skip_and_expand_character_refs<
              attribute_value_pred<Ch('\'')>,
              attribute_value_pure_pred<Ch('\'')>, AttFlags>(p);
        else
          end =
              skip_and_expand_character_refs<attribute_value_pred<Ch('"')>,
                                             attribute_value_pure_pred<Ch('"')>,
                                             AttFlags>(p);
        attr->value(value, end - value);
        if (!(Flags & parse_no_string_terminators))
          attr->value()[attr->value_size()] = 0;
      }
      if (recurse) {
        for (xml_node<Ch> *child = element->first_node(); child;
             child = child->next_sibling()) {
          this->fixup<Flags>(child, true);
        }
        if (!(Flags & parse_no_string_terminators) && element->value())
          element->value()[element->value_size()] = 0;
      }
    }
  }

  void validate() const {
    for (xml_node<Ch> *child = this->first_node(); child;
         child = child->next_sibling()) {
      child->validate();
    }
  }

private:
  ///////////////////////////////////////////////////////////////////////
  // Internal character utility functions

  // Detect whitespace character
  struct whitespace_pred {
    static unsigned char test(Ch ch) {
      return internal::lookup_tables<
          0>::lookup_whitespace[static_cast<unsigned char>(ch)];
    }
  };

  // Detect node name character
  struct node_name_pred {
    static unsigned char test(Ch ch) {
      return internal::lookup_tables<
          0>::lookup_node_name[static_cast<unsigned char>(ch)];
    }
  };

  // Detect element name character
  struct element_name_pred {
    static unsigned char test(Ch ch) {
      return internal::lookup_tables<
          0>::lookup_element_name[static_cast<unsigned char>(ch)];
    }
  };

  // Detect attribute name character
  struct attribute_name_pred {
    static unsigned char test(Ch ch) {
      return internal::lookup_tables<
          0>::lookup_attribute_name[static_cast<unsigned char>(ch)];
    }
  };

  // Detect text character (PCDATA)
  struct text_pred {
    static unsigned char test(Ch ch) {
      return internal::lookup_tables<0>::lookup_text[static_cast<unsigned char>(
          ch)];
    }
  };

  // Detect text character (PCDATA) that does not require processing
  struct text_pure_no_ws_pred {
    static unsigned char test(Ch ch) {
      return internal::lookup_tables<
          0>::lookup_text_pure_no_ws[static_cast<unsigned char>(ch)];
    }
  };

  // Detect text character (PCDATA) that does not require processing
  struct text_pure_with_ws_pred {
    static unsigned char test(Ch ch) {
      return internal::lookup_tables<
          0>::lookup_text_pure_with_ws[static_cast<unsigned char>(ch)];
    }
  };

  // Detect attribute value character
  template <Ch Quote> struct attribute_value_pred {
    static unsigned char test(Ch ch) {
      if (Quote == Ch('\''))
        return internal::lookup_tables<
            0>::lookup_attribute_data_1[static_cast<unsigned char>(ch)];
      if (Quote == Ch('\"'))
        return internal::lookup_tables<
            0>::lookup_attribute_data_2[static_cast<unsigned char>(ch)];
      return 0; // Should never be executed, to avoid warnings on Comeau
    }
  };

  // Detect attribute value character
  template <Ch Quote> struct attribute_value_pure_pred {
    static unsigned char test(Ch ch) {
      if (Quote == Ch('\''))
        return internal::lookup_tables<
            0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)];
      if (Quote == Ch('\"'))
        return internal::lookup_tables<
            0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)];
      return 0; // Should never be executed, to avoid warnings on Comeau
    }
  };

  // Insert coded character, using UTF8 or 8-bit ASCII
  template <int Flags>
  static void insert_coded_character(Ch *&text, unsigned long code) {
    if (Flags & parse_no_utf8) {
      // Insert 8-bit ASCII character
      // Todo: possibly verify that code is less than 256 and use replacement
      // char otherwise?
      text[0] = static_cast<unsigned char>(code);
      text += 1;
    } else {
      // Insert UTF8 sequence
      if (code < 0x80) // 1 byte sequence
      {
        text[0] = static_cast<unsigned char>(code);
        text += 1;
      } else if (code < 0x800) // 2 byte sequence
      {
        text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF);
        code >>= 6;
        text[0] = static_cast<unsigned char>(code | 0xC0);
        text += 2;
      } else if (code < 0x10000) // 3 byte sequence
      {
        text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF);
        code >>= 6;
        text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF);
        code >>= 6;
        text[0] = static_cast<unsigned char>(code | 0xE0);
        text += 3;
      } else if (code < 0x110000) // 4 byte sequence
      {
        text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF);
        code >>= 6;
        text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF);
        code >>= 6;
        text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF);
        code >>= 6;
        text[0] = static_cast<unsigned char>(code | 0xF0);
        text += 4;
      } else // Invalid, only codes up to 0x10FFFF are allowed in Unicode
      {
        RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
      }
    }
  }

  // Skip characters until predicate evaluates to true
  template <class StopPred, int Flags> static void skip(Ch *&text) {
    Ch *tmp = text;
    while (StopPred::test(*tmp))
      ++tmp;
    text = tmp;
  }

  // Skip characters until predicate evaluates to true while doing the
  // following:
  // - replacing XML character entity references with proper characters (&apos;
  // &amp; &quot; &lt; &gt; &#...;)
  // - condensing whitespace sequences to single space character
  template <class StopPred, class StopPredPure, int Flags>
  static Ch *skip_and_expand_character_refs(Ch *&text) {
    // If entity translation, whitespace condense and whitespace trimming is
    // disabled, use plain skip
    if (Flags & parse_no_entity_translation &&
        !(Flags & parse_normalize_whitespace) &&
        !(Flags & parse_trim_whitespace)) {
      skip<StopPred, Flags>(text);
      return text;
    }

    // Use simple skip until first modification is detected
    skip<StopPredPure, Flags>(text);

    // Use translation skip
    Ch *src = text;
    Ch *dest = src;
    while (StopPred::test(*src)) {
      // If entity translation is enabled
      if (!(Flags & parse_no_entity_translation)) {
        // Test if replacement is needed
        if (src[0] == Ch('&')) {
          switch (src[1]) {

          // &amp; &apos;
          case Ch('a'):
            if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';')) {
              *dest = Ch('&');
              ++dest;
              src += 5;
              continue;
            }
            if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') &&
                src[5] == Ch(';')) {
              *dest = Ch('\'');
              ++dest;
              src += 6;
              continue;
            }
            break;

          // &quot;
          case Ch('q'):
            if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') &&
                src[5] == Ch(';')) {
              *dest = Ch('"');
              ++dest;
              src += 6;
              continue;
            }
            break;

          // &gt;
          case Ch('g'):
            if (src[2] == Ch('t') && src[3] == Ch(';')) {
              *dest = Ch('>');
              ++dest;
              src += 4;
              continue;
            }
            break;

          // &lt;
          case Ch('l'):
            if (src[2] == Ch('t') && src[3] == Ch(';')) {
              *dest = Ch('<');
              ++dest;
              src += 4;
              continue;
            }
            break;

          // &#...; - assumes ASCII
          case Ch('#'):
            if (src[2] == Ch('x')) {
              unsigned long code = 0;
              src += 3; // Skip &#x
              while (1) {
                unsigned char digit = internal::lookup_tables<
                    0>::lookup_digits[static_cast<unsigned char>(*src)];
                if (digit == 0xFF)
                  break;
                code = code * 16 + digit;
                ++src;
              }
              insert_coded_character<Flags>(dest,
                                            code); // Put character in output
            } else {
              unsigned long code = 0;
              src += 2; // Skip &#
              while (1) {
                unsigned char digit = internal::lookup_tables<
                    0>::lookup_digits[static_cast<unsigned char>(*src)];
                if (digit == 0xFF)
                  break;
                code = code * 10 + digit;
                ++src;
              }
              insert_coded_character<Flags>(dest,
                                            code); // Put character in output
            }
            if (*src == Ch(';'))
              ++src;
            else
              RAPIDXML_PARSE_ERROR("expected ;", src);
            continue;

          // Something else
          default:
            // Ignore, just copy '&' verbatim
            break;
          }
        }
      }

      // If whitespace condensing is enabled
      if (Flags & parse_normalize_whitespace) {
        // Test if condensing is needed
        if (whitespace_pred::test(*src)) {
          *dest = Ch(' ');
          ++dest; // Put single space in dest
          ++src;  // Skip first whitespace char
          // Skip remaining whitespace chars
          while (whitespace_pred::test(*src))
            ++src;
          continue;
        }
      }

      // No replacement, only copy character
      *dest++ = *src++;
    }

    // Return new end
    text = src;
    return dest;
  }

  ///////////////////////////////////////////////////////////////////////
  // Internal parsing functions

  // Parse BOM, if any
  template <int Flags> void parse_bom(Ch *&text) {
    // UTF-8?
    if (static_cast<unsigned char>(text[0]) == 0xEF &&
        static_cast<unsigned char>(text[1]) == 0xBB &&
        static_cast<unsigned char>(text[2]) == 0xBF) {
      text += 3; // Skup utf-8 bom
    }
  }

  // Parse XML declaration (<?xml...)
  template <int Flags> xml_node<Ch> *parse_xml_declaration(Ch *&text) {
    // If parsing of declaration is disabled
    if (!(Flags & parse_declaration_node)) {
      // Skip until end of declaration
      while (text[0] != Ch('?') || text[1] != Ch('>')) {
        if (!text[0])
          RAPIDXML_PARSE_ERROR("unexpected end of data", text);
        ++text;
      }
      text += 2; // Skip '?>'
      return 0;
    }

    // Create declaration
    xml_node<Ch> *declaration = this->allocate_node(node_declaration);

    // Skip whitespace before attributes or ?>
    skip<whitespace_pred, Flags>(text);

    // Parse declaration attributes
    parse_node_attributes<Flags>(text, declaration);

    // Skip ?>
    if (text[0] != Ch('?') || text[1] != Ch('>'))
      RAPIDXML_PARSE_ERROR("expected ?>", text);
    text += 2;

    return declaration;
  }

  // Parse XML comment (<!--...)
  template <int Flags> xml_node<Ch> *parse_comment(Ch *&text) {
    // If parsing of comments is disabled
    if (!(Flags & parse_comment_nodes)) {
      // Skip until end of comment
      while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) {
        if (!text[0])
          RAPIDXML_PARSE_ERROR("unexpected end of data", text);
        ++text;
      }
      text += 3; // Skip '-->'
      return 0;  // Do not produce comment node
    }

    // Remember value start
    Ch *value = text;

    // Skip until end of comment
    while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>')) {
      if (!text[0])
        RAPIDXML_PARSE_ERROR("unexpected end of data", text);
      ++text;
    }

    // Create comment node
    xml_node<Ch> *comment = this->allocate_node(node_comment);
    comment->value(value, text - value);

    // Place zero terminator after comment value
    if (!(Flags & parse_no_string_terminators))
      *text = Ch('\0');

    text += 3; // Skip '-->'
    return comment;
  }

  // Parse DOCTYPE
  template <int Flags> xml_node<Ch> *parse_doctype(Ch *&text) {
    // Remember value start
    Ch *value = text;

    // Skip to >
    while (*text != Ch('>')) {
      // Determine character type
      switch (*text) {

      // If '[' encountered, scan for matching ending ']' using naive algorithm
      // with depth This works for all W3C test files except for 2 most wicked
      case Ch('['): {
        ++text; // Skip '['
        int depth = 1;
        while (depth > 0) {
          switch (*text) {
          case Ch('['):
            ++depth;
            break;
          case Ch(']'):
            --depth;
            break;
          case 0:
            RAPIDXML_PARSE_ERROR("unexpected end of data", text);
          }
          ++text;
        }
        break;
      }

      // Error on end of text
      case Ch('\0'):
        RAPIDXML_PARSE_ERROR("unexpected end of data", text);

      // Other character, skip it
      default:
        ++text;
      }
    }

    // If DOCTYPE nodes enabled
    if (Flags & parse_doctype_node) {
      // Create a new doctype node
      xml_node<Ch> *doctype = this->allocate_node(node_doctype);
      doctype->value(value, text - value);

      // Place zero terminator after value
      if (!(Flags & parse_no_string_terminators))
        *text = Ch('\0');

      text += 1; // skip '>'
      return doctype;
    } else {
      text += 1; // skip '>'
      return 0;
    }
  }

  // Parse PI
  template <int Flags> xml_node<Ch> *parse_pi(Ch *&text) {
    // If creation of PI nodes is enabled
    if (Flags & parse_pi_nodes) {
      // Create pi node
      xml_node<Ch> *pi = this->allocate_node(node_pi);

      // Extract PI target name
      Ch *name = text;
      skip<node_name_pred, Flags>(text);
      if (text == name)
        RAPIDXML_PARSE_ERROR("expected PI target", text);
      pi->name(name, text - name);

      // Skip whitespace between pi target and pi
      skip<whitespace_pred, Flags>(text);

      // Remember start of pi
      Ch *value = text;

      // Skip to '?>'
      while (text[0] != Ch('?') || text[1] != Ch('>')) {
        if (*text == Ch('\0'))
          RAPIDXML_PARSE_ERROR("unexpected end of data", text);
        ++text;
      }

      // Set pi value (verbatim, no entity expansion or whitespace
      // normalization)
      pi->value(value, text - value);

      // Place zero terminator after name and value
      if (!(Flags & parse_no_string_terminators)) {
        pi->name()[pi->name_size()] = Ch('\0');
        pi->value()[pi->value_size()] = Ch('\0');
      }

      text += 2; // Skip '?>'
      return pi;
    } else {
      // Skip to '?>'
      while (text[0] != Ch('?') || text[1] != Ch('>')) {
        if (*text == Ch('\0'))
          RAPIDXML_PARSE_ERROR("unexpected end of data", text);
        ++text;
      }
      text += 2; // Skip '?>'
      return 0;
    }
  }

  // Parse and append data
  // Return character that ends data.
  // This is necessary because this character might have been overwritten by a
  // terminating 0
  template <int Flags>
  Ch parse_and_append_data(xml_node<Ch> *node, Ch *&text, Ch *contents_start) {
    // Backup to contents start if whitespace trimming is disabled
    if (!(Flags & parse_trim_whitespace))
      text = contents_start;

    // Skip until end of data
    Ch *value = text, *end;
    if (Flags & parse_normalize_whitespace)
      end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred,
                                           Flags>(text);
    else
      end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred,
                                           Flags>(text);

    // Trim trailing whitespace if flag is set; leading was already trimmed by
    // whitespace skip after >
    if (Flags & parse_trim_whitespace) {
      if (Flags & parse_normalize_whitespace) {
        // Whitespace is already condensed to single space characters by
        // skipping function, so just trim 1 char off the end
        if (*(end - 1) == Ch(' '))
          --end;
      } else {
        // Backup until non-whitespace character is found
        while (whitespace_pred::test(*(end - 1)))
          --end;
      }
    }

    // If characters are still left between end and value (this test is only
    // necessary if normalization is enabled) Create new data node
    if (!(Flags & parse_no_data_nodes)) {
      xml_node<Ch> *data = this->allocate_node(node_data);
      data->value(value, end - value);
      node->append_node(data);
    }

    // Add data to parent node if no data exists yet
    if (!(Flags & parse_no_element_values))
      if (*node->value() == Ch('\0'))
        node->value(value, end - value);

    // Place zero terminator after value
    if (!(Flags & parse_no_string_terminators)) {
      Ch ch = *text;
      *end = Ch('\0');
      return ch; // Return character that ends data; this is required because
                 // zero terminator overwritten it
    }

    // Return character that ends data
    return *text;
  }

  // Parse CDATA
  template <int Flags> xml_node<Ch> *parse_cdata(Ch *&text) {
    // If CDATA is disabled
    if (Flags & parse_no_data_nodes) {
      // Skip until end of cdata
      while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) {
        if (!text[0])
          RAPIDXML_PARSE_ERROR("unexpected end of data", text);
        ++text;
      }
      text += 3; // Skip ]]>
      return 0;  // Do not produce CDATA node
    }

    // Skip until end of cdata
    Ch *value = text;
    while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>')) {
      if (!text[0])
        RAPIDXML_PARSE_ERROR("unexpected end of data", text);
      ++text;
    }

    // Create new cdata node
    xml_node<Ch> *cdata = this->allocate_node(node_cdata);
    cdata->value(value, text - value);

    // Place zero terminator after value
    if (!(Flags & parse_no_string_terminators))
      *text = Ch('\0');

    text += 3; // Skip ]]>
    return cdata;
  }

  // Parse element node
  template <int Flags> xml_node<Ch> *parse_element(Ch *&text) {
    // Create element node
    xml_node<Ch> *element = this->allocate_node(node_element);

    // Extract element name
    Ch *prefix = text;
    skip<element_name_pred, Flags>(text);
    if (text == prefix)
      RAPIDXML_PARSE_ERROR("expected element name or prefix", text);
    if (*text == Ch(':')) {
      element->prefix(prefix, text - prefix);
      ++text;
      Ch *name = text;
      skip<node_name_pred, Flags>(text);
      if (text == name)
        RAPIDXML_PARSE_ERROR("expected element local name", text);
      element->name(name, text - name);
    } else {
      element->name(prefix, text - prefix);
    }

    // Skip whitespace between element name and attributes or >
    skip<whitespace_pred, Flags>(text);

    // Parse attributes, if any
    parse_node_attributes<Flags>(text, element);

    // Determine ending type
    if (*text == Ch('>')) {
      Ch const *contents = ++text;
      Ch const *contents_end = 0;
      if (!(Flags & parse_open_only))
        contents_end = parse_node_contents<Flags>(text, element);
      std::size_t sz = contents_end - contents;
      if (sz)
        element->contents(contents, sz);
    } else if (*text == Ch('/')) {
      ++text;
      if (*text != Ch('>'))
        RAPIDXML_PARSE_ERROR("expected >", text);
      ++text;
      if (Flags & parse_open_only)
        RAPIDXML_PARSE_ERROR("open_only, but closed", text);
    } else
      RAPIDXML_PARSE_ERROR("expected >", text);

    // Place zero terminator after name
    if (!(Flags & parse_no_string_terminators)) {
      element->name()[element->name_size()] = Ch('\0');
      if (element->prefix())
        element->prefix()[element->prefix_size()] = Ch('\0');
    }

    // Return parsed element
    return element;
  }

  // Determine node type, and parse it
  template <int Flags> xml_node<Ch> *parse_node(Ch *&text) {
    // Parse proper node type
    switch (text[0]) {

    // <...
    default:
      // Parse and append element node
      return parse_element<Flags>(text);

    // <?...
    case Ch('?'):
      ++text; // Skip ?
      if ((text[0] == Ch('x') || text[0] == Ch('X')) &&
          (text[1] == Ch('m') || text[1] == Ch('M')) &&
          (text[2] == Ch('l') || text[2] == Ch('L')) &&
          whitespace_pred::test(text[3])) {
        // '<?xml ' - xml declaration
        text += 4; // Skip 'xml '
        return parse_xml_declaration<Flags>(text);
      } else {
        // Parse PI
        return parse_pi<Flags>(text);
      }

    // <!...
    case Ch('!'):

      // Parse proper subset of <! node
      switch (text[1]) {

      // <!-
      case Ch('-'):
        if (text[2] == Ch('-')) {
          // '<!--' - xml comment
          text += 3; // Skip '!--'
          return parse_comment<Flags>(text);
        }
        break;

      // <![
      case Ch('['):
        if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') &&
            text[5] == Ch('T') && text[6] == Ch('A') && text[7] == Ch('[')) {
          // '<![CDATA[' - cdata
          text += 8; // Skip '![CDATA['
          return parse_cdata<Flags>(text);
        }
        break;

      // <!D
      case Ch('D'):
        if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') &&
            text[5] == Ch('Y') && text[6] == Ch('P') && text[7] == Ch('E') &&
            whitespace_pred::test(text[8])) {
          // '<!DOCTYPE ' - doctype
          text += 9; // skip '!DOCTYPE '
          return parse_doctype<Flags>(text);
        }

      } // switch

      // Attempt to skip other, unrecognized node types starting with <!
      ++text; // Skip !
      while (*text != Ch('>')) {
        if (*text == 0)
          RAPIDXML_PARSE_ERROR("unexpected end of data", text);
        ++text;
      }
      ++text;   // Skip '>'
      return 0; // No node recognized
    }
  }

  // Parse contents of the node - children, data etc.
  // Return end pointer.
  template <int Flags> Ch *parse_node_contents(Ch *&text, xml_node<Ch> *node) {
    Ch *retval = 0;
    // For all children and text
    while (1) {
      // Skip whitespace between > and node contents
      Ch *contents_start =
          text; // Store start of node contents before whitespace is skipped
      skip<whitespace_pred, Flags>(text);
      Ch next_char = *text;

    // After data nodes, instead of continuing the loop, control jumps here.
    // This is because zero termination inside parse_and_append_data() function
    // would wreak havoc with the above code.
    // Also, skipping whitespace after data nodes is unnecessary.
    after_data_node:

      // Determine what comes next: node closing, child node, data node, or 0?
      switch (next_char) {

      // Node closing or child node
      case Ch('<'):
        if (text[1] == Ch('/')) {
          // Node closing
          retval = text;
          text += 2; // Skip '</'
          if (Flags & parse_validate_closing_tags) {
            // Skip and validate closing tag name
            Ch *closing_name = text;
            skip<node_name_pred, Flags>(text);
            if (!internal::compare(node->name(), node->name_size(),
                                   closing_name, text - closing_name, true))
              RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
          } else {
            // No validation, just skip name
            skip<node_name_pred, Flags>(text);
          }
          // Skip remaining whitespace after node name
          skip<whitespace_pred, Flags>(text);
          if (*text != Ch('>'))
            RAPIDXML_PARSE_ERROR("expected >", text);
          ++text; // Skip '>'
          if (Flags & parse_open_only)
            RAPIDXML_PARSE_ERROR("Unclosed element actually closed.", text);
          return retval; // Node closed, finished parsing contents
        } else {
          // Child node
          ++text; // Skip '<'
          if (xml_node<Ch> *child = parse_node<Flags & ~parse_open_only>(text))
            node->append_node(child);
        }
        break;

      // End of data - error unless we expected this.
      case Ch('\0'):
        if (Flags & parse_open_only) {
          return 0;
        } else {
          RAPIDXML_PARSE_ERROR("unexpected end of data", text);
        }

      // Data node
      default:
        next_char = parse_and_append_data<Flags>(node, text, contents_start);
        goto after_data_node; // Bypass regular processing after data nodes
      }
    }
  }

  // Parse XML attributes of the node
  template <int Flags>
  void parse_node_attributes(Ch *&text, xml_node<Ch> *node) {
    // For all attributes
    while (attribute_name_pred::test(*text)) {
      // Extract attribute name
      Ch *name = text;
      ++text; // Skip first character of attribute name
      skip<attribute_name_pred, Flags>(text);
      if (text == name)
        RAPIDXML_PARSE_ERROR("expected attribute name", name);

      // Create new attribute
      xml_attribute<Ch> *attribute = this->allocate_attribute();
      attribute->name(name, text - name);
      node->append_attribute(attribute);

      // Skip whitespace after attribute name
      skip<whitespace_pred, Flags>(text);

      // Skip =
      if (*text != Ch('='))
        RAPIDXML_PARSE_ERROR("expected =", text);
      ++text;

      // Add terminating zero after name
      if (!(Flags & parse_no_string_terminators))
        attribute->name()[attribute->name_size()] = 0;

      // Skip whitespace after =
      skip<whitespace_pred, Flags>(text);

      // Skip quote and remember if it was ' or "
      Ch quote = *text;
      if (quote != Ch('\'') && quote != Ch('"'))
        RAPIDXML_PARSE_ERROR("expected ' or \"", text);
      ++text;

      // Extract attribute value and expand char refs in it
      Ch *value = text, *end;
      const int AttFlags =
          Flags & ~parse_normalize_whitespace; // No whitespace normalization in
                                               // attributes
      if (quote == Ch('\''))
        end =
            skip_and_expand_character_refs<attribute_value_pred<Ch('\'')>,
                                           attribute_value_pure_pred<Ch('\'')>,
                                           AttFlags>(text);
      else
        end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>,
                                             attribute_value_pure_pred<Ch('"')>,
                                             AttFlags>(text);

      // Set attribute value
      attribute->value(value, end - value);

      // Make sure that end quote is present
      if (*text != quote)
        RAPIDXML_PARSE_ERROR("expected ' or \"", text);
      ++text; // Skip quote

      // Add terminating zero after value
      if (!(Flags & parse_no_string_terminators))
        attribute->value()[attribute->value_size()] = 0;

      // Skip whitespace after attribute value
      skip<whitespace_pred, Flags>(text);
    }
  }
};

//! \cond internal
namespace internal {

// Whitespace (space \n \r \t)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
    1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  // F
};

// Element name (anything but space \n \r \t / > ? \0 and :)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_element_name[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Node name (anything but space \n \r \t / > ? \0)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_node_name[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Text (i.e. PCDATA) (anything but < \0)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_text[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Text (i.e. PCDATA) that does not require processing when ws normalization is
// disabled (anything but < \0 &)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Text (i.e. PCDATA) that does not require processing when ws normalizationis
// is enabled (anything but < \0 & space \n \r \t)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Attribute name (anything but space \n \r \t / < > = ? ! \0)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Attribute data with single quote (anything but ' \0)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Attribute data with single quote that does not require processing (anything
// but ' \0 &)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Attribute data with double quote (anything but " \0)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Attribute data with double quote that does not require processing (anything
// but " \0 &)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
    1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // F
};

// Digits (dec and hex, 255 denotes end of numeric character reference)
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_digits[256] = {
    // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // 0
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // 1
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // 2
    0,   1,   2,   3,   4,   5,   6,   7,
    8,   9,   255, 255, 255, 255, 255, 255, // 3
    255, 10,  11,  12,  13,  14,  15,  255,
    255, 255, 255, 255, 255, 255, 255, 255, // 4
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // 5
    255, 10,  11,  12,  13,  14,  15,  255,
    255, 255, 255, 255, 255, 255, 255, 255, // 6
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // 7
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // 8
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // 9
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // A
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // B
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // C
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // D
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255, // E
    255, 255, 255, 255, 255, 255, 255, 255,
    255, 255, 255, 255, 255, 255, 255, 255 // F
};

// Upper case conversion
template <int Dummy>
const unsigned char lookup_tables<Dummy>::lookup_upcase[256] = {
    // 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  A   B   C   D   E   F
    0,   1,   2,   3,   4,   5,   6,   7,
    8,   9,   10,  11,  12,  13,  14,  15, // 0
    16,  17,  18,  19,  20,  21,  22,  23,
    24,  25,  26,  27,  28,  29,  30,  31, // 1
    32,  33,  34,  35,  36,  37,  38,  39,
    40,  41,  42,  43,  44,  45,  46,  47, // 2
    48,  49,  50,  51,  52,  53,  54,  55,
    56,  57,  58,  59,  60,  61,  62,  63, // 3
    64,  65,  66,  67,  68,  69,  70,  71,
    72,  73,  74,  75,  76,  77,  78,  79, // 4
    80,  81,  82,  83,  84,  85,  86,  87,
    88,  89,  90,  91,  92,  93,  94,  95, // 5
    96,  65,  66,  67,  68,  69,  70,  71,
    72,  73,  74,  75,  76,  77,  78,  79, // 6
    80,  81,  82,  83,  84,  85,  86,  87,
    88,  89,  90,  123, 124, 125, 126, 127, // 7
    128, 129, 130, 131, 132, 133, 134, 135,
    136, 137, 138, 139, 140, 141, 142, 143, // 8
    144, 145, 146, 147, 148, 149, 150, 151,
    152, 153, 154, 155, 156, 157, 158, 159, // 9
    160, 161, 162, 163, 164, 165, 166, 167,
    168, 169, 170, 171, 172, 173, 174, 175, // A
    176, 177, 178, 179, 180, 181, 182, 183,
    184, 185, 186, 187, 188, 189, 190, 191, // B
    192, 193, 194, 195, 196, 197, 198, 199,
    200, 201, 202, 203, 204, 205, 206, 207, // C
    208, 209, 210, 211, 212, 213, 214, 215,
    216, 217, 218, 219, 220, 221, 222, 223, // D
    224, 225, 226, 227, 228, 229, 230, 231,
    232, 233, 234, 235, 236, 237, 238, 239, // E
    240, 241, 242, 243, 244, 245, 246, 247,
    248, 249, 250, 251, 252, 253, 254, 255 // F
};
} // namespace internal
  //! \endcond

} // namespace rapidxml

// Undefine internal macros
#undef RAPIDXML_PARSE_ERROR

// On MSVC, restore warnings state
#ifdef _MSC_VER
#pragma warning(pop)
#endif

#endif
