RAPIDXML

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

RAPIDXML的相关文章

RapidXml用法

一.写xml 文件 #include <iostream> #include "rapidxml/rapidxml.hpp" #include "rapidxml/rapidxml_utils.hpp" #include "rapidxml/rapidxml_print.hpp" using namespace rapidxml; int main() { xml_document<> doc; xml_node<&

rapidxml 修改节点值

config.xml文件内容: <cfg> <sys> <ip>192.168.1.22</ip> <netmask>255.255.0.0</netmask> <gateway>169.254.1.1</gateway> <mac>00:00:00:00:00:01</mac> </sys> </cfg> 譬如现在要修改ip节点值为169.254.1.20,代码

TinyXml 与 Rapidxml效率对照

曾经在做开发中一直使用TinyXml,在网上搜索说Rapidxml的效率比tinyXml高.个人比較喜欢追求效率.所以忍不住尝试性使用Rapidxml. RapidXml 的官方站点例如以下: http://rapidxml.sourceforge.net/manual.html. RapidXml是一个使用C++编写的XML DOM解析工具包,整个解析工具包包括在一个头文件里.所以使用时不用编译也不用连接.仅仅要包括rapidxml中的三个头文件就可以.RapidXml 试图成为最快的 XML

rapidxml 解析修改内存的值

1.使用rapidxml解析的时候,特别注意,rapidxml会修改内存的值,把右尖括号>修改为'\0',因此特别注意,如果char指针指向的内容还要使用,需要做个备份. 2.如果char指针指向的内容,不再使用,不需要做备份,rapidxml会直接修改内存.这个时候不要忘记delete []释放资源.delete释放内存,跟内存中的取值没有关系,取值为0,也会正确地释放内存.使用new分配内存8个字节,操作系统会多分配一些内存,额外的内存记录分配了多少内存,这样在释放的时候,就知道应该释放多少

rapidxml 序列化

void TestRapidXml() { char* xmlContent = new char[1024]; sprintf(xmlContent,"<root><head>aaa</head><body>bbb</body></root>"); xml_document<> xmlDoc; xmlDoc.parse<0>(xmlContent); // back_inserter 返回

rapidxml读取utf-8 格式xml乱码问题(utf-8格式转GBK)

1.我是用rapidxml文件读取utf-8格式的xml,但是显示乱码.我们需要把读出来的内容转为GBK格式,则能正常显示. char * utf82gbk(char* strutf) { //utf-8转为Unicode int size = MultiByteToWideChar(CP_UTF8, 0, strutf, -1, NULL, 0); WCHAR   *strUnicode = new   WCHAR[size]; MultiByteToWideChar(CP_UTF8, 0,

rapidxml读取包含中文路径的xml解析错误的解决方法

from http://blog.csdn.net/qinwei4072880/article/details/38865179 1.rapidxml不支持中文路径. 2.rapidxml不支持Unicode xml必须为utf-8编码. 解决方法: #ifdef _UNICODE setlocale(LC_ALL, "Chinese-simplified"); // 设置中文环境USES_CONVERSION;file<> doc(W2A(lpszXml)); setlo

rapidxml修改节点的值

1.rapidxml修改节点的value,修改之后,序列化还是原来的值,具体原因是什么,要看rapidxml是怎么实现的.如下: void TestRapidXml() { char* xmlContent = new char[1024]; sprintf(xmlContent,"<root><head>aaa</head><body x=\"10\">bbb</body></root>");

C++中rapidxml用法及例子

rapidxml是一个快速的xml库,比tinyxml快了50-100倍.本文给出创建.读取.写入xml的源码. 由于新浪博客不支持文本文件上传,在使用下面代码需要先下载 rapidxml,关于这个库的下载地址为:官方网站: http://rapidxml.sourceforge.net/,这个库源码一共只有四个文件分别是: 关于raidxml资料相关的介绍网上有很多资料,在这里我就不重复介绍了,下面直接贴代码: #include "stdafx.h" #include "s