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