annotate DEPENDENCIES/generic/include/boost/property_tree/detail/rapidxml.hpp @ 125:34e428693f5d vext

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