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