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