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


asr_rapidxml
Author(s): Aumann Florian
autogenerated on Thu Dec 5 2019 03:14:36