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