Photon 1.0.0
Loading...
Searching...
No Matches
rapidxml.hpp
Go to the documentation of this file.
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 $
8
9// If standard library is disabled, user must provide implementations of required functions and typedefs
10#if !defined(RAPIDXML_NO_STDLIB)
11#include <cassert> // For assert
12#include <cstdlib> // For std::size_t
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
24// RAPIDXML_PARSE_ERROR
25
26#if defined(RAPIDXML_NO_EXCEPTIONS)
27
28#define RAPIDXML_PARSE_ERROR(what, where) \
29 { \
30 parse_error_handler(what, where); \
31 assert(0); \
32 }
33
34namespace rapidxml
35{
52 void parse_error_handler(const char* what, void* where);
53} // namespace rapidxml
54
55#else
56
57#include <exception> // For std::exception
58
59#define RAPIDXML_PARSE_ERROR(what, where) throw parse_error(what, where)
60
61namespace rapidxml
62{
63
75 class parse_error : public std::exception
76 {
77
78 public:
80 parse_error(const char* what, void* where) : m_what(what), m_where(where)
81 {
82 }
83
86 virtual const char* what() const throw()
87 {
88 return m_what;
89 }
90
94 template <class Ch> Ch* where() const
95 {
96 return reinterpret_cast<Ch*>(m_where);
97 }
98
99 private:
100 const char* m_what;
101 void* m_where;
102 };
103} // namespace rapidxml
104
105#endif
106
108// Pool sizes
109
110#ifndef RAPIDXML_STATIC_POOL_SIZE
111// Size of static memory block of memory_pool.
112// Define RAPIDXML_STATIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
113// No dynamic memory allocations are performed by memory_pool until static memory is exhausted.
114#define RAPIDXML_STATIC_POOL_SIZE (64 * 1024)
115#endif
116
117#ifndef RAPIDXML_DYNAMIC_POOL_SIZE
118// Size of dynamic memory block of memory_pool.
119// Define RAPIDXML_DYNAMIC_POOL_SIZE before including rapidxml.hpp if you want to override the default value.
120// After the static block is exhausted, dynamic blocks with approximately this size are allocated by memory_pool.
121#define RAPIDXML_DYNAMIC_POOL_SIZE (64 * 1024)
122#endif
123
124#ifndef RAPIDXML_ALIGNMENT
125// Memory allocation alignment.
126// Define RAPIDXML_ALIGNMENT before including rapidxml.hpp if you want to override the default value, which is the size
127// of pointer. All memory allocations for nodes, attributes and strings will be aligned to this value. This must be a
128// power of 2 and at least 1, otherwise memory_pool will not work.
129#define RAPIDXML_ALIGNMENT sizeof(void*)
130#endif
131
132namespace rapidxml
133{
134 // Forward declarations
135 template <class Ch> class xml_node;
136 template <class Ch> class xml_attribute;
137 template <class Ch> class xml_document;
138
153
155 // Parsing flags
156
162 const int parse_no_data_nodes = 0x1;
163
170 const int parse_no_element_values = 0x2;
171
178
185
191 const int parse_no_utf8 = 0x10;
192
198 const int parse_declaration_node = 0x20;
199
205 const int parse_comment_nodes = 0x40;
206
211 const int parse_doctype_node = 0x80;
212
218 const int parse_pi_nodes = 0x100;
219
227
234 const int parse_trim_whitespace = 0x400;
235
243 const int parse_normalize_whitespace = 0x800;
244
245 // Compound flags
246
255 const int parse_default = 0;
256
266
271
278
280 // Internals
281
283 namespace internal
284 {
285
286 // Struct that contains lookup tables for the parser
287 // It must be a template to allow correct linking (because it has static data members, which are defined in a
288 // header file).
289 template <int Dummy> struct lookup_tables
290 {
291 static const unsigned char lookup_whitespace[256]; // Whitespace table
292 static const unsigned char lookup_node_name[256]; // Node name table
293 static const unsigned char lookup_text[256]; // Text table
294 static const unsigned char lookup_text_pure_no_ws[256]; // Text table
295 static const unsigned char lookup_text_pure_with_ws[256]; // Text table
296 static const unsigned char lookup_attribute_name[256]; // Attribute name table
297 static const unsigned char lookup_attribute_data_1[256]; // Attribute data table with single quote
298 static const unsigned char lookup_attribute_data_1_pure[256]; // Attribute data table with single quote
299 static const unsigned char lookup_attribute_data_2[256]; // Attribute data table with double quotes
300 static const unsigned char lookup_attribute_data_2_pure[256]; // Attribute data table with double quotes
301 static const unsigned char lookup_digits[256]; // Digits
302 static const unsigned char lookup_upcase[256]; // To uppercase conversion table for ASCII characters
303 };
304
305 // Find length of the string
306 template <class Ch> inline std::size_t measure(const Ch* p)
307 {
308 const Ch* tmp = p;
309 while (*tmp)
310 ++tmp;
311 return tmp - p;
312 }
313
314 // Compare strings for equality
315 template <class Ch>
316 inline bool compare(const Ch* p1, std::size_t size1, const Ch* p2, std::size_t size2, bool case_sensitive)
317 {
318 if (size1 != size2)
319 return false;
320 if (case_sensitive)
321 {
322 for (const Ch* end = p1 + size1; p1 < end; ++p1, ++p2)
323 if (*p1 != *p2)
324 return false;
325 }
326 else
327 {
328 for (const Ch* end = p1 + size1; p1 < end; ++p1, ++p2)
329 if (lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p1)] !=
330 lookup_tables<0>::lookup_upcase[static_cast<unsigned char>(*p2)])
331 return false;
332 }
333 return true;
334 }
335 } // namespace internal
337
339 // Memory pool
340
365 template <class Ch = char> class memory_pool
366 {
367
368 public:
370 typedef void*(alloc_func)(std::size_t); // Type of user-defined function used to allocate memory
371 typedef void(free_func)(void*); // Type of user-defined function used to free memory
373
376 {
377 init();
378 }
379
384 {
385 clear();
386 }
387
399 const Ch* name = 0,
400 const Ch* value = 0,
401 std::size_t name_size = 0,
402 std::size_t value_size = 0)
403 {
404 void* memory = allocate_aligned(sizeof(xml_node<Ch>));
405 xml_node<Ch>* node = new (memory) xml_node<Ch>(type);
406 if (name)
407 {
408 if (name_size > 0)
409 node->name(name, name_size);
410 else
411 node->name(name);
412 }
413 if (value)
414 {
415 if (value_size > 0)
416 node->value(value, value_size);
417 else
418 node->value(value);
419 }
420 return node;
421 }
422
433 const Ch* value = 0,
434 std::size_t name_size = 0,
435 std::size_t value_size = 0)
436 {
437 void* memory = allocate_aligned(sizeof(xml_attribute<Ch>));
438 xml_attribute<Ch>* attribute = new (memory) xml_attribute<Ch>;
439 if (name)
440 {
441 if (name_size > 0)
442 attribute->name(name, name_size);
443 else
444 attribute->name(name);
445 }
446 if (value)
447 {
448 if (value_size > 0)
449 attribute->value(value, value_size);
450 else
451 attribute->value(value);
452 }
453 return attribute;
454 }
455
464 Ch* allocate_string(const Ch* source = 0, std::size_t size = 0)
465 {
466 assert(source || size); // Either source or size (or both) must be specified
467 if (size == 0)
468 size = internal::measure(source) + 1;
469 Ch* result = static_cast<Ch*>(allocate_aligned(size * sizeof(Ch)));
470 if (source)
471 for (std::size_t i = 0; i < size; ++i)
472 result[i] = source[i];
473 return result;
474 }
475
486 {
487 // Prepare result node
488 if (result)
489 {
490 result->remove_all_attributes();
491 result->remove_all_nodes();
492 result->type(source->type());
493 }
494 else
495 result = allocate_node(source->type());
496
497 // Clone name and value
498 result->name(source->name(), source->name_size());
499 result->value(source->value(), source->value_size());
500
501 // Clone child nodes and attributes
502 for (xml_node<Ch>* child = source->first_node(); child; child = child->next_sibling())
503 result->append_node(clone_node(child));
504 for (xml_attribute<Ch>* attr = source->first_attribute(); attr; attr = attr->next_attribute())
505 result->append_attribute(
506 allocate_attribute(attr->name(), attr->value(), attr->name_size(), attr->value_size()));
507
508 return result;
509 }
510
514 void clear()
515 {
516 while (m_begin != m_static_memory)
517 {
518 char* previous_begin = reinterpret_cast<header*>(align(m_begin))->previous_begin;
519 if (m_free_func)
521 else
522 delete[] m_begin;
523 m_begin = previous_begin;
524 }
525 init();
526 }
527
541 void set_allocator(alloc_func* af, free_func* ff)
542 {
543 assert(m_begin == m_static_memory && m_ptr == align(m_begin)); // Verify that no memory is allocated yet
544 m_alloc_func = af;
545 m_free_func = ff;
546 }
547
548 private:
549 struct header
550 {
552 };
553
554 void init()
555 {
559 }
560
561 char* align(char* ptr)
562 {
563 std::size_t alignment =
564 ((RAPIDXML_ALIGNMENT - (std::size_t(ptr) & (RAPIDXML_ALIGNMENT - 1))) & (RAPIDXML_ALIGNMENT - 1));
565 return ptr + alignment;
566 }
567
568 char* allocate_raw(std::size_t size)
569 {
570 // Allocate
571 void* memory;
572 if (m_alloc_func) // Allocate memory using either user-specified allocation function or global operator
573 // new[]
574 {
575 memory = m_alloc_func(size);
576 assert(memory); // Allocator is not allowed to return 0, on failure it must either throw, stop the
577 // program or use longjmp
578 }
579 else
580 {
581 memory = new char[size];
582#ifdef RAPIDXML_NO_EXCEPTIONS
583 if (!memory) // If exceptions are disabled, verify memory allocation, because new will not be able to
584 // throw bad_alloc
585 RAPIDXML_PARSE_ERROR("out of memory", 0);
586#endif
587 }
588 return static_cast<char*>(memory);
589 }
590
591 void* allocate_aligned(std::size_t size)
592 {
593 // Calculate aligned pointer
594 char* result = align(m_ptr);
595
596 // If not enough memory left in current pool, allocate a new pool
597 if (result + size > m_end)
598 {
599 // Calculate required pool size (may be bigger than RAPIDXML_DYNAMIC_POOL_SIZE)
600 std::size_t pool_size = RAPIDXML_DYNAMIC_POOL_SIZE;
601 if (pool_size < size)
602 pool_size = size;
603
604 // Allocate
605 std::size_t alloc_size =
606 sizeof(header) + (2 * RAPIDXML_ALIGNMENT - 2) +
607 pool_size; // 2 alignments required in worst case: one for header, one for actual allocation
608 char* raw_memory = allocate_raw(alloc_size);
609
610 // Setup new pool in allocated memory
611 char* pool = align(raw_memory);
612 header* new_header = reinterpret_cast<header*>(pool);
613 new_header->previous_begin = m_begin;
614 m_begin = raw_memory;
615 m_ptr = pool + sizeof(header);
616 m_end = raw_memory + alloc_size;
617
618 // Calculate aligned pointer again using new pool
619 result = align(m_ptr);
620 }
621
622 // Update pool and return aligned pointer
623 m_ptr = result + size;
624 return result;
625 }
626
627 char* m_begin; // Start of raw memory making up current pool
628 char* m_ptr; // First free byte in current pool
629 char* m_end; // One past last available byte in current pool
630 char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]; // Static raw memory
631 alloc_func* m_alloc_func; // Allocator function, or 0 if default is to be used
632 free_func* m_free_func; // Free function, or 0 if default is to be used
633 };
634
636 // XML base
637
641 template <class Ch = char> class xml_base
642 {
643
644 public:
646 // Construction & destruction
647
648 // Construct a base with empty name, value and parent
650 {
651 }
652
654 // Node data access
655
661 Ch* name() const
662 {
663 return m_name ? m_name : nullstr();
664 }
665
669 std::size_t name_size() const
670 {
671 return m_name ? m_name_size : 0;
672 }
673
679 Ch* value() const
680 {
681 return m_value ? m_value : nullstr();
682 }
683
687 std::size_t value_size() const
688 {
689 return m_value ? m_value_size : 0;
690 }
691
693 // Node modification
694
708 void name(const Ch* name, std::size_t size)
709 {
710 m_name = const_cast<Ch*>(name);
711 m_name_size = size;
712 }
713
717 void name(const Ch* name)
718 {
719 this->name(name, internal::measure(name));
720 }
721
739 void value(const Ch* value, std::size_t size)
740 {
741 m_value = const_cast<Ch*>(value);
742 m_value_size = size;
743 }
744
748 void value(const Ch* value)
749 {
750 this->value(value, internal::measure(value));
751 }
752
754 // Related nodes access
755
759 {
760 return m_parent;
761 }
762
763 protected:
764 // Return empty string
765 static Ch* nullstr()
766 {
767 static Ch zero = Ch('\0');
768 return &zero;
769 }
770
771 Ch* m_name; // Name of node, or 0 if no name
772 Ch* m_value; // Value of node, or 0 if no value
773 std::size_t m_name_size; // Length of node name, or undefined of no name
774 std::size_t m_value_size; // Length of node value, or undefined if no value
775 xml_node<Ch>* m_parent; // Pointer to parent node, or 0 if none
776 };
777
783 template <class Ch = char> class xml_attribute : public xml_base<Ch>
784 {
785
786 friend class xml_node<Ch>;
787
788 public:
790 // Construction & destruction
791
795 {
796 }
797
799 // Related nodes access
800
804 {
805 if (xml_node<Ch>* node = this->parent())
806 {
807 while (node->parent())
808 node = node->parent();
809 return node->type() == node_document ? static_cast<xml_document<Ch>*>(node) : 0;
810 }
811 else
812 return 0;
813 }
814
822 std::size_t name_size = 0,
823 bool case_sensitive = true) const
824 {
825 if (name)
826 {
827 if (name_size == 0)
828 name_size = internal::measure(name);
829 for (xml_attribute<Ch>* attribute = m_prev_attribute; attribute;
830 attribute = attribute->m_prev_attribute)
831 if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
832 return attribute;
833 return 0;
834 }
835 else
836 return this->m_parent ? m_prev_attribute : 0;
837 }
838
846 std::size_t name_size = 0,
847 bool case_sensitive = true) const
848 {
849 if (name)
850 {
851 if (name_size == 0)
852 name_size = internal::measure(name);
853 for (xml_attribute<Ch>* attribute = m_next_attribute; attribute;
854 attribute = attribute->m_next_attribute)
855 if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
856 return attribute;
857 return 0;
858 }
859 else
860 return this->m_parent ? m_next_attribute : 0;
861 }
862
863 private:
864 xml_attribute<Ch>* m_prev_attribute; // Pointer to previous sibling of attribute, or 0 if none; only valid if
865 // parent is non-zero
867 m_next_attribute; // Pointer to next sibling of attribute, or 0 if none; only valid if parent is non-zero
868 };
869
871 // XML node
872
881 template <class Ch = char> class xml_node : public xml_base<Ch>
882 {
883
884 public:
886 // Construction & destruction
887
894
896 // Node data access
897
901 {
902 return m_type;
903 }
904
906 // Related nodes access
907
911 {
912 xml_node<Ch>* node = const_cast<xml_node<Ch>*>(this);
913 while (node->parent())
914 node = node->parent();
915 return node->type() == node_document ? static_cast<xml_document<Ch>*>(node) : 0;
916 }
917
924 xml_node<Ch>* first_node(const Ch* name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
925 {
926 if (name)
927 {
928 if (name_size == 0)
929 name_size = internal::measure(name);
930 for (xml_node<Ch>* child = m_first_node; child; child = child->next_sibling())
931 if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
932 return child;
933 return 0;
934 }
935 else
936 return m_first_node;
937 }
938
947 xml_node<Ch>* last_node(const Ch* name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
948 {
949 assert(m_first_node); // Cannot query for last child if node has no children
950 if (name)
951 {
952 if (name_size == 0)
953 name_size = internal::measure(name);
954 for (xml_node<Ch>* child = m_last_node; child; child = child->previous_sibling())
955 if (internal::compare(child->name(), child->name_size(), name, name_size, case_sensitive))
956 return child;
957 return 0;
958 }
959 else
960 return m_last_node;
961 }
962
971 xml_node<Ch>* previous_sibling(const Ch* name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
972 {
973 assert(this->m_parent); // Cannot query for siblings if node has no parent
974 if (name)
975 {
976 if (name_size == 0)
977 name_size = internal::measure(name);
978 for (xml_node<Ch>* sibling = m_prev_sibling; sibling; sibling = sibling->m_prev_sibling)
979 if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
980 return sibling;
981 return 0;
982 }
983 else
984 return m_prev_sibling;
985 }
986
995 xml_node<Ch>* next_sibling(const Ch* name = 0, std::size_t name_size = 0, bool case_sensitive = true) const
996 {
997 assert(this->m_parent); // Cannot query for siblings if node has no parent
998 if (name)
999 {
1000 if (name_size == 0)
1001 name_size = internal::measure(name);
1002 for (xml_node<Ch>* sibling = m_next_sibling; sibling; sibling = sibling->m_next_sibling)
1003 if (internal::compare(sibling->name(), sibling->name_size(), name, name_size, case_sensitive))
1004 return sibling;
1005 return 0;
1006 }
1007 else
1008 return m_next_sibling;
1009 }
1010
1018 std::size_t name_size = 0,
1019 bool case_sensitive = true) const
1020 {
1021 if (name)
1022 {
1023 if (name_size == 0)
1024 name_size = internal::measure(name);
1025 for (xml_attribute<Ch>* attribute = m_first_attribute; attribute;
1026 attribute = attribute->m_next_attribute)
1027 if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
1028 return attribute;
1029 return 0;
1030 }
1031 else
1032 return m_first_attribute;
1033 }
1034
1042 std::size_t name_size = 0,
1043 bool case_sensitive = true) const
1044 {
1045 if (name)
1046 {
1047 if (name_size == 0)
1048 name_size = internal::measure(name);
1049 for (xml_attribute<Ch>* attribute = m_last_attribute; attribute;
1050 attribute = attribute->m_prev_attribute)
1051 if (internal::compare(attribute->name(), attribute->name_size(), name, name_size, case_sensitive))
1052 return attribute;
1053 return 0;
1054 }
1055 else
1057 }
1058
1060 // Node modification
1061
1065 {
1066 m_type = type;
1067 }
1068
1070 // Node manipulation
1071
1076 {
1077 assert(child && !child->parent() && child->type() != node_document);
1078 if (first_node())
1079 {
1082 }
1083 else
1084 {
1085 child->m_next_sibling = 0;
1086 m_last_node = child;
1087 }
1088 m_first_node = child;
1089 child->m_parent = this;
1090 child->m_prev_sibling = 0;
1091 }
1092
1097 {
1098 assert(child && !child->parent() && child->type() != node_document);
1099 if (first_node())
1100 {
1101 child->m_prev_sibling = m_last_node;
1102 m_last_node->m_next_sibling = child;
1103 }
1104 else
1105 {
1106 child->m_prev_sibling = 0;
1107 m_first_node = child;
1108 }
1109 m_last_node = child;
1110 child->m_parent = this;
1111 child->m_next_sibling = 0;
1112 }
1113
1119 {
1120 assert(!where || where->parent() == this);
1121 assert(child && !child->parent() && child->type() != node_document);
1122 if (where == m_first_node)
1123 prepend_node(child);
1124 else if (where == 0)
1125 append_node(child);
1126 else
1127 {
1128 child->m_prev_sibling = where->m_prev_sibling;
1129 child->m_next_sibling = where;
1130 where->m_prev_sibling->m_next_sibling = child;
1131 where->m_prev_sibling = child;
1132 child->m_parent = this;
1133 }
1134 }
1135
1140 {
1141 assert(first_node());
1142 xml_node<Ch>* child = m_first_node;
1144 if (child->m_next_sibling)
1145 child->m_next_sibling->m_prev_sibling = 0;
1146 else
1147 m_last_node = 0;
1148 child->m_parent = 0;
1149 }
1150
1155 {
1156 assert(first_node());
1157 xml_node<Ch>* child = m_last_node;
1158 if (child->m_prev_sibling)
1159 {
1160 m_last_node = child->m_prev_sibling;
1161 child->m_prev_sibling->m_next_sibling = 0;
1162 }
1163 else
1164 m_first_node = 0;
1165 child->m_parent = 0;
1166 }
1167
1169 // \param where Pointer to child to be removed.
1171 {
1172 assert(where && where->parent() == this);
1173 assert(first_node());
1174 if (where == m_first_node)
1176 else if (where == m_last_node)
1178 else
1179 {
1182 where->m_parent = 0;
1183 }
1184 }
1185
1188 {
1189 for (xml_node<Ch>* node = first_node(); node; node = node->m_next_sibling)
1190 node->m_parent = 0;
1191 m_first_node = 0;
1192 }
1193
1197 {
1198 assert(attribute && !attribute->parent());
1199 if (first_attribute())
1200 {
1203 }
1204 else
1205 {
1206 attribute->m_next_attribute = 0;
1207 m_last_attribute = attribute;
1208 }
1209 m_first_attribute = attribute;
1210 attribute->m_parent = this;
1211 attribute->m_prev_attribute = 0;
1212 }
1213
1217 {
1218 assert(attribute && !attribute->parent());
1219 if (first_attribute())
1220 {
1223 }
1224 else
1225 {
1226 attribute->m_prev_attribute = 0;
1227 m_first_attribute = attribute;
1228 }
1229 m_last_attribute = attribute;
1230 attribute->m_parent = this;
1231 attribute->m_next_attribute = 0;
1232 }
1233
1239 {
1240 assert(!where || where->parent() == this);
1241 assert(attribute && !attribute->parent());
1242 if (where == m_first_attribute)
1243 prepend_attribute(attribute);
1244 else if (where == 0)
1245 append_attribute(attribute);
1246 else
1247 {
1248 attribute->m_prev_attribute = where->m_prev_attribute;
1249 attribute->m_next_attribute = where;
1250 where->m_prev_attribute->m_next_attribute = attribute;
1251 where->m_prev_attribute = attribute;
1252 attribute->m_parent = this;
1253 }
1254 }
1255
1260 {
1261 assert(first_attribute());
1263 if (attribute->m_next_attribute)
1264 {
1265 attribute->m_next_attribute->m_prev_attribute = 0;
1266 }
1267 else
1268 m_last_attribute = 0;
1269 attribute->m_parent = 0;
1271 }
1272
1277 {
1278 assert(first_attribute());
1280 if (attribute->m_prev_attribute)
1281 {
1282 attribute->m_prev_attribute->m_next_attribute = 0;
1284 }
1285 else
1287 attribute->m_parent = 0;
1288 }
1289
1293 {
1294 assert(first_attribute() && where->parent() == this);
1295 if (where == m_first_attribute)
1297 else if (where == m_last_attribute)
1299 else
1300 {
1303 where->m_parent = 0;
1304 }
1305 }
1306
1309 {
1310 for (xml_attribute<Ch>* attribute = first_attribute(); attribute; attribute = attribute->m_next_attribute)
1311 attribute->m_parent = 0;
1313 }
1314
1315 private:
1317 // Restrictions
1318
1319 // No copying
1321 void operator=(const xml_node&);
1322
1324 // Data members
1325
1326 // Note that some of the pointers below have UNDEFINED values if certain other pointers are 0.
1327 // This is required for maximum performance, as it allows the parser to omit initialization of
1328 // unneded/redundant values.
1329 //
1330 // The rules are as follows:
1331 // 1. first_node and first_attribute contain valid pointers, or 0 if node has no children/attributes
1332 // respectively
1333 // 2. last_node and last_attribute are valid only if node has at least one child/attribute respectively,
1334 // otherwise they contain garbage
1335 // 3. prev_sibling and next_sibling are valid only if node has a parent, otherwise they contain garbage
1336
1337 node_type m_type; // Type of node; always valid
1338 xml_node<Ch>* m_first_node; // Pointer to first child node, or 0 if none; always valid
1339 xml_node<Ch>* m_last_node; // Pointer to last child node, or 0 if none; this value is only valid if m_first_node
1340 // is non-zero
1341 xml_attribute<Ch>* m_first_attribute; // Pointer to first attribute of node, or 0 if none; always valid
1342 xml_attribute<Ch>* m_last_attribute; // Pointer to last attribute of node, or 0 if none; this value is only
1343 // valid if m_first_attribute is non-zero
1344 xml_node<Ch>* m_prev_sibling; // Pointer to previous sibling of node, or 0 if none; this value is only valid if
1345 // m_parent is non-zero
1346 xml_node<Ch>* m_next_sibling; // Pointer to next sibling of node, or 0 if none; this value is only valid if
1347 // m_parent is non-zero
1348 };
1349
1351 // XML document
1352
1360 template <class Ch = char> class xml_document : public xml_node<Ch>, public memory_pool<Ch>
1361 {
1362
1363 public:
1366 {
1367 }
1368
1379 template <int Flags> void parse(Ch* text)
1380 {
1381 assert(text);
1382
1383 // Remove current contents
1384 this->remove_all_nodes();
1385 this->remove_all_attributes();
1386
1387 // Parse BOM, if any
1388 parse_bom<Flags>(text);
1389
1390 // Parse children
1391 while (1)
1392 {
1393 // Skip whitespace before node
1394 skip<whitespace_pred, Flags>(text);
1395 if (*text == 0)
1396 break;
1397
1398 // Parse and append new child
1399 if (*text == Ch('<'))
1400 {
1401 ++text; // Skip '<'
1402 if (xml_node<Ch>* node = parse_node<Flags>(text))
1403 this->append_node(node);
1404 }
1405 else
1406 RAPIDXML_PARSE_ERROR("expected <", text);
1407 }
1408 }
1409
1412 void clear()
1413 {
1414 this->remove_all_nodes();
1415 this->remove_all_attributes();
1417 }
1418
1419 private:
1421 // Internal character utility functions
1422
1423 // Detect whitespace character
1425 {
1426 static unsigned char test(Ch ch)
1427 {
1428 return internal::lookup_tables<0>::lookup_whitespace[static_cast<unsigned char>(ch)];
1429 }
1430 };
1431
1432 // Detect node name character
1434 {
1435 static unsigned char test(Ch ch)
1436 {
1437 return internal::lookup_tables<0>::lookup_node_name[static_cast<unsigned char>(ch)];
1438 }
1439 };
1440
1441 // Detect attribute name character
1443 {
1444 static unsigned char test(Ch ch)
1445 {
1446 return internal::lookup_tables<0>::lookup_attribute_name[static_cast<unsigned char>(ch)];
1447 }
1448 };
1449
1450 // Detect text character (PCDATA)
1452 {
1453 static unsigned char test(Ch ch)
1454 {
1455 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
1461 {
1462 static unsigned char test(Ch ch)
1463 {
1464 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
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> struct attribute_value_pred
1479 {
1480 static unsigned char test(Ch ch)
1481 {
1482 if (Quote == Ch('\''))
1483 return internal::lookup_tables<0>::lookup_attribute_data_1[static_cast<unsigned char>(ch)];
1484 if (Quote == Ch('\"'))
1485 return internal::lookup_tables<0>::lookup_attribute_data_2[static_cast<unsigned char>(ch)];
1486 return 0; // Should never be executed, to avoid warnings on Comeau
1487 }
1488 };
1489
1490 // Detect attribute value character
1491 template <Ch Quote> struct attribute_value_pure_pred
1492 {
1493 static unsigned char test(Ch ch)
1494 {
1495 if (Quote == Ch('\''))
1496 return internal::lookup_tables<0>::lookup_attribute_data_1_pure[static_cast<unsigned char>(ch)];
1497 if (Quote == Ch('\"'))
1498 return internal::lookup_tables<0>::lookup_attribute_data_2_pure[static_cast<unsigned char>(ch)];
1499 return 0; // Should never be executed, to avoid warnings on Comeau
1500 }
1501 };
1502
1503 // Insert coded character, using UTF8 or 8-bit ASCII
1504 template <int Flags> static void insert_coded_character(Ch*& text, unsigned long code)
1505 {
1506 if (Flags & parse_no_utf8)
1507 {
1508 // Insert 8-bit ASCII character
1509 // Todo: possibly verify that code is less than 256 and use replacement char otherwise?
1510 text[0] = static_cast<unsigned char>(code);
1511 text += 1;
1512 }
1513 else
1514 {
1515 // Insert UTF8 sequence
1516 if (code < 0x80) // 1 byte sequence
1517 {
1518 text[0] = static_cast<unsigned char>(code);
1519 text += 1;
1520 }
1521 else if (code < 0x800) // 2 byte sequence
1522 {
1523 text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF);
1524 code >>= 6;
1525 text[0] = static_cast<unsigned char>(code | 0xC0);
1526 text += 2;
1527 }
1528 else if (code < 0x10000) // 3 byte sequence
1529 {
1530 text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF);
1531 code >>= 6;
1532 text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF);
1533 code >>= 6;
1534 text[0] = static_cast<unsigned char>(code | 0xE0);
1535 text += 3;
1536 }
1537 else if (code < 0x110000) // 4 byte sequence
1538 {
1539 text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF);
1540 code >>= 6;
1541 text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF);
1542 code >>= 6;
1543 text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF);
1544 code >>= 6;
1545 text[0] = static_cast<unsigned char>(code | 0xF0);
1546 text += 4;
1547 }
1548 else // Invalid, only codes up to 0x10FFFF are allowed in Unicode
1549 {
1550 RAPIDXML_PARSE_ERROR("invalid numeric character entity", text);
1551 }
1552 }
1553 }
1554
1555 // Skip characters until predicate evaluates to true
1556 template <class StopPred, int Flags> static void skip(Ch*& text)
1557 {
1558 Ch* tmp = text;
1559 while (StopPred::test(*tmp))
1560 ++tmp;
1561 text = tmp;
1562 }
1563
1564 // Skip characters until predicate evaluates to true while doing the following:
1565 // - replacing XML character entity references with proper characters (&apos; &amp; &quot; &lt; &gt; &#...;)
1566 // - condensing whitespace sequences to single space character
1567 template <class StopPred, class StopPredPure, int Flags> static Ch* skip_and_expand_character_refs(Ch*& text)
1568 {
1569 // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
1570 if (Flags & parse_no_entity_translation && !(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 Ch* dest = src;
1583 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 if (src[0] == Ch('&'))
1590 {
1591 switch (src[1])
1592 {
1593
1594 // &amp; &apos;
1595 case Ch('a'):
1596 if (src[2] == Ch('m') && src[3] == Ch('p') && src[4] == Ch(';'))
1597 {
1598 *dest = Ch('&');
1599 ++dest;
1600 src += 5;
1601 continue;
1602 }
1603 if (src[2] == Ch('p') && src[3] == Ch('o') && src[4] == Ch('s') && src[5] == Ch(';'))
1604 {
1605 *dest = Ch('\'');
1606 ++dest;
1607 src += 6;
1608 continue;
1609 }
1610 break;
1611
1612 // &quot;
1613 case Ch('q'):
1614 if (src[2] == Ch('u') && src[3] == Ch('o') && src[4] == Ch('t') && src[5] == Ch(';'))
1615 {
1616 *dest = Ch('"');
1617 ++dest;
1618 src += 6;
1619 continue;
1620 }
1621 break;
1622
1623 // &gt;
1624 case Ch('g'):
1625 if (src[2] == Ch('t') && src[3] == Ch(';'))
1626 {
1627 *dest = Ch('>');
1628 ++dest;
1629 src += 4;
1630 continue;
1631 }
1632 break;
1633
1634 // &lt;
1635 case Ch('l'):
1636 if (src[2] == Ch('t') && src[3] == Ch(';'))
1637 {
1638 *dest = Ch('<');
1639 ++dest;
1640 src += 4;
1641 continue;
1642 }
1643 break;
1644
1645 // &#...; - assumes ASCII
1646 case Ch('#'):
1647 if (src[2] == Ch('x'))
1648 {
1649 unsigned long code = 0;
1650 src += 3; // Skip &#x
1651 while (1)
1652 {
1653 unsigned char digit =
1654 internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
1655 if (digit == 0xFF)
1656 break;
1657 code = code * 16 + digit;
1658 ++src;
1659 }
1660 insert_coded_character<Flags>(dest, code); // Put character in output
1661 }
1662 else
1663 {
1664 unsigned long code = 0;
1665 src += 2; // Skip &#
1666 while (1)
1667 {
1668 unsigned char digit =
1669 internal::lookup_tables<0>::lookup_digits[static_cast<unsigned char>(*src)];
1670 if (digit == 0xFF)
1671 break;
1672 code = code * 10 + digit;
1673 ++src;
1674 }
1675 insert_coded_character<Flags>(dest, code); // Put character in output
1676 }
1677 if (*src == Ch(';'))
1678 ++src;
1679 else
1680 RAPIDXML_PARSE_ERROR("expected ;", src);
1681 continue;
1682
1683 // Something else
1684 default:
1685 // Ignore, just copy '&' verbatim
1686 break;
1687 }
1688 }
1689 }
1690
1691 // If whitespace condensing is enabled
1692 if (Flags & parse_normalize_whitespace)
1693 {
1694 // Test if condensing is needed
1695 if (whitespace_pred::test(*src))
1696 {
1697 *dest = Ch(' ');
1698 ++dest; // Put single space in dest
1699 ++src; // Skip first whitespace char
1700 // Skip remaining whitespace chars
1701 while (whitespace_pred::test(*src))
1702 ++src;
1703 continue;
1704 }
1705 }
1706
1707 // No replacement, only copy character
1708 *dest++ = *src++;
1709 }
1710
1711 // Return new end
1712 text = src;
1713 return dest;
1714 }
1715
1717 // Internal parsing functions
1718
1719 // Parse BOM, if any
1720 template <int Flags> void parse_bom(Ch*& text)
1721 {
1722 // UTF-8?
1723 if (static_cast<unsigned char>(text[0]) == 0xEF && static_cast<unsigned char>(text[1]) == 0xBB &&
1724 static_cast<unsigned char>(text[2]) == 0xBF)
1725 {
1726 text += 3; // Skup utf-8 bom
1727 }
1728 }
1729
1730 // Parse XML declaration (<?xml...)
1731 template <int Flags> xml_node<Ch>* parse_xml_declaration(Ch*& text)
1732 {
1733 // If parsing of declaration is disabled
1734 if (!(Flags & parse_declaration_node))
1735 {
1736 // Skip until end of declaration
1737 while (text[0] != Ch('?') || text[1] != Ch('>'))
1738 {
1739 if (!text[0])
1740 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1741 ++text;
1742 }
1743 text += 2; // Skip '?>'
1744 return 0;
1745 }
1746
1747 // Create declaration
1748 xml_node<Ch>* declaration = this->allocate_node(node_declaration);
1749
1750 // Skip whitespace before attributes or ?>
1751 skip<whitespace_pred, Flags>(text);
1752
1753 // Parse declaration attributes
1754 parse_node_attributes<Flags>(text, declaration);
1755
1756 // Skip ?>
1757 if (text[0] != Ch('?') || text[1] != Ch('>'))
1758 RAPIDXML_PARSE_ERROR("expected ?>", text);
1759 text += 2;
1760
1761 return declaration;
1762 }
1763
1764 // Parse XML comment (<!--...)
1765 template <int Flags> xml_node<Ch>* parse_comment(Ch*& text)
1766 {
1767 // If parsing of comments is disabled
1768 if (!(Flags & parse_comment_nodes))
1769 {
1770 // Skip until end of comment
1771 while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
1772 {
1773 if (!text[0])
1774 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1775 ++text;
1776 }
1777 text += 3; // Skip '-->'
1778 return 0; // Do not produce comment node
1779 }
1780
1781 // Remember value start
1782 Ch* value = text;
1783
1784 // Skip until end of comment
1785 while (text[0] != Ch('-') || text[1] != Ch('-') || text[2] != Ch('>'))
1786 {
1787 if (!text[0])
1788 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1789 ++text;
1790 }
1791
1792 // Create comment node
1793 xml_node<Ch>* comment = this->allocate_node(node_comment);
1794 comment->value(value, text - value);
1795
1796 // Place zero terminator after comment value
1797 if (!(Flags & parse_no_string_terminators))
1798 *text = Ch('\0');
1799
1800 text += 3; // Skip '-->'
1801 return comment;
1802 }
1803
1804 // Parse DOCTYPE
1805 template <int Flags> xml_node<Ch>* parse_doctype(Ch*& text)
1806 {
1807 // Remember value start
1808 Ch* value = text;
1809
1810 // Skip to >
1811 while (*text != Ch('>'))
1812 {
1813 // Determine character type
1814 switch (*text)
1815 {
1816
1817 // If '[' encountered, scan for matching ending ']' using naive algorithm with depth
1818 // This works for all W3C test files except for 2 most wicked
1819 case Ch('['): {
1820 ++text; // Skip '['
1821 int depth = 1;
1822 while (depth > 0)
1823 {
1824 switch (*text)
1825 {
1826 case Ch('['):
1827 ++depth;
1828 break;
1829 case Ch(']'):
1830 --depth;
1831 break;
1832 case 0:
1833 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1834 }
1835 ++text;
1836 }
1837 break;
1838 }
1839
1840 // Error on end of text
1841 case Ch('\0'):
1842 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1843
1844 // Other character, skip it
1845 default:
1846 ++text;
1847 }
1848 }
1849
1850 // If DOCTYPE nodes enabled
1851 if (Flags & parse_doctype_node)
1852 {
1853 // Create a new doctype node
1854 xml_node<Ch>* doctype = this->allocate_node(node_doctype);
1855 doctype->value(value, text - value);
1856
1857 // Place zero terminator after value
1858 if (!(Flags & parse_no_string_terminators))
1859 *text = Ch('\0');
1860
1861 text += 1; // skip '>'
1862 return doctype;
1863 }
1864 else
1865 {
1866 text += 1; // skip '>'
1867 return 0;
1868 }
1869 }
1870
1871 // Parse PI
1872 template <int Flags> xml_node<Ch>* parse_pi(Ch*& text)
1873 {
1874 // If creation of PI nodes is enabled
1875 if (Flags & parse_pi_nodes)
1876 {
1877 // Create pi node
1878 xml_node<Ch>* pi = this->allocate_node(node_pi);
1879
1880 // Extract PI target name
1881 Ch* name = text;
1882 skip<node_name_pred, Flags>(text);
1883 if (text == name)
1884 RAPIDXML_PARSE_ERROR("expected PI target", text);
1885 pi->name(name, text - name);
1886
1887 // Skip whitespace between pi target and pi
1888 skip<whitespace_pred, Flags>(text);
1889
1890 // Remember start of pi
1891 Ch* value = text;
1892
1893 // Skip to '?>'
1894 while (text[0] != Ch('?') || text[1] != Ch('>'))
1895 {
1896 if (*text == Ch('\0'))
1897 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1898 ++text;
1899 }
1900
1901 // Set pi value (verbatim, no entity expansion or whitespace normalization)
1902 pi->value(value, text - value);
1903
1904 // Place zero terminator after name and value
1905 if (!(Flags & parse_no_string_terminators))
1906 {
1907 pi->name()[pi->name_size()] = Ch('\0');
1908 pi->value()[pi->value_size()] = Ch('\0');
1909 }
1910
1911 text += 2; // Skip '?>'
1912 return pi;
1913 }
1914 else
1915 {
1916 // Skip to '?>'
1917 while (text[0] != Ch('?') || text[1] != Ch('>'))
1918 {
1919 if (*text == Ch('\0'))
1920 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1921 ++text;
1922 }
1923 text += 2; // Skip '?>'
1924 return 0;
1925 }
1926 }
1927
1928 // Parse and append data
1929 // Return character that ends data.
1930 // This is necessary because this character might have been overwritten by a terminating 0
1931 template <int Flags> Ch parse_and_append_data(xml_node<Ch>* node, Ch*& text, Ch* contents_start)
1932 {
1933 // Backup to contents start if whitespace trimming is disabled
1934 if (!(Flags & parse_trim_whitespace))
1935 text = contents_start;
1936
1937 // Skip until end of data
1938 Ch *value = text, *end;
1939 if (Flags & parse_normalize_whitespace)
1940 end = skip_and_expand_character_refs<text_pred, text_pure_with_ws_pred, Flags>(text);
1941 else
1942 end = skip_and_expand_character_refs<text_pred, text_pure_no_ws_pred, Flags>(text);
1943
1944 // Trim trailing whitespace if flag is set; leading was already trimmed by whitespace skip after >
1945 if (Flags & parse_trim_whitespace)
1946 {
1947 if (Flags & parse_normalize_whitespace)
1948 {
1949 // Whitespace is already condensed to single space characters by skipping function, so just trim 1
1950 // char off the end
1951 if (*(end - 1) == Ch(' '))
1952 --end;
1953 }
1954 else
1955 {
1956 // Backup until non-whitespace character is found
1957 while (whitespace_pred::test(*(end - 1)))
1958 --end;
1959 }
1960 }
1961
1962 // If characters are still left between end and value (this test is only necessary if normalization is
1963 // enabled) Create new data node
1964 if (!(Flags & parse_no_data_nodes))
1965 {
1967 data->value(value, end - value);
1968 node->append_node(data);
1969 }
1970
1971 // Add data to parent node if no data exists yet
1972 if (!(Flags & parse_no_element_values))
1973 if (*node->value() == Ch('\0'))
1974 node->value(value, end - value);
1975
1976 // Place zero terminator after value
1977 if (!(Flags & parse_no_string_terminators))
1978 {
1979 Ch ch = *text;
1980 *end = Ch('\0');
1981 return ch; // Return character that ends data; this is required because zero terminator overwritten it
1982 }
1983
1984 // Return character that ends data
1985 return *text;
1986 }
1987
1988 // Parse CDATA
1989 template <int Flags> xml_node<Ch>* parse_cdata(Ch*& text)
1990 {
1991 // If CDATA is disabled
1992 if (Flags & parse_no_data_nodes)
1993 {
1994 // Skip until end of cdata
1995 while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
1996 {
1997 if (!text[0])
1998 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
1999 ++text;
2000 }
2001 text += 3; // Skip ]]>
2002 return 0; // Do not produce CDATA node
2003 }
2004
2005 // Skip until end of cdata
2006 Ch* value = text;
2007 while (text[0] != Ch(']') || text[1] != Ch(']') || text[2] != Ch('>'))
2008 {
2009 if (!text[0])
2010 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2011 ++text;
2012 }
2013
2014 // Create new cdata node
2015 xml_node<Ch>* cdata = this->allocate_node(node_cdata);
2016 cdata->value(value, text - value);
2017
2018 // Place zero terminator after value
2019 if (!(Flags & parse_no_string_terminators))
2020 *text = Ch('\0');
2021
2022 text += 3; // Skip ]]>
2023 return cdata;
2024 }
2025
2026 // Parse element node
2027 template <int Flags> xml_node<Ch>* parse_element(Ch*& text)
2028 {
2029 // Create element node
2030 xml_node<Ch>* element = this->allocate_node(node_element);
2031
2032 // Extract element name
2033 Ch* name = text;
2034 skip<node_name_pred, Flags>(text);
2035 if (text == name)
2036 RAPIDXML_PARSE_ERROR("expected element name", text);
2037 element->name(name, text - name);
2038
2039 // Skip whitespace between element name and attributes or >
2040 skip<whitespace_pred, Flags>(text);
2041
2042 // Parse attributes, if any
2043 parse_node_attributes<Flags>(text, element);
2044
2045 // Determine ending type
2046 if (*text == Ch('>'))
2047 {
2048 ++text;
2049 parse_node_contents<Flags>(text, element);
2050 }
2051 else if (*text == Ch('/'))
2052 {
2053 ++text;
2054 if (*text != Ch('>'))
2055 RAPIDXML_PARSE_ERROR("expected >", text);
2056 ++text;
2057 }
2058 else
2059 RAPIDXML_PARSE_ERROR("expected >", text);
2060
2061 // Place zero terminator after name
2062 if (!(Flags & parse_no_string_terminators))
2063 element->name()[element->name_size()] = Ch('\0');
2064
2065 // Return parsed element
2066 return element;
2067 }
2068
2069 // Determine node type, and parse it
2070 template <int Flags> xml_node<Ch>* parse_node(Ch*& text)
2071 {
2072 // Parse proper node type
2073 switch (text[0])
2074 {
2075
2076 // <...
2077 default:
2078 // Parse and append element node
2079 return parse_element<Flags>(text);
2080
2081 // <?...
2082 case Ch('?'):
2083 ++text; // Skip ?
2084 if ((text[0] == Ch('x') || text[0] == Ch('X')) && (text[1] == Ch('m') || text[1] == Ch('M')) &&
2085 (text[2] == Ch('l') || text[2] == Ch('L')) && whitespace_pred::test(text[3]))
2086 {
2087 // '<?xml ' - xml declaration
2088 text += 4; // Skip 'xml '
2089 return parse_xml_declaration<Flags>(text);
2090 }
2091 else
2092 {
2093 // Parse PI
2094 return parse_pi<Flags>(text);
2095 }
2096
2097 // <!...
2098 case Ch('!'):
2099
2100 // Parse proper subset of <! node
2101 switch (text[1])
2102 {
2103
2104 // <!-
2105 case Ch('-'):
2106 if (text[2] == Ch('-'))
2107 {
2108 // '<!--' - xml comment
2109 text += 3; // Skip '!--'
2110 return parse_comment<Flags>(text);
2111 }
2112 break;
2113
2114 // <![
2115 case Ch('['):
2116 if (text[2] == Ch('C') && text[3] == Ch('D') && text[4] == Ch('A') && text[5] == Ch('T') &&
2117 text[6] == Ch('A') && text[7] == Ch('['))
2118 {
2119 // '<![CDATA[' - cdata
2120 text += 8; // Skip '![CDATA['
2121 return parse_cdata<Flags>(text);
2122 }
2123 break;
2124
2125 // <!D
2126 case Ch('D'):
2127 if (text[2] == Ch('O') && text[3] == Ch('C') && text[4] == Ch('T') && text[5] == Ch('Y') &&
2128 text[6] == Ch('P') && text[7] == Ch('E') && whitespace_pred::test(text[8]))
2129 {
2130 // '<!DOCTYPE ' - doctype
2131 text += 9; // skip '!DOCTYPE '
2132 return parse_doctype<Flags>(text);
2133 }
2134
2135 } // switch
2136
2137 // Attempt to skip other, unrecognized node types starting with <!
2138 ++text; // Skip !
2139 while (*text != Ch('>'))
2140 {
2141 if (*text == 0)
2142 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2143 ++text;
2144 }
2145 ++text; // Skip '>'
2146 return 0; // No node recognized
2147 }
2148 }
2149
2150 // Parse contents of the node - children, data etc.
2151 template <int Flags> void parse_node_contents(Ch*& text, xml_node<Ch>* node)
2152 {
2153 // For all children and text
2154 while (1)
2155 {
2156 // Skip whitespace between > and node contents
2157 Ch* contents_start = text; // Store start of node contents before whitespace is skipped
2158 skip<whitespace_pred, Flags>(text);
2159 Ch next_char = *text;
2160
2161 // After data nodes, instead of continuing the loop, control jumps here.
2162 // This is because zero termination inside parse_and_append_data() function
2163 // would wreak havoc with the above code.
2164 // Also, skipping whitespace after data nodes is unnecessary.
2165 after_data_node:
2166
2167 // Determine what comes next: node closing, child node, data node, or 0?
2168 switch (next_char)
2169 {
2170
2171 // Node closing or child node
2172 case Ch('<'):
2173 if (text[1] == Ch('/'))
2174 {
2175 // Node closing
2176 text += 2; // Skip '</'
2177 if (Flags & parse_validate_closing_tags)
2178 {
2179 // Skip and validate closing tag name
2180 Ch* closing_name = text;
2181 skip<node_name_pred, Flags>(text);
2182 if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name,
2183 true))
2184 RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
2185 }
2186 else
2187 {
2188 // No validation, just skip name
2189 skip<node_name_pred, Flags>(text);
2190 }
2191 // Skip remaining whitespace after node name
2192 skip<whitespace_pred, Flags>(text);
2193 if (*text != Ch('>'))
2194 RAPIDXML_PARSE_ERROR("expected >", text);
2195 ++text; // Skip '>'
2196 return; // Node closed, finished parsing contents
2197 }
2198 else
2199 {
2200 // Child node
2201 ++text; // Skip '<'
2202 if (xml_node<Ch>* child = parse_node<Flags>(text))
2203 node->append_node(child);
2204 }
2205 break;
2206
2207 // End of data - error
2208 case Ch('\0'):
2209 RAPIDXML_PARSE_ERROR("unexpected end of data", text);
2210
2211 // Data node
2212 default:
2213 next_char = parse_and_append_data<Flags>(node, text, contents_start);
2214 goto after_data_node; // Bypass regular processing after data nodes
2215 }
2216 }
2217 }
2218
2219 // Parse XML attributes of the node
2220 template <int Flags> void parse_node_attributes(Ch*& text, xml_node<Ch>* node)
2221 {
2222 // For all attributes
2223 while (attribute_name_pred::test(*text))
2224 {
2225 // Extract attribute name
2226 Ch* name = text;
2227 ++text; // Skip first character of attribute name
2228 skip<attribute_name_pred, Flags>(text);
2229 if (text == name)
2230 RAPIDXML_PARSE_ERROR("expected attribute name", name);
2231
2232 // Create new attribute
2233 xml_attribute<Ch>* attribute = this->allocate_attribute();
2234 attribute->name(name, text - name);
2235 node->append_attribute(attribute);
2236
2237 // Skip whitespace after attribute name
2238 skip<whitespace_pred, Flags>(text);
2239
2240 // Skip =
2241 if (*text != Ch('='))
2242 RAPIDXML_PARSE_ERROR("expected =", text);
2243 ++text;
2244
2245 // Add terminating zero after name
2246 if (!(Flags & parse_no_string_terminators))
2247 attribute->name()[attribute->name_size()] = 0;
2248
2249 // Skip whitespace after =
2250 skip<whitespace_pred, Flags>(text);
2251
2252 // Skip quote and remember if it was ' or "
2253 Ch quote = *text;
2254 if (quote != Ch('\'') && quote != Ch('"'))
2255 RAPIDXML_PARSE_ERROR("expected ' or \"", text);
2256 ++text;
2257
2258 // Extract attribute value and expand char refs in it
2259 Ch *value = text, *end;
2260 const int AttFlags = Flags & ~parse_normalize_whitespace; // No whitespace normalization in attributes
2261 if (quote == Ch('\''))
2263 attribute_value_pure_pred<Ch('\'')>, AttFlags>(text);
2264 else
2266 attribute_value_pure_pred<Ch('"')>, AttFlags>(text);
2267
2268 // Set attribute value
2269 attribute->value(value, end - value);
2270
2271 // Make sure that end quote is present
2272 if (*text != quote)
2273 RAPIDXML_PARSE_ERROR("expected ' or \"", text);
2274 ++text; // Skip quote
2275
2276 // Add terminating zero after value
2277 if (!(Flags & parse_no_string_terminators))
2278 attribute->value()[attribute->value_size()] = 0;
2279
2280 // Skip whitespace after attribute value
2281 skip<whitespace_pred, Flags>(text);
2282 }
2283 }
2284 };
2285
2287 namespace internal
2288 {
2289
2290 // Whitespace (space \n \r \t)
2291 template <int Dummy>
2292 const unsigned char lookup_tables<Dummy>::lookup_whitespace[256] = {
2293 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2294 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, // 0
2295 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
2296 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
2297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
2298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
2299 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
2300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
2301 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 7
2302 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
2303 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
2304 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
2305 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
2306 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
2307 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
2308 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
2309 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
2310 };
2311
2312 // Node name (anything but space \n \r \t / > ? \0)
2313 template <int Dummy>
2314 const unsigned char lookup_tables<Dummy>::lookup_node_name[256] = {
2315 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2316 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
2317 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2318 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
2319 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, // 3
2320 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2321 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2322 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2323 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2324 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2325 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2326 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2327 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2328 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2329 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2330 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2331 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2332 };
2333
2334 // Text (i.e. PCDATA) (anything but < \0)
2335 template <int Dummy>
2336 const unsigned char lookup_tables<Dummy>::lookup_text[256] = {
2337 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2338 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2339 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2340 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2341 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
2342 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2343 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2344 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2345 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2346 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2347 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2348 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2349 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2354 };
2355
2356 // Text (i.e. PCDATA) that does not require processing when ws normalization is disabled
2357 // (anything but < \0 &)
2358 template <int Dummy>
2359 const unsigned char lookup_tables<Dummy>::lookup_text_pure_no_ws[256] = {
2360 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2361 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2362 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2363 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
2365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2367 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2368 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2369 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2370 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2371 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2372 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2373 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2375 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2377 };
2378
2379 // Text (i.e. PCDATA) that does not require processing when ws normalizationis is enabled
2380 // (anything but < \0 & space \n \r \t)
2381 template <int Dummy>
2382 const unsigned char lookup_tables<Dummy>::lookup_text_pure_with_ws[256] = {
2383 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2384 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
2385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2386 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2387 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 3
2388 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2389 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2390 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2391 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2392 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2393 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2394 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2395 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2396 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2397 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2398 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2399 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2400 };
2401
2402 // Attribute name (anything but space \n \r \t / < > = ? ! \0)
2403 template <int Dummy>
2404 const unsigned char lookup_tables<Dummy>::lookup_attribute_name[256] = {
2405 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2406 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, // 0
2407 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2408 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 2
2409 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 3
2410 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2411 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2412 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2413 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2414 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2415 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2419 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2421 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2422 };
2423
2424 // Attribute data with single quote (anything but ' \0)
2425 template <int Dummy>
2426 const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1[256] = {
2427 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2428 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2429 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2430 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
2432 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2433 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2437 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2439 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2440 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2441 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2442 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2443 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2444 };
2445
2446 // Attribute data with single quote that does not require processing (anything but ' \0 &)
2447 template <int Dummy>
2448 const unsigned char lookup_tables<Dummy>::lookup_attribute_data_1_pure[256] = {
2449 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2450 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2451 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2452 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2453 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
2454 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2455 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2456 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2457 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2458 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2459 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2460 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2461 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2462 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2463 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2464 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2465 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2466 };
2467
2468 // Attribute data with double quote (anything but " \0)
2469 template <int Dummy>
2470 const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2[256] = {
2471 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2472 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2473 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2474 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2475 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
2476 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2477 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2478 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2479 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2480 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2481 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2482 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2483 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2484 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2485 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2486 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2487 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2488 };
2489
2490 // Attribute data with double quote that does not require processing (anything but " \0 &)
2491 template <int Dummy>
2492 const unsigned char lookup_tables<Dummy>::lookup_attribute_data_2_pure[256] = {
2493 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2494 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0
2495 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 1
2496 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 2
2497 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 3
2498 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
2499 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 5
2500 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
2501 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 7
2502 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 8
2503 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 9
2504 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A
2505 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B
2506 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C
2507 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D
2508 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E
2509 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // F
2510 };
2511
2512 // Digits (dec and hex, 255 denotes end of numeric character reference)
2513 template <int Dummy>
2514 const unsigned char lookup_tables<Dummy>::lookup_digits[256] = {
2515 // 0 1 2 3 4 5 6 7 8 9 A B C D E F
2516 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 0
2517 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 1
2518 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 2
2519 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, // 3
2520 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 4
2521 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 5
2522 255, 10, 11, 12, 13, 14, 15, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 6
2523 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 7
2524 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 8
2525 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 9
2526 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // A
2527 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // B
2528 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // C
2529 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // D
2530 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // E
2531 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 // F
2532 };
2533
2534 // Upper case conversion
2535 template <int Dummy>
2536 const unsigned char lookup_tables<Dummy>::lookup_upcase[256] = {
2537 // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A B C D E F
2538 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0
2539 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, // 1
2540 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 2
2541 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 3
2542 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 4
2543 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, // 5
2544 96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, // 6
2545 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123, 124, 125, 126, 127, // 7
2546 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, // 8
2547 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 9
2548 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, // A
2549 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, // B
2550 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, // C
2551 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, // D
2552 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // E
2553 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 // F
2554 };
2555 } // namespace internal
2557
2558} // namespace rapidxml
2559
2560// Undefine internal macros
2561#undef RAPIDXML_PARSE_ERROR
2562
2563// On MSVC, restore warnings state
2564#ifdef _MSC_VER
2565#pragma warning(pop)
2566#endif
2567
2568#endif
Definition rapidxml.hpp:366
~memory_pool()
Definition rapidxml.hpp:383
memory_pool()
Constructs empty pool with default allocator functions.
Definition rapidxml.hpp:375
void init()
Definition rapidxml.hpp:554
xml_node< Ch > * clone_node(const xml_node< Ch > *source, xml_node< Ch > *result=0)
Definition rapidxml.hpp:485
char * m_ptr
Definition rapidxml.hpp:628
char * allocate_raw(std::size_t size)
Definition rapidxml.hpp:568
char * m_end
Definition rapidxml.hpp:629
void * allocate_aligned(std::size_t size)
Definition rapidxml.hpp:591
char * m_begin
Definition rapidxml.hpp:627
xml_node< Ch > * allocate_node(node_type type, const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
Definition rapidxml.hpp:398
void set_allocator(alloc_func *af, free_func *ff)
Definition rapidxml.hpp:541
Ch * allocate_string(const Ch *source=0, std::size_t size=0)
Definition rapidxml.hpp:464
char * align(char *ptr)
Definition rapidxml.hpp:561
char m_static_memory[RAPIDXML_STATIC_POOL_SIZE]
Definition rapidxml.hpp:630
void clear()
Definition rapidxml.hpp:514
xml_attribute< Ch > * allocate_attribute(const Ch *name=0, const Ch *value=0, std::size_t name_size=0, std::size_t value_size=0)
Definition rapidxml.hpp:432
alloc_func * m_alloc_func
Definition rapidxml.hpp:631
free_func * m_free_func
Definition rapidxml.hpp:632
Definition rapidxml.hpp:76
const char * m_what
Definition rapidxml.hpp:100
virtual const char * what() const
Definition rapidxml.hpp:86
void * m_where
Definition rapidxml.hpp:101
Ch * where() const
Definition rapidxml.hpp:94
parse_error(const char *what, void *where)
Constructs parse error.
Definition rapidxml.hpp:80
Definition rapidxml.hpp:784
xml_attribute< Ch > * next_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition rapidxml.hpp:845
xml_attribute< Ch > * previous_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition rapidxml.hpp:821
xml_attribute< Ch > * m_prev_attribute
Definition rapidxml.hpp:864
xml_attribute()
Definition rapidxml.hpp:794
xml_attribute< Ch > * m_next_attribute
Definition rapidxml.hpp:867
xml_document< Ch > * document() const
Definition rapidxml.hpp:803
Definition rapidxml.hpp:642
std::size_t name_size() const
Definition rapidxml.hpp:669
xml_base()
Definition rapidxml.hpp:649
Ch * m_value
Definition rapidxml.hpp:772
std::size_t value_size() const
Definition rapidxml.hpp:687
void value(const Ch *value, std::size_t size)
Definition rapidxml.hpp:739
void name(const Ch *name)
Definition rapidxml.hpp:717
std::size_t m_name_size
Definition rapidxml.hpp:773
Ch * name() const
Definition rapidxml.hpp:661
void value(const Ch *value)
Definition rapidxml.hpp:748
xml_node< Ch > * m_parent
Definition rapidxml.hpp:775
std::size_t m_value_size
Definition rapidxml.hpp:774
static Ch * nullstr()
Definition rapidxml.hpp:765
xml_node< Ch > * parent() const
Definition rapidxml.hpp:758
void name(const Ch *name, std::size_t size)
Definition rapidxml.hpp:708
Ch * value() const
Definition rapidxml.hpp:679
Ch * m_name
Definition rapidxml.hpp:771
Definition rapidxml.hpp:1361
xml_node< Ch > * parse_element(Ch *&text)
Definition rapidxml.hpp:2027
xml_node< Ch > * parse_cdata(Ch *&text)
Definition rapidxml.hpp:1989
static void skip(Ch *&text)
Definition rapidxml.hpp:1556
void clear()
Definition rapidxml.hpp:1412
void parse_bom(Ch *&text)
Definition rapidxml.hpp:1720
void parse_node_contents(Ch *&text, xml_node< Ch > *node)
Definition rapidxml.hpp:2151
xml_document()
Constructs empty XML document.
Definition rapidxml.hpp:1365
static Ch * skip_and_expand_character_refs(Ch *&text)
Definition rapidxml.hpp:1567
xml_node< Ch > * parse_pi(Ch *&text)
Definition rapidxml.hpp:1872
void parse_node_attributes(Ch *&text, xml_node< Ch > *node)
Definition rapidxml.hpp:2220
void parse(Ch *text)
Definition rapidxml.hpp:1379
xml_node< Ch > * parse_xml_declaration(Ch *&text)
Definition rapidxml.hpp:1731
xml_node< Ch > * parse_node(Ch *&text)
Definition rapidxml.hpp:2070
static void insert_coded_character(Ch *&text, unsigned long code)
Definition rapidxml.hpp:1504
Ch parse_and_append_data(xml_node< Ch > *node, Ch *&text, Ch *contents_start)
Definition rapidxml.hpp:1931
xml_node< Ch > * parse_doctype(Ch *&text)
Definition rapidxml.hpp:1805
xml_node< Ch > * parse_comment(Ch *&text)
Definition rapidxml.hpp:1765
Definition rapidxml.hpp:882
void remove_last_attribute()
Definition rapidxml.hpp:1276
xml_node< Ch > * m_next_sibling
Definition rapidxml.hpp:1346
node_type m_type
Definition rapidxml.hpp:1337
void append_attribute(xml_attribute< Ch > *attribute)
Definition rapidxml.hpp:1216
xml_node< Ch > * m_first_node
Definition rapidxml.hpp:1338
void type(node_type type)
Definition rapidxml.hpp:1064
xml_node< Ch > * m_prev_sibling
Definition rapidxml.hpp:1344
xml_attribute< Ch > * m_first_attribute
Definition rapidxml.hpp:1341
node_type type() const
Definition rapidxml.hpp:900
void remove_first_node()
Definition rapidxml.hpp:1139
void insert_node(xml_node< Ch > *where, xml_node< Ch > *child)
Definition rapidxml.hpp:1118
void remove_attribute(xml_attribute< Ch > *where)
Definition rapidxml.hpp:1292
void append_node(xml_node< Ch > *child)
Definition rapidxml.hpp:1096
void prepend_attribute(xml_attribute< Ch > *attribute)
Definition rapidxml.hpp:1196
xml_node(node_type type)
Definition rapidxml.hpp:891
xml_attribute< Ch > * last_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition rapidxml.hpp:1041
void remove_last_node()
Definition rapidxml.hpp:1154
void remove_all_nodes()
Removes all child nodes (but not attributes).
Definition rapidxml.hpp:1187
void remove_node(xml_node< Ch > *where)
Removes specified child from the node.
Definition rapidxml.hpp:1170
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition rapidxml.hpp:1017
void insert_attribute(xml_attribute< Ch > *where, xml_attribute< Ch > *attribute)
Definition rapidxml.hpp:1238
xml_document< Ch > * document() const
Definition rapidxml.hpp:910
void remove_all_attributes()
Removes all attributes of node.
Definition rapidxml.hpp:1308
void operator=(const xml_node &)
void remove_first_attribute()
Definition rapidxml.hpp:1259
xml_node< Ch > * next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition rapidxml.hpp:995
xml_node< Ch > * previous_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition rapidxml.hpp:971
xml_attribute< Ch > * m_last_attribute
Definition rapidxml.hpp:1342
xml_node< Ch > * m_last_node
Definition rapidxml.hpp:1339
void prepend_node(xml_node< Ch > *child)
Definition rapidxml.hpp:1075
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition rapidxml.hpp:924
xml_node(const xml_node &)
xml_node< Ch > * last_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition rapidxml.hpp:947
Definition core.h:1598
type
Definition core.h:681
auto ptr(T p) -> const void *
Definition format.h:4568
Definition core.h:2677
Definition rapidxml.hpp:62
const int parse_no_element_values
Definition rapidxml.hpp:170
const int parse_pi_nodes
Definition rapidxml.hpp:218
const int parse_no_utf8
Definition rapidxml.hpp:191
const int parse_normalize_whitespace
Definition rapidxml.hpp:243
const int parse_doctype_node
Definition rapidxml.hpp:211
const int parse_non_destructive
Definition rapidxml.hpp:265
const int parse_trim_whitespace
Definition rapidxml.hpp:234
const int parse_fastest
Definition rapidxml.hpp:270
const int parse_validate_closing_tags
Definition rapidxml.hpp:226
const int parse_no_entity_translation
Definition rapidxml.hpp:184
const int parse_declaration_node
Definition rapidxml.hpp:198
node_type
Definition rapidxml.hpp:142
@ node_comment
A comment node. Name is empty. Value contains comment text.
Definition rapidxml.hpp:147
@ node_document
A document node. Name and value are empty.
Definition rapidxml.hpp:143
@ node_element
An element node. Name contains element name. Value contains text of first data node.
Definition rapidxml.hpp:144
@ node_data
A data node. Name is empty. Value contains data text.
Definition rapidxml.hpp:145
@ node_cdata
A CDATA node. Name is empty. Value contains data text.
Definition rapidxml.hpp:146
@ node_doctype
A DOCTYPE node. Name is empty. Value contains DOCTYPE text.
Definition rapidxml.hpp:150
@ node_pi
A PI node. Name contains target. Value contains instructions.
Definition rapidxml.hpp:151
@ node_declaration
Definition rapidxml.hpp:148
const int parse_full
Definition rapidxml.hpp:276
const int parse_no_data_nodes
Definition rapidxml.hpp:162
const int parse_default
Definition rapidxml.hpp:255
const int parse_comment_nodes
Definition rapidxml.hpp:205
const int parse_no_string_terminators
Definition rapidxml.hpp:177
#define RAPIDXML_STATIC_POOL_SIZE
Definition rapidxml.hpp:114
#define RAPIDXML_PARSE_ERROR(what, where)
Definition rapidxml.hpp:59
#define RAPIDXML_DYNAMIC_POOL_SIZE
Definition rapidxml.hpp:121
#define RAPIDXML_ALIGNMENT
Definition rapidxml.hpp:129
Definition format.h:1901
Definition rapidxml.hpp:550
char * previous_begin
Definition rapidxml.hpp:551
static unsigned char test(Ch ch)
Definition rapidxml.hpp:1444
static unsigned char test(Ch ch)
Definition rapidxml.hpp:1480
static unsigned char test(Ch ch)
Definition rapidxml.hpp:1493
Definition rapidxml.hpp:1434
static unsigned char test(Ch ch)
Definition rapidxml.hpp:1435
Definition rapidxml.hpp:1452
static unsigned char test(Ch ch)
Definition rapidxml.hpp:1453
static unsigned char test(Ch ch)
Definition rapidxml.hpp:1462
static unsigned char test(Ch ch)
Definition rapidxml.hpp:1471
Definition rapidxml.hpp:1425
static unsigned char test(Ch ch)
Definition rapidxml.hpp:1426
source
Definition tag_strings.h:83
i
Definition tag_strings.h:60
p
Definition tag_strings.h:29
code
Definition tag_strings.h:54