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