ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
pugixml.cpp
Go to the documentation of this file.
1 
14 #ifndef SOURCE_PUGIXML_CPP
15 #define SOURCE_PUGIXML_CPP
16 
17 #ifndef NO_ETISS
19 #else
20 #include "fault/xml/pugixml.hpp"
21 #endif
22 #include <assert.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #ifdef PUGIXML_WCHAR_MODE
28 #include <wchar.h>
29 #endif
30 
31 #ifndef PUGIXML_NO_XPATH
32 #include <math.h>
33 #include <float.h>
34 #ifdef PUGIXML_NO_EXCEPTIONS
35 #include <setjmp.h>
36 #endif
37 #endif
38 
39 #ifndef PUGIXML_NO_STL
40 #include <istream>
41 #include <ostream>
42 #include <string>
43 #endif
44 
45 // For placement new
46 #include <new>
47 
48 #ifdef _MSC_VER
49 #pragma warning(push)
50 #pragma warning(disable : 4127) // conditional expression is constant
51 #pragma warning(disable : 4324) // structure was padded due to __declspec(align())
52 #pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
53 #pragma warning(disable : 4702) // unreachable code
54 #pragma warning(disable : 4996) // this function or variable may be unsafe
55 #pragma warning(disable : 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
56 #endif
57 
58 #ifdef __INTEL_COMPILER
59 #pragma warning(disable : 177) // function was declared but never referenced
60 #pragma warning(disable : 279) // controlling expression is constant
61 #pragma warning(disable : 1478 1786) // function was declared "deprecated"
62 #pragma warning(disable : 1684) // conversion from pointer to same-sized integral type
63 #endif
64 
65 #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
66 #pragma warn - 8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the
67  // warning go away
68 #endif
69 
70 #ifdef __BORLANDC__
71 #pragma option push
72 #pragma warn - 8008 // condition is always false
73 #pragma warn - 8066 // unreachable code
74 #endif
75 
76 #ifdef __SNC__
77 // Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug
78 #pragma diag_suppress = 178 // function was declared but never referenced
79 #pragma diag_suppress = 237 // controlling expression is constant
80 #endif
81 
82 // Inlining controls
83 #if defined(_MSC_VER) && _MSC_VER >= 1300
84 #define PUGI__NO_INLINE __declspec(noinline)
85 #elif defined(__GNUC__)
86 #define PUGI__NO_INLINE __attribute__((noinline))
87 #else
88 #define PUGI__NO_INLINE
89 #endif
90 
91 // Simple static assertion
92 #define PUGI__STATIC_ASSERT(cond) \
93  { \
94  static const char condition_failed[(cond) ? 1 : -1] = { 0 }; \
95  (void)condition_failed[0]; \
96  }
97 
98 // Digital Mars C++ bug workaround for passing char loaded from memory via stack
99 #ifdef __DMC__
100 #define PUGI__DMC_VOLATILE volatile
101 #else
102 #define PUGI__DMC_VOLATILE
103 #endif
104 
105 // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy
106 // because some compilers don't have it at all)
107 #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
108 using std::memcpy;
109 using std::memmove;
110 #endif
111 
112 // In some environments MSVC is a compiler but the CRT lacks certain
113 // MSVC-specific features
114 #if defined(_MSC_VER) && !defined(__S3E__)
115 #define PUGI__MSVC_CRT_VERSION _MSC_VER
116 #endif
117 
118 #ifdef PUGIXML_HEADER_ONLY
119 #define PUGI__NS_BEGIN \
120  namespace pugi \
121  { \
122  namespace impl \
123  {
124 #define PUGI__NS_END \
125  } \
126  }
127 #define PUGI__FN inline
128 #define PUGI__FN_NO_INLINE inline
129 #else
130 #if defined(_MSC_VER) && \
131  _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
132 #define PUGI__NS_BEGIN \
133  namespace pugi \
134  { \
135  namespace impl \
136  {
137 #define PUGI__NS_END \
138  } \
139  }
140 #else
141 #define PUGI__NS_BEGIN \
142  namespace pugi \
143  { \
144  namespace impl \
145  { \
146  namespace \
147  {
148 #define PUGI__NS_END \
149  } \
150  } \
151  }
152 #endif
153 #define PUGI__FN
154 #define PUGI__FN_NO_INLINE PUGI__NO_INLINE
155 #endif
156 
157 // uintptr_t
158 #if !defined(_MSC_VER) || _MSC_VER >= 1600
159 #include <stdint.h>
160 #else
161 #ifndef _UINTPTR_T_DEFINED
162 // No native uintptr_t in MSVC6 and in some WinCE versions
163 typedef size_t uintptr_t;
164 #define _UINTPTR_T_DEFINED
165 #endif
167 typedef unsigned __int8 uint8_t;
168 typedef unsigned __int16 uint16_t;
169 typedef unsigned __int32 uint32_t;
171 #endif
172 
173 // Memory allocation
175 PUGI__FN void *default_allocate(size_t size)
176 {
177  return malloc(size);
178 }
179 
181 {
182  free(ptr);
183 }
184 
185 template <typename T>
187 {
190 };
191 
192 template <typename T>
194 template <typename T>
196 
199 
200 // String utilities
202 // Get string length
203 PUGI__FN size_t strlength(const char_t *s)
204 {
205  assert(s);
206 
207 #ifdef PUGIXML_WCHAR_MODE
208  return wcslen(s);
209 #else
210  return strlen(s);
211 #endif
212 }
213 
214 // Compare two strings
215 PUGI__FN bool strequal(const char_t *src, const char_t *dst)
216 {
217  assert(src && dst);
218 
219 #ifdef PUGIXML_WCHAR_MODE
220  return wcscmp(src, dst) == 0;
221 #else
222  return strcmp(src, dst) == 0;
223 #endif
224 }
225 
226 // Compare lhs with [rhs_begin, rhs_end)
227 PUGI__FN bool strequalrange(const char_t *lhs, const char_t *rhs, size_t count)
228 {
229  for (size_t i = 0; i < count; ++i)
230  if (lhs[i] != rhs[i])
231  return false;
232 
233  return lhs[count] == 0;
234 }
235 
236 // Get length of wide string, even if CRT lacks wide character support
237 PUGI__FN size_t strlength_wide(const wchar_t *s)
238 {
239  assert(s);
240 
241 #ifdef PUGIXML_WCHAR_MODE
242  return wcslen(s);
243 #else
244  const wchar_t *end = s;
245  while (*end)
246  end++;
247  return static_cast<size_t>(end - s);
248 #endif
249 }
250 
251 #ifdef PUGIXML_WCHAR_MODE
252 // Convert string to wide string, assuming all symbols are ASCII
253 PUGI__FN void widen_ascii(wchar_t *dest, const char *source)
254 {
255  for (const char *i = source; *i; ++i)
256  *dest++ = *i;
257  *dest = 0;
258 }
259 #endif
261 
262 #if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH)
263 // auto_ptr-like buffer holder for exception recovery
266 {
267  void *data;
268  void (*deleter)(void *);
269 
270  buffer_holder(void *data_, void (*deleter_)(void *)) : data(data_), deleter(deleter_) {}
271 
273  {
274  if (data)
275  deleter(data);
276  }
277 
278  void *release()
279  {
280  void *result = data;
281  data = 0;
282  return result;
283  }
284 };
286 #endif
287 
289 static const size_t xml_memory_page_size =
290 #ifdef PUGIXML_MEMORY_PAGE_SIZE
291  PUGIXML_MEMORY_PAGE_SIZE
292 #else
293  32768
294 #endif
295  ;
296 
302 
303 struct xml_allocator;
304 
306 {
308  {
309  if (!memory)
310  return 0; //$ redundant, left for performance
311 
312  xml_memory_page *result = static_cast<xml_memory_page *>(memory);
313 
314  result->allocator = 0;
315  result->memory = 0;
316  result->prev = 0;
317  result->next = 0;
318  result->busy_size = 0;
319  result->freed_size = 0;
320 
321  return result;
322  }
323 
325 
326  void *memory;
327 
330 
331  size_t busy_size;
332  size_t freed_size;
333 
334  char data[1];
335 };
336 
338 {
339  uint16_t page_offset; // offset from page->data
340  uint16_t full_size; // 0 if string occupies whole page
341 };
342 
344 {
345  xml_allocator(xml_memory_page *root) : _root(root), _busy_size(root->busy_size) {}
346 
347  xml_memory_page *allocate_page(size_t data_size)
348  {
349  size_t size = offsetof(xml_memory_page, data) + data_size;
350 
351  // allocate block with some alignment, leaving memory for worst-case padding
352  void *memory = xml_memory::allocate(size + xml_memory_page_alignment);
353  if (!memory)
354  return 0;
355 
356  // align upwards to page boundary
357  void *page_memory = reinterpret_cast<void *>(
358  (reinterpret_cast<uintptr_t>(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1));
359 
360  // prepare page structure
361  xml_memory_page *page = xml_memory_page::construct(page_memory);
362  assert(page);
363 
364  page->memory = memory;
365  page->allocator = _root->allocator;
366 
367  return page;
368  }
369 
371 
372  void *allocate_memory_oob(size_t size, xml_memory_page *&out_page);
373 
374  void *allocate_memory(size_t size, xml_memory_page *&out_page)
375  {
376  if (_busy_size + size > xml_memory_page_size)
377  return allocate_memory_oob(size, out_page);
378 
379  void *buf = _root->data + _busy_size;
380 
381  _busy_size += size;
382 
383  out_page = _root;
384 
385  return buf;
386  }
387 
388  void deallocate_memory(void *ptr, size_t size, xml_memory_page *page)
389  {
390  if (page == _root)
391  page->busy_size = _busy_size;
392 
393  assert(ptr >= page->data && ptr < page->data + page->busy_size);
394  (void)!ptr;
395 
396  page->freed_size += size;
397  assert(page->freed_size <= page->busy_size);
398 
399  if (page->freed_size == page->busy_size)
400  {
401  if (page->next == 0)
402  {
403  assert(_root == page);
404 
405  // top page freed, just reset sizes
406  page->busy_size = page->freed_size = 0;
407  _busy_size = 0;
408  }
409  else
410  {
411  assert(_root != page);
412  assert(page->prev);
413 
414  // remove from the list
415  page->prev->next = page->next;
416  page->next->prev = page->prev;
417 
418  // deallocate
419  deallocate_page(page);
420  }
421  }
422  }
423 
425  {
426  // allocate memory for string and header block
427  size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
428 
429  // round size up to pointer alignment boundary
430  size_t full_size = (size + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1);
431 
432  xml_memory_page *page;
433  xml_memory_string_header *header = static_cast<xml_memory_string_header *>(allocate_memory(full_size, page));
434 
435  if (!header)
436  return 0;
437 
438  // setup header
439  ptrdiff_t page_offset = reinterpret_cast<char *>(header) - page->data;
440 
441  assert(page_offset >= 0 && page_offset < (1 << 16));
442  header->page_offset = static_cast<uint16_t>(page_offset);
443 
444  // full_size == 0 for large strings that occupy the whole page
445  assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0));
446  header->full_size = static_cast<uint16_t>(full_size < (1 << 16) ? full_size : 0);
447 
448  // round-trip through void* to avoid 'cast increases required alignment of target type' warning
449  // header is guaranteed a pointer-sized alignment, which should be enough for char_t
450  return static_cast<char_t *>(static_cast<void *>(header + 1));
451  }
452 
453  void deallocate_string(char_t *string)
454  {
455  // this function casts pointers through void* to avoid 'cast increases required alignment of target type'
456  // warnings we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via
457  // allocate_string
458 
459  // get header
460  xml_memory_string_header *header = static_cast<xml_memory_string_header *>(static_cast<void *>(string)) - 1;
461 
462  // deallocate
463  size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset;
464  xml_memory_page *page =
465  reinterpret_cast<xml_memory_page *>(static_cast<void *>(reinterpret_cast<char *>(header) - page_offset));
466 
467  // if full_size == 0 then this string occupies the whole page
468  size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size;
469 
470  deallocate_memory(header, full_size, page);
471  }
472 
474  size_t _busy_size;
475 };
476 
478 {
479  const size_t large_allocation_threshold = xml_memory_page_size / 4;
480 
481  xml_memory_page *page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
482  out_page = page;
483 
484  if (!page)
485  return 0;
486 
487  if (size <= large_allocation_threshold)
488  {
490 
491  // insert page at the end of linked list
492  page->prev = _root;
493  _root->next = page;
494  _root = page;
495 
496  _busy_size = size;
497  }
498  else
499  {
500  // insert page before the end of linked list, so that it is deleted as soon as possible
501  // the last page is not deleted even if it's empty (see deallocate_memory)
502  assert(_root->prev);
503 
504  page->prev = _root->prev;
505  page->next = _root;
506 
507  _root->prev->next = page;
508  _root->prev = page;
509  }
510 
511  // allocate inside page
512  page->busy_size = size;
513 
514  return page->data;
515 }
517 
518 namespace pugi
519 {
522 {
524  xml_attribute_struct(impl::xml_memory_page *page)
525  : header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0)
526  {
527  }
528 
530 
533 
536 };
537 
540 {
543  xml_node_struct(impl::xml_memory_page *page, xml_node_type type)
544  : header(reinterpret_cast<uintptr_t>(page) | (type - 1))
545  , parent(0)
546  , name(0)
547  , value(0)
548  , first_child(0)
549  , prev_sibling_c(0)
550  , next_sibling(0)
551  , first_attribute(0)
552  {
553  }
554 
556 
558 
561 
563 
566 
568 };
569 } // namespace pugi
570 
573 {
576 };
577 
579 {
582  {
583  }
584 
585  const char_t *buffer;
586 
588 };
589 
591 {
592  assert(node);
593 
594  return *reinterpret_cast<xml_memory_page *>(node->header & xml_memory_page_pointer_mask)->allocator;
595 }
597 
598 // Low-level DOM operations
600 inline xml_attribute_struct *allocate_attribute(xml_allocator &alloc)
601 {
602  xml_memory_page *page;
603  void *memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page);
604 
605  return new (memory) xml_attribute_struct(page);
606 }
607 
609 {
610  xml_memory_page *page;
611  void *memory = alloc.allocate_memory(sizeof(xml_node_struct), page);
612 
613  return new (memory) xml_node_struct(page, type);
614 }
615 
616 inline void destroy_attribute(xml_attribute_struct *a, xml_allocator &alloc)
617 {
618  uintptr_t header = a->header;
619 
621  alloc.deallocate_string(a->name);
623  alloc.deallocate_string(a->value);
624 
625  alloc.deallocate_memory(a, sizeof(xml_attribute_struct),
626  reinterpret_cast<xml_memory_page *>(header & xml_memory_page_pointer_mask));
627 }
628 
630 {
631  uintptr_t header = n->header;
632 
634  alloc.deallocate_string(n->name);
636  alloc.deallocate_string(n->value);
637 
638  for (xml_attribute_struct *attr = n->first_attribute; attr;)
639  {
640  xml_attribute_struct *next = attr->next_attribute;
641 
642  destroy_attribute(attr, alloc);
643 
644  attr = next;
645  }
646 
647  for (xml_node_struct *child = n->first_child; child;)
648  {
649  xml_node_struct *next = child->next_sibling;
650 
651  destroy_node(child, alloc);
652 
653  child = next;
654  }
655 
656  alloc.deallocate_memory(n, sizeof(xml_node_struct),
657  reinterpret_cast<xml_memory_page *>(header & xml_memory_page_pointer_mask));
658 }
659 
662 {
663  xml_node_struct *child = allocate_node(alloc, type);
664  if (!child)
665  return 0;
666 
667  child->parent = node;
668 
669  xml_node_struct *first_child = node->first_child;
670 
671  if (first_child)
672  {
673  xml_node_struct *last_child = first_child->prev_sibling_c;
674 
675  last_child->next_sibling = child;
676  child->prev_sibling_c = last_child;
677  first_child->prev_sibling_c = child;
678  }
679  else
680  {
681  node->first_child = child;
682  child->prev_sibling_c = child;
683  }
684 
685  return child;
686 }
687 
689 {
690  xml_attribute_struct *a = allocate_attribute(alloc);
691  if (!a)
692  return 0;
693 
694  xml_attribute_struct *first_attribute = node->first_attribute;
695 
696  if (first_attribute)
697  {
698  xml_attribute_struct *last_attribute = first_attribute->prev_attribute_c;
699 
700  last_attribute->next_attribute = a;
701  a->prev_attribute_c = last_attribute;
702  first_attribute->prev_attribute_c = a;
703  }
704  else
705  {
706  node->first_attribute = a;
707  a->prev_attribute_c = a;
708  }
709 
710  return a;
711 }
713 
714 // Helper classes for code generation
716 struct opt_false
717 {
718  enum
719  {
720  value = 0
721  };
722 };
723 
724 struct opt_true
725 {
726  enum
727  {
728  value = 1
729  };
730 };
732 
733 // Unicode utilities
736 {
737  return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
738 }
739 
741 {
742  return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
743 }
744 
746 {
747  typedef size_t value_type;
748 
749  static value_type low(value_type result, uint32_t ch)
750  {
751  // U+0000..U+007F
752  if (ch < 0x80)
753  return result + 1;
754  // U+0080..U+07FF
755  else if (ch < 0x800)
756  return result + 2;
757  // U+0800..U+FFFF
758  else
759  return result + 3;
760  }
761 
763  {
764  // U+10000..U+10FFFF
765  return result + 4;
766  }
767 };
768 
770 {
771  typedef uint8_t *value_type;
772 
773  static value_type low(value_type result, uint32_t ch)
774  {
775  // U+0000..U+007F
776  if (ch < 0x80)
777  {
778  *result = static_cast<uint8_t>(ch);
779  return result + 1;
780  }
781  // U+0080..U+07FF
782  else if (ch < 0x800)
783  {
784  result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));
785  result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
786  return result + 2;
787  }
788  // U+0800..U+FFFF
789  else
790  {
791  result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));
792  result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
793  result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
794  return result + 3;
795  }
796  }
797 
798  static value_type high(value_type result, uint32_t ch)
799  {
800  // U+10000..U+10FFFF
801  result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));
802  result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));
803  result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
804  result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
805  return result + 4;
806  }
807 
808  static value_type any(value_type result, uint32_t ch)
809  {
810  return (ch < 0x10000) ? low(result, ch) : high(result, ch);
811  }
812 };
813 
815 {
816  typedef size_t value_type;
817 
818  static value_type low(value_type result, uint32_t) { return result + 1; }
819 
820  static value_type high(value_type result, uint32_t) { return result + 2; }
821 };
822 
824 {
826 
827  static value_type low(value_type result, uint32_t ch)
828  {
829  *result = static_cast<uint16_t>(ch);
830 
831  return result + 1;
832  }
833 
834  static value_type high(value_type result, uint32_t ch)
835  {
836  uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10;
837  uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff;
838 
839  result[0] = static_cast<uint16_t>(0xD800 + msh);
840  result[1] = static_cast<uint16_t>(0xDC00 + lsh);
841 
842  return result + 2;
843  }
844 
845  static value_type any(value_type result, uint32_t ch)
846  {
847  return (ch < 0x10000) ? low(result, ch) : high(result, ch);
848  }
849 };
850 
852 {
853  typedef size_t value_type;
854 
855  static value_type low(value_type result, uint32_t) { return result + 1; }
856 
857  static value_type high(value_type result, uint32_t) { return result + 1; }
858 };
859 
861 {
863 
864  static value_type low(value_type result, uint32_t ch)
865  {
866  *result = ch;
867 
868  return result + 1;
869  }
870 
871  static value_type high(value_type result, uint32_t ch)
872  {
873  *result = ch;
874 
875  return result + 1;
876  }
877 
878  static value_type any(value_type result, uint32_t ch)
879  {
880  *result = ch;
881 
882  return result + 1;
883  }
884 };
885 
887 {
888  typedef uint8_t *value_type;
889 
890  static value_type low(value_type result, uint32_t ch)
891  {
892  *result = static_cast<uint8_t>(ch > 255 ? '?' : ch);
893 
894  return result + 1;
895  }
896 
897  static value_type high(value_type result, uint32_t ch)
898  {
899  (void)ch;
900 
901  *result = '?';
902 
903  return result + 1;
904  }
905 };
906 
907 template <size_t size>
909 
910 template <>
911 struct wchar_selector<2>
912 {
913  typedef uint16_t type;
916 };
917 
918 template <>
919 struct wchar_selector<4>
920 {
921  typedef uint32_t type;
924 };
925 
926 typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
928 
929 template <typename Traits, typename opt_swap = opt_false>
931 {
932  static inline typename Traits::value_type decode_utf8_block(const uint8_t *data, size_t size,
933  typename Traits::value_type result)
934  {
935  const uint8_t utf8_byte_mask = 0x3f;
936 
937  while (size)
938  {
939  uint8_t lead = *data;
940 
941  // 0xxxxxxx -> U+0000..U+007F
942  if (lead < 0x80)
943  {
944  result = Traits::low(result, lead);
945  data += 1;
946  size -= 1;
947 
948  // process aligned single-byte (ascii) blocks
949  if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
950  {
951  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
952  while (size >= 4 &&
953  (*static_cast<const uint32_t *>(static_cast<const void *>(data)) & 0x80808080) == 0)
954  {
955  result = Traits::low(result, data[0]);
956  result = Traits::low(result, data[1]);
957  result = Traits::low(result, data[2]);
958  result = Traits::low(result, data[3]);
959  data += 4;
960  size -= 4;
961  }
962  }
963  }
964  // 110xxxxx -> U+0080..U+07FF
965  else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
966  {
967  result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
968  data += 2;
969  size -= 2;
970  }
971  // 1110xxxx -> U+0800-U+FFFF
972  else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 &&
973  (data[2] & 0xc0) == 0x80)
974  {
975  result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) |
976  (data[2] & utf8_byte_mask));
977  data += 3;
978  size -= 3;
979  }
980  // 11110xxx -> U+10000..U+10FFFF
981  else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 &&
982  (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
983  {
984  result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) |
985  ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
986  data += 4;
987  size -= 4;
988  }
989  // 10xxxxxx or 11111xxx -> invalid
990  else
991  {
992  data += 1;
993  size -= 1;
994  }
995  }
996 
997  return result;
998  }
999 
1000  static inline typename Traits::value_type decode_utf16_block(const uint16_t *data, size_t size,
1001  typename Traits::value_type result)
1002  {
1003  const uint16_t *end = data + size;
1004 
1005  while (data < end)
1006  {
1007  unsigned int lead = opt_swap::value ? endian_swap(*data) : *data;
1008 
1009  // U+0000..U+D7FF
1010  if (lead < 0xD800)
1011  {
1012  result = Traits::low(result, lead);
1013  data += 1;
1014  }
1015  // U+E000..U+FFFF
1016  else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
1017  {
1018  result = Traits::low(result, lead);
1019  data += 1;
1020  }
1021  // surrogate pair lead
1022  else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && data + 1 < end)
1023  {
1024  uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
1025 
1026  if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
1027  {
1028  result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
1029  data += 2;
1030  }
1031  else
1032  {
1033  data += 1;
1034  }
1035  }
1036  else
1037  {
1038  data += 1;
1039  }
1040  }
1041 
1042  return result;
1043  }
1044 
1045  static inline typename Traits::value_type decode_utf32_block(const uint32_t *data, size_t size,
1046  typename Traits::value_type result)
1047  {
1048  const uint32_t *end = data + size;
1049 
1050  while (data < end)
1051  {
1052  uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
1053 
1054  // U+0000..U+FFFF
1055  if (lead < 0x10000)
1056  {
1057  result = Traits::low(result, lead);
1058  data += 1;
1059  }
1060  // U+10000..U+10FFFF
1061  else
1062  {
1063  result = Traits::high(result, lead);
1064  data += 1;
1065  }
1066  }
1067 
1068  return result;
1069  }
1070 
1071  static inline typename Traits::value_type decode_latin1_block(const uint8_t *data, size_t size,
1072  typename Traits::value_type result)
1073  {
1074  for (size_t i = 0; i < size; ++i)
1075  {
1076  result = Traits::low(result, data[i]);
1077  }
1078 
1079  return result;
1080  }
1081 
1082  static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t *data, size_t size,
1083  typename Traits::value_type result)
1084  {
1085  return decode_utf16_block(data, size, result);
1086  }
1087 
1088  static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t *data, size_t size,
1089  typename Traits::value_type result)
1090  {
1091  return decode_utf32_block(data, size, result);
1092  }
1093 
1094  static inline typename Traits::value_type decode_wchar_block(const wchar_t *data, size_t size,
1095  typename Traits::value_type result)
1096  {
1097  return decode_wchar_block_impl(reinterpret_cast<const wchar_selector<sizeof(wchar_t)>::type *>(data), size,
1098  result);
1099  }
1100 };
1101 
1102 template <typename T>
1103 PUGI__FN void convert_utf_endian_swap(T *result, const T *data, size_t length)
1104 {
1105  for (size_t i = 0; i < length; ++i)
1106  result[i] = endian_swap(data[i]);
1107 }
1108 
1109 #ifdef PUGIXML_WCHAR_MODE
1110 PUGI__FN void convert_wchar_endian_swap(wchar_t *result, const wchar_t *data, size_t length)
1111 {
1112  for (size_t i = 0; i < length; ++i)
1113  result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
1114 }
1115 #endif
1117 
1120 {
1121  ct_parse_pcdata = 1, // \0, &, \r, <
1122  ct_parse_attr = 2, // \0, &, \r, ', "
1123  ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab
1124  ct_space = 8, // \r, \n, space, tab
1125  ct_parse_cdata = 16, // \0, ], >, \r
1126  ct_parse_comment = 32, // \0, -, >, \r
1127  ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .
1128  ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, :
1129 };
1130 
1131 static const unsigned char chartype_table[256] = {
1132  55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15
1133  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
1134  8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47
1135  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63
1136  0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79
1137  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95
1138  0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111
1139  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127
1140 
1141  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+
1142  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1143  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1144  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1145  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1146  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
1147 };
1148 
1150 {
1151  ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
1152  ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, "
1153  ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _
1154  ctx_digit = 8, // 0-9
1155  ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
1156 };
1157 
1158 static const unsigned char chartypex_table[256] = {
1159  3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15
1160  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31
1161  0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47
1162  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63
1163 
1164  0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79
1165  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95
1166  0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111
1167  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127
1168 
1169  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+
1170  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1171  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1172  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1173  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
1174 };
1175 
1176 #ifdef PUGIXML_WCHAR_MODE
1177 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) \
1178  ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
1179 #else
1180 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
1181 #endif
1182 
1183 #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
1184 #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
1185 
1187 {
1188  unsigned int ui = 1;
1189 
1190  return *reinterpret_cast<unsigned char *>(&ui) == 1;
1191 }
1192 
1194 {
1195  PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
1196 
1197  if (sizeof(wchar_t) == 2)
1199  else
1201 }
1202 
1204 {
1205  // look for BOM in first few bytes
1206  if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff)
1207  return encoding_utf32_be;
1208  if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0)
1209  return encoding_utf32_le;
1210  if (d0 == 0xfe && d1 == 0xff)
1211  return encoding_utf16_be;
1212  if (d0 == 0xff && d1 == 0xfe)
1213  return encoding_utf16_le;
1214  if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf)
1215  return encoding_utf8;
1216 
1217  // look for <, <? or <?xm in various encodings
1218  if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c)
1219  return encoding_utf32_be;
1220  if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0)
1221  return encoding_utf32_le;
1222  if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f)
1223  return encoding_utf16_be;
1224  if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0)
1225  return encoding_utf16_le;
1226  if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d)
1227  return encoding_utf8;
1228 
1229  // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so
1230  // early)
1231  if (d0 == 0 && d1 == 0x3c)
1232  return encoding_utf16_be;
1233  if (d0 == 0x3c && d1 == 0)
1234  return encoding_utf16_le;
1235 
1236  // no known BOM detected, assume utf8
1237  return encoding_utf8;
1238 }
1239 
1240 PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void *contents, size_t size)
1241 {
1242  // replace wchar encoding with utf implementation
1243  if (encoding == encoding_wchar)
1244  return get_wchar_encoding();
1245 
1246  // replace utf16 encoding with utf16 with specific endianness
1247  if (encoding == encoding_utf16)
1249 
1250  // replace utf32 encoding with utf32 with specific endianness
1251  if (encoding == encoding_utf32)
1253 
1254  // only do autodetection if no explicit encoding is requested
1255  if (encoding != encoding_auto)
1256  return encoding;
1257 
1258  // skip encoding autodetection if input buffer is too small
1259  if (size < 4)
1260  return encoding_utf8;
1261 
1262  // try to guess encoding (based on XML specification, Appendix F.1)
1263  const uint8_t *data = static_cast<const uint8_t *>(contents);
1264 
1265  PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1266 
1267  return guess_buffer_encoding(d0, d1, d2, d3);
1268 }
1269 
1270 PUGI__FN bool get_mutable_buffer(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size,
1271  bool is_mutable)
1272 {
1273  size_t length = size / sizeof(char_t);
1274 
1275  if (is_mutable)
1276  {
1277  out_buffer = static_cast<char_t *>(const_cast<void *>(contents));
1278  out_length = length;
1279  }
1280  else
1281  {
1282  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1283  if (!buffer)
1284  return false;
1285 
1286  memcpy(buffer, contents, length * sizeof(char_t));
1287  buffer[length] = 0;
1288 
1289  out_buffer = buffer;
1290  out_length = length + 1;
1291  }
1292 
1293  return true;
1294 }
1295 
1296 #ifdef PUGIXML_WCHAR_MODE
1297 PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
1298 {
1299  return (le == encoding_utf16_be && re == encoding_utf16_le) ||
1300  (le == encoding_utf16_le && re == encoding_utf16_be) ||
1301  (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
1302 }
1303 
1304 PUGI__FN bool convert_buffer_endian_swap(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size,
1305  bool is_mutable)
1306 {
1307  const char_t *data = static_cast<const char_t *>(contents);
1308  size_t length = size / sizeof(char_t);
1309 
1310  if (is_mutable)
1311  {
1312  char_t *buffer = const_cast<char_t *>(data);
1313 
1314  convert_wchar_endian_swap(buffer, data, length);
1315 
1316  out_buffer = buffer;
1317  out_length = length;
1318  }
1319  else
1320  {
1321  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1322  if (!buffer)
1323  return false;
1324 
1325  convert_wchar_endian_swap(buffer, data, length);
1326  buffer[length] = 0;
1327 
1328  out_buffer = buffer;
1329  out_length = length + 1;
1330  }
1331 
1332  return true;
1333 }
1334 
1335 PUGI__FN bool convert_buffer_utf8(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size)
1336 {
1337  const uint8_t *data = static_cast<const uint8_t *>(contents);
1338  size_t data_length = size;
1339 
1340  // first pass: get length in wchar_t units
1341  size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, data_length, 0);
1342 
1343  // allocate buffer of suitable length
1344  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1345  if (!buffer)
1346  return false;
1347 
1348  // second pass: convert utf8 input to wchar_t
1349  wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
1350  wchar_writer::value_type oend = utf_decoder<wchar_writer>::decode_utf8_block(data, data_length, obegin);
1351 
1352  assert(oend == obegin + length);
1353  *oend = 0;
1354 
1355  out_buffer = buffer;
1356  out_length = length + 1;
1357 
1358  return true;
1359 }
1360 
1361 template <typename opt_swap>
1362 PUGI__FN bool convert_buffer_utf16(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
1363 {
1364  const uint16_t *data = static_cast<const uint16_t *>(contents);
1365  size_t data_length = size / sizeof(uint16_t);
1366 
1367  // first pass: get length in wchar_t units
1369 
1370  // allocate buffer of suitable length
1371  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1372  if (!buffer)
1373  return false;
1374 
1375  // second pass: convert utf16 input to wchar_t
1376  wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
1377  wchar_writer::value_type oend = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, data_length, obegin);
1378 
1379  assert(oend == obegin + length);
1380  *oend = 0;
1381 
1382  out_buffer = buffer;
1383  out_length = length + 1;
1384 
1385  return true;
1386 }
1387 
1388 template <typename opt_swap>
1389 PUGI__FN bool convert_buffer_utf32(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
1390 {
1391  const uint32_t *data = static_cast<const uint32_t *>(contents);
1392  size_t data_length = size / sizeof(uint32_t);
1393 
1394  // first pass: get length in wchar_t units
1396 
1397  // allocate buffer of suitable length
1398  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1399  if (!buffer)
1400  return false;
1401 
1402  // second pass: convert utf32 input to wchar_t
1403  wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
1404  wchar_writer::value_type oend = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, data_length, obegin);
1405 
1406  assert(oend == obegin + length);
1407  *oend = 0;
1408 
1409  out_buffer = buffer;
1410  out_length = length + 1;
1411 
1412  return true;
1413 }
1414 
1415 PUGI__FN bool convert_buffer_latin1(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size)
1416 {
1417  const uint8_t *data = static_cast<const uint8_t *>(contents);
1418  size_t data_length = size;
1419 
1420  // get length in wchar_t units
1421  size_t length = data_length;
1422 
1423  // allocate buffer of suitable length
1424  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1425  if (!buffer)
1426  return false;
1427 
1428  // convert latin1 input to wchar_t
1429  wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
1430  wchar_writer::value_type oend = utf_decoder<wchar_writer>::decode_latin1_block(data, data_length, obegin);
1431 
1432  assert(oend == obegin + length);
1433  *oend = 0;
1434 
1435  out_buffer = buffer;
1436  out_length = length + 1;
1437 
1438  return true;
1439 }
1440 
1441 PUGI__FN bool convert_buffer(char_t *&out_buffer, size_t &out_length, xml_encoding encoding, const void *contents,
1442  size_t size, bool is_mutable)
1443 {
1444  // get native encoding
1445  xml_encoding wchar_encoding = get_wchar_encoding();
1446 
1447  // fast path: no conversion required
1448  if (encoding == wchar_encoding)
1449  return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1450 
1451  // only endian-swapping is required
1452  if (need_endian_swap_utf(encoding, wchar_encoding))
1453  return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
1454 
1455  // source encoding is utf8
1456  if (encoding == encoding_utf8)
1457  return convert_buffer_utf8(out_buffer, out_length, contents, size);
1458 
1459  // source encoding is utf16
1460  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
1461  {
1463 
1464  return (native_encoding == encoding) ? convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false())
1465  : convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1466  }
1467 
1468  // source encoding is utf32
1469  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
1470  {
1472 
1473  return (native_encoding == encoding) ? convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false())
1474  : convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1475  }
1476 
1477  // source encoding is latin1
1478  if (encoding == encoding_latin1)
1479  return convert_buffer_latin1(out_buffer, out_length, contents, size);
1480 
1481  assert(!"Invalid encoding");
1482  return false;
1483 }
1484 #else
1485 template <typename opt_swap>
1486 PUGI__FN bool convert_buffer_utf16(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
1487 {
1488  const uint16_t *data = static_cast<const uint16_t *>(contents);
1489  size_t data_length = size / sizeof(uint16_t);
1490 
1491  // first pass: get length in utf8 units
1492  size_t length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, data_length, 0);
1493 
1494  // allocate buffer of suitable length
1495  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1496  if (!buffer)
1497  return false;
1498 
1499  // second pass: convert utf16 input to utf8
1500  uint8_t *obegin = reinterpret_cast<uint8_t *>(buffer);
1501  uint8_t *oend = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, data_length, obegin);
1502 
1503  assert(oend == obegin + length);
1504  *oend = 0;
1505 
1506  out_buffer = buffer;
1507  out_length = length + 1;
1508 
1509  return true;
1510 }
1511 
1512 template <typename opt_swap>
1513 PUGI__FN bool convert_buffer_utf32(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
1514 {
1515  const uint32_t *data = static_cast<const uint32_t *>(contents);
1516  size_t data_length = size / sizeof(uint32_t);
1517 
1518  // first pass: get length in utf8 units
1519  size_t length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, data_length, 0);
1520 
1521  // allocate buffer of suitable length
1522  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1523  if (!buffer)
1524  return false;
1525 
1526  // second pass: convert utf32 input to utf8
1527  uint8_t *obegin = reinterpret_cast<uint8_t *>(buffer);
1528  uint8_t *oend = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, data_length, obegin);
1529 
1530  assert(oend == obegin + length);
1531  *oend = 0;
1532 
1533  out_buffer = buffer;
1534  out_length = length + 1;
1535 
1536  return true;
1537 }
1538 
1539 PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t *data, size_t size)
1540 {
1541  for (size_t i = 0; i < size; ++i)
1542  if (data[i] > 127)
1543  return i;
1544 
1545  return size;
1546 }
1547 
1548 PUGI__FN bool convert_buffer_latin1(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size,
1549  bool is_mutable)
1550 {
1551  const uint8_t *data = static_cast<const uint8_t *>(contents);
1552  size_t data_length = size;
1553 
1554  // get size of prefix that does not need utf8 conversion
1555  size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
1556  assert(prefix_length <= data_length);
1557 
1558  const uint8_t *postfix = data + prefix_length;
1559  size_t postfix_length = data_length - prefix_length;
1560 
1561  // if no conversion is needed, just return the original buffer
1562  if (postfix_length == 0)
1563  return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1564 
1565  // first pass: get length in utf8 units
1566  size_t length = prefix_length + utf_decoder<utf8_counter>::decode_latin1_block(postfix, postfix_length, 0);
1567 
1568  // allocate buffer of suitable length
1569  char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1570  if (!buffer)
1571  return false;
1572 
1573  // second pass: convert latin1 input to utf8
1574  memcpy(buffer, data, prefix_length);
1575 
1576  uint8_t *obegin = reinterpret_cast<uint8_t *>(buffer);
1577  uint8_t *oend = utf_decoder<utf8_writer>::decode_latin1_block(postfix, postfix_length, obegin + prefix_length);
1578 
1579  assert(oend == obegin + length);
1580  *oend = 0;
1581 
1582  out_buffer = buffer;
1583  out_length = length + 1;
1584 
1585  return true;
1586 }
1587 
1588 PUGI__FN bool convert_buffer(char_t *&out_buffer, size_t &out_length, xml_encoding encoding, const void *contents,
1589  size_t size, bool is_mutable)
1590 {
1591  // fast path: no conversion required
1592  if (encoding == encoding_utf8)
1593  return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1594 
1595  // source encoding is utf16
1596  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
1597  {
1599 
1600  return (native_encoding == encoding) ? convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false())
1601  : convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1602  }
1603 
1604  // source encoding is utf32
1605  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
1606  {
1608 
1609  return (native_encoding == encoding) ? convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false())
1610  : convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1611  }
1612 
1613  // source encoding is latin1
1614  if (encoding == encoding_latin1)
1615  return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
1616 
1617  assert(!"Invalid encoding");
1618  return false;
1619 }
1620 #endif
1621 
1622 PUGI__FN size_t as_utf8_begin(const wchar_t *str, size_t length)
1623 {
1624  // get length in utf8 characters
1626 }
1627 
1628 PUGI__FN void as_utf8_end(char *buffer, size_t size, const wchar_t *str, size_t length)
1629 {
1630  // convert to utf8
1631  uint8_t *begin = reinterpret_cast<uint8_t *>(buffer);
1633 
1634  assert(begin + size == end);
1635  (void)!end;
1636 
1637  // zero-terminate
1638  buffer[size] = 0;
1639 }
1640 
1641 #ifndef PUGIXML_NO_STL
1642 PUGI__FN std::string as_utf8_impl(const wchar_t *str, size_t length)
1643 {
1644  // first pass: get length in utf8 characters
1645  size_t size = as_utf8_begin(str, length);
1646 
1647  // allocate resulting string
1648  std::string result;
1649  result.resize(size);
1650 
1651  // second pass: convert to utf8
1652  if (size > 0)
1653  as_utf8_end(&result[0], size, str, length);
1654 
1655  return result;
1656 }
1657 
1658 PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char *str, size_t size)
1659 {
1660  const uint8_t *data = reinterpret_cast<const uint8_t *>(str);
1661 
1662  // first pass: get length in wchar_t units
1663  size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
1664 
1665  // allocate resulting string
1666  std::basic_string<wchar_t> result;
1667  result.resize(length);
1668 
1669  // second pass: convert to wchar_t
1670  if (length > 0)
1671  {
1672  wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
1673  wchar_writer::value_type end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, begin);
1674 
1675  assert(begin + length == end);
1676  (void)!end;
1677  }
1678 
1679  return result;
1680 }
1681 #endif
1682 
1683 inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t *target)
1684 {
1685  assert(target);
1686  size_t target_length = strlength(target);
1687 
1688  // always reuse document buffer memory if possible
1689  if (!allocated)
1690  return target_length >= length;
1691 
1692  // reuse heap memory if waste is not too great
1693  const size_t reuse_threshold = 32;
1694 
1695  return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
1696 }
1697 
1698 PUGI__FN bool strcpy_insitu(char_t *&dest, uintptr_t &header, uintptr_t header_mask, const char_t *source)
1699 {
1700  assert(header);
1701 
1702  size_t source_length = strlength(source);
1703 
1704  if (source_length == 0)
1705  {
1706  // empty string and null pointer are equivalent, so just deallocate old memory
1707  xml_allocator *alloc = reinterpret_cast<xml_memory_page *>(header & xml_memory_page_pointer_mask)->allocator;
1708 
1709  if (header & header_mask)
1710  alloc->deallocate_string(dest);
1711 
1712  // mark the string as not allocated
1713  dest = 0;
1714  header &= ~header_mask;
1715 
1716  return true;
1717  }
1718  else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest))
1719  {
1720  // we can reuse old buffer, so just copy the new data (including zero terminator)
1721  memcpy(dest, source, (source_length + 1) * sizeof(char_t));
1722 
1723  return true;
1724  }
1725  else
1726  {
1727  xml_allocator *alloc = reinterpret_cast<xml_memory_page *>(header & xml_memory_page_pointer_mask)->allocator;
1728 
1729  // allocate new buffer
1730  char_t *buf = alloc->allocate_string(source_length + 1);
1731  if (!buf)
1732  return false;
1733 
1734  // copy the string (including zero terminator)
1735  memcpy(buf, source, (source_length + 1) * sizeof(char_t));
1736 
1737  // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
1738  if (header & header_mask)
1739  alloc->deallocate_string(dest);
1740 
1741  // the string is now allocated, so set the flag
1742  dest = buf;
1743  header |= header_mask;
1744 
1745  return true;
1746  }
1747 }
1748 
1749 struct gap
1750 {
1752  size_t size;
1753 
1754  gap() : end(0), size(0) {}
1755 
1756  // Push new gap, move s count bytes further (skipping the gap).
1757  // Collapse previous gap.
1758  void push(char_t *&s, size_t count)
1759  {
1760  if (end) // there was a gap already; collapse it
1761  {
1762  // Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
1763  assert(s >= end);
1764  memmove(end - size, end, reinterpret_cast<char *>(s) - reinterpret_cast<char *>(end));
1765  }
1766 
1767  s += count; // end of current gap
1768 
1769  // "merge" two gaps
1770  end = s;
1771  size += count;
1772  }
1773 
1774  // Collapse all gaps, return past-the-end pointer
1776  {
1777  if (end)
1778  {
1779  // Move [old_gap_end, current_pos) to [old_gap_start, ...)
1780  assert(s >= end);
1781  memmove(end - size, end, reinterpret_cast<char *>(s) - reinterpret_cast<char *>(end));
1782 
1783  return s - size;
1784  }
1785  else
1786  return s;
1787  }
1788 };
1789 
1791 {
1792  char_t *stre = s + 1;
1793 
1794  switch (*stre)
1795  {
1796  case '#': // &#...
1797  {
1798  unsigned int ucsc = 0;
1799 
1800  if (stre[1] == 'x') // &#x... (hex code)
1801  {
1802  stre += 2;
1803 
1804  char_t ch = *stre;
1805 
1806  if (ch == ';')
1807  return stre;
1808 
1809  for (;;)
1810  {
1811  if (static_cast<unsigned int>(ch - '0') <= 9)
1812  ucsc = 16 * ucsc + (ch - '0');
1813  else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)
1814  ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);
1815  else if (ch == ';')
1816  break;
1817  else // cancel
1818  return stre;
1819 
1820  ch = *++stre;
1821  }
1822 
1823  ++stre;
1824  }
1825  else // &#... (dec code)
1826  {
1827  char_t ch = *++stre;
1828 
1829  if (ch == ';')
1830  return stre;
1831 
1832  for (;;)
1833  {
1834  if (static_cast<unsigned int>(static_cast<unsigned int>(ch) - '0') <= 9)
1835  ucsc = 10 * ucsc + (ch - '0');
1836  else if (ch == ';')
1837  break;
1838  else // cancel
1839  return stre;
1840 
1841  ch = *++stre;
1842  }
1843 
1844  ++stre;
1845  }
1846 
1847 #ifdef PUGIXML_WCHAR_MODE
1848  s = reinterpret_cast<char_t *>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
1849 #else
1850  s = reinterpret_cast<char_t *>(utf8_writer::any(reinterpret_cast<uint8_t *>(s), ucsc));
1851 #endif
1852 
1853  g.push(s, stre - s);
1854  return stre;
1855  }
1856 
1857  case 'a': // &a
1858  {
1859  ++stre;
1860 
1861  if (*stre == 'm') // &am
1862  {
1863  if (*++stre == 'p' && *++stre == ';') // &amp;
1864  {
1865  *s++ = '&';
1866  ++stre;
1867 
1868  g.push(s, stre - s);
1869  return stre;
1870  }
1871  }
1872  else if (*stre == 'p') // &ap
1873  {
1874  if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // &apos;
1875  {
1876  *s++ = '\'';
1877  ++stre;
1878 
1879  g.push(s, stre - s);
1880  return stre;
1881  }
1882  }
1883  break;
1884  }
1885 
1886  case 'g': // &g
1887  {
1888  if (*++stre == 't' && *++stre == ';') // &gt;
1889  {
1890  *s++ = '>';
1891  ++stre;
1892 
1893  g.push(s, stre - s);
1894  return stre;
1895  }
1896  break;
1897  }
1898 
1899  case 'l': // &l
1900  {
1901  if (*++stre == 't' && *++stre == ';') // &lt;
1902  {
1903  *s++ = '<';
1904  ++stre;
1905 
1906  g.push(s, stre - s);
1907  return stre;
1908  }
1909  break;
1910  }
1911 
1912  case 'q': // &q
1913  {
1914  if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // &quot;
1915  {
1916  *s++ = '"';
1917  ++stre;
1918 
1919  g.push(s, stre - s);
1920  return stre;
1921  }
1922  break;
1923  }
1924 
1925  default:
1926  break;
1927  }
1928 
1929  return stre;
1930 }
1931 
1932 // Utility macro for last character handling
1933 #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
1934 
1936 {
1937  gap g;
1938 
1939  while (true)
1940  {
1942  ++s;
1943 
1944  if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
1945  {
1946  *s++ = '\n'; // replace first one with 0x0a
1947 
1948  if (*s == '\n')
1949  g.push(s, 1);
1950  }
1951  else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here
1952  {
1953  *g.flush(s) = 0;
1954 
1955  return s + (s[2] == '>' ? 3 : 2);
1956  }
1957  else if (*s == 0)
1958  {
1959  return 0;
1960  }
1961  else
1962  ++s;
1963  }
1964 }
1965 
1967 {
1968  gap g;
1969 
1970  while (true)
1971  {
1972  while (!PUGI__IS_CHARTYPE(*s, ct_parse_cdata))
1973  ++s;
1974 
1975  if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
1976  {
1977  *s++ = '\n'; // replace first one with 0x0a
1978 
1979  if (*s == '\n')
1980  g.push(s, 1);
1981  }
1982  else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here
1983  {
1984  *g.flush(s) = 0;
1985 
1986  return s + 1;
1987  }
1988  else if (*s == 0)
1989  {
1990  return 0;
1991  }
1992  else
1993  ++s;
1994  }
1995 }
1996 
1997 typedef char_t *(*strconv_pcdata_t)(char_t *);
1998 
1999 template <typename opt_trim, typename opt_eol, typename opt_escape>
2001 {
2002  static char_t *parse(char_t *s)
2003  {
2004  gap g;
2005 
2006  char_t *begin = s;
2007 
2008  while (true)
2009  {
2010  while (!PUGI__IS_CHARTYPE(*s, ct_parse_pcdata))
2011  ++s;
2012 
2013  if (*s == '<') // PCDATA ends here
2014  {
2015  char_t *end = g.flush(s);
2016 
2017  if (opt_trim::value)
2018  while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2019  --end;
2020 
2021  *end = 0;
2022 
2023  return s + 1;
2024  }
2025  else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
2026  {
2027  *s++ = '\n'; // replace first one with 0x0a
2028 
2029  if (*s == '\n')
2030  g.push(s, 1);
2031  }
2032  else if (opt_escape::value && *s == '&')
2033  {
2034  s = strconv_escape(s, g);
2035  }
2036  else if (*s == 0)
2037  {
2038  char_t *end = g.flush(s);
2039 
2040  if (opt_trim::value)
2041  while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2042  --end;
2043 
2044  *end = 0;
2045 
2046  return s;
2047  }
2048  else
2049  ++s;
2050  }
2051  }
2052 };
2053 
2055 {
2056  PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
2057 
2058  switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (eol escapes trim)
2059  {
2060  case 0:
2062  case 1:
2064  case 2:
2066  case 3:
2068  case 4:
2070  case 5:
2072  case 6:
2074  case 7:
2076  default:
2077  assert(false);
2078  return 0; // should not get here
2079  }
2080 }
2081 
2082 typedef char_t *(*strconv_attribute_t)(char_t *, char_t);
2083 
2084 template <typename opt_escape>
2086 {
2087  static char_t *parse_wnorm(char_t *s, char_t end_quote)
2088  {
2089  gap g;
2090 
2091  // trim leading whitespaces
2092  if (PUGI__IS_CHARTYPE(*s, ct_space))
2093  {
2094  char_t *str = s;
2095 
2096  do
2097  ++str;
2098  while (PUGI__IS_CHARTYPE(*str, ct_space));
2099 
2100  g.push(s, str - s);
2101  }
2102 
2103  while (true)
2104  {
2106  ++s;
2107 
2108  if (*s == end_quote)
2109  {
2110  char_t *str = g.flush(s);
2111 
2112  do
2113  *str-- = 0;
2114  while (PUGI__IS_CHARTYPE(*str, ct_space));
2115 
2116  return s + 1;
2117  }
2118  else if (PUGI__IS_CHARTYPE(*s, ct_space))
2119  {
2120  *s++ = ' ';
2121 
2122  if (PUGI__IS_CHARTYPE(*s, ct_space))
2123  {
2124  char_t *str = s + 1;
2125  while (PUGI__IS_CHARTYPE(*str, ct_space))
2126  ++str;
2127 
2128  g.push(s, str - s);
2129  }
2130  }
2131  else if (opt_escape::value && *s == '&')
2132  {
2133  s = strconv_escape(s, g);
2134  }
2135  else if (!*s)
2136  {
2137  return 0;
2138  }
2139  else
2140  ++s;
2141  }
2142  }
2143 
2144  static char_t *parse_wconv(char_t *s, char_t end_quote)
2145  {
2146  gap g;
2147 
2148  while (true)
2149  {
2151  ++s;
2152 
2153  if (*s == end_quote)
2154  {
2155  *g.flush(s) = 0;
2156 
2157  return s + 1;
2158  }
2159  else if (PUGI__IS_CHARTYPE(*s, ct_space))
2160  {
2161  if (*s == '\r')
2162  {
2163  *s++ = ' ';
2164 
2165  if (*s == '\n')
2166  g.push(s, 1);
2167  }
2168  else
2169  *s++ = ' ';
2170  }
2171  else if (opt_escape::value && *s == '&')
2172  {
2173  s = strconv_escape(s, g);
2174  }
2175  else if (!*s)
2176  {
2177  return 0;
2178  }
2179  else
2180  ++s;
2181  }
2182  }
2183 
2184  static char_t *parse_eol(char_t *s, char_t end_quote)
2185  {
2186  gap g;
2187 
2188  while (true)
2189  {
2190  while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr))
2191  ++s;
2192 
2193  if (*s == end_quote)
2194  {
2195  *g.flush(s) = 0;
2196 
2197  return s + 1;
2198  }
2199  else if (*s == '\r')
2200  {
2201  *s++ = '\n';
2202 
2203  if (*s == '\n')
2204  g.push(s, 1);
2205  }
2206  else if (opt_escape::value && *s == '&')
2207  {
2208  s = strconv_escape(s, g);
2209  }
2210  else if (!*s)
2211  {
2212  return 0;
2213  }
2214  else
2215  ++s;
2216  }
2217  }
2218 
2219  static char_t *parse_simple(char_t *s, char_t end_quote)
2220  {
2221  gap g;
2222 
2223  while (true)
2224  {
2225  while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr))
2226  ++s;
2227 
2228  if (*s == end_quote)
2229  {
2230  *g.flush(s) = 0;
2231 
2232  return s + 1;
2233  }
2234  else if (opt_escape::value && *s == '&')
2235  {
2236  s = strconv_escape(s, g);
2237  }
2238  else if (!*s)
2239  {
2240  return 0;
2241  }
2242  else
2243  ++s;
2244  }
2245  }
2246 };
2247 
2249 {
2250  PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 &&
2251  parse_wnorm_attribute == 0x80);
2252 
2253  switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes)
2254  {
2255  case 0:
2257  case 1:
2259  case 2:
2261  case 3:
2263  case 4:
2265  case 5:
2267  case 6:
2269  case 7:
2271  case 8:
2273  case 9:
2275  case 10:
2277  case 11:
2279  case 12:
2281  case 13:
2283  case 14:
2285  case 15:
2287  default:
2288  assert(false);
2289  return 0; // should not get here
2290  }
2291 }
2292 
2293 inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
2294 {
2295  xml_parse_result result;
2296  result.status = status;
2297  result.offset = offset;
2298 
2299  return result;
2300 }
2301 
2303 {
2307 
2308 // Parser utilities.
2309 #define PUGI__SKIPWS() \
2310  { \
2311  while (PUGI__IS_CHARTYPE(*s, ct_space)) \
2312  ++s; \
2313  }
2314 #define PUGI__OPTSET(OPT) (optmsk & (OPT))
2315 #define PUGI__PUSHNODE(TYPE) \
2316  { \
2317  cursor = append_node(cursor, alloc, TYPE); \
2318  if (!cursor) \
2319  PUGI__THROW_ERROR(status_out_of_memory, s); \
2320  }
2321 #define PUGI__POPNODE() \
2322  { \
2323  cursor = cursor->parent; \
2324  }
2325 #define PUGI__SCANFOR(X) \
2326  { \
2327  while (*s != 0 && !(X)) \
2328  ++s; \
2329  }
2330 #define PUGI__SCANWHILE(X) \
2331  { \
2332  while ((X)) \
2333  ++s; \
2334  }
2335 #define PUGI__ENDSEG() \
2336  { \
2337  ch = *s; \
2338  *s = 0; \
2339  ++s; \
2340  }
2341 #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t *>(0)
2342 #define PUGI__CHECK_ERROR(err, m) \
2343  { \
2344  if (*s == 0) \
2345  PUGI__THROW_ERROR(err, m); \
2346  }
2347 
2349 
2350  // DOCTYPE consists of nested sections of the following possible types:
2351  // <!-- ... -->, <? ... ?>, "...", '...'
2352  // <![...]]>
2353  // <!...>
2354  // First group can not contain nested groups
2355  // Second group can contain nested groups of the same type
2356  // Third group can contain all other groups
2358  {
2359  if (*s == '"' || *s == '\'')
2360  {
2361  // quoted string
2362  char_t ch = *s++;
2363  PUGI__SCANFOR(*s == ch);
2364  if (!*s)
2366 
2367  s++;
2368  }
2369  else if (s[0] == '<' && s[1] == '?')
2370  {
2371  // <? ... ?>
2372  s += 2;
2373  PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
2374  if (!*s)
2376 
2377  s += 2;
2378  }
2379  else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')
2380  {
2381  s += 4;
2382  PUGI__SCANFOR(s[0] == '-' && s[1] == '-' &&
2383  s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
2384  if (!*s)
2386 
2387  s += 4;
2388  }
2389  else
2391 
2392  return s;
2393  }
2394 
2396  {
2397  assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
2398  s++;
2399 
2400  while (*s)
2401  {
2402  if (s[0] == '<' && s[1] == '!' && s[2] == '[')
2403  {
2404  // nested ignore section
2406  if (!s)
2407  return s;
2408  }
2409  else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
2410  {
2411  // ignore section end
2412  s += 3;
2413 
2414  return s;
2415  }
2416  else
2417  s++;
2418  }
2419 
2421  }
2422 
2423  char_t *parse_doctype_group(char_t *s, char_t endch, bool toplevel)
2424  {
2425  assert((s[0] == '<' || s[0] == 0) && s[1] == '!');
2426  s++;
2427 
2428  while (*s)
2429  {
2430  if (s[0] == '<' && s[1] == '!' && s[2] != '-')
2431  {
2432  if (s[2] == '[')
2433  {
2434  // ignore
2436  if (!s)
2437  return s;
2438  }
2439  else
2440  {
2441  // some control group
2442  s = parse_doctype_group(s, endch, false);
2443  if (!s)
2444  return s;
2445 
2446  // skip >
2447  assert(*s == '>');
2448  s++;
2449  }
2450  }
2451  else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
2452  {
2453  // unknown tag (forbidden), or some primitive group
2455  if (!s)
2456  return s;
2457  }
2458  else if (*s == '>')
2459  {
2460  return s;
2461  }
2462  else
2463  s++;
2464  }
2465 
2466  if (!toplevel || endch != '>')
2468 
2469  return s;
2470  }
2471 
2472  char_t *parse_exclamation(char_t *s, xml_node_struct *cursor, unsigned int optmsk, char_t endch)
2473  {
2474  // parse node contents, starting with exclamation mark
2475  ++s;
2476 
2477  if (*s == '-') // '<!-...'
2478  {
2479  ++s;
2480 
2481  if (*s == '-') // '<!--...'
2482  {
2483  ++s;
2484 
2486  {
2487  PUGI__PUSHNODE(node_comment); // Append a new node on the tree.
2488  cursor->value = s; // Save the offset.
2489  }
2490 
2492  {
2493  s = strconv_comment(s, endch);
2494 
2495  if (!s)
2496  PUGI__THROW_ERROR(status_bad_comment, cursor->value);
2497  }
2498  else
2499  {
2500  // Scan for terminating '-->'.
2501  PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>'));
2503 
2505  *s = 0; // Zero-terminate this segment at the first terminating '-'.
2506 
2507  s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
2508  }
2509  }
2510  else
2512  }
2513  else if (*s == '[')
2514  {
2515  // '<![CDATA[...'
2516  if (*++s == 'C' && *++s == 'D' && *++s == 'A' && *++s == 'T' && *++s == 'A' && *++s == '[')
2517  {
2518  ++s;
2519 
2521  {
2522  PUGI__PUSHNODE(node_cdata); // Append a new node on the tree.
2523  cursor->value = s; // Save the offset.
2524 
2525  if (PUGI__OPTSET(parse_eol))
2526  {
2527  s = strconv_cdata(s, endch);
2528 
2529  if (!s)
2530  PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
2531  }
2532  else
2533  {
2534  // Scan for terminating ']]>'.
2535  PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
2537 
2538  *s++ = 0; // Zero-terminate this segment.
2539  }
2540  }
2541  else // Flagged for discard, but we still have to scan for the terminator.
2542  {
2543  // Scan for terminating ']]>'.
2544  PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
2546 
2547  ++s;
2548  }
2549 
2550  s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
2551  }
2552  else
2554  }
2555  else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' &&
2556  ENDSWITH(s[6], 'E'))
2557  {
2558  s -= 2;
2559 
2560  if (cursor->parent)
2562 
2563  char_t *mark = s + 9;
2564 
2565  s = parse_doctype_group(s, endch, true);
2566  if (!s)
2567  return s;
2568 
2569  assert((*s == 0 && endch == '>') || *s == '>');
2570  if (*s)
2571  *s++ = 0;
2572 
2574  {
2575  while (PUGI__IS_CHARTYPE(*mark, ct_space))
2576  ++mark;
2577 
2579 
2580  cursor->value = mark;
2581 
2582  PUGI__POPNODE();
2583  }
2584  }
2585  else if (*s == 0 && endch == '-')
2587  else if (*s == 0 && endch == '[')
2589  else
2591 
2592  return s;
2593  }
2594 
2595  char_t *parse_question(char_t *s, xml_node_struct *&ref_cursor, unsigned int optmsk, char_t endch)
2596  {
2597  // load into registers
2598  xml_node_struct *cursor = ref_cursor;
2599  char_t ch = 0;
2600 
2601  // parse node contents, starting with question mark
2602  ++s;
2603 
2604  // read PI target
2605  char_t *target = s;
2606 
2609 
2612 
2613  // determine node type; stricmp / strcasecmp is not portable
2614  bool declaration =
2615  (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
2616 
2617  if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
2618  {
2619  if (declaration)
2620  {
2621  // disallow non top-level declarations
2622  if (cursor->parent)
2624 
2626  }
2627  else
2628  {
2630  }
2631 
2632  cursor->name = target;
2633 
2634  PUGI__ENDSEG();
2635 
2636  // parse value/attributes
2637  if (ch == '?')
2638  {
2639  // empty node
2640  if (!ENDSWITH(*s, '>'))
2642  s += (*s == '>');
2643 
2644  PUGI__POPNODE();
2645  }
2646  else if (PUGI__IS_CHARTYPE(ch, ct_space))
2647  {
2648  PUGI__SKIPWS();
2649 
2650  // scan for tag end
2651  char_t *value = s;
2652 
2653  PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
2655 
2656  if (declaration)
2657  {
2658  // replace ending ? with / so that 'element' terminates properly
2659  *s = '/';
2660 
2661  // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to
2662  // LOC_ATTRIBUTES
2663  s = value;
2664  }
2665  else
2666  {
2667  // store value and step over >
2668  cursor->value = value;
2669  PUGI__POPNODE();
2670 
2671  PUGI__ENDSEG();
2672 
2673  s += (*s == '>');
2674  }
2675  }
2676  else
2678  }
2679  else
2680  {
2681  // scan for tag end
2682  PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
2684 
2685  s += (s[1] == '>' ? 2 : 1);
2686  }
2687 
2688  // store from registers
2689  ref_cursor = cursor;
2690 
2691  return s;
2692  }
2693 
2694  char_t *parse_tree(char_t *s, xml_node_struct *root, unsigned int optmsk, char_t endch)
2695  {
2696  strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
2697  strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
2698 
2699  char_t ch = 0;
2700  xml_node_struct *cursor = root;
2701  char_t *mark = s;
2702 
2703  while (*s != 0)
2704  {
2705  if (*s == '<')
2706  {
2707  ++s;
2708 
2709  LOC_TAG:
2710  if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
2711  {
2712  PUGI__PUSHNODE(node_element); // Append a new node to the tree.
2713 
2714  cursor->name = s;
2715 
2716  PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
2717  PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
2718 
2719  if (ch == '>')
2720  {
2721  // end of tag
2722  }
2723  else if (PUGI__IS_CHARTYPE(ch, ct_space))
2724  {
2725  LOC_ATTRIBUTES:
2726  while (true)
2727  {
2728  PUGI__SKIPWS(); // Eat any whitespace.
2729 
2730  if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
2731  {
2732  xml_attribute_struct *a =
2733  append_attribute_ll(cursor, alloc); // Make space for this attribute.
2734  if (!a)
2736 
2737  a->name = s; // Save the offset.
2738 
2739  PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
2740  PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2741 
2742  PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
2743  PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2744 
2745  if (PUGI__IS_CHARTYPE(ch, ct_space))
2746  {
2747  PUGI__SKIPWS(); // Eat any whitespace.
2748  PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2749 
2750  ch = *s;
2751  ++s;
2752  }
2753 
2754  if (ch == '=') // '<... #=...'
2755  {
2756  PUGI__SKIPWS(); // Eat any whitespace.
2757 
2758  if (*s == '"' || *s == '\'') // '<... #="...'
2759  {
2760  ch = *s; // Save quote char to avoid breaking on "''" -or- '""'.
2761  ++s; // Step over the quote.
2762  a->value = s; // Save the offset.
2763 
2764  s = strconv_attribute(s, ch);
2765 
2766  if (!s)
2768 
2769  // After this line the loop continues from the start;
2770  // Whitespaces, / and > are ok, symbols and EOF are wrong,
2771  // everything else will be detected
2774  }
2775  else
2777  }
2778  else
2780  }
2781  else if (*s == '/')
2782  {
2783  ++s;
2784 
2785  if (*s == '>')
2786  {
2787  PUGI__POPNODE();
2788  s++;
2789  break;
2790  }
2791  else if (*s == 0 && endch == '>')
2792  {
2793  PUGI__POPNODE();
2794  break;
2795  }
2796  else
2798  }
2799  else if (*s == '>')
2800  {
2801  ++s;
2802 
2803  break;
2804  }
2805  else if (*s == 0 && endch == '>')
2806  {
2807  break;
2808  }
2809  else
2811  }
2812 
2813  // !!!
2814  }
2815  else if (ch == '/') // '<#.../'
2816  {
2817  if (!ENDSWITH(*s, '>'))
2819 
2820  PUGI__POPNODE(); // Pop.
2821 
2822  s += (*s == '>');
2823  }
2824  else if (ch == 0)
2825  {
2826  // we stepped over null terminator, backtrack & handle closing tag
2827  --s;
2828 
2829  if (endch != '>')
2831  }
2832  else
2834  }
2835  else if (*s == '/')
2836  {
2837  ++s;
2838 
2839  char_t *name = cursor->name;
2840  if (!name)
2842 
2843  while (PUGI__IS_CHARTYPE(*s, ct_symbol))
2844  {
2845  if (*s++ != *name++)
2847  }
2848 
2849  if (*name)
2850  {
2851  if (*s == 0 && name[0] == endch && name[1] == 0)
2853  else
2855  }
2856 
2857  PUGI__POPNODE(); // Pop.
2858 
2859  PUGI__SKIPWS();
2860 
2861  if (*s == 0)
2862  {
2863  if (endch != '>')
2865  }
2866  else
2867  {
2868  if (*s != '>')
2870  ++s;
2871  }
2872  }
2873  else if (*s == '?') // '<?...'
2874  {
2875  s = parse_question(s, cursor, optmsk, endch);
2876  if (!s)
2877  return s;
2878 
2879  assert(cursor);
2880  if ((cursor->header & xml_memory_page_type_mask) + 1 == node_declaration)
2881  goto LOC_ATTRIBUTES;
2882  }
2883  else if (*s == '!') // '<!...'
2884  {
2885  s = parse_exclamation(s, cursor, optmsk, endch);
2886  if (!s)
2887  return s;
2888  }
2889  else if (*s == 0 && endch == '?')
2891  else
2893  }
2894  else
2895  {
2896  mark = s; // Save this offset while searching for a terminator.
2897 
2898  PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
2899 
2900  if (*s == '<' || !*s)
2901  {
2902  // We skipped some whitespace characters because otherwise we would take the tag branch instead of
2903  // PCDATA one
2904  assert(mark != s);
2905 
2907  {
2908  continue;
2909  }
2911  {
2912  if (s[0] != '<' || s[1] != '/' || cursor->first_child)
2913  continue;
2914  }
2915  }
2916 
2918  s = mark;
2919 
2920  if (cursor->parent || PUGI__OPTSET(parse_fragment))
2921  {
2922  PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree.
2923  cursor->value = s; // Save the offset.
2924 
2925  s = strconv_pcdata(s);
2926 
2927  PUGI__POPNODE(); // Pop since this is a standalone.
2928 
2929  if (!*s)
2930  break;
2931  }
2932  else
2933  {
2934  PUGI__SCANFOR(*s == '<'); // '...<'
2935  if (!*s)
2936  break;
2937 
2938  ++s;
2939  }
2940 
2941  // We're after '<'
2942  goto LOC_TAG;
2943  }
2944  }
2945 
2946  // check that last tag is closed
2947  if (cursor != root)
2949 
2950  return s;
2951  }
2952 
2953 #ifdef PUGIXML_WCHAR_MODE
2954  static char_t *parse_skip_bom(char_t *s)
2955  {
2956  unsigned int bom = 0xfeff;
2957  return (s[0] == static_cast<wchar_t>(bom)) ? s + 1 : s;
2958  }
2959 #else
2961  {
2962  return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s;
2963  }
2964 #endif
2965 
2967  {
2968  while (node)
2969  {
2970  xml_node_type type = static_cast<xml_node_type>((node->header & impl::xml_memory_page_type_mask) + 1);
2971  if (type == node_element)
2972  return true;
2973 
2974  node = node->next_sibling;
2975  }
2976 
2977  return false;
2978  }
2979 
2980  static xml_parse_result parse(char_t *buffer, size_t length, xml_document_struct *xmldoc, xml_node_struct *root,
2981  unsigned int optmsk)
2982  {
2983  // allocator object is a part of document object
2984  xml_allocator &alloc = *static_cast<xml_allocator *>(xmldoc);
2985 
2986  // early-out for empty documents
2987  if (length == 0)
2989 
2990  // get last child of the root before parsing
2991  xml_node_struct *last_root_child = root->first_child ? root->first_child->prev_sibling_c : 0;
2992 
2993  // create parser on stack
2995 
2996  // save last character and make buffer zero-terminated (speeds up parsing)
2997  char_t endch = buffer[length - 1];
2998  buffer[length - 1] = 0;
2999 
3000  // skip BOM to make sure it does not end up as part of parse output
3001  char_t *buffer_data = parse_skip_bom(buffer);
3002 
3003  // perform actual parsing
3004  parser.parse_tree(buffer_data, root, optmsk, endch);
3005 
3006  // update allocator state
3007  alloc = parser.alloc;
3008 
3009  xml_parse_result result =
3010  make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
3011  assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
3012 
3013  if (result)
3014  {
3015  // since we removed last character, we have to handle the only possible false positive (stray <)
3016  if (endch == '<')
3018 
3019  // check if there are any element nodes parsed
3020  xml_node_struct *first_root_child_parsed =
3021  last_root_child ? last_root_child->next_sibling : root->first_child;
3022 
3023  if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
3025  }
3026  else
3027  {
3028  // roll back offset if it occurs on a null terminator in the source buffer
3029  if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0)
3030  result.offset--;
3031  }
3032 
3033  return result;
3034  }
3035 };
3036 
3037 // Output facilities
3039 {
3040 #ifdef PUGIXML_WCHAR_MODE
3041  return get_wchar_encoding();
3042 #else
3043  return encoding_utf8;
3044 #endif
3045 }
3046 
3048 {
3049  // replace wchar encoding with utf implementation
3050  if (encoding == encoding_wchar)
3051  return get_wchar_encoding();
3052 
3053  // replace utf16 encoding with utf16 with specific endianness
3054  if (encoding == encoding_utf16)
3056 
3057  // replace utf32 encoding with utf32 with specific endianness
3058  if (encoding == encoding_utf32)
3060 
3061  // only do autodetection if no explicit encoding is requested
3062  if (encoding != encoding_auto)
3063  return encoding;
3064 
3065  // assume utf8 encoding
3066  return encoding_utf8;
3067 }
3068 
3069 #ifdef PUGIXML_WCHAR_MODE
3070 PUGI__FN size_t get_valid_length(const char_t *data, size_t length)
3071 {
3072  assert(length > 0);
3073 
3074  // discard last character if it's the lead of a surrogate pair
3075  return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400)
3076  ? length - 1
3077  : length;
3078 }
3079 
3080 PUGI__FN size_t convert_buffer_output(char_t *r_char, uint8_t *r_u8, uint16_t *r_u16, uint32_t *r_u32,
3081  const char_t *data, size_t length, xml_encoding encoding)
3082 {
3083  // only endian-swapping is required
3084  if (need_endian_swap_utf(encoding, get_wchar_encoding()))
3085  {
3086  convert_wchar_endian_swap(r_char, data, length);
3087 
3088  return length * sizeof(char_t);
3089  }
3090 
3091  // convert to utf8
3092  if (encoding == encoding_utf8)
3093  {
3094  uint8_t *dest = r_u8;
3096 
3097  return static_cast<size_t>(end - dest);
3098  }
3099 
3100  // convert to utf16
3101  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3102  {
3103  uint16_t *dest = r_u16;
3104 
3105  // convert to native utf16
3107 
3108  // swap if necessary
3110 
3111  if (native_encoding != encoding)
3112  convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
3113 
3114  return static_cast<size_t>(end - dest) * sizeof(uint16_t);
3115  }
3116 
3117  // convert to utf32
3118  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3119  {
3120  uint32_t *dest = r_u32;
3121 
3122  // convert to native utf32
3124 
3125  // swap if necessary
3127 
3128  if (native_encoding != encoding)
3129  convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
3130 
3131  return static_cast<size_t>(end - dest) * sizeof(uint32_t);
3132  }
3133 
3134  // convert to latin1
3135  if (encoding == encoding_latin1)
3136  {
3137  uint8_t *dest = r_u8;
3139 
3140  return static_cast<size_t>(end - dest);
3141  }
3142 
3143  assert(!"Invalid encoding");
3144  return 0;
3145 }
3146 #else
3147 PUGI__FN size_t get_valid_length(const char_t *data, size_t length)
3148 {
3149  assert(length > 4);
3150 
3151  for (size_t i = 1; i <= 4; ++i)
3152  {
3153  uint8_t ch = static_cast<uint8_t>(data[length - i]);
3154 
3155  // either a standalone character or a leading one
3156  if ((ch & 0xc0) != 0x80)
3157  return length - i;
3158  }
3159 
3160  // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole
3161  // chunk
3162  return length;
3163 }
3164 
3165 PUGI__FN size_t convert_buffer_output(char_t * /* r_char */, uint8_t *r_u8, uint16_t *r_u16, uint32_t *r_u32,
3166  const char_t *data, size_t length, xml_encoding encoding)
3167 {
3168  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3169  {
3170  uint16_t *dest = r_u16;
3171 
3172  // convert to native utf16
3173  uint16_t *end =
3174  utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t *>(data), length, dest);
3175 
3176  // swap if necessary
3178 
3179  if (native_encoding != encoding)
3180  convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
3181 
3182  return static_cast<size_t>(end - dest) * sizeof(uint16_t);
3183  }
3184 
3185  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3186  {
3187  uint32_t *dest = r_u32;
3188 
3189  // convert to native utf32
3190  uint32_t *end =
3191  utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t *>(data), length, dest);
3192 
3193  // swap if necessary
3195 
3196  if (native_encoding != encoding)
3197  convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
3198 
3199  return static_cast<size_t>(end - dest) * sizeof(uint32_t);
3200  }
3201 
3202  if (encoding == encoding_latin1)
3203  {
3204  uint8_t *dest = r_u8;
3205  uint8_t *end =
3206  utf_decoder<latin1_writer>::decode_utf8_block(reinterpret_cast<const uint8_t *>(data), length, dest);
3207 
3208  return static_cast<size_t>(end - dest);
3209  }
3210 
3211  assert(!"Invalid encoding");
3212  return 0;
3213 }
3214 #endif
3215 
3217 {
3220 
3221  public:
3222  xml_buffered_writer(xml_writer &writer_, xml_encoding user_encoding)
3223  : writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
3224  {
3226  }
3227 
3229 
3230  void flush()
3231  {
3232  flush(buffer, bufsize);
3233  bufsize = 0;
3234  }
3235 
3236  void flush(const char_t *data, size_t size)
3237  {
3238  if (size == 0)
3239  return;
3240 
3241  // fast path, just write data
3243  writer.write(data, size * sizeof(char_t));
3244  else
3245  {
3246  // convert chunk
3247  size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16,
3248  scratch.data_u32, data, size, encoding);
3249  assert(result <= sizeof(scratch));
3250 
3251  // write data
3252  writer.write(scratch.data_u8, result);
3253  }
3254  }
3255 
3256  void write(const char_t *data, size_t length)
3257  {
3258  if (bufsize + length > bufcapacity)
3259  {
3260  // flush the remaining buffer contents
3261  flush();
3262 
3263  // handle large chunks
3264  if (length > bufcapacity)
3265  {
3267  {
3268  // fast path, can just write data chunk
3269  writer.write(data, length * sizeof(char_t));
3270  return;
3271  }
3272 
3273  // need to convert in suitable chunks
3274  while (length > bufcapacity)
3275  {
3276  // get chunk size by selecting such number of characters that are guaranteed to fit into scratch
3277  // buffer and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
3278  size_t chunk_size = get_valid_length(data, bufcapacity);
3279 
3280  // convert chunk and write
3281  flush(data, chunk_size);
3282 
3283  // iterate
3284  data += chunk_size;
3285  length -= chunk_size;
3286  }
3287 
3288  // small tail is copied below
3289  bufsize = 0;
3290  }
3291  }
3292 
3293  memcpy(buffer + bufsize, data, length * sizeof(char_t));
3294  bufsize += length;
3295  }
3296 
3297  void write(const char_t *data) { write(data, strlength(data)); }
3298 
3299  void write(char_t d0)
3300  {
3301  if (bufsize + 1 > bufcapacity)
3302  flush();
3303 
3304  buffer[bufsize + 0] = d0;
3305  bufsize += 1;
3306  }
3307 
3308  void write(char_t d0, char_t d1)
3309  {
3310  if (bufsize + 2 > bufcapacity)
3311  flush();
3312 
3313  buffer[bufsize + 0] = d0;
3314  buffer[bufsize + 1] = d1;
3315  bufsize += 2;
3316  }
3317 
3318  void write(char_t d0, char_t d1, char_t d2)
3319  {
3320  if (bufsize + 3 > bufcapacity)
3321  flush();
3322 
3323  buffer[bufsize + 0] = d0;
3324  buffer[bufsize + 1] = d1;
3325  buffer[bufsize + 2] = d2;
3326  bufsize += 3;
3327  }
3328 
3329  void write(char_t d0, char_t d1, char_t d2, char_t d3)
3330  {
3331  if (bufsize + 4 > bufcapacity)
3332  flush();
3333 
3334  buffer[bufsize + 0] = d0;
3335  buffer[bufsize + 1] = d1;
3336  buffer[bufsize + 2] = d2;
3337  buffer[bufsize + 3] = d3;
3338  bufsize += 4;
3339  }
3340 
3341  void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
3342  {
3343  if (bufsize + 5 > bufcapacity)
3344  flush();
3345 
3346  buffer[bufsize + 0] = d0;
3347  buffer[bufsize + 1] = d1;
3348  buffer[bufsize + 2] = d2;
3349  buffer[bufsize + 3] = d3;
3350  buffer[bufsize + 4] = d4;
3351  bufsize += 5;
3352  }
3353 
3354  void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
3355  {
3356  if (bufsize + 6 > bufcapacity)
3357  flush();
3358 
3359  buffer[bufsize + 0] = d0;
3360  buffer[bufsize + 1] = d1;
3361  buffer[bufsize + 2] = d2;
3362  buffer[bufsize + 3] = d3;
3363  buffer[bufsize + 4] = d4;
3364  buffer[bufsize + 5] = d5;
3365  bufsize += 6;
3366  }
3367 
3368  // utf8 maximum expansion: x4 (-> utf32)
3369  // utf16 maximum expansion: x2 (-> utf32)
3370  // utf32 maximum expansion: x1
3371  enum
3372  {
3374 #ifdef PUGIXML_MEMORY_OUTPUT_STACK
3375  PUGIXML_MEMORY_OUTPUT_STACK
3376 #else
3377  10240
3378 #endif
3379  ,
3380  bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4)
3381  };
3382 
3384 
3385  union {
3391 
3392  xml_writer &writer;
3393  size_t bufsize;
3395 };
3396 
3398 {
3399  while (*s)
3400  {
3401  const char_t *prev = s;
3402 
3403  // While *s is a usual symbol
3404  while (!PUGI__IS_CHARTYPEX(*s, type))
3405  ++s;
3406 
3407  writer.write(prev, static_cast<size_t>(s - prev));
3408 
3409  switch (*s)
3410  {
3411  case 0:
3412  break;
3413  case '&':
3414  writer.write('&', 'a', 'm', 'p', ';');
3415  ++s;
3416  break;
3417  case '<':
3418  writer.write('&', 'l', 't', ';');
3419  ++s;
3420  break;
3421  case '>':
3422  writer.write('&', 'g', 't', ';');
3423  ++s;
3424  break;
3425  case '"':
3426  writer.write('&', 'q', 'u', 'o', 't', ';');
3427  ++s;
3428  break;
3429  default: // s is not a usual symbol
3430  {
3431  unsigned int ch = static_cast<unsigned int>(*s++);
3432  assert(ch < 32);
3433 
3434  writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');
3435  }
3436  }
3437  }
3438 }
3439 
3441 {
3442  if (flags & format_no_escapes)
3443  writer.write(s);
3444  else
3446 }
3447 
3449 {
3450  do
3451  {
3452  writer.write('<', '!', '[', 'C', 'D');
3453  writer.write('A', 'T', 'A', '[');
3454 
3455  const char_t *prev = s;
3456 
3457  // look for ]]> sequence - we can't output it as is since it terminates CDATA
3458  while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>'))
3459  ++s;
3460 
3461  // skip ]] if we stopped at ]]>, > will go to the next CDATA section
3462  if (*s)
3463  s += 2;
3464 
3465  writer.write(prev, static_cast<size_t>(s - prev));
3466 
3467  writer.write(']', ']', '>');
3468  } while (*s);
3469 }
3470 
3471 PUGI__FN void node_output_attributes(xml_buffered_writer &writer, const xml_node &node, unsigned int flags)
3472 {
3473  const char_t *default_name = PUGIXML_TEXT(":anonymous");
3474 
3475  for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute())
3476  {
3477  writer.write(' ');
3478  writer.write(a.name()[0] ? a.name() : default_name);
3479  writer.write('=', '"');
3480 
3481  text_output(writer, a.value(), ctx_special_attr, flags);
3482 
3483  writer.write('"');
3484  }
3485 }
3486 
3487 PUGI__FN void node_output(xml_buffered_writer &writer, const xml_node &node, const char_t *indent, unsigned int flags,
3488  unsigned int depth)
3489 {
3490  const char_t *default_name = PUGIXML_TEXT(":anonymous");
3491 
3492  if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
3493  for (unsigned int i = 0; i < depth; ++i)
3494  writer.write(indent);
3495 
3496  switch (node.type())
3497  {
3498  case node_document:
3499  {
3500  for (xml_node n = node.first_child(); n; n = n.next_sibling())
3501  node_output(writer, n, indent, flags, depth);
3502  break;
3503  }
3504 
3505  case node_element:
3506  {
3507  const char_t *name = node.name()[0] ? node.name() : default_name;
3508 
3509  writer.write('<');
3510  writer.write(name);
3511 
3512  node_output_attributes(writer, node, flags);
3513 
3514  if (flags & format_raw)
3515  {
3516  if (!node.first_child())
3517  writer.write(' ', '/', '>');
3518  else
3519  {
3520  writer.write('>');
3521 
3522  for (xml_node n = node.first_child(); n; n = n.next_sibling())
3523  node_output(writer, n, indent, flags, depth + 1);
3524 
3525  writer.write('<', '/');
3526  writer.write(name);
3527  writer.write('>');
3528  }
3529  }
3530  else if (!node.first_child())
3531  writer.write(' ', '/', '>', '\n');
3532  else if (node.first_child() == node.last_child() &&
3533  (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata))
3534  {
3535  writer.write('>');
3536 
3537  if (node.first_child().type() == node_pcdata)
3538  text_output(writer, node.first_child().value(), ctx_special_pcdata, flags);
3539  else
3540  text_output_cdata(writer, node.first_child().value());
3541 
3542  writer.write('<', '/');
3543  writer.write(name);
3544  writer.write('>', '\n');
3545  }
3546  else
3547  {
3548  writer.write('>', '\n');
3549 
3550  for (xml_node n = node.first_child(); n; n = n.next_sibling())
3551  node_output(writer, n, indent, flags, depth + 1);
3552 
3553  if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
3554  for (unsigned int i = 0; i < depth; ++i)
3555  writer.write(indent);
3556 
3557  writer.write('<', '/');
3558  writer.write(name);
3559  writer.write('>', '\n');
3560  }
3561 
3562  break;
3563  }
3564 
3565  case node_pcdata:
3566  text_output(writer, node.value(), ctx_special_pcdata, flags);
3567  if ((flags & format_raw) == 0)
3568  writer.write('\n');
3569  break;
3570 
3571  case node_cdata:
3572  text_output_cdata(writer, node.value());
3573  if ((flags & format_raw) == 0)
3574  writer.write('\n');
3575  break;
3576 
3577  case node_comment:
3578  writer.write('<', '!', '-', '-');
3579  writer.write(node.value());
3580  writer.write('-', '-', '>');
3581  if ((flags & format_raw) == 0)
3582  writer.write('\n');
3583  break;
3584 
3585  case node_pi:
3586  case node_declaration:
3587  writer.write('<', '?');
3588  writer.write(node.name()[0] ? node.name() : default_name);
3589 
3590  if (node.type() == node_declaration)
3591  {
3592  node_output_attributes(writer, node, flags);
3593  }
3594  else if (node.value()[0])
3595  {
3596  writer.write(' ');
3597  writer.write(node.value());
3598  }
3599 
3600  writer.write('?', '>');
3601  if ((flags & format_raw) == 0)
3602  writer.write('\n');
3603  break;
3604 
3605  case node_doctype:
3606  writer.write('<', '!', 'D', 'O', 'C');
3607  writer.write('T', 'Y', 'P', 'E');
3608 
3609  if (node.value()[0])
3610  {
3611  writer.write(' ');
3612  writer.write(node.value());
3613  }
3614 
3615  writer.write('>');
3616  if ((flags & format_raw) == 0)
3617  writer.write('\n');
3618  break;
3619 
3620  default:
3621  assert(!"Invalid node type");
3622  }
3623 }
3624 
3625 inline bool has_declaration(const xml_node &node)
3626 {
3627  for (xml_node child = node.first_child(); child; child = child.next_sibling())
3628  {
3629  xml_node_type type = child.type();
3630 
3631  if (type == node_declaration)
3632  return true;
3633  if (type == node_element)
3634  return false;
3635  }
3636 
3637  return false;
3638 }
3639 
3641 {
3642  if (parent != node_document && parent != node_element)
3643  return false;
3644  if (child == node_document || child == node_null)
3645  return false;
3646  if (parent != node_document && (child == node_declaration || child == node_doctype))
3647  return false;
3648 
3649  return true;
3650 }
3651 
3652 PUGI__FN void recursive_copy_skip(xml_node &dest, const xml_node &source, const xml_node &skip)
3653 {
3654  assert(dest.type() == source.type());
3655 
3656  switch (source.type())
3657  {
3658  case node_element:
3659  {
3660  dest.set_name(source.name());
3661 
3662  for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
3663  dest.append_attribute(a.name()).set_value(a.value());
3664 
3665  for (xml_node c = source.first_child(); c; c = c.next_sibling())
3666  {
3667  if (c == skip)
3668  continue;
3669 
3670  xml_node cc = dest.append_child(c.type());
3671  assert(cc);
3672 
3673  recursive_copy_skip(cc, c, skip);
3674  }
3675 
3676  break;
3677  }
3678 
3679  case node_pcdata:
3680  case node_cdata:
3681  case node_comment:
3682  case node_doctype:
3683  dest.set_value(source.value());
3684  break;
3685 
3686  case node_pi:
3687  dest.set_name(source.name());
3688  dest.set_value(source.value());
3689  break;
3690 
3691  case node_declaration:
3692  {
3693  dest.set_name(source.name());
3694 
3695  for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
3696  dest.append_attribute(a.name()).set_value(a.value());
3697 
3698  break;
3699  }
3700 
3701  default:
3702  assert(!"Invalid node type");
3703  }
3704 }
3705 
3706 inline bool is_text_node(xml_node_struct *node)
3707 {
3708  xml_node_type type = static_cast<xml_node_type>((node->header & impl::xml_memory_page_type_mask) + 1);
3709 
3710  return type == node_pcdata || type == node_cdata;
3711 }
3712 
3713 // get value with conversion functions
3715 {
3716  const char_t *s = value;
3717 
3718  while (PUGI__IS_CHARTYPE(*s, ct_space))
3719  s++;
3720 
3721  if (*s == '-')
3722  s++;
3723 
3724  return (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
3725 }
3726 
3727 PUGI__FN int get_value_int(const char_t *value, int def)
3728 {
3729  if (!value)
3730  return def;
3731 
3732  int base = get_integer_base(value);
3733 
3734 #ifdef PUGIXML_WCHAR_MODE
3735  return static_cast<int>(wcstol(value, 0, base));
3736 #else
3737  return static_cast<int>(strtol(value, 0, base));
3738 #endif
3739 }
3740 
3741 PUGI__FN unsigned int get_value_uint(const char_t *value, unsigned int def)
3742 {
3743  if (!value)
3744  return def;
3745 
3746  int base = get_integer_base(value);
3747 
3748 #ifdef PUGIXML_WCHAR_MODE
3749  return static_cast<unsigned int>(wcstoul(value, 0, base));
3750 #else
3751  return static_cast<unsigned int>(strtoul(value, 0, base));
3752 #endif
3753 }
3754 
3755 PUGI__FN double get_value_double(const char_t *value, double def)
3756 {
3757  if (!value)
3758  return def;
3759 
3760 #ifdef PUGIXML_WCHAR_MODE
3761  return wcstod(value, 0);
3762 #else
3763  return strtod(value, 0);
3764 #endif
3765 }
3766 
3767 PUGI__FN float get_value_float(const char_t *value, float def)
3768 {
3769  if (!value)
3770  return def;
3771 
3772 #ifdef PUGIXML_WCHAR_MODE
3773  return static_cast<float>(wcstod(value, 0));
3774 #else
3775  return static_cast<float>(strtod(value, 0));
3776 #endif
3777 }
3778 
3779 PUGI__FN bool get_value_bool(const char_t *value, bool def)
3780 {
3781  if (!value)
3782  return def;
3783 
3784  // only look at first char
3785  char_t first = *value;
3786 
3787  // 1*, t* (true), T* (True), y* (yes), Y* (YES)
3788  return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
3789 }
3790 
3791 #ifdef PUGIXML_HAS_LONG_LONG
3792 PUGI__FN long long get_value_llong(const char_t *value, long long def)
3793 {
3794  if (!value)
3795  return def;
3796 
3797  int base = get_integer_base(value);
3798 
3799 #ifdef PUGIXML_WCHAR_MODE
3800 #ifdef PUGI__MSVC_CRT_VERSION
3801  return _wcstoi64(value, 0, base);
3802 #else
3803  return wcstoll(value, 0, base);
3804 #endif
3805 #else
3806 #ifdef PUGI__MSVC_CRT_VERSION
3807  return _strtoi64(value, 0, base);
3808 #else
3809  return strtoll(value, 0, base);
3810 #endif
3811 #endif
3812 }
3813 
3814 PUGI__FN unsigned long long get_value_ullong(const char_t *value, unsigned long long def)
3815 {
3816  if (!value)
3817  return def;
3818 
3819  int base = get_integer_base(value);
3820 
3821 #ifdef PUGIXML_WCHAR_MODE
3822 #ifdef PUGI__MSVC_CRT_VERSION
3823  return _wcstoui64(value, 0, base);
3824 #else
3825  return wcstoull(value, 0, base);
3826 #endif
3827 #else
3828 #ifdef PUGI__MSVC_CRT_VERSION
3829  return _strtoui64(value, 0, base);
3830 #else
3831  return strtoull(value, 0, base);
3832 #endif
3833 #endif
3834 }
3835 #endif
3836 
3837 // set value with conversion functions
3838 PUGI__FN bool set_value_buffer(char_t *&dest, uintptr_t &header, uintptr_t header_mask, char (&buf)[128])
3839 {
3840 #ifdef PUGIXML_WCHAR_MODE
3841  char_t wbuf[128];
3842  impl::widen_ascii(wbuf, buf);
3843 
3844  return strcpy_insitu(dest, header, header_mask, wbuf);
3845 #else
3846  return strcpy_insitu(dest, header, header_mask, buf);
3847 #endif
3848 }
3849 
3850 PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, int value)
3851 {
3852  char buf[128];
3853  sprintf(buf, "%d", value);
3854 
3855  return set_value_buffer(dest, header, header_mask, buf);
3856 }
3857 
3858 PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, unsigned int value)
3859 {
3860  char buf[128];
3861  sprintf(buf, "%u", value);
3862 
3863  return set_value_buffer(dest, header, header_mask, buf);
3864 }
3865 
3866 PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, double value)
3867 {
3868  char buf[128];
3869  sprintf(buf, "%g", value);
3870 
3871  return set_value_buffer(dest, header, header_mask, buf);
3872 }
3873 
3874 PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, bool value)
3875 {
3876  return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
3877 }
3878 
3879 #ifdef PUGIXML_HAS_LONG_LONG
3880 PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, long long value)
3881 {
3882  char buf[128];
3883  sprintf(buf, "%lld", value);
3884 
3885  return set_value_buffer(dest, header, header_mask, buf);
3886 }
3887 
3888 PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, unsigned long long value)
3889 {
3890  char buf[128];
3891  sprintf(buf, "%llu", value);
3892 
3893  return set_value_buffer(dest, header, header_mask, buf);
3894 }
3895 #endif
3896 
3897 // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell
3898 // trick
3899 PUGI__FN xml_parse_status get_file_size(FILE *file, size_t &out_result)
3900 {
3901 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
3902  // there are 64-bit versions of fseek/ftell, let's use them
3903  typedef __int64 length_type;
3904 
3905  _fseeki64(file, 0, SEEK_END);
3906  length_type length = _ftelli64(file);
3907  _fseeki64(file, 0, SEEK_SET);
3908 #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__)
3909  // there are 64-bit versions of fseek/ftell, let's use them
3910  typedef off64_t length_type;
3911 
3912  fseeko64(file, 0, SEEK_END);
3913  length_type length = ftello64(file);
3914  fseeko64(file, 0, SEEK_SET);
3915 #else
3916  // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we
3917  // can't do anything anyway.
3918  typedef long length_type;
3919 
3920  fseek(file, 0, SEEK_END);
3921  length_type length = ftell(file);
3922  fseek(file, 0, SEEK_SET);
3923 #endif
3924 
3925  // check for I/O errors
3926  if (length < 0)
3927  return status_io_error;
3928 
3929  // check for overflow
3930  size_t result = static_cast<size_t>(length);
3931 
3932  if (static_cast<length_type>(result) != length)
3933  return status_out_of_memory;
3934 
3935  // finalize
3936  out_result = result;
3937 
3938  return status_ok;
3939 }
3940 
3941 PUGI__FN size_t zero_terminate_buffer(void *buffer, size_t size, xml_encoding encoding)
3942 {
3943  // We only need to zero-terminate if encoding conversion does not do it for us
3944 #ifdef PUGIXML_WCHAR_MODE
3945  xml_encoding wchar_encoding = get_wchar_encoding();
3946 
3947  if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding))
3948  {
3949  size_t length = size / sizeof(char_t);
3950 
3951  static_cast<char_t *>(buffer)[length] = 0;
3952  return (length + 1) * sizeof(char_t);
3953  }
3954 #else
3955  if (encoding == encoding_utf8)
3956  {
3957  static_cast<char *>(buffer)[size] = 0;
3958  return size + 1;
3959  }
3960 #endif
3961 
3962  return size;
3963 }
3964 
3965 PUGI__FN xml_parse_result load_file_impl(xml_document &doc, FILE *file, unsigned int options, xml_encoding encoding)
3966 {
3967  if (!file)
3969 
3970  // get file size (can result in I/O errors)
3971  size_t size = 0;
3972  xml_parse_status size_status = get_file_size(file, size);
3973 
3974  if (size_status != status_ok)
3975  {
3976  fclose(file);
3977  return make_parse_result(size_status);
3978  }
3979 
3980  size_t max_suffix_size = sizeof(char_t);
3981 
3982  // allocate buffer for the whole file
3983  char *contents = static_cast<char *>(xml_memory::allocate(size + max_suffix_size));
3984 
3985  if (!contents)
3986  {
3987  fclose(file);
3989  }
3990 
3991  // read file in memory
3992  size_t read_size = fread(contents, 1, size, file);
3993  fclose(file);
3994 
3995  if (read_size != size)
3996  {
3997  xml_memory::deallocate(contents);
3999  }
4000 
4001  xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
4002 
4003  return doc.load_buffer_inplace_own(contents, zero_terminate_buffer(contents, size, real_encoding), options,
4004  real_encoding);
4005 }
4006 
4007 #ifndef PUGIXML_NO_STL
4008 template <typename T>
4010 {
4012  {
4013  void *memory = xml_memory::allocate(sizeof(xml_stream_chunk));
4014 
4015  return new (memory) xml_stream_chunk();
4016  }
4017 
4018  static void destroy(void *ptr)
4019  {
4020  xml_stream_chunk *chunk = static_cast<xml_stream_chunk *>(ptr);
4021 
4022  // free chunk chain
4023  while (chunk)
4024  {
4025  xml_stream_chunk *next = chunk->next;
4026  xml_memory::deallocate(chunk);
4027  chunk = next;
4028  }
4029  }
4030 
4032 
4034  size_t size;
4035 
4036  T data[xml_memory_page_size / sizeof(T)];
4037 };
4038 
4039 template <typename T>
4040 PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T> &stream, void **out_buffer, size_t *out_size)
4041 {
4043 
4044  // read file to a chunk list
4045  size_t total = 0;
4046  xml_stream_chunk<T> *last = 0;
4047 
4048  while (!stream.eof())
4049  {
4050  // allocate new chunk
4052  if (!chunk)
4053  return status_out_of_memory;
4054 
4055  // append chunk to list
4056  if (last)
4057  last = last->next = chunk;
4058  else
4059  chunks.data = last = chunk;
4060 
4061  // read data to chunk
4062  stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));
4063  chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);
4064 
4065  // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors
4066  if (stream.bad() || (!stream.eof() && stream.fail()))
4067  return status_io_error;
4068 
4069  // guard against huge files (chunk size is small enough to make this overflow check work)
4070  if (total + chunk->size < total)
4071  return status_out_of_memory;
4072  total += chunk->size;
4073  }
4074 
4075  size_t max_suffix_size = sizeof(char_t);
4076 
4077  // copy chunk list to a contiguous buffer
4078  char *buffer = static_cast<char *>(xml_memory::allocate(total + max_suffix_size));
4079  if (!buffer)
4080  return status_out_of_memory;
4081 
4082  char *write = buffer;
4083 
4084  for (xml_stream_chunk<T> *chunk = static_cast<xml_stream_chunk<T> *>(chunks.data); chunk; chunk = chunk->next)
4085  {
4086  assert(write + chunk->size <= buffer + total);
4087  memcpy(write, chunk->data, chunk->size);
4088  write += chunk->size;
4089  }
4090 
4091  assert(write == buffer + total);
4092 
4093  // return buffer
4094  *out_buffer = buffer;
4095  *out_size = total;
4096 
4097  return status_ok;
4098 }
4099 
4100 template <typename T>
4101 PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T> &stream, void **out_buffer, size_t *out_size)
4102 {
4103  // get length of remaining data in stream
4104  typename std::basic_istream<T>::pos_type pos = stream.tellg();
4105  stream.seekg(0, std::ios::end);
4106  std::streamoff length = stream.tellg() - pos;
4107  stream.seekg(pos);
4108 
4109  if (stream.fail() || pos < 0)
4110  return status_io_error;
4111 
4112  // guard against huge files
4113  size_t read_length = static_cast<size_t>(length);
4114 
4115  if (static_cast<std::streamsize>(read_length) != length || length < 0)
4116  return status_out_of_memory;
4117 
4118  size_t max_suffix_size = sizeof(char_t);
4119 
4120  // read stream data into memory (guard against stream exceptions with buffer holder)
4121  buffer_holder buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);
4122  if (!buffer.data)
4123  return status_out_of_memory;
4124 
4125  stream.read(static_cast<T *>(buffer.data), static_cast<std::streamsize>(read_length));
4126 
4127  // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check
4128  // for other I/O errors
4129  if (stream.bad() || (!stream.eof() && stream.fail()))
4130  return status_io_error;
4131 
4132  // return buffer
4133  size_t actual_length = static_cast<size_t>(stream.gcount());
4134  assert(actual_length <= read_length);
4135 
4136  *out_buffer = buffer.release();
4137  *out_size = actual_length * sizeof(T);
4138 
4139  return status_ok;
4140 }
4141 
4142 template <typename T>
4143 PUGI__FN xml_parse_result load_stream_impl(xml_document &doc, std::basic_istream<T> &stream, unsigned int options,
4144  xml_encoding encoding)
4145 {
4146  void *buffer = 0;
4147  size_t size = 0;
4148  xml_parse_status status = status_ok;
4149 
4150  // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits)
4151  if (stream.fail())
4153 
4154  // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)
4155  if (stream.tellg() < 0)
4156  {
4157  stream.clear(); // clear error flags that could be set by a failing tellg
4158  status = load_stream_data_noseek(stream, &buffer, &size);
4159  }
4160  else
4161  status = load_stream_data_seek(stream, &buffer, &size);
4162 
4163  if (status != status_ok)
4164  return make_parse_result(status);
4165 
4166  xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
4167 
4168  return doc.load_buffer_inplace_own(buffer, zero_terminate_buffer(buffer, size, real_encoding), options,
4169  real_encoding);
4170 }
4171 #endif
4172 
4173 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__))
4174 PUGI__FN FILE *open_file_wide(const wchar_t *path, const wchar_t *mode)
4175 {
4176  return _wfopen(path, mode);
4177 }
4178 #else
4179 PUGI__FN char *convert_path_heap(const wchar_t *str)
4180 {
4181  assert(str);
4182 
4183  // first pass: get length in utf8 characters
4184  size_t length = strlength_wide(str);
4185  size_t size = as_utf8_begin(str, length);
4186 
4187  // allocate resulting string
4188  char *result = static_cast<char *>(xml_memory::allocate(size + 1));
4189  if (!result)
4190  return 0;
4191 
4192  // second pass: convert to utf8
4193  as_utf8_end(result, size, str, length);
4194 
4195  return result;
4196 }
4197 
4198 PUGI__FN FILE *open_file_wide(const wchar_t *path, const wchar_t *mode)
4199 {
4200  // there is no standard function to open wide paths, so our best bet is to try utf8 path
4201  char *path_utf8 = convert_path_heap(path);
4202  if (!path_utf8)
4203  return 0;
4204 
4205  // convert mode to ASCII (we mirror _wfopen interface)
4206  char mode_ascii[4] = { 0 };
4207  for (size_t i = 0; mode[i]; ++i)
4208  mode_ascii[i] = static_cast<char>(mode[i]);
4209 
4210  // try to open the utf8 path
4211  FILE *result = fopen(path_utf8, mode_ascii);
4212 
4213  // free dummy buffer
4214  xml_memory::deallocate(path_utf8);
4215 
4216  return result;
4217 }
4218 #endif
4219 
4220 PUGI__FN bool save_file_impl(const xml_document &doc, FILE *file, const char_t *indent, unsigned int flags,
4221  xml_encoding encoding)
4222 {
4223  if (!file)
4224  return false;
4225 
4226  xml_writer_file writer(file);
4227  doc.save(writer, indent, flags, encoding);
4228 
4229  int result = ferror(file);
4230 
4231  fclose(file);
4232 
4233  return result == 0;
4234 }
4235 
4236 PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct *doc, xml_node_struct *root, void *contents, size_t size,
4237  unsigned int options, xml_encoding encoding, bool is_mutable, bool own,
4238  char_t **out_buffer)
4239 {
4240  // check input buffer
4241  assert(contents || size == 0);
4242 
4243  // get actual encoding
4244  xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
4245 
4246  // get private buffer
4247  char_t *buffer = 0;
4248  size_t length = 0;
4249 
4250  if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable))
4252 
4253  // delete original buffer if we performed a conversion
4254  if (own && buffer != contents && contents)
4255  impl::xml_memory::deallocate(contents);
4256 
4257  // store buffer for offset_debug
4258  doc->buffer = buffer;
4259 
4260  // parse
4261  xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
4262 
4263  // remember encoding
4264  res.encoding = buffer_encoding;
4265 
4266  // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
4267  if (own || buffer != contents)
4268  *out_buffer = buffer;
4269 
4270  return res;
4271 }
4273 
4274 namespace pugi
4275 {
4276 PUGI__FN xml_writer_file::xml_writer_file(void *file_) : file(file_) {}
4277 
4278 PUGI__FN void xml_writer_file::write(const void *data, size_t size)
4279 {
4280  size_t result = fwrite(data, 1, size, static_cast<FILE *>(file));
4281  (void)!result; // unfortunately we can't do proper error handling here
4282 }
4283 
4284 #ifndef PUGIXML_NO_STL
4285 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char>> &stream)
4286  : narrow_stream(&stream), wide_stream(0)
4287 {
4288 }
4289 
4290 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t>> &stream)
4291  : narrow_stream(0), wide_stream(&stream)
4292 {
4293 }
4294 
4295 PUGI__FN void xml_writer_stream::write(const void *data, size_t size)
4296 {
4297  if (narrow_stream)
4298  {
4299  assert(!wide_stream);
4300  narrow_stream->write(reinterpret_cast<const char *>(data), static_cast<std::streamsize>(size));
4301  }
4302  else
4303  {
4304  assert(wide_stream);
4305  assert(size % sizeof(wchar_t) == 0);
4306 
4307  wide_stream->write(reinterpret_cast<const wchar_t *>(data),
4308  static_cast<std::streamsize>(size / sizeof(wchar_t)));
4309  }
4310 }
4311 #endif
4312 
4314 
4316 
4318 {
4319  return _depth;
4320 }
4321 
4323 {
4324  return true;
4325 }
4326 
4328 {
4329  return true;
4330 }
4331 
4333 
4335 
4337 
4338 PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
4339 {
4341 }
4342 
4344 {
4345  return !_attr;
4346 }
4347 
4349 {
4350  return (_attr == r._attr);
4351 }
4352 
4354 {
4355  return (_attr != r._attr);
4356 }
4357 
4359 {
4360  return (_attr < r._attr);
4361 }
4362 
4364 {
4365  return (_attr > r._attr);
4366 }
4367 
4369 {
4370  return (_attr <= r._attr);
4371 }
4372 
4374 {
4375  return (_attr >= r._attr);
4376 }
4377 
4379 {
4381 }
4382 
4384 {
4386 }
4387 
4389 {
4390  return (_attr && _attr->value) ? _attr->value : def;
4391 }
4392 
4394 {
4395  return impl::get_value_int(_attr ? _attr->value : 0, def);
4396 }
4397 
4398 PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
4399 {
4400  return impl::get_value_uint(_attr ? _attr->value : 0, def);
4401 }
4402 
4403 PUGI__FN double xml_attribute::as_double(double def) const
4404 {
4405  return impl::get_value_double(_attr ? _attr->value : 0, def);
4406 }
4407 
4408 PUGI__FN float xml_attribute::as_float(float def) const
4409 {
4410  return impl::get_value_float(_attr ? _attr->value : 0, def);
4411 }
4412 
4413 PUGI__FN bool xml_attribute::as_bool(bool def) const
4414 {
4415  return impl::get_value_bool(_attr ? _attr->value : 0, def);
4416 }
4417 
4418 #ifdef PUGIXML_HAS_LONG_LONG
4419 PUGI__FN long long xml_attribute::as_llong(long long def) const
4420 {
4421  return impl::get_value_llong(_attr ? _attr->value : 0, def);
4422 }
4423 
4424 PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
4425 {
4426  return impl::get_value_ullong(_attr ? _attr->value : 0, def);
4427 }
4428 #endif
4429 
4431 {
4432  return !_attr;
4433 }
4434 
4436 {
4437  return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT("");
4438 }
4439 
4441 {
4442  return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");
4443 }
4444 
4446 {
4447  return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
4448 }
4449 
4451 {
4452  return _attr;
4453 }
4454 
4456 {
4457  set_value(rhs);
4458  return *this;
4459 }
4460 
4462 {
4463  set_value(rhs);
4464  return *this;
4465 }
4466 
4468 {
4469  set_value(rhs);
4470  return *this;
4471 }
4472 
4474 {
4475  set_value(rhs);
4476  return *this;
4477 }
4478 
4480 {
4481  set_value(rhs);
4482  return *this;
4483 }
4484 
4485 #ifdef PUGIXML_HAS_LONG_LONG
4487 {
4488  set_value(rhs);
4489  return *this;
4490 }
4491 
4492 PUGI__FN xml_attribute &xml_attribute::operator=(unsigned long long rhs)
4493 {
4494  set_value(rhs);
4495  return *this;
4496 }
4497 #endif
4498 
4500 {
4501  if (!_attr)
4502  return false;
4503 
4505 }
4506 
4508 {
4509  if (!_attr)
4510  return false;
4511 
4513 }
4514 
4516 {
4517  if (!_attr)
4518  return false;
4519 
4521 }
4522 
4523 PUGI__FN bool xml_attribute::set_value(unsigned int rhs)
4524 {
4525  if (!_attr)
4526  return false;
4527 
4529 }
4530 
4532 {
4533  if (!_attr)
4534  return false;
4535 
4537 }
4538 
4540 {
4541  if (!_attr)
4542  return false;
4543 
4545 }
4546 
4547 #ifdef PUGIXML_HAS_LONG_LONG
4548 PUGI__FN bool xml_attribute::set_value(long long rhs)
4549 {
4550  if (!_attr)
4551  return false;
4552 
4554 }
4555 
4556 PUGI__FN bool xml_attribute::set_value(unsigned long long rhs)
4557 {
4558  if (!_attr)
4559  return false;
4560 
4562 }
4563 #endif
4564 
4565 #ifdef __BORLANDC__
4566 PUGI__FN bool operator&&(const xml_attribute &lhs, bool rhs)
4567 {
4568  return (bool)lhs && rhs;
4569 }
4570 
4571 PUGI__FN bool operator||(const xml_attribute &lhs, bool rhs)
4572 {
4573  return (bool)lhs || rhs;
4574 }
4575 #endif
4576 
4578 
4580 
4582 
4583 PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const
4584 {
4585  return _root ? unspecified_bool_xml_node : 0;
4586 }
4587 
4589 {
4590  return !_root;
4591 }
4592 
4594 {
4595  return iterator(_root ? _root->first_child : 0, _root);
4596 }
4597 
4599 {
4600  return iterator(0, _root);
4601 }
4602 
4604 {
4606 }
4607 
4609 {
4610  return attribute_iterator(0, _root);
4611 }
4612 
4614 {
4616 }
4617 
4619 {
4621  xml_named_node_iterator(0, _root, name_));
4622 }
4623 
4625 {
4627 }
4628 
4630 {
4631  return (_root == r._root);
4632 }
4633 
4635 {
4636  return (_root != r._root);
4637 }
4638 
4640 {
4641  return (_root < r._root);
4642 }
4643 
4645 {
4646  return (_root > r._root);
4647 }
4648 
4650 {
4651  return (_root <= r._root);
4652 }
4653 
4655 {
4656  return (_root >= r._root);
4657 }
4658 
4660 {
4661  return !_root;
4662 }
4663 
4665 {
4666  return (_root && _root->name) ? _root->name : PUGIXML_TEXT("");
4667 }
4668 
4670 {
4671  return _root ? static_cast<xml_node_type>((_root->header & impl::xml_memory_page_type_mask) + 1) : node_null;
4672 }
4673 
4675 {
4676  return (_root && _root->value) ? _root->value : PUGIXML_TEXT("");
4677 }
4678 
4680 {
4681  if (!_root)
4682  return xml_node();
4683 
4684  for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
4685  if (i->name && impl::strequal(name_, i->name))
4686  return xml_node(i);
4687 
4688  return xml_node();
4689 }
4690 
4692 {
4693  if (!_root)
4694  return xml_attribute();
4695 
4697  if (i->name && impl::strequal(name_, i->name))
4698  return xml_attribute(i);
4699 
4700  return xml_attribute();
4701 }
4702 
4704 {
4705  if (!_root)
4706  return xml_node();
4707 
4708  for (xml_node_struct *i = _root->next_sibling; i; i = i->next_sibling)
4709  if (i->name && impl::strequal(name_, i->name))
4710  return xml_node(i);
4711 
4712  return xml_node();
4713 }
4714 
4716 {
4717  if (!_root)
4718  return xml_node();
4719 
4720  if (_root->next_sibling)
4721  return xml_node(_root->next_sibling);
4722  else
4723  return xml_node();
4724 }
4725 
4727 {
4728  if (!_root)
4729  return xml_node();
4730 
4732  if (i->name && impl::strequal(name_, i->name))
4733  return xml_node(i);
4734 
4735  return xml_node();
4736 }
4737 
4739 {
4740  if (!_root)
4741  return xml_node();
4742 
4744  return xml_node(_root->prev_sibling_c);
4745  else
4746  return xml_node();
4747 }
4748 
4750 {
4751  return _root ? xml_node(_root->parent) : xml_node();
4752 }
4753 
4755 {
4756  if (!_root)
4757  return xml_node();
4758 
4759  impl::xml_memory_page *page =
4760  reinterpret_cast<impl::xml_memory_page *>(_root->header & impl::xml_memory_page_pointer_mask);
4761 
4762  return xml_node(static_cast<impl::xml_document_struct *>(page->allocator));
4763 }
4764 
4766 {
4767  return xml_text(_root);
4768 }
4769 
4771 {
4772  if (!_root)
4773  return PUGIXML_TEXT("");
4774 
4775  for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
4776  if (i->value && impl::is_text_node(i))
4777  return i->value;
4778 
4779  return PUGIXML_TEXT("");
4780 }
4781 
4782 PUGI__FN const char_t *xml_node::child_value(const char_t *name_) const
4783 {
4784  return child(name_).child_value();
4785 }
4786 
4788 {
4790 }
4791 
4793 {
4795 }
4796 
4798 {
4799  return _root ? xml_node(_root->first_child) : xml_node();
4800 }
4801 
4803 {
4805 }
4806 
4808 {
4809  switch (type())
4810  {
4811  case node_pi:
4812  case node_declaration:
4813  case node_element:
4815 
4816  default:
4817  return false;
4818  }
4819 }
4820 
4822 {
4823  switch (type())
4824  {
4825  case node_pi:
4826  case node_cdata:
4827  case node_pcdata:
4828  case node_comment:
4829  case node_doctype:
4831 
4832  default:
4833  return false;
4834  }
4835 }
4836 
4838 {
4839  if (type() != node_element && type() != node_declaration)
4840  return xml_attribute();
4841 
4843  a.set_name(name_);
4844 
4845  return a;
4846 }
4847 
4849 {
4850  if (type() != node_element && type() != node_declaration)
4851  return xml_attribute();
4852 
4854  if (!a)
4855  return xml_attribute();
4856 
4857  a.set_name(name_);
4858 
4860 
4861  if (head)
4862  {
4864  head->prev_attribute_c = a._attr;
4865  }
4866  else
4867  a._attr->prev_attribute_c = a._attr;
4868 
4869  a._attr->next_attribute = head;
4871 
4872  return a;
4873 }
4874 
4876 {
4877  if ((type() != node_element && type() != node_declaration) || attr.empty())
4878  return xml_attribute();
4879 
4880  // check that attribute belongs to *this
4881  xml_attribute_struct *cur = attr._attr;
4882 
4883  while (cur->prev_attribute_c->next_attribute)
4884  cur = cur->prev_attribute_c;
4885 
4886  if (cur != _root->first_attribute)
4887  return xml_attribute();
4888 
4890  if (!a)
4891  return xml_attribute();
4892 
4893  a.set_name(name_);
4894 
4897  else
4899 
4901  a._attr->next_attribute = attr._attr;
4902  attr._attr->prev_attribute_c = a._attr;
4903 
4904  return a;
4905 }
4906 
4908 {
4909  if ((type() != node_element && type() != node_declaration) || attr.empty())
4910  return xml_attribute();
4911 
4912  // check that attribute belongs to *this
4913  xml_attribute_struct *cur = attr._attr;
4914 
4915  while (cur->prev_attribute_c->next_attribute)
4916  cur = cur->prev_attribute_c;
4917 
4918  if (cur != _root->first_attribute)
4919  return xml_attribute();
4920 
4922  if (!a)
4923  return xml_attribute();
4924 
4925  a.set_name(name_);
4926 
4927  if (attr._attr->next_attribute)
4929  else
4931 
4933  a._attr->prev_attribute_c = attr._attr;
4934  attr._attr->next_attribute = a._attr;
4935 
4936  return a;
4937 }
4938 
4940 {
4941  if (!proto)
4942  return xml_attribute();
4943 
4944  xml_attribute result = append_attribute(proto.name());
4945  result.set_value(proto.value());
4946 
4947  return result;
4948 }
4949 
4951 {
4952  if (!proto)
4953  return xml_attribute();
4954 
4955  xml_attribute result = prepend_attribute(proto.name());
4956  result.set_value(proto.value());
4957 
4958  return result;
4959 }
4960 
4962 {
4963  if (!proto)
4964  return xml_attribute();
4965 
4966  xml_attribute result = insert_attribute_after(proto.name(), attr);
4967  result.set_value(proto.value());
4968 
4969  return result;
4970 }
4971 
4973 {
4974  if (!proto)
4975  return xml_attribute();
4976 
4977  xml_attribute result = insert_attribute_before(proto.name(), attr);
4978  result.set_value(proto.value());
4979 
4980  return result;
4981 }
4982 
4984 {
4985  if (!impl::allow_insert_child(this->type(), type_))
4986  return xml_node();
4987 
4989 
4990  if (type_ == node_declaration)
4991  n.set_name(PUGIXML_TEXT("xml"));
4992 
4993  return n;
4994 }
4995 
4997 {
4998  if (!impl::allow_insert_child(this->type(), type_))
4999  return xml_node();
5000 
5002  if (!n)
5003  return xml_node();
5004 
5005  n._root->parent = _root;
5006 
5008 
5009  if (head)
5010  {
5011  n._root->prev_sibling_c = head->prev_sibling_c;
5012  head->prev_sibling_c = n._root;
5013  }
5014  else
5015  n._root->prev_sibling_c = n._root;
5016 
5017  n._root->next_sibling = head;
5018  _root->first_child = n._root;
5019 
5020  if (type_ == node_declaration)
5021  n.set_name(PUGIXML_TEXT("xml"));
5022 
5023  return n;
5024 }
5025 
5027 {
5028  if (!impl::allow_insert_child(this->type(), type_))
5029  return xml_node();
5030  if (!node._root || node._root->parent != _root)
5031  return xml_node();
5032 
5034  if (!n)
5035  return xml_node();
5036 
5037  n._root->parent = _root;
5038 
5039  if (node._root->prev_sibling_c->next_sibling)
5041  else
5042  _root->first_child = n._root;
5043 
5045  n._root->next_sibling = node._root;
5046  node._root->prev_sibling_c = n._root;
5047 
5048  if (type_ == node_declaration)
5049  n.set_name(PUGIXML_TEXT("xml"));
5050 
5051  return n;
5052 }
5053 
5055 {
5056  if (!impl::allow_insert_child(this->type(), type_))
5057  return xml_node();
5058  if (!node._root || node._root->parent != _root)
5059  return xml_node();
5060 
5062  if (!n)
5063  return xml_node();
5064 
5065  n._root->parent = _root;
5066 
5067  if (node._root->next_sibling)
5069  else
5071 
5072  n._root->next_sibling = node._root->next_sibling;
5073  n._root->prev_sibling_c = node._root;
5074  node._root->next_sibling = n._root;
5075 
5076  if (type_ == node_declaration)
5077  n.set_name(PUGIXML_TEXT("xml"));
5078 
5079  return n;
5080 }
5081 
5083 {
5085 
5086  result.set_name(name_);
5087 
5088  return result;
5089 }
5090 
5092 {
5094 
5095  result.set_name(name_);
5096 
5097  return result;
5098 }
5099 
5101 {
5102  xml_node result = insert_child_after(node_element, node);
5103 
5104  result.set_name(name_);
5105 
5106  return result;
5107 }
5108 
5110 {
5111  xml_node result = insert_child_before(node_element, node);
5112 
5113  result.set_name(name_);
5114 
5115  return result;
5116 }
5117 
5119 {
5120  xml_node result = append_child(proto.type());
5121 
5122  if (result)
5123  impl::recursive_copy_skip(result, proto, result);
5124 
5125  return result;
5126 }
5127 
5129 {
5130  xml_node result = prepend_child(proto.type());
5131 
5132  if (result)
5133  impl::recursive_copy_skip(result, proto, result);
5134 
5135  return result;
5136 }
5137 
5139 {
5140  xml_node result = insert_child_after(proto.type(), node);
5141 
5142  if (result)
5143  impl::recursive_copy_skip(result, proto, result);
5144 
5145  return result;
5146 }
5147 
5149 {
5150  xml_node result = insert_child_before(proto.type(), node);
5151 
5152  if (result)
5153  impl::recursive_copy_skip(result, proto, result);
5154 
5155  return result;
5156 }
5157 
5159 {
5160  return remove_attribute(attribute(name_));
5161 }
5162 
5164 {
5165  if (!_root || !a._attr)
5166  return false;
5167 
5168  // check that attribute belongs to *this
5169  xml_attribute_struct *attr = a._attr;
5170 
5171  while (attr->prev_attribute_c->next_attribute)
5172  attr = attr->prev_attribute_c;
5173 
5174  if (attr != _root->first_attribute)
5175  return false;
5176 
5177  if (a._attr->next_attribute)
5179  else if (_root->first_attribute)
5181 
5184  else
5186 
5188 
5189  return true;
5190 }
5191 
5193 {
5194  return remove_child(child(name_));
5195 }
5196 
5198 {
5199  if (!_root || !n._root || n._root->parent != _root)
5200  return false;
5201 
5202  if (n._root->next_sibling)
5204  else if (_root->first_child)
5206 
5209  else
5211 
5213 
5214  return true;
5215 }
5216 
5217 PUGI__FN xml_parse_result xml_node::append_buffer(const void *contents, size_t size, unsigned int options,
5218  xml_encoding encoding)
5219 {
5220  // append_buffer is only valid for elements/documents
5223 
5224  // get document node
5225  impl::xml_document_struct *doc = static_cast<impl::xml_document_struct *>(root()._root);
5226  assert(doc);
5227 
5228  // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later)
5229  impl::xml_memory_page *page = 0;
5230  impl::xml_extra_buffer *extra =
5231  static_cast<impl::xml_extra_buffer *>(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page));
5232  (void)page;
5233 
5234  if (!extra)
5236 
5237  // save name; name of the root has to be NULL before parsing - otherwise closing node mismatches will not be
5238  // detected at the top level
5239  char_t *rootname = _root->name;
5240  _root->name = 0;
5241 
5242  // parse
5243  char_t *buffer = 0;
5244  xml_parse_result res = impl::load_buffer_impl(doc, _root, const_cast<void *>(contents), size, options, encoding,
5245  false, false, &buffer);
5246 
5247  // restore name
5248  _root->name = rootname;
5249 
5250  // add extra buffer to the list
5251  extra->buffer = buffer;
5252  extra->next = doc->extra_buffers;
5253  doc->extra_buffers = extra;
5254 
5255  return res;
5256 }
5257 
5259  const char_t *attr_value) const
5260 {
5261  if (!_root)
5262  return xml_node();
5263 
5264  for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
5265  if (i->name && impl::strequal(name_, i->name))
5266  {
5267  for (xml_attribute_struct *a = i->first_attribute; a; a = a->next_attribute)
5268  if (a->name && impl::strequal(attr_name, a->name) &&
5269  impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT("")))
5270  return xml_node(i);
5271  }
5272 
5273  return xml_node();
5274 }
5275 
5276 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t *attr_name, const char_t *attr_value) const
5277 {
5278  if (!_root)
5279  return xml_node();
5280 
5281  for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
5282  for (xml_attribute_struct *a = i->first_attribute; a; a = a->next_attribute)
5283  if (a->name && impl::strequal(attr_name, a->name) &&
5284  impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT("")))
5285  return xml_node(i);
5286 
5287  return xml_node();
5288 }
5289 
5290 #ifndef PUGIXML_NO_STL
5292 {
5293  xml_node cursor = *this; // Make a copy.
5294 
5295  string_t result = cursor.name();
5296 
5297  while (cursor.parent())
5298  {
5299  cursor = cursor.parent();
5300 
5301  string_t temp = cursor.name();
5302  temp += delimiter;
5303  temp += result;
5304  result.swap(temp);
5305  }
5306 
5307  return result;
5308 }
5309 #endif
5310 
5312 {
5313  xml_node found = *this; // Current search context.
5314 
5315  if (!_root || !path_ || !path_[0])
5316  return found;
5317 
5318  if (path_[0] == delimiter)
5319  {
5320  // Absolute path; e.g. '/foo/bar'
5321  found = found.root();
5322  ++path_;
5323  }
5324 
5325  const char_t *path_segment = path_;
5326 
5327  while (*path_segment == delimiter)
5328  ++path_segment;
5329 
5330  const char_t *path_segment_end = path_segment;
5331 
5332  while (*path_segment_end && *path_segment_end != delimiter)
5333  ++path_segment_end;
5334 
5335  if (path_segment == path_segment_end)
5336  return found;
5337 
5338  const char_t *next_segment = path_segment_end;
5339 
5340  while (*next_segment == delimiter)
5341  ++next_segment;
5342 
5343  if (*path_segment == '.' && path_segment + 1 == path_segment_end)
5344  return found.first_element_by_path(next_segment, delimiter);
5345  else if (*path_segment == '.' && *(path_segment + 1) == '.' && path_segment + 2 == path_segment_end)
5346  return found.parent().first_element_by_path(next_segment, delimiter);
5347  else
5348  {
5349  for (xml_node_struct *j = found._root->first_child; j; j = j->next_sibling)
5350  {
5351  if (j->name &&
5352  impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
5353  {
5354  xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
5355 
5356  if (subsearch)
5357  return subsearch;
5358  }
5359  }
5360 
5361  return xml_node();
5362  }
5363 }
5364 
5366 {
5367  walker._depth = -1;
5368 
5369  xml_node arg_begin = *this;
5370  if (!walker.begin(arg_begin))
5371  return false;
5372 
5373  xml_node cur = first_child();
5374 
5375  if (cur)
5376  {
5377  ++walker._depth;
5378 
5379  do
5380  {
5381  xml_node arg_for_each = cur;
5382  if (!walker.for_each(arg_for_each))
5383  return false;
5384 
5385  if (cur.first_child())
5386  {
5387  ++walker._depth;
5388  cur = cur.first_child();
5389  }
5390  else if (cur.next_sibling())
5391  cur = cur.next_sibling();
5392  else
5393  {
5394  // Borland C++ workaround
5395  while (!cur.next_sibling() && cur != *this && !cur.parent().empty())
5396  {
5397  --walker._depth;
5398  cur = cur.parent();
5399  }
5400 
5401  if (cur != *this)
5402  cur = cur.next_sibling();
5403  }
5404  } while (cur && cur != *this);
5405  }
5406 
5407  assert(walker._depth == -1);
5408 
5409  xml_node arg_end = *this;
5410  return walker.end(arg_end);
5411 }
5412 
5414 {
5415  return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
5416 }
5417 
5419 {
5420  return _root;
5421 }
5422 
5423 PUGI__FN void xml_node::print(xml_writer &writer, const char_t *indent, unsigned int flags, xml_encoding encoding,
5424  unsigned int depth) const
5425 {
5426  if (!_root)
5427  return;
5428 
5429  impl::xml_buffered_writer buffered_writer(writer, encoding);
5430 
5431  impl::node_output(buffered_writer, *this, indent, flags, depth);
5432 }
5433 
5434 #ifndef PUGIXML_NO_STL
5435 PUGI__FN void xml_node::print(std::basic_ostream<char, std::char_traits<char>> &stream, const char_t *indent,
5436  unsigned int flags, xml_encoding encoding, unsigned int depth) const
5437 {
5438  xml_writer_stream writer(stream);
5439 
5440  print(writer, indent, flags, encoding, depth);
5441 }
5442 
5443 PUGI__FN void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t>> &stream, const char_t *indent,
5444  unsigned int flags, unsigned int depth) const
5445 {
5446  xml_writer_stream writer(stream);
5447 
5448  print(writer, indent, flags, encoding_wchar, depth);
5449 }
5450 #endif
5451 
5453 {
5454  xml_node_struct *r = root()._root;
5455 
5456  if (!r)
5457  return -1;
5458 
5459  const char_t *buffer = static_cast<impl::xml_document_struct *>(r)->buffer;
5460 
5461  if (!buffer)
5462  return -1;
5463 
5464  switch (type())
5465  {
5466  case node_document:
5467  return 0;
5468 
5469  case node_element:
5470  case node_declaration:
5471  case node_pi:
5472  return (_root->header & impl::xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer;
5473 
5474  case node_pcdata:
5475  case node_cdata:
5476  case node_comment:
5477  case node_doctype:
5478  return (_root->header & impl::xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer;
5479 
5480  default:
5481  return -1;
5482  }
5483 }
5484 
5485 #ifdef __BORLANDC__
5486 PUGI__FN bool operator&&(const xml_node &lhs, bool rhs)
5487 {
5488  return (bool)lhs && rhs;
5489 }
5490 
5491 PUGI__FN bool operator||(const xml_node &lhs, bool rhs)
5492 {
5493  return (bool)lhs || rhs;
5494 }
5495 #endif
5496 
5498 
5500 {
5501  if (!_root || impl::is_text_node(_root))
5502  return _root;
5503 
5504  for (xml_node_struct *node = _root->first_child; node; node = node->next_sibling)
5505  if (impl::is_text_node(node))
5506  return node;
5507 
5508  return 0;
5509 }
5510 
5512 {
5513  xml_node_struct *d = _data();
5514  if (d)
5515  return d;
5516 
5517  return xml_node(_root).append_child(node_pcdata).internal_object();
5518 }
5519 
5521 
5523 
5524 PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const
5525 {
5526  return _data() ? unspecified_bool_xml_text : 0;
5527 }
5528 
5530 {
5531  return !_data();
5532 }
5533 
5535 {
5536  return _data() == 0;
5537 }
5538 
5540 {
5541  xml_node_struct *d = _data();
5542 
5543  return (d && d->value) ? d->value : PUGIXML_TEXT("");
5544 }
5545 
5546 PUGI__FN const char_t *xml_text::as_string(const char_t *def) const
5547 {
5548  xml_node_struct *d = _data();
5549 
5550  return (d && d->value) ? d->value : def;
5551 }
5552 
5553 PUGI__FN int xml_text::as_int(int def) const
5554 {
5555  xml_node_struct *d = _data();
5556 
5557  return impl::get_value_int(d ? d->value : 0, def);
5558 }
5559 
5560 PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
5561 {
5562  xml_node_struct *d = _data();
5563 
5564  return impl::get_value_uint(d ? d->value : 0, def);
5565 }
5566 
5567 PUGI__FN double xml_text::as_double(double def) const
5568 {
5569  xml_node_struct *d = _data();
5570 
5571  return impl::get_value_double(d ? d->value : 0, def);
5572 }
5573 
5574 PUGI__FN float xml_text::as_float(float def) const
5575 {
5576  xml_node_struct *d = _data();
5577 
5578  return impl::get_value_float(d ? d->value : 0, def);
5579 }
5580 
5581 PUGI__FN bool xml_text::as_bool(bool def) const
5582 {
5583  xml_node_struct *d = _data();
5584 
5585  return impl::get_value_bool(d ? d->value : 0, def);
5586 }
5587 
5588 #ifdef PUGIXML_HAS_LONG_LONG
5589 PUGI__FN long long xml_text::as_llong(long long def) const
5590 {
5591  xml_node_struct *d = _data();
5592 
5593  return impl::get_value_llong(d ? d->value : 0, def);
5594 }
5595 
5596 PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const
5597 {
5598  xml_node_struct *d = _data();
5599 
5600  return impl::get_value_ullong(d ? d->value : 0, def);
5601 }
5602 #endif
5603 
5605 {
5606  xml_node_struct *dn = _data_new();
5607 
5608  return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5609 }
5610 
5612 {
5613  xml_node_struct *dn = _data_new();
5614 
5616 }
5617 
5618 PUGI__FN bool xml_text::set(unsigned int rhs)
5619 {
5620  xml_node_struct *dn = _data_new();
5621 
5623 }
5624 
5625 PUGI__FN bool xml_text::set(double rhs)
5626 {
5627  xml_node_struct *dn = _data_new();
5628 
5630 }
5631 
5632 PUGI__FN bool xml_text::set(bool rhs)
5633 {
5634  xml_node_struct *dn = _data_new();
5635 
5637 }
5638 
5639 #ifdef PUGIXML_HAS_LONG_LONG
5640 PUGI__FN bool xml_text::set(long long rhs)
5641 {
5642  xml_node_struct *dn = _data_new();
5643 
5645 }
5646 
5647 PUGI__FN bool xml_text::set(unsigned long long rhs)
5648 {
5649  xml_node_struct *dn = _data_new();
5650 
5651  return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5652 }
5653 #endif
5654 
5656 {
5657  set(rhs);
5658  return *this;
5659 }
5660 
5662 {
5663  set(rhs);
5664  return *this;
5665 }
5666 
5668 {
5669  set(rhs);
5670  return *this;
5671 }
5672 
5674 {
5675  set(rhs);
5676  return *this;
5677 }
5678 
5680 {
5681  set(rhs);
5682  return *this;
5683 }
5684 
5685 #ifdef PUGIXML_HAS_LONG_LONG
5686 PUGI__FN xml_text &xml_text::operator=(long long rhs)
5687 {
5688  set(rhs);
5689  return *this;
5690 }
5691 
5692 PUGI__FN xml_text &xml_text::operator=(unsigned long long rhs)
5693 {
5694  set(rhs);
5695  return *this;
5696 }
5697 #endif
5698 
5700 {
5701  return xml_node(_data());
5702 }
5703 
5704 #ifdef __BORLANDC__
5705 PUGI__FN bool operator&&(const xml_text &lhs, bool rhs)
5706 {
5707  return (bool)lhs && rhs;
5708 }
5709 
5710 PUGI__FN bool operator||(const xml_text &lhs, bool rhs)
5711 {
5712  return (bool)lhs || rhs;
5713 }
5714 #endif
5715 
5717 
5718 PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node &node) : _wrap(node), _parent(node.parent()) {}
5719 
5721  : _wrap(ref), _parent(parent)
5722 {
5723 }
5724 
5726 {
5727  return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
5728 }
5729 
5731 {
5732  return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
5733 }
5734 
5736 {
5737  assert(_wrap._root);
5738  return _wrap;
5739 }
5740 
5742 {
5743  assert(_wrap._root);
5744  return const_cast<xml_node *>(&_wrap); // BCC32 workaround
5745 }
5746 
5748 {
5749  assert(_wrap._root);
5751  return *this;
5752 }
5753 
5755 {
5756  xml_node_iterator temp = *this;
5757  ++*this;
5758  return temp;
5759 }
5760 
5762 {
5764  return *this;
5765 }
5766 
5768 {
5769  xml_node_iterator temp = *this;
5770  --*this;
5771  return temp;
5772 }
5773 
5775 
5777  : _wrap(attr), _parent(parent)
5778 {
5779 }
5780 
5782  : _wrap(ref), _parent(parent)
5783 {
5784 }
5785 
5787 {
5788  return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
5789 }
5790 
5792 {
5793  return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
5794 }
5795 
5797 {
5798  assert(_wrap._attr);
5799  return _wrap;
5800 }
5801 
5803 {
5804  assert(_wrap._attr);
5805  return const_cast<xml_attribute *>(&_wrap); // BCC32 workaround
5806 }
5807 
5809 {
5810  assert(_wrap._attr);
5812  return *this;
5813 }
5814 
5816 {
5817  xml_attribute_iterator temp = *this;
5818  ++*this;
5819  return temp;
5820 }
5821 
5823 {
5825  return *this;
5826 }
5827 
5829 {
5830  xml_attribute_iterator temp = *this;
5831  --*this;
5832  return temp;
5833 }
5834 
5836 
5838  : _wrap(node), _parent(node.parent()), _name(name)
5839 {
5840 }
5841 
5843  const char_t *name)
5844  : _wrap(ref), _parent(parent), _name(name)
5845 {
5846 }
5847 
5849 {
5850  return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
5851 }
5852 
5854 {
5855  return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
5856 }
5857 
5859 {
5860  assert(_wrap._root);
5861  return _wrap;
5862 }
5863 
5865 {
5866  assert(_wrap._root);
5867  return const_cast<xml_node *>(&_wrap); // BCC32 workaround
5868 }
5869 
5871 {
5872  assert(_wrap._root);
5874  return *this;
5875 }
5876 
5878 {
5879  xml_named_node_iterator temp = *this;
5880  ++*this;
5881  return temp;
5882 }
5883 
5885 {
5886  if (_wrap._root)
5888  else
5889  {
5890  _wrap = _parent.last_child();
5891 
5892  if (!impl::strequal(_wrap.name(), _name))
5894  }
5895 
5896  return *this;
5897 }
5898 
5900 {
5901  xml_named_node_iterator temp = *this;
5902  --*this;
5903  return temp;
5904 }
5905 
5907 
5908 PUGI__FN xml_parse_result::operator bool() const
5909 {
5910  return status == status_ok;
5911 }
5912 
5914 {
5915  switch (status)
5916  {
5917  case status_ok:
5918  return "No error";
5919 
5920  case status_file_not_found:
5921  return "File was not found";
5922  case status_io_error:
5923  return "Error reading from file/stream";
5924  case status_out_of_memory:
5925  return "Could not allocate memory";
5926  case status_internal_error:
5927  return "Internal error occurred";
5928 
5930  return "Could not determine tag type";
5931 
5932  case status_bad_pi:
5933  return "Error parsing document declaration/processing instruction";
5934  case status_bad_comment:
5935  return "Error parsing comment";
5936  case status_bad_cdata:
5937  return "Error parsing CDATA section";
5938  case status_bad_doctype:
5939  return "Error parsing document type declaration";
5940  case status_bad_pcdata:
5941  return "Error parsing PCDATA section";
5943  return "Error parsing start element tag";
5944  case status_bad_attribute:
5945  return "Error parsing element attribute";
5947  return "Error parsing end element tag";
5949  return "Start-end tags mismatch";
5950 
5952  return "Unable to append nodes: root is not an element or document";
5953 
5955  return "No document element found";
5956 
5957  default:
5958  return "Unknown error";
5959  }
5960 }
5961 
5963 {
5964  create();
5965 }
5966 
5968 {
5969  destroy();
5970 }
5971 
5973 {
5974  destroy();
5975  create();
5976 }
5977 
5979 {
5980  reset();
5981 
5982  for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
5983  append_copy(cur);
5984 }
5985 
5987 {
5988  assert(!_root);
5989 
5990  // initialize sentinel page
5991  PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) +
5993  sizeof(_memory));
5994 
5995  // align upwards to page boundary
5996  void *page_memory =
5997  reinterpret_cast<void *>((reinterpret_cast<uintptr_t>(_memory) + (impl::xml_memory_page_alignment - 1)) &
5999 
6000  // prepare page structure
6001  impl::xml_memory_page *page = impl::xml_memory_page::construct(page_memory);
6002  assert(page);
6003 
6004  page->busy_size = impl::xml_memory_page_size;
6005 
6006  // allocate new root
6007  _root = new (page->data) impl::xml_document_struct(page);
6009 
6010  // setup sentinel page
6011  page->allocator = static_cast<impl::xml_document_struct *>(_root);
6012 }
6013 
6015 {
6016  assert(_root);
6017 
6018  // destroy static storage
6019  if (_buffer)
6020  {
6021  impl::xml_memory::deallocate(_buffer);
6022  _buffer = 0;
6023  }
6024 
6025  // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator)
6026  for (impl::xml_extra_buffer *extra = static_cast<impl::xml_document_struct *>(_root)->extra_buffers; extra;
6027  extra = extra->next)
6028  {
6029  if (extra->buffer)
6030  impl::xml_memory::deallocate(extra->buffer);
6031  }
6032 
6033  // destroy dynamic storage, leave sentinel page (it's in static memory)
6034  impl::xml_memory_page *root_page =
6035  reinterpret_cast<impl::xml_memory_page *>(_root->header & impl::xml_memory_page_pointer_mask);
6036  assert(root_page && !root_page->prev && !root_page->memory);
6037 
6038  for (impl::xml_memory_page *page = root_page->next; page;)
6039  {
6040  impl::xml_memory_page *next = page->next;
6041 
6042  impl::xml_allocator::deallocate_page(page);
6043 
6044  page = next;
6045  }
6046 
6047  _root = 0;
6048 }
6049 
6050 #ifndef PUGIXML_NO_STL
6051 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char>> &stream,
6052  unsigned int options, xml_encoding encoding)
6053 {
6054  reset();
6055 
6056  return impl::load_stream_impl(*this, stream, options, encoding);
6057 }
6058 
6059 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t>> &stream,
6060  unsigned int options)
6061 {
6062  reset();
6063 
6064  return impl::load_stream_impl(*this, stream, options, encoding_wchar);
6065 }
6066 #endif
6067 
6069 {
6070  // Force native encoding (skip autodetection)
6071 #ifdef PUGIXML_WCHAR_MODE
6072  xml_encoding encoding = encoding_wchar;
6073 #else
6074  xml_encoding encoding = encoding_utf8;
6075 #endif
6076 
6077  return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
6078 }
6079 
6080 PUGI__FN xml_parse_result xml_document::load_file(const char *path_, unsigned int options, xml_encoding encoding)
6081 {
6082  reset();
6083 
6084  FILE *file = fopen(path_, "rb");
6085 
6086  return impl::load_file_impl(*this, file, options, encoding);
6087 }
6088 
6089 PUGI__FN xml_parse_result xml_document::load_file(const wchar_t *path_, unsigned int options, xml_encoding encoding)
6090 {
6091  reset();
6092 
6093  FILE *file = impl::open_file_wide(path_, L"rb");
6094 
6095  return impl::load_file_impl(*this, file, options, encoding);
6096 }
6097 
6098 PUGI__FN xml_parse_result xml_document::load_buffer(const void *contents, size_t size, unsigned int options,
6099  xml_encoding encoding)
6100 {
6101  reset();
6102 
6103  return impl::load_buffer_impl(static_cast<impl::xml_document_struct *>(_root), _root, const_cast<void *>(contents),
6104  size, options, encoding, false, false, &_buffer);
6105 }
6106 
6107 PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void *contents, size_t size, unsigned int options,
6108  xml_encoding encoding)
6109 {
6110  reset();
6111 
6112  return impl::load_buffer_impl(static_cast<impl::xml_document_struct *>(_root), _root, contents, size, options,
6113  encoding, true, false, &_buffer);
6114 }
6115 
6117  xml_encoding encoding)
6118 {
6119  reset();
6120 
6121  return impl::load_buffer_impl(static_cast<impl::xml_document_struct *>(_root), _root, contents, size, options,
6122  encoding, true, true, &_buffer);
6123 }
6124 
6125 PUGI__FN void xml_document::save(xml_writer &writer, const char_t *indent, unsigned int flags,
6126  xml_encoding encoding) const
6127 {
6128  impl::xml_buffered_writer buffered_writer(writer, encoding);
6129 
6130  if ((flags & format_write_bom) && encoding != encoding_latin1)
6131  {
6132  // BOM always represents the codepoint U+FEFF, so just write it in native encoding
6133 #ifdef PUGIXML_WCHAR_MODE
6134  unsigned int bom = 0xfeff;
6135  buffered_writer.write(static_cast<wchar_t>(bom));
6136 #else
6137  buffered_writer.write('\xef', '\xbb', '\xbf');
6138 #endif
6139  }
6140 
6141  if (!(flags & format_no_declaration) && !impl::has_declaration(*this))
6142  {
6143  buffered_writer.write(PUGIXML_TEXT("<?xml version=\"1.0\""));
6144  if (encoding == encoding_latin1)
6145  buffered_writer.write(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
6146  buffered_writer.write('?', '>');
6147  if (!(flags & format_raw))
6148  buffered_writer.write('\n');
6149  }
6150 
6151  impl::node_output(buffered_writer, *this, indent, flags, 0);
6152 }
6153 
6154 #ifndef PUGIXML_NO_STL
6155 PUGI__FN void xml_document::save(std::basic_ostream<char, std::char_traits<char>> &stream, const char_t *indent,
6156  unsigned int flags, xml_encoding encoding) const
6157 {
6158  xml_writer_stream writer(stream);
6159 
6160  save(writer, indent, flags, encoding);
6161 }
6162 
6163 PUGI__FN void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t>> &stream, const char_t *indent,
6164  unsigned int flags) const
6165 {
6166  xml_writer_stream writer(stream);
6167 
6168  save(writer, indent, flags, encoding_wchar);
6169 }
6170 #endif
6171 
6172 PUGI__FN bool xml_document::save_file(const char *path_, const char_t *indent, unsigned int flags,
6173  xml_encoding encoding) const
6174 {
6175  FILE *file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb");
6176  return impl::save_file_impl(*this, file, indent, flags, encoding);
6177 }
6178 
6179 PUGI__FN bool xml_document::save_file(const wchar_t *path_, const char_t *indent, unsigned int flags,
6180  xml_encoding encoding) const
6181 {
6182  FILE *file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb");
6183  return impl::save_file_impl(*this, file, indent, flags, encoding);
6184 }
6185 
6187 {
6188  assert(_root);
6189 
6190  for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
6191  if ((i->header & impl::xml_memory_page_type_mask) + 1 == node_element)
6192  return xml_node(i);
6193 
6194  return xml_node();
6195 }
6196 
6197 #ifndef PUGIXML_NO_STL
6198 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t *str)
6199 {
6200  assert(str);
6201 
6203 }
6204 
6205 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t> &str)
6206 {
6207  return impl::as_utf8_impl(str.c_str(), str.size());
6208 }
6209 
6210 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char *str)
6211 {
6212  assert(str);
6213 
6214  return impl::as_wide_impl(str, strlen(str));
6215 }
6216 
6217 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string &str)
6218 {
6219  return impl::as_wide_impl(str.c_str(), str.size());
6220 }
6221 #endif
6222 
6224  deallocation_function deallocate)
6225 {
6226  impl::xml_memory::allocate = allocate;
6227  impl::xml_memory::deallocate = deallocate;
6228 }
6229 
6231 {
6232  return impl::xml_memory::allocate;
6233 }
6234 
6236 {
6237  return impl::xml_memory::deallocate;
6238 }
6239 } // namespace pugi
6240 
6241 #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
6242 namespace std
6243 {
6244 // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
6245 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator &)
6246 {
6247  return std::bidirectional_iterator_tag();
6248 }
6249 
6250 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator &)
6251 {
6252  return std::bidirectional_iterator_tag();
6253 }
6254 
6255 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator &)
6256 {
6257  return std::bidirectional_iterator_tag();
6258 }
6259 } // namespace std
6260 #endif
6261 
6262 #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
6263 namespace std
6264 {
6265 // Workarounds for (non-standard) iterator category detection
6266 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator &)
6267 {
6268  return std::bidirectional_iterator_tag();
6269 }
6270 
6271 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator &)
6272 {
6273  return std::bidirectional_iterator_tag();
6274 }
6275 
6276 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator &)
6277 {
6278  return std::bidirectional_iterator_tag();
6279 }
6280 } // namespace std
6281 #endif
6282 
6283 #ifndef PUGIXML_NO_XPATH
6284 
6285 // STL replacements
6287 struct equal_to
6288 {
6289  template <typename T>
6290  bool operator()(const T &lhs, const T &rhs) const
6291  {
6292  return lhs == rhs;
6293  }
6294 };
6295 
6297 {
6298  template <typename T>
6299  bool operator()(const T &lhs, const T &rhs) const
6300  {
6301  return lhs != rhs;
6302  }
6303 };
6304 
6305 struct less
6306 {
6307  template <typename T>
6308  bool operator()(const T &lhs, const T &rhs) const
6309  {
6310  return lhs < rhs;
6311  }
6312 };
6313 
6315 {
6316  template <typename T>
6317  bool operator()(const T &lhs, const T &rhs) const
6318  {
6319  return lhs <= rhs;
6320  }
6321 };
6322 
6323 template <typename T>
6324 void swap(T &lhs, T &rhs)
6325 {
6326  T temp = lhs;
6327  lhs = rhs;
6328  rhs = temp;
6329 }
6330 
6331 template <typename I, typename Pred>
6332 I min_element(I begin, I end, const Pred &pred)
6333 {
6334  I result = begin;
6335 
6336  for (I it = begin + 1; it != end; ++it)
6337  if (pred(*it, *result))
6338  result = it;
6339 
6340  return result;
6341 }
6342 
6343 template <typename I>
6344 void reverse(I begin, I end)
6345 {
6346  while (end - begin > 1)
6347  swap(*begin++, *--end);
6348 }
6349 
6350 template <typename I>
6351 I unique(I begin, I end)
6352 {
6353  // fast skip head
6354  while (end - begin > 1 && *begin != *(begin + 1))
6355  begin++;
6356 
6357  if (begin == end)
6358  return begin;
6359 
6360  // last written element
6361  I write = begin++;
6362 
6363  // merge unique elements
6364  while (begin != end)
6365  {
6366  if (*begin != *write)
6367  *++write = *begin++;
6368  else
6369  begin++;
6370  }
6371 
6372  // past-the-end (write points to live element)
6373  return write + 1;
6374 }
6375 
6376 template <typename I>
6377 void copy_backwards(I begin, I end, I target)
6378 {
6379  while (begin != end)
6380  *--target = *--end;
6381 }
6382 
6383 template <typename I, typename Pred, typename T>
6384 void insertion_sort(I begin, I end, const Pred &pred, T *)
6385 {
6386  assert(begin != end);
6387 
6388  for (I it = begin + 1; it != end; ++it)
6389  {
6390  T val = *it;
6391 
6392  if (pred(val, *begin))
6393  {
6394  // move to front
6395  copy_backwards(begin, it, it + 1);
6396  *begin = val;
6397  }
6398  else
6399  {
6400  I hole = it;
6401 
6402  // move hole backwards
6403  while (pred(val, *(hole - 1)))
6404  {
6405  *hole = *(hole - 1);
6406  hole--;
6407  }
6408 
6409  // fill hole with element
6410  *hole = val;
6411  }
6412  }
6413 }
6414 
6415 // std variant for elements with ==
6416 template <typename I, typename Pred>
6417 void partition(I begin, I middle, I end, const Pred &pred, I *out_eqbeg, I *out_eqend)
6418 {
6419  I eqbeg = middle, eqend = middle + 1;
6420 
6421  // expand equal range
6422  while (eqbeg != begin && *(eqbeg - 1) == *eqbeg)
6423  --eqbeg;
6424  while (eqend != end && *eqend == *eqbeg)
6425  ++eqend;
6426 
6427  // process outer elements
6428  I ltend = eqbeg, gtbeg = eqend;
6429 
6430  for (;;)
6431  {
6432  // find the element from the right side that belongs to the left one
6433  for (; gtbeg != end; ++gtbeg)
6434  if (!pred(*eqbeg, *gtbeg))
6435  {
6436  if (*gtbeg == *eqbeg)
6437  swap(*gtbeg, *eqend++);
6438  else
6439  break;
6440  }
6441 
6442  // find the element from the left side that belongs to the right one
6443  for (; ltend != begin; --ltend)
6444  if (!pred(*(ltend - 1), *eqbeg))
6445  {
6446  if (*eqbeg == *(ltend - 1))
6447  swap(*(ltend - 1), *--eqbeg);
6448  else
6449  break;
6450  }
6451 
6452  // scanned all elements
6453  if (gtbeg == end && ltend == begin)
6454  {
6455  *out_eqbeg = eqbeg;
6456  *out_eqend = eqend;
6457  return;
6458  }
6459 
6460  // make room for elements by moving equal area
6461  if (gtbeg == end)
6462  {
6463  if (--ltend != --eqbeg)
6464  swap(*ltend, *eqbeg);
6465  swap(*eqbeg, *--eqend);
6466  }
6467  else if (ltend == begin)
6468  {
6469  if (eqend != gtbeg)
6470  swap(*eqbeg, *eqend);
6471  ++eqend;
6472  swap(*gtbeg++, *eqbeg++);
6473  }
6474  else
6475  swap(*gtbeg++, *--ltend);
6476  }
6477 }
6478 
6479 template <typename I, typename Pred>
6480 void median3(I first, I middle, I last, const Pred &pred)
6481 {
6482  if (pred(*middle, *first))
6483  swap(*middle, *first);
6484  if (pred(*last, *middle))
6485  swap(*last, *middle);
6486  if (pred(*middle, *first))
6487  swap(*middle, *first);
6488 }
6489 
6490 template <typename I, typename Pred>
6491 void median(I first, I middle, I last, const Pred &pred)
6492 {
6493  if (last - first <= 40)
6494  {
6495  // median of three for small chunks
6496  median3(first, middle, last, pred);
6497  }
6498  else
6499  {
6500  // median of nine
6501  size_t step = (last - first + 1) / 8;
6502 
6503  median3(first, first + step, first + 2 * step, pred);
6504  median3(middle - step, middle, middle + step, pred);
6505  median3(last - 2 * step, last - step, last, pred);
6506  median3(first + step, middle, last - step, pred);
6507  }
6508 }
6509 
6510 template <typename I, typename Pred>
6511 void sort(I begin, I end, const Pred &pred)
6512 {
6513  // sort large chunks
6514  while (end - begin > 32)
6515  {
6516  // find median element
6517  I middle = begin + (end - begin) / 2;
6518  median(begin, middle, end - 1, pred);
6519 
6520  // partition in three chunks (< = >)
6521  I eqbeg, eqend;
6522  partition(begin, middle, end, pred, &eqbeg, &eqend);
6523 
6524  // loop on larger half
6525  if (eqbeg - begin > end - eqend)
6526  {
6527  sort(eqend, end, pred);
6528  end = eqbeg;
6529  }
6530  else
6531  {
6532  sort(begin, eqbeg, pred);
6533  begin = eqend;
6534  }
6535  }
6536 
6537  // insertion sort small chunk
6538  if (begin != end)
6539  insertion_sort(begin, end, pred, &*begin);
6540 }
6542 
6543 // Allocator used for AST and evaluation stacks
6546 {
6548 
6549  char data[
6550 #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
6551  PUGIXML_MEMORY_XPATH_PAGE_SIZE
6552 #else
6553  4096
6554 #endif
6555  ];
6556 };
6557 
6559 {
6561  size_t _root_size;
6562 
6563  public:
6564 #ifdef PUGIXML_NO_EXCEPTIONS
6565  jmp_buf *error_handler;
6566 #endif
6567 
6568  xpath_allocator(xpath_memory_block *root, size_t root_size = 0) : _root(root), _root_size(root_size)
6569  {
6570 #ifdef PUGIXML_NO_EXCEPTIONS
6571  error_handler = 0;
6572 #endif
6573  }
6574 
6575  void *allocate_nothrow(size_t size)
6576  {
6577  const size_t block_capacity = sizeof(_root->data);
6578 
6579  // align size so that we're able to store pointers in subsequent blocks
6580  size = (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
6581 
6582  if (_root_size + size <= block_capacity)
6583  {
6584  void *buf = _root->data + _root_size;
6585  _root_size += size;
6586  return buf;
6587  }
6588  else
6589  {
6590  size_t block_data_size = (size > block_capacity) ? size : block_capacity;
6591  size_t block_size = block_data_size + offsetof(xpath_memory_block, data);
6592 
6593  xpath_memory_block *block = static_cast<xpath_memory_block *>(xml_memory::allocate(block_size));
6594  if (!block)
6595  return 0;
6596 
6597  block->next = _root;
6598 
6599  _root = block;
6600  _root_size = size;
6601 
6602  return block->data;
6603  }
6604  }
6605 
6606  void *allocate(size_t size)
6607  {
6608  void *result = allocate_nothrow(size);
6609 
6610  if (!result)
6611  {
6612 #ifdef PUGIXML_NO_EXCEPTIONS
6613  assert(error_handler);
6614  longjmp(*error_handler, 1);
6615 #else
6616  throw std::bad_alloc();
6617 #endif
6618  }
6619 
6620  return result;
6621  }
6622 
6623  void *reallocate(void *ptr, size_t old_size, size_t new_size)
6624  {
6625  // align size so that we're able to store pointers in subsequent blocks
6626  old_size = (old_size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
6627  new_size = (new_size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
6628 
6629  // we can only reallocate the last object
6630  assert(ptr == 0 || static_cast<char *>(ptr) + old_size == _root->data + _root_size);
6631 
6632  // adjust root size so that we have not allocated the object at all
6633  bool only_object = (_root_size == old_size);
6634 
6635  if (ptr)
6636  _root_size -= old_size;
6637 
6638  // allocate a new version (this will obviously reuse the memory if possible)
6639  void *result = allocate(new_size);
6640  assert(result);
6641 
6642  // we have a new block
6643  if (result != ptr && ptr)
6644  {
6645  // copy old data
6646  assert(new_size >= old_size);
6647  memcpy(result, ptr, old_size);
6648 
6649  // free the previous page if it had no other objects
6650  if (only_object)
6651  {
6652  assert(_root->data == result);
6653  assert(_root->next);
6654 
6655  xpath_memory_block *next = _root->next->next;
6656 
6657  if (next)
6658  {
6659  // deallocate the whole page, unless it was the first one
6661  _root->next = next;
6662  }
6663  }
6664  }
6665 
6666  return result;
6667  }
6668 
6669  void revert(const xpath_allocator &state)
6670  {
6671  // free all new pages
6672  xpath_memory_block *cur = _root;
6673 
6674  while (cur != state._root)
6675  {
6676  xpath_memory_block *next = cur->next;
6677 
6679 
6680  cur = next;
6681  }
6682 
6683  // restore state
6684  _root = state._root;
6685  _root_size = state._root_size;
6686  }
6687 
6688  void release()
6689  {
6690  xpath_memory_block *cur = _root;
6691  assert(cur);
6692 
6693  while (cur->next)
6694  {
6695  xpath_memory_block *next = cur->next;
6696 
6698 
6699  cur = next;
6700  }
6701  }
6702 };
6703 
6705 {
6707 
6709 
6712 };
6713 
6715 {
6718 };
6719 
6721 {
6726 
6727 #ifdef PUGIXML_NO_EXCEPTIONS
6728  jmp_buf error_handler;
6729 #endif
6730 
6732  {
6733  blocks[0].next = blocks[1].next = 0;
6734 
6735  stack.result = &result;
6736  stack.temp = &temp;
6737 
6738 #ifdef PUGIXML_NO_EXCEPTIONS
6739  result.error_handler = temp.error_handler = &error_handler;
6740 #endif
6741  }
6742 
6744  {
6745  result.release();
6746  temp.release();
6747  }
6748 };
6750 
6751 // String class
6754 {
6755  const char_t *_buffer;
6757 
6758  static char_t *duplicate_string(const char_t *string, size_t length, xpath_allocator *alloc)
6759  {
6760  char_t *result = static_cast<char_t *>(alloc->allocate((length + 1) * sizeof(char_t)));
6761  assert(result);
6762 
6763  memcpy(result, string, length * sizeof(char_t));
6764  result[length] = 0;
6765 
6766  return result;
6767  }
6768 
6769  static char_t *duplicate_string(const char_t *string, xpath_allocator *alloc)
6770  {
6771  return duplicate_string(string, strlength(string), alloc);
6772  }
6773 
6774  public:
6776 
6777  explicit xpath_string(const char_t *str, xpath_allocator *alloc)
6778  {
6779  bool empty_ = (*str == 0);
6780 
6781  _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(str, alloc);
6782  _uses_heap = !empty_;
6783  }
6784 
6785  explicit xpath_string(const char_t *str, bool use_heap) : _buffer(str), _uses_heap(use_heap) {}
6786 
6787  xpath_string(const char_t *begin, const char_t *end, xpath_allocator *alloc)
6788  {
6789  assert(begin <= end);
6790 
6791  bool empty_ = (begin == end);
6792 
6793  _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast<size_t>(end - begin), alloc);
6794  _uses_heap = !empty_;
6795  }
6796 
6797  void append(const xpath_string &o, xpath_allocator *alloc)
6798  {
6799  // skip empty sources
6800  if (!*o._buffer)
6801  return;
6802 
6803  // fast append for constant empty target and constant source
6804  if (!*_buffer && !_uses_heap && !o._uses_heap)
6805  {
6806  _buffer = o._buffer;
6807  }
6808  else
6809  {
6810  // need to make heap copy
6811  size_t target_length = strlength(_buffer);
6812  size_t source_length = strlength(o._buffer);
6813  size_t result_length = target_length + source_length;
6814 
6815  // allocate new buffer
6816  char_t *result = static_cast<char_t *>(alloc->reallocate(_uses_heap ? const_cast<char_t *>(_buffer) : 0,
6817  (target_length + 1) * sizeof(char_t),
6818  (result_length + 1) * sizeof(char_t)));
6819  assert(result);
6820 
6821  // append first string to the new buffer in case there was no reallocation
6822  if (!_uses_heap)
6823  memcpy(result, _buffer, target_length * sizeof(char_t));
6824 
6825  // append second string to the new buffer
6826  memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
6827  result[result_length] = 0;
6828 
6829  // finalize
6830  _buffer = result;
6831  _uses_heap = true;
6832  }
6833  }
6834 
6835  const char_t *c_str() const { return _buffer; }
6836 
6837  size_t length() const { return strlength(_buffer); }
6838 
6840  {
6841  // make private heap copy
6842  if (!_uses_heap)
6843  {
6844  _buffer = duplicate_string(_buffer, alloc);
6845  _uses_heap = true;
6846  }
6847 
6848  return const_cast<char_t *>(_buffer);
6849  }
6850 
6851  bool empty() const { return *_buffer == 0; }
6852 
6853  bool operator==(const xpath_string &o) const { return strequal(_buffer, o._buffer); }
6854 
6855  bool operator!=(const xpath_string &o) const { return !strequal(_buffer, o._buffer); }
6856 
6857  bool uses_heap() const { return _uses_heap; }
6858 };
6859 
6861 {
6862  return xpath_string(str, false);
6863 }
6865 
6867 PUGI__FN bool starts_with(const char_t *string, const char_t *pattern)
6868 {
6869  while (*pattern && *string == *pattern)
6870  {
6871  string++;
6872  pattern++;
6873  }
6874 
6875  return *pattern == 0;
6876 }
6877 
6879 {
6880 #ifdef PUGIXML_WCHAR_MODE
6881  return wcschr(s, c);
6882 #else
6883  return strchr(s, c);
6884 #endif
6885 }
6886 
6887 PUGI__FN const char_t *find_substring(const char_t *s, const char_t *p)
6888 {
6889 #ifdef PUGIXML_WCHAR_MODE
6890  // MSVC6 wcsstr bug workaround (if s is empty it always returns 0)
6891  return (*p == 0) ? s : wcsstr(s, p);
6892 #else
6893  return strstr(s, p);
6894 #endif
6895 }
6896 
6897 // Converts symbol to lower case, if it is an ASCII one
6899 {
6900  return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
6901 }
6902 
6903 PUGI__FN xpath_string string_value(const xpath_node &na, xpath_allocator *alloc)
6904 {
6905  if (na.attribute())
6906  return xpath_string_const(na.attribute().value());
6907  else
6908  {
6909  const xml_node &n = na.node();
6910 
6911  switch (n.type())
6912  {
6913  case node_pcdata:
6914  case node_cdata:
6915  case node_comment:
6916  case node_pi:
6917  return xpath_string_const(n.value());
6918 
6919  case node_document:
6920  case node_element:
6921  {
6922  xpath_string result;
6923 
6924  xml_node cur = n.first_child();
6925 
6926  while (cur && cur != n)
6927  {
6928  if (cur.type() == node_pcdata || cur.type() == node_cdata)
6929  result.append(xpath_string_const(cur.value()), alloc);
6930 
6931  if (cur.first_child())
6932  cur = cur.first_child();
6933  else if (cur.next_sibling())
6934  cur = cur.next_sibling();
6935  else
6936  {
6937  while (!cur.next_sibling() && cur != n)
6938  cur = cur.parent();
6939 
6940  if (cur != n)
6941  cur = cur.next_sibling();
6942  }
6943  }
6944 
6945  return result;
6946  }
6947 
6948  default:
6949  return xpath_string();
6950  }
6951  }
6952 }
6953 
6954 PUGI__FN unsigned int node_height(xml_node n)
6955 {
6956  unsigned int result = 0;
6957 
6958  while (n)
6959  {
6960  ++result;
6961  n = n.parent();
6962  }
6963 
6964  return result;
6965 }
6966 
6967 PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh)
6968 {
6969  // normalize heights
6970  for (unsigned int i = rh; i < lh; i++)
6971  ln = ln.parent();
6972  for (unsigned int j = lh; j < rh; j++)
6973  rn = rn.parent();
6974 
6975  // one node is the ancestor of the other
6976  if (ln == rn)
6977  return lh < rh;
6978 
6979  // find common ancestor
6980  while (ln.parent() != rn.parent())
6981  {
6982  ln = ln.parent();
6983  rn = rn.parent();
6984  }
6985 
6986  // there is no common ancestor (the shared parent is null), nodes are from different documents
6987  if (!ln.parent())
6988  return ln < rn;
6989 
6990  // determine sibling order
6991  for (; ln; ln = ln.next_sibling())
6992  if (ln == rn)
6993  return true;
6994 
6995  return false;
6996 }
6997 
6998 PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node)
6999 {
7000  while (node && node != parent)
7001  node = node.parent();
7002 
7003  return parent && node == parent;
7004 }
7005 
7006 PUGI__FN const void *document_order(const xpath_node &xnode)
7007 {
7008  xml_node_struct *node = xnode.node().internal_object();
7009 
7010  if (node)
7011  {
7012  if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0)
7013  return node->name;
7014  if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0)
7015  return node->value;
7016  return 0;
7017  }
7018 
7019  xml_attribute_struct *attr = xnode.attribute().internal_object();
7020 
7021  if (attr)
7022  {
7023  if ((attr->header & xml_memory_page_name_allocated_mask) == 0)
7024  return attr->name;
7025  if ((attr->header & xml_memory_page_value_allocated_mask) == 0)
7026  return attr->value;
7027  return 0;
7028  }
7029 
7030  return 0;
7031 }
7032 
7034 {
7035  bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
7036  {
7037  // optimized document order based check
7038  const void *lo = document_order(lhs);
7039  const void *ro = document_order(rhs);
7040 
7041  if (lo && ro)
7042  return lo < ro;
7043 
7044  // slow comparison
7045  xml_node ln = lhs.node(), rn = rhs.node();
7046 
7047  // compare attributes
7048  if (lhs.attribute() && rhs.attribute())
7049  {
7050  // shared parent
7051  if (lhs.parent() == rhs.parent())
7052  {
7053  // determine sibling order
7054  for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
7055  if (a == rhs.attribute())
7056  return true;
7057 
7058  return false;
7059  }
7060 
7061  // compare attribute parents
7062  ln = lhs.parent();
7063  rn = rhs.parent();
7064  }
7065  else if (lhs.attribute())
7066  {
7067  // attributes go after the parent element
7068  if (lhs.parent() == rhs.node())
7069  return false;
7070 
7071  ln = lhs.parent();
7072  }
7073  else if (rhs.attribute())
7074  {
7075  // attributes go after the parent element
7076  if (rhs.parent() == lhs.node())
7077  return true;
7078 
7079  rn = rhs.parent();
7080  }
7081 
7082  if (ln == rn)
7083  return false;
7084 
7085  unsigned int lh = node_height(ln);
7086  unsigned int rh = node_height(rn);
7087 
7088  return node_is_before(ln, lh, rn, rh);
7089  }
7090 };
7091 
7093 {
7094  bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
7095  {
7096  if (lhs.attribute())
7097  return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true;
7098  else
7099  return rhs.attribute() ? false : lhs.node() < rhs.node();
7100  }
7101 };
7102 
7104 {
7105 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
7106  union {
7107  float f;
7108  uint32_t i;
7109  } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1];
7110  u[0].i = 0x7fc00000;
7111  return u[0].f;
7112 #else
7113  // fallback
7114  const volatile double zero = 0.0;
7115  return zero / zero;
7116 #endif
7117 }
7118 
7119 PUGI__FN bool is_nan(double value)
7120 {
7121 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
7122  return !!_isnan(value);
7123 #elif defined(fpclassify) && defined(FP_NAN)
7124  return fpclassify(value) == FP_NAN;
7125 #else
7126  // fallback
7127  const volatile double v = value;
7128  return v != v;
7129 #endif
7130 }
7131 
7133 {
7134 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
7135  if (_finite(value))
7136  return (value == 0) ? PUGIXML_TEXT("0") : 0;
7137  if (_isnan(value))
7138  return PUGIXML_TEXT("NaN");
7139  return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
7140 #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
7141  switch (fpclassify(value))
7142  {
7143  case FP_NAN:
7144  return PUGIXML_TEXT("NaN");
7145 
7146  case FP_INFINITE:
7147  return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
7148 
7149  case FP_ZERO:
7150  return PUGIXML_TEXT("0");
7151 
7152  default:
7153  return 0;
7154  }
7155 #else
7156  // fallback
7157  const volatile double v = value;
7158 
7159  if (v == 0)
7160  return PUGIXML_TEXT("0");
7161  if (v != v)
7162  return PUGIXML_TEXT("NaN");
7163  if (v * 2 == v)
7164  return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
7165  return 0;
7166 #endif
7167 }
7168 
7170 {
7171  return (value != 0 && !is_nan(value));
7172 }
7173 
7174 PUGI__FN void truncate_zeros(char *begin, char *end)
7175 {
7176  while (begin != end && end[-1] == '0')
7177  end--;
7178 
7179  *end = 0;
7180 }
7181 
7182 // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
7183 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
7184 PUGI__FN void convert_number_to_mantissa_exponent(double value, char *buffer, size_t buffer_size, char **out_mantissa,
7185  int *out_exponent)
7186 {
7187  // get base values
7188  int sign, exponent;
7189  _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign);
7190 
7191  // truncate redundant zeros
7192  truncate_zeros(buffer, buffer + strlen(buffer));
7193 
7194  // fill results
7195  *out_mantissa = buffer;
7196  *out_exponent = exponent;
7197 }
7198 #else
7199 PUGI__FN void convert_number_to_mantissa_exponent(double value, char *buffer, size_t buffer_size, char **out_mantissa,
7200  int *out_exponent)
7201 {
7202  // get a scientific notation value with IEEE DBL_DIG decimals
7203  sprintf(buffer, "%.*e", DBL_DIG, value);
7204  assert(strlen(buffer) < buffer_size);
7205  (void)!buffer_size;
7206 
7207  // get the exponent (possibly negative)
7208  char *exponent_string = strchr(buffer, 'e');
7209  assert(exponent_string);
7210 
7211  int exponent = atoi(exponent_string + 1);
7212 
7213  // extract mantissa string: skip sign
7214  char *mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
7215  assert(mantissa[0] != '0' && mantissa[1] == '.');
7216 
7217  // divide mantissa by 10 to eliminate integer part
7218  mantissa[1] = mantissa[0];
7219  mantissa++;
7220  exponent++;
7221 
7222  // remove extra mantissa digits and zero-terminate mantissa
7223  truncate_zeros(mantissa, exponent_string);
7224 
7225  // fill results
7226  *out_mantissa = mantissa;
7227  *out_exponent = exponent;
7228 }
7229 #endif
7230 
7232 {
7233  // try special number conversion
7234  const char_t *special = convert_number_to_string_special(value);
7235  if (special)
7236  return xpath_string_const(special);
7237 
7238  // get mantissa + exponent form
7239  char mantissa_buffer[32];
7240 
7241  char *mantissa;
7242  int exponent;
7243  convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent);
7244 
7245  // allocate a buffer of suitable length for the number
7246  size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
7247  char_t *result = static_cast<char_t *>(alloc->allocate(sizeof(char_t) * result_size));
7248  assert(result);
7249 
7250  // make the number!
7251  char_t *s = result;
7252 
7253  // sign
7254  if (value < 0)
7255  *s++ = '-';
7256 
7257  // integer part
7258  if (exponent <= 0)
7259  {
7260  *s++ = '0';
7261  }
7262  else
7263  {
7264  while (exponent > 0)
7265  {
7266  assert(*mantissa == 0 || static_cast<unsigned int>(static_cast<unsigned int>(*mantissa) - '0') <= 9);
7267  *s++ = *mantissa ? *mantissa++ : '0';
7268  exponent--;
7269  }
7270  }
7271 
7272  // fractional part
7273  if (*mantissa)
7274  {
7275  // decimal point
7276  *s++ = '.';
7277 
7278  // extra zeroes from negative exponent
7279  while (exponent < 0)
7280  {
7281  *s++ = '0';
7282  exponent++;
7283  }
7284 
7285  // extra mantissa digits
7286  while (*mantissa)
7287  {
7288  assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
7289  *s++ = *mantissa++;
7290  }
7291  }
7292 
7293  // zero-terminate
7294  assert(s < result + result_size);
7295  *s = 0;
7296 
7297  return xpath_string(result, true);
7298 }
7299 
7301 {
7302  // parse leading whitespace
7303  while (PUGI__IS_CHARTYPE(*string, ct_space))
7304  ++string;
7305 
7306  // parse sign
7307  if (*string == '-')
7308  ++string;
7309 
7310  if (!*string)
7311  return false;
7312 
7313  // if there is no integer part, there should be a decimal part with at least one digit
7314  if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit)))
7315  return false;
7316 
7317  // parse integer part
7318  while (PUGI__IS_CHARTYPEX(*string, ctx_digit))
7319  ++string;
7320 
7321  // parse decimal part
7322  if (*string == '.')
7323  {
7324  ++string;
7325 
7326  while (PUGI__IS_CHARTYPEX(*string, ctx_digit))
7327  ++string;
7328  }
7329 
7330  // parse trailing whitespace
7331  while (PUGI__IS_CHARTYPE(*string, ct_space))
7332  ++string;
7333 
7334  return *string == 0;
7335 }
7336 
7338 {
7339  // check string format
7340  if (!check_string_to_number_format(string))
7341  return gen_nan();
7342 
7343  // parse string
7344 #ifdef PUGIXML_WCHAR_MODE
7345  return wcstod(string, 0);
7346 #else
7347  return atof(string);
7348 #endif
7349 }
7350 
7351 PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t *begin, const char_t *end,
7352  double *out_result)
7353 {
7354  size_t length = static_cast<size_t>(end - begin);
7355  char_t *scratch = buffer;
7356 
7357  if (length >= sizeof(buffer) / sizeof(buffer[0]))
7358  {
7359  // need to make dummy on-heap copy
7360  scratch = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
7361  if (!scratch)
7362  return false;
7363  }
7364 
7365  // copy string to zero-terminated buffer and perform conversion
7366  memcpy(scratch, begin, length * sizeof(char_t));
7367  scratch[length] = 0;
7368 
7369  *out_result = convert_string_to_number(scratch);
7370 
7371  // free dummy buffer
7372  if (scratch != buffer)
7373  xml_memory::deallocate(scratch);
7374 
7375  return true;
7376 }
7377 
7378 PUGI__FN double round_nearest(double value)
7379 {
7380  return floor(value + 0.5);
7381 }
7382 
7383 PUGI__FN double round_nearest_nzero(double value)
7384 {
7385  // same as round_nearest, but returns -0 for [-0.5, -0]
7386  // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)
7387  return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
7388 }
7389 
7390 PUGI__FN const char_t *qualified_name(const xpath_node &node)
7391 {
7392  return node.attribute() ? node.attribute().name() : node.node().name();
7393 }
7394 
7395 PUGI__FN const char_t *local_name(const xpath_node &node)
7396 {
7397  const char_t *name = qualified_name(node);
7398  const char_t *p = find_char(name, ':');
7399 
7400  return p ? p + 1 : name;
7401 }
7402 
7404 {
7405  const char_t *prefix;
7407 
7409  {
7410  const char_t *pos = find_char(name, ':');
7411 
7412  prefix = pos ? name : 0;
7413  prefix_length = pos ? static_cast<size_t>(pos - name) : 0;
7414  }
7415 
7416  bool operator()(const xml_attribute &a) const
7417  {
7418  const char_t *name = a.name();
7419 
7420  if (!starts_with(name, PUGIXML_TEXT("xmlns")))
7421  return false;
7422 
7423  return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
7424  }
7425 };
7426 
7427 PUGI__FN const char_t *namespace_uri(const xml_node &node)
7428 {
7429  namespace_uri_predicate pred = node.name();
7430 
7431  xml_node p = node;
7432 
7433  while (p)
7434  {
7435  xml_attribute a = p.find_attribute(pred);
7436 
7437  if (a)
7438  return a.value();
7439 
7440  p = p.parent();
7441  }
7442 
7443  return PUGIXML_TEXT("");
7444 }
7445 
7446 PUGI__FN const char_t *namespace_uri(const xml_attribute &attr, const xml_node &parent)
7447 {
7448  namespace_uri_predicate pred = attr.name();
7449 
7450  // Default namespace does not apply to attributes
7451  if (!pred.prefix)
7452  return PUGIXML_TEXT("");
7453 
7454  xml_node p = parent;
7455 
7456  while (p)
7457  {
7458  xml_attribute a = p.find_attribute(pred);
7459 
7460  if (a)
7461  return a.value();
7462 
7463  p = p.parent();
7464  }
7465 
7466  return PUGIXML_TEXT("");
7467 }
7468 
7469 PUGI__FN const char_t *namespace_uri(const xpath_node &node)
7470 {
7471  return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
7472 }
7473 
7475 {
7476  char_t *write = buffer;
7477 
7478  for (char_t *it = buffer; *it;)
7479  {
7480  char_t ch = *it++;
7481 
7482  if (PUGI__IS_CHARTYPE(ch, ct_space))
7483  {
7484  // replace whitespace sequence with single space
7485  while (PUGI__IS_CHARTYPE(*it, ct_space))
7486  it++;
7487 
7488  // avoid leading spaces
7489  if (write != buffer)
7490  *write++ = ' ';
7491  }
7492  else
7493  *write++ = ch;
7494  }
7495 
7496  // remove trailing space
7497  if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space))
7498  write--;
7499 
7500  // zero-terminate
7501  *write = 0;
7502 }
7503 
7504 PUGI__FN void translate(char_t *buffer, const char_t *from, const char_t *to)
7505 {
7506  size_t to_length = strlength(to);
7507 
7508  char_t *write = buffer;
7509 
7510  while (*buffer)
7511  {
7512  PUGI__DMC_VOLATILE char_t ch = *buffer++;
7513 
7514  const char_t *pos = find_char(from, ch);
7515 
7516  if (!pos)
7517  *write++ = ch; // do not process
7518  else if (static_cast<size_t>(pos - from) < to_length)
7519  *write++ = to[pos - from]; // replace
7520  }
7521 
7522  // zero-terminate
7523  *write = 0;
7524 }
7525 
7527 {
7529 
7530  bool value;
7532 };
7533 
7535 {
7537 
7538  double value;
7540 };
7541 
7543 {
7545 
7547  {
7548  if (value)
7550  }
7551 
7554 };
7555 
7557 {
7558  xpath_node_set value;
7560 };
7561 
7562 static const xpath_node_set dummy_node_set;
7563 
7564 PUGI__FN unsigned int hash_string(const char_t *str)
7565 {
7566  // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
7567  unsigned int result = 0;
7568 
7569  while (*str)
7570  {
7571  result += static_cast<unsigned int>(*str++);
7572  result += result << 10;
7573  result ^= result >> 6;
7574  }
7575 
7576  result += result << 3;
7577  result ^= result >> 11;
7578  result += result << 15;
7579 
7580  return result;
7581 }
7582 
7583 template <typename T>
7585 {
7586  size_t length = strlength(name);
7587  if (length == 0)
7588  return 0; // empty variable names are invalid
7589 
7590  // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
7591  void *memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));
7592  if (!memory)
7593  return 0;
7594 
7595  T *result = new (memory) T();
7596 
7597  memcpy(result->name, name, (length + 1) * sizeof(char_t));
7598 
7599  return result;
7600 }
7601 
7603 {
7604  switch (type)
7605  {
7606  case xpath_type_node_set:
7607  return new_xpath_variable<xpath_variable_node_set>(name);
7608 
7609  case xpath_type_number:
7610  return new_xpath_variable<xpath_variable_number>(name);
7611 
7612  case xpath_type_string:
7613  return new_xpath_variable<xpath_variable_string>(name);
7614 
7615  case xpath_type_boolean:
7616  return new_xpath_variable<xpath_variable_boolean>(name);
7617 
7618  default:
7619  return 0;
7620  }
7621 }
7622 
7623 template <typename T>
7625 {
7626  var->~T();
7628 }
7629 
7631 {
7632  switch (type)
7633  {
7634  case xpath_type_node_set:
7635  delete_xpath_variable(static_cast<xpath_variable_node_set *>(var));
7636  break;
7637 
7638  case xpath_type_number:
7639  delete_xpath_variable(static_cast<xpath_variable_number *>(var));
7640  break;
7641 
7642  case xpath_type_string:
7643  delete_xpath_variable(static_cast<xpath_variable_string *>(var));
7644  break;
7645 
7646  case xpath_type_boolean:
7647  delete_xpath_variable(static_cast<xpath_variable_boolean *>(var));
7648  break;
7649 
7650  default:
7651  assert(!"Invalid variable type");
7652  }
7653 }
7654 
7655 PUGI__FN xpath_variable *get_variable_scratch(char_t (&buffer)[32], xpath_variable_set *set, const char_t *begin,
7656  const char_t *end)
7657 {
7658  size_t length = static_cast<size_t>(end - begin);
7659  char_t *scratch = buffer;
7660 
7661  if (length >= sizeof(buffer) / sizeof(buffer[0]))
7662  {
7663  // need to make dummy on-heap copy
7664  scratch = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
7665  if (!scratch)
7666  return 0;
7667  }
7668 
7669  // copy string to zero-terminated buffer and perform lookup
7670  memcpy(scratch, begin, length * sizeof(char_t));
7671  scratch[length] = 0;
7672 
7673  xpath_variable *result = set->get(scratch);
7674 
7675  // free dummy buffer
7676  if (scratch != buffer)
7677  xml_memory::deallocate(scratch);
7678 
7679  return result;
7680 }
7682 
7683 // Internal node set class
7685 PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node *begin, xpath_node *end, xpath_node_set::type_t type, bool rev)
7686 {
7687  xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
7688 
7689  if (type == xpath_node_set::type_unsorted)
7690  {
7691  sort(begin, end, document_order_comparator());
7692 
7693  type = xpath_node_set::type_sorted;
7694  }
7695 
7696  if (type != order)
7697  reverse(begin, end);
7698 
7699  return order;
7700 }
7701 
7702 PUGI__FN xpath_node xpath_first(const xpath_node *begin, const xpath_node *end, xpath_node_set::type_t type)
7703 {
7704  if (begin == end)
7705  return xpath_node();
7706 
7707  switch (type)
7708  {
7709  case xpath_node_set::type_sorted:
7710  return *begin;
7711 
7712  case xpath_node_set::type_sorted_reverse:
7713  return *(end - 1);
7714 
7715  case xpath_node_set::type_unsorted:
7716  return *min_element(begin, end, document_order_comparator());
7717 
7718  default:
7719  assert(!"Invalid node set type");
7720  return xpath_node();
7721  }
7722 }
7723 
7725 {
7726  xpath_node_set::type_t _type;
7727 
7728  xpath_node *_begin;
7729  xpath_node *_end;
7730  xpath_node *_eos;
7731 
7732  public:
7733  xpath_node_set_raw() : _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) {}
7734 
7735  xpath_node *begin() const { return _begin; }
7736 
7737  xpath_node *end() const { return _end; }
7738 
7739  bool empty() const { return _begin == _end; }
7740 
7741  size_t size() const { return static_cast<size_t>(_end - _begin); }
7742 
7743  xpath_node first() const { return xpath_first(_begin, _end, _type); }
7744 
7745  void push_back(const xpath_node &node, xpath_allocator *alloc)
7746  {
7747  if (_end == _eos)
7748  {
7749  size_t capacity = static_cast<size_t>(_eos - _begin);
7750 
7751  // get new capacity (1.5x rule)
7752  size_t new_capacity = capacity + capacity / 2 + 1;
7753 
7754  // reallocate the old array or allocate a new one
7755  xpath_node *data = static_cast<xpath_node *>(
7756  alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
7757  assert(data);
7758 
7759  // finalize
7760  _begin = data;
7761  _end = data + capacity;
7762  _eos = data + new_capacity;
7763  }
7764 
7765  *_end++ = node;
7766  }
7767 
7768  void append(const xpath_node *begin_, const xpath_node *end_, xpath_allocator *alloc)
7769  {
7770  size_t size_ = static_cast<size_t>(_end - _begin);
7771  size_t capacity = static_cast<size_t>(_eos - _begin);
7772  size_t count = static_cast<size_t>(end_ - begin_);
7773 
7774  if (size_ + count > capacity)
7775  {
7776  // reallocate the old array or allocate a new one
7777  xpath_node *data = static_cast<xpath_node *>(
7778  alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
7779  assert(data);
7780 
7781  // finalize
7782  _begin = data;
7783  _end = data + size_;
7784  _eos = data + size_ + count;
7785  }
7786 
7787  memcpy(_end, begin_, count * sizeof(xpath_node));
7788  _end += count;
7789  }
7790 
7791  void sort_do() { _type = xpath_sort(_begin, _end, _type, false); }
7792 
7793  void truncate(xpath_node *pos)
7794  {
7795  assert(_begin <= pos && pos <= _end);
7796 
7797  _end = pos;
7798  }
7799 
7801  {
7802  if (_type == xpath_node_set::type_unsorted)
7804 
7805  _end = unique(_begin, _end);
7806  }
7807 
7808  xpath_node_set::type_t type() const { return _type; }
7809 
7810  void set_type(xpath_node_set::type_t value) { _type = value; }
7811 };
7813 
7816 {
7817  xpath_node n;
7818  size_t position, size;
7819 
7820  xpath_context(const xpath_node &n_, size_t position_, size_t size_) : n(n_), position(position_), size(size_) {}
7821 };
7822 
7824 {
7851  lex_eof
7852 };
7853 
7855 {
7856  const char_t *begin;
7857  const char_t *end;
7858 
7860 
7861  bool operator==(const char_t *other) const
7862  {
7863  size_t length = static_cast<size_t>(end - begin);
7864 
7865  return strequalrange(other, begin, length);
7866  }
7867 };
7868 
7870 {
7871  const char_t *_cur;
7874 
7876 
7877  public:
7878  explicit xpath_lexer(const char_t *query) : _cur(query) { next(); }
7879 
7880  const char_t *state() const { return _cur; }
7881 
7882  void next()
7883  {
7884  const char_t *cur = _cur;
7885 
7886  while (PUGI__IS_CHARTYPE(*cur, ct_space))
7887  ++cur;
7888 
7889  // save lexeme position for error reporting
7890  _cur_lexeme_pos = cur;
7891 
7892  switch (*cur)
7893  {
7894  case 0:
7895  _cur_lexeme = lex_eof;
7896  break;
7897 
7898  case '>':
7899  if (*(cur + 1) == '=')
7900  {
7901  cur += 2;
7903  }
7904  else
7905  {
7906  cur += 1;
7908  }
7909  break;
7910 
7911  case '<':
7912  if (*(cur + 1) == '=')
7913  {
7914  cur += 2;
7916  }
7917  else
7918  {
7919  cur += 1;
7921  }
7922  break;
7923 
7924  case '!':
7925  if (*(cur + 1) == '=')
7926  {
7927  cur += 2;
7929  }
7930  else
7931  {
7933  }
7934  break;
7935 
7936  case '=':
7937  cur += 1;
7939 
7940  break;
7941 
7942  case '+':
7943  cur += 1;
7945 
7946  break;
7947 
7948  case '-':
7949  cur += 1;
7951 
7952  break;
7953 
7954  case '*':
7955  cur += 1;
7957 
7958  break;
7959 
7960  case '|':
7961  cur += 1;
7963 
7964  break;
7965 
7966  case '$':
7967  cur += 1;
7968 
7970  {
7972 
7973  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol))
7974  cur++;
7975 
7976  if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
7977  {
7978  cur++; // :
7979 
7980  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol))
7981  cur++;
7982  }
7983 
7984  _cur_lexeme_contents.end = cur;
7985 
7987  }
7988  else
7989  {
7991  }
7992 
7993  break;
7994 
7995  case '(':
7996  cur += 1;
7998 
7999  break;
8000 
8001  case ')':
8002  cur += 1;
8004 
8005  break;
8006 
8007  case '[':
8008  cur += 1;
8010 
8011  break;
8012 
8013  case ']':
8014  cur += 1;
8016 
8017  break;
8018 
8019  case ',':
8020  cur += 1;
8022 
8023  break;
8024 
8025  case '/':
8026  if (*(cur + 1) == '/')
8027  {
8028  cur += 2;
8030  }
8031  else
8032  {
8033  cur += 1;
8035  }
8036  break;
8037 
8038  case '.':
8039  if (*(cur + 1) == '.')
8040  {
8041  cur += 2;
8043  }
8044  else if (PUGI__IS_CHARTYPEX(*(cur + 1), ctx_digit))
8045  {
8046  _cur_lexeme_contents.begin = cur; // .
8047 
8048  ++cur;
8049 
8050  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
8051  cur++;
8052 
8053  _cur_lexeme_contents.end = cur;
8054 
8056  }
8057  else
8058  {
8059  cur += 1;
8060  _cur_lexeme = lex_dot;
8061  }
8062  break;
8063 
8064  case '@':
8065  cur += 1;
8067 
8068  break;
8069 
8070  case '"':
8071  case '\'':
8072  {
8073  char_t terminator = *cur;
8074 
8075  ++cur;
8076 
8078  while (*cur && *cur != terminator)
8079  cur++;
8080  _cur_lexeme_contents.end = cur;
8081 
8082  if (!*cur)
8084  else
8085  {
8086  cur += 1;
8088  }
8089 
8090  break;
8091  }
8092 
8093  case ':':
8094  if (*(cur + 1) == ':')
8095  {
8096  cur += 2;
8098  }
8099  else
8100  {
8102  }
8103  break;
8104 
8105  default:
8106  if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
8107  {
8109 
8110  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
8111  cur++;
8112 
8113  if (*cur == '.')
8114  {
8115  cur++;
8116 
8117  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
8118  cur++;
8119  }
8120 
8121  _cur_lexeme_contents.end = cur;
8122 
8124  }
8125  else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
8126  {
8128 
8129  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol))
8130  cur++;
8131 
8132  if (cur[0] == ':')
8133  {
8134  if (cur[1] == '*') // namespace test ncname:*
8135  {
8136  cur += 2; // :*
8137  }
8138  else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
8139  {
8140  cur++; // :
8141 
8142  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol))
8143  cur++;
8144  }
8145  }
8146 
8147  _cur_lexeme_contents.end = cur;
8148 
8150  }
8151  else
8152  {
8154  }
8155  }
8156 
8157  _cur = cur;
8158  }
8159 
8160  lexeme_t current() const { return _cur_lexeme; }
8161 
8162  const char_t *current_pos() const { return _cur_lexeme_pos; }
8163 
8165  {
8168 
8169  return _cur_lexeme_contents;
8170  }
8171 };
8172 
8174 {
8176  ast_op_or, // left or right
8177  ast_op_and, // left and right
8178  ast_op_equal, // left = right
8179  ast_op_not_equal, // left != right
8180  ast_op_less, // left < right
8181  ast_op_greater, // left > right
8182  ast_op_less_or_equal, // left <= right
8183  ast_op_greater_or_equal, // left >= right
8184  ast_op_add, // left + right
8185  ast_op_subtract, // left - right
8186  ast_op_multiply, // left * right
8187  ast_op_divide, // left / right
8188  ast_op_mod, // left % right
8189  ast_op_negate, // left - right
8190  ast_op_union, // left | right
8191  ast_predicate, // apply predicate to set; next points to next predicate
8192  ast_filter, // select * from left where right
8193  ast_filter_posinv, // select * from left where right; proximity position invariant
8194  ast_string_constant, // string constant
8195  ast_number_constant, // number constant
8196  ast_variable, // variable
8197  ast_func_last, // last()
8198  ast_func_position, // position()
8199  ast_func_count, // count(left)
8200  ast_func_id, // id(left)
8201  ast_func_local_name_0, // local-name()
8202  ast_func_local_name_1, // local-name(left)
8203  ast_func_namespace_uri_0, // namespace-uri()
8204  ast_func_namespace_uri_1, // namespace-uri(left)
8205  ast_func_name_0, // name()
8206  ast_func_name_1, // name(left)
8207  ast_func_string_0, // string()
8208  ast_func_string_1, // string(left)
8209  ast_func_concat, // concat(left, right, siblings)
8210  ast_func_starts_with, // starts_with(left, right)
8211  ast_func_contains, // contains(left, right)
8212  ast_func_substring_before, // substring-before(left, right)
8213  ast_func_substring_after, // substring-after(left, right)
8214  ast_func_substring_2, // substring(left, right)
8215  ast_func_substring_3, // substring(left, right, third)
8216  ast_func_string_length_0, // string-length()
8217  ast_func_string_length_1, // string-length(left)
8218  ast_func_normalize_space_0, // normalize-space()
8219  ast_func_normalize_space_1, // normalize-space(left)
8220  ast_func_translate, // translate(left, right, third)
8221  ast_func_boolean, // boolean(left)
8222  ast_func_not, // not(left)
8223  ast_func_true, // true()
8224  ast_func_false, // false()
8225  ast_func_lang, // lang(left)
8226  ast_func_number_0, // number()
8227  ast_func_number_1, // number(left)
8228  ast_func_sum, // sum(left)
8229  ast_func_floor, // floor(left)
8230  ast_func_ceiling, // ceiling(left)
8231  ast_func_round, // round(left)
8232  ast_step, // process set left with step
8233  ast_step_root // select root node
8234 };
8235 
8237 {
8250  axis_self
8251 };
8252 
8254 {
8264 };
8265 
8266 template <axis_t N>
8268 {
8269  static const axis_t axis;
8270 };
8271 
8272 template <axis_t N>
8273 const axis_t axis_to_type<N>::axis = N;
8274 
8276 {
8277  private:
8278  // node type
8279  char _type;
8280  char _rettype;
8281 
8282  // for ast_step / ast_predicate
8283  char _axis;
8284  char _test;
8285 
8286  // tree node structure
8290 
8291  union {
8292  // value for ast_string_constant
8293  const char_t *string;
8294  // value for ast_number_constant
8295  double number;
8296  // variable for ast_variable
8298  // node test for ast_step (node name/namespace/node type/pi target)
8301 
8304 
8305  template <class Comp>
8306  static bool compare_eq(xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack,
8307  const Comp &comp)
8308  {
8309  xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
8310 
8311  if (lt != xpath_type_node_set && rt != xpath_type_node_set)
8312  {
8313  if (lt == xpath_type_boolean || rt == xpath_type_boolean)
8314  return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
8315  else if (lt == xpath_type_number || rt == xpath_type_number)
8316  return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
8317  else if (lt == xpath_type_string || rt == xpath_type_string)
8318  {
8319  xpath_allocator_capture cr(stack.result);
8320 
8321  xpath_string ls = lhs->eval_string(c, stack);
8322  xpath_string rs = rhs->eval_string(c, stack);
8323 
8324  return comp(ls, rs);
8325  }
8326  }
8327  else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
8328  {
8329  xpath_allocator_capture cr(stack.result);
8330 
8331  xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
8332  xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8333 
8334  for (const xpath_node *li = ls.begin(); li != ls.end(); ++li)
8335  for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8336  {
8337  xpath_allocator_capture cri(stack.result);
8338 
8339  if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
8340  return true;
8341  }
8342 
8343  return false;
8344  }
8345  else
8346  {
8347  if (lt == xpath_type_node_set)
8348  {
8349  swap(lhs, rhs);
8350  swap(lt, rt);
8351  }
8352 
8353  if (lt == xpath_type_boolean)
8354  return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
8355  else if (lt == xpath_type_number)
8356  {
8357  xpath_allocator_capture cr(stack.result);
8358 
8359  double l = lhs->eval_number(c, stack);
8360  xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8361 
8362  for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8363  {
8364  xpath_allocator_capture cri(stack.result);
8365 
8366  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8367  return true;
8368  }
8369 
8370  return false;
8371  }
8372  else if (lt == xpath_type_string)
8373  {
8374  xpath_allocator_capture cr(stack.result);
8375 
8376  xpath_string l = lhs->eval_string(c, stack);
8377  xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8378 
8379  for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8380  {
8381  xpath_allocator_capture cri(stack.result);
8382 
8383  if (comp(l, string_value(*ri, stack.result)))
8384  return true;
8385  }
8386 
8387  return false;
8388  }
8389  }
8390 
8391  assert(!"Wrong types");
8392  return false;
8393  }
8394 
8395  template <class Comp>
8396  static bool compare_rel(xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack,
8397  const Comp &comp)
8398  {
8399  xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
8400 
8401  if (lt != xpath_type_node_set && rt != xpath_type_node_set)
8402  return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
8403  else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
8404  {
8405  xpath_allocator_capture cr(stack.result);
8406 
8407  xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
8408  xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8409 
8410  for (const xpath_node *li = ls.begin(); li != ls.end(); ++li)
8411  {
8412  xpath_allocator_capture cri(stack.result);
8413 
8414  double l = convert_string_to_number(string_value(*li, stack.result).c_str());
8415 
8416  for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8417  {
8418  xpath_allocator_capture crii(stack.result);
8419 
8420  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8421  return true;
8422  }
8423  }
8424 
8425  return false;
8426  }
8427  else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
8428  {
8429  xpath_allocator_capture cr(stack.result);
8430 
8431  double l = lhs->eval_number(c, stack);
8432  xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8433 
8434  for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8435  {
8436  xpath_allocator_capture cri(stack.result);
8437 
8438  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8439  return true;
8440  }
8441 
8442  return false;
8443  }
8444  else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
8445  {
8446  xpath_allocator_capture cr(stack.result);
8447 
8448  xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
8449  double r = rhs->eval_number(c, stack);
8450 
8451  for (const xpath_node *li = ls.begin(); li != ls.end(); ++li)
8452  {
8453  xpath_allocator_capture cri(stack.result);
8454 
8455  if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
8456  return true;
8457  }
8458 
8459  return false;
8460  }
8461  else
8462  {
8463  assert(!"Wrong types");
8464  return false;
8465  }
8466  }
8467 
8468  void apply_predicate(xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack)
8469  {
8470  assert(ns.size() >= first);
8471 
8472  size_t i = 1;
8473  size_t size = ns.size() - first;
8474 
8475  xpath_node *last = ns.begin() + first;
8476 
8477  // remove_if... or well, sort of
8478  for (xpath_node *it = last; it != ns.end(); ++it, ++i)
8479  {
8480  xpath_context c(*it, i, size);
8481 
8482  if (expr->rettype() == xpath_type_number)
8483  {
8484  if (expr->eval_number(c, stack) == i)
8485  *last++ = *it;
8486  }
8487  else if (expr->eval_boolean(c, stack))
8488  *last++ = *it;
8489  }
8490 
8491  ns.truncate(last);
8492  }
8493 
8494  void apply_predicates(xpath_node_set_raw &ns, size_t first, const xpath_stack &stack)
8495  {
8496  if (ns.size() == first)
8497  return;
8498 
8499  for (xpath_ast_node *pred = _right; pred; pred = pred->_next)
8500  {
8501  apply_predicate(ns, first, pred->_left, stack);
8502  }
8503  }
8504 
8505  void step_push(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &parent, xpath_allocator *alloc)
8506  {
8507  if (!a)
8508  return;
8509 
8510  const char_t *name = a.name();
8511 
8512  // There are no attribute nodes corresponding to attributes that declare namespaces
8513  // That is, "xmlns:..." or "xmlns"
8514  if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':'))
8515  return;
8516 
8517  switch (_test)
8518  {
8519  case nodetest_name:
8520  if (strequal(name, _data.nodetest))
8521  ns.push_back(xpath_node(a, parent), alloc);
8522  break;
8523 
8524  case nodetest_type_node:
8525  case nodetest_all:
8526  ns.push_back(xpath_node(a, parent), alloc);
8527  break;
8528 
8530  if (starts_with(name, _data.nodetest))
8531  ns.push_back(xpath_node(a, parent), alloc);
8532  break;
8533 
8534  default:;
8535  }
8536  }
8537 
8538  void step_push(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc)
8539  {
8540  if (!n)
8541  return;
8542 
8543  switch (_test)
8544  {
8545  case nodetest_name:
8546  if (n.type() == node_element && strequal(n.name(), _data.nodetest))
8547  ns.push_back(n, alloc);
8548  break;
8549 
8550  case nodetest_type_node:
8551  ns.push_back(n, alloc);
8552  break;
8553 
8554  case nodetest_type_comment:
8555  if (n.type() == node_comment)
8556  ns.push_back(n, alloc);
8557  break;
8558 
8559  case nodetest_type_text:
8560  if (n.type() == node_pcdata || n.type() == node_cdata)
8561  ns.push_back(n, alloc);
8562  break;
8563 
8564  case nodetest_type_pi:
8565  if (n.type() == node_pi)
8566  ns.push_back(n, alloc);
8567  break;
8568 
8569  case nodetest_pi:
8570  if (n.type() == node_pi && strequal(n.name(), _data.nodetest))
8571  ns.push_back(n, alloc);
8572  break;
8573 
8574  case nodetest_all:
8575  if (n.type() == node_element)
8576  ns.push_back(n, alloc);
8577  break;
8578 
8580  if (n.type() == node_element && starts_with(n.name(), _data.nodetest))
8581  ns.push_back(n, alloc);
8582  break;
8583 
8584  default:
8585  assert(!"Unknown axis");
8586  }
8587  }
8588 
8589  template <class T>
8590  void step_fill(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc, T)
8591  {
8592  const axis_t axis = T::axis;
8593 
8594  switch (axis)
8595  {
8596  case axis_attribute:
8597  {
8598  for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute())
8599  step_push(ns, a, n, alloc);
8600 
8601  break;
8602  }
8603 
8604  case axis_child:
8605  {
8606  for (xml_node c = n.first_child(); c; c = c.next_sibling())
8607  step_push(ns, c, alloc);
8608 
8609  break;
8610  }
8611 
8612  case axis_descendant:
8614  {
8615  if (axis == axis_descendant_or_self)
8616  step_push(ns, n, alloc);
8617 
8618  xml_node cur = n.first_child();
8619 
8620  while (cur && cur != n)
8621  {
8622  step_push(ns, cur, alloc);
8623 
8624  if (cur.first_child())
8625  cur = cur.first_child();
8626  else if (cur.next_sibling())
8627  cur = cur.next_sibling();
8628  else
8629  {
8630  while (!cur.next_sibling() && cur != n)
8631  cur = cur.parent();
8632 
8633  if (cur != n)
8634  cur = cur.next_sibling();
8635  }
8636  }
8637 
8638  break;
8639  }
8640 
8642  {
8643  for (xml_node c = n.next_sibling(); c; c = c.next_sibling())
8644  step_push(ns, c, alloc);
8645 
8646  break;
8647  }
8648 
8650  {
8651  for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling())
8652  step_push(ns, c, alloc);
8653 
8654  break;
8655  }
8656 
8657  case axis_following:
8658  {
8659  xml_node cur = n;
8660 
8661  // exit from this node so that we don't include descendants
8662  while (cur && !cur.next_sibling())
8663  cur = cur.parent();
8664  cur = cur.next_sibling();
8665 
8666  for (;;)
8667  {
8668  step_push(ns, cur, alloc);
8669 
8670  if (cur.first_child())
8671  cur = cur.first_child();
8672  else if (cur.next_sibling())
8673  cur = cur.next_sibling();
8674  else
8675  {
8676  while (cur && !cur.next_sibling())
8677  cur = cur.parent();
8678  cur = cur.next_sibling();
8679 
8680  if (!cur)
8681  break;
8682  }
8683  }
8684 
8685  break;
8686  }
8687 
8688  case axis_preceding:
8689  {
8690  xml_node cur = n;
8691 
8692  while (cur && !cur.previous_sibling())
8693  cur = cur.parent();
8694  cur = cur.previous_sibling();
8695 
8696  for (;;)
8697  {
8698  if (cur.last_child())
8699  cur = cur.last_child();
8700  else
8701  {
8702  // leaf node, can't be ancestor
8703  step_push(ns, cur, alloc);
8704 
8705  if (cur.previous_sibling())
8706  cur = cur.previous_sibling();
8707  else
8708  {
8709  do
8710  {
8711  cur = cur.parent();
8712  if (!cur)
8713  break;
8714 
8715  if (!node_is_ancestor(cur, n))
8716  step_push(ns, cur, alloc);
8717  } while (!cur.previous_sibling());
8718 
8719  cur = cur.previous_sibling();
8720 
8721  if (!cur)
8722  break;
8723  }
8724  }
8725  }
8726 
8727  break;
8728  }
8729 
8730  case axis_ancestor:
8731  case axis_ancestor_or_self:
8732  {
8733  if (axis == axis_ancestor_or_self)
8734  step_push(ns, n, alloc);
8735 
8736  xml_node cur = n.parent();
8737 
8738  while (cur)
8739  {
8740  step_push(ns, cur, alloc);
8741 
8742  cur = cur.parent();
8743  }
8744 
8745  break;
8746  }
8747 
8748  case axis_self:
8749  {
8750  step_push(ns, n, alloc);
8751 
8752  break;
8753  }
8754 
8755  case axis_parent:
8756  {
8757  if (n.parent())
8758  step_push(ns, n.parent(), alloc);
8759 
8760  break;
8761  }
8762 
8763  default:
8764  assert(!"Unimplemented axis");
8765  }
8766  }
8767 
8768  template <class T>
8769  void step_fill(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &p, xpath_allocator *alloc, T v)
8770  {
8771  const axis_t axis = T::axis;
8772 
8773  switch (axis)
8774  {
8775  case axis_ancestor:
8776  case axis_ancestor_or_self:
8777  {
8778  if (axis == axis_ancestor_or_self &&
8779  _test == nodetest_type_node) // reject attributes based on principal node type test
8780  step_push(ns, a, p, alloc);
8781 
8782  xml_node cur = p;
8783 
8784  while (cur)
8785  {
8786  step_push(ns, cur, alloc);
8787 
8788  cur = cur.parent();
8789  }
8790 
8791  break;
8792  }
8793 
8795  case axis_self:
8796  {
8797  if (_test == nodetest_type_node) // reject attributes based on principal node type test
8798  step_push(ns, a, p, alloc);
8799 
8800  break;
8801  }
8802 
8803  case axis_following:
8804  {
8805  xml_node cur = p;
8806 
8807  for (;;)
8808  {
8809  if (cur.first_child())
8810  cur = cur.first_child();
8811  else if (cur.next_sibling())
8812  cur = cur.next_sibling();
8813  else
8814  {
8815  while (cur && !cur.next_sibling())
8816  cur = cur.parent();
8817  cur = cur.next_sibling();
8818 
8819  if (!cur)
8820  break;
8821  }
8822 
8823  step_push(ns, cur, alloc);
8824  }
8825 
8826  break;
8827  }
8828 
8829  case axis_parent:
8830  {
8831  step_push(ns, p, alloc);
8832 
8833  break;
8834  }
8835 
8836  case axis_preceding:
8837  {
8838  // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's
8839  // ancestors), so we can reuse node preceding
8840  step_fill(ns, p, alloc, v);
8841  break;
8842  }
8843 
8844  default:
8845  assert(!"Unimplemented axis");
8846  }
8847  }
8848 
8849  template <class T>
8851  {
8852  const axis_t axis = T::axis;
8853  bool attributes =
8854  (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self ||
8855  axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
8856 
8857  xpath_node_set_raw ns;
8858  ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding ||
8859  axis == axis_preceding_sibling)
8860  ? xpath_node_set::type_sorted_reverse
8861  : xpath_node_set::type_sorted);
8862 
8863  if (_left)
8864  {
8866 
8867  // self axis preserves the original order
8868  if (axis == axis_self)
8869  ns.set_type(s.type());
8870 
8871  for (const xpath_node *it = s.begin(); it != s.end(); ++it)
8872  {
8873  size_t size = ns.size();
8874 
8875  // in general, all axes generate elements in a particular order, but there is no order guarantee if axis
8876  // is applied to two nodes
8877  if (axis != axis_self && size != 0)
8878  ns.set_type(xpath_node_set::type_unsorted);
8879 
8880  if (it->node())
8881  step_fill(ns, it->node(), stack.result, v);
8882  else if (attributes)
8883  step_fill(ns, it->attribute(), it->parent(), stack.result, v);
8884 
8885  apply_predicates(ns, size, stack);
8886  }
8887  }
8888  else
8889  {
8890  if (c.n.node())
8891  step_fill(ns, c.n.node(), stack.result, v);
8892  else if (attributes)
8893  step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v);
8894 
8895  apply_predicates(ns, 0, stack);
8896  }
8897 
8898  // child, attribute and self axes always generate unique set of nodes
8899  // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the
8900  // same node twice
8901  if (axis != axis_child && axis != axis_attribute && axis != axis_self &&
8902  ns.type() == xpath_node_set::type_unsorted)
8903  ns.remove_duplicates();
8904 
8905  return ns;
8906  }
8907 
8908  public:
8910  : _type(static_cast<char>(type))
8911  , _rettype(static_cast<char>(rettype_))
8912  , _axis(0)
8913  , _test(0)
8914  , _left(0)
8915  , _right(0)
8916  , _next(0)
8917  {
8918  assert(type == ast_string_constant);
8919  _data.string = value;
8920  }
8921 
8923  : _type(static_cast<char>(type))
8924  , _rettype(static_cast<char>(rettype_))
8925  , _axis(0)
8926  , _test(0)
8927  , _left(0)
8928  , _right(0)
8929  , _next(0)
8930  {
8931  assert(type == ast_number_constant);
8932  _data.number = value;
8933  }
8934 
8936  : _type(static_cast<char>(type))
8937  , _rettype(static_cast<char>(rettype_))
8938  , _axis(0)
8939  , _test(0)
8940  , _left(0)
8941  , _right(0)
8942  , _next(0)
8943  {
8944  assert(type == ast_variable);
8945  _data.variable = value;
8946  }
8947 
8949  : _type(static_cast<char>(type))
8950  , _rettype(static_cast<char>(rettype_))
8951  , _axis(0)
8952  , _test(0)
8953  , _left(left)
8954  , _right(right)
8955  , _next(0)
8956  {
8957  }
8958 
8959  xpath_ast_node(ast_type_t type, xpath_ast_node *left, axis_t axis, nodetest_t test, const char_t *contents)
8960  : _type(static_cast<char>(type))
8962  , _axis(static_cast<char>(axis))
8963  , _test(static_cast<char>(test))
8964  , _left(left)
8965  , _right(0)
8966  , _next(0)
8967  {
8968  _data.nodetest = contents;
8969  }
8970 
8971  void set_next(xpath_ast_node *value) { _next = value; }
8972 
8973  void set_right(xpath_ast_node *value) { _right = value; }
8974 
8975  bool eval_boolean(const xpath_context &c, const xpath_stack &stack)
8976  {
8977  switch (_type)
8978  {
8979  case ast_op_or:
8980  return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
8981 
8982  case ast_op_and:
8983  return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
8984 
8985  case ast_op_equal:
8986  return compare_eq(_left, _right, c, stack, equal_to());
8987 
8988  case ast_op_not_equal:
8989  return compare_eq(_left, _right, c, stack, not_equal_to());
8990 
8991  case ast_op_less:
8992  return compare_rel(_left, _right, c, stack, less());
8993 
8994  case ast_op_greater:
8995  return compare_rel(_right, _left, c, stack, less());
8996 
8997  case ast_op_less_or_equal:
8998  return compare_rel(_left, _right, c, stack, less_equal());
8999 
9001  return compare_rel(_right, _left, c, stack, less_equal());
9002 
9003  case ast_func_starts_with:
9004  {
9005  xpath_allocator_capture cr(stack.result);
9006 
9007  xpath_string lr = _left->eval_string(c, stack);
9008  xpath_string rr = _right->eval_string(c, stack);
9009 
9010  return starts_with(lr.c_str(), rr.c_str());
9011  }
9012 
9013  case ast_func_contains:
9014  {
9015  xpath_allocator_capture cr(stack.result);
9016 
9017  xpath_string lr = _left->eval_string(c, stack);
9018  xpath_string rr = _right->eval_string(c, stack);
9019 
9020  return find_substring(lr.c_str(), rr.c_str()) != 0;
9021  }
9022 
9023  case ast_func_boolean:
9024  return _left->eval_boolean(c, stack);
9025 
9026  case ast_func_not:
9027  return !_left->eval_boolean(c, stack);
9028 
9029  case ast_func_true:
9030  return true;
9031 
9032  case ast_func_false:
9033  return false;
9034 
9035  case ast_func_lang:
9036  {
9037  if (c.n.attribute())
9038  return false;
9039 
9040  xpath_allocator_capture cr(stack.result);
9041 
9042  xpath_string lang = _left->eval_string(c, stack);
9043 
9044  for (xml_node n = c.n.node(); n; n = n.parent())
9045  {
9046  xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
9047 
9048  if (a)
9049  {
9050  const char_t *value = a.value();
9051 
9052  // strnicmp / strncasecmp is not portable
9053  for (const char_t *lit = lang.c_str(); *lit; ++lit)
9054  {
9055  if (tolower_ascii(*lit) != tolower_ascii(*value))
9056  return false;
9057  ++value;
9058  }
9059 
9060  return *value == 0 || *value == '-';
9061  }
9062  }
9063 
9064  return false;
9065  }
9066 
9067  case ast_variable:
9068  {
9069  assert(_rettype == _data.variable->type());
9070 
9072  return _data.variable->get_boolean();
9073 
9074  // fallthrough to type conversion
9075  }
9076 
9077  default:
9078  {
9079  switch (_rettype)
9080  {
9081  case xpath_type_number:
9082  return convert_number_to_boolean(eval_number(c, stack));
9083 
9084  case xpath_type_string:
9085  {
9086  xpath_allocator_capture cr(stack.result);
9087 
9088  return !eval_string(c, stack).empty();
9089  }
9090 
9091  case xpath_type_node_set:
9092  {
9093  xpath_allocator_capture cr(stack.result);
9094 
9095  return !eval_node_set(c, stack).empty();
9096  }
9097 
9098  default:
9099  assert(!"Wrong expression for return type boolean");
9100  return false;
9101  }
9102  }
9103  }
9104  }
9105 
9106  double eval_number(const xpath_context &c, const xpath_stack &stack)
9107  {
9108  switch (_type)
9109  {
9110  case ast_op_add:
9111  return _left->eval_number(c, stack) + _right->eval_number(c, stack);
9112 
9113  case ast_op_subtract:
9114  return _left->eval_number(c, stack) - _right->eval_number(c, stack);
9115 
9116  case ast_op_multiply:
9117  return _left->eval_number(c, stack) * _right->eval_number(c, stack);
9118 
9119  case ast_op_divide:
9120  return _left->eval_number(c, stack) / _right->eval_number(c, stack);
9121 
9122  case ast_op_mod:
9123  return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
9124 
9125  case ast_op_negate:
9126  return -_left->eval_number(c, stack);
9127 
9128  case ast_number_constant:
9129  return _data.number;
9130 
9131  case ast_func_last:
9132  return static_cast<double>(c.size);
9133 
9134  case ast_func_position:
9135  return static_cast<double>(c.position);
9136 
9137  case ast_func_count:
9138  {
9139  xpath_allocator_capture cr(stack.result);
9140 
9141  return static_cast<double>(_left->eval_node_set(c, stack).size());
9142  }
9143 
9145  {
9146  xpath_allocator_capture cr(stack.result);
9147 
9148  return static_cast<double>(string_value(c.n, stack.result).length());
9149  }
9150 
9152  {
9153  xpath_allocator_capture cr(stack.result);
9154 
9155  return static_cast<double>(_left->eval_string(c, stack).length());
9156  }
9157 
9158  case ast_func_number_0:
9159  {
9160  xpath_allocator_capture cr(stack.result);
9161 
9162  return convert_string_to_number(string_value(c.n, stack.result).c_str());
9163  }
9164 
9165  case ast_func_number_1:
9166  return _left->eval_number(c, stack);
9167 
9168  case ast_func_sum:
9169  {
9170  xpath_allocator_capture cr(stack.result);
9171 
9172  double r = 0;
9173 
9174  xpath_node_set_raw ns = _left->eval_node_set(c, stack);
9175 
9176  for (const xpath_node *it = ns.begin(); it != ns.end(); ++it)
9177  {
9178  xpath_allocator_capture cri(stack.result);
9179 
9180  r += convert_string_to_number(string_value(*it, stack.result).c_str());
9181  }
9182 
9183  return r;
9184  }
9185 
9186  case ast_func_floor:
9187  {
9188  double r = _left->eval_number(c, stack);
9189 
9190  return r == r ? floor(r) : r;
9191  }
9192 
9193  case ast_func_ceiling:
9194  {
9195  double r = _left->eval_number(c, stack);
9196 
9197  return r == r ? ceil(r) : r;
9198  }
9199 
9200  case ast_func_round:
9201  return round_nearest_nzero(_left->eval_number(c, stack));
9202 
9203  case ast_variable:
9204  {
9205  assert(_rettype == _data.variable->type());
9206 
9207  if (_rettype == xpath_type_number)
9208  return _data.variable->get_number();
9209 
9210  // fallthrough to type conversion
9211  }
9212 
9213  default:
9214  {
9215  switch (_rettype)
9216  {
9217  case xpath_type_boolean:
9218  return eval_boolean(c, stack) ? 1 : 0;
9219 
9220  case xpath_type_string:
9221  {
9222  xpath_allocator_capture cr(stack.result);
9223 
9224  return convert_string_to_number(eval_string(c, stack).c_str());
9225  }
9226 
9227  case xpath_type_node_set:
9228  {
9229  xpath_allocator_capture cr(stack.result);
9230 
9231  return convert_string_to_number(eval_string(c, stack).c_str());
9232  }
9233 
9234  default:
9235  assert(!"Wrong expression for return type number");
9236  return 0;
9237  }
9238  }
9239  }
9240  }
9241 
9243  {
9244  assert(_type == ast_func_concat);
9245 
9246  xpath_allocator_capture ct(stack.temp);
9247 
9248  // count the string number
9249  size_t count = 1;
9250  for (xpath_ast_node *nc = _right; nc; nc = nc->_next)
9251  count++;
9252 
9253  // gather all strings
9254  xpath_string static_buffer[4];
9255  xpath_string *buffer = static_buffer;
9256 
9257  // allocate on-heap for large concats
9258  if (count > sizeof(static_buffer) / sizeof(static_buffer[0]))
9259  {
9260  buffer = static_cast<xpath_string *>(stack.temp->allocate(count * sizeof(xpath_string)));
9261  assert(buffer);
9262  }
9263 
9264  // evaluate all strings to temporary stack
9265  xpath_stack swapped_stack = { stack.temp, stack.result };
9266 
9267  buffer[0] = _left->eval_string(c, swapped_stack);
9268 
9269  size_t pos = 1;
9270  for (xpath_ast_node *n = _right; n; n = n->_next, ++pos)
9271  buffer[pos] = n->eval_string(c, swapped_stack);
9272  assert(pos == count);
9273 
9274  // get total length
9275  size_t length = 0;
9276  for (size_t i = 0; i < count; ++i)
9277  length += buffer[i].length();
9278 
9279  // create final string
9280  char_t *result = static_cast<char_t *>(stack.result->allocate((length + 1) * sizeof(char_t)));
9281  assert(result);
9282 
9283  char_t *ri = result;
9284 
9285  for (size_t j = 0; j < count; ++j)
9286  for (const char_t *bi = buffer[j].c_str(); *bi; ++bi)
9287  *ri++ = *bi;
9288 
9289  *ri = 0;
9290 
9291  return xpath_string(result, true);
9292  }
9293 
9295  {
9296  switch (_type)
9297  {
9298  case ast_string_constant:
9299  return xpath_string_const(_data.string);
9300 
9301  case ast_func_local_name_0:
9302  {
9303  xpath_node na = c.n;
9304 
9305  return xpath_string_const(local_name(na));
9306  }
9307 
9308  case ast_func_local_name_1:
9309  {
9310  xpath_allocator_capture cr(stack.result);
9311 
9312  xpath_node_set_raw ns = _left->eval_node_set(c, stack);
9313  xpath_node na = ns.first();
9314 
9315  return xpath_string_const(local_name(na));
9316  }
9317 
9318  case ast_func_name_0:
9319  {
9320  xpath_node na = c.n;
9321 
9322  return xpath_string_const(qualified_name(na));
9323  }
9324 
9325  case ast_func_name_1:
9326  {
9327  xpath_allocator_capture cr(stack.result);
9328 
9329  xpath_node_set_raw ns = _left->eval_node_set(c, stack);
9330  xpath_node na = ns.first();
9331 
9332  return xpath_string_const(qualified_name(na));
9333  }
9334 
9336  {
9337  xpath_node na = c.n;
9338 
9339  return xpath_string_const(namespace_uri(na));
9340  }
9341 
9343  {
9344  xpath_allocator_capture cr(stack.result);
9345 
9346  xpath_node_set_raw ns = _left->eval_node_set(c, stack);
9347  xpath_node na = ns.first();
9348 
9349  return xpath_string_const(namespace_uri(na));
9350  }
9351 
9352  case ast_func_string_0:
9353  return string_value(c.n, stack.result);
9354 
9355  case ast_func_string_1:
9356  return _left->eval_string(c, stack);
9357 
9358  case ast_func_concat:
9359  return eval_string_concat(c, stack);
9360 
9362  {
9363  xpath_allocator_capture cr(stack.temp);
9364 
9365  xpath_stack swapped_stack = { stack.temp, stack.result };
9366 
9367  xpath_string s = _left->eval_string(c, swapped_stack);
9368  xpath_string p = _right->eval_string(c, swapped_stack);
9369 
9370  const char_t *pos = find_substring(s.c_str(), p.c_str());
9371 
9372  return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string();
9373  }
9374 
9376  {
9377  xpath_allocator_capture cr(stack.temp);
9378 
9379  xpath_stack swapped_stack = { stack.temp, stack.result };
9380 
9381  xpath_string s = _left->eval_string(c, swapped_stack);
9382  xpath_string p = _right->eval_string(c, swapped_stack);
9383 
9384  const char_t *pos = find_substring(s.c_str(), p.c_str());
9385  if (!pos)
9386  return xpath_string();
9387 
9388  const char_t *result = pos + p.length();
9389 
9390  return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result);
9391  }
9392 
9393  case ast_func_substring_2:
9394  {
9395  xpath_allocator_capture cr(stack.temp);
9396 
9397  xpath_stack swapped_stack = { stack.temp, stack.result };
9398 
9399  xpath_string s = _left->eval_string(c, swapped_stack);
9400  size_t s_length = s.length();
9401 
9402  double first = round_nearest(_right->eval_number(c, stack));
9403 
9404  if (is_nan(first))
9405  return xpath_string(); // NaN
9406  else if (first >= s_length + 1)
9407  return xpath_string();
9408 
9409  size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
9410  assert(1 <= pos && pos <= s_length + 1);
9411 
9412  const char_t *rbegin = s.c_str() + (pos - 1);
9413 
9414  return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin);
9415  }
9416 
9417  case ast_func_substring_3:
9418  {
9419  xpath_allocator_capture cr(stack.temp);
9420 
9421  xpath_stack swapped_stack = { stack.temp, stack.result };
9422 
9423  xpath_string s = _left->eval_string(c, swapped_stack);
9424  size_t s_length = s.length();
9425 
9426  double first = round_nearest(_right->eval_number(c, stack));
9427  double last = first + round_nearest(_right->_next->eval_number(c, stack));
9428 
9429  if (is_nan(first) || is_nan(last))
9430  return xpath_string();
9431  else if (first >= s_length + 1)
9432  return xpath_string();
9433  else if (first >= last)
9434  return xpath_string();
9435  else if (last < 1)
9436  return xpath_string();
9437 
9438  size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
9439  size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last);
9440 
9441  assert(1 <= pos && pos <= end && end <= s_length + 1);
9442  const char_t *rbegin = s.c_str() + (pos - 1);
9443  const char_t *rend = s.c_str() + (end - 1);
9444 
9445  return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin)
9446  : xpath_string(rbegin, rend, stack.result);
9447  }
9448 
9450  {
9451  xpath_string s = string_value(c.n, stack.result);
9452 
9453  normalize_space(s.data(stack.result));
9454 
9455  return s;
9456  }
9457 
9459  {
9460  xpath_string s = _left->eval_string(c, stack);
9461 
9462  normalize_space(s.data(stack.result));
9463 
9464  return s;
9465  }
9466 
9467  case ast_func_translate:
9468  {
9469  xpath_allocator_capture cr(stack.temp);
9470 
9471  xpath_stack swapped_stack = { stack.temp, stack.result };
9472 
9473  xpath_string s = _left->eval_string(c, stack);
9474  xpath_string from = _right->eval_string(c, swapped_stack);
9475  xpath_string to = _right->_next->eval_string(c, swapped_stack);
9476 
9477  translate(s.data(stack.result), from.c_str(), to.c_str());
9478 
9479  return s;
9480  }
9481 
9482  case ast_variable:
9483  {
9484  assert(_rettype == _data.variable->type());
9485 
9486  if (_rettype == xpath_type_string)
9487  return xpath_string_const(_data.variable->get_string());
9488 
9489  // fallthrough to type conversion
9490  }
9491 
9492  default:
9493  {
9494  switch (_rettype)
9495  {
9496  case xpath_type_boolean:
9497  return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
9498 
9499  case xpath_type_number:
9500  return convert_number_to_string(eval_number(c, stack), stack.result);
9501 
9502  case xpath_type_node_set:
9503  {
9504  xpath_allocator_capture cr(stack.temp);
9505 
9506  xpath_stack swapped_stack = { stack.temp, stack.result };
9507 
9508  xpath_node_set_raw ns = eval_node_set(c, swapped_stack);
9509  return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
9510  }
9511 
9512  default:
9513  assert(!"Wrong expression for return type string");
9514  return xpath_string();
9515  }
9516  }
9517  }
9518  }
9519 
9521  {
9522  switch (_type)
9523  {
9524  case ast_op_union:
9525  {
9526  xpath_allocator_capture cr(stack.temp);
9527 
9528  xpath_stack swapped_stack = { stack.temp, stack.result };
9529 
9530  xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack);
9531  xpath_node_set_raw rs = _right->eval_node_set(c, stack);
9532 
9533  // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
9534  rs.set_type(xpath_node_set::type_unsorted);
9535 
9536  rs.append(ls.begin(), ls.end(), stack.result);
9537  rs.remove_duplicates();
9538 
9539  return rs;
9540  }
9541 
9542  case ast_filter:
9543  case ast_filter_posinv:
9544  {
9545  xpath_node_set_raw set = _left->eval_node_set(c, stack);
9546 
9547  // either expression is a number or it contains position() call; sort by document order
9548  if (_type == ast_filter)
9549  set.sort_do();
9550 
9551  apply_predicate(set, 0, _right, stack);
9552 
9553  return set;
9554  }
9555 
9556  case ast_func_id:
9557  return xpath_node_set_raw();
9558 
9559  case ast_step:
9560  {
9561  switch (_axis)
9562  {
9563  case axis_ancestor:
9564  return step_do(c, stack, axis_to_type<axis_ancestor>());
9565 
9566  case axis_ancestor_or_self:
9567  return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());
9568 
9569  case axis_attribute:
9570  return step_do(c, stack, axis_to_type<axis_attribute>());
9571 
9572  case axis_child:
9573  return step_do(c, stack, axis_to_type<axis_child>());
9574 
9575  case axis_descendant:
9576  return step_do(c, stack, axis_to_type<axis_descendant>());
9577 
9580 
9581  case axis_following:
9582  return step_do(c, stack, axis_to_type<axis_following>());
9583 
9586 
9587  case axis_namespace:
9588  // namespaced axis is not supported
9589  return xpath_node_set_raw();
9590 
9591  case axis_parent:
9592  return step_do(c, stack, axis_to_type<axis_parent>());
9593 
9594  case axis_preceding:
9595  return step_do(c, stack, axis_to_type<axis_preceding>());
9596 
9599 
9600  case axis_self:
9601  return step_do(c, stack, axis_to_type<axis_self>());
9602 
9603  default:
9604  assert(!"Unknown axis");
9605  return xpath_node_set_raw();
9606  }
9607  }
9608 
9609  case ast_step_root:
9610  {
9611  assert(!_right); // root step can't have any predicates
9612 
9613  xpath_node_set_raw ns;
9614 
9615  ns.set_type(xpath_node_set::type_sorted);
9616 
9617  if (c.n.node())
9618  ns.push_back(c.n.node().root(), stack.result);
9619  else if (c.n.attribute())
9620  ns.push_back(c.n.parent().root(), stack.result);
9621 
9622  return ns;
9623  }
9624 
9625  case ast_variable:
9626  {
9627  assert(_rettype == _data.variable->type());
9628 
9630  {
9631  const xpath_node_set &s = _data.variable->get_node_set();
9632 
9633  xpath_node_set_raw ns;
9634 
9635  ns.set_type(s.type());
9636  ns.append(s.begin(), s.end(), stack.result);
9637 
9638  return ns;
9639  }
9640 
9641  // fallthrough to type conversion
9642  }
9643 
9644  default:
9645  assert(!"Wrong expression for return type node set");
9646  return xpath_node_set_raw();
9647  }
9648  }
9649 
9650  bool is_posinv()
9651  {
9652  switch (_type)
9653  {
9654  case ast_func_position:
9655  return false;
9656 
9657  case ast_string_constant:
9658  case ast_number_constant:
9659  case ast_variable:
9660  return true;
9661 
9662  case ast_step:
9663  case ast_step_root:
9664  return true;
9665 
9666  case ast_predicate:
9667  case ast_filter:
9668  case ast_filter_posinv:
9669  return true;
9670 
9671  default:
9672  if (_left && !_left->is_posinv())
9673  return false;
9674 
9675  for (xpath_ast_node *n = _right; n; n = n->_next)
9676  if (!n->is_posinv())
9677  return false;
9678 
9679  return true;
9680  }
9681  }
9682 
9683  xpath_value_type rettype() const { return static_cast<xpath_value_type>(_rettype); }
9684 };
9685 
9687 {
9690 
9691  const char_t *_query;
9692  xpath_variable_set *_variables;
9693 
9694  xpath_parse_result *_result;
9695 
9697 
9698 #ifdef PUGIXML_NO_EXCEPTIONS
9699  jmp_buf _error_handler;
9700 #endif
9701 
9702  void throw_error(const char *message)
9703  {
9704  _result->error = message;
9705  _result->offset = _lexer.current_pos() - _query;
9706 
9707 #ifdef PUGIXML_NO_EXCEPTIONS
9708  longjmp(_error_handler, 1);
9709 #else
9710  throw xpath_exception(*_result);
9711 #endif
9712  }
9713 
9715  {
9716 #ifdef PUGIXML_NO_EXCEPTIONS
9717  throw_error("Out of memory");
9718 #else
9719  throw std::bad_alloc();
9720 #endif
9721  }
9722 
9723  void *alloc_node()
9724  {
9725  void *result = _alloc->allocate_nothrow(sizeof(xpath_ast_node));
9726 
9727  if (!result)
9728  throw_error_oom();
9729 
9730  return result;
9731  }
9732 
9734  {
9735  if (value.begin)
9736  {
9737  size_t length = static_cast<size_t>(value.end - value.begin);
9738 
9739  char_t *c = static_cast<char_t *>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t)));
9740  if (!c)
9741  throw_error_oom();
9742  assert(c); // workaround for clang static analysis
9743 
9744  memcpy(c, value.begin, length * sizeof(char_t));
9745  c[length] = 0;
9746 
9747  return c;
9748  }
9749  else
9750  return 0;
9751  }
9752 
9754  {
9755  assert(argc <= 1);
9756 
9757  if (argc == 1 && args[0]->rettype() != xpath_type_node_set)
9758  throw_error("Function has to be applied to node set");
9759 
9760  return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
9761  }
9762 
9764  {
9765  switch (name.begin[0])
9766  {
9767  case 'b':
9768  if (name == PUGIXML_TEXT("boolean") && argc == 1)
9770 
9771  break;
9772 
9773  case 'c':
9774  if (name == PUGIXML_TEXT("count") && argc == 1)
9775  {
9776  if (args[0]->rettype() != xpath_type_node_set)
9777  throw_error("Function has to be applied to node set");
9779  }
9780  else if (name == PUGIXML_TEXT("contains") && argc == 2)
9782  else if (name == PUGIXML_TEXT("concat") && argc >= 2)
9784  else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
9786 
9787  break;
9788 
9789  case 'f':
9790  if (name == PUGIXML_TEXT("false") && argc == 0)
9792  else if (name == PUGIXML_TEXT("floor") && argc == 1)
9794 
9795  break;
9796 
9797  case 'i':
9798  if (name == PUGIXML_TEXT("id") && argc == 1)
9800 
9801  break;
9802 
9803  case 'l':
9804  if (name == PUGIXML_TEXT("last") && argc == 0)
9806  else if (name == PUGIXML_TEXT("lang") && argc == 1)
9808  else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
9810 
9811  break;
9812 
9813  case 'n':
9814  if (name == PUGIXML_TEXT("name") && argc <= 1)
9816  else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1)
9818  else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
9819  return new (alloc_node())
9821  xpath_type_string, args[0], args[1]);
9822  else if (name == PUGIXML_TEXT("not") && argc == 1)
9824  else if (name == PUGIXML_TEXT("number") && argc <= 1)
9825  return new (alloc_node())
9827 
9828  break;
9829 
9830  case 'p':
9831  if (name == PUGIXML_TEXT("position") && argc == 0)
9833 
9834  break;
9835 
9836  case 'r':
9837  if (name == PUGIXML_TEXT("round") && argc == 1)
9839 
9840  break;
9841 
9842  case 's':
9843  if (name == PUGIXML_TEXT("string") && argc <= 1)
9844  return new (alloc_node())
9846  else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
9847  return new (alloc_node()) xpath_ast_node(
9849  else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
9851  else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
9852  return new (alloc_node())
9854  else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
9856  else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
9858  xpath_type_string, args[0], args[1]);
9859  else if (name == PUGIXML_TEXT("sum") && argc == 1)
9860  {
9861  if (args[0]->rettype() != xpath_type_node_set)
9862  throw_error("Function has to be applied to node set");
9864  }
9865 
9866  break;
9867 
9868  case 't':
9869  if (name == PUGIXML_TEXT("translate") && argc == 3)
9871  else if (name == PUGIXML_TEXT("true") && argc == 0)
9873 
9874  break;
9875 
9876  default:
9877  break;
9878  }
9879 
9880  throw_error("Unrecognized function or wrong parameter count");
9881 
9882  return 0;
9883  }
9884 
9885  axis_t parse_axis_name(const xpath_lexer_string &name, bool &specified)
9886  {
9887  specified = true;
9888 
9889  switch (name.begin[0])
9890  {
9891  case 'a':
9892  if (name == PUGIXML_TEXT("ancestor"))
9893  return axis_ancestor;
9894  else if (name == PUGIXML_TEXT("ancestor-or-self"))
9895  return axis_ancestor_or_self;
9896  else if (name == PUGIXML_TEXT("attribute"))
9897  return axis_attribute;
9898 
9899  break;
9900 
9901  case 'c':
9902  if (name == PUGIXML_TEXT("child"))
9903  return axis_child;
9904 
9905  break;
9906 
9907  case 'd':
9908  if (name == PUGIXML_TEXT("descendant"))
9909  return axis_descendant;
9910  else if (name == PUGIXML_TEXT("descendant-or-self"))
9911  return axis_descendant_or_self;
9912 
9913  break;
9914 
9915  case 'f':
9916  if (name == PUGIXML_TEXT("following"))
9917  return axis_following;
9918  else if (name == PUGIXML_TEXT("following-sibling"))
9919  return axis_following_sibling;
9920 
9921  break;
9922 
9923  case 'n':
9924  if (name == PUGIXML_TEXT("namespace"))
9925  return axis_namespace;
9926 
9927  break;
9928 
9929  case 'p':
9930  if (name == PUGIXML_TEXT("parent"))
9931  return axis_parent;
9932  else if (name == PUGIXML_TEXT("preceding"))
9933  return axis_preceding;
9934  else if (name == PUGIXML_TEXT("preceding-sibling"))
9935  return axis_preceding_sibling;
9936 
9937  break;
9938 
9939  case 's':
9940  if (name == PUGIXML_TEXT("self"))
9941  return axis_self;
9942 
9943  break;
9944 
9945  default:
9946  break;
9947  }
9948 
9949  specified = false;
9950  return axis_child;
9951  }
9952 
9954  {
9955  switch (name.begin[0])
9956  {
9957  case 'c':
9958  if (name == PUGIXML_TEXT("comment"))
9959  return nodetest_type_comment;
9960 
9961  break;
9962 
9963  case 'n':
9964  if (name == PUGIXML_TEXT("node"))
9965  return nodetest_type_node;
9966 
9967  break;
9968 
9969  case 'p':
9970  if (name == PUGIXML_TEXT("processing-instruction"))
9971  return nodetest_type_pi;
9972 
9973  break;
9974 
9975  case 't':
9976  if (name == PUGIXML_TEXT("text"))
9977  return nodetest_type_text;
9978 
9979  break;
9980 
9981  default:
9982  break;
9983  }
9984 
9985  return nodetest_none;
9986  }
9987 
9988  // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
9990  {
9991  switch (_lexer.current())
9992  {
9993  case lex_var_ref:
9994  {
9996 
9997  if (!_variables)
9998  throw_error("Unknown variable: variable set is not provided");
9999 
10001 
10002  if (!var)
10003  throw_error("Unknown variable: variable set does not contain the given name");
10004 
10005  _lexer.next();
10006 
10007  return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
10008  }
10009 
10010  case lex_open_brace:
10011  {
10012  _lexer.next();
10013 
10015 
10016  if (_lexer.current() != lex_close_brace)
10017  throw_error("Unmatched braces");
10018 
10019  _lexer.next();
10020 
10021  return n;
10022  }
10023 
10024  case lex_quoted_string:
10025  {
10026  const char_t *value = alloc_string(_lexer.contents());
10027 
10029  _lexer.next();
10030 
10031  return n;
10032  }
10033 
10034  case lex_number:
10035  {
10036  double value = 0;
10037 
10039  throw_error_oom();
10040 
10042  _lexer.next();
10043 
10044  return n;
10045  }
10046 
10047  case lex_string:
10048  {
10049  xpath_ast_node *args[2] = { 0 };
10050  size_t argc = 0;
10051 
10052  xpath_lexer_string function = _lexer.contents();
10053  _lexer.next();
10054 
10055  xpath_ast_node *last_arg = 0;
10056 
10057  if (_lexer.current() != lex_open_brace)
10058  throw_error("Unrecognized function call");
10059  _lexer.next();
10060 
10061  if (_lexer.current() != lex_close_brace)
10062  args[argc++] = parse_expression();
10063 
10064  while (_lexer.current() != lex_close_brace)
10065  {
10066  if (_lexer.current() != lex_comma)
10067  throw_error("No comma between function arguments");
10068  _lexer.next();
10069 
10071 
10072  if (argc < 2)
10073  args[argc] = n;
10074  else
10075  last_arg->set_next(n);
10076 
10077  argc++;
10078  last_arg = n;
10079  }
10080 
10081  _lexer.next();
10082 
10083  return parse_function(function, argc, args);
10084  }
10085 
10086  default:
10087  throw_error("Unrecognizable primary expression");
10088 
10089  return 0;
10090  }
10091  }
10092 
10093  // FilterExpr ::= PrimaryExpr | FilterExpr Predicate
10094  // Predicate ::= '[' PredicateExpr ']'
10095  // PredicateExpr ::= Expr
10097  {
10099 
10100  while (_lexer.current() == lex_open_square_brace)
10101  {
10102  _lexer.next();
10103 
10104  xpath_ast_node *expr = parse_expression();
10105 
10106  if (n->rettype() != xpath_type_node_set)
10107  throw_error("Predicate has to be applied to node set");
10108 
10109  bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv();
10110 
10111  n = new (alloc_node())
10113 
10115  throw_error("Unmatched square brace");
10116 
10117  _lexer.next();
10118  }
10119 
10120  return n;
10121  }
10122 
10123  // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
10124  // AxisSpecifier ::= AxisName '::' | '@'?
10125  // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
10126  // NameTest ::= '*' | NCName ':' '*' | QName
10127  // AbbreviatedStep ::= '.' | '..'
10129  {
10130  if (set && set->rettype() != xpath_type_node_set)
10131  throw_error("Step has to be applied to node set");
10132 
10133  bool axis_specified = false;
10134  axis_t axis = axis_child; // implied child axis
10135 
10137  {
10138  axis = axis_attribute;
10139  axis_specified = true;
10140 
10141  _lexer.next();
10142  }
10143  else if (_lexer.current() == lex_dot)
10144  {
10145  _lexer.next();
10146 
10148  }
10149  else if (_lexer.current() == lex_double_dot)
10150  {
10151  _lexer.next();
10152 
10154  }
10155 
10156  nodetest_t nt_type = nodetest_none;
10157  xpath_lexer_string nt_name;
10158 
10159  if (_lexer.current() == lex_string)
10160  {
10161  // node name test
10162  nt_name = _lexer.contents();
10163  _lexer.next();
10164 
10165  // was it an axis name?
10166  if (_lexer.current() == lex_double_colon)
10167  {
10168  // parse axis name
10169  if (axis_specified)
10170  throw_error("Two axis specifiers in one step");
10171 
10172  axis = parse_axis_name(nt_name, axis_specified);
10173 
10174  if (!axis_specified)
10175  throw_error("Unknown axis");
10176 
10177  // read actual node test
10178  _lexer.next();
10179 
10180  if (_lexer.current() == lex_multiply)
10181  {
10182  nt_type = nodetest_all;
10183  nt_name = xpath_lexer_string();
10184  _lexer.next();
10185  }
10186  else if (_lexer.current() == lex_string)
10187  {
10188  nt_name = _lexer.contents();
10189  _lexer.next();
10190  }
10191  else
10192  throw_error("Unrecognized node test");
10193  }
10194 
10195  if (nt_type == nodetest_none)
10196  {
10197  // node type test or processing-instruction
10198  if (_lexer.current() == lex_open_brace)
10199  {
10200  _lexer.next();
10201 
10202  if (_lexer.current() == lex_close_brace)
10203  {
10204  _lexer.next();
10205 
10206  nt_type = parse_node_test_type(nt_name);
10207 
10208  if (nt_type == nodetest_none)
10209  throw_error("Unrecognized node type");
10210 
10211  nt_name = xpath_lexer_string();
10212  }
10213  else if (nt_name == PUGIXML_TEXT("processing-instruction"))
10214  {
10215  if (_lexer.current() != lex_quoted_string)
10216  throw_error("Only literals are allowed as arguments to processing-instruction()");
10217 
10218  nt_type = nodetest_pi;
10219  nt_name = _lexer.contents();
10220  _lexer.next();
10221 
10222  if (_lexer.current() != lex_close_brace)
10223  throw_error("Unmatched brace near processing-instruction()");
10224  _lexer.next();
10225  }
10226  else
10227  throw_error("Unmatched brace near node type test");
10228  }
10229  // QName or NCName:*
10230  else
10231  {
10232  if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:*
10233  {
10234  nt_name.end--; // erase *
10235 
10236  nt_type = nodetest_all_in_namespace;
10237  }
10238  else
10239  nt_type = nodetest_name;
10240  }
10241  }
10242  }
10243  else if (_lexer.current() == lex_multiply)
10244  {
10245  nt_type = nodetest_all;
10246  _lexer.next();
10247  }
10248  else
10249  throw_error("Unrecognized node test");
10250 
10251  xpath_ast_node *n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name));
10252 
10253  xpath_ast_node *last = 0;
10254 
10255  while (_lexer.current() == lex_open_square_brace)
10256  {
10257  _lexer.next();
10258 
10259  xpath_ast_node *expr = parse_expression();
10260 
10262 
10264  throw_error("Unmatched square brace");
10265  _lexer.next();
10266 
10267  if (last)
10268  last->set_next(pred);
10269  else
10270  n->set_right(pred);
10271 
10272  last = pred;
10273  }
10274 
10275  return n;
10276  }
10277 
10278  // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
10280  {
10281  xpath_ast_node *n = parse_step(set);
10282 
10283  while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
10284  {
10285  lexeme_t l = _lexer.current();
10286  _lexer.next();
10287 
10288  if (l == lex_double_slash)
10290 
10291  n = parse_step(n);
10292  }
10293 
10294  return n;
10295  }
10296 
10297  // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
10298  // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
10300  {
10301  if (_lexer.current() == lex_slash)
10302  {
10303  _lexer.next();
10304 
10306 
10307  // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any
10308  // other lexeme means standalone root path
10309  lexeme_t l = _lexer.current();
10310 
10311  if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
10312  return parse_relative_location_path(n);
10313  else
10314  return n;
10315  }
10316  else if (_lexer.current() == lex_double_slash)
10317  {
10318  _lexer.next();
10319 
10322 
10323  return parse_relative_location_path(n);
10324  }
10325 
10326  // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being
10327  // inlined' in gcc 4.0.1
10328  return parse_relative_location_path(0);
10329  }
10330 
10331  // PathExpr ::= LocationPath
10332  // | FilterExpr
10333  // | FilterExpr '/' RelativeLocationPath
10334  // | FilterExpr '//' RelativeLocationPath
10335  // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
10336  // UnaryExpr ::= UnionExpr | '-' UnaryExpr
10338  {
10339  // Clarification.
10340  // PathExpr begins with either LocationPath or FilterExpr.
10341  // FilterExpr begins with PrimaryExpr
10342  // PrimaryExpr begins with '$' in case of it being a variable reference,
10343  // '(' in case of it being an expression, string literal, number constant or
10344  // function call.
10345 
10348  {
10349  if (_lexer.current() == lex_string)
10350  {
10351  // This is either a function call, or not - if not, we shall proceed with location path
10352  const char_t *state = _lexer.state();
10353 
10354  while (PUGI__IS_CHARTYPE(*state, ct_space))
10355  ++state;
10356 
10357  if (*state != '(')
10358  return parse_location_path();
10359 
10360  // This looks like a function call; however this still can be a node-test. Check it.
10362  return parse_location_path();
10363  }
10364 
10366 
10368  {
10369  lexeme_t l = _lexer.current();
10370  _lexer.next();
10371 
10372  if (l == lex_double_slash)
10373  {
10374  if (n->rettype() != xpath_type_node_set)
10375  throw_error("Step has to be applied to node set");
10376 
10378  }
10379 
10380  // select from location path
10381  return parse_relative_location_path(n);
10382  }
10383 
10384  return n;
10385  }
10386  else if (_lexer.current() == lex_minus)
10387  {
10388  _lexer.next();
10389 
10390  // precedence 7+ - only parses union expressions
10392 
10394  }
10395  else
10396  return parse_location_path();
10397  }
10398 
10400  {
10404 
10406 
10407  binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_)
10408  : asttype(asttype_), rettype(rettype_), precedence(precedence_)
10409  {
10410  }
10411 
10413  {
10414  switch (lexer.current())
10415  {
10416  case lex_string:
10417  if (lexer.contents() == PUGIXML_TEXT("or"))
10419  else if (lexer.contents() == PUGIXML_TEXT("and"))
10421  else if (lexer.contents() == PUGIXML_TEXT("div"))
10423  else if (lexer.contents() == PUGIXML_TEXT("mod"))
10425  else
10426  return binary_op_t();
10427 
10428  case lex_equal:
10430 
10431  case lex_not_equal:
10433 
10434  case lex_less:
10436 
10437  case lex_greater:
10439 
10440  case lex_less_or_equal:
10442 
10443  case lex_greater_or_equal:
10445 
10446  case lex_plus:
10448 
10449  case lex_minus:
10451 
10452  case lex_multiply:
10454 
10455  case lex_union:
10457 
10458  default:
10459  return binary_op_t();
10460  }
10461  }
10462  };
10463 
10465  {
10467 
10468  while (op.asttype != ast_unknown && op.precedence >= limit)
10469  {
10470  _lexer.next();
10471 
10473 
10475 
10476  while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)
10477  {
10478  rhs = parse_expression_rec(rhs, nextop.precedence);
10479 
10480  nextop = binary_op_t::parse(_lexer);
10481  }
10482 
10483  if (op.asttype == ast_op_union &&
10484  (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))
10485  throw_error("Union operator has to be applied to node sets");
10486 
10487  lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs);
10488 
10489  op = binary_op_t::parse(_lexer);
10490  }
10491 
10492  return lhs;
10493  }
10494 
10495  // Expr ::= OrExpr
10496  // OrExpr ::= AndExpr | OrExpr 'or' AndExpr
10497  // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
10498  // EqualityExpr ::= RelationalExpr
10499  // | EqualityExpr '=' RelationalExpr
10500  // | EqualityExpr '!=' RelationalExpr
10501  // RelationalExpr ::= AdditiveExpr
10502  // | RelationalExpr '<' AdditiveExpr
10503  // | RelationalExpr '>' AdditiveExpr
10504  // | RelationalExpr '<=' AdditiveExpr
10505  // | RelationalExpr '>=' AdditiveExpr
10506  // AdditiveExpr ::= MultiplicativeExpr
10507  // | AdditiveExpr '+' MultiplicativeExpr
10508  // | AdditiveExpr '-' MultiplicativeExpr
10509  // MultiplicativeExpr ::= UnaryExpr
10510  // | MultiplicativeExpr '*' UnaryExpr
10511  // | MultiplicativeExpr 'div' UnaryExpr
10512  // | MultiplicativeExpr 'mod' UnaryExpr
10514 
10515  xpath_parser(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
10516  : _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result)
10517  {
10518  }
10519 
10521  {
10522  xpath_ast_node *result = parse_expression();
10523 
10524  if (_lexer.current() != lex_eof)
10525  {
10526  // there are still unparsed tokens left, error
10527  throw_error("Incorrect query");
10528  }
10529 
10530  return result;
10531  }
10532 
10533  static xpath_ast_node *parse(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc,
10534  xpath_parse_result *result)
10535  {
10536  xpath_parser parser(query, variables, alloc, result);
10537 
10538 #ifdef PUGIXML_NO_EXCEPTIONS
10539  int error = setjmp(parser._error_handler);
10540 
10541  return (error == 0) ? parser.parse() : 0;
10542 #else
10543  return parser.parse();
10544 #endif
10545  }
10546 };
10547 
10549 {
10551  {
10552  void *memory = xml_memory::allocate(sizeof(xpath_query_impl));
10553 
10554  return new (memory) xpath_query_impl();
10555  }
10556 
10557  static void destroy(void *ptr)
10558  {
10559  if (!ptr)
10560  return;
10561 
10562  // free all allocated pages
10563  static_cast<xpath_query_impl *>(ptr)->alloc.release();
10564 
10565  // free allocator memory (with the first page)
10567  }
10568 
10570 
10574 };
10575 
10577 {
10578  if (!impl)
10579  return xpath_string();
10580 
10581 #ifdef PUGIXML_NO_EXCEPTIONS
10582  if (setjmp(sd.error_handler))
10583  return xpath_string();
10584 #endif
10585 
10586  xpath_context c(n, 1, 1);
10587 
10588  return impl->root->eval_string(c, sd.stack);
10589 }
10591 
10592 namespace pugi
10593 {
10594 #ifndef PUGIXML_NO_EXCEPTIONS
10596 {
10597  assert(_result.error);
10598 }
10599 
10600 PUGI__FN const char *xpath_exception::what() const throw()
10601 {
10602  return _result.error;
10603 }
10604 
10606 {
10607  return _result;
10608 }
10609 #endif
10610 
10612 
10613 PUGI__FN xpath_node::xpath_node(const xml_node &node_) : _node(node_) {}
10614 
10615 PUGI__FN xpath_node::xpath_node(const xml_attribute &attribute_, const xml_node &parent_)
10616  : _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
10617 {
10618 }
10619 
10621 {
10622  return _attribute ? xml_node() : _node;
10623 }
10624 
10626 {
10627  return _attribute;
10628 }
10629 
10631 {
10632  return _attribute ? _node : _node.parent();
10633 }
10634 
10636 
10637 PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const
10638 {
10639  return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
10640 }
10641 
10643 {
10644  return !(_node || _attribute);
10645 }
10646 
10648 {
10649  return _node == n._node && _attribute == n._attribute;
10650 }
10651 
10653 {
10654  return _node != n._node || _attribute != n._attribute;
10655 }
10656 
10657 #ifdef __BORLANDC__
10658 PUGI__FN bool operator&&(const xpath_node &lhs, bool rhs)
10659 {
10660  return (bool)lhs && rhs;
10661 }
10662 
10663 PUGI__FN bool operator||(const xpath_node &lhs, bool rhs)
10664 {
10665  return (bool)lhs || rhs;
10666 }
10667 #endif
10668 
10670 {
10671  assert(begin_ <= end_);
10672 
10673  size_t size_ = static_cast<size_t>(end_ - begin_);
10674 
10675  if (size_ <= 1)
10676  {
10677  // deallocate old buffer
10678  if (_begin != &_storage)
10679  impl::xml_memory::deallocate(_begin);
10680 
10681  // use internal buffer
10682  if (begin_ != end_)
10683  _storage = *begin_;
10684 
10685  _begin = &_storage;
10686  _end = &_storage + size_;
10687  }
10688  else
10689  {
10690  // make heap copy
10691  xpath_node *storage = static_cast<xpath_node *>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
10692 
10693  if (!storage)
10694  {
10695 #ifdef PUGIXML_NO_EXCEPTIONS
10696  return;
10697 #else
10698  throw std::bad_alloc();
10699 #endif
10700  }
10701 
10702  memcpy(storage, begin_, size_ * sizeof(xpath_node));
10703 
10704  // deallocate old buffer
10705  if (_begin != &_storage)
10706  impl::xml_memory::deallocate(_begin);
10707 
10708  // finalize
10709  _begin = storage;
10710  _end = storage + size_;
10711  }
10712 }
10713 
10714 PUGI__FN xpath_node_set::xpath_node_set() : _type(type_unsorted), _begin(&_storage), _end(&_storage) {}
10715 
10717  : _type(type_), _begin(&_storage), _end(&_storage)
10718 {
10719  _assign(begin_, end_);
10720 }
10721 
10723 {
10724  if (_begin != &_storage)
10725  impl::xml_memory::deallocate(_begin);
10726 }
10727 
10728 PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set &ns) : _type(ns._type), _begin(&_storage), _end(&_storage)
10729 {
10730  _assign(ns._begin, ns._end);
10731 }
10732 
10734 {
10735  if (this == &ns)
10736  return *this;
10737 
10738  _type = ns._type;
10739  _assign(ns._begin, ns._end);
10740 
10741  return *this;
10742 }
10743 
10745 {
10746  return _type;
10747 }
10748 
10750 {
10751  return _end - _begin;
10752 }
10753 
10755 {
10756  return _begin == _end;
10757 }
10758 
10760 {
10761  assert(index < size());
10762  return _begin[index];
10763 }
10764 
10766 {
10767  return _begin;
10768 }
10769 
10771 {
10772  return _end;
10773 }
10774 
10776 {
10778 }
10779 
10781 {
10782  return impl::xpath_first(_begin, _end, _type);
10783 }
10784 
10785 PUGI__FN xpath_parse_result::xpath_parse_result() : error("Internal error"), offset(0) {}
10786 
10787 PUGI__FN xpath_parse_result::operator bool() const
10788 {
10789  return error == 0;
10790 }
10791 
10793 {
10794  return error ? error : "No error";
10795 }
10796 
10798 
10800 {
10801  switch (_type)
10802  {
10803  case xpath_type_node_set:
10804  return static_cast<const impl::xpath_variable_node_set *>(this)->name;
10805 
10806  case xpath_type_number:
10807  return static_cast<const impl::xpath_variable_number *>(this)->name;
10808 
10809  case xpath_type_string:
10810  return static_cast<const impl::xpath_variable_string *>(this)->name;
10811 
10812  case xpath_type_boolean:
10813  return static_cast<const impl::xpath_variable_boolean *>(this)->name;
10814 
10815  default:
10816  assert(!"Invalid variable type");
10817  return 0;
10818  }
10819 }
10820 
10822 {
10823  return _type;
10824 }
10825 
10827 {
10828  return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean *>(this)->value : false;
10829 }
10830 
10832 {
10833  return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number *>(this)->value
10834  : impl::gen_nan();
10835 }
10836 
10838 {
10839  const char_t *value =
10840  (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string *>(this)->value : 0;
10841  return value ? value : PUGIXML_TEXT("");
10842 }
10843 
10845 {
10846  return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set *>(this)->value
10848 }
10849 
10851 {
10852  if (_type != xpath_type_boolean)
10853  return false;
10854 
10855  static_cast<impl::xpath_variable_boolean *>(this)->value = value;
10856  return true;
10857 }
10858 
10859 PUGI__FN bool xpath_variable::set(double value)
10860 {
10861  if (_type != xpath_type_number)
10862  return false;
10863 
10864  static_cast<impl::xpath_variable_number *>(this)->value = value;
10865  return true;
10866 }
10867 
10869 {
10870  if (_type != xpath_type_string)
10871  return false;
10872 
10873  impl::xpath_variable_string *var = static_cast<impl::xpath_variable_string *>(this);
10874 
10875  // duplicate string
10876  size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
10877 
10878  char_t *copy = static_cast<char_t *>(impl::xml_memory::allocate(size));
10879  if (!copy)
10880  return false;
10881 
10882  memcpy(copy, value, size);
10883 
10884  // replace old string
10885  if (var->value)
10886  impl::xml_memory::deallocate(var->value);
10887  var->value = copy;
10888 
10889  return true;
10890 }
10891 
10893 {
10894  if (_type != xpath_type_node_set)
10895  return false;
10896 
10897  static_cast<impl::xpath_variable_node_set *>(this)->value = value;
10898  return true;
10899 }
10900 
10902 {
10903  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
10904  _data[i] = 0;
10905 }
10906 
10908 {
10909  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
10910  {
10911  xpath_variable *var = _data[i];
10912 
10913  while (var)
10914  {
10915  xpath_variable *next = var->_next;
10916 
10918 
10919  var = next;
10920  }
10921  }
10922 }
10923 
10925 {
10926  const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
10927  size_t hash = impl::hash_string(name) % hash_size;
10928 
10929  // look for existing variable
10930  for (xpath_variable *var = _data[hash]; var; var = var->_next)
10931  if (impl::strequal(var->name(), name))
10932  return var;
10933 
10934  return 0;
10935 }
10936 
10938 {
10939  const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
10940  size_t hash = impl::hash_string(name) % hash_size;
10941 
10942  // look for existing variable
10943  for (xpath_variable *var = _data[hash]; var; var = var->_next)
10944  if (impl::strequal(var->name(), name))
10945  return var->type() == type ? var : 0;
10946 
10947  // add new variable
10948  xpath_variable *result = impl::new_xpath_variable(type, name);
10949 
10950  if (result)
10951  {
10952  result->_type = type;
10953  result->_next = _data[hash];
10954 
10955  _data[hash] = result;
10956  }
10957 
10958  return result;
10959 }
10960 
10961 PUGI__FN bool xpath_variable_set::set(const char_t *name, bool value)
10962 {
10963  xpath_variable *var = add(name, xpath_type_boolean);
10964  return var ? var->set(value) : false;
10965 }
10966 
10967 PUGI__FN bool xpath_variable_set::set(const char_t *name, double value)
10968 {
10969  xpath_variable *var = add(name, xpath_type_number);
10970  return var ? var->set(value) : false;
10971 }
10972 
10973 PUGI__FN bool xpath_variable_set::set(const char_t *name, const char_t *value)
10974 {
10975  xpath_variable *var = add(name, xpath_type_string);
10976  return var ? var->set(value) : false;
10977 }
10978 
10980 {
10981  xpath_variable *var = add(name, xpath_type_node_set);
10982  return var ? var->set(value) : false;
10983 }
10984 
10986 {
10987  return find(name);
10988 }
10989 
10991 {
10992  return find(name);
10993 }
10994 
10995 PUGI__FN xpath_query::xpath_query(const char_t *query, xpath_variable_set *variables) : _impl(0)
10996 {
10997  impl::xpath_query_impl *qimpl = impl::xpath_query_impl::create();
10998 
10999  if (!qimpl)
11000  {
11001 #ifdef PUGIXML_NO_EXCEPTIONS
11002  _result.error = "Out of memory";
11003 #else
11004  throw std::bad_alloc();
11005 #endif
11006  }
11007  else
11008  {
11009  impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy);
11010 
11011  qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
11012 
11013  if (qimpl->root)
11014  {
11015  _impl = static_cast<impl::xpath_query_impl *>(impl_holder.release());
11016  _result.error = 0;
11017  }
11018  }
11019 }
11020 
11022 {
11023  impl::xpath_query_impl::destroy(_impl);
11024 }
11025 
11027 {
11028  if (!_impl)
11029  return xpath_type_none;
11030 
11031  return static_cast<impl::xpath_query_impl *>(_impl)->root->rettype();
11032 }
11033 
11035 {
11036  if (!_impl)
11037  return false;
11038 
11039  impl::xpath_context c(n, 1, 1);
11040  impl::xpath_stack_data sd;
11041 
11042 #ifdef PUGIXML_NO_EXCEPTIONS
11043  if (setjmp(sd.error_handler))
11044  return false;
11045 #endif
11046 
11047  return static_cast<impl::xpath_query_impl *>(_impl)->root->eval_boolean(c, sd.stack);
11048 }
11049 
11051 {
11052  if (!_impl)
11053  return impl::gen_nan();
11054 
11055  impl::xpath_context c(n, 1, 1);
11056  impl::xpath_stack_data sd;
11057 
11058 #ifdef PUGIXML_NO_EXCEPTIONS
11059  if (setjmp(sd.error_handler))
11060  return impl::gen_nan();
11061 #endif
11062 
11063  return static_cast<impl::xpath_query_impl *>(_impl)->root->eval_number(c, sd.stack);
11064 }
11065 
11066 #ifndef PUGIXML_NO_STL
11068 {
11069  impl::xpath_stack_data sd;
11070 
11071  return impl::evaluate_string_impl(static_cast<impl::xpath_query_impl *>(_impl), n, sd).c_str();
11072 }
11073 #endif
11074 
11075 PUGI__FN size_t xpath_query::evaluate_string(char_t *buffer, size_t capacity, const xpath_node &n) const
11076 {
11077  impl::xpath_stack_data sd;
11078 
11079  impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl *>(_impl), n, sd);
11080 
11081  size_t full_size = r.length() + 1;
11082 
11083  if (capacity > 0)
11084  {
11085  size_t size = (full_size < capacity) ? full_size : capacity;
11086  assert(size > 0);
11087 
11088  memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
11089  buffer[size - 1] = 0;
11090  }
11091 
11092  return full_size;
11093 }
11094 
11096 {
11097  if (!_impl)
11098  return xpath_node_set();
11099 
11100  impl::xpath_ast_node *root = static_cast<impl::xpath_query_impl *>(_impl)->root;
11101 
11102  if (root->rettype() != xpath_type_node_set)
11103  {
11104 #ifdef PUGIXML_NO_EXCEPTIONS
11105  return xpath_node_set();
11106 #else
11107  xpath_parse_result res;
11108  res.error = "Expression does not evaluate to node set";
11109 
11110  throw xpath_exception(res);
11111 #endif
11112  }
11113 
11114  impl::xpath_context c(n, 1, 1);
11115  impl::xpath_stack_data sd;
11116 
11117 #ifdef PUGIXML_NO_EXCEPTIONS
11118  if (setjmp(sd.error_handler))
11119  return xpath_node_set();
11120 #endif
11121 
11122  impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack);
11123 
11124  return xpath_node_set(r.begin(), r.end(), r.type());
11125 }
11126 
11128 {
11129  return _result;
11130 }
11131 
11133 
11134 PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
11135 {
11136  return _impl ? unspecified_bool_xpath_query : 0;
11137 }
11138 
11140 {
11141  return !_impl;
11142 }
11143 
11145 {
11146  xpath_query q(query, variables);
11147  return select_single_node(q);
11148 }
11149 
11151 {
11152  xpath_node_set s = query.evaluate_node_set(*this);
11153  return s.empty() ? xpath_node() : s.first();
11154 }
11155 
11157 {
11158  xpath_query q(query, variables);
11159  return select_nodes(q);
11160 }
11161 
11163 {
11164  return query.evaluate_node_set(*this);
11165 }
11166 } // namespace pugi
11167 
11168 #endif
11169 
11170 #ifdef __BORLANDC__
11171 #pragma option pop
11172 #endif
11173 
11174 // Intel C++ does not properly keep warning state for function templates,
11175 // so popping warning state at the end of translation unit leads to warnings in
11176 // the middle.
11177 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
11178 #pragma warning(pop)
11179 #endif
11180 
11181 // Undefine all local macros (makes sure we're not leaking macros in header-only
11182 // mode)
11183 #undef PUGI__NO_INLINE
11184 #undef PUGI__STATIC_ASSERT
11185 #undef PUGI__DMC_VOLATILE
11186 #undef PUGI__MSVC_CRT_VERSION
11187 #undef PUGI__NS_BEGIN
11188 #undef PUGI__NS_END
11189 #undef PUGI__FN
11190 #undef PUGI__FN_NO_INLINE
11191 #undef PUGI__IS_CHARTYPE_IMPL
11192 #undef PUGI__IS_CHARTYPE
11193 #undef PUGI__IS_CHARTYPEX
11194 #undef PUGI__SKIPWS
11195 #undef PUGI__OPTSET
11196 #undef PUGI__PUSHNODE
11197 #undef PUGI__POPNODE
11198 #undef PUGI__SCANFOR
11199 #undef PUGI__SCANWHILE
11200 #undef PUGI__ENDSEG
11201 #undef PUGI__THROW_ERROR
11202 #undef PUGI__CHECK_ERROR
11203 
11204 #endif
11205 
ETISS_PLUGIN_EXPORT etiss::CPUArch std::map< std::string, std::string > options
create new instance of the CPUArch type at index
__DEVICE__ int fpclassify(float __x)
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
__device__ __2f16 float c
__device__ float
__device__ __2f16 float bool s
do v
Definition: arm_acle.h:76
static __inline__ uint32_t
Definition: arm_cde.h:25
static __inline__ uint8_t
Definition: arm_mve.h:323
static __inline__ uint16_t
Definition: arm_mve.h:315
bool operator!=(const xml_attribute_iterator &rhs) const
Definition: pugixml.cpp:5791
const xml_attribute_iterator & operator--()
Definition: pugixml.cpp:5822
xml_attribute * operator->() const
Definition: pugixml.cpp:5802
xml_attribute & operator*() const
Definition: pugixml.cpp:5796
bool operator==(const xml_attribute_iterator &rhs) const
Definition: pugixml.cpp:5786
const xml_attribute_iterator & operator++()
Definition: pugixml.cpp:5808
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition: pugixml.cpp:4388
bool operator>=(const xml_attribute &r) const
Definition: pugixml.cpp:4373
bool as_bool(bool def=false) const
Definition: pugixml.cpp:4413
bool operator!=(const xml_attribute &r) const
Definition: pugixml.cpp:4353
bool operator<(const xml_attribute &r) const
Definition: pugixml.cpp:4358
int as_int(int def=0) const
Definition: pugixml.cpp:4393
float as_float(float def=0) const
Definition: pugixml.cpp:4408
bool operator==(const xml_attribute &r) const
Definition: pugixml.cpp:4348
bool empty() const
Definition: pugixml.cpp:4430
size_t hash_value() const
Definition: pugixml.cpp:4445
const char_t * name() const
Definition: pugixml.cpp:4435
xml_attribute & operator=(const char_t *rhs)
Definition: pugixml.cpp:4455
xml_attribute previous_attribute() const
Definition: pugixml.cpp:4383
xml_attribute_struct * _attr
Definition: pugixml.hpp:302
xml_attribute next_attribute() const
Definition: pugixml.cpp:4378
bool operator!() const
Definition: pugixml.cpp:4343
bool operator<=(const xml_attribute &r) const
Definition: pugixml.cpp:4368
double as_double(double def=0) const
Definition: pugixml.cpp:4403
void(* unspecified_bool_type)(xml_attribute ***)
Definition: pugixml.hpp:304
bool set_name(const char_t *rhs)
Definition: pugixml.cpp:4499
bool set_value(const char_t *rhs)
Definition: pugixml.cpp:4507
unsigned int as_uint(unsigned int def=0) const
Definition: pugixml.cpp:4398
xml_attribute_struct * internal_object() const
Definition: pugixml.cpp:4450
bool operator>(const xml_attribute &r) const
Definition: pugixml.cpp:4363
const char_t * value() const
Definition: pugixml.cpp:4440
xml_parse_result load(std::basic_istream< char, std::char_traits< char > > &stream, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
xml_parse_result load_buffer_inplace(void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:6107
char _memory[192]
Definition: pugixml.hpp:927
xml_node document_element() const
Definition: pugixml.cpp:6186
bool save_file(const char *path, const char_t *indent=PUGIXML_TEXT("\t"), unsigned int flags=format_default, xml_encoding encoding=encoding_auto) const
Definition: pugixml.cpp:6172
xml_parse_result load_buffer_inplace_own(void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:6116
xml_parse_result load_file(const char *path, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:6080
xml_parse_result load_buffer(const void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:6098
void save(xml_writer &writer, const char_t *indent=PUGIXML_TEXT("\t"), unsigned int flags=format_default, xml_encoding encoding=encoding_auto) const
Definition: pugixml.cpp:6125
char_t * _buffer
Definition: pugixml.hpp:925
bool operator!=(const xml_named_node_iterator &rhs) const
Definition: pugixml.cpp:5853
xml_node * operator->() const
Definition: pugixml.cpp:5864
const xml_named_node_iterator & operator--()
Definition: pugixml.cpp:5884
bool operator==(const xml_named_node_iterator &rhs) const
Definition: pugixml.cpp:5848
xml_node & operator*() const
Definition: pugixml.cpp:5858
const xml_named_node_iterator & operator++()
Definition: pugixml.cpp:5870
bool operator==(const xml_node_iterator &rhs) const
Definition: pugixml.cpp:5725
const xml_node_iterator & operator--()
Definition: pugixml.cpp:5761
xml_node * operator->() const
Definition: pugixml.cpp:5741
bool operator!=(const xml_node_iterator &rhs) const
Definition: pugixml.cpp:5730
const xml_node_iterator & operator++()
Definition: pugixml.cpp:5747
xml_node & operator*() const
Definition: pugixml.cpp:5735
string_t path(char_t delimiter='/') const
Definition: pugixml.cpp:5291
size_t hash_value() const
Definition: pugixml.cpp:5413
xpath_node select_single_node(const char_t *query, xpath_variable_set *variables=0) const
Definition: pugixml.cpp:11144
bool set_value(const char_t *rhs)
Definition: pugixml.cpp:4821
xml_node_type type() const
Definition: pugixml.cpp:4669
xml_node append_child(xml_node_type type=node_element)
Definition: pugixml.cpp:4983
xml_node child(const char_t *name) const
Definition: pugixml.cpp:4679
friend class xml_named_node_iterator
Definition: pugixml.hpp:400
xml_node last_child() const
Definition: pugixml.cpp:4802
xml_node first_child() const
Definition: pugixml.cpp:4797
bool operator>(const xml_node &r) const
Definition: pugixml.cpp:4644
xml_object_range< xml_node_iterator > children() const
Definition: pugixml.cpp:4613
xml_attribute append_attribute(const char_t *name)
Definition: pugixml.cpp:4837
xml_node next_sibling() const
Definition: pugixml.cpp:4715
xml_node_struct * internal_object() const
Definition: pugixml.cpp:5418
xml_node_struct * _root
Definition: pugixml.hpp:403
xml_object_range< xml_attribute_iterator > attributes() const
Definition: pugixml.cpp:4624
xml_node parent() const
Definition: pugixml.cpp:4749
bool remove_child(const xml_node &n)
Definition: pugixml.cpp:5197
xml_attribute append_copy(const xml_attribute &proto)
Definition: pugixml.cpp:4939
xml_node insert_child_after(xml_node_type type, const xml_node &node)
Definition: pugixml.cpp:5054
xml_attribute last_attribute() const
Definition: pugixml.cpp:4792
attribute_iterator attributes_end() const
Definition: pugixml.cpp:4608
xml_node previous_sibling() const
Definition: pugixml.cpp:4738
ptrdiff_t offset_debug() const
Definition: pugixml.cpp:5452
iterator end() const
Definition: pugixml.cpp:4598
xml_text text() const
Definition: pugixml.cpp:4765
xml_attribute insert_attribute_before(const char_t *name, const xml_attribute &attr)
Definition: pugixml.cpp:4875
xml_attribute insert_attribute_after(const char_t *name, const xml_attribute &attr)
Definition: pugixml.cpp:4907
bool operator!=(const xml_node &r) const
Definition: pugixml.cpp:4634
bool operator<(const xml_node &r) const
Definition: pugixml.cpp:4639
xml_attribute prepend_attribute(const char_t *name)
Definition: pugixml.cpp:4848
xml_parse_result append_buffer(const void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:5217
const char_t * value() const
Definition: pugixml.cpp:4674
void(* unspecified_bool_type)(xml_node ***)
Definition: pugixml.hpp:405
xml_attribute_iterator attribute_iterator
Definition: pugixml.hpp:610
bool traverse(xml_tree_walker &walker)
Definition: pugixml.cpp:5365
xml_node find_child_by_attribute(const char_t *name, const char_t *attr_name, const char_t *attr_value) const
Definition: pugixml.cpp:5258
const char_t * child_value() const
Definition: pugixml.cpp:4770
bool set_name(const char_t *rhs)
Definition: pugixml.cpp:4807
xml_node prepend_child(xml_node_type type=node_element)
Definition: pugixml.cpp:4996
xml_attribute first_attribute() const
Definition: pugixml.cpp:4787
bool operator!() const
Definition: pugixml.cpp:4588
bool operator>=(const xml_node &r) const
Definition: pugixml.cpp:4654
xml_attribute insert_copy_after(const xml_attribute &proto, const xml_attribute &attr)
Definition: pugixml.cpp:4961
xml_attribute prepend_copy(const xml_attribute &proto)
Definition: pugixml.cpp:4950
xml_node first_element_by_path(const char_t *path, char_t delimiter='/') const
Definition: pugixml.cpp:5311
xml_attribute attribute(const char_t *name) const
Definition: pugixml.cpp:4691
const char_t * name() const
Definition: pugixml.cpp:4664
xml_attribute insert_copy_before(const xml_attribute &proto, const xml_attribute &attr)
Definition: pugixml.cpp:4972
attribute_iterator attributes_begin() const
Definition: pugixml.cpp:4603
xpath_node_set select_nodes(const char_t *query, xpath_variable_set *variables=0) const
Definition: pugixml.cpp:11156
xml_node_iterator iterator
Definition: pugixml.hpp:604
bool operator<=(const xml_node &r) const
Definition: pugixml.cpp:4649
iterator begin() const
Definition: pugixml.cpp:4593
bool remove_attribute(const xml_attribute &a)
Definition: pugixml.cpp:5163
xml_node root() const
Definition: pugixml.cpp:4754
bool empty() const
Definition: pugixml.cpp:4659
void print(xml_writer &writer, const char_t *indent=PUGIXML_TEXT("\t"), unsigned int flags=format_default, xml_encoding encoding=encoding_auto, unsigned int depth=0) const
Definition: pugixml.cpp:5423
xml_node insert_child_before(xml_node_type type, const xml_node &node)
Definition: pugixml.cpp:5026
bool operator==(const xml_node &r) const
Definition: pugixml.cpp:4629
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition: pugixml.cpp:5546
double as_double(double def=0) const
Definition: pugixml.cpp:5567
xml_text & operator=(const char_t *rhs)
Definition: pugixml.cpp:5655
bool operator!() const
Definition: pugixml.cpp:5529
friend class xml_node
Definition: pugixml.hpp:639
float as_float(float def=0) const
Definition: pugixml.cpp:5574
xml_node_struct * _data_new()
Definition: pugixml.cpp:5511
xml_node_struct * _root
Definition: pugixml.hpp:641
bool as_bool(bool def=false) const
Definition: pugixml.cpp:5581
xml_node data() const
Definition: pugixml.cpp:5699
bool empty() const
Definition: pugixml.cpp:5534
bool set(const char_t *rhs)
Definition: pugixml.cpp:5604
int as_int(int def=0) const
Definition: pugixml.cpp:5553
unsigned int as_uint(unsigned int def=0) const
Definition: pugixml.cpp:5560
void(* unspecified_bool_type)(xml_text ***)
Definition: pugixml.hpp:643
const char_t * get() const
Definition: pugixml.cpp:5539
xml_node_struct * _data() const
Definition: pugixml.cpp:5499
virtual bool end(xml_node &node)
Definition: pugixml.cpp:4327
virtual bool for_each(xml_node &node)=0
virtual bool begin(xml_node &node)
Definition: pugixml.cpp:4322
virtual ~xml_tree_walker()
Definition: pugixml.cpp:4315
virtual void write(const void *data, size_t size)
Definition: pugixml.cpp:4278
xml_writer_file(void *file)
Definition: pugixml.cpp:4276
std::basic_ostream< wchar_t, std::char_traits< wchar_t > > * wide_stream
Definition: pugixml.hpp:291
virtual void write(const void *data, size_t size)
Definition: pugixml.cpp:4295
xml_writer_stream(std::basic_ostream< char, std::char_traits< char > > &stream)
std::basic_ostream< char, std::char_traits< char > > * narrow_stream
Definition: pugixml.hpp:290
virtual const char * what() const
Definition: pugixml.cpp:10600
const xpath_parse_result & result() const
Definition: pugixml.cpp:10605
xpath_exception(const xpath_parse_result &result)
Definition: pugixml.cpp:10595
xpath_parse_result _result
Definition: pugixml.hpp:1150
bool empty() const
Definition: pugixml.cpp:10754
type_t type() const
Definition: pugixml.cpp:10744
xpath_node_set & operator=(const xpath_node_set &ns)
Definition: pugixml.cpp:10733
void _assign(const_iterator begin, const_iterator end)
Definition: pugixml.cpp:10669
const_iterator end() const
Definition: pugixml.cpp:10770
void sort(bool reverse=false)
Definition: pugixml.cpp:10775
const_iterator begin() const
Definition: pugixml.cpp:10765
xpath_node first() const
Definition: pugixml.cpp:10780
const xpath_node & operator[](size_t index) const
Definition: pugixml.cpp:10759
size_t size() const
Definition: pugixml.cpp:10749
xpath_node * _begin
Definition: pugixml.hpp:1260
xpath_node * _end
Definition: pugixml.hpp:1261
xpath_node _storage
Definition: pugixml.hpp:1258
void(* unspecified_bool_type)(xpath_node ***)
Definition: pugixml.hpp:1171
xml_node _node
Definition: pugixml.hpp:1168
bool operator!() const
Definition: pugixml.cpp:10642
xml_node parent() const
Definition: pugixml.cpp:10630
xml_attribute attribute() const
Definition: pugixml.cpp:10625
xml_node node() const
Definition: pugixml.cpp:10620
bool operator!=(const xpath_node &n) const
Definition: pugixml.cpp:10652
xml_attribute _attribute
Definition: pugixml.hpp:1169
bool operator==(const xpath_node &n) const
Definition: pugixml.cpp:10647
string_t evaluate_string(const xpath_node &n) const
Definition: pugixml.cpp:11067
void(* unspecified_bool_type)(xpath_query ***)
Definition: pugixml.hpp:1093
bool operator!() const
Definition: pugixml.cpp:11139
double evaluate_number(const xpath_node &n) const
Definition: pugixml.cpp:11050
xpath_node_set evaluate_node_set(const xpath_node &n) const
Definition: pugixml.cpp:11095
xpath_value_type return_type() const
Definition: pugixml.cpp:11026
xpath_parse_result _result
Definition: pugixml.hpp:1091
xpath_query(const xpath_query &)
const xpath_parse_result & result() const
Definition: pugixml.cpp:11127
bool evaluate_boolean(const xpath_node &n) const
Definition: pugixml.cpp:11034
xpath_variable * add(const char_t *name, xpath_value_type type)
Definition: pugixml.cpp:10937
xpath_variable * find(const char_t *name) const
Definition: pugixml.cpp:10924
bool set(const char_t *name, bool value)
Definition: pugixml.cpp:10961
xpath_variable * get(const char_t *name)
Definition: pugixml.cpp:10985
xpath_variable * _data[64]
Definition: pugixml.hpp:1059
xpath_variable * _next
Definition: pugixml.hpp:1027
bool set(bool value)
Definition: pugixml.cpp:10850
double get_number() const
Definition: pugixml.cpp:10831
const char_t * get_string() const
Definition: pugixml.cpp:10837
bool get_boolean() const
Definition: pugixml.cpp:10826
const xpath_node_set & get_node_set() const
Definition: pugixml.cpp:10844
xpath_value_type type() const
Definition: pugixml.cpp:10821
const char_t * name() const
Definition: pugixml.cpp:10799
xpath_value_type _type
Definition: pugixml.hpp:1026
xml_buffered_writer & operator=(const xml_buffered_writer &)
void write(char_t d0)
Definition: pugixml.cpp:3299
xml_writer & writer
Definition: pugixml.cpp:3392
xml_buffered_writer(xml_writer &writer_, xml_encoding user_encoding)
Definition: pugixml.cpp:3222
void write(char_t d0, char_t d1)
Definition: pugixml.cpp:3308
xml_buffered_writer(const xml_buffered_writer &)
char_t data_char[bufcapacity]
Definition: pugixml.cpp:3389
char_t buffer[bufcapacity]
Definition: pugixml.cpp:3383
void flush(const char_t *data, size_t size)
Definition: pugixml.cpp:3236
uint16_t data_u16[2 *bufcapacity]
Definition: pugixml.cpp:3387
union xml_buffered_writer::@9 scratch
void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
Definition: pugixml.cpp:3341
xml_encoding encoding
Definition: pugixml.cpp:3394
uint8_t data_u8[4 *bufcapacity]
Definition: pugixml.cpp:3386
void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
Definition: pugixml.cpp:3354
void write(const char_t *data)
Definition: pugixml.cpp:3297
void write(char_t d0, char_t d1, char_t d2, char_t d3)
Definition: pugixml.cpp:3329
void write(char_t d0, char_t d1, char_t d2)
Definition: pugixml.cpp:3318
void write(const char_t *data, size_t length)
Definition: pugixml.cpp:3256
uint32_t data_u32[bufcapacity]
Definition: pugixml.cpp:3388
xpath_allocator(xpath_memory_block *root, size_t root_size=0)
Definition: pugixml.cpp:6568
void * reallocate(void *ptr, size_t old_size, size_t new_size)
Definition: pugixml.cpp:6623
void * allocate_nothrow(size_t size)
Definition: pugixml.cpp:6575
void * allocate(size_t size)
Definition: pugixml.cpp:6606
xpath_memory_block * _root
Definition: pugixml.cpp:6560
size_t _root_size
Definition: pugixml.cpp:6561
void revert(const xpath_allocator &state)
Definition: pugixml.cpp:6669
xpath_variable * variable
Definition: pugixml.cpp:8297
xpath_ast_node * _next
Definition: pugixml.cpp:8289
const char_t * string
Definition: pugixml.cpp:8293
void set_next(xpath_ast_node *value)
Definition: pugixml.cpp:8971
xpath_value_type rettype() const
Definition: pugixml.cpp:9683
xpath_node_set_raw eval_node_set(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:9520
const char_t * nodetest
Definition: pugixml.cpp:8299
xpath_ast_node & operator=(const xpath_ast_node &)
xpath_string eval_string(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:9294
void step_push(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc)
Definition: pugixml.cpp:8538
void step_fill(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc, T)
Definition: pugixml.cpp:8590
xpath_ast_node(ast_type_t type, xpath_ast_node *left, axis_t axis, nodetest_t test, const char_t *contents)
Definition: pugixml.cpp:8959
xpath_node_set_raw step_do(const xpath_context &c, const xpath_stack &stack, T v)
Definition: pugixml.cpp:8850
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable *value)
Definition: pugixml.cpp:8935
bool is_posinv()
Definition: pugixml.cpp:9650
double eval_number(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:9106
static bool compare_eq(xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack, const Comp &comp)
Definition: pugixml.cpp:8306
void step_push(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &parent, xpath_allocator *alloc)
Definition: pugixml.cpp:8505
void step_fill(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &p, xpath_allocator *alloc, T v)
Definition: pugixml.cpp:8769
xpath_string eval_string_concat(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:9242
xpath_ast_node * _right
Definition: pugixml.cpp:8288
bool eval_boolean(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:8975
static bool compare_rel(xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack, const Comp &comp)
Definition: pugixml.cpp:8396
xpath_ast_node * _left
Definition: pugixml.cpp:8287
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value)
Definition: pugixml.cpp:8922
union xpath_ast_node::@10 _data
xpath_ast_node(const xpath_ast_node &)
void apply_predicates(xpath_node_set_raw &ns, size_t first, const xpath_stack &stack)
Definition: pugixml.cpp:8494
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t *value)
Definition: pugixml.cpp:8909
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node *left=0, xpath_ast_node *right=0)
Definition: pugixml.cpp:8948
void apply_predicate(xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack)
Definition: pugixml.cpp:8468
void set_right(xpath_ast_node *value)
Definition: pugixml.cpp:8973
const char_t * _cur_lexeme_pos
Definition: pugixml.cpp:7872
lexeme_t _cur_lexeme
Definition: pugixml.cpp:7875
void next()
Definition: pugixml.cpp:7882
const xpath_lexer_string & contents() const
Definition: pugixml.cpp:8164
lexeme_t current() const
Definition: pugixml.cpp:8160
const char_t * current_pos() const
Definition: pugixml.cpp:8162
xpath_lexer_string _cur_lexeme_contents
Definition: pugixml.cpp:7873
const char_t * state() const
Definition: pugixml.cpp:7880
xpath_lexer(const char_t *query)
Definition: pugixml.cpp:7878
const char_t * _cur
Definition: pugixml.cpp:7871
xpath_node_set::type_t _type
Definition: pugixml.cpp:7726
void append(const xpath_node *begin_, const xpath_node *end_, xpath_allocator *alloc)
Definition: pugixml.cpp:7768
size_t size() const
Definition: pugixml.cpp:7741
xpath_node * begin() const
Definition: pugixml.cpp:7735
xpath_node_set::type_t type() const
Definition: pugixml.cpp:7808
xpath_node * end() const
Definition: pugixml.cpp:7737
void push_back(const xpath_node &node, xpath_allocator *alloc)
Definition: pugixml.cpp:7745
xpath_node * _eos
Definition: pugixml.cpp:7730
xpath_node first() const
Definition: pugixml.cpp:7743
xpath_node * _begin
Definition: pugixml.cpp:7728
bool empty() const
Definition: pugixml.cpp:7739
void truncate(xpath_node *pos)
Definition: pugixml.cpp:7793
void set_type(xpath_node_set::type_t value)
Definition: pugixml.cpp:7810
void remove_duplicates()
Definition: pugixml.cpp:7800
xpath_node * _end
Definition: pugixml.cpp:7729
bool empty() const
Definition: pugixml.cpp:6851
bool uses_heap() const
Definition: pugixml.cpp:6857
static char_t * duplicate_string(const char_t *string, size_t length, xpath_allocator *alloc)
Definition: pugixml.cpp:6758
bool _uses_heap
Definition: pugixml.cpp:6756
const char_t * c_str() const
Definition: pugixml.cpp:6835
size_t length() const
Definition: pugixml.cpp:6837
bool operator!=(const xpath_string &o) const
Definition: pugixml.cpp:6855
static char_t * duplicate_string(const char_t *string, xpath_allocator *alloc)
Definition: pugixml.cpp:6769
void append(const xpath_string &o, xpath_allocator *alloc)
Definition: pugixml.cpp:6797
xpath_string(const char_t *str, xpath_allocator *alloc)
Definition: pugixml.cpp:6777
bool operator==(const xpath_string &o) const
Definition: pugixml.cpp:6853
xpath_string(const char_t *begin, const char_t *end, xpath_allocator *alloc)
Definition: pugixml.cpp:6787
const char_t * _buffer
Definition: pugixml.cpp:6755
char_t * data(xpath_allocator *alloc)
Definition: pugixml.cpp:6839
xpath_string(const char_t *str, bool use_heap)
Definition: pugixml.cpp:6785
#define DBL_DIG
Definition: float.h:95
uint32_t I
Definition: Instruction.h:80
static std::string depth(Dot::Node *node)
Definition: Dot.cpp:848
void copy(VirtualStruct &dst, VirtualStruct &src, std::list< std::shared_ptr< VirtualStruct::Field >> &dst_notPresent, std::list< std::shared_ptr< VirtualStruct::Field >> &dst_notWriteable, std::list< std::shared_ptr< VirtualStruct::Field >> dst_unknown, bool pretend=false, std::list< std::shared_ptr< VirtualStruct::Field >> *src_private=0, std::list< std::shared_ptr< VirtualStruct::Field >> *dst_private=0)
copies all fields with the same name from the source to the destination structure.
Definition: pugixml.hpp:89
xml_encoding
Definition: pugixml.hpp:177
@ encoding_utf32
Definition: pugixml.hpp:185
@ encoding_utf16_le
Definition: pugixml.hpp:180
@ encoding_utf32_be
Definition: pugixml.hpp:184
@ encoding_utf16_be
Definition: pugixml.hpp:181
@ encoding_utf8
Definition: pugixml.hpp:179
@ encoding_latin1
Definition: pugixml.hpp:187
@ encoding_utf16
Definition: pugixml.hpp:182
@ encoding_utf32_le
Definition: pugixml.hpp:183
@ encoding_auto
Definition: pugixml.hpp:178
@ encoding_wchar
Definition: pugixml.hpp:186
std::basic_string< PUGIXML_CHAR, std::char_traits< PUGIXML_CHAR >, std::allocator< PUGIXML_CHAR > > string_t
Definition: pugixml.hpp:95
const unsigned int format_no_declaration
Definition: pugixml.hpp:202
xml_node_type
Definition: pugixml.hpp:104
@ node_comment
Definition: pugixml.hpp:110
@ node_pcdata
Definition: pugixml.hpp:108
@ node_element
Definition: pugixml.hpp:107
@ node_doctype
Definition: pugixml.hpp:113
@ node_document
Definition: pugixml.hpp:106
@ node_declaration
Definition: pugixml.hpp:112
@ node_pi
Definition: pugixml.hpp:111
@ node_null
Definition: pugixml.hpp:105
@ node_cdata
Definition: pugixml.hpp:109
const unsigned int parse_trim_pcdata
Definition: pugixml.hpp:159
const unsigned int parse_wconv_attribute
Definition: pugixml.hpp:142
const unsigned int format_raw
Definition: pugixml.hpp:199
void(* deallocation_function)(void *ptr)
Definition: pugixml.hpp:1281
std::basic_string< char, std::char_traits< char >, std::allocator< char > > PUGIXML_FUNCTION as_utf8(const wchar_t *str)
Definition: pugixml.cpp:6198
static PUGI__FN void unspecified_bool_xpath_query(xpath_query ***)
Definition: pugixml.cpp:11132
const unsigned int parse_cdata
Definition: pugixml.hpp:129
static PUGI__FN void unspecified_bool_xml_node(xml_node ***)
Definition: pugixml.cpp:4581
const unsigned int parse_fragment
Definition: pugixml.hpp:163
void *(* allocation_function)(size_t size)
Definition: pugixml.hpp:1278
const unsigned int parse_wnorm_attribute
Definition: pugixml.hpp:145
static PUGI__FN void unspecified_bool_xml_attribute(xml_attribute ***)
Definition: pugixml.cpp:4336
const unsigned int parse_pi
Definition: pugixml.hpp:123
xml_parse_status
Definition: pugixml.hpp:874
@ status_append_invalid_root
Definition: pugixml.hpp:894
@ status_end_element_mismatch
Definition: pugixml.hpp:892
@ status_bad_end_element
Definition: pugixml.hpp:891
@ status_io_error
Definition: pugixml.hpp:878
@ status_bad_attribute
Definition: pugixml.hpp:890
@ status_file_not_found
Definition: pugixml.hpp:877
@ status_internal_error
Definition: pugixml.hpp:880
@ status_bad_start_element
Definition: pugixml.hpp:889
@ status_ok
Definition: pugixml.hpp:875
@ status_bad_comment
Definition: pugixml.hpp:885
@ status_bad_doctype
Definition: pugixml.hpp:887
@ status_out_of_memory
Definition: pugixml.hpp:879
@ status_unrecognized_tag
Definition: pugixml.hpp:882
@ status_bad_cdata
Definition: pugixml.hpp:886
@ status_bad_pcdata
Definition: pugixml.hpp:888
@ status_bad_pi
Definition: pugixml.hpp:884
@ status_no_document_element
Definition: pugixml.hpp:896
void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
Definition: pugixml.cpp:6223
deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
Definition: pugixml.cpp:6235
std::basic_string< wchar_t, std::char_traits< wchar_t >, std::allocator< wchar_t > > PUGIXML_FUNCTION as_wide(const char *str)
Definition: pugixml.cpp:6210
const unsigned int format_save_file_text
Definition: pugixml.hpp:208
allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
Definition: pugixml.cpp:6230
const unsigned int parse_escapes
Definition: pugixml.hpp:136
const unsigned int format_write_bom
Definition: pugixml.hpp:196
static PUGI__FN void unspecified_bool_xpath_node(xpath_node ***)
Definition: pugixml.cpp:10635
const unsigned int format_indent
Definition: pugixml.hpp:193
static PUGI__FN void unspecified_bool_xml_text(xml_text ***)
Definition: pugixml.cpp:5522
const unsigned int parse_eol
Definition: pugixml.hpp:139
const unsigned int parse_declaration
Definition: pugixml.hpp:148
const unsigned int parse_comments
Definition: pugixml.hpp:126
xpath_value_type
Definition: pugixml.hpp:993
@ xpath_type_number
Definition: pugixml.hpp:996
@ xpath_type_boolean
Definition: pugixml.hpp:998
@ xpath_type_none
Definition: pugixml.hpp:994
@ xpath_type_string
Definition: pugixml.hpp:997
@ xpath_type_node_set
Definition: pugixml.hpp:995
const unsigned int parse_ws_pcdata
Definition: pugixml.hpp:133
const unsigned int parse_ws_pcdata_single
Definition: pugixml.hpp:156
const unsigned int format_no_escapes
Definition: pugixml.hpp:205
PUGIXML_CHAR char_t
Definition: pugixml.hpp:91
const unsigned int parse_doctype
Definition: pugixml.hpp:151
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...
Definition: opencl-c-base.h:62
__PTRDIFF_TYPE__ ptrdiff_t
A signed integer type that is the result of subtracting two pointers.
Definition: opencl-c-base.h:48
float __ovld __cnfn sign(float x)
Returns 1.0 if x > 0, -0.0 if x = -0.0, +0.0 if x = +0.0, or -1.0 if x < 0.
float __ovld __cnfn length(float p)
Return the length of vector p, i.e., sqrt(p.x2 + p.y 2 + ...)
int __ovld __cnfn any(char x)
Returns 1 if the most significant bit in any component of x is set; otherwise returns 0.
float __ovld __cnfn step(float edge, float x)
Returns 0.0 if x < edge, otherwise it returns 1.0.
void destroy_node(xml_node_struct *n, xml_allocator &alloc)
Definition: pugixml.cpp:629
#define PUGI__CHECK_ERROR(err, m)
Definition: pugixml.cpp:2342
PUGI__FN void default_deallocate(void *ptr)
Definition: pugixml.cpp:180
PUGI__FN size_t strlength_wide(const wchar_t *s)
Definition: pugixml.cpp:237
#define PUGI__OPTSET(OPT)
Definition: pugixml.cpp:2314
PUGI__FN double round_nearest_nzero(double value)
Definition: pugixml.cpp:7383
PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t *data, size_t size)
Definition: pugixml.cpp:1539
PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct *doc, xml_node_struct *root, void *contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t **out_buffer)
Definition: pugixml.cpp:4236
PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl *impl, const xpath_node &n, xpath_stack_data &sd)
Definition: pugixml.cpp:10576
ast_type_t
Definition: pugixml.cpp:8174
@ ast_op_and
Definition: pugixml.cpp:8177
@ ast_number_constant
Definition: pugixml.cpp:8195
@ ast_filter
Definition: pugixml.cpp:8192
@ ast_func_substring_3
Definition: pugixml.cpp:8215
@ ast_func_sum
Definition: pugixml.cpp:8228
@ ast_func_name_1
Definition: pugixml.cpp:8206
@ ast_func_floor
Definition: pugixml.cpp:8229
@ ast_op_divide
Definition: pugixml.cpp:8187
@ ast_func_concat
Definition: pugixml.cpp:8209
@ ast_op_equal
Definition: pugixml.cpp:8178
@ ast_unknown
Definition: pugixml.cpp:8175
@ ast_func_name_0
Definition: pugixml.cpp:8205
@ ast_predicate
Definition: pugixml.cpp:8191
@ ast_filter_posinv
Definition: pugixml.cpp:8193
@ ast_func_not
Definition: pugixml.cpp:8222
@ ast_variable
Definition: pugixml.cpp:8196
@ ast_func_string_1
Definition: pugixml.cpp:8208
@ ast_func_string_0
Definition: pugixml.cpp:8207
@ ast_func_number_0
Definition: pugixml.cpp:8226
@ ast_op_union
Definition: pugixml.cpp:8190
@ ast_func_substring_before
Definition: pugixml.cpp:8212
@ ast_func_string_length_0
Definition: pugixml.cpp:8216
@ ast_func_local_name_1
Definition: pugixml.cpp:8202
@ ast_func_namespace_uri_0
Definition: pugixml.cpp:8203
@ ast_func_lang
Definition: pugixml.cpp:8225
@ ast_func_true
Definition: pugixml.cpp:8223
@ ast_func_normalize_space_1
Definition: pugixml.cpp:8219
@ ast_op_not_equal
Definition: pugixml.cpp:8179
@ ast_func_contains
Definition: pugixml.cpp:8211
@ ast_op_greater
Definition: pugixml.cpp:8181
@ ast_op_negate
Definition: pugixml.cpp:8189
@ ast_func_substring_2
Definition: pugixml.cpp:8214
@ ast_func_position
Definition: pugixml.cpp:8198
@ ast_string_constant
Definition: pugixml.cpp:8194
@ ast_func_ceiling
Definition: pugixml.cpp:8230
@ ast_op_subtract
Definition: pugixml.cpp:8185
@ ast_func_last
Definition: pugixml.cpp:8197
@ ast_func_normalize_space_0
Definition: pugixml.cpp:8218
@ ast_func_boolean
Definition: pugixml.cpp:8221
@ ast_op_less_or_equal
Definition: pugixml.cpp:8182
@ ast_step
Definition: pugixml.cpp:8232
@ ast_op_multiply
Definition: pugixml.cpp:8186
@ ast_func_count
Definition: pugixml.cpp:8199
@ ast_func_substring_after
Definition: pugixml.cpp:8213
@ ast_func_namespace_uri_1
Definition: pugixml.cpp:8204
@ ast_step_root
Definition: pugixml.cpp:8233
@ ast_func_translate
Definition: pugixml.cpp:8220
@ ast_func_round
Definition: pugixml.cpp:8231
@ ast_func_number_1
Definition: pugixml.cpp:8227
@ ast_func_string_length_1
Definition: pugixml.cpp:8217
@ ast_func_starts_with
Definition: pugixml.cpp:8210
@ ast_op_add
Definition: pugixml.cpp:8184
@ ast_op_or
Definition: pugixml.cpp:8176
@ ast_op_greater_or_equal
Definition: pugixml.cpp:8183
@ ast_func_false
Definition: pugixml.cpp:8224
@ ast_func_local_name_0
Definition: pugixml.cpp:8201
@ ast_op_mod
Definition: pugixml.cpp:8188
@ ast_func_id
Definition: pugixml.cpp:8200
@ ast_op_less
Definition: pugixml.cpp:8180
PUGI__FN xml_encoding get_write_native_encoding()
Definition: pugixml.cpp:3038
PUGI__FN bool convert_number_to_boolean(double value)
Definition: pugixml.cpp:7169
PUGI__FN void as_utf8_end(char *buffer, size_t size, const wchar_t *str, size_t length)
Definition: pugixml.cpp:1628
wchar_selector< sizeof(wchar_t)>::writer wchar_writer
Definition: pugixml.cpp:927
PUGI__FN xml_encoding get_wchar_encoding()
Definition: pugixml.cpp:1193
lexeme_t
Definition: pugixml.cpp:7824
@ lex_multiply
Definition: pugixml.cpp:7834
@ lex_double_slash
Definition: pugixml.cpp:7842
@ lex_quoted_string
Definition: pugixml.cpp:7839
@ lex_not_equal
Definition: pugixml.cpp:7827
@ lex_axis_attribute
Definition: pugixml.cpp:7847
@ lex_less
Definition: pugixml.cpp:7828
@ lex_equal
Definition: pugixml.cpp:7826
@ lex_greater_or_equal
Definition: pugixml.cpp:7831
@ lex_none
Definition: pugixml.cpp:7825
@ lex_union
Definition: pugixml.cpp:7835
@ lex_comma
Definition: pugixml.cpp:7846
@ lex_close_brace
Definition: pugixml.cpp:7838
@ lex_slash
Definition: pugixml.cpp:7841
@ lex_var_ref
Definition: pugixml.cpp:7836
@ lex_dot
Definition: pugixml.cpp:7848
@ lex_minus
Definition: pugixml.cpp:7833
@ lex_string
Definition: pugixml.cpp:7845
@ lex_eof
Definition: pugixml.cpp:7851
@ lex_plus
Definition: pugixml.cpp:7832
@ lex_number
Definition: pugixml.cpp:7840
@ lex_greater
Definition: pugixml.cpp:7829
@ lex_double_dot
Definition: pugixml.cpp:7849
@ lex_less_or_equal
Definition: pugixml.cpp:7830
@ lex_close_square_brace
Definition: pugixml.cpp:7844
@ lex_open_square_brace
Definition: pugixml.cpp:7843
@ lex_open_brace
Definition: pugixml.cpp:7837
@ lex_double_colon
Definition: pugixml.cpp:7850
PUGI__FN void text_output_cdata(xml_buffered_writer &writer, const char_t *s)
Definition: pugixml.cpp:3448
bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t *target)
Definition: pugixml.cpp:1683
PUGI__FN bool get_mutable_buffer(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, bool is_mutable)
Definition: pugixml.cpp:1270
static const uintptr_t xml_memory_page_type_mask
Definition: pugixml.cpp:301
PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator *alloc)
Definition: pugixml.cpp:7231
PUGI__FN bool is_little_endian()
Definition: pugixml.cpp:1186
PUGI__FN unsigned int hash_string(const char_t *str)
Definition: pugixml.cpp:7564
PUGI__FN size_t zero_terminate_buffer(void *buffer, size_t size, xml_encoding encoding)
Definition: pugixml.cpp:3941
#define PUGI__IS_CHARTYPE(c, ct)
Definition: pugixml.cpp:1183
PUGI__FN double gen_nan()
Definition: pugixml.cpp:7103
PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
Definition: pugixml.cpp:2248
PUGI__FN T * new_xpath_variable(const char_t *name)
Definition: pugixml.cpp:7584
PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
Definition: pugixml.cpp:2054
PUGI__FN bool convert_buffer(char_t *&out_buffer, size_t &out_length, xml_encoding encoding, const void *contents, size_t size, bool is_mutable)
Definition: pugixml.cpp:1588
PUGI__FN void convert_utf_endian_swap(T *result, const T *data, size_t length)
Definition: pugixml.cpp:1103
PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream< T > &stream, void **out_buffer, size_t *out_size)
Definition: pugixml.cpp:4101
PUGI__FN xml_parse_result load_stream_impl(xml_document &doc, std::basic_istream< T > &stream, unsigned int options, xml_encoding encoding)
Definition: pugixml.cpp:4143
PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, int value)
Definition: pugixml.cpp:3850
I min_element(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:6332
#define PUGI__ENDSEG()
Definition: pugixml.cpp:2335
#define ENDSWITH(c, e)
Definition: pugixml.cpp:1933
static const uintptr_t xml_memory_page_pointer_mask
Definition: pugixml.cpp:298
PUGI__FN const char_t * find_substring(const char_t *s, const char_t *p)
Definition: pugixml.cpp:6887
PUGI__FN const char_t * local_name(const xpath_node &node)
Definition: pugixml.cpp:7395
void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:6511
void destroy_attribute(xml_attribute_struct *a, xml_allocator &alloc)
Definition: pugixml.cpp:616
char_t *(* strconv_pcdata_t)(char_t *)
Definition: pugixml.cpp:1997
PUGI__FN bool convert_buffer_utf32(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
Definition: pugixml.cpp:1513
wchar_selector< sizeof(wchar_t)>::counter wchar_counter
Definition: pugixml.cpp:926
PUGI__FN const char_t * find_char(const char_t *s, char_t c)
Definition: pugixml.cpp:6878
void median(I first, I middle, I last, const Pred &pred)
Definition: pugixml.cpp:6491
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN bool starts_with(const char_t *string, const char_t *pattern)
Definition: pugixml.cpp:6867
#define PUGI__IS_CHARTYPEX(c, ct)
Definition: pugixml.cpp:1184
I unique(I begin, I end)
Definition: pugixml.cpp:6351
bool has_declaration(const xml_node &node)
Definition: pugixml.cpp:3625
void insertion_sort(I begin, I end, const Pred &pred, T *)
Definition: pugixml.cpp:6384
static const unsigned char chartypex_table[256]
Definition: pugixml.cpp:1158
PUGI__FN bool check_string_to_number_format(const char_t *string)
Definition: pugixml.cpp:7300
PUGI__NS_BEGIN PUGI__FN void * default_allocate(size_t size)
Definition: pugixml.cpp:175
PUGI__FN size_t get_valid_length(const char_t *data, size_t length)
Definition: pugixml.cpp:3147
PUGI__FN std::string as_utf8_impl(const wchar_t *str, size_t length)
Definition: pugixml.cpp:1642
xml_memory_management_function_storage< int > xml_memory
Definition: pugixml.cpp:197
PUGI__FN xml_parse_status get_file_size(FILE *file, size_t &out_result)
Definition: pugixml.cpp:3899
PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh)
Definition: pugixml.cpp:6967
PUGI__FN xpath_variable * get_variable_scratch(char_t(&buffer)[32], xpath_variable_set *set, const char_t *begin, const char_t *end)
Definition: pugixml.cpp:7655
PUGI__FN FILE * open_file_wide(const wchar_t *path, const wchar_t *mode)
Definition: pugixml.cpp:4198
static const unsigned char chartype_table[256]
Definition: pugixml.cpp:1131
PUGI__NS_END PUGI__NS_BEGIN uint16_t endian_swap(uint16_t value)
Definition: pugixml.cpp:735
xml_node_struct * allocate_node(xml_allocator &alloc, xml_node_type type)
Definition: pugixml.cpp:608
void copy_backwards(I begin, I end, I target)
Definition: pugixml.cpp:6377
PUGI__FN unsigned int node_height(xml_node n)
Definition: pugixml.cpp:6954
bool is_text_node(xml_node_struct *node)
Definition: pugixml.cpp:3706
PUGI__FN xpath_string string_value(const xpath_node &na, xpath_allocator *alloc)
Definition: pugixml.cpp:6903
PUGI__FN xml_parse_result load_file_impl(xml_document &doc, FILE *file, unsigned int options, xml_encoding encoding)
Definition: pugixml.cpp:3965
void reverse(I begin, I end)
Definition: pugixml.cpp:6344
#define PUGI__FN_NO_INLINE
Definition: pugixml.cpp:154
PUGI__FN char_t * strconv_escape(char_t *s, gap &g)
Definition: pugixml.cpp:1790
#define PUGI__STATIC_ASSERT(cond)
Definition: pugixml.cpp:92
#define PUGI__NS_BEGIN
Definition: pugixml.cpp:141
PUGI__FN void node_output(xml_buffered_writer &writer, const xml_node &node, const char_t *indent, unsigned int flags, unsigned int depth)
Definition: pugixml.cpp:3487
PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream< T > &stream, void **out_buffer, size_t *out_size)
Definition: pugixml.cpp:4040
#define PUGI__FN
Definition: pugixml.cpp:153
PUGI__FN bool get_value_bool(const char_t *value, bool def)
Definition: pugixml.cpp:3779
#define PUGI__SKIPWS()
Definition: pugixml.cpp:2309
#define PUGI__DMC_VOLATILE
Definition: pugixml.cpp:102
PUGI__FN double get_value_double(const char_t *value, double def)
Definition: pugixml.cpp:3755
#define PUGI__THROW_ERROR(err, m)
Definition: pugixml.cpp:2341
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node *begin, xpath_node *end, xpath_node_set::type_t type, bool rev)
Definition: pugixml.cpp:7685
xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset=0)
Definition: pugixml.cpp:2293
char_t *(* strconv_attribute_t)(char_t *, char_t)
Definition: pugixml.cpp:2082
PUGI__FN size_t convert_buffer_output(char_t *, uint8_t *r_u8, uint16_t *r_u16, uint32_t *r_u32, const char_t *data, size_t length, xml_encoding encoding)
Definition: pugixml.cpp:3165
#define PUGI__SCANFOR(X)
Definition: pugixml.cpp:2325
bool allow_insert_child(xml_node_type parent, xml_node_type child)
Definition: pugixml.cpp:3640
PUGI__FN char_t * strconv_cdata(char_t *s, char_t endch)
Definition: pugixml.cpp:1966
static const uintptr_t xml_memory_page_name_allocated_mask
Definition: pugixml.cpp:299
PUGI__NS_END static PUGI__NS_BEGIN const size_t xml_memory_page_size
Definition: pugixml.cpp:289
PUGI__FN bool convert_string_to_number_scratch(char_t(&buffer)[32], const char_t *begin, const char_t *end, double *out_result)
Definition: pugixml.cpp:7351
#define PUGI__NS_END
Definition: pugixml.cpp:148
PUGI__NS_END PUGI__NS_BEGIN xml_attribute_struct * allocate_attribute(xml_allocator &alloc)
Definition: pugixml.cpp:600
PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
Definition: pugixml.cpp:3047
PUGI__FN void convert_number_to_mantissa_exponent(double value, char *buffer, size_t buffer_size, char **out_mantissa, int *out_exponent)
Definition: pugixml.cpp:7199
PUGI__FN void delete_xpath_variable(T *var)
Definition: pugixml.cpp:7624
PUGI__FN bool convert_buffer_latin1(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, bool is_mutable)
Definition: pugixml.cpp:1548
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:6324
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN size_t strlength(const char_t *s)
Definition: pugixml.cpp:203
PUGI__FN_NO_INLINE xml_attribute_struct * append_attribute_ll(xml_node_struct *node, xml_allocator &alloc)
Definition: pugixml.cpp:688
PUGI__FN void recursive_copy_skip(xml_node &dest, const xml_node &source, const xml_node &skip)
Definition: pugixml.cpp:3652
PUGI__FN double round_nearest(double value)
Definition: pugixml.cpp:7378
xml_allocator & get_allocator(const xml_node_struct *node)
Definition: pugixml.cpp:590
PUGI__FN void node_output_attributes(xml_buffered_writer &writer, const xml_node &node, unsigned int flags)
Definition: pugixml.cpp:3471
nodetest_t
Definition: pugixml.cpp:8254
@ nodetest_all
Definition: pugixml.cpp:8262
@ nodetest_name
Definition: pugixml.cpp:8256
@ nodetest_none
Definition: pugixml.cpp:8255
@ nodetest_type_text
Definition: pugixml.cpp:8260
@ nodetest_all_in_namespace
Definition: pugixml.cpp:8263
@ nodetest_pi
Definition: pugixml.cpp:8261
@ nodetest_type_comment
Definition: pugixml.cpp:8258
@ nodetest_type_node
Definition: pugixml.cpp:8257
@ nodetest_type_pi
Definition: pugixml.cpp:8259
static const uintptr_t xml_memory_page_alignment
Definition: pugixml.cpp:297
PUGI__FN bool set_value_buffer(char_t *&dest, uintptr_t &header, uintptr_t header_mask, char(&buf)[128])
Definition: pugixml.cpp:3838
#define PUGI__POPNODE()
Definition: pugixml.cpp:2321
PUGI__FN bool strcpy_insitu(char_t *&dest, uintptr_t &header, uintptr_t header_mask, const char_t *source)
Definition: pugixml.cpp:1698
void partition(I begin, I middle, I end, const Pred &pred, I *out_eqbeg, I *out_eqend)
Definition: pugixml.cpp:6417
PUGI__FN void normalize_space(char_t *buffer)
Definition: pugixml.cpp:7474
PUGI__FN bool strequalrange(const char_t *lhs, const char_t *rhs, size_t count)
Definition: pugixml.cpp:227
PUGI__FN bool save_file_impl(const xml_document &doc, FILE *file, const char_t *indent, unsigned int flags, xml_encoding encoding)
Definition: pugixml.cpp:4220
PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
Definition: pugixml.cpp:1203
PUGI__FN double convert_string_to_number(const char_t *string)
Definition: pugixml.cpp:7337
PUGI__FN bool is_nan(double value)
Definition: pugixml.cpp:7119
static const uintptr_t xml_memory_page_value_allocated_mask
Definition: pugixml.cpp:300
PUGI__FN xpath_node xpath_first(const xpath_node *begin, const xpath_node *end, xpath_node_set::type_t type)
Definition: pugixml.cpp:7702
PUGI__FN const char_t * convert_number_to_string_special(double value)
Definition: pugixml.cpp:7132
#define PUGI__PUSHNODE(TYPE)
Definition: pugixml.cpp:2315
PUGI__FN std::basic_string< wchar_t > as_wide_impl(const char *str, size_t size)
Definition: pugixml.cpp:1658
PUGI__FN char_t * strconv_comment(char_t *s, char_t endch)
Definition: pugixml.cpp:1935
static const xpath_node_set dummy_node_set
Definition: pugixml.cpp:7562
PUGI__FN size_t as_utf8_begin(const wchar_t *str, size_t length)
Definition: pugixml.cpp:1622
PUGI__FN void text_output(xml_buffered_writer &writer, const char_t *s, chartypex_t type, unsigned int flags)
Definition: pugixml.cpp:3440
PUGI__FN void translate(char_t *buffer, const char_t *from, const char_t *to)
Definition: pugixml.cpp:7504
PUGI__FN_NO_INLINE xml_node_struct * append_node(xml_node_struct *node, xml_allocator &alloc, xml_node_type type=node_element)
Definition: pugixml.cpp:660
#define PUGI__SCANWHILE(X)
Definition: pugixml.cpp:2330
PUGI__FN char * convert_path_heap(const wchar_t *str)
Definition: pugixml.cpp:4179
PUGI__FN void truncate_zeros(char *begin, char *end)
Definition: pugixml.cpp:7174
PUGI__FN unsigned int get_value_uint(const char_t *value, unsigned int def)
Definition: pugixml.cpp:3741
axis_t
Definition: pugixml.cpp:8237
@ axis_preceding
Definition: pugixml.cpp:8248
@ axis_ancestor_or_self
Definition: pugixml.cpp:8239
@ axis_attribute
Definition: pugixml.cpp:8240
@ axis_following_sibling
Definition: pugixml.cpp:8245
@ axis_child
Definition: pugixml.cpp:8241
@ axis_descendant
Definition: pugixml.cpp:8242
@ axis_descendant_or_self
Definition: pugixml.cpp:8243
@ axis_self
Definition: pugixml.cpp:8250
@ axis_following
Definition: pugixml.cpp:8244
@ axis_ancestor
Definition: pugixml.cpp:8238
@ axis_preceding_sibling
Definition: pugixml.cpp:8249
@ axis_namespace
Definition: pugixml.cpp:8246
@ axis_parent
Definition: pugixml.cpp:8247
chartype_t
Definition: pugixml.cpp:1120
@ ct_parse_comment
Definition: pugixml.cpp:1126
@ ct_start_symbol
Definition: pugixml.cpp:1128
@ ct_parse_attr
Definition: pugixml.cpp:1122
@ ct_parse_attr_ws
Definition: pugixml.cpp:1123
@ ct_parse_cdata
Definition: pugixml.cpp:1125
@ ct_parse_pcdata
Definition: pugixml.cpp:1121
@ ct_space
Definition: pugixml.cpp:1124
@ ct_symbol
Definition: pugixml.cpp:1127
PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void *contents, size_t size)
Definition: pugixml.cpp:1240
PUGI__FN float get_value_float(const char_t *value, float def)
Definition: pugixml.cpp:3767
void median3(I first, I middle, I last, const Pred &pred)
Definition: pugixml.cpp:6480
PUGI__FN const void * document_order(const xpath_node &xnode)
Definition: pugixml.cpp:7006
PUGI__FN const char_t * qualified_name(const xpath_node &node)
Definition: pugixml.cpp:7390
PUGI__FN bool strequal(const char_t *src, const char_t *dst)
Definition: pugixml.cpp:215
PUGI__FN bool convert_buffer_utf16(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
Definition: pugixml.cpp:1486
chartypex_t
Definition: pugixml.cpp:1150
@ ctx_digit
Definition: pugixml.cpp:1154
@ ctx_special_attr
Definition: pugixml.cpp:1152
@ ctx_symbol
Definition: pugixml.cpp:1155
@ ctx_start_symbol
Definition: pugixml.cpp:1153
@ ctx_special_pcdata
Definition: pugixml.cpp:1151
PUGI__FN xpath_string xpath_string_const(const char_t *str)
Definition: pugixml.cpp:6860
PUGI__FN const char_t * namespace_uri(const xml_node &node)
Definition: pugixml.cpp:7427
PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node)
Definition: pugixml.cpp:6998
PUGI__FN int get_value_int(const char_t *value, int def)
Definition: pugixml.cpp:3727
PUGI__FN char_t tolower_ascii(char_t ch)
Definition: pugixml.cpp:6898
PUGI__FN int get_integer_base(const char_t *value)
Definition: pugixml.cpp:3714
PUGI__FN void text_output_escaped(xml_buffered_writer &writer, const char_t *s, chartypex_t type)
Definition: pugixml.cpp:3397
#define PUGIXML_FUNCTION
Definition: pugixml.hpp:67
#define PUGIXML_TEXT(t)
Definition: pugixml.hpp:84
#define false
Definition: stdbool.h:17
#define bool
Definition: stdbool.h:15
__WCHAR_TYPE__ wchar_t
Definition: stddef.h:74
#define offsetof(t, d)
Definition: stddef.h:104
static const axis_t axis
Definition: pugixml.cpp:8269
void * data
Definition: pugixml.cpp:267
void(* deleter)(void *)
Definition: pugixml.cpp:268
void * release()
Definition: pugixml.cpp:278
buffer_holder(void *data_, void(*deleter_)(void *))
Definition: pugixml.cpp:270
bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
Definition: pugixml.cpp:7035
bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
Definition: pugixml.cpp:7094
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:6290
char_t * flush(char_t *s)
Definition: pugixml.cpp:1775
char_t * end
Definition: pugixml.cpp:1751
gap()
Definition: pugixml.cpp:1754
void push(char_t *&s, size_t count)
Definition: pugixml.cpp:1758
size_t size
Definition: pugixml.cpp:1752
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:897
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:890
uint8_t * value_type
Definition: pugixml.cpp:888
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:6317
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:6308
namespace_uri_predicate(const char_t *name)
Definition: pugixml.cpp:7408
const char_t * prefix
Definition: pugixml.cpp:7405
bool operator()(const xml_attribute &a) const
Definition: pugixml.cpp:7416
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:6299
A 'name=value' XML attribute structure.
Definition: pugixml.cpp:522
xml_attribute_struct * prev_attribute_c
Previous attribute (cyclic list)
Definition: pugixml.cpp:534
xml_attribute_struct(impl::xml_memory_page *page)
Default ctor.
Definition: pugixml.cpp:524
xml_attribute_struct * next_attribute
Next attribute.
Definition: pugixml.cpp:535
char_t * name
Pointer to attribute name.
Definition: pugixml.cpp:531
char_t * value
Pointer to attribute value.
Definition: pugixml.cpp:532
An XML document tree node.
Definition: pugixml.cpp:540
char_t * value
Pointer to any associated string data.
Definition: pugixml.cpp:560
xml_attribute_struct * first_attribute
First attribute.
Definition: pugixml.cpp:567
xml_node_struct * prev_sibling_c
Left brother (cyclic list)
Definition: pugixml.cpp:564
xml_node_struct * next_sibling
Right brother.
Definition: pugixml.cpp:565
char_t * name
Pointer to element name.
Definition: pugixml.cpp:559
xml_node_struct * parent
Pointer to parent.
Definition: pugixml.cpp:557
xml_node_struct * first_child
First child.
Definition: pugixml.cpp:562
xml_node_struct(impl::xml_memory_page *page, xml_node_type type)
Default ctor.
Definition: pugixml.cpp:543
const char * description() const
Definition: pugixml.cpp:5913
xml_parse_status status
Definition: pugixml.hpp:903
const char * description() const
Definition: pugixml.cpp:10792
static char_t * parse_eol(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2184
static char_t * parse_wconv(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2144
static char_t * parse_simple(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2219
static char_t * parse_wnorm(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2087
static char_t * parse(char_t *s)
Definition: pugixml.cpp:2002
size_t value_type
Definition: pugixml.cpp:816
static value_type low(value_type result, uint32_t)
Definition: pugixml.cpp:818
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:820
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:834
uint16_t * value_type
Definition: pugixml.cpp:825
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:827
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:845
static value_type low(value_type result, uint32_t)
Definition: pugixml.cpp:855
size_t value_type
Definition: pugixml.cpp:853
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:857
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:864
uint32_t * value_type
Definition: pugixml.cpp:862
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:871
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:878
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:749
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:762
size_t value_type
Definition: pugixml.cpp:747
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:808
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:798
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:773
uint8_t * value_type
Definition: pugixml.cpp:771
static Traits::value_type decode_wchar_block_impl(const uint32_t *data, size_t size, typename Traits::value_type result)
Definition: pugixml.cpp:1088
static Traits::value_type decode_latin1_block(const uint8_t *data, size_t size, typename Traits::value_type result)
Definition: pugixml.cpp:1071
static Traits::value_type decode_wchar_block_impl(const uint16_t *data, size_t size, typename Traits::value_type result)
Definition: pugixml.cpp:1082
static Traits::value_type decode_wchar_block(const wchar_t *data, size_t size, typename Traits::value_type result)
Definition: pugixml.cpp:1094
static Traits::value_type decode_utf8_block(const uint8_t *data, size_t size, typename Traits::value_type result)
Definition: pugixml.cpp:932
static Traits::value_type decode_utf32_block(const uint32_t *data, size_t size, typename Traits::value_type result)
Definition: pugixml.cpp:1045
static Traits::value_type decode_utf16_block(const uint16_t *data, size_t size, typename Traits::value_type result)
Definition: pugixml.cpp:1000
utf16_counter counter
Definition: pugixml.cpp:914
utf16_writer writer
Definition: pugixml.cpp:915
utf32_writer writer
Definition: pugixml.cpp:923
utf32_counter counter
Definition: pugixml.cpp:922
static void deallocate_page(xml_memory_page *page)
Definition: pugixml.cpp:370
void * allocate_memory_oob(size_t size, xml_memory_page *&out_page)
Definition: pugixml.cpp:477
xml_memory_page * _root
Definition: pugixml.cpp:473
size_t _busy_size
Definition: pugixml.cpp:474
xml_memory_page * allocate_page(size_t data_size)
Definition: pugixml.cpp:347
void deallocate_memory(void *ptr, size_t size, xml_memory_page *page)
Definition: pugixml.cpp:388
char_t * allocate_string(size_t length)
Definition: pugixml.cpp:424
xml_allocator(xml_memory_page *root)
Definition: pugixml.cpp:345
void deallocate_string(char_t *string)
Definition: pugixml.cpp:453
void * allocate_memory(size_t size, xml_memory_page *&out_page)
Definition: pugixml.cpp:374
const char_t * buffer
Definition: pugixml.cpp:585
xml_document_struct(xml_memory_page *page)
Definition: pugixml.cpp:580
xml_extra_buffer * extra_buffers
Definition: pugixml.cpp:587
xml_extra_buffer * next
Definition: pugixml.cpp:575
char_t * buffer
Definition: pugixml.cpp:574
static deallocation_function deallocate
Definition: pugixml.cpp:189
static allocation_function allocate
Definition: pugixml.cpp:188
xml_memory_page * prev
Definition: pugixml.cpp:328
size_t busy_size
Definition: pugixml.cpp:331
xml_memory_page * next
Definition: pugixml.cpp:329
static xml_memory_page * construct(void *memory)
Definition: pugixml.cpp:307
size_t freed_size
Definition: pugixml.cpp:332
char data[1]
Definition: pugixml.cpp:334
xml_allocator * allocator
Definition: pugixml.cpp:324
xml_parse_status error_status
Definition: pugixml.cpp:2306
char_t * parse_doctype_ignore(char_t *s)
Definition: pugixml.cpp:2395
xml_allocator alloc
Definition: pugixml.cpp:2304
char_t * error_offset
Definition: pugixml.cpp:2305
char_t * parse_question(char_t *s, xml_node_struct *&ref_cursor, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:2595
char_t * parse_exclamation(char_t *s, xml_node_struct *cursor, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:2472
static xml_parse_result parse(char_t *buffer, size_t length, xml_document_struct *xmldoc, xml_node_struct *root, unsigned int optmsk)
Definition: pugixml.cpp:2980
static bool has_element_node_siblings(xml_node_struct *node)
Definition: pugixml.cpp:2966
char_t * parse_doctype_primitive(char_t *s)
Definition: pugixml.cpp:2357
char_t * parse_tree(char_t *s, xml_node_struct *root, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:2694
char_t * parse_doctype_group(char_t *s, char_t endch, bool toplevel)
Definition: pugixml.cpp:2423
xml_parser(const xml_allocator &alloc_)
Definition: pugixml.cpp:2348
static char_t * parse_skip_bom(char_t *s)
Definition: pugixml.cpp:2960
T data[xml_memory_page_size/sizeof(T)]
Definition: pugixml.cpp:4036
static void destroy(void *ptr)
Definition: pugixml.cpp:4018
static xml_stream_chunk * create()
Definition: pugixml.cpp:4011
xml_stream_chunk * next
Definition: pugixml.cpp:4033
xpath_allocator _state
Definition: pugixml.cpp:6711
xpath_allocator * _target
Definition: pugixml.cpp:6710
xpath_allocator_capture(xpath_allocator *alloc)
Definition: pugixml.cpp:6706
xpath_context(const xpath_node &n_, size_t position_, size_t size_)
Definition: pugixml.cpp:7820
xpath_node n
Definition: pugixml.cpp:7817
size_t position
Definition: pugixml.cpp:7818
const char_t * begin
Definition: pugixml.cpp:7856
const char_t * end
Definition: pugixml.cpp:7857
bool operator==(const char_t *other) const
Definition: pugixml.cpp:7861
xpath_memory_block * next
Definition: pugixml.cpp:6547
char data[4096]
Definition: pugixml.cpp:6555
xpath_value_type rettype
Definition: pugixml.cpp:10402
binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_)
Definition: pugixml.cpp:10407
static binary_op_t parse(xpath_lexer &lexer)
Definition: pugixml.cpp:10412
void throw_error(const char *message)
Definition: pugixml.cpp:9702
xpath_ast_node * parse_filter_expression()
Definition: pugixml.cpp:10096
const char_t * alloc_string(const xpath_lexer_string &value)
Definition: pugixml.cpp:9733
xpath_ast_node * parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node *args[2])
Definition: pugixml.cpp:9753
xpath_ast_node * parse_primary_expression()
Definition: pugixml.cpp:9989
xpath_variable_set * _variables
Definition: pugixml.cpp:9692
xpath_parser(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
Definition: pugixml.cpp:10515
xpath_lexer _lexer
Definition: pugixml.cpp:9689
xpath_ast_node * parse()
Definition: pugixml.cpp:10520
xpath_ast_node * parse_function(const xpath_lexer_string &name, size_t argc, xpath_ast_node *args[2])
Definition: pugixml.cpp:9763
nodetest_t parse_node_test_type(const xpath_lexer_string &name)
Definition: pugixml.cpp:9953
xpath_ast_node * parse_step(xpath_ast_node *set)
Definition: pugixml.cpp:10128
xpath_parse_result * _result
Definition: pugixml.cpp:9694
xpath_ast_node * parse_path_or_unary_expression()
Definition: pugixml.cpp:10337
char_t _scratch[32]
Definition: pugixml.cpp:9696
xpath_ast_node * parse_location_path()
Definition: pugixml.cpp:10299
const char_t * _query
Definition: pugixml.cpp:9691
xpath_ast_node * parse_relative_location_path(xpath_ast_node *set)
Definition: pugixml.cpp:10279
static xpath_ast_node * parse(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
Definition: pugixml.cpp:10533
xpath_allocator * _alloc
Definition: pugixml.cpp:9688
axis_t parse_axis_name(const xpath_lexer_string &name, bool &specified)
Definition: pugixml.cpp:9885
xpath_ast_node * parse_expression()
Definition: pugixml.cpp:10513
xpath_ast_node * parse_expression_rec(xpath_ast_node *lhs, int limit)
Definition: pugixml.cpp:10464
void * alloc_node()
Definition: pugixml.cpp:9723
void throw_error_oom()
Definition: pugixml.cpp:9714
xpath_memory_block block
Definition: pugixml.cpp:10573
static void destroy(void *ptr)
Definition: pugixml.cpp:10557
xpath_ast_node * root
Definition: pugixml.cpp:10571
xpath_allocator alloc
Definition: pugixml.cpp:10572
static xpath_query_impl * create()
Definition: pugixml.cpp:10550
xpath_allocator temp
Definition: pugixml.cpp:6724
xpath_memory_block blocks[2]
Definition: pugixml.cpp:6722
xpath_allocator result
Definition: pugixml.cpp:6723
xpath_stack stack
Definition: pugixml.cpp:6725
xpath_allocator * temp
Definition: pugixml.cpp:6717
xpath_allocator * result
Definition: pugixml.cpp:6716
xpath_node_set value
Definition: pugixml.cpp:7558
#define fmod(__x, __y)
Definition: tgmath.h:798
#define floor(__x)
Definition: tgmath.h:722
#define ceil(__x)
Definition: tgmath.h:601