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 (' & " < > &#...;) 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 // & ' 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 // " 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 // > 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 // < 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