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