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


livox_ros_driver
Author(s): Livox Dev Team
autogenerated on Mon Mar 15 2021 02:40:46