μHAL (v2.7.9)
Part of the IPbus software repository
pugixml.cpp
Go to the documentation of this file.
1 
14 #ifndef SOURCE_PUGIXML_CPP
15 #define SOURCE_PUGIXML_CPP
16 
17 #include "pugixml.hpp"
18 
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <limits.h>
24 
25 #ifdef PUGIXML_WCHAR_MODE
26 # include <wchar.h>
27 #endif
28 
29 #ifndef PUGIXML_NO_XPATH
30 # include <math.h>
31 # include <float.h>
32 #endif
33 
34 #ifndef PUGIXML_NO_STL
35 # include <istream>
36 # include <ostream>
37 # include <string>
38 #endif
39 
40 // For placement new
41 #include <new>
42 
43 #ifdef _MSC_VER
44 # pragma warning(push)
45 # pragma warning(disable: 4127) // conditional expression is constant
46 # pragma warning(disable: 4324) // structure was padded due to __declspec(align())
47 # pragma warning(disable: 4702) // unreachable code
48 # pragma warning(disable: 4996) // this function or variable may be unsafe
49 #endif
50 
51 #if defined(_MSC_VER) && defined(__c2__)
52 # pragma clang diagnostic push
53 # pragma clang diagnostic ignored "-Wdeprecated" // this function or variable may be unsafe
54 #endif
55 
56 #ifdef __INTEL_COMPILER
57 # pragma warning(disable: 177) // function was declared but never referenced
58 # pragma warning(disable: 279) // controlling expression is constant
59 # pragma warning(disable: 1478 1786) // function was declared "deprecated"
60 # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type
61 #endif
62 
63 #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
64 # pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away
65 #endif
66 
67 #ifdef __BORLANDC__
68 # pragma option push
69 # pragma warn -8008 // condition is always false
70 # pragma warn -8066 // unreachable code
71 #endif
72 
73 #ifdef __SNC__
74 // Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug
75 # pragma diag_suppress=178 // function was declared but never referenced
76 # pragma diag_suppress=237 // controlling expression is constant
77 #endif
78 
79 #ifdef __TI_COMPILER_VERSION__
80 # pragma diag_suppress 179 // function was declared but never referenced
81 #endif
82 
83 // Inlining controls
84 #if defined(_MSC_VER) && _MSC_VER >= 1300
85 # define PUGI__NO_INLINE __declspec(noinline)
86 #elif defined(__GNUC__)
87 # define PUGI__NO_INLINE __attribute__((noinline))
88 #else
89 # define PUGI__NO_INLINE
90 #endif
91 
92 // Branch weight controls
93 #if defined(__GNUC__) && !defined(__c2__)
94 # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0)
95 #else
96 # define PUGI__UNLIKELY(cond) (cond)
97 #endif
98 
99 // Simple static assertion
100 #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
101 
102 // Digital Mars C++ bug workaround for passing char loaded from memory via stack
103 #ifdef __DMC__
104 # define PUGI__DMC_VOLATILE volatile
105 #else
106 # define PUGI__DMC_VOLATILE
107 #endif
108 
109 // Integer sanitizer workaround; we only apply this for clang since gcc8 has no_sanitize but not unsigned-integer-overflow and produces "attribute directive ignored" warnings
110 #if defined(__clang__) && defined(__has_attribute)
111 # if __has_attribute(no_sanitize)
112 # define PUGI__UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow")))
113 # else
114 # define PUGI__UNSIGNED_OVERFLOW
115 # endif
116 #else
117 # define PUGI__UNSIGNED_OVERFLOW
118 #endif
119 
120 // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all)
121 #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
122 using std::memcpy;
123 using std::memmove;
124 using std::memset;
125 #endif
126 
127 // Some MinGW/GCC versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions from limits.h in some configurations
128 #if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX)
129 # define LLONG_MIN (-LLONG_MAX - 1LL)
130 # define LLONG_MAX __LONG_LONG_MAX__
131 # define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
132 #endif
133 
134 // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features
135 #if defined(_MSC_VER) && !defined(__S3E__)
136 # define PUGI__MSVC_CRT_VERSION _MSC_VER
137 #endif
138 
139 // Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size.
140 #if __cplusplus >= 201103
141 # define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
142 #elif defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
143 # define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__)
144 #else
145 # define PUGI__SNPRINTF sprintf
146 #endif
147 
148 // We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat.
149 #ifdef PUGIXML_HEADER_ONLY
150 # define PUGI__NS_BEGIN namespace pugi { namespace impl {
151 # define PUGI__NS_END } }
152 # define PUGI__FN inline
153 # define PUGI__FN_NO_INLINE inline
154 #else
155 # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
156 # define PUGI__NS_BEGIN namespace pugi { namespace impl {
157 # define PUGI__NS_END } }
158 # else
159 # define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace {
160 # define PUGI__NS_END } } }
161 # endif
162 # define PUGI__FN
163 # define PUGI__FN_NO_INLINE PUGI__NO_INLINE
164 #endif
165 
166 // uintptr_t
167 #if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561)
168 namespace pugi
169 {
170 # ifndef _UINTPTR_T_DEFINED
171  typedef size_t uintptr_t;
172 # endif
173 
174  typedef unsigned __int8 uint8_t;
175  typedef unsigned __int16 uint16_t;
176  typedef unsigned __int32 uint32_t;
177 }
178 #else
179 # include <stdint.h>
180 #endif
181 
182 // Memory allocation
184  PUGI__FN void* default_allocate(size_t size)
185  {
186  return malloc(size);
187  }
188 
189  PUGI__FN void default_deallocate(void* ptr)
190  {
191  free(ptr);
192  }
193 
194  template <typename T>
196  {
199  };
200 
201  // Global allocation functions are stored in class statics so that in header mode linker deduplicates them
202  // Without a template<> we'll get multiple definitions of the same static
205 
208 
209 // String utilities
211  // Get string length
212  PUGI__FN size_t strlength(const char_t* s)
213  {
214  assert(s);
215 
216  #ifdef PUGIXML_WCHAR_MODE
217  return wcslen(s);
218  #else
219  return strlen(s);
220  #endif
221  }
222 
223  // Compare two strings
224  PUGI__FN bool strequal(const char_t* src, const char_t* dst)
225  {
226  assert(src && dst);
227 
228  #ifdef PUGIXML_WCHAR_MODE
229  return wcscmp(src, dst) == 0;
230  #else
231  return strcmp(src, dst) == 0;
232  #endif
233  }
234 
235  // Compare lhs with [rhs_begin, rhs_end)
236  PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
237  {
238  for (size_t i = 0; i < count; ++i)
239  if (lhs[i] != rhs[i])
240  return false;
241 
242  return lhs[count] == 0;
243  }
244 
245  // Get length of wide string, even if CRT lacks wide character support
246  PUGI__FN size_t strlength_wide(const wchar_t* s)
247  {
248  assert(s);
249 
250  #ifdef PUGIXML_WCHAR_MODE
251  return wcslen(s);
252  #else
253  const wchar_t* end = s;
254  while (*end) end++;
255  return static_cast<size_t>(end - s);
256  #endif
257  }
259 
260 // auto_ptr-like object for exception recovery
262  template <typename T> struct auto_deleter
263  {
264  typedef void (*D)(T*);
265 
266  T* data;
268 
269  auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_)
270  {
271  }
272 
274  {
275  if (data) deleter(data);
276  }
277 
278  T* release()
279  {
280  T* result = data;
281  data = 0;
282  return result;
283  }
284  };
286 
287 #ifdef PUGIXML_COMPACT
289  class compact_hash_table
290  {
291  public:
292  compact_hash_table(): _items(0), _capacity(0), _count(0)
293  {
294  }
295 
296  void clear()
297  {
298  if (_items)
299  {
300  xml_memory::deallocate(_items);
301  _items = 0;
302  _capacity = 0;
303  _count = 0;
304  }
305  }
306 
307  void* find(const void* key)
308  {
309  if (_capacity == 0) return 0;
310 
311  item_t* item = get_item(key);
312  assert(item);
313  assert(item->key == key || (item->key == 0 && item->value == 0));
314 
315  return item->value;
316  }
317 
318  void insert(const void* key, void* value)
319  {
320  assert(_capacity != 0 && _count < _capacity - _capacity / 4);
321 
322  item_t* item = get_item(key);
323  assert(item);
324 
325  if (item->key == 0)
326  {
327  _count++;
328  item->key = key;
329  }
330 
331  item->value = value;
332  }
333 
334  bool reserve(size_t extra = 16)
335  {
336  if (_count + extra >= _capacity - _capacity / 4)
337  return rehash(_count + extra);
338 
339  return true;
340  }
341 
342  private:
343  struct item_t
344  {
345  const void* key;
346  void* value;
347  };
348 
349  item_t* _items;
350  size_t _capacity;
351 
352  size_t _count;
353 
354  bool rehash(size_t count);
355 
356  item_t* get_item(const void* key)
357  {
358  assert(key);
359  assert(_capacity > 0);
360 
361  size_t hashmod = _capacity - 1;
362  size_t bucket = hash(key) & hashmod;
363 
364  for (size_t probe = 0; probe <= hashmod; ++probe)
365  {
366  item_t& probe_item = _items[bucket];
367 
368  if (probe_item.key == key || probe_item.key == 0)
369  return &probe_item;
370 
371  // hash collision, quadratic probing
372  bucket = (bucket + probe + 1) & hashmod;
373  }
374 
375  assert(false && "Hash table is full"); // unreachable
376  return 0;
377  }
378 
379  static PUGI__UNSIGNED_OVERFLOW unsigned int hash(const void* key)
380  {
381  unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key));
382 
383  // MurmurHash3 32-bit finalizer
384  h ^= h >> 16;
385  h *= 0x85ebca6bu;
386  h ^= h >> 13;
387  h *= 0xc2b2ae35u;
388  h ^= h >> 16;
389 
390  return h;
391  }
392  };
393 
394  PUGI__FN_NO_INLINE bool compact_hash_table::rehash(size_t count)
395  {
396  size_t capacity = 32;
397  while (count >= capacity - capacity / 4)
398  capacity *= 2;
399 
400  compact_hash_table rt;
401  rt._capacity = capacity;
402  rt._items = static_cast<item_t*>(xml_memory::allocate(sizeof(item_t) * capacity));
403 
404  if (!rt._items)
405  return false;
406 
407  memset(rt._items, 0, sizeof(item_t) * capacity);
408 
409  for (size_t i = 0; i < _capacity; ++i)
410  if (_items[i].key)
411  rt.insert(_items[i].key, _items[i].value);
412 
413  if (_items)
414  xml_memory::deallocate(_items);
415 
416  _capacity = capacity;
417  _items = rt._items;
418 
419  assert(_count == rt._count);
420 
421  return true;
422  }
423 
425 #endif
426 
428 #ifdef PUGIXML_COMPACT
429  static const uintptr_t xml_memory_block_alignment = 4;
430 #else
431  static const uintptr_t xml_memory_block_alignment = sizeof(void*);
432 #endif
433 
434  // extra metadata bits
435  static const uintptr_t xml_memory_page_contents_shared_mask = 64;
436  static const uintptr_t xml_memory_page_name_allocated_mask = 32;
437  static const uintptr_t xml_memory_page_value_allocated_mask = 16;
438  static const uintptr_t xml_memory_page_type_mask = 15;
439 
440  // combined masks for string uniqueness
443 
444 #ifdef PUGIXML_COMPACT
445  #define PUGI__GETHEADER_IMPL(object, page, flags) // unused
446  #define PUGI__GETPAGE_IMPL(header) (header).get_page()
447 #else
448  #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))
449  // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
450  #define PUGI__GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8))))
451 #endif
452 
453  #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header)
454  #define PUGI__NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
455 
456  struct xml_allocator;
457 
459  {
460  static xml_memory_page* construct(void* memory)
461  {
462  xml_memory_page* result = static_cast<xml_memory_page*>(memory);
463 
464  result->allocator = 0;
465  result->prev = 0;
466  result->next = 0;
467  result->busy_size = 0;
468  result->freed_size = 0;
469 
470  #ifdef PUGIXML_COMPACT
471  result->compact_string_base = 0;
472  result->compact_shared_parent = 0;
473  result->compact_page_marker = 0;
474  #endif
475 
476  return result;
477  }
478 
480 
483 
484  size_t busy_size;
485  size_t freed_size;
486 
487  #ifdef PUGIXML_COMPACT
488  char_t* compact_string_base;
489  void* compact_shared_parent;
490  uint32_t* compact_page_marker;
491  #endif
492  };
493 
494  static const size_t xml_memory_page_size =
495  #ifdef PUGIXML_MEMORY_PAGE_SIZE
496  (PUGIXML_MEMORY_PAGE_SIZE)
497  #else
498  32768
499  #endif
500  - sizeof(xml_memory_page);
501 
503  {
504  uint16_t page_offset; // offset from page->data
505  uint16_t full_size; // 0 if string occupies whole page
506  };
507 
509  {
510  xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
511  {
512  #ifdef PUGIXML_COMPACT
513  _hash = 0;
514  #endif
515  }
516 
517  xml_memory_page* allocate_page(size_t data_size)
518  {
519  size_t size = sizeof(xml_memory_page) + data_size;
520 
521  // allocate block with some alignment, leaving memory for worst-case padding
522  void* memory = xml_memory::allocate(size);
523  if (!memory) return 0;
524 
525  // prepare page structure
527  assert(page);
528 
529  page->allocator = _root->allocator;
530 
531  return page;
532  }
533 
534  static void deallocate_page(xml_memory_page* page)
535  {
537  }
538 
539  void* allocate_memory_oob(size_t size, xml_memory_page*& out_page);
540 
541  void* allocate_memory(size_t size, xml_memory_page*& out_page)
542  {
544  return allocate_memory_oob(size, out_page);
545 
546  void* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size;
547 
548  _busy_size += size;
549 
550  out_page = _root;
551 
552  return buf;
553  }
554 
555  #ifdef PUGIXML_COMPACT
556  void* allocate_object(size_t size, xml_memory_page*& out_page)
557  {
558  void* result = allocate_memory(size + sizeof(uint32_t), out_page);
559  if (!result) return 0;
560 
561  // adjust for marker
562  ptrdiff_t offset = static_cast<char*>(result) - reinterpret_cast<char*>(out_page->compact_page_marker);
563 
564  if (PUGI__UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment))
565  {
566  // insert new marker
567  uint32_t* marker = static_cast<uint32_t*>(result);
568 
569  *marker = static_cast<uint32_t>(reinterpret_cast<char*>(marker) - reinterpret_cast<char*>(out_page));
570  out_page->compact_page_marker = marker;
571 
572  // since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block
573  // this will make sure deallocate_memory correctly tracks the size
574  out_page->freed_size += sizeof(uint32_t);
575 
576  return marker + 1;
577  }
578  else
579  {
580  // roll back uint32_t part
581  _busy_size -= sizeof(uint32_t);
582 
583  return result;
584  }
585  }
586  #else
587  void* allocate_object(size_t size, xml_memory_page*& out_page)
588  {
589  return allocate_memory(size, out_page);
590  }
591  #endif
592 
593  void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
594  {
595  if (page == _root) page->busy_size = _busy_size;
596 
597  assert(ptr >= reinterpret_cast<char*>(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast<char*>(page) + sizeof(xml_memory_page) + page->busy_size);
598  (void)!ptr;
599 
600  page->freed_size += size;
601  assert(page->freed_size <= page->busy_size);
602 
603  if (page->freed_size == page->busy_size)
604  {
605  if (page->next == 0)
606  {
607  assert(_root == page);
608 
609  // top page freed, just reset sizes
610  page->busy_size = 0;
611  page->freed_size = 0;
612 
613  #ifdef PUGIXML_COMPACT
614  // reset compact state to maximize efficiency
615  page->compact_string_base = 0;
616  page->compact_shared_parent = 0;
617  page->compact_page_marker = 0;
618  #endif
619 
620  _busy_size = 0;
621  }
622  else
623  {
624  assert(_root != page);
625  assert(page->prev);
626 
627  // remove from the list
628  page->prev->next = page->next;
629  page->next->prev = page->prev;
630 
631  // deallocate
632  deallocate_page(page);
633  }
634  }
635  }
636 
637  char_t* allocate_string(size_t length)
638  {
639  static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment;
640 
641  PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
642 
643  // allocate memory for string and header block
644  size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
645 
646  // round size up to block alignment boundary
647  size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1);
648 
649  xml_memory_page* page;
650  xml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page));
651 
652  if (!header) return 0;
653 
654  // setup header
655  ptrdiff_t page_offset = reinterpret_cast<char*>(header) - reinterpret_cast<char*>(page) - sizeof(xml_memory_page);
656 
657  assert(page_offset % xml_memory_block_alignment == 0);
658  assert(page_offset >= 0 && static_cast<size_t>(page_offset) < max_encoded_offset);
659  header->page_offset = static_cast<uint16_t>(static_cast<size_t>(page_offset) / xml_memory_block_alignment);
660 
661  // full_size == 0 for large strings that occupy the whole page
662  assert(full_size % xml_memory_block_alignment == 0);
663  assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0));
664  header->full_size = static_cast<uint16_t>(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0);
665 
666  // round-trip through void* to avoid 'cast increases required alignment of target type' warning
667  // header is guaranteed a pointer-sized alignment, which should be enough for char_t
668  return static_cast<char_t*>(static_cast<void*>(header + 1));
669  }
670 
671  void deallocate_string(char_t* string)
672  {
673  // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
674  // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string
675 
676  // get header
677  xml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1;
678  assert(header);
679 
680  // deallocate
681  size_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment;
682  xml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset));
683 
684  // if full_size == 0 then this string occupies the whole page
685  size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment;
686 
687  deallocate_memory(header, full_size, page);
688  }
689 
690  bool reserve()
691  {
692  #ifdef PUGIXML_COMPACT
693  return _hash->reserve();
694  #else
695  return true;
696  #endif
697  }
698 
700  size_t _busy_size;
701 
702  #ifdef PUGIXML_COMPACT
703  compact_hash_table* _hash;
704  #endif
705  };
706 
708  {
709  const size_t large_allocation_threshold = xml_memory_page_size / 4;
710 
711  xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
712  out_page = page;
713 
714  if (!page) return 0;
715 
716  if (size <= large_allocation_threshold)
717  {
719 
720  // insert page at the end of linked list
721  page->prev = _root;
722  _root->next = page;
723  _root = page;
724 
725  _busy_size = size;
726  }
727  else
728  {
729  // insert page before the end of linked list, so that it is deleted as soon as possible
730  // the last page is not deleted even if it's empty (see deallocate_memory)
731  assert(_root->prev);
732 
733  page->prev = _root->prev;
734  page->next = _root;
735 
736  _root->prev->next = page;
737  _root->prev = page;
738 
739  page->busy_size = size;
740  }
741 
742  return reinterpret_cast<char*>(page) + sizeof(xml_memory_page);
743  }
745 
746 #ifdef PUGIXML_COMPACT
748  static const uintptr_t compact_alignment_log2 = 2;
749  static const uintptr_t compact_alignment = 1 << compact_alignment_log2;
750 
751  class compact_header
752  {
753  public:
754  compact_header(xml_memory_page* page, unsigned int flags)
755  {
756  PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
757 
758  ptrdiff_t offset = (reinterpret_cast<char*>(this) - reinterpret_cast<char*>(page->compact_page_marker));
759  assert(offset % compact_alignment == 0 && static_cast<uintptr_t>(offset) < 256 * compact_alignment);
760 
761  _page = static_cast<unsigned char>(offset >> compact_alignment_log2);
762  _flags = static_cast<unsigned char>(flags);
763  }
764 
765  void operator&=(uintptr_t mod)
766  {
767  _flags &= static_cast<unsigned char>(mod);
768  }
769 
770  void operator|=(uintptr_t mod)
771  {
772  _flags |= static_cast<unsigned char>(mod);
773  }
774 
775  uintptr_t operator&(uintptr_t mod) const
776  {
777  return _flags & mod;
778  }
779 
780  xml_memory_page* get_page() const
781  {
782  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
783  const char* page_marker = reinterpret_cast<const char*>(this) - (_page << compact_alignment_log2);
784  const char* page = page_marker - *reinterpret_cast<const uint32_t*>(static_cast<const void*>(page_marker));
785 
786  return const_cast<xml_memory_page*>(reinterpret_cast<const xml_memory_page*>(static_cast<const void*>(page)));
787  }
788 
789  private:
790  unsigned char _page;
791  unsigned char _flags;
792  };
793 
794  PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset)
795  {
796  const compact_header* header = reinterpret_cast<const compact_header*>(static_cast<const char*>(object) - header_offset);
797 
798  return header->get_page();
799  }
800 
801  template <int header_offset, typename T> PUGI__FN_NO_INLINE T* compact_get_value(const void* object)
802  {
803  return static_cast<T*>(compact_get_page(object, header_offset)->allocator->_hash->find(object));
804  }
805 
806  template <int header_offset, typename T> PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value)
807  {
808  compact_get_page(object, header_offset)->allocator->_hash->insert(object, value);
809  }
810 
811  template <typename T, int header_offset, int start = -126> class compact_pointer
812  {
813  public:
814  compact_pointer(): _data(0)
815  {
816  }
817 
818  void operator=(const compact_pointer& rhs)
819  {
820  *this = rhs + 0;
821  }
822 
823  void operator=(T* value)
824  {
825  if (value)
826  {
827  // value is guaranteed to be compact-aligned; 'this' is not
828  // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
829  // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
830  // compensate for arithmetic shift rounding for negative values
831  ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
832  ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start;
833 
834  if (static_cast<uintptr_t>(offset) <= 253)
835  _data = static_cast<unsigned char>(offset + 1);
836  else
837  {
838  compact_set_value<header_offset>(this, value);
839 
840  _data = 255;
841  }
842  }
843  else
844  _data = 0;
845  }
846 
847  operator T*() const
848  {
849  if (_data)
850  {
851  if (_data < 255)
852  {
853  uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
854 
855  return reinterpret_cast<T*>(base + (_data - 1 + start) * compact_alignment);
856  }
857  else
858  return compact_get_value<header_offset, T>(this);
859  }
860  else
861  return 0;
862  }
863 
864  T* operator->() const
865  {
866  return *this;
867  }
868 
869  private:
870  unsigned char _data;
871  };
872 
873  template <typename T, int header_offset> class compact_pointer_parent
874  {
875  public:
876  compact_pointer_parent(): _data(0)
877  {
878  }
879 
880  void operator=(const compact_pointer_parent& rhs)
881  {
882  *this = rhs + 0;
883  }
884 
885  void operator=(T* value)
886  {
887  if (value)
888  {
889  // value is guaranteed to be compact-aligned; 'this' is not
890  // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
891  // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
892  // compensate for arithmetic shift behavior for negative values
893  ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
894  ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533;
895 
896  if (static_cast<uintptr_t>(offset) <= 65533)
897  {
898  _data = static_cast<unsigned short>(offset + 1);
899  }
900  else
901  {
902  xml_memory_page* page = compact_get_page(this, header_offset);
903 
904  if (PUGI__UNLIKELY(page->compact_shared_parent == 0))
905  page->compact_shared_parent = value;
906 
907  if (page->compact_shared_parent == value)
908  {
909  _data = 65534;
910  }
911  else
912  {
913  compact_set_value<header_offset>(this, value);
914 
915  _data = 65535;
916  }
917  }
918  }
919  else
920  {
921  _data = 0;
922  }
923  }
924 
925  operator T*() const
926  {
927  if (_data)
928  {
929  if (_data < 65534)
930  {
931  uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
932 
933  return reinterpret_cast<T*>(base + (_data - 1 - 65533) * compact_alignment);
934  }
935  else if (_data == 65534)
936  return static_cast<T*>(compact_get_page(this, header_offset)->compact_shared_parent);
937  else
938  return compact_get_value<header_offset, T>(this);
939  }
940  else
941  return 0;
942  }
943 
944  T* operator->() const
945  {
946  return *this;
947  }
948 
949  private:
950  uint16_t _data;
951  };
952 
953  template <int header_offset, int base_offset> class compact_string
954  {
955  public:
956  compact_string(): _data(0)
957  {
958  }
959 
960  void operator=(const compact_string& rhs)
961  {
962  *this = rhs + 0;
963  }
964 
965  void operator=(char_t* value)
966  {
967  if (value)
968  {
969  xml_memory_page* page = compact_get_page(this, header_offset);
970 
971  if (PUGI__UNLIKELY(page->compact_string_base == 0))
972  page->compact_string_base = value;
973 
974  ptrdiff_t offset = value - page->compact_string_base;
975 
976  if (static_cast<uintptr_t>(offset) < (65535 << 7))
977  {
978  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
979  uint16_t* base = reinterpret_cast<uint16_t*>(static_cast<void*>(reinterpret_cast<char*>(this) - base_offset));
980 
981  if (*base == 0)
982  {
983  *base = static_cast<uint16_t>((offset >> 7) + 1);
984  _data = static_cast<unsigned char>((offset & 127) + 1);
985  }
986  else
987  {
988  ptrdiff_t remainder = offset - ((*base - 1) << 7);
989 
990  if (static_cast<uintptr_t>(remainder) <= 253)
991  {
992  _data = static_cast<unsigned char>(remainder + 1);
993  }
994  else
995  {
996  compact_set_value<header_offset>(this, value);
997 
998  _data = 255;
999  }
1000  }
1001  }
1002  else
1003  {
1004  compact_set_value<header_offset>(this, value);
1005 
1006  _data = 255;
1007  }
1008  }
1009  else
1010  {
1011  _data = 0;
1012  }
1013  }
1014 
1015  operator char_t*() const
1016  {
1017  if (_data)
1018  {
1019  if (_data < 255)
1020  {
1021  xml_memory_page* page = compact_get_page(this, header_offset);
1022 
1023  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
1024  const uint16_t* base = reinterpret_cast<const uint16_t*>(static_cast<const void*>(reinterpret_cast<const char*>(this) - base_offset));
1025  assert(*base);
1026 
1027  ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);
1028 
1029  return page->compact_string_base + offset;
1030  }
1031  else
1032  {
1033  return compact_get_value<header_offset, char_t>(this);
1034  }
1035  }
1036  else
1037  return 0;
1038  }
1039 
1040  private:
1041  unsigned char _data;
1042  };
1044 #endif
1045 
1046 #ifdef PUGIXML_COMPACT
1047 namespace pugi
1048 {
1049  struct xml_attribute_struct
1050  {
1051  xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)
1052  {
1054  }
1055 
1056  impl::compact_header header;
1057 
1058  uint16_t namevalue_base;
1059 
1060  impl::compact_string<4, 2> name;
1061  impl::compact_string<5, 3> value;
1062 
1063  impl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c;
1064  impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute;
1065  };
1066 
1067  struct xml_node_struct
1068  {
1069  xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0)
1070  {
1071  PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12);
1072  }
1073 
1074  impl::compact_header header;
1075 
1076  uint16_t namevalue_base;
1077 
1078  impl::compact_string<4, 2> name;
1079  impl::compact_string<5, 3> value;
1080 
1081  impl::compact_pointer_parent<xml_node_struct, 6> parent;
1082 
1083  impl::compact_pointer<xml_node_struct, 8, 0> first_child;
1084 
1085  impl::compact_pointer<xml_node_struct, 9> prev_sibling_c;
1086  impl::compact_pointer<xml_node_struct, 10, 0> next_sibling;
1087 
1088  impl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute;
1089  };
1090 }
1091 #else
1092 namespace pugi
1093 {
1095  {
1096  xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0)
1097  {
1098  header = PUGI__GETHEADER_IMPL(this, page, 0);
1099  }
1100 
1101  uintptr_t header;
1102 
1105 
1108  };
1109 
1111  {
1112  xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
1113  {
1114  header = PUGI__GETHEADER_IMPL(this, page, type);
1115  }
1116 
1117  uintptr_t header;
1118 
1121 
1123 
1125 
1128 
1130  };
1131 }
1132 #endif
1133 
1136  {
1139  };
1140 
1141  struct xml_document_struct: public xml_node_struct, public xml_allocator
1142  {
1144  {
1145  }
1146 
1147  const char_t* buffer;
1148 
1150 
1151  #ifdef PUGIXML_COMPACT
1152  compact_hash_table hash;
1153  #endif
1154  };
1155 
1156  template <typename Object> inline xml_allocator& get_allocator(const Object* object)
1157  {
1158  assert(object);
1159 
1160  return *PUGI__GETPAGE(object)->allocator;
1161  }
1162 
1163  template <typename Object> inline xml_document_struct& get_document(const Object* object)
1164  {
1165  assert(object);
1166 
1167  return *static_cast<xml_document_struct*>(PUGI__GETPAGE(object)->allocator);
1168  }
1170 
1171 // Low-level DOM operations
1173  inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
1174  {
1175  xml_memory_page* page;
1176  void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page);
1177  if (!memory) return 0;
1178 
1179  return new (memory) xml_attribute_struct(page);
1180  }
1181 
1182  inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type)
1183  {
1184  xml_memory_page* page;
1185  void* memory = alloc.allocate_object(sizeof(xml_node_struct), page);
1186  if (!memory) return 0;
1187 
1188  return new (memory) xml_node_struct(page, type);
1189  }
1190 
1191  inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
1192  {
1194  alloc.deallocate_string(a->name);
1195 
1197  alloc.deallocate_string(a->value);
1198 
1199  alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a));
1200  }
1201 
1202  inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
1203  {
1205  alloc.deallocate_string(n->name);
1206 
1208  alloc.deallocate_string(n->value);
1209 
1210  for (xml_attribute_struct* attr = n->first_attribute; attr; )
1211  {
1212  xml_attribute_struct* next = attr->next_attribute;
1213 
1214  destroy_attribute(attr, alloc);
1215 
1216  attr = next;
1217  }
1218 
1219  for (xml_node_struct* child = n->first_child; child; )
1220  {
1221  xml_node_struct* next = child->next_sibling;
1222 
1223  destroy_node(child, alloc);
1224 
1225  child = next;
1226  }
1227 
1228  alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n));
1229  }
1230 
1231  inline void append_node(xml_node_struct* child, xml_node_struct* node)
1232  {
1233  child->parent = node;
1234 
1235  xml_node_struct* head = node->first_child;
1236 
1237  if (head)
1238  {
1239  xml_node_struct* tail = head->prev_sibling_c;
1240 
1241  tail->next_sibling = child;
1242  child->prev_sibling_c = tail;
1243  head->prev_sibling_c = child;
1244  }
1245  else
1246  {
1247  node->first_child = child;
1248  child->prev_sibling_c = child;
1249  }
1250  }
1251 
1252  inline void prepend_node(xml_node_struct* child, xml_node_struct* node)
1253  {
1254  child->parent = node;
1255 
1256  xml_node_struct* head = node->first_child;
1257 
1258  if (head)
1259  {
1260  child->prev_sibling_c = head->prev_sibling_c;
1261  head->prev_sibling_c = child;
1262  }
1263  else
1264  child->prev_sibling_c = child;
1265 
1266  child->next_sibling = head;
1267  node->first_child = child;
1268  }
1269 
1270  inline void insert_node_after(xml_node_struct* child, xml_node_struct* node)
1271  {
1272  xml_node_struct* parent = node->parent;
1273 
1274  child->parent = parent;
1275 
1276  if (node->next_sibling)
1277  node->next_sibling->prev_sibling_c = child;
1278  else
1279  parent->first_child->prev_sibling_c = child;
1280 
1281  child->next_sibling = node->next_sibling;
1282  child->prev_sibling_c = node;
1283 
1284  node->next_sibling = child;
1285  }
1286 
1287  inline void insert_node_before(xml_node_struct* child, xml_node_struct* node)
1288  {
1289  xml_node_struct* parent = node->parent;
1290 
1291  child->parent = parent;
1292 
1293  if (node->prev_sibling_c->next_sibling)
1294  node->prev_sibling_c->next_sibling = child;
1295  else
1296  parent->first_child = child;
1297 
1298  child->prev_sibling_c = node->prev_sibling_c;
1299  child->next_sibling = node;
1300 
1301  node->prev_sibling_c = child;
1302  }
1303 
1304  inline void remove_node(xml_node_struct* node)
1305  {
1306  xml_node_struct* parent = node->parent;
1307 
1308  if (node->next_sibling)
1309  node->next_sibling->prev_sibling_c = node->prev_sibling_c;
1310  else
1311  parent->first_child->prev_sibling_c = node->prev_sibling_c;
1312 
1313  if (node->prev_sibling_c->next_sibling)
1314  node->prev_sibling_c->next_sibling = node->next_sibling;
1315  else
1316  parent->first_child = node->next_sibling;
1317 
1318  node->parent = 0;
1319  node->prev_sibling_c = 0;
1320  node->next_sibling = 0;
1321  }
1322 
1323  inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1324  {
1325  xml_attribute_struct* head = node->first_attribute;
1326 
1327  if (head)
1328  {
1329  xml_attribute_struct* tail = head->prev_attribute_c;
1330 
1331  tail->next_attribute = attr;
1332  attr->prev_attribute_c = tail;
1333  head->prev_attribute_c = attr;
1334  }
1335  else
1336  {
1337  node->first_attribute = attr;
1338  attr->prev_attribute_c = attr;
1339  }
1340  }
1341 
1342  inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1343  {
1344  xml_attribute_struct* head = node->first_attribute;
1345 
1346  if (head)
1347  {
1348  attr->prev_attribute_c = head->prev_attribute_c;
1349  head->prev_attribute_c = attr;
1350  }
1351  else
1352  attr->prev_attribute_c = attr;
1353 
1354  attr->next_attribute = head;
1355  node->first_attribute = attr;
1356  }
1357 
1358  inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
1359  {
1360  if (place->next_attribute)
1361  place->next_attribute->prev_attribute_c = attr;
1362  else
1363  node->first_attribute->prev_attribute_c = attr;
1364 
1365  attr->next_attribute = place->next_attribute;
1366  attr->prev_attribute_c = place;
1367  place->next_attribute = attr;
1368  }
1369 
1370  inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
1371  {
1372  if (place->prev_attribute_c->next_attribute)
1373  place->prev_attribute_c->next_attribute = attr;
1374  else
1375  node->first_attribute = attr;
1376 
1377  attr->prev_attribute_c = place->prev_attribute_c;
1378  attr->next_attribute = place;
1379  place->prev_attribute_c = attr;
1380  }
1381 
1382  inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1383  {
1384  if (attr->next_attribute)
1385  attr->next_attribute->prev_attribute_c = attr->prev_attribute_c;
1386  else
1387  node->first_attribute->prev_attribute_c = attr->prev_attribute_c;
1388 
1389  if (attr->prev_attribute_c->next_attribute)
1390  attr->prev_attribute_c->next_attribute = attr->next_attribute;
1391  else
1392  node->first_attribute = attr->next_attribute;
1393 
1394  attr->prev_attribute_c = 0;
1395  attr->next_attribute = 0;
1396  }
1397 
1398  PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
1399  {
1400  if (!alloc.reserve()) return 0;
1401 
1402  xml_node_struct* child = allocate_node(alloc, type);
1403  if (!child) return 0;
1404 
1405  append_node(child, node);
1406 
1407  return child;
1408  }
1409 
1410  PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)
1411  {
1412  if (!alloc.reserve()) return 0;
1413 
1414  xml_attribute_struct* attr = allocate_attribute(alloc);
1415  if (!attr) return 0;
1416 
1417  append_attribute(attr, node);
1418 
1419  return attr;
1420  }
1422 
1423 // Helper classes for code generation
1425  struct opt_false
1426  {
1427  enum { value = 0 };
1428  };
1429 
1430  struct opt_true
1431  {
1432  enum { value = 1 };
1433  };
1435 
1436 // Unicode utilities
1438  inline uint16_t endian_swap(uint16_t value)
1439  {
1440  return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
1441  }
1442 
1443  inline uint32_t endian_swap(uint32_t value)
1444  {
1445  return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
1446  }
1447 
1449  {
1450  typedef size_t value_type;
1451 
1452  static value_type low(value_type result, uint32_t ch)
1453  {
1454  // U+0000..U+007F
1455  if (ch < 0x80) return result + 1;
1456  // U+0080..U+07FF
1457  else if (ch < 0x800) return result + 2;
1458  // U+0800..U+FFFF
1459  else return result + 3;
1460  }
1461 
1462  static value_type high(value_type result, uint32_t)
1463  {
1464  // U+10000..U+10FFFF
1465  return result + 4;
1466  }
1467  };
1468 
1470  {
1471  typedef uint8_t* value_type;
1472 
1473  static value_type low(value_type result, uint32_t ch)
1474  {
1475  // U+0000..U+007F
1476  if (ch < 0x80)
1477  {
1478  *result = static_cast<uint8_t>(ch);
1479  return result + 1;
1480  }
1481  // U+0080..U+07FF
1482  else if (ch < 0x800)
1483  {
1484  result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));
1485  result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
1486  return result + 2;
1487  }
1488  // U+0800..U+FFFF
1489  else
1490  {
1491  result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));
1492  result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
1493  result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
1494  return result + 3;
1495  }
1496  }
1497 
1498  static value_type high(value_type result, uint32_t ch)
1499  {
1500  // U+10000..U+10FFFF
1501  result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));
1502  result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));
1503  result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
1504  result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
1505  return result + 4;
1506  }
1507 
1508  static value_type any(value_type result, uint32_t ch)
1509  {
1510  return (ch < 0x10000) ? low(result, ch) : high(result, ch);
1511  }
1512  };
1513 
1515  {
1516  typedef size_t value_type;
1517 
1518  static value_type low(value_type result, uint32_t)
1519  {
1520  return result + 1;
1521  }
1522 
1523  static value_type high(value_type result, uint32_t)
1524  {
1525  return result + 2;
1526  }
1527  };
1528 
1530  {
1531  typedef uint16_t* value_type;
1532 
1533  static value_type low(value_type result, uint32_t ch)
1534  {
1535  *result = static_cast<uint16_t>(ch);
1536 
1537  return result + 1;
1538  }
1539 
1540  static value_type high(value_type result, uint32_t ch)
1541  {
1542  uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10;
1543  uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff;
1544 
1545  result[0] = static_cast<uint16_t>(0xD800 + msh);
1546  result[1] = static_cast<uint16_t>(0xDC00 + lsh);
1547 
1548  return result + 2;
1549  }
1550 
1551  static value_type any(value_type result, uint32_t ch)
1552  {
1553  return (ch < 0x10000) ? low(result, ch) : high(result, ch);
1554  }
1555  };
1556 
1558  {
1559  typedef size_t value_type;
1560 
1561  static value_type low(value_type result, uint32_t)
1562  {
1563  return result + 1;
1564  }
1565 
1566  static value_type high(value_type result, uint32_t)
1567  {
1568  return result + 1;
1569  }
1570  };
1571 
1573  {
1574  typedef uint32_t* value_type;
1575 
1576  static value_type low(value_type result, uint32_t ch)
1577  {
1578  *result = ch;
1579 
1580  return result + 1;
1581  }
1582 
1583  static value_type high(value_type result, uint32_t ch)
1584  {
1585  *result = ch;
1586 
1587  return result + 1;
1588  }
1589 
1590  static value_type any(value_type result, uint32_t ch)
1591  {
1592  *result = ch;
1593 
1594  return result + 1;
1595  }
1596  };
1597 
1599  {
1600  typedef uint8_t* value_type;
1601 
1602  static value_type low(value_type result, uint32_t ch)
1603  {
1604  *result = static_cast<uint8_t>(ch > 255 ? '?' : ch);
1605 
1606  return result + 1;
1607  }
1608 
1609  static value_type high(value_type result, uint32_t ch)
1610  {
1611  (void)ch;
1612 
1613  *result = '?';
1614 
1615  return result + 1;
1616  }
1617  };
1618 
1620  {
1621  typedef uint8_t type;
1622 
1623  template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
1624  {
1625  const uint8_t utf8_byte_mask = 0x3f;
1626 
1627  while (size)
1628  {
1629  uint8_t lead = *data;
1630 
1631  // 0xxxxxxx -> U+0000..U+007F
1632  if (lead < 0x80)
1633  {
1634  result = Traits::low(result, lead);
1635  data += 1;
1636  size -= 1;
1637 
1638  // process aligned single-byte (ascii) blocks
1639  if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
1640  {
1641  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
1642  while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)
1643  {
1644  result = Traits::low(result, data[0]);
1645  result = Traits::low(result, data[1]);
1646  result = Traits::low(result, data[2]);
1647  result = Traits::low(result, data[3]);
1648  data += 4;
1649  size -= 4;
1650  }
1651  }
1652  }
1653  // 110xxxxx -> U+0080..U+07FF
1654  else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
1655  {
1656  result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
1657  data += 2;
1658  size -= 2;
1659  }
1660  // 1110xxxx -> U+0800-U+FFFF
1661  else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
1662  {
1663  result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
1664  data += 3;
1665  size -= 3;
1666  }
1667  // 11110xxx -> U+10000..U+10FFFF
1668  else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
1669  {
1670  result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
1671  data += 4;
1672  size -= 4;
1673  }
1674  // 10xxxxxx or 11111xxx -> invalid
1675  else
1676  {
1677  data += 1;
1678  size -= 1;
1679  }
1680  }
1681 
1682  return result;
1683  }
1684  };
1685 
1686  template <typename opt_swap> struct utf16_decoder
1687  {
1688  typedef uint16_t type;
1689 
1690  template <typename Traits> static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits)
1691  {
1692  while (size)
1693  {
1694  uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
1695 
1696  // U+0000..U+D7FF
1697  if (lead < 0xD800)
1698  {
1699  result = Traits::low(result, lead);
1700  data += 1;
1701  size -= 1;
1702  }
1703  // U+E000..U+FFFF
1704  else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
1705  {
1706  result = Traits::low(result, lead);
1707  data += 1;
1708  size -= 1;
1709  }
1710  // surrogate pair lead
1711  else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
1712  {
1713  uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
1714 
1715  if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
1716  {
1717  result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
1718  data += 2;
1719  size -= 2;
1720  }
1721  else
1722  {
1723  data += 1;
1724  size -= 1;
1725  }
1726  }
1727  else
1728  {
1729  data += 1;
1730  size -= 1;
1731  }
1732  }
1733 
1734  return result;
1735  }
1736  };
1737 
1738  template <typename opt_swap> struct utf32_decoder
1739  {
1740  typedef uint32_t type;
1741 
1742  template <typename Traits> static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits)
1743  {
1744  while (size)
1745  {
1746  uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
1747 
1748  // U+0000..U+FFFF
1749  if (lead < 0x10000)
1750  {
1751  result = Traits::low(result, lead);
1752  data += 1;
1753  size -= 1;
1754  }
1755  // U+10000..U+10FFFF
1756  else
1757  {
1758  result = Traits::high(result, lead);
1759  data += 1;
1760  size -= 1;
1761  }
1762  }
1763 
1764  return result;
1765  }
1766  };
1767 
1769  {
1770  typedef uint8_t type;
1771 
1772  template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
1773  {
1774  while (size)
1775  {
1776  result = Traits::low(result, *data);
1777  data += 1;
1778  size -= 1;
1779  }
1780 
1781  return result;
1782  }
1783  };
1784 
1785  template <size_t size> struct wchar_selector;
1786 
1787  template <> struct wchar_selector<2>
1788  {
1789  typedef uint16_t type;
1793  };
1794 
1795  template <> struct wchar_selector<4>
1796  {
1797  typedef uint32_t type;
1801  };
1802 
1803  typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
1804  typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
1805 
1807  {
1808  typedef wchar_t type;
1809 
1810  template <typename Traits> static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits)
1811  {
1812  typedef wchar_selector<sizeof(wchar_t)>::decoder decoder;
1813 
1814  return decoder::process(reinterpret_cast<const typename decoder::type*>(data), size, result, traits);
1815  }
1816  };
1817 
1818 #ifdef PUGIXML_WCHAR_MODE
1819  PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
1820  {
1821  for (size_t i = 0; i < length; ++i)
1822  result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
1823  }
1824 #endif
1826 
1829  {
1830  ct_parse_pcdata = 1, // \0, &, \r, <
1831  ct_parse_attr = 2, // \0, &, \r, ', "
1832  ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab
1833  ct_space = 8, // \r, \n, space, tab
1834  ct_parse_cdata = 16, // \0, ], >, \r
1835  ct_parse_comment = 32, // \0, -, >, \r
1836  ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .
1837  ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, :
1838  };
1839 
1840  static const unsigned char chartype_table[256] =
1841  {
1842  55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15
1843  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
1844  8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47
1845  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63
1846  0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79
1847  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95
1848  0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111
1849  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127
1850 
1851  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+
1852  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1853  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1854  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1855  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1856  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1857  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1858  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
1859  };
1860 
1862  {
1863  ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
1864  ctx_special_attr = 2, // Any symbol >= 0 and < 32, &, <, ", '
1865  ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _
1866  ctx_digit = 8, // 0-9
1867  ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
1868  };
1869 
1870  static const unsigned char chartypex_table[256] =
1871  {
1872  3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, // 0-15
1873  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31
1874  0, 0, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47
1875  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 1, 0, // 48-63
1876 
1877  0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79
1878  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95
1879  0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111
1880  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127
1881 
1882  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+
1883  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1884  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1885  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1886  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1887  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1888  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1889  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
1890  };
1891 
1892 #ifdef PUGIXML_WCHAR_MODE
1893  #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
1894 #else
1895  #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
1896 #endif
1897 
1898  #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
1899  #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
1902  {
1903  unsigned int ui = 1;
1904 
1905  return *reinterpret_cast<unsigned char*>(&ui) == 1;
1906  }
1907 
1909  {
1910  PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
1911 
1912  if (sizeof(wchar_t) == 2)
1914  else
1916  }
1917 
1918  PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length)
1919  {
1920  #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
1921  #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; }
1922 
1923  // check if we have a non-empty XML declaration
1924  if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space)))
1925  return false;
1926 
1927  // scan XML declaration until the encoding field
1928  for (size_t i = 6; i + 1 < size; ++i)
1929  {
1930  // declaration can not contain ? in quoted values
1931  if (data[i] == '?')
1932  return false;
1933 
1934  if (data[i] == 'e' && data[i + 1] == 'n')
1935  {
1936  size_t offset = i;
1937 
1938  // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed
1941 
1942  // S? = S?
1944  PUGI__SCANCHAR('=');
1946 
1947  // the only two valid delimiters are ' and "
1948  uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\'';
1949 
1950  PUGI__SCANCHAR(delimiter);
1951 
1952  size_t start = offset;
1953 
1954  out_encoding = data + offset;
1955 
1957 
1958  out_length = offset - start;
1959 
1960  PUGI__SCANCHAR(delimiter);
1961 
1962  return true;
1963  }
1964  }
1965 
1966  return false;
1967 
1968  #undef PUGI__SCANCHAR
1969  #undef PUGI__SCANCHARTYPE
1970  }
1971 
1972  PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size)
1973  {
1974  // skip encoding autodetection if input buffer is too small
1975  if (size < 4) return encoding_utf8;
1976 
1977  uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1978 
1979  // look for BOM in first few bytes
1980  if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be;
1981  if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le;
1982  if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be;
1983  if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le;
1984  if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8;
1985 
1986  // look for <, <? or <?xm in various encodings
1987  if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be;
1988  if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le;
1989  if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be;
1990  if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le;
1991 
1992  // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)
1993  if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be;
1994  if (d0 == 0x3c && d1 == 0) return encoding_utf16_le;
1995 
1996  // no known BOM detected; parse declaration
1997  const uint8_t* enc = 0;
1998  size_t enc_length = 0;
1999 
2000  if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length))
2001  {
2002  // iso-8859-1 (case-insensitive)
2003  if (enc_length == 10
2004  && (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o'
2005  && enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9'
2006  && enc[8] == '-' && enc[9] == '1')
2007  return encoding_latin1;
2008 
2009  // latin1 (case-insensitive)
2010  if (enc_length == 6
2011  && (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't'
2012  && (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n'
2013  && enc[5] == '1')
2014  return encoding_latin1;
2015  }
2016 
2017  return encoding_utf8;
2018  }
2019 
2020  PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
2021  {
2022  // replace wchar encoding with utf implementation
2023  if (encoding == encoding_wchar) return get_wchar_encoding();
2024 
2025  // replace utf16 encoding with utf16 with specific endianness
2027 
2028  // replace utf32 encoding with utf32 with specific endianness
2030 
2031  // only do autodetection if no explicit encoding is requested
2032  if (encoding != encoding_auto) return encoding;
2033 
2034  // try to guess encoding (based on XML specification, Appendix F.1)
2035  const uint8_t* data = static_cast<const uint8_t*>(contents);
2036 
2037  return guess_buffer_encoding(data, size);
2038  }
2039 
2040  PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
2041  {
2042  size_t length = size / sizeof(char_t);
2043 
2044  if (is_mutable)
2045  {
2046  out_buffer = static_cast<char_t*>(const_cast<void*>(contents));
2047  out_length = length;
2048  }
2049  else
2050  {
2051  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2052  if (!buffer) return false;
2053 
2054  if (contents)
2055  memcpy(buffer, contents, length * sizeof(char_t));
2056  else
2057  assert(length == 0);
2058 
2059  buffer[length] = 0;
2060 
2061  out_buffer = buffer;
2062  out_length = length + 1;
2063  }
2064 
2065  return true;
2066  }
2067 
2068 #ifdef PUGIXML_WCHAR_MODE
2069  PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
2070  {
2071  return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
2072  (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
2073  }
2074 
2075  PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
2076  {
2077  const char_t* data = static_cast<const char_t*>(contents);
2078  size_t length = size / sizeof(char_t);
2079 
2080  if (is_mutable)
2081  {
2082  char_t* buffer = const_cast<char_t*>(data);
2083 
2084  convert_wchar_endian_swap(buffer, data, length);
2085 
2086  out_buffer = buffer;
2087  out_length = length;
2088  }
2089  else
2090  {
2091  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2092  if (!buffer) return false;
2093 
2094  convert_wchar_endian_swap(buffer, data, length);
2095  buffer[length] = 0;
2096 
2097  out_buffer = buffer;
2098  out_length = length + 1;
2099  }
2100 
2101  return true;
2102  }
2103 
2104  template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
2105  {
2106  const typename D::type* data = static_cast<const typename D::type*>(contents);
2107  size_t data_length = size / sizeof(typename D::type);
2108 
2109  // first pass: get length in wchar_t units
2110  size_t length = D::process(data, data_length, 0, wchar_counter());
2111 
2112  // allocate buffer of suitable length
2113  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2114  if (!buffer) return false;
2115 
2116  // second pass: convert utf16 input to wchar_t
2117  wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
2118  wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer());
2119 
2120  assert(oend == obegin + length);
2121  *oend = 0;
2122 
2123  out_buffer = buffer;
2124  out_length = length + 1;
2125 
2126  return true;
2127  }
2128 
2129  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)
2130  {
2131  // get native encoding
2132  xml_encoding wchar_encoding = get_wchar_encoding();
2133 
2134  // fast path: no conversion required
2135  if (encoding == wchar_encoding)
2136  return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2137 
2138  // only endian-swapping is required
2139  if (need_endian_swap_utf(encoding, wchar_encoding))
2140  return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
2141 
2142  // source encoding is utf8
2143  if (encoding == encoding_utf8)
2144  return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder());
2145 
2146  // source encoding is utf16
2147  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2148  {
2150 
2151  return (native_encoding == encoding) ?
2152  convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
2153  convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
2154  }
2155 
2156  // source encoding is utf32
2157  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2158  {
2160 
2161  return (native_encoding == encoding) ?
2162  convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
2163  convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
2164  }
2165 
2166  // source encoding is latin1
2167  if (encoding == encoding_latin1)
2168  return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder());
2169 
2170  assert(false && "Invalid encoding"); // unreachable
2171  return false;
2172  }
2173 #else
2174  template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
2175  {
2176  const typename D::type* data = static_cast<const typename D::type*>(contents);
2177  size_t data_length = size / sizeof(typename D::type);
2178 
2179  // first pass: get length in utf8 units
2180  size_t length = D::process(data, data_length, 0, utf8_counter());
2181 
2182  // allocate buffer of suitable length
2183  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2184  if (!buffer) return false;
2185 
2186  // second pass: convert utf16 input to utf8
2187  uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
2188  uint8_t* oend = D::process(data, data_length, obegin, utf8_writer());
2189 
2190  assert(oend == obegin + length);
2191  *oend = 0;
2192 
2193  out_buffer = buffer;
2194  out_length = length + 1;
2195 
2196  return true;
2197  }
2198 
2199  PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
2200  {
2201  for (size_t i = 0; i < size; ++i)
2202  if (data[i] > 127)
2203  return i;
2204 
2205  return size;
2206  }
2207 
2208  PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
2209  {
2210  const uint8_t* data = static_cast<const uint8_t*>(contents);
2211  size_t data_length = size;
2212 
2213  // get size of prefix that does not need utf8 conversion
2214  size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
2215  assert(prefix_length <= data_length);
2216 
2217  const uint8_t* postfix = data + prefix_length;
2218  size_t postfix_length = data_length - prefix_length;
2219 
2220  // if no conversion is needed, just return the original buffer
2221  if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2222 
2223  // first pass: get length in utf8 units
2224  size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter());
2225 
2226  // allocate buffer of suitable length
2227  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2228  if (!buffer) return false;
2229 
2230  // second pass: convert latin1 input to utf8
2231  memcpy(buffer, data, prefix_length);
2232 
2233  uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
2234  uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer());
2235 
2236  assert(oend == obegin + length);
2237  *oend = 0;
2238 
2239  out_buffer = buffer;
2240  out_length = length + 1;
2241 
2242  return true;
2243  }
2244 
2245  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)
2246  {
2247  // fast path: no conversion required
2248  if (encoding == encoding_utf8)
2249  return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2250 
2251  // source encoding is utf16
2252  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2253  {
2255 
2256  return (native_encoding == encoding) ?
2257  convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
2258  convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
2259  }
2260 
2261  // source encoding is utf32
2262  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2263  {
2265 
2266  return (native_encoding == encoding) ?
2267  convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
2268  convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
2269  }
2270 
2271  // source encoding is latin1
2272  if (encoding == encoding_latin1)
2273  return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
2274 
2275  assert(false && "Invalid encoding"); // unreachable
2276  return false;
2277  }
2278 #endif
2279 
2280  PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length)
2281  {
2282  // get length in utf8 characters
2283  return wchar_decoder::process(str, length, 0, utf8_counter());
2284  }
2285 
2286  PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
2287  {
2288  // convert to utf8
2289  uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
2290  uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer());
2291 
2292  assert(begin + size == end);
2293  (void)!end;
2294  (void)!size;
2295  }
2296 
2297 #ifndef PUGIXML_NO_STL
2298  PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length)
2299  {
2300  // first pass: get length in utf8 characters
2301  size_t size = as_utf8_begin(str, length);
2302 
2303  // allocate resulting string
2304  std::string result;
2305  result.resize(size);
2306 
2307  // second pass: convert to utf8
2308  if (size > 0) as_utf8_end(&result[0], size, str, length);
2309 
2310  return result;
2311  }
2312 
2313  PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)
2314  {
2315  const uint8_t* data = reinterpret_cast<const uint8_t*>(str);
2316 
2317  // first pass: get length in wchar_t units
2318  size_t length = utf8_decoder::process(data, size, 0, wchar_counter());
2319 
2320  // allocate resulting string
2321  std::basic_string<wchar_t> result;
2322  result.resize(length);
2323 
2324  // second pass: convert to wchar_t
2325  if (length > 0)
2326  {
2327  wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
2328  wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer());
2329 
2330  assert(begin + length == end);
2331  (void)!end;
2332  }
2333 
2334  return result;
2335  }
2336 #endif
2337 
2338  template <typename Header>
2339  inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target)
2340  {
2341  // never reuse shared memory
2342  if (header & xml_memory_page_contents_shared_mask) return false;
2343 
2344  size_t target_length = strlength(target);
2345 
2346  // always reuse document buffer memory if possible
2347  if ((header & header_mask) == 0) return target_length >= length;
2348 
2349  // reuse heap memory if waste is not too great
2350  const size_t reuse_threshold = 32;
2351 
2352  return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
2353  }
2354 
2355  template <typename String, typename Header>
2356  PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length)
2357  {
2358  if (source_length == 0)
2359  {
2360  // empty string and null pointer are equivalent, so just deallocate old memory
2361  xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
2362 
2363  if (header & header_mask) alloc->deallocate_string(dest);
2364 
2365  // mark the string as not allocated
2366  dest = 0;
2367  header &= ~header_mask;
2368 
2369  return true;
2370  }
2371  else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest))
2372  {
2373  // we can reuse old buffer, so just copy the new data (including zero terminator)
2374  memcpy(dest, source, source_length * sizeof(char_t));
2375  dest[source_length] = 0;
2376 
2377  return true;
2378  }
2379  else
2380  {
2381  xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
2382 
2383  if (!alloc->reserve()) return false;
2384 
2385  // allocate new buffer
2386  char_t* buf = alloc->allocate_string(source_length + 1);
2387  if (!buf) return false;
2388 
2389  // copy the string (including zero terminator)
2390  memcpy(buf, source, source_length * sizeof(char_t));
2391  buf[source_length] = 0;
2392 
2393  // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
2394  if (header & header_mask) alloc->deallocate_string(dest);
2395 
2396  // the string is now allocated, so set the flag
2397  dest = buf;
2398  header |= header_mask;
2399 
2400  return true;
2401  }
2402  }
2403 
2404  struct gap
2405  {
2407  size_t size;
2408 
2409  gap(): end(0), size(0)
2410  {
2411  }
2412 
2413  // Push new gap, move s count bytes further (skipping the gap).
2414  // Collapse previous gap.
2415  void push(char_t*& s, size_t count)
2416  {
2417  if (end) // there was a gap already; collapse it
2418  {
2419  // Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
2420  assert(s >= end);
2421  memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
2422  }
2423 
2424  s += count; // end of current gap
2425 
2426  // "merge" two gaps
2427  end = s;
2428  size += count;
2429  }
2430 
2431  // Collapse all gaps, return past-the-end pointer
2433  {
2434  if (end)
2435  {
2436  // Move [old_gap_end, current_pos) to [old_gap_start, ...)
2437  assert(s >= end);
2438  memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
2439 
2440  return s - size;
2441  }
2442  else return s;
2443  }
2444  };
2445 
2447  {
2448  char_t* stre = s + 1;
2449 
2450  switch (*stre)
2451  {
2452  case '#': // &#...
2453  {
2454  unsigned int ucsc = 0;
2455 
2456  if (stre[1] == 'x') // &#x... (hex code)
2457  {
2458  stre += 2;
2459 
2460  char_t ch = *stre;
2461 
2462  if (ch == ';') return stre;
2463 
2464  for (;;)
2465  {
2466  if (static_cast<unsigned int>(ch - '0') <= 9)
2467  ucsc = 16 * ucsc + (ch - '0');
2468  else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)
2469  ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);
2470  else if (ch == ';')
2471  break;
2472  else // cancel
2473  return stre;
2474 
2475  ch = *++stre;
2476  }
2477 
2478  ++stre;
2479  }
2480  else // &#... (dec code)
2481  {
2482  char_t ch = *++stre;
2483 
2484  if (ch == ';') return stre;
2485 
2486  for (;;)
2487  {
2488  if (static_cast<unsigned int>(ch - '0') <= 9)
2489  ucsc = 10 * ucsc + (ch - '0');
2490  else if (ch == ';')
2491  break;
2492  else // cancel
2493  return stre;
2494 
2495  ch = *++stre;
2496  }
2497 
2498  ++stre;
2499  }
2500 
2501  #ifdef PUGIXML_WCHAR_MODE
2502  s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
2503  #else
2504  s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));
2505  #endif
2506 
2507  g.push(s, stre - s);
2508  return stre;
2509  }
2510 
2511  case 'a': // &a
2512  {
2513  ++stre;
2514 
2515  if (*stre == 'm') // &am
2516  {
2517  if (*++stre == 'p' && *++stre == ';') // &amp;
2518  {
2519  *s++ = '&';
2520  ++stre;
2521 
2522  g.push(s, stre - s);
2523  return stre;
2524  }
2525  }
2526  else if (*stre == 'p') // &ap
2527  {
2528  if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // &apos;
2529  {
2530  *s++ = '\'';
2531  ++stre;
2532 
2533  g.push(s, stre - s);
2534  return stre;
2535  }
2536  }
2537  break;
2538  }
2539 
2540  case 'g': // &g
2541  {
2542  if (*++stre == 't' && *++stre == ';') // &gt;
2543  {
2544  *s++ = '>';
2545  ++stre;
2546 
2547  g.push(s, stre - s);
2548  return stre;
2549  }
2550  break;
2551  }
2552 
2553  case 'l': // &l
2554  {
2555  if (*++stre == 't' && *++stre == ';') // &lt;
2556  {
2557  *s++ = '<';
2558  ++stre;
2559 
2560  g.push(s, stre - s);
2561  return stre;
2562  }
2563  break;
2564  }
2565 
2566  case 'q': // &q
2567  {
2568  if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // &quot;
2569  {
2570  *s++ = '"';
2571  ++stre;
2572 
2573  g.push(s, stre - s);
2574  return stre;
2575  }
2576  break;
2577  }
2578 
2579  default:
2580  break;
2581  }
2582 
2583  return stre;
2584  }
2585 
2586  // Parser utilities
2587  #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
2588  #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
2589  #define PUGI__OPTSET(OPT) ( optmsk & (OPT) )
2590  #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
2591  #define PUGI__POPNODE() { cursor = cursor->parent; }
2592  #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
2593  #define PUGI__SCANWHILE(X) { while (X) ++s; }
2594  #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
2595  #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; }
2596  #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t*>(0)
2597  #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); }
2600  {
2601  gap g;
2602 
2603  while (true)
2604  {
2606 
2607  if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
2608  {
2609  *s++ = '\n'; // replace first one with 0x0a
2610 
2611  if (*s == '\n') g.push(s, 1);
2612  }
2613  else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here
2614  {
2615  *g.flush(s) = 0;
2616 
2617  return s + (s[2] == '>' ? 3 : 2);
2618  }
2619  else if (*s == 0)
2620  {
2621  return 0;
2622  }
2623  else ++s;
2624  }
2625  }
2626 
2628  {
2629  gap g;
2630 
2631  while (true)
2632  {
2634 
2635  if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
2636  {
2637  *s++ = '\n'; // replace first one with 0x0a
2638 
2639  if (*s == '\n') g.push(s, 1);
2640  }
2641  else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here
2642  {
2643  *g.flush(s) = 0;
2644 
2645  return s + 1;
2646  }
2647  else if (*s == 0)
2648  {
2649  return 0;
2650  }
2651  else ++s;
2652  }
2653  }
2654 
2655  typedef char_t* (*strconv_pcdata_t)(char_t*);
2656 
2657  template <typename opt_trim, typename opt_eol, typename opt_escape> struct strconv_pcdata_impl
2658  {
2659  static char_t* parse(char_t* s)
2660  {
2661  gap g;
2662 
2663  char_t* begin = s;
2664 
2665  while (true)
2666  {
2668 
2669  if (*s == '<') // PCDATA ends here
2670  {
2671  char_t* end = g.flush(s);
2672 
2673  if (opt_trim::value)
2674  while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2675  --end;
2676 
2677  *end = 0;
2678 
2679  return s + 1;
2680  }
2681  else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
2682  {
2683  *s++ = '\n'; // replace first one with 0x0a
2684 
2685  if (*s == '\n') g.push(s, 1);
2686  }
2687  else if (opt_escape::value && *s == '&')
2688  {
2689  s = strconv_escape(s, g);
2690  }
2691  else if (*s == 0)
2692  {
2693  char_t* end = g.flush(s);
2694 
2695  if (opt_trim::value)
2696  while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2697  --end;
2698 
2699  *end = 0;
2700 
2701  return s;
2702  }
2703  else ++s;
2704  }
2705  }
2706  };
2707 
2709  {
2710  PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
2711 
2712  switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (trim eol escapes); this simultaneously checks 3 options from assertion above
2713  {
2722  default: assert(false); return 0; // unreachable
2723  }
2724  }
2725 
2726  typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
2727 
2728  template <typename opt_escape> struct strconv_attribute_impl
2729  {
2730  static char_t* parse_wnorm(char_t* s, char_t end_quote)
2731  {
2732  gap g;
2733 
2734  // trim leading whitespaces
2735  if (PUGI__IS_CHARTYPE(*s, ct_space))
2736  {
2737  char_t* str = s;
2738 
2739  do ++str;
2740  while (PUGI__IS_CHARTYPE(*str, ct_space));
2741 
2742  g.push(s, str - s);
2743  }
2744 
2745  while (true)
2746  {
2748 
2749  if (*s == end_quote)
2750  {
2751  char_t* str = g.flush(s);
2752 
2753  do *str-- = 0;
2754  while (PUGI__IS_CHARTYPE(*str, ct_space));
2755 
2756  return s + 1;
2757  }
2758  else if (PUGI__IS_CHARTYPE(*s, ct_space))
2759  {
2760  *s++ = ' ';
2761 
2762  if (PUGI__IS_CHARTYPE(*s, ct_space))
2763  {
2764  char_t* str = s + 1;
2765  while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
2766 
2767  g.push(s, str - s);
2768  }
2769  }
2770  else if (opt_escape::value && *s == '&')
2771  {
2772  s = strconv_escape(s, g);
2773  }
2774  else if (!*s)
2775  {
2776  return 0;
2777  }
2778  else ++s;
2779  }
2780  }
2781 
2782  static char_t* parse_wconv(char_t* s, char_t end_quote)
2783  {
2784  gap g;
2785 
2786  while (true)
2787  {
2789 
2790  if (*s == end_quote)
2791  {
2792  *g.flush(s) = 0;
2793 
2794  return s + 1;
2795  }
2796  else if (PUGI__IS_CHARTYPE(*s, ct_space))
2797  {
2798  if (*s == '\r')
2799  {
2800  *s++ = ' ';
2801 
2802  if (*s == '\n') g.push(s, 1);
2803  }
2804  else *s++ = ' ';
2805  }
2806  else if (opt_escape::value && *s == '&')
2807  {
2808  s = strconv_escape(s, g);
2809  }
2810  else if (!*s)
2811  {
2812  return 0;
2813  }
2814  else ++s;
2815  }
2816  }
2817 
2818  static char_t* parse_eol(char_t* s, char_t end_quote)
2819  {
2820  gap g;
2821 
2822  while (true)
2823  {
2825 
2826  if (*s == end_quote)
2827  {
2828  *g.flush(s) = 0;
2829 
2830  return s + 1;
2831  }
2832  else if (*s == '\r')
2833  {
2834  *s++ = '\n';
2835 
2836  if (*s == '\n') g.push(s, 1);
2837  }
2838  else if (opt_escape::value && *s == '&')
2839  {
2840  s = strconv_escape(s, g);
2841  }
2842  else if (!*s)
2843  {
2844  return 0;
2845  }
2846  else ++s;
2847  }
2848  }
2849 
2850  static char_t* parse_simple(char_t* s, char_t end_quote)
2851  {
2852  gap g;
2853 
2854  while (true)
2855  {
2857 
2858  if (*s == end_quote)
2859  {
2860  *g.flush(s) = 0;
2861 
2862  return s + 1;
2863  }
2864  else if (opt_escape::value && *s == '&')
2865  {
2866  s = strconv_escape(s, g);
2867  }
2868  else if (!*s)
2869  {
2870  return 0;
2871  }
2872  else ++s;
2873  }
2874  }
2875  };
2876 
2878  {
2880 
2881  switch ((optmask >> 4) & 15) // get bitmask for flags (wnorm wconv eol escapes); this simultaneously checks 4 options from assertion above
2882  {
2899  default: assert(false); return 0; // unreachable
2900  }
2901  }
2902 
2903  inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
2904  {
2905  xml_parse_result result;
2906  result.status = status;
2907  result.offset = offset;
2908 
2909  return result;
2910  }
2911 
2912  struct xml_parser
2913  {
2917 
2919  {
2920  }
2921 
2922  // DOCTYPE consists of nested sections of the following possible types:
2923  // <!-- ... -->, <? ... ?>, "...", '...'
2924  // <![...]]>
2925  // <!...>
2926  // First group can not contain nested groups
2927  // Second group can contain nested groups of the same type
2928  // Third group can contain all other groups
2930  {
2931  if (*s == '"' || *s == '\'')
2932  {
2933  // quoted string
2934  char_t ch = *s++;
2935  PUGI__SCANFOR(*s == ch);
2937 
2938  s++;
2939  }
2940  else if (s[0] == '<' && s[1] == '?')
2941  {
2942  // <? ... ?>
2943  s += 2;
2944  PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
2946 
2947  s += 2;
2948  }
2949  else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')
2950  {
2951  s += 4;
2952  PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
2954 
2955  s += 3;
2956  }
2958 
2959  return s;
2960  }
2961 
2963  {
2964  size_t depth = 0;
2965 
2966  assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
2967  s += 3;
2968 
2969  while (*s)
2970  {
2971  if (s[0] == '<' && s[1] == '!' && s[2] == '[')
2972  {
2973  // nested ignore section
2974  s += 3;
2975  depth++;
2976  }
2977  else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
2978  {
2979  // ignore section end
2980  s += 3;
2981 
2982  if (depth == 0)
2983  return s;
2984 
2985  depth--;
2986  }
2987  else s++;
2988  }
2989 
2991  }
2992 
2994  {
2995  size_t depth = 0;
2996 
2997  assert((s[0] == '<' || s[0] == 0) && s[1] == '!');
2998  s += 2;
2999 
3000  while (*s)
3001  {
3002  if (s[0] == '<' && s[1] == '!' && s[2] != '-')
3003  {
3004  if (s[2] == '[')
3005  {
3006  // ignore
3007  s = parse_doctype_ignore(s);
3008  if (!s) return s;
3009  }
3010  else
3011  {
3012  // some control group
3013  s += 2;
3014  depth++;
3015  }
3016  }
3017  else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
3018  {
3019  // unknown tag (forbidden), or some primitive group
3020  s = parse_doctype_primitive(s);
3021  if (!s) return s;
3022  }
3023  else if (*s == '>')
3024  {
3025  if (depth == 0)
3026  return s;
3027 
3028  depth--;
3029  s++;
3030  }
3031  else s++;
3032  }
3033 
3034  if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
3035 
3036  return s;
3037  }
3038 
3039  char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch)
3040  {
3041  // parse node contents, starting with exclamation mark
3042  ++s;
3043 
3044  if (*s == '-') // '<!-...'
3045  {
3046  ++s;
3047 
3048  if (*s == '-') // '<!--...'
3049  {
3050  ++s;
3051 
3053  {
3054  PUGI__PUSHNODE(node_comment); // Append a new node on the tree.
3055  cursor->value = s; // Save the offset.
3056  }
3057 
3059  {
3060  s = strconv_comment(s, endch);
3061 
3062  if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
3063  }
3064  else
3065  {
3066  // Scan for terminating '-->'.
3067  PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>'));
3069 
3071  *s = 0; // Zero-terminate this segment at the first terminating '-'.
3072 
3073  s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
3074  }
3075  }
3077  }
3078  else if (*s == '[')
3079  {
3080  // '<![CDATA[...'
3081  if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')
3082  {
3083  ++s;
3084 
3086  {
3087  PUGI__PUSHNODE(node_cdata); // Append a new node on the tree.
3088  cursor->value = s; // Save the offset.
3089 
3090  if (PUGI__OPTSET(parse_eol))
3091  {
3092  s = strconv_cdata(s, endch);
3093 
3094  if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
3095  }
3096  else
3097  {
3098  // Scan for terminating ']]>'.
3099  PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
3101 
3102  *s++ = 0; // Zero-terminate this segment.
3103  }
3104  }
3105  else // Flagged for discard, but we still have to scan for the terminator.
3106  {
3107  // Scan for terminating ']]>'.
3108  PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
3110 
3111  ++s;
3112  }
3113 
3114  s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
3115  }
3117  }
3118  else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI__ENDSWITH(s[6], 'E'))
3119  {
3120  s -= 2;
3121 
3122  if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
3123 
3124  char_t* mark = s + 9;
3125 
3126  s = parse_doctype_group(s, endch);
3127  if (!s) return s;
3128 
3129  assert((*s == 0 && endch == '>') || *s == '>');
3130  if (*s) *s++ = 0;
3131 
3133  {
3134  while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
3135 
3137 
3138  cursor->value = mark;
3139  }
3140  }
3141  else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s);
3142  else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s);
3144 
3145  return s;
3146  }
3147 
3148  char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch)
3149  {
3150  // load into registers
3151  xml_node_struct* cursor = ref_cursor;
3152  char_t ch = 0;
3153 
3154  // parse node contents, starting with question mark
3155  ++s;
3156 
3157  // read PI target
3158  char_t* target = s;
3159 
3161 
3164 
3165  // determine node type; stricmp / strcasecmp is not portable
3166  bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
3167 
3168  if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
3169  {
3170  if (declaration)
3171  {
3172  // disallow non top-level declarations
3173  if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
3174 
3176  }
3177  else
3178  {
3180  }
3181 
3182  cursor->name = target;
3183 
3184  PUGI__ENDSEG();
3185 
3186  // parse value/attributes
3187  if (ch == '?')
3188  {
3189  // empty node
3190  if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s);
3191  s += (*s == '>');
3192 
3193  PUGI__POPNODE();
3194  }
3195  else if (PUGI__IS_CHARTYPE(ch, ct_space))
3196  {
3197  PUGI__SKIPWS();
3198 
3199  // scan for tag end
3200  char_t* value = s;
3201 
3202  PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
3204 
3205  if (declaration)
3206  {
3207  // replace ending ? with / so that 'element' terminates properly
3208  *s = '/';
3209 
3210  // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES
3211  s = value;
3212  }
3213  else
3214  {
3215  // store value and step over >
3216  cursor->value = value;
3217 
3218  PUGI__POPNODE();
3219 
3220  PUGI__ENDSEG();
3221 
3222  s += (*s == '>');
3223  }
3224  }
3226  }
3227  else
3228  {
3229  // scan for tag end
3230  PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
3232 
3233  s += (s[1] == '>' ? 2 : 1);
3234  }
3235 
3236  // store from registers
3237  ref_cursor = cursor;
3238 
3239  return s;
3240  }
3241 
3242  char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch)
3243  {
3244  strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
3245  strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
3246 
3247  char_t ch = 0;
3248  xml_node_struct* cursor = root;
3249  char_t* mark = s;
3250 
3251  while (*s != 0)
3252  {
3253  if (*s == '<')
3254  {
3255  ++s;
3256 
3257  LOC_TAG:
3258  if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
3259  {
3260  PUGI__PUSHNODE(node_element); // Append a new node to the tree.
3261 
3262  cursor->name = s;
3263 
3264  PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
3265  PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
3266 
3267  if (ch == '>')
3268  {
3269  // end of tag
3270  }
3271  else if (PUGI__IS_CHARTYPE(ch, ct_space))
3272  {
3273  LOC_ATTRIBUTES:
3274  while (true)
3275  {
3276  PUGI__SKIPWS(); // Eat any whitespace.
3277 
3278  if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
3279  {
3280  xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute.
3282 
3283  a->name = s; // Save the offset.
3284 
3285  PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
3286  PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
3287 
3288  if (PUGI__IS_CHARTYPE(ch, ct_space))
3289  {
3290  PUGI__SKIPWS(); // Eat any whitespace.
3291 
3292  ch = *s;
3293  ++s;
3294  }
3295 
3296  if (ch == '=') // '<... #=...'
3297  {
3298  PUGI__SKIPWS(); // Eat any whitespace.
3299 
3300  if (*s == '"' || *s == '\'') // '<... #="...'
3301  {
3302  ch = *s; // Save quote char to avoid breaking on "''" -or- '""'.
3303  ++s; // Step over the quote.
3304  a->value = s; // Save the offset.
3305 
3306  s = strconv_attribute(s, ch);
3307 
3308  if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
3309 
3310  // After this line the loop continues from the start;
3311  // Whitespaces, / and > are ok, symbols and EOF are wrong,
3312  // everything else will be detected
3314  }
3316  }
3318  }
3319  else if (*s == '/')
3320  {
3321  ++s;
3322 
3323  if (*s == '>')
3324  {
3325  PUGI__POPNODE();
3326  s++;
3327  break;
3328  }
3329  else if (*s == 0 && endch == '>')
3330  {
3331  PUGI__POPNODE();
3332  break;
3333  }
3335  }
3336  else if (*s == '>')
3337  {
3338  ++s;
3339 
3340  break;
3341  }
3342  else if (*s == 0 && endch == '>')
3343  {
3344  break;
3345  }
3347  }
3348 
3349  // !!!
3350  }
3351  else if (ch == '/') // '<#.../'
3352  {
3354 
3355  PUGI__POPNODE(); // Pop.
3356 
3357  s += (*s == '>');
3358  }
3359  else if (ch == 0)
3360  {
3361  // we stepped over null terminator, backtrack & handle closing tag
3362  --s;
3363 
3364  if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s);
3365  }
3367  }
3368  else if (*s == '/')
3369  {
3370  ++s;
3371 
3372  mark = s;
3373 
3374  char_t* name = cursor->name;
3376 
3377  while (PUGI__IS_CHARTYPE(*s, ct_symbol))
3378  {
3379  if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
3380  }
3381 
3382  if (*name)
3383  {
3384  if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
3386  }
3387 
3388  PUGI__POPNODE(); // Pop.
3389 
3390  PUGI__SKIPWS();
3391 
3392  if (*s == 0)
3393  {
3394  if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
3395  }
3396  else
3397  {
3398  if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
3399  ++s;
3400  }
3401  }
3402  else if (*s == '?') // '<?...'
3403  {
3404  s = parse_question(s, cursor, optmsk, endch);
3405  if (!s) return s;
3406 
3407  assert(cursor);
3408  if (PUGI__NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES;
3409  }
3410  else if (*s == '!') // '<!...'
3411  {
3412  s = parse_exclamation(s, cursor, optmsk, endch);
3413  if (!s) return s;
3414  }
3415  else if (*s == 0 && endch == '?') PUGI__THROW_ERROR(status_bad_pi, s);
3417  }
3418  else
3419  {
3420  mark = s; // Save this offset while searching for a terminator.
3421 
3422  PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
3423 
3424  if (*s == '<' || !*s)
3425  {
3426  // We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one
3427  assert(mark != s);
3428 
3430  {
3431  continue;
3432  }
3434  {
3435  if (s[0] != '<' || s[1] != '/' || cursor->first_child) continue;
3436  }
3437  }
3438 
3440  s = mark;
3441 
3442  if (cursor->parent || PUGI__OPTSET(parse_fragment))
3443  {
3444  if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value)
3445  {
3446  cursor->value = s; // Save the offset.
3447  }
3448  else
3449  {
3450  PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree.
3451 
3452  cursor->value = s; // Save the offset.
3453 
3454  PUGI__POPNODE(); // Pop since this is a standalone.
3455  }
3456 
3457  s = strconv_pcdata(s);
3458 
3459  if (!*s) break;
3460  }
3461  else
3462  {
3463  PUGI__SCANFOR(*s == '<'); // '...<'
3464  if (!*s) break;
3465 
3466  ++s;
3467  }
3468 
3469  // We're after '<'
3470  goto LOC_TAG;
3471  }
3472  }
3473 
3474  // check that last tag is closed
3475  if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s);
3476 
3477  return s;
3478  }
3479 
3480  #ifdef PUGIXML_WCHAR_MODE
3481  static char_t* parse_skip_bom(char_t* s)
3482  {
3483  unsigned int bom = 0xfeff;
3484  return (s[0] == static_cast<wchar_t>(bom)) ? s + 1 : s;
3485  }
3486  #else
3488  {
3489  return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s;
3490  }
3491  #endif
3492 
3493  static bool has_element_node_siblings(xml_node_struct* node)
3494  {
3495  while (node)
3496  {
3497  if (PUGI__NODETYPE(node) == node_element) return true;
3498 
3499  node = node->next_sibling;
3500  }
3501 
3502  return false;
3503  }
3504 
3505  static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk)
3506  {
3507  // early-out for empty documents
3508  if (length == 0)
3510 
3511  // get last child of the root before parsing
3512  xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
3513 
3514  // create parser on stack
3515  xml_parser parser(static_cast<xml_allocator*>(xmldoc));
3516 
3517  // save last character and make buffer zero-terminated (speeds up parsing)
3518  char_t endch = buffer[length - 1];
3519  buffer[length - 1] = 0;
3520 
3521  // skip BOM to make sure it does not end up as part of parse output
3522  char_t* buffer_data = parse_skip_bom(buffer);
3523 
3524  // perform actual parsing
3525  parser.parse_tree(buffer_data, root, optmsk, endch);
3526 
3527  xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
3528  assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
3529 
3530  if (result)
3531  {
3532  // since we removed last character, we have to handle the only possible false positive (stray <)
3533  if (endch == '<')
3534  return make_parse_result(status_unrecognized_tag, length - 1);
3535 
3536  // check if there are any element nodes parsed
3537  xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0;
3538 
3539  if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
3540  return make_parse_result(status_no_document_element, length - 1);
3541  }
3542  else
3543  {
3544  // roll back offset if it occurs on a null terminator in the source buffer
3545  if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0)
3546  result.offset--;
3547  }
3548 
3549  return result;
3550  }
3551  };
3552 
3553  // Output facilities
3555  {
3556  #ifdef PUGIXML_WCHAR_MODE
3557  return get_wchar_encoding();
3558  #else
3559  return encoding_utf8;
3560  #endif
3561  }
3562 
3564  {
3565  // replace wchar encoding with utf implementation
3566  if (encoding == encoding_wchar) return get_wchar_encoding();
3567 
3568  // replace utf16 encoding with utf16 with specific endianness
3570 
3571  // replace utf32 encoding with utf32 with specific endianness
3573 
3574  // only do autodetection if no explicit encoding is requested
3575  if (encoding != encoding_auto) return encoding;
3576 
3577  // assume utf8 encoding
3578  return encoding_utf8;
3579  }
3580 
3581  template <typename D, typename T> PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T)
3582  {
3583  PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
3584 
3585  typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
3586 
3587  return static_cast<size_t>(end - dest) * sizeof(*dest);
3588  }
3589 
3590  template <typename D, typename T> PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap)
3591  {
3592  PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
3593 
3594  typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
3595 
3596  if (opt_swap)
3597  {
3598  for (typename T::value_type i = dest; i != end; ++i)
3599  *i = endian_swap(*i);
3600  }
3601 
3602  return static_cast<size_t>(end - dest) * sizeof(*dest);
3603  }
3604 
3605 #ifdef PUGIXML_WCHAR_MODE
3606  PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
3607  {
3608  if (length < 1) return 0;
3609 
3610  // discard last character if it's the lead of a surrogate pair
3611  return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
3612  }
3613 
3614  PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
3615  {
3616  // only endian-swapping is required
3617  if (need_endian_swap_utf(encoding, get_wchar_encoding()))
3618  {
3619  convert_wchar_endian_swap(r_char, data, length);
3620 
3621  return length * sizeof(char_t);
3622  }
3623 
3624  // convert to utf8
3625  if (encoding == encoding_utf8)
3626  return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer());
3627 
3628  // convert to utf16
3629  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3630  {
3632 
3633  return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding);
3634  }
3635 
3636  // convert to utf32
3637  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3638  {
3640 
3641  return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding);
3642  }
3643 
3644  // convert to latin1
3645  if (encoding == encoding_latin1)
3646  return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer());
3647 
3648  assert(false && "Invalid encoding"); // unreachable
3649  return 0;
3650  }
3651 #else
3652  PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
3653  {
3654  if (length < 5) return 0;
3655 
3656  for (size_t i = 1; i <= 4; ++i)
3657  {
3658  uint8_t ch = static_cast<uint8_t>(data[length - i]);
3659 
3660  // either a standalone character or a leading one
3661  if ((ch & 0xc0) != 0x80) return length - i;
3662  }
3663 
3664  // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk
3665  return length;
3666  }
3667 
3668  PUGI__FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
3669  {
3670  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3671  {
3673 
3674  return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding);
3675  }
3676 
3677  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3678  {
3680 
3681  return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding);
3682  }
3683 
3684  if (encoding == encoding_latin1)
3685  return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer());
3686 
3687  assert(false && "Invalid encoding"); // unreachable
3688  return 0;
3689  }
3690 #endif
3691 
3693  {
3696 
3697  public:
3698  xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
3699  {
3701  }
3702 
3703  size_t flush()
3704  {
3705  flush(buffer, bufsize);
3706  bufsize = 0;
3707  return 0;
3708  }
3709 
3710  void flush(const char_t* data, size_t size)
3711  {
3712  if (size == 0) return;
3713 
3714  // fast path, just write data
3716  writer.write(data, size * sizeof(char_t));
3717  else
3718  {
3719  // convert chunk
3720  size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);
3721  assert(result <= sizeof(scratch));
3722 
3723  // write data
3724  writer.write(scratch.data_u8, result);
3725  }
3726  }
3727 
3728  void write_direct(const char_t* data, size_t length)
3729  {
3730  // flush the remaining buffer contents
3731  flush();
3732 
3733  // handle large chunks
3734  if (length > bufcapacity)
3735  {
3737  {
3738  // fast path, can just write data chunk
3739  writer.write(data, length * sizeof(char_t));
3740  return;
3741  }
3742 
3743  // need to convert in suitable chunks
3744  while (length > bufcapacity)
3745  {
3746  // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer
3747  // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
3748  size_t chunk_size = get_valid_length(data, bufcapacity);
3749  assert(chunk_size);
3750 
3751  // convert chunk and write
3752  flush(data, chunk_size);
3753 
3754  // iterate
3755  data += chunk_size;
3756  length -= chunk_size;
3757  }
3758 
3759  // small tail is copied below
3760  bufsize = 0;
3761  }
3762 
3763  memcpy(buffer + bufsize, data, length * sizeof(char_t));
3764  bufsize += length;
3765  }
3766 
3767  void write_buffer(const char_t* data, size_t length)
3768  {
3769  size_t offset = bufsize;
3770 
3771  if (offset + length <= bufcapacity)
3772  {
3773  memcpy(buffer + offset, data, length * sizeof(char_t));
3774  bufsize = offset + length;
3775  }
3776  else
3777  {
3778  write_direct(data, length);
3779  }
3780  }
3781 
3782  void write_string(const char_t* data)
3783  {
3784  // write the part of the string that fits in the buffer
3785  size_t offset = bufsize;
3786 
3787  while (*data && offset < bufcapacity)
3788  buffer[offset++] = *data++;
3789 
3790  // write the rest
3791  if (offset < bufcapacity)
3792  {
3793  bufsize = offset;
3794  }
3795  else
3796  {
3797  // backtrack a bit if we have split the codepoint
3798  size_t length = offset - bufsize;
3799  size_t extra = length - get_valid_length(data - length, length);
3800 
3801  bufsize = offset - extra;
3802 
3803  write_direct(data - extra, strlength(data) + extra);
3804  }
3805  }
3806 
3807  void write(char_t d0)
3808  {
3809  size_t offset = bufsize;
3810  if (offset > bufcapacity - 1) offset = flush();
3811 
3812  buffer[offset + 0] = d0;
3813  bufsize = offset + 1;
3814  }
3815 
3816  void write(char_t d0, char_t d1)
3817  {
3818  size_t offset = bufsize;
3819  if (offset > bufcapacity - 2) offset = flush();
3820 
3821  buffer[offset + 0] = d0;
3822  buffer[offset + 1] = d1;
3823  bufsize = offset + 2;
3824  }
3825 
3826  void write(char_t d0, char_t d1, char_t d2)
3827  {
3828  size_t offset = bufsize;
3829  if (offset > bufcapacity - 3) offset = flush();
3830 
3831  buffer[offset + 0] = d0;
3832  buffer[offset + 1] = d1;
3833  buffer[offset + 2] = d2;
3834  bufsize = offset + 3;
3835  }
3836 
3837  void write(char_t d0, char_t d1, char_t d2, char_t d3)
3838  {
3839  size_t offset = bufsize;
3840  if (offset > bufcapacity - 4) offset = flush();
3841 
3842  buffer[offset + 0] = d0;
3843  buffer[offset + 1] = d1;
3844  buffer[offset + 2] = d2;
3845  buffer[offset + 3] = d3;
3846  bufsize = offset + 4;
3847  }
3848 
3849  void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
3850  {
3851  size_t offset = bufsize;
3852  if (offset > bufcapacity - 5) offset = flush();
3853 
3854  buffer[offset + 0] = d0;
3855  buffer[offset + 1] = d1;
3856  buffer[offset + 2] = d2;
3857  buffer[offset + 3] = d3;
3858  buffer[offset + 4] = d4;
3859  bufsize = offset + 5;
3860  }
3861 
3862  void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
3863  {
3864  size_t offset = bufsize;
3865  if (offset > bufcapacity - 6) offset = flush();
3866 
3867  buffer[offset + 0] = d0;
3868  buffer[offset + 1] = d1;
3869  buffer[offset + 2] = d2;
3870  buffer[offset + 3] = d3;
3871  buffer[offset + 4] = d4;
3872  buffer[offset + 5] = d5;
3873  bufsize = offset + 6;
3874  }
3875 
3876  // utf8 maximum expansion: x4 (-> utf32)
3877  // utf16 maximum expansion: x2 (-> utf32)
3878  // utf32 maximum expansion: x1
3879  enum
3880  {
3882  #ifdef PUGIXML_MEMORY_OUTPUT_STACK
3883  PUGIXML_MEMORY_OUTPUT_STACK
3884  #else
3885  10240
3886  #endif
3887  ,
3888  bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4)
3889  };
3890 
3892 
3893  union
3894  {
3895  uint8_t data_u8[4 * bufcapacity];
3896  uint16_t data_u16[2 * bufcapacity];
3900 
3901  xml_writer& writer;
3902  size_t bufsize;
3904  };
3905 
3906  PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
3907  {
3908  while (*s)
3909  {
3910  const char_t* prev = s;
3911 
3912  // While *s is a usual symbol
3914 
3915  writer.write_buffer(prev, static_cast<size_t>(s - prev));
3916 
3917  switch (*s)
3918  {
3919  case 0: break;
3920  case '&':
3921  writer.write('&', 'a', 'm', 'p', ';');
3922  ++s;
3923  break;
3924  case '<':
3925  writer.write('&', 'l', 't', ';');
3926  ++s;
3927  break;
3928  case '>':
3929  writer.write('&', 'g', 't', ';');
3930  ++s;
3931  break;
3932  case '"':
3933  if (flags & format_attribute_single_quote)
3934  writer.write('"');
3935  else
3936  writer.write('&', 'q', 'u', 'o', 't', ';');
3937  ++s;
3938  break;
3939  case '\'':
3940  if (flags & format_attribute_single_quote)
3941  writer.write('&', 'a', 'p', 'o', 's', ';');
3942  else
3943  writer.write('\'');
3944  ++s;
3945  break;
3946  default: // s is not a usual symbol
3947  {
3948  unsigned int ch = static_cast<unsigned int>(*s++);
3949  assert(ch < 32);
3950 
3951  if (!(flags & format_skip_control_chars))
3952  writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');
3953  }
3954  }
3955  }
3956  }
3957 
3958  PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
3959  {
3960  if (flags & format_no_escapes)
3961  writer.write_string(s);
3962  else
3963  text_output_escaped(writer, s, type, flags);
3964  }
3965 
3967  {
3968  do
3969  {
3970  writer.write('<', '!', '[', 'C', 'D');
3971  writer.write('A', 'T', 'A', '[');
3972 
3973  const char_t* prev = s;
3974 
3975  // look for ]]> sequence - we can't output it as is since it terminates CDATA
3976  while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s;
3977 
3978  // skip ]] if we stopped at ]]>, > will go to the next CDATA section
3979  if (*s) s += 2;
3980 
3981  writer.write_buffer(prev, static_cast<size_t>(s - prev));
3982 
3983  writer.write(']', ']', '>');
3984  }
3985  while (*s);
3986  }
3987 
3988  PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth)
3989  {
3990  switch (indent_length)
3991  {
3992  case 1:
3993  {
3994  for (unsigned int i = 0; i < depth; ++i)
3995  writer.write(indent[0]);
3996  break;
3997  }
3998 
3999  case 2:
4000  {
4001  for (unsigned int i = 0; i < depth; ++i)
4002  writer.write(indent[0], indent[1]);
4003  break;
4004  }
4005 
4006  case 3:
4007  {
4008  for (unsigned int i = 0; i < depth; ++i)
4009  writer.write(indent[0], indent[1], indent[2]);
4010  break;
4011  }
4012 
4013  case 4:
4014  {
4015  for (unsigned int i = 0; i < depth; ++i)
4016  writer.write(indent[0], indent[1], indent[2], indent[3]);
4017  break;
4018  }
4019 
4020  default:
4021  {
4022  for (unsigned int i = 0; i < depth; ++i)
4023  writer.write_buffer(indent, indent_length);
4024  }
4025  }
4026  }
4027 
4029  {
4030  writer.write('<', '!', '-', '-');
4031 
4032  while (*s)
4033  {
4034  const char_t* prev = s;
4035 
4036  // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body
4037  while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s;
4038 
4039  writer.write_buffer(prev, static_cast<size_t>(s - prev));
4040 
4041  if (*s)
4042  {
4043  assert(*s == '-');
4044 
4045  writer.write('-', ' ');
4046  ++s;
4047  }
4048  }
4049 
4050  writer.write('-', '-', '>');
4051  }
4052 
4054  {
4055  while (*s)
4056  {
4057  const char_t* prev = s;
4058 
4059  // look for ?> sequence - we can't output it since ?> terminates PI
4060  while (*s && !(s[0] == '?' && s[1] == '>')) ++s;
4061 
4062  writer.write_buffer(prev, static_cast<size_t>(s - prev));
4063 
4064  if (*s)
4065  {
4066  assert(s[0] == '?' && s[1] == '>');
4067 
4068  writer.write('?', ' ', '>');
4069  s += 2;
4070  }
4071  }
4072  }
4073 
4074  PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)
4075  {
4076  const char_t* default_name = PUGIXML_TEXT(":anonymous");
4077  const char_t enquotation_char = (flags & format_attribute_single_quote) ? '\'' : '"';
4078 
4079  for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
4080  {
4082  {
4083  writer.write('\n');
4084 
4085  text_output_indent(writer, indent, indent_length, depth + 1);
4086  }
4087  else
4088  {
4089  writer.write(' ');
4090  }
4091 
4092  writer.write_string(a->name ? a->name + 0 : default_name);
4093  writer.write('=', enquotation_char);
4094 
4095  if (a->value)
4096  text_output(writer, a->value, ctx_special_attr, flags);
4097 
4098  writer.write(enquotation_char);
4099  }
4100  }
4101 
4102  PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)
4103  {
4104  const char_t* default_name = PUGIXML_TEXT(":anonymous");
4105  const char_t* name = node->name ? node->name + 0 : default_name;
4106 
4107  writer.write('<');
4108  writer.write_string(name);
4109 
4110  if (node->first_attribute)
4111  node_output_attributes(writer, node, indent, indent_length, flags, depth);
4112 
4113  // element nodes can have value if parse_embed_pcdata was used
4114  if (!node->value)
4115  {
4116  if (!node->first_child)
4117  {
4118  if (flags & format_no_empty_element_tags)
4119  {
4120  writer.write('>', '<', '/');
4121  writer.write_string(name);
4122  writer.write('>');
4123 
4124  return false;
4125  }
4126  else
4127  {
4128  if ((flags & format_raw) == 0)
4129  writer.write(' ');
4130 
4131  writer.write('/', '>');
4132 
4133  return false;
4134  }
4135  }
4136  else
4137  {
4138  writer.write('>');
4139 
4140  return true;
4141  }
4142  }
4143  else
4144  {
4145  writer.write('>');
4146 
4147  text_output(writer, node->value, ctx_special_pcdata, flags);
4148 
4149  if (!node->first_child)
4150  {
4151  writer.write('<', '/');
4152  writer.write_string(name);
4153  writer.write('>');
4154 
4155  return false;
4156  }
4157  else
4158  {
4159  return true;
4160  }
4161  }
4162  }
4163 
4164  PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node)
4165  {
4166  const char_t* default_name = PUGIXML_TEXT(":anonymous");
4167  const char_t* name = node->name ? node->name + 0 : default_name;
4168 
4169  writer.write('<', '/');
4170  writer.write_string(name);
4171  writer.write('>');
4172  }
4173 
4174  PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)
4175  {
4176  const char_t* default_name = PUGIXML_TEXT(":anonymous");
4177 
4178  switch (PUGI__NODETYPE(node))
4179  {
4180  case node_pcdata:
4181  text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags);
4182  break;
4183 
4184  case node_cdata:
4185  text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
4186  break;
4187 
4188  case node_comment:
4189  node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
4190  break;
4191 
4192  case node_pi:
4193  writer.write('<', '?');
4194  writer.write_string(node->name ? node->name + 0 : default_name);
4195 
4196  if (node->value)
4197  {
4198  writer.write(' ');
4199  node_output_pi_value(writer, node->value);
4200  }
4201 
4202  writer.write('?', '>');
4203  break;
4204 
4205  case node_declaration:
4206  writer.write('<', '?');
4207  writer.write_string(node->name ? node->name + 0 : default_name);
4208  node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0);
4209  writer.write('?', '>');
4210  break;
4211 
4212  case node_doctype:
4213  writer.write('<', '!', 'D', 'O', 'C');
4214  writer.write('T', 'Y', 'P', 'E');
4215 
4216  if (node->value)
4217  {
4218  writer.write(' ');
4219  writer.write_string(node->value);
4220  }
4221 
4222  writer.write('>');
4223  break;
4224 
4225  default:
4226  assert(false && "Invalid node type"); // unreachable
4227  }
4228  }
4229 
4231  {
4233  indent_indent = 2
4234  };
4235 
4236  PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth)
4237  {
4238  size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0;
4239  unsigned int indent_flags = indent_indent;
4240 
4241  xml_node_struct* node = root;
4242 
4243  do
4244  {
4245  assert(node);
4246 
4247  // begin writing current node
4248  if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata)
4249  {
4250  node_output_simple(writer, node, flags);
4251 
4252  indent_flags = 0;
4253  }
4254  else
4255  {
4256  if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4257  writer.write('\n');
4258 
4259  if ((indent_flags & indent_indent) && indent_length)
4260  text_output_indent(writer, indent, indent_length, depth);
4261 
4262  if (PUGI__NODETYPE(node) == node_element)
4263  {
4264  indent_flags = indent_newline | indent_indent;
4265 
4266  if (node_output_start(writer, node, indent, indent_length, flags, depth))
4267  {
4268  // element nodes can have value if parse_embed_pcdata was used
4269  if (node->value)
4270  indent_flags = 0;
4271 
4272  node = node->first_child;
4273  depth++;
4274  continue;
4275  }
4276  }
4277  else if (PUGI__NODETYPE(node) == node_document)
4278  {
4279  indent_flags = indent_indent;
4280 
4281  if (node->first_child)
4282  {
4283  node = node->first_child;
4284  continue;
4285  }
4286  }
4287  else
4288  {
4289  node_output_simple(writer, node, flags);
4290 
4291  indent_flags = indent_newline | indent_indent;
4292  }
4293  }
4294 
4295  // continue to the next node
4296  while (node != root)
4297  {
4298  if (node->next_sibling)
4299  {
4300  node = node->next_sibling;
4301  break;
4302  }
4303 
4304  node = node->parent;
4305 
4306  // write closing node
4307  if (PUGI__NODETYPE(node) == node_element)
4308  {
4309  depth--;
4310 
4311  if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4312  writer.write('\n');
4313 
4314  if ((indent_flags & indent_indent) && indent_length)
4315  text_output_indent(writer, indent, indent_length, depth);
4316 
4317  node_output_end(writer, node);
4318 
4319  indent_flags = indent_newline | indent_indent;
4320  }
4321  }
4322  }
4323  while (node != root);
4324 
4325  if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4326  writer.write('\n');
4327  }
4328 
4329  PUGI__FN bool has_declaration(xml_node_struct* node)
4330  {
4331  for (xml_node_struct* child = node->first_child; child; child = child->next_sibling)
4332  {
4333  xml_node_type type = PUGI__NODETYPE(child);
4334 
4335  if (type == node_declaration) return true;
4336  if (type == node_element) return false;
4337  }
4338 
4339  return false;
4340  }
4341 
4342  PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node)
4343  {
4344  for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
4345  if (a == attr)
4346  return true;
4347 
4348  return false;
4349  }
4350 
4352  {
4353  return parent == node_element || parent == node_declaration;
4354  }
4355 
4357  {
4358  if (parent != node_document && parent != node_element) return false;
4359  if (child == node_document || child == node_null) return false;
4360  if (parent != node_document && (child == node_declaration || child == node_doctype)) return false;
4361 
4362  return true;
4363  }
4364 
4365  PUGI__FN bool allow_move(xml_node parent, xml_node child)
4366  {
4367  // check that child can be a child of parent
4368  if (!allow_insert_child(parent.type(), child.type()))
4369  return false;
4370 
4371  // check that node is not moved between documents
4372  if (parent.root() != child.root())
4373  return false;
4374 
4375  // check that new parent is not in the child subtree
4376  xml_node cur = parent;
4377 
4378  while (cur)
4379  {
4380  if (cur == child)
4381  return false;
4382 
4383  cur = cur.parent();
4384  }
4385 
4386  return true;
4387  }
4388 
4389  template <typename String, typename Header>
4390  PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)
4391  {
4392  assert(!dest && (header & header_mask) == 0);
4393 
4394  if (source)
4395  {
4396  if (alloc && (source_header & header_mask) == 0)
4397  {
4398  dest = source;
4399 
4400  // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared
4402  source_header |= xml_memory_page_contents_shared_mask;
4403  }
4404  else
4405  strcpy_insitu(dest, header, header_mask, source, strlength(source));
4406  }
4407  }
4408 
4409  PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc)
4410  {
4411  node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc);
4412  node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc);
4413 
4414  for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute)
4415  {
4416  xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn));
4417 
4418  if (da)
4419  {
4420  node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
4421  node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
4422  }
4423  }
4424  }
4425 
4426  PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)
4427  {
4428  xml_allocator& alloc = get_allocator(dn);
4429  xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0;
4430 
4431  node_copy_contents(dn, sn, shared_alloc);
4432 
4433  xml_node_struct* dit = dn;
4434  xml_node_struct* sit = sn->first_child;
4435 
4436  while (sit && sit != sn)
4437  {
4438  // when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop
4439  if (sit != dn)
4440  {
4441  xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit));
4442 
4443  if (copy)
4444  {
4445  node_copy_contents(copy, sit, shared_alloc);
4446 
4447  if (sit->first_child)
4448  {
4449  dit = copy;
4450  sit = sit->first_child;
4451  continue;
4452  }
4453  }
4454  }
4455 
4456  // continue to the next node
4457  do
4458  {
4459  if (sit->next_sibling)
4460  {
4461  sit = sit->next_sibling;
4462  break;
4463  }
4464 
4465  sit = sit->parent;
4466  dit = dit->parent;
4467  }
4468  while (sit != sn);
4469  }
4470  }
4471 
4472  PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
4473  {
4474  xml_allocator& alloc = get_allocator(da);
4475  xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0;
4476 
4477  node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
4478  node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
4479  }
4480 
4481  inline bool is_text_node(xml_node_struct* node)
4482  {
4483  xml_node_type type = PUGI__NODETYPE(node);
4484 
4485  return type == node_pcdata || type == node_cdata;
4486  }
4487 
4488  // get value with conversion functions
4489  template <typename U> PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv)
4490  {
4491  U result = 0;
4492  const char_t* s = value;
4493 
4494  while (PUGI__IS_CHARTYPE(*s, ct_space))
4495  s++;
4496 
4497  bool negative = (*s == '-');
4498 
4499  s += (*s == '+' || *s == '-');
4500 
4501  bool overflow = false;
4502 
4503  if (s[0] == '0' && (s[1] | ' ') == 'x')
4504  {
4505  s += 2;
4506 
4507  // since overflow detection relies on length of the sequence skip leading zeros
4508  while (*s == '0')
4509  s++;
4510 
4511  const char_t* start = s;
4512 
4513  for (;;)
4514  {
4515  if (static_cast<unsigned>(*s - '0') < 10)
4516  result = result * 16 + (*s - '0');
4517  else if (static_cast<unsigned>((*s | ' ') - 'a') < 6)
4518  result = result * 16 + ((*s | ' ') - 'a' + 10);
4519  else
4520  break;
4521 
4522  s++;
4523  }
4524 
4525  size_t digits = static_cast<size_t>(s - start);
4526 
4527  overflow = digits > sizeof(U) * 2;
4528  }
4529  else
4530  {
4531  // since overflow detection relies on length of the sequence skip leading zeros
4532  while (*s == '0')
4533  s++;
4534 
4535  const char_t* start = s;
4536 
4537  for (;;)
4538  {
4539  if (static_cast<unsigned>(*s - '0') < 10)
4540  result = result * 10 + (*s - '0');
4541  else
4542  break;
4543 
4544  s++;
4545  }
4546 
4547  size_t digits = static_cast<size_t>(s - start);
4548 
4549  PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);
4550 
4551  const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
4552  const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6';
4553  const size_t high_bit = sizeof(U) * 8 - 1;
4554 
4555  overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit)));
4556  }
4557 
4558  if (negative)
4559  {
4560  // Workaround for crayc++ CC-3059: Expected no overflow in routine.
4561  #ifdef _CRAYC
4562  return (overflow || result > ~minv + 1) ? minv : ~result + 1;
4563  #else
4564  return (overflow || result > 0 - minv) ? minv : 0 - result;
4565  #endif
4566  }
4567  else
4568  return (overflow || result > maxv) ? maxv : result;
4569  }
4570 
4571  PUGI__FN int get_value_int(const char_t* value)
4572  {
4573  return string_to_integer<unsigned int>(value, static_cast<unsigned int>(INT_MIN), INT_MAX);
4574  }
4575 
4576  PUGI__FN unsigned int get_value_uint(const char_t* value)
4577  {
4578  return string_to_integer<unsigned int>(value, 0, UINT_MAX);
4579  }
4580 
4581  PUGI__FN double get_value_double(const char_t* value)
4582  {
4583  #ifdef PUGIXML_WCHAR_MODE
4584  return wcstod(value, 0);
4585  #else
4586  return strtod(value, 0);
4587  #endif
4588  }
4589 
4590  PUGI__FN float get_value_float(const char_t* value)
4591  {
4592  #ifdef PUGIXML_WCHAR_MODE
4593  return static_cast<float>(wcstod(value, 0));
4594  #else
4595  return static_cast<float>(strtod(value, 0));
4596  #endif
4597  }
4598 
4599  PUGI__FN bool get_value_bool(const char_t* value)
4600  {
4601  // only look at first char
4602  char_t first = *value;
4603 
4604  // 1*, t* (true), T* (True), y* (yes), Y* (YES)
4605  return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
4606  }
4607 
4608 #ifdef PUGIXML_HAS_LONG_LONG
4609  PUGI__FN long long get_value_llong(const char_t* value)
4610  {
4611  return string_to_integer<unsigned long long>(value, static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);
4612  }
4613 
4614  PUGI__FN unsigned long long get_value_ullong(const char_t* value)
4615  {
4616  return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);
4617  }
4618 #endif
4619 
4620  template <typename U> PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative)
4621  {
4622  char_t* result = end - 1;
4623  U rest = negative ? 0 - value : value;
4624 
4625  do
4626  {
4627  *result-- = static_cast<char_t>('0' + (rest % 10));
4628  rest /= 10;
4629  }
4630  while (rest);
4631 
4632  assert(result >= begin);
4633  (void)begin;
4634 
4635  *result = '-';
4636 
4637  return result + !negative;
4638  }
4639 
4640  // set value with conversion functions
4641  template <typename String, typename Header>
4642  PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf)
4643  {
4644  #ifdef PUGIXML_WCHAR_MODE
4645  char_t wbuf[128];
4646  assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0]));
4647 
4648  size_t offset = 0;
4649  for (; buf[offset]; ++offset) wbuf[offset] = buf[offset];
4650 
4651  return strcpy_insitu(dest, header, header_mask, wbuf, offset);
4652  #else
4653  return strcpy_insitu(dest, header, header_mask, buf, strlen(buf));
4654  #endif
4655  }
4656 
4657  template <typename U, typename String, typename Header>
4658  PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative)
4659  {
4660  char_t buf[64];
4661  char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
4662  char_t* begin = integer_to_string(buf, end, value, negative);
4663 
4664  return strcpy_insitu(dest, header, header_mask, begin, end - begin);
4665  }
4666 
4667  template <typename String, typename Header>
4668  PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value)
4669  {
4670  char buf[128];
4671  PUGI__SNPRINTF(buf, "%.9g", double(value));
4672 
4673  return set_value_ascii(dest, header, header_mask, buf);
4674  }
4675 
4676  template <typename String, typename Header>
4677  PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value)
4678  {
4679  char buf[128];
4680  PUGI__SNPRINTF(buf, "%.17g", value);
4681 
4682  return set_value_ascii(dest, header, header_mask, buf);
4683  }
4684 
4685  template <typename String, typename Header>
4686  PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value)
4687  {
4688  return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5);
4689  }
4690 
4691  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)
4692  {
4693  // check input buffer
4694  if (!contents && size) return make_parse_result(status_io_error);
4695 
4696  // get actual encoding
4697  xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
4698 
4699  // get private buffer
4700  char_t* buffer = 0;
4701  size_t length = 0;
4702 
4703  // coverity[var_deref_model]
4704  if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
4705 
4706  // delete original buffer if we performed a conversion
4707  if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
4708 
4709  // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
4710  if (own || buffer != contents) *out_buffer = buffer;
4711 
4712  // store buffer for offset_debug
4713  doc->buffer = buffer;
4714 
4715  // parse
4716  xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
4717 
4718  // remember encoding
4719  res.encoding = buffer_encoding;
4720 
4721  return res;
4722  }
4723 
4724  // 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 trick
4725  PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
4726  {
4727  #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
4728  // there are 64-bit versions of fseek/ftell, let's use them
4729  typedef __int64 length_type;
4730 
4731  _fseeki64(file, 0, SEEK_END);
4732  length_type length = _ftelli64(file);
4733  _fseeki64(file, 0, SEEK_SET);
4734  #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))
4735  // there are 64-bit versions of fseek/ftell, let's use them
4736  typedef off64_t length_type;
4737 
4738  fseeko64(file, 0, SEEK_END);
4739  length_type length = ftello64(file);
4740  fseeko64(file, 0, SEEK_SET);
4741  #else
4742  // 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 can't do anything anyway.
4743  typedef long length_type;
4744 
4745  fseek(file, 0, SEEK_END);
4746  length_type length = ftell(file);
4747  fseek(file, 0, SEEK_SET);
4748  #endif
4749 
4750  // check for I/O errors
4751  if (length < 0) return status_io_error;
4752 
4753  // check for overflow
4754  size_t result = static_cast<size_t>(length);
4755 
4756  if (static_cast<length_type>(result) != length) return status_out_of_memory;
4757 
4758  // finalize
4759  out_result = result;
4760 
4761  return status_ok;
4762  }
4763 
4764  // This function assumes that buffer has extra sizeof(char_t) writable bytes after size
4765  PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding)
4766  {
4767  // We only need to zero-terminate if encoding conversion does not do it for us
4768  #ifdef PUGIXML_WCHAR_MODE
4769  xml_encoding wchar_encoding = get_wchar_encoding();
4770 
4771  if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding))
4772  {
4773  size_t length = size / sizeof(char_t);
4774 
4775  static_cast<char_t*>(buffer)[length] = 0;
4776  return (length + 1) * sizeof(char_t);
4777  }
4778  #else
4779  if (encoding == encoding_utf8)
4780  {
4781  static_cast<char*>(buffer)[size] = 0;
4782  return size + 1;
4783  }
4784  #endif
4785 
4786  return size;
4787  }
4788 
4789  PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer)
4790  {
4791  if (!file) return make_parse_result(status_file_not_found);
4792 
4793  // get file size (can result in I/O errors)
4794  size_t size = 0;
4795  xml_parse_status size_status = get_file_size(file, size);
4796  if (size_status != status_ok) return make_parse_result(size_status);
4797 
4798  size_t max_suffix_size = sizeof(char_t);
4799 
4800  // allocate buffer for the whole file
4801  char* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size));
4802  if (!contents) return make_parse_result(status_out_of_memory);
4803 
4804  // read file in memory
4805  size_t read_size = fread(contents, 1, size, file);
4806 
4807  if (read_size != size)
4808  {
4809  xml_memory::deallocate(contents);
4811  }
4812 
4813  xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
4814 
4815  return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer);
4816  }
4817 
4818  PUGI__FN void close_file(FILE* file)
4819  {
4820  fclose(file);
4821  }
4822 
4823 #ifndef PUGIXML_NO_STL
4824  template <typename T> struct xml_stream_chunk
4825  {
4827  {
4828  void* memory = xml_memory::allocate(sizeof(xml_stream_chunk));
4829  if (!memory) return 0;
4830 
4831  return new (memory) xml_stream_chunk();
4832  }
4833 
4834  static void destroy(xml_stream_chunk* chunk)
4835  {
4836  // free chunk chain
4837  while (chunk)
4838  {
4839  xml_stream_chunk* next_ = chunk->next;
4840 
4841  xml_memory::deallocate(chunk);
4842 
4843  chunk = next_;
4844  }
4845  }
4846 
4848  {
4849  }
4850 
4852  size_t size;
4853 
4854  T data[xml_memory_page_size / sizeof(T)];
4855  };
4856 
4857  template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
4858  {
4860 
4861  // read file to a chunk list
4862  size_t total = 0;
4863  xml_stream_chunk<T>* last = 0;
4864 
4865  while (!stream.eof())
4866  {
4867  // allocate new chunk
4869  if (!chunk) return status_out_of_memory;
4870 
4871  // append chunk to list
4872  if (last) last = last->next = chunk;
4873  else chunks.data = last = chunk;
4874 
4875  // read data to chunk
4876  stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));
4877  chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);
4878 
4879  // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors
4880  if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
4881 
4882  // guard against huge files (chunk size is small enough to make this overflow check work)
4883  if (total + chunk->size < total) return status_out_of_memory;
4884  total += chunk->size;
4885  }
4886 
4887  size_t max_suffix_size = sizeof(char_t);
4888 
4889  // copy chunk list to a contiguous buffer
4890  char* buffer = static_cast<char*>(xml_memory::allocate(total + max_suffix_size));
4891  if (!buffer) return status_out_of_memory;
4892 
4893  char* write = buffer;
4894 
4895  for (xml_stream_chunk<T>* chunk = chunks.data; chunk; chunk = chunk->next)
4896  {
4897  assert(write + chunk->size <= buffer + total);
4898  memcpy(write, chunk->data, chunk->size);
4899  write += chunk->size;
4900  }
4901 
4902  assert(write == buffer + total);
4903 
4904  // return buffer
4905  *out_buffer = buffer;
4906  *out_size = total;
4907 
4908  return status_ok;
4909  }
4910 
4911  template <typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
4912  {
4913  // get length of remaining data in stream
4914  typename std::basic_istream<T>::pos_type pos = stream.tellg();
4915  stream.seekg(0, std::ios::end);
4916  std::streamoff length = stream.tellg() - pos;
4917  stream.seekg(pos);
4918 
4919  if (stream.fail() || pos < 0) return status_io_error;
4920 
4921  // guard against huge files
4922  size_t read_length = static_cast<size_t>(length);
4923 
4924  if (static_cast<std::streamsize>(read_length) != length || length < 0) return status_out_of_memory;
4925 
4926  size_t max_suffix_size = sizeof(char_t);
4927 
4928  // read stream data into memory (guard against stream exceptions with buffer holder)
4929  auto_deleter<void> buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);
4930  if (!buffer.data) return status_out_of_memory;
4931 
4932  stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
4933 
4934  // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors
4935  if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
4936 
4937  // return buffer
4938  size_t actual_length = static_cast<size_t>(stream.gcount());
4939  assert(actual_length <= read_length);
4940 
4941  *out_buffer = buffer.release();
4942  *out_size = actual_length * sizeof(T);
4943 
4944  return status_ok;
4945  }
4946 
4947  template <typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer)
4948  {
4949  void* buffer = 0;
4950  size_t size = 0;
4951  xml_parse_status status = status_ok;
4952 
4953  // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits)
4954  if (stream.fail()) return make_parse_result(status_io_error);
4955 
4956  // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)
4957  if (stream.tellg() < 0)
4958  {
4959  stream.clear(); // clear error flags that could be set by a failing tellg
4960  status = load_stream_data_noseek(stream, &buffer, &size);
4961  }
4962  else
4963  status = load_stream_data_seek(stream, &buffer, &size);
4964 
4965  if (status != status_ok) return make_parse_result(status);
4966 
4967  xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
4968 
4969  return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer);
4970  }
4971 #endif
4972 
4973 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))
4974  PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
4975  {
4976  return _wfopen(path, mode);
4977  }
4978 #else
4979  PUGI__FN char* convert_path_heap(const wchar_t* str)
4980  {
4981  assert(str);
4982 
4983  // first pass: get length in utf8 characters
4984  size_t length = strlength_wide(str);
4985  size_t size = as_utf8_begin(str, length);
4986 
4987  // allocate resulting string
4988  char* result = static_cast<char*>(xml_memory::allocate(size + 1));
4989  if (!result) return 0;
4990 
4991  // second pass: convert to utf8
4992  as_utf8_end(result, size, str, length);
4993 
4994  // zero-terminate
4995  result[size] = 0;
4996 
4997  return result;
4998  }
4999 
5000  PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
5001  {
5002  // there is no standard function to open wide paths, so our best bet is to try utf8 path
5003  char* path_utf8 = convert_path_heap(path);
5004  if (!path_utf8) return 0;
5005 
5006  // convert mode to ASCII (we mirror _wfopen interface)
5007  char mode_ascii[4] = {0};
5008  for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);
5009 
5010  // try to open the utf8 path
5011  FILE* result = fopen(path_utf8, mode_ascii);
5012 
5013  // free dummy buffer
5014  xml_memory::deallocate(path_utf8);
5015 
5016  return result;
5017  }
5018 #endif
5019 
5020  PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)
5021  {
5022  if (!file) return false;
5023 
5024  xml_writer_file writer(file);
5025  doc.save(writer, indent, flags, encoding);
5026 
5027  return ferror(file) == 0;
5028  }
5029 
5031  {
5032  xml_node_struct* node;
5034 
5035  name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name)
5036  {
5037  node->name = 0;
5038  }
5039 
5041  {
5042  node->name = name;
5043  }
5044  };
5046 
5047 namespace pugi
5048 {
5049  PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_)
5050  {
5051  }
5052 
5053  PUGI__FN void xml_writer_file::write(const void* data, size_t size)
5054  {
5055  size_t result = fwrite(data, 1, size, static_cast<FILE*>(file));
5056  (void)!result; // unfortunately we can't do proper error handling here
5057  }
5058 
5059 #ifndef PUGIXML_NO_STL
5060  PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
5061  {
5062  }
5063 
5064  PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
5065  {
5066  }
5067 
5068  PUGI__FN void xml_writer_stream::write(const void* data, size_t size)
5069  {
5070  if (narrow_stream)
5071  {
5072  assert(!wide_stream);
5073  narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
5074  }
5075  else
5076  {
5077  assert(wide_stream);
5078  assert(size % sizeof(wchar_t) == 0);
5079 
5080  wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size / sizeof(wchar_t)));
5081  }
5082  }
5083 #endif
5084 
5086  {
5087  }
5088 
5090  {
5091  }
5092 
5094  {
5095  return _depth;
5096  }
5097 
5099  {
5100  return true;
5101  }
5102 
5104  {
5105  return true;
5106  }
5107 
5109  {
5110  }
5111 
5113  {
5114  }
5115 
5117  {
5118  }
5119 
5120  PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
5121  {
5123  }
5124 
5126  {
5127  return !_attr;
5128  }
5129 
5131  {
5132  return (_attr == r._attr);
5133  }
5134 
5136  {
5137  return (_attr != r._attr);
5138  }
5139 
5141  {
5142  return (_attr < r._attr);
5143  }
5144 
5146  {
5147  return (_attr > r._attr);
5148  }
5149 
5151  {
5152  return (_attr <= r._attr);
5153  }
5154 
5156  {
5157  return (_attr >= r._attr);
5158  }
5159 
5161  {
5163  }
5164 
5166  {
5168  }
5169 
5171  {
5172  return (_attr && _attr->value) ? _attr->value + 0 : def;
5173  }
5174 
5175  PUGI__FN int xml_attribute::as_int(int def) const
5176  {
5177  return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def;
5178  }
5179 
5180  PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
5181  {
5182  return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def;
5183  }
5184 
5185  PUGI__FN double xml_attribute::as_double(double def) const
5186  {
5187  return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def;
5188  }
5189 
5190  PUGI__FN float xml_attribute::as_float(float def) const
5191  {
5192  return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def;
5193  }
5194 
5195  PUGI__FN bool xml_attribute::as_bool(bool def) const
5196  {
5197  return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def;
5198  }
5199 
5200 #ifdef PUGIXML_HAS_LONG_LONG
5201  PUGI__FN long long xml_attribute::as_llong(long long def) const
5202  {
5203  return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def;
5204  }
5205 
5206  PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
5207  {
5208  return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def;
5209  }
5210 #endif
5211 
5213  {
5214  return !_attr;
5215  }
5216 
5218  {
5219  return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT("");
5220  }
5221 
5223  {
5224  return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT("");
5225  }
5226 
5228  {
5229  return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
5230  }
5231 
5233  {
5234  return _attr;
5235  }
5236 
5238  {
5239  set_value(rhs);
5240  return *this;
5241  }
5242 
5244  {
5245  set_value(rhs);
5246  return *this;
5247  }
5248 
5250  {
5251  set_value(rhs);
5252  return *this;
5253  }
5254 
5256  {
5257  set_value(rhs);
5258  return *this;
5259  }
5260 
5262  {
5263  set_value(rhs);
5264  return *this;
5265  }
5266 
5268  {
5269  set_value(rhs);
5270  return *this;
5271  }
5272 
5274  {
5275  set_value(rhs);
5276  return *this;
5277  }
5278 
5280  {
5281  set_value(rhs);
5282  return *this;
5283  }
5284 
5285 #ifdef PUGIXML_HAS_LONG_LONG
5287  {
5288  set_value(rhs);
5289  return *this;
5290  }
5291 
5292  PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs)
5293  {
5294  set_value(rhs);
5295  return *this;
5296  }
5297 #endif
5298 
5300  {
5301  if (!_attr) return false;
5302 
5304  }
5305 
5307  {
5308  if (!_attr) return false;
5309 
5311  }
5312 
5314  {
5315  if (!_attr) return false;
5316 
5317  return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5318  }
5319 
5320  PUGI__FN bool xml_attribute::set_value(unsigned int rhs)
5321  {
5322  if (!_attr) return false;
5323 
5324  return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
5325  }
5326 
5328  {
5329  if (!_attr) return false;
5330 
5331  return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5332  }
5333 
5334  PUGI__FN bool xml_attribute::set_value(unsigned long rhs)
5335  {
5336  if (!_attr) return false;
5337 
5338  return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
5339  }
5340 
5342  {
5343  if (!_attr) return false;
5344 
5346  }
5347 
5349  {
5350  if (!_attr) return false;
5351 
5353  }
5354 
5356  {
5357  if (!_attr) return false;
5358 
5360  }
5361 
5362 #ifdef PUGIXML_HAS_LONG_LONG
5363  PUGI__FN bool xml_attribute::set_value(long long rhs)
5364  {
5365  if (!_attr) return false;
5366 
5367  return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5368  }
5369 
5370  PUGI__FN bool xml_attribute::set_value(unsigned long long rhs)
5371  {
5372  if (!_attr) return false;
5373 
5374  return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
5375  }
5376 #endif
5377 
5378 #ifdef __BORLANDC__
5379  PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs)
5380  {
5381  return (bool)lhs && rhs;
5382  }
5383 
5384  PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs)
5385  {
5386  return (bool)lhs || rhs;
5387  }
5388 #endif
5389 
5391  {
5392  }
5393 
5395  {
5396  }
5397 
5399  {
5400  }
5401 
5402  PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const
5403  {
5404  return _root ? unspecified_bool_xml_node : 0;
5405  }
5406 
5408  {
5409  return !_root;
5410  }
5411 
5413  {
5414  return iterator(_root ? _root->first_child + 0 : 0, _root);
5415  }
5416 
5418  {
5419  return iterator(0, _root);
5420  }
5421 
5423  {
5424  return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root);
5425  }
5426 
5428  {
5429  return attribute_iterator(0, _root);
5430  }
5431 
5433  {
5435  }
5436 
5438  {
5440  }
5441 
5443  {
5445  }
5446 
5448  {
5449  return (_root == r._root);
5450  }
5451 
5453  {
5454  return (_root != r._root);
5455  }
5456 
5458  {
5459  return (_root < r._root);
5460  }
5461 
5463  {
5464  return (_root > r._root);
5465  }
5466 
5468  {
5469  return (_root <= r._root);
5470  }
5471 
5473  {
5474  return (_root >= r._root);
5475  }
5476 
5478  {
5479  return !_root;
5480  }
5481 
5483  {
5484  return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT("");
5485  }
5486 
5488  {
5489  return _root ? PUGI__NODETYPE(_root) : node_null;
5490  }
5491 
5493  {
5494  return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT("");
5495  }
5496 
5498  {
5499  if (!_root) return xml_node();
5500 
5501  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5502  if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
5503 
5504  return xml_node();
5505  }
5506 
5508  {
5509  if (!_root) return xml_attribute();
5510 
5512  if (i->name && impl::strequal(name_, i->name))
5513  return xml_attribute(i);
5514 
5515  return xml_attribute();
5516  }
5517 
5519  {
5520  if (!_root) return xml_node();
5521 
5522  for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
5523  if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
5524 
5525  return xml_node();
5526  }
5527 
5529  {
5530  return _root ? xml_node(_root->next_sibling) : xml_node();
5531  }
5532 
5534  {
5535  if (!_root) return xml_node();
5536 
5538  if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
5539 
5540  return xml_node();
5541  }
5542 
5544  {
5545  xml_attribute_struct* hint = hint_._attr;
5546 
5547  // if hint is not an attribute of node, behavior is not defined
5548  assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
5549 
5550  if (!_root) return xml_attribute();
5551 
5552  // optimistically search from hint up until the end
5553  for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
5554  if (i->name && impl::strequal(name_, i->name))
5555  {
5556  // update hint to maximize efficiency of searching for consecutive attributes
5557  hint_._attr = i->next_attribute;
5558 
5559  return xml_attribute(i);
5560  }
5561 
5562  // wrap around and search from the first attribute until the hint
5563  // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails
5564  for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)
5565  if (j->name && impl::strequal(name_, j->name))
5566  {
5567  // update hint to maximize efficiency of searching for consecutive attributes
5568  hint_._attr = j->next_attribute;
5569 
5570  return xml_attribute(j);
5571  }
5572 
5573  return xml_attribute();
5574  }
5575 
5577  {
5578  if (!_root) return xml_node();
5579 
5581  else return xml_node();
5582  }
5583 
5585  {
5586  return _root ? xml_node(_root->parent) : xml_node();
5587  }
5588 
5590  {
5592  }
5593 
5595  {
5596  return xml_text(_root);
5597  }
5598 
5600  {
5601  if (!_root) return PUGIXML_TEXT("");
5602 
5603  // element nodes can have value if parse_embed_pcdata was used
5605  return _root->value;
5606 
5607  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5608  if (impl::is_text_node(i) && i->value)
5609  return i->value;
5610 
5611  return PUGIXML_TEXT("");
5612  }
5613 
5614  PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const
5615  {
5616  return child(name_).child_value();
5617  }
5618 
5620  {
5622  }
5623 
5625  {
5627  }
5628 
5630  {
5631  return _root ? xml_node(_root->first_child) : xml_node();
5632  }
5633 
5635  {
5637  }
5638 
5640  {
5642 
5643  if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
5644  return false;
5645 
5647  }
5648 
5650  {
5652 
5653  if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
5654  return false;
5655 
5657  }
5658 
5660  {
5662 
5663  impl::xml_allocator& alloc = impl::get_allocator(_root);
5664  if (!alloc.reserve()) return xml_attribute();
5665 
5667  if (!a) return xml_attribute();
5668 
5670 
5671  a.set_name(name_);
5672 
5673  return a;
5674  }
5675 
5677  {
5679 
5680  impl::xml_allocator& alloc = impl::get_allocator(_root);
5681  if (!alloc.reserve()) return xml_attribute();
5682 
5684  if (!a) return xml_attribute();
5685 
5687 
5688  a.set_name(name_);
5689 
5690  return a;
5691  }
5692 
5694  {
5696  if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
5697 
5698  impl::xml_allocator& alloc = impl::get_allocator(_root);
5699  if (!alloc.reserve()) return xml_attribute();
5700 
5702  if (!a) return xml_attribute();
5703 
5705 
5706  a.set_name(name_);
5707 
5708  return a;
5709  }
5710 
5712  {
5714  if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
5715 
5716  impl::xml_allocator& alloc = impl::get_allocator(_root);
5717  if (!alloc.reserve()) return xml_attribute();
5718 
5720  if (!a) return xml_attribute();
5721 
5723 
5724  a.set_name(name_);
5725 
5726  return a;
5727  }
5728 
5730  {
5731  if (!proto) return xml_attribute();
5733 
5734  impl::xml_allocator& alloc = impl::get_allocator(_root);
5735  if (!alloc.reserve()) return xml_attribute();
5736 
5738  if (!a) return xml_attribute();
5739 
5742 
5743  return a;
5744  }
5745 
5747  {
5748  if (!proto) return xml_attribute();
5750 
5751  impl::xml_allocator& alloc = impl::get_allocator(_root);
5752  if (!alloc.reserve()) return xml_attribute();
5753 
5755  if (!a) return xml_attribute();
5756 
5759 
5760  return a;
5761  }
5762 
5764  {
5765  if (!proto) return xml_attribute();
5767  if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
5768 
5769  impl::xml_allocator& alloc = impl::get_allocator(_root);
5770  if (!alloc.reserve()) return xml_attribute();
5771 
5773  if (!a) return xml_attribute();
5774 
5777 
5778  return a;
5779  }
5780 
5782  {
5783  if (!proto) return xml_attribute();
5785  if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
5786 
5787  impl::xml_allocator& alloc = impl::get_allocator(_root);
5788  if (!alloc.reserve()) return xml_attribute();
5789 
5791  if (!a) return xml_attribute();
5792 
5795 
5796  return a;
5797  }
5798 
5800  {
5801  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5802 
5803  impl::xml_allocator& alloc = impl::get_allocator(_root);
5804  if (!alloc.reserve()) return xml_node();
5805 
5806  xml_node n(impl::allocate_node(alloc, type_));
5807  if (!n) return xml_node();
5808 
5810 
5811  if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
5812 
5813  return n;
5814  }
5815 
5817  {
5818  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5819 
5820  impl::xml_allocator& alloc = impl::get_allocator(_root);
5821  if (!alloc.reserve()) return xml_node();
5822 
5823  xml_node n(impl::allocate_node(alloc, type_));
5824  if (!n) return xml_node();
5825 
5827 
5828  if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
5829 
5830  return n;
5831  }
5832 
5834  {
5835  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5836  if (!node._root || node._root->parent != _root) return xml_node();
5837 
5838  impl::xml_allocator& alloc = impl::get_allocator(_root);
5839  if (!alloc.reserve()) return xml_node();
5840 
5841  xml_node n(impl::allocate_node(alloc, type_));
5842  if (!n) return xml_node();
5843 
5845 
5846  if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
5847 
5848  return n;
5849  }
5850 
5852  {
5853  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5854  if (!node._root || node._root->parent != _root) return xml_node();
5855 
5856  impl::xml_allocator& alloc = impl::get_allocator(_root);
5857  if (!alloc.reserve()) return xml_node();
5858 
5859  xml_node n(impl::allocate_node(alloc, type_));
5860  if (!n) return xml_node();
5861 
5863 
5864  if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
5865 
5866  return n;
5867  }
5868 
5870  {
5872 
5873  result.set_name(name_);
5874 
5875  return result;
5876  }
5877 
5879  {
5881 
5882  result.set_name(name_);
5883 
5884  return result;
5885  }
5886 
5888  {
5889  xml_node result = insert_child_after(node_element, node);
5890 
5891  result.set_name(name_);
5892 
5893  return result;
5894  }
5895 
5897  {
5898  xml_node result = insert_child_before(node_element, node);
5899 
5900  result.set_name(name_);
5901 
5902  return result;
5903  }
5904 
5906  {
5907  xml_node_type type_ = proto.type();
5908  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5909 
5910  impl::xml_allocator& alloc = impl::get_allocator(_root);
5911  if (!alloc.reserve()) return xml_node();
5912 
5913  xml_node n(impl::allocate_node(alloc, type_));
5914  if (!n) return xml_node();
5915 
5917  impl::node_copy_tree(n._root, proto._root);
5918 
5919  return n;
5920  }
5921 
5923  {
5924  xml_node_type type_ = proto.type();
5925  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5926 
5927  impl::xml_allocator& alloc = impl::get_allocator(_root);
5928  if (!alloc.reserve()) return xml_node();
5929 
5930  xml_node n(impl::allocate_node(alloc, type_));
5931  if (!n) return xml_node();
5932 
5934  impl::node_copy_tree(n._root, proto._root);
5935 
5936  return n;
5937  }
5938 
5940  {
5941  xml_node_type type_ = proto.type();
5942  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5943  if (!node._root || node._root->parent != _root) return xml_node();
5944 
5945  impl::xml_allocator& alloc = impl::get_allocator(_root);
5946  if (!alloc.reserve()) return xml_node();
5947 
5948  xml_node n(impl::allocate_node(alloc, type_));
5949  if (!n) return xml_node();
5950 
5952  impl::node_copy_tree(n._root, proto._root);
5953 
5954  return n;
5955  }
5956 
5958  {
5959  xml_node_type type_ = proto.type();
5960  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5961  if (!node._root || node._root->parent != _root) return xml_node();
5962 
5963  impl::xml_allocator& alloc = impl::get_allocator(_root);
5964  if (!alloc.reserve()) return xml_node();
5965 
5966  xml_node n(impl::allocate_node(alloc, type_));
5967  if (!n) return xml_node();
5968 
5970  impl::node_copy_tree(n._root, proto._root);
5971 
5972  return n;
5973  }
5974 
5976  {
5977  if (!impl::allow_move(*this, moved)) return xml_node();
5978 
5979  impl::xml_allocator& alloc = impl::get_allocator(_root);
5980  if (!alloc.reserve()) return xml_node();
5981 
5982  // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
5984 
5985  impl::remove_node(moved._root);
5986  impl::append_node(moved._root, _root);
5987 
5988  return moved;
5989  }
5990 
5992  {
5993  if (!impl::allow_move(*this, moved)) return xml_node();
5994 
5995  impl::xml_allocator& alloc = impl::get_allocator(_root);
5996  if (!alloc.reserve()) return xml_node();
5997 
5998  // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
6000 
6001  impl::remove_node(moved._root);
6002  impl::prepend_node(moved._root, _root);
6003 
6004  return moved;
6005  }
6006 
6008  {
6009  if (!impl::allow_move(*this, moved)) return xml_node();
6010  if (!node._root || node._root->parent != _root) return xml_node();
6011  if (moved._root == node._root) return xml_node();
6012 
6013  impl::xml_allocator& alloc = impl::get_allocator(_root);
6014  if (!alloc.reserve()) return xml_node();
6015 
6016  // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
6018 
6019  impl::remove_node(moved._root);
6020  impl::insert_node_after(moved._root, node._root);
6021 
6022  return moved;
6023  }
6024 
6026  {
6027  if (!impl::allow_move(*this, moved)) return xml_node();
6028  if (!node._root || node._root->parent != _root) return xml_node();
6029  if (moved._root == node._root) return xml_node();
6030 
6031  impl::xml_allocator& alloc = impl::get_allocator(_root);
6032  if (!alloc.reserve()) return xml_node();
6033 
6034  // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
6036 
6037  impl::remove_node(moved._root);
6038  impl::insert_node_before(moved._root, node._root);
6039 
6040  return moved;
6041  }
6042 
6044  {
6045  return remove_attribute(attribute(name_));
6046  }
6047 
6049  {
6050  if (!_root || !a._attr) return false;
6051  if (!impl::is_attribute_of(a._attr, _root)) return false;
6052 
6053  impl::xml_allocator& alloc = impl::get_allocator(_root);
6054  if (!alloc.reserve()) return false;
6055 
6057  impl::destroy_attribute(a._attr, alloc);
6058 
6059  return true;
6060  }
6061 
6063  {
6064  return remove_child(child(name_));
6065  }
6066 
6068  {
6069  if (!_root || !n._root || n._root->parent != _root) return false;
6070 
6071  impl::xml_allocator& alloc = impl::get_allocator(_root);
6072  if (!alloc.reserve()) return false;
6073 
6075  impl::destroy_node(n._root, alloc);
6076 
6077  return true;
6078  }
6079 
6080  PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
6081  {
6082  // append_buffer is only valid for elements/documents
6084 
6085  // get document node
6086  impl::xml_document_struct* doc = &impl::get_document(_root);
6087 
6088  // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense
6090 
6091  // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later)
6092  impl::xml_memory_page* page = 0;
6093  impl::xml_extra_buffer* extra = static_cast<impl::xml_extra_buffer*>(doc->allocate_memory(sizeof(impl::xml_extra_buffer) + sizeof(void*), page));
6094  (void)page;
6095 
6096  if (!extra) return impl::make_parse_result(status_out_of_memory);
6097 
6098  #ifdef PUGIXML_COMPACT
6099  // align the memory block to a pointer boundary; this is required for compact mode where memory allocations are only 4b aligned
6100  // note that this requires up to sizeof(void*)-1 additional memory, which the allocation above takes into account
6101  extra = reinterpret_cast<impl::xml_extra_buffer*>((reinterpret_cast<uintptr_t>(extra) + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1));
6102  #endif
6103 
6104  // add extra buffer to the list
6105  extra->buffer = 0;
6106  extra->next = doc->extra_buffers;
6107  doc->extra_buffers = extra;
6108 
6109  // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level
6110  impl::name_null_sentry sentry(_root);
6111 
6112  return impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &extra->buffer);
6113  }
6114 
6115  PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const
6116  {
6117  if (!_root) return xml_node();
6118 
6119  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
6120  if (i->name && impl::strequal(name_, i->name))
6121  {
6122  for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
6123  if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
6124  return xml_node(i);
6125  }
6126 
6127  return xml_node();
6128  }
6129 
6130  PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
6131  {
6132  if (!_root) return xml_node();
6133 
6134  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
6135  for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
6136  if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
6137  return xml_node(i);
6138 
6139  return xml_node();
6140  }
6141 
6142 #ifndef PUGIXML_NO_STL
6144  {
6145  if (!_root) return string_t();
6146 
6147  size_t offset = 0;
6148 
6149  for (xml_node_struct* i = _root; i; i = i->parent)
6150  {
6151  offset += (i != _root);
6152  offset += i->name ? impl::strlength(i->name) : 0;
6153  }
6154 
6155  string_t result;
6156  result.resize(offset);
6157 
6158  for (xml_node_struct* j = _root; j; j = j->parent)
6159  {
6160  if (j != _root)
6161  result[--offset] = delimiter;
6162 
6163  if (j->name)
6164  {
6165  size_t length = impl::strlength(j->name);
6166 
6167  offset -= length;
6168  memcpy(&result[offset], j->name, length * sizeof(char_t));
6169  }
6170  }
6171 
6172  assert(offset == 0);
6173 
6174  return result;
6175  }
6176 #endif
6177 
6179  {
6180  xml_node found = *this; // Current search context.
6181 
6182  if (!_root || !path_[0]) return found;
6183 
6184  if (path_[0] == delimiter)
6185  {
6186  // Absolute path; e.g. '/foo/bar'
6187  found = found.root();
6188  ++path_;
6189  }
6190 
6191  const char_t* path_segment = path_;
6192 
6193  while (*path_segment == delimiter) ++path_segment;
6194 
6195  const char_t* path_segment_end = path_segment;
6196 
6197  while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;
6198 
6199  if (path_segment == path_segment_end) return found;
6200 
6201  const char_t* next_segment = path_segment_end;
6202 
6203  while (*next_segment == delimiter) ++next_segment;
6204 
6205  if (*path_segment == '.' && path_segment + 1 == path_segment_end)
6206  return found.first_element_by_path(next_segment, delimiter);
6207  else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end)
6208  return found.parent().first_element_by_path(next_segment, delimiter);
6209  else
6210  {
6211  for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling)
6212  {
6213  if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
6214  {
6215  xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
6216 
6217  if (subsearch) return subsearch;
6218  }
6219  }
6220 
6221  return xml_node();
6222  }
6223  }
6224 
6226  {
6227  walker._depth = -1;
6228 
6229  xml_node arg_begin(_root);
6230  if (!walker.begin(arg_begin)) return false;
6231 
6232  xml_node_struct* cur = _root ? _root->first_child + 0 : 0;
6233 
6234  if (cur)
6235  {
6236  ++walker._depth;
6237 
6238  do
6239  {
6240  xml_node arg_for_each(cur);
6241  if (!walker.for_each(arg_for_each))
6242  return false;
6243 
6244  if (cur->first_child)
6245  {
6246  ++walker._depth;
6247  cur = cur->first_child;
6248  }
6249  else if (cur->next_sibling)
6250  cur = cur->next_sibling;
6251  else
6252  {
6253  while (!cur->next_sibling && cur != _root && cur->parent)
6254  {
6255  --walker._depth;
6256  cur = cur->parent;
6257  }
6258 
6259  if (cur != _root)
6260  cur = cur->next_sibling;
6261  }
6262  }
6263  while (cur && cur != _root);
6264  }
6265 
6266  assert(walker._depth == -1);
6267 
6268  xml_node arg_end(_root);
6269  return walker.end(arg_end);
6270  }
6271 
6273  {
6274  return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
6275  }
6276 
6278  {
6279  return _root;
6280  }
6281 
6282  PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
6283  {
6284  if (!_root) return;
6285 
6286  impl::xml_buffered_writer buffered_writer(writer, encoding);
6287 
6288  impl::node_output(buffered_writer, _root, indent, flags, depth);
6289 
6290  buffered_writer.flush();
6291  }
6292 
6293 #ifndef PUGIXML_NO_STL
6294  PUGI__FN void xml_node::print(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
6295  {
6296  xml_writer_stream writer(stream);
6297 
6298  print(writer, indent, flags, encoding, depth);
6299  }
6300 
6301  PUGI__FN void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const
6302  {
6303  xml_writer_stream writer(stream);
6304 
6305  print(writer, indent, flags, encoding_wchar, depth);
6306  }
6307 #endif
6308 
6310  {
6311  if (!_root) return -1;
6312 
6313  impl::xml_document_struct& doc = impl::get_document(_root);
6314 
6315  // we can determine the offset reliably only if there is exactly once parse buffer
6316  if (!doc.buffer || doc.extra_buffers) return -1;
6317 
6318  switch (type())
6319  {
6320  case node_document:
6321  return 0;
6322 
6323  case node_element:
6324  case node_declaration:
6325  case node_pi:
6326  return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1;
6327 
6328  case node_pcdata:
6329  case node_cdata:
6330  case node_comment:
6331  case node_doctype:
6332  return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1;
6333 
6334  default:
6335  assert(false && "Invalid node type"); // unreachable
6336  return -1;
6337  }
6338  }
6339 
6340 #ifdef __BORLANDC__
6341  PUGI__FN bool operator&&(const xml_node& lhs, bool rhs)
6342  {
6343  return (bool)lhs && rhs;
6344  }
6345 
6346  PUGI__FN bool operator||(const xml_node& lhs, bool rhs)
6347  {
6348  return (bool)lhs || rhs;
6349  }
6350 #endif
6351 
6353  {
6354  }
6355 
6357  {
6358  if (!_root || impl::is_text_node(_root)) return _root;
6359 
6360  // element nodes can have value if parse_embed_pcdata was used
6362  return _root;
6363 
6364  for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
6365  if (impl::is_text_node(node))
6366  return node;
6367 
6368  return 0;
6369  }
6370 
6372  {
6373  xml_node_struct* d = _data();
6374  if (d) return d;
6375 
6376  return xml_node(_root).append_child(node_pcdata).internal_object();
6377  }
6378 
6380  {
6381  }
6382 
6384  {
6385  }
6386 
6387  PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const
6388  {
6389  return _data() ? unspecified_bool_xml_text : 0;
6390  }
6391 
6393  {
6394  return !_data();
6395  }
6396 
6398  {
6399  return _data() == 0;
6400  }
6401 
6403  {
6404  xml_node_struct* d = _data();
6405 
6406  return (d && d->value) ? d->value + 0 : PUGIXML_TEXT("");
6407  }
6408 
6409  PUGI__FN const char_t* xml_text::as_string(const char_t* def) const
6410  {
6411  xml_node_struct* d = _data();
6412 
6413  return (d && d->value) ? d->value + 0 : def;
6414  }
6415 
6416  PUGI__FN int xml_text::as_int(int def) const
6417  {
6418  xml_node_struct* d = _data();
6419 
6420  return (d && d->value) ? impl::get_value_int(d->value) : def;
6421  }
6422 
6423  PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
6424  {
6425  xml_node_struct* d = _data();
6426 
6427  return (d && d->value) ? impl::get_value_uint(d->value) : def;
6428  }
6429 
6430  PUGI__FN double xml_text::as_double(double def) const
6431  {
6432  xml_node_struct* d = _data();
6433 
6434  return (d && d->value) ? impl::get_value_double(d->value) : def;
6435  }
6436 
6437  PUGI__FN float xml_text::as_float(float def) const
6438  {
6439  xml_node_struct* d = _data();
6440 
6441  return (d && d->value) ? impl::get_value_float(d->value) : def;
6442  }
6443 
6444  PUGI__FN bool xml_text::as_bool(bool def) const
6445  {
6446  xml_node_struct* d = _data();
6447 
6448  return (d && d->value) ? impl::get_value_bool(d->value) : def;
6449  }
6450 
6451 #ifdef PUGIXML_HAS_LONG_LONG
6452  PUGI__FN long long xml_text::as_llong(long long def) const
6453  {
6454  xml_node_struct* d = _data();
6455 
6456  return (d && d->value) ? impl::get_value_llong(d->value) : def;
6457  }
6458 
6459  PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const
6460  {
6461  xml_node_struct* d = _data();
6462 
6463  return (d && d->value) ? impl::get_value_ullong(d->value) : def;
6464  }
6465 #endif
6466 
6467  PUGI__FN bool xml_text::set(const char_t* rhs)
6468  {
6469  xml_node_struct* dn = _data_new();
6470 
6471  return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false;
6472  }
6473 
6474  PUGI__FN bool xml_text::set(int rhs)
6475  {
6476  xml_node_struct* dn = _data_new();
6477 
6478  return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6479  }
6480 
6481  PUGI__FN bool xml_text::set(unsigned int rhs)
6482  {
6483  xml_node_struct* dn = _data_new();
6484 
6485  return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
6486  }
6487 
6488  PUGI__FN bool xml_text::set(long rhs)
6489  {
6490  xml_node_struct* dn = _data_new();
6491 
6492  return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6493  }
6494 
6495  PUGI__FN bool xml_text::set(unsigned long rhs)
6496  {
6497  xml_node_struct* dn = _data_new();
6498 
6499  return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
6500  }
6501 
6502  PUGI__FN bool xml_text::set(float rhs)
6503  {
6504  xml_node_struct* dn = _data_new();
6505 
6506  return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
6507  }
6508 
6509  PUGI__FN bool xml_text::set(double rhs)
6510  {
6511  xml_node_struct* dn = _data_new();
6512 
6513  return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
6514  }
6515 
6516  PUGI__FN bool xml_text::set(bool rhs)
6517  {
6518  xml_node_struct* dn = _data_new();
6519 
6520  return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
6521  }
6522 
6523 #ifdef PUGIXML_HAS_LONG_LONG
6524  PUGI__FN bool xml_text::set(long long rhs)
6525  {
6526  xml_node_struct* dn = _data_new();
6527 
6528  return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6529  }
6530 
6531  PUGI__FN bool xml_text::set(unsigned long long rhs)
6532  {
6533  xml_node_struct* dn = _data_new();
6534 
6535  return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
6536  }
6537 #endif
6538 
6540  {
6541  set(rhs);
6542  return *this;
6543  }
6544 
6546  {
6547  set(rhs);
6548  return *this;
6549  }
6550 
6552  {
6553  set(rhs);
6554  return *this;
6555  }
6556 
6558  {
6559  set(rhs);
6560  return *this;
6561  }
6562 
6564  {
6565  set(rhs);
6566  return *this;
6567  }
6568 
6570  {
6571  set(rhs);
6572  return *this;
6573  }
6574 
6576  {
6577  set(rhs);
6578  return *this;
6579  }
6580 
6582  {
6583  set(rhs);
6584  return *this;
6585  }
6586 
6587 #ifdef PUGIXML_HAS_LONG_LONG
6588  PUGI__FN xml_text& xml_text::operator=(long long rhs)
6589  {
6590  set(rhs);
6591  return *this;
6592  }
6593 
6594  PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs)
6595  {
6596  set(rhs);
6597  return *this;
6598  }
6599 #endif
6600 
6602  {
6603  return xml_node(_data());
6604  }
6605 
6606 #ifdef __BORLANDC__
6607  PUGI__FN bool operator&&(const xml_text& lhs, bool rhs)
6608  {
6609  return (bool)lhs && rhs;
6610  }
6611 
6612  PUGI__FN bool operator||(const xml_text& lhs, bool rhs)
6613  {
6614  return (bool)lhs || rhs;
6615  }
6616 #endif
6617 
6619  {
6620  }
6621 
6622  PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
6623  {
6624  }
6625 
6627  {
6628  }
6629 
6631  {
6632  return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
6633  }
6634 
6636  {
6637  return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
6638  }
6639 
6641  {
6642  assert(_wrap._root);
6643  return _wrap;
6644  }
6645 
6647  {
6648  assert(_wrap._root);
6649  return const_cast<xml_node*>(&_wrap); // BCC5 workaround
6650  }
6651 
6653  {
6654  assert(_wrap._root);
6656  return *this;
6657  }
6658 
6660  {
6661  xml_node_iterator temp = *this;
6662  ++*this;
6663  return temp;
6664  }
6665 
6667  {
6669  return *this;
6670  }
6671 
6673  {
6674  xml_node_iterator temp = *this;
6675  --*this;
6676  return temp;
6677  }
6678 
6680  {
6681  }
6682 
6683  PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
6684  {
6685  }
6686 
6688  {
6689  }
6690 
6692  {
6693  return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
6694  }
6695 
6697  {
6698  return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
6699  }
6700 
6702  {
6703  assert(_wrap._attr);
6704  return _wrap;
6705  }
6706 
6708  {
6709  assert(_wrap._attr);
6710  return const_cast<xml_attribute*>(&_wrap); // BCC5 workaround
6711  }
6712 
6714  {
6715  assert(_wrap._attr);
6717  return *this;
6718  }
6719 
6721  {
6722  xml_attribute_iterator temp = *this;
6723  ++*this;
6724  return temp;
6725  }
6726 
6728  {
6730  return *this;
6731  }
6732 
6734  {
6735  xml_attribute_iterator temp = *this;
6736  --*this;
6737  return temp;
6738  }
6739 
6741  {
6742  }
6743 
6744  PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name)
6745  {
6746  }
6747 
6749  {
6750  }
6751 
6753  {
6754  return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
6755  }
6756 
6758  {
6759  return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
6760  }
6761 
6763  {
6764  assert(_wrap._root);
6765  return _wrap;
6766  }
6767 
6769  {
6770  assert(_wrap._root);
6771  return const_cast<xml_node*>(&_wrap); // BCC5 workaround
6772  }
6773 
6775  {
6776  assert(_wrap._root);
6778  return *this;
6779  }
6780 
6782  {
6783  xml_named_node_iterator temp = *this;
6784  ++*this;
6785  return temp;
6786  }
6787 
6789  {
6790  if (_wrap._root)
6792  else
6793  {
6794  _wrap = _parent.last_child();
6795 
6796  if (!impl::strequal(_wrap.name(), _name))
6798  }
6799 
6800  return *this;
6801  }
6802 
6804  {
6805  xml_named_node_iterator temp = *this;
6806  --*this;
6807  return temp;
6808  }
6809 
6811  {
6812  }
6813 
6814  PUGI__FN xml_parse_result::operator bool() const
6815  {
6816  return status == status_ok;
6817  }
6818 
6820  {
6821  switch (status)
6822  {
6823  case status_ok: return "No error";
6824 
6825  case status_file_not_found: return "File was not found";
6826  case status_io_error: return "Error reading from file/stream";
6827  case status_out_of_memory: return "Could not allocate memory";
6828  case status_internal_error: return "Internal error occurred";
6829 
6830  case status_unrecognized_tag: return "Could not determine tag type";
6831 
6832  case status_bad_pi: return "Error parsing document declaration/processing instruction";
6833  case status_bad_comment: return "Error parsing comment";
6834  case status_bad_cdata: return "Error parsing CDATA section";
6835  case status_bad_doctype: return "Error parsing document type declaration";
6836  case status_bad_pcdata: return "Error parsing PCDATA section";
6837  case status_bad_start_element: return "Error parsing start element tag";
6838  case status_bad_attribute: return "Error parsing element attribute";
6839  case status_bad_end_element: return "Error parsing end element tag";
6840  case status_end_element_mismatch: return "Start-end tags mismatch";
6841 
6842  case status_append_invalid_root: return "Unable to append nodes: root is not an element or document";
6843 
6844  case status_no_document_element: return "No document element found";
6845 
6846  default: return "Unknown error";
6847  }
6848  }
6849 
6851  {
6852  _create();
6853  }
6854 
6856  {
6857  _destroy();
6858  }
6859 
6860 #ifdef PUGIXML_HAS_MOVE
6862  {
6863  _create();
6864  _move(rhs);
6865  }
6866 
6867  PUGI__FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
6868  {
6869  if (this == &rhs) return *this;
6870 
6871  _destroy();
6872  _create();
6873  _move(rhs);
6874 
6875  return *this;
6876  }
6877 #endif
6878 
6880  {
6881  _destroy();
6882  _create();
6883  }
6884 
6886  {
6887  reset();
6888 
6889  for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
6890  append_copy(cur);
6891  }
6892 
6894  {
6895  assert(!_root);
6896 
6897  #ifdef PUGIXML_COMPACT
6898  // space for page marker for the first page (uint32_t), rounded up to pointer size; assumes pointers are at least 32-bit
6899  const size_t page_offset = sizeof(void*);
6900  #else
6901  const size_t page_offset = 0;
6902  #endif
6903 
6904  // initialize sentinel page
6905  PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory));
6906 
6907  // prepare page structure
6908  impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory);
6909  assert(page);
6910 
6911  page->busy_size = impl::xml_memory_page_size;
6912 
6913  // setup first page marker
6914  #ifdef PUGIXML_COMPACT
6915  // round-trip through void* to avoid 'cast increases required alignment of target type' warning
6916  page->compact_page_marker = reinterpret_cast<uint32_t*>(static_cast<void*>(reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page)));
6917  *page->compact_page_marker = sizeof(impl::xml_memory_page);
6918  #endif
6919 
6920  // allocate new root
6921  _root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page);
6923 
6924  // setup sentinel page
6925  page->allocator = static_cast<impl::xml_document_struct*>(_root);
6926 
6927  // setup hash table pointer in allocator
6928  #ifdef PUGIXML_COMPACT
6929  page->allocator->_hash = &static_cast<impl::xml_document_struct*>(_root)->hash;
6930  #endif
6931 
6932  // verify the document allocation
6933  assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory));
6934  }
6935 
6937  {
6938  assert(_root);
6939 
6940  // destroy static storage
6941  if (_buffer)
6942  {
6943  impl::xml_memory::deallocate(_buffer);
6944  _buffer = 0;
6945  }
6946 
6947  // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator)
6948  for (impl::xml_extra_buffer* extra = static_cast<impl::xml_document_struct*>(_root)->extra_buffers; extra; extra = extra->next)
6949  {
6950  if (extra->buffer) impl::xml_memory::deallocate(extra->buffer);
6951  }
6952 
6953  // destroy dynamic storage, leave sentinel page (it's in static memory)
6954  impl::xml_memory_page* root_page = PUGI__GETPAGE(_root);
6955  assert(root_page && !root_page->prev);
6956  assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));
6957 
6958  for (impl::xml_memory_page* page = root_page->next; page; )
6959  {
6960  impl::xml_memory_page* next = page->next;
6961 
6962  impl::xml_allocator::deallocate_page(page);
6963 
6964  page = next;
6965  }
6966 
6967  #ifdef PUGIXML_COMPACT
6968  // destroy hash table
6969  static_cast<impl::xml_document_struct*>(_root)->hash.clear();
6970  #endif
6971 
6972  _root = 0;
6973  }
6974 
6975 #ifdef PUGIXML_HAS_MOVE
6977  {
6978  impl::xml_document_struct* doc = static_cast<impl::xml_document_struct*>(_root);
6979  impl::xml_document_struct* other = static_cast<impl::xml_document_struct*>(rhs._root);
6980 
6981  // save first child pointer for later; this needs hash access
6982  xml_node_struct* other_first_child = other->first_child;
6983 
6984  #ifdef PUGIXML_COMPACT
6985  // reserve space for the hash table up front; this is the only operation that can fail
6986  // if it does, we have no choice but to throw (if we have exceptions)
6987  if (other_first_child)
6988  {
6989  size_t other_children = 0;
6990  for (xml_node_struct* node = other_first_child; node; node = node->next_sibling)
6991  other_children++;
6992 
6993  // in compact mode, each pointer assignment could result in a hash table request
6994  // during move, we have to relocate document first_child and parents of all children
6995  // normally there's just one child and its parent has a pointerless encoding but
6996  // we assume the worst here
6997  if (!other->_hash->reserve(other_children + 1))
6998  {
6999  #ifdef PUGIXML_NO_EXCEPTIONS
7000  return;
7001  #else
7002  throw std::bad_alloc();
7003  #endif
7004  }
7005  }
7006  #endif
7007 
7008  // move allocation state
7009  doc->_root = other->_root;
7010  doc->_busy_size = other->_busy_size;
7011 
7012  // move buffer state
7013  doc->buffer = other->buffer;
7014  doc->extra_buffers = other->extra_buffers;
7015  _buffer = rhs._buffer;
7016 
7017  #ifdef PUGIXML_COMPACT
7018  // move compact hash; note that the hash table can have pointers to other but they will be "inactive", similarly to nodes removed with remove_child
7019  doc->hash = other->hash;
7020  doc->_hash = &doc->hash;
7021 
7022  // make sure we don't access other hash up until the end when we reinitialize other document
7023  other->_hash = 0;
7024  #endif
7025 
7026  // move page structure
7027  impl::xml_memory_page* doc_page = PUGI__GETPAGE(doc);
7028  assert(doc_page && !doc_page->prev && !doc_page->next);
7029 
7030  impl::xml_memory_page* other_page = PUGI__GETPAGE(other);
7031  assert(other_page && !other_page->prev);
7032 
7033  // relink pages since root page is embedded into xml_document
7034  if (impl::xml_memory_page* page = other_page->next)
7035  {
7036  assert(page->prev == other_page);
7037 
7038  page->prev = doc_page;
7039 
7040  doc_page->next = page;
7041  other_page->next = 0;
7042  }
7043 
7044  // make sure pages point to the correct document state
7045  for (impl::xml_memory_page* page = doc_page->next; page; page = page->next)
7046  {
7047  assert(page->allocator == other);
7048 
7049  page->allocator = doc;
7050 
7051  #ifdef PUGIXML_COMPACT
7052  // this automatically migrates most children between documents and prevents ->parent assignment from allocating
7053  if (page->compact_shared_parent == other)
7054  page->compact_shared_parent = doc;
7055  #endif
7056  }
7057 
7058  // move tree structure
7059  assert(!doc->first_child);
7060 
7061  doc->first_child = other_first_child;
7062 
7063  for (xml_node_struct* node = other_first_child; node; node = node->next_sibling)
7064  {
7065  #ifdef PUGIXML_COMPACT
7066  // most children will have migrated when we reassigned compact_shared_parent
7067  assert(node->parent == other || node->parent == doc);
7068 
7069  node->parent = doc;
7070  #else
7071  assert(node->parent == other);
7072  node->parent = doc;
7073  #endif
7074  }
7075 
7076  // reset other document
7077  new (other) impl::xml_document_struct(PUGI__GETPAGE(other));
7078  rhs._buffer = 0;
7079  }
7080 #endif
7081 
7082 #ifndef PUGIXML_NO_STL
7083  PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
7084  {
7085  reset();
7086 
7087  return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding, &_buffer);
7088  }
7089 
7090  PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
7091  {
7092  reset();
7093 
7094  return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding_wchar, &_buffer);
7095  }
7096 #endif
7097 
7098  PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options)
7099  {
7100  // Force native encoding (skip autodetection)
7101  #ifdef PUGIXML_WCHAR_MODE
7102  xml_encoding encoding = encoding_wchar;
7103  #else
7104  xml_encoding encoding = encoding_utf8;
7105  #endif
7106 
7107  return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
7108  }
7109 
7110  PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
7111  {
7112  return load_string(contents, options);
7113  }
7114 
7115  PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
7116  {
7117  reset();
7118 
7119  using impl::auto_deleter; // MSVC7 workaround
7120  auto_deleter<FILE> file(fopen(path_, "rb"), impl::close_file);
7121 
7122  return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
7123  }
7124 
7125  PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)
7126  {
7127  reset();
7128 
7129  using impl::auto_deleter; // MSVC7 workaround
7131 
7132  return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
7133  }
7134 
7135  PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
7136  {
7137  reset();
7138 
7139  return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, const_cast<void*>(contents), size, options, encoding, false, false, &_buffer);
7140  }
7141 
7142  PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
7143  {
7144  reset();
7145 
7146  return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, false, &_buffer);
7147  }
7148 
7149  PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
7150  {
7151  reset();
7152 
7153  return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, true, &_buffer);
7154  }
7155 
7156  PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
7157  {
7158  impl::xml_buffered_writer buffered_writer(writer, encoding);
7159 
7160  if ((flags & format_write_bom) && encoding != encoding_latin1)
7161  {
7162  // BOM always represents the codepoint U+FEFF, so just write it in native encoding
7163  #ifdef PUGIXML_WCHAR_MODE
7164  unsigned int bom = 0xfeff;
7165  buffered_writer.write(static_cast<wchar_t>(bom));
7166  #else
7167  buffered_writer.write('\xef', '\xbb', '\xbf');
7168  #endif
7169  }
7170 
7172  {
7173  buffered_writer.write_string(PUGIXML_TEXT("<?xml version=\"1.0\""));
7174  if (encoding == encoding_latin1) buffered_writer.write_string(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
7175  buffered_writer.write('?', '>');
7176  if (!(flags & format_raw)) buffered_writer.write('\n');
7177  }
7178 
7179  impl::node_output(buffered_writer, _root, indent, flags, 0);
7180 
7181  buffered_writer.flush();
7182  }
7183 
7184 #ifndef PUGIXML_NO_STL
7185  PUGI__FN void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const
7186  {
7187  xml_writer_stream writer(stream);
7188 
7189  save(writer, indent, flags, encoding);
7190  }
7191 
7192  PUGI__FN void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const
7193  {
7194  xml_writer_stream writer(stream);
7195 
7196  save(writer, indent, flags, encoding_wchar);
7197  }
7198 #endif
7199 
7200  PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
7201  {
7202  using impl::auto_deleter; // MSVC7 workaround
7203  auto_deleter<FILE> file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file);
7204 
7205  return impl::save_file_impl(*this, file.data, indent, flags, encoding);
7206  }
7207 
7208  PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
7209  {
7210  using impl::auto_deleter; // MSVC7 workaround
7211  auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file);
7212 
7213  return impl::save_file_impl(*this, file.data, indent, flags, encoding);
7214  }
7215 
7217  {
7218  assert(_root);
7219 
7220  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
7221  if (PUGI__NODETYPE(i) == node_element)
7222  return xml_node(i);
7223 
7224  return xml_node();
7225  }
7226 
7227 #ifndef PUGIXML_NO_STL
7228  PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
7229  {
7230  assert(str);
7231 
7232  return impl::as_utf8_impl(str, impl::strlength_wide(str));
7233  }
7234 
7235  PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str)
7236  {
7237  return impl::as_utf8_impl(str.c_str(), str.size());
7238  }
7239 
7240  PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str)
7241  {
7242  assert(str);
7243 
7244  return impl::as_wide_impl(str, strlen(str));
7245  }
7246 
7247  PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str)
7248  {
7249  return impl::as_wide_impl(str.c_str(), str.size());
7250  }
7251 #endif
7252 
7254  {
7255  impl::xml_memory::allocate = allocate;
7256  impl::xml_memory::deallocate = deallocate;
7257  }
7258 
7260  {
7261  return impl::xml_memory::allocate;
7262  }
7263 
7265  {
7266  return impl::xml_memory::deallocate;
7267  }
7268 }
7269 
7270 #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
7271 namespace std
7272 {
7273  // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
7274  PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
7275  {
7276  return std::bidirectional_iterator_tag();
7277  }
7278 
7279  PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
7280  {
7281  return std::bidirectional_iterator_tag();
7282  }
7283 
7284  PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)
7285  {
7286  return std::bidirectional_iterator_tag();
7287  }
7288 }
7289 #endif
7290 
7291 #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
7292 namespace std
7293 {
7294  // Workarounds for (non-standard) iterator category detection
7295  PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)
7296  {
7297  return std::bidirectional_iterator_tag();
7298  }
7299 
7300  PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)
7301  {
7302  return std::bidirectional_iterator_tag();
7303  }
7304 
7305  PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)
7306  {
7307  return std::bidirectional_iterator_tag();
7308  }
7309 }
7310 #endif
7311 
7312 #ifndef PUGIXML_NO_XPATH
7313 // STL replacements
7315  struct equal_to
7316  {
7317  template <typename T> bool operator()(const T& lhs, const T& rhs) const
7318  {
7319  return lhs == rhs;
7320  }
7321  };
7322 
7324  {
7325  template <typename T> bool operator()(const T& lhs, const T& rhs) const
7326  {
7327  return lhs != rhs;
7328  }
7329  };
7330 
7331  struct less
7332  {
7333  template <typename T> bool operator()(const T& lhs, const T& rhs) const
7334  {
7335  return lhs < rhs;
7336  }
7337  };
7338 
7339  struct less_equal
7340  {
7341  template <typename T> bool operator()(const T& lhs, const T& rhs) const
7342  {
7343  return lhs <= rhs;
7344  }
7345  };
7346 
7347  template <typename T> inline void swap(T& lhs, T& rhs)
7348  {
7349  T temp = lhs;
7350  lhs = rhs;
7351  rhs = temp;
7352  }
7353 
7354  template <typename I, typename Pred> PUGI__FN I min_element(I begin, I end, const Pred& pred)
7355  {
7356  I result = begin;
7357 
7358  for (I it = begin + 1; it != end; ++it)
7359  if (pred(*it, *result))
7360  result = it;
7361 
7362  return result;
7363  }
7364 
7365  template <typename I> PUGI__FN void reverse(I begin, I end)
7366  {
7367  while (end - begin > 1)
7368  swap(*begin++, *--end);
7369  }
7370 
7371  template <typename I> PUGI__FN I unique(I begin, I end)
7372  {
7373  // fast skip head
7374  while (end - begin > 1 && *begin != *(begin + 1))
7375  begin++;
7376 
7377  if (begin == end)
7378  return begin;
7379 
7380  // last written element
7381  I write = begin++;
7382 
7383  // merge unique elements
7384  while (begin != end)
7385  {
7386  if (*begin != *write)
7387  *++write = *begin++;
7388  else
7389  begin++;
7390  }
7391 
7392  // past-the-end (write points to live element)
7393  return write + 1;
7394  }
7395 
7396  template <typename T, typename Pred> PUGI__FN void insertion_sort(T* begin, T* end, const Pred& pred)
7397  {
7398  if (begin == end)
7399  return;
7400 
7401  for (T* it = begin + 1; it != end; ++it)
7402  {
7403  T val = *it;
7404  T* hole = it;
7405 
7406  // move hole backwards
7407  while (hole > begin && pred(val, *(hole - 1)))
7408  {
7409  *hole = *(hole - 1);
7410  hole--;
7411  }
7412 
7413  // fill hole with element
7414  *hole = val;
7415  }
7416  }
7417 
7418  template <typename I, typename Pred> inline I median3(I first, I middle, I last, const Pred& pred)
7419  {
7420  if (pred(*middle, *first))
7421  swap(middle, first);
7422  if (pred(*last, *middle))
7423  swap(last, middle);
7424  if (pred(*middle, *first))
7425  swap(middle, first);
7426 
7427  return middle;
7428  }
7429 
7430  template <typename T, typename Pred> PUGI__FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend)
7431  {
7432  // invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups)
7433  T* eq = begin;
7434  T* lt = begin;
7435  T* gt = end;
7436 
7437  while (lt < gt)
7438  {
7439  if (pred(*lt, pivot))
7440  lt++;
7441  else if (*lt == pivot)
7442  swap(*eq++, *lt++);
7443  else
7444  swap(*lt, *--gt);
7445  }
7446 
7447  // we now have just 4 groups: = < >; move equal elements to the middle
7448  T* eqbeg = gt;
7449 
7450  for (T* it = begin; it != eq; ++it)
7451  swap(*it, *--eqbeg);
7452 
7453  *out_eqbeg = eqbeg;
7454  *out_eqend = gt;
7455  }
7456 
7457  template <typename I, typename Pred> PUGI__FN void sort(I begin, I end, const Pred& pred)
7458  {
7459  // sort large chunks
7460  while (end - begin > 16)
7461  {
7462  // find median element
7463  I middle = begin + (end - begin) / 2;
7464  I median = median3(begin, middle, end - 1, pred);
7465 
7466  // partition in three chunks (< = >)
7467  I eqbeg, eqend;
7468  partition3(begin, end, *median, pred, &eqbeg, &eqend);
7469 
7470  // loop on larger half
7471  if (eqbeg - begin > end - eqend)
7472  {
7473  sort(eqend, end, pred);
7474  end = eqbeg;
7475  }
7476  else
7477  {
7478  sort(begin, eqbeg, pred);
7479  begin = eqend;
7480  }
7481  }
7482 
7483  // insertion sort small chunk
7484  insertion_sort(begin, end, pred);
7485  }
7486 
7487  PUGI__FN bool hash_insert(const void** table, size_t size, const void* key)
7488  {
7489  assert(key);
7490 
7491  unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key));
7492 
7493  // MurmurHash3 32-bit finalizer
7494  h ^= h >> 16;
7495  h *= 0x85ebca6bu;
7496  h ^= h >> 13;
7497  h *= 0xc2b2ae35u;
7498  h ^= h >> 16;
7499 
7500  size_t hashmod = size - 1;
7501  size_t bucket = h & hashmod;
7502 
7503  for (size_t probe = 0; probe <= hashmod; ++probe)
7504  {
7505  if (table[bucket] == 0)
7506  {
7507  table[bucket] = key;
7508  return true;
7509  }
7510 
7511  if (table[bucket] == key)
7512  return false;
7513 
7514  // hash collision, quadratic probing
7515  bucket = (bucket + probe + 1) & hashmod;
7516  }
7517 
7518  assert(false && "Hash table is full"); // unreachable
7519  return false;
7520  }
7522 
7523 // Allocator used for AST and evaluation stacks
7525  static const size_t xpath_memory_page_size =
7526  #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
7527  PUGIXML_MEMORY_XPATH_PAGE_SIZE
7528  #else
7529  4096
7530  #endif
7531  ;
7532 
7533  static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*);
7534 
7536  {
7538  size_t capacity;
7539 
7540  union
7541  {
7543  double alignment;
7544  };
7545  };
7546 
7548  {
7550  size_t _root_size;
7551  bool* _error;
7552 
7553  xpath_allocator(xpath_memory_block* root, bool* error = 0): _root(root), _root_size(0), _error(error)
7554  {
7555  }
7556 
7557  void* allocate(size_t size)
7558  {
7559  // round size up to block alignment boundary
7560  size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7561 
7562  if (_root_size + size <= _root->capacity)
7563  {
7564  void* buf = &_root->data[0] + _root_size;
7565  _root_size += size;
7566  return buf;
7567  }
7568  else
7569  {
7570  // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests
7571  size_t block_capacity_base = sizeof(_root->data);
7572  size_t block_capacity_req = size + block_capacity_base / 4;
7573  size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req;
7574 
7575  size_t block_size = block_capacity + offsetof(xpath_memory_block, data);
7576 
7577  xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));
7578  if (!block)
7579  {
7580  if (_error) *_error = true;
7581  return 0;
7582  }
7583 
7584  block->next = _root;
7585  block->capacity = block_capacity;
7586 
7587  _root = block;
7588  _root_size = size;
7589 
7590  return block->data;
7591  }
7592  }
7593 
7594  void* reallocate(void* ptr, size_t old_size, size_t new_size)
7595  {
7596  // round size up to block alignment boundary
7597  old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7598  new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7599 
7600  // we can only reallocate the last object
7601  assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);
7602 
7603  // try to reallocate the object inplace
7604  if (ptr && _root_size - old_size + new_size <= _root->capacity)
7605  {
7606  _root_size = _root_size - old_size + new_size;
7607  return ptr;
7608  }
7609 
7610  // allocate a new block
7611  void* result = allocate(new_size);
7612  if (!result) return 0;
7613 
7614  // we have a new block
7615  if (ptr)
7616  {
7617  // copy old data (we only support growing)
7618  assert(new_size >= old_size);
7619  memcpy(result, ptr, old_size);
7620 
7621  // free the previous page if it had no other objects
7622  assert(_root->data == result);
7623  assert(_root->next);
7624 
7625  if (_root->next->data == ptr)
7626  {
7627  // deallocate the whole page, unless it was the first one
7628  xpath_memory_block* next = _root->next->next;
7629 
7630  if (next)
7631  {
7633  _root->next = next;
7634  }
7635  }
7636  }
7637 
7638  return result;
7639  }
7640 
7641  void revert(const xpath_allocator& state)
7642  {
7643  // free all new pages
7644  xpath_memory_block* cur = _root;
7645 
7646  while (cur != state._root)
7647  {
7648  xpath_memory_block* next = cur->next;
7649 
7651 
7652  cur = next;
7653  }
7654 
7655  // restore state
7656  _root = state._root;
7657  _root_size = state._root_size;
7658  }
7659 
7660  void release()
7661  {
7662  xpath_memory_block* cur = _root;
7663  assert(cur);
7664 
7665  while (cur->next)
7666  {
7667  xpath_memory_block* next = cur->next;
7668 
7670 
7671  cur = next;
7672  }
7673  }
7674  };
7675 
7677  {
7679  {
7680  }
7681 
7683  {
7684  _target->revert(_state);
7685  }
7686 
7689  };
7690 
7692  {
7695  };
7696 
7698  {
7703  bool oom;
7704 
7705  xpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false)
7706  {
7707  blocks[0].next = blocks[1].next = 0;
7708  blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data);
7709 
7710  stack.result = &result;
7711  stack.temp = &temp;
7712  }
7713 
7715  {
7716  result.release();
7717  temp.release();
7718  }
7719  };
7721 
7722 // String class
7725  {
7726  const char_t* _buffer;
7729 
7730  static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc)
7731  {
7732  char_t* result = static_cast<char_t*>(alloc->allocate((length + 1) * sizeof(char_t)));
7733  if (!result) return 0;
7734 
7735  memcpy(result, string, length * sizeof(char_t));
7736  result[length] = 0;
7737 
7738  return result;
7739  }
7740 
7741  xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap)
7742  {
7743  }
7744 
7745  public:
7746  static xpath_string from_const(const char_t* str)
7747  {
7748  return xpath_string(str, false, 0);
7749  }
7750 
7751  static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end)
7752  {
7753  assert(begin <= end && *end == 0);
7754 
7755  return xpath_string(begin, true, static_cast<size_t>(end - begin));
7756  }
7757 
7758  static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc)
7759  {
7760  assert(begin <= end);
7761 
7762  if (begin == end)
7763  return xpath_string();
7764 
7765  size_t length = static_cast<size_t>(end - begin);
7766  const char_t* data = duplicate_string(begin, length, alloc);
7767 
7768  return data ? xpath_string(data, true, length) : xpath_string();
7769  }
7770 
7772  {
7773  }
7774 
7775  void append(const xpath_string& o, xpath_allocator* alloc)
7776  {
7777  // skip empty sources
7778  if (!*o._buffer) return;
7779 
7780  // fast append for constant empty target and constant source
7781  if (!*_buffer && !_uses_heap && !o._uses_heap)
7782  {
7783  _buffer = o._buffer;
7784  }
7785  else
7786  {
7787  // need to make heap copy
7788  size_t target_length = length();
7789  size_t source_length = o.length();
7790  size_t result_length = target_length + source_length;
7791 
7792  // allocate new buffer
7793  char_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t)));
7794  if (!result) return;
7795 
7796  // append first string to the new buffer in case there was no reallocation
7797  if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t));
7798 
7799  // append second string to the new buffer
7800  memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
7801  result[result_length] = 0;
7802 
7803  // finalize
7804  _buffer = result;
7805  _uses_heap = true;
7806  _length_heap = result_length;
7807  }
7808  }
7809 
7810  const char_t* c_str() const
7811  {
7812  return _buffer;
7813  }
7814 
7815  size_t length() const
7816  {
7818  }
7819 
7821  {
7822  // make private heap copy
7823  if (!_uses_heap)
7824  {
7825  size_t length_ = strlength(_buffer);
7826  const char_t* data_ = duplicate_string(_buffer, length_, alloc);
7827 
7828  if (!data_) return 0;
7829 
7830  _buffer = data_;
7831  _uses_heap = true;
7832  _length_heap = length_;
7833  }
7834 
7835  return const_cast<char_t*>(_buffer);
7836  }
7837 
7838  bool empty() const
7839  {
7840  return *_buffer == 0;
7841  }
7842 
7843  bool operator==(const xpath_string& o) const
7844  {
7845  return strequal(_buffer, o._buffer);
7846  }
7847 
7848  bool operator!=(const xpath_string& o) const
7849  {
7850  return !strequal(_buffer, o._buffer);
7851  }
7852 
7853  bool uses_heap() const
7854  {
7855  return _uses_heap;
7856  }
7857  };
7859 
7861  PUGI__FN bool starts_with(const char_t* string, const char_t* pattern)
7862  {
7863  while (*pattern && *string == *pattern)
7864  {
7865  string++;
7866  pattern++;
7867  }
7868 
7869  return *pattern == 0;
7870  }
7871 
7873  {
7874  #ifdef PUGIXML_WCHAR_MODE
7875  return wcschr(s, c);
7876  #else
7877  return strchr(s, c);
7878  #endif
7879  }
7880 
7881  PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p)
7882  {
7883  #ifdef PUGIXML_WCHAR_MODE
7884  // MSVC6 wcsstr bug workaround (if s is empty it always returns 0)
7885  return (*p == 0) ? s : wcsstr(s, p);
7886  #else
7887  return strstr(s, p);
7888  #endif
7889  }
7890 
7891  // Converts symbol to lower case, if it is an ASCII one
7893  {
7894  return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
7895  }
7896 
7897  PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
7898  {
7899  if (na.attribute())
7900  return xpath_string::from_const(na.attribute().value());
7901  else
7902  {
7903  xml_node n = na.node();
7904 
7905  switch (n.type())
7906  {
7907  case node_pcdata:
7908  case node_cdata:
7909  case node_comment:
7910  case node_pi:
7911  return xpath_string::from_const(n.value());
7912 
7913  case node_document:
7914  case node_element:
7915  {
7916  xpath_string result;
7917 
7918  // element nodes can have value if parse_embed_pcdata was used
7919  if (n.value()[0])
7920  result.append(xpath_string::from_const(n.value()), alloc);
7921 
7922  xml_node cur = n.first_child();
7923 
7924  while (cur && cur != n)
7925  {
7926  if (cur.type() == node_pcdata || cur.type() == node_cdata)
7927  result.append(xpath_string::from_const(cur.value()), alloc);
7928 
7929  if (cur.first_child())
7930  cur = cur.first_child();
7931  else if (cur.next_sibling())
7932  cur = cur.next_sibling();
7933  else
7934  {
7935  while (!cur.next_sibling() && cur != n)
7936  cur = cur.parent();
7937 
7938  if (cur != n) cur = cur.next_sibling();
7939  }
7940  }
7941 
7942  return result;
7943  }
7944 
7945  default:
7946  return xpath_string();
7947  }
7948  }
7949  }
7950 
7951  PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)
7952  {
7953  assert(ln->parent == rn->parent);
7954 
7955  // there is no common ancestor (the shared parent is null), nodes are from different documents
7956  if (!ln->parent) return ln < rn;
7957 
7958  // determine sibling order
7959  xml_node_struct* ls = ln;
7960  xml_node_struct* rs = rn;
7961 
7962  while (ls && rs)
7963  {
7964  if (ls == rn) return true;
7965  if (rs == ln) return false;
7966 
7967  ls = ls->next_sibling;
7968  rs = rs->next_sibling;
7969  }
7970 
7971  // if rn sibling chain ended ln must be before rn
7972  return !rs;
7973  }
7974 
7975  PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
7976  {
7977  // find common ancestor at the same depth, if any
7978  xml_node_struct* lp = ln;
7979  xml_node_struct* rp = rn;
7980 
7981  while (lp && rp && lp->parent != rp->parent)
7982  {
7983  lp = lp->parent;
7984  rp = rp->parent;
7985  }
7986 
7987  // parents are the same!
7988  if (lp && rp) return node_is_before_sibling(lp, rp);
7989 
7990  // nodes are at different depths, need to normalize heights
7991  bool left_higher = !lp;
7992 
7993  while (lp)
7994  {
7995  lp = lp->parent;
7996  ln = ln->parent;
7997  }
7998 
7999  while (rp)
8000  {
8001  rp = rp->parent;
8002  rn = rn->parent;
8003  }
8004 
8005  // one node is the ancestor of the other
8006  if (ln == rn) return left_higher;
8007 
8008  // find common ancestor... again
8009  while (ln->parent != rn->parent)
8010  {
8011  ln = ln->parent;
8012  rn = rn->parent;
8013  }
8014 
8015  return node_is_before_sibling(ln, rn);
8016  }
8017 
8018  PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)
8019  {
8020  while (node && node != parent) node = node->parent;
8021 
8022  return parent && node == parent;
8023  }
8024 
8025  PUGI__FN const void* document_buffer_order(const xpath_node& xnode)
8026  {
8027  xml_node_struct* node = xnode.node().internal_object();
8028 
8029  if (node)
8030  {
8031  if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0)
8032  {
8033  if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name;
8034  if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value;
8035  }
8036 
8037  return 0;
8038  }
8039 
8040  xml_attribute_struct* attr = xnode.attribute().internal_object();
8041 
8042  if (attr)
8043  {
8044  if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0)
8045  {
8046  if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name;
8047  if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value;
8048  }
8049 
8050  return 0;
8051  }
8052 
8053  return 0;
8054  }
8055 
8057  {
8058  bool operator()(const xpath_node& lhs, const xpath_node& rhs) const
8059  {
8060  // optimized document order based check
8061  const void* lo = document_buffer_order(lhs);
8062  const void* ro = document_buffer_order(rhs);
8063 
8064  if (lo && ro) return lo < ro;
8065 
8066  // slow comparison
8067  xml_node ln = lhs.node(), rn = rhs.node();
8068 
8069  // compare attributes
8070  if (lhs.attribute() && rhs.attribute())
8071  {
8072  // shared parent
8073  if (lhs.parent() == rhs.parent())
8074  {
8075  // determine sibling order
8076  for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
8077  if (a == rhs.attribute())
8078  return true;
8079 
8080  return false;
8081  }
8082 
8083  // compare attribute parents
8084  ln = lhs.parent();
8085  rn = rhs.parent();
8086  }
8087  else if (lhs.attribute())
8088  {
8089  // attributes go after the parent element
8090  if (lhs.parent() == rhs.node()) return false;
8091 
8092  ln = lhs.parent();
8093  }
8094  else if (rhs.attribute())
8095  {
8096  // attributes go after the parent element
8097  if (rhs.parent() == lhs.node()) return true;
8098 
8099  rn = rhs.parent();
8100  }
8101 
8102  if (ln == rn) return false;
8103 
8104  if (!ln || !rn) return ln < rn;
8105 
8106  return node_is_before(ln.internal_object(), rn.internal_object());
8107  }
8108  };
8109 
8111  {
8112  #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
8113  PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t));
8114  typedef uint32_t UI; // BCC5 workaround
8115  union { float f; UI i; } u;
8116  u.i = 0x7fc00000;
8117  return double(u.f);
8118  #else
8119  // fallback
8120  const volatile double zero = 0.0;
8121  return zero / zero;
8122  #endif
8123  }
8124 
8125  PUGI__FN bool is_nan(double value)
8126  {
8127  #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
8128  return !!_isnan(value);
8129  #elif defined(fpclassify) && defined(FP_NAN)
8130  return fpclassify(value) == FP_NAN;
8131  #else
8132  // fallback
8133  const volatile double v = value;
8134  return v != v;
8135  #endif
8136  }
8137 
8139  {
8140  #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
8141  if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0;
8142  if (_isnan(value)) return PUGIXML_TEXT("NaN");
8143  return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
8144  #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
8145  switch (fpclassify(value))
8146  {
8147  case FP_NAN:
8148  return PUGIXML_TEXT("NaN");
8149 
8150  case FP_INFINITE:
8151  return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
8152 
8153  case FP_ZERO:
8154  return PUGIXML_TEXT("0");
8155 
8156  default:
8157  return 0;
8158  }
8159  #else
8160  // fallback
8161  const volatile double v = value;
8162 
8163  if (v == 0) return PUGIXML_TEXT("0");
8164  if (v != v) return PUGIXML_TEXT("NaN");
8165  if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
8166  return 0;
8167  #endif
8168  }
8169 
8171  {
8172  return (value != 0 && !is_nan(value));
8173  }
8174 
8175  PUGI__FN void truncate_zeros(char* begin, char* end)
8176  {
8177  while (begin != end && end[-1] == '0') end--;
8178 
8179  *end = 0;
8180  }
8181 
8182  // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
8183 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
8184  PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
8185  {
8186  // get base values
8187  int sign, exponent;
8188  _ecvt_s(buffer, sizeof(buffer), value, DBL_DIG + 1, &exponent, &sign);
8189 
8190  // truncate redundant zeros
8191  truncate_zeros(buffer, buffer + strlen(buffer));
8192 
8193  // fill results
8194  *out_mantissa = buffer;
8195  *out_exponent = exponent;
8196  }
8197 #else
8198  PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
8199  {
8200  // get a scientific notation value with IEEE DBL_DIG decimals
8201  PUGI__SNPRINTF(buffer, "%.*e", DBL_DIG, value);
8202 
8203  // get the exponent (possibly negative)
8204  char* exponent_string = strchr(buffer, 'e');
8205  assert(exponent_string);
8206 
8207  int exponent = atoi(exponent_string + 1);
8208 
8209  // extract mantissa string: skip sign
8210  char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
8211  assert(mantissa[0] != '0' && mantissa[1] == '.');
8212 
8213  // divide mantissa by 10 to eliminate integer part
8214  mantissa[1] = mantissa[0];
8215  mantissa++;
8216  exponent++;
8217 
8218  // remove extra mantissa digits and zero-terminate mantissa
8219  truncate_zeros(mantissa, exponent_string);
8220 
8221  // fill results
8222  *out_mantissa = mantissa;
8223  *out_exponent = exponent;
8224  }
8225 #endif
8226 
8228  {
8229  // try special number conversion
8230  const char_t* special = convert_number_to_string_special(value);
8231  if (special) return xpath_string::from_const(special);
8232 
8233  // get mantissa + exponent form
8234  char mantissa_buffer[32];
8235 
8236  char* mantissa;
8237  int exponent;
8238  convert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent);
8239 
8240  // allocate a buffer of suitable length for the number
8241  size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
8242  char_t* result = static_cast<char_t*>(alloc->allocate(sizeof(char_t) * result_size));
8243  if (!result) return xpath_string();
8244 
8245  // make the number!
8246  char_t* s = result;
8247 
8248  // sign
8249  if (value < 0) *s++ = '-';
8250 
8251  // integer part
8252  if (exponent <= 0)
8253  {
8254  *s++ = '0';
8255  }
8256  else
8257  {
8258  while (exponent > 0)
8259  {
8260  assert(*mantissa == 0 || static_cast<unsigned int>(*mantissa - '0') <= 9);
8261  *s++ = *mantissa ? *mantissa++ : '0';
8262  exponent--;
8263  }
8264  }
8265 
8266  // fractional part
8267  if (*mantissa)
8268  {
8269  // decimal point
8270  *s++ = '.';
8271 
8272  // extra zeroes from negative exponent
8273  while (exponent < 0)
8274  {
8275  *s++ = '0';
8276  exponent++;
8277  }
8278 
8279  // extra mantissa digits
8280  while (*mantissa)
8281  {
8282  assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
8283  *s++ = *mantissa++;
8284  }
8285  }
8286 
8287  // zero-terminate
8288  assert(s < result + result_size);
8289  *s = 0;
8290 
8291  return xpath_string::from_heap_preallocated(result, s);
8292  }
8293 
8295  {
8296  // parse leading whitespace
8297  while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
8298 
8299  // parse sign
8300  if (*string == '-') ++string;
8301 
8302  if (!*string) return false;
8303 
8304  // if there is no integer part, there should be a decimal part with at least one digit
8305  if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false;
8306 
8307  // parse integer part
8308  while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
8309 
8310  // parse decimal part
8311  if (*string == '.')
8312  {
8313  ++string;
8314 
8315  while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
8316  }
8317 
8318  // parse trailing whitespace
8319  while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
8320 
8321  return *string == 0;
8322  }
8323 
8325  {
8326  // check string format
8327  if (!check_string_to_number_format(string)) return gen_nan();
8328 
8329  // parse string
8330  #ifdef PUGIXML_WCHAR_MODE
8331  return wcstod(string, 0);
8332  #else
8333  return strtod(string, 0);
8334  #endif
8335  }
8336 
8337  PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result)
8338  {
8339  size_t length = static_cast<size_t>(end - begin);
8340  char_t* scratch = buffer;
8341 
8342  if (length >= sizeof(buffer) / sizeof(buffer[0]))
8343  {
8344  // need to make dummy on-heap copy
8345  scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
8346  if (!scratch) return false;
8347  }
8348 
8349  // copy string to zero-terminated buffer and perform conversion
8350  memcpy(scratch, begin, length * sizeof(char_t));
8351  scratch[length] = 0;
8352 
8353  *out_result = convert_string_to_number(scratch);
8354 
8355  // free dummy buffer
8356  if (scratch != buffer) xml_memory::deallocate(scratch);
8357 
8358  return true;
8359  }
8360 
8361  PUGI__FN double round_nearest(double value)
8362  {
8363  return floor(value + 0.5);
8364  }
8365 
8366  PUGI__FN double round_nearest_nzero(double value)
8367  {
8368  // same as round_nearest, but returns -0 for [-0.5, -0]
8369  // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)
8370  return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
8371  }
8372 
8373  PUGI__FN const char_t* qualified_name(const xpath_node& node)
8374  {
8375  return node.attribute() ? node.attribute().name() : node.node().name();
8376  }
8377 
8378  PUGI__FN const char_t* local_name(const xpath_node& node)
8379  {
8380  const char_t* name = qualified_name(node);
8381  const char_t* p = find_char(name, ':');
8382 
8383  return p ? p + 1 : name;
8384  }
8385 
8387  {
8388  const char_t* prefix;
8390 
8392  {
8393  const char_t* pos = find_char(name, ':');
8394 
8395  prefix = pos ? name : 0;
8396  prefix_length = pos ? static_cast<size_t>(pos - name) : 0;
8397  }
8398 
8399  bool operator()(xml_attribute a) const
8400  {
8401  const char_t* name = a.name();
8402 
8403  if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false;
8404 
8405  return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
8406  }
8407  };
8408 
8409  PUGI__FN const char_t* namespace_uri(xml_node node)
8410  {
8411  namespace_uri_predicate pred = node.name();
8412 
8413  xml_node p = node;
8414 
8415  while (p)
8416  {
8417  xml_attribute a = p.find_attribute(pred);
8418 
8419  if (a) return a.value();
8420 
8421  p = p.parent();
8422  }
8423 
8424  return PUGIXML_TEXT("");
8425  }
8426 
8427  PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent)
8428  {
8429  namespace_uri_predicate pred = attr.name();
8430 
8431  // Default namespace does not apply to attributes
8432  if (!pred.prefix) return PUGIXML_TEXT("");
8433 
8434  xml_node p = parent;
8435 
8436  while (p)
8437  {
8438  xml_attribute a = p.find_attribute(pred);
8439 
8440  if (a) return a.value();
8441 
8442  p = p.parent();
8443  }
8444 
8445  return PUGIXML_TEXT("");
8446  }
8447 
8448  PUGI__FN const char_t* namespace_uri(const xpath_node& node)
8449  {
8450  return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
8451  }
8452 
8454  {
8455  char_t* write = buffer;
8456 
8457  for (char_t* it = buffer; *it; )
8458  {
8459  char_t ch = *it++;
8460 
8461  if (PUGI__IS_CHARTYPE(ch, ct_space))
8462  {
8463  // replace whitespace sequence with single space
8464  while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
8465 
8466  // avoid leading spaces
8467  if (write != buffer) *write++ = ' ';
8468  }
8469  else *write++ = ch;
8470  }
8471 
8472  // remove trailing space
8473  if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
8474 
8475  // zero-terminate
8476  *write = 0;
8477 
8478  return write;
8479  }
8480 
8481  PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)
8482  {
8483  char_t* write = buffer;
8484 
8485  while (*buffer)
8486  {
8487  PUGI__DMC_VOLATILE char_t ch = *buffer++;
8488 
8489  const char_t* pos = find_char(from, ch);
8490 
8491  if (!pos)
8492  *write++ = ch; // do not process
8493  else if (static_cast<size_t>(pos - from) < to_length)
8494  *write++ = to[pos - from]; // replace
8495  }
8496 
8497  // zero-terminate
8498  *write = 0;
8499 
8500  return write;
8501  }
8502 
8503  PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to)
8504  {
8505  unsigned char table[128] = {0};
8506 
8507  while (*from)
8508  {
8509  unsigned int fc = static_cast<unsigned int>(*from);
8510  unsigned int tc = static_cast<unsigned int>(*to);
8511 
8512  if (fc >= 128 || tc >= 128)
8513  return 0;
8514 
8515  // code=128 means "skip character"
8516  if (!table[fc])
8517  table[fc] = static_cast<unsigned char>(tc ? tc : 128);
8518 
8519  from++;
8520  if (tc) to++;
8521  }
8522 
8523  for (int i = 0; i < 128; ++i)
8524  if (!table[i])
8525  table[i] = static_cast<unsigned char>(i);
8526 
8527  void* result = alloc->allocate(sizeof(table));
8528  if (!result) return 0;
8529 
8530  memcpy(result, table, sizeof(table));
8531 
8532  return static_cast<unsigned char*>(result);
8533  }
8534 
8535  PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table)
8536  {
8537  char_t* write = buffer;
8538 
8539  while (*buffer)
8540  {
8541  char_t ch = *buffer++;
8542  unsigned int index = static_cast<unsigned int>(ch);
8543 
8544  if (index < 128)
8545  {
8546  unsigned char code = table[index];
8547 
8548  // code=128 means "skip character" (table size is 128 so 128 can be a special value)
8549  // this code skips these characters without extra branches
8550  *write = static_cast<char_t>(code);
8551  write += 1 - (code >> 7);
8552  }
8553  else
8554  {
8555  *write++ = ch;
8556  }
8557  }
8558 
8559  // zero-terminate
8560  *write = 0;
8561 
8562  return write;
8563  }
8564 
8565  inline bool is_xpath_attribute(const char_t* name)
8566  {
8567  return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':'));
8568  }
8569 
8570  struct xpath_variable_boolean: xpath_variable
8571  {
8573  {
8574  }
8575 
8576  bool value;
8578  };
8579 
8580  struct xpath_variable_number: xpath_variable
8581  {
8583  {
8584  }
8585 
8586  double value;
8588  };
8589 
8590  struct xpath_variable_string: xpath_variable
8591  {
8593  {
8594  }
8595 
8597  {
8599  }
8600 
8603  };
8604 
8605  struct xpath_variable_node_set: xpath_variable
8606  {
8608  {
8609  }
8610 
8611  xpath_node_set value;
8613  };
8614 
8615  static const xpath_node_set dummy_node_set;
8616 
8618  {
8619  // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
8620  unsigned int result = 0;
8621 
8622  while (*str)
8623  {
8624  result += static_cast<unsigned int>(*str++);
8625  result += result << 10;
8626  result ^= result >> 6;
8627  }
8628 
8629  result += result << 3;
8630  result ^= result >> 11;
8631  result += result << 15;
8632 
8633  return result;
8634  }
8635 
8636  template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name)
8637  {
8638  size_t length = strlength(name);
8639  if (length == 0) return 0; // empty variable names are invalid
8640 
8641  // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
8642  void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));
8643  if (!memory) return 0;
8644 
8645  T* result = new (memory) T();
8646 
8647  memcpy(result->name, name, (length + 1) * sizeof(char_t));
8648 
8649  return result;
8650  }
8651 
8653  {
8654  switch (type)
8655  {
8656  case xpath_type_node_set:
8657  return new_xpath_variable<xpath_variable_node_set>(name);
8658 
8659  case xpath_type_number:
8660  return new_xpath_variable<xpath_variable_number>(name);
8661 
8662  case xpath_type_string:
8663  return new_xpath_variable<xpath_variable_string>(name);
8664 
8665  case xpath_type_boolean:
8666  return new_xpath_variable<xpath_variable_boolean>(name);
8667 
8668  default:
8669  return 0;
8670  }
8671  }
8672 
8673  template <typename T> PUGI__FN void delete_xpath_variable(T* var)
8674  {
8675  var->~T();
8677  }
8678 
8679  PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
8680  {
8681  switch (type)
8682  {
8683  case xpath_type_node_set:
8684  delete_xpath_variable(static_cast<xpath_variable_node_set*>(var));
8685  break;
8686 
8687  case xpath_type_number:
8688  delete_xpath_variable(static_cast<xpath_variable_number*>(var));
8689  break;
8690 
8691  case xpath_type_string:
8692  delete_xpath_variable(static_cast<xpath_variable_string*>(var));
8693  break;
8694 
8695  case xpath_type_boolean:
8696  delete_xpath_variable(static_cast<xpath_variable_boolean*>(var));
8697  break;
8698 
8699  default:
8700  assert(false && "Invalid variable type"); // unreachable
8701  }
8702  }
8703 
8704  PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs)
8705  {
8706  switch (rhs->type())
8707  {
8708  case xpath_type_node_set:
8709  return lhs->set(static_cast<const xpath_variable_node_set*>(rhs)->value);
8710 
8711  case xpath_type_number:
8712  return lhs->set(static_cast<const xpath_variable_number*>(rhs)->value);
8713 
8714  case xpath_type_string:
8715  return lhs->set(static_cast<const xpath_variable_string*>(rhs)->value);
8716 
8717  case xpath_type_boolean:
8718  return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value);
8719 
8720  default:
8721  assert(false && "Invalid variable type"); // unreachable
8722  return false;
8723  }
8724  }
8725 
8726  PUGI__FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result)
8727  {
8728  size_t length = static_cast<size_t>(end - begin);
8729  char_t* scratch = buffer;
8730 
8731  if (length >= sizeof(buffer) / sizeof(buffer[0]))
8732  {
8733  // need to make dummy on-heap copy
8734  scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
8735  if (!scratch) return false;
8736  }
8737 
8738  // copy string to zero-terminated buffer and perform lookup
8739  memcpy(scratch, begin, length * sizeof(char_t));
8740  scratch[length] = 0;
8741 
8742  *out_result = set->get(scratch);
8743 
8744  // free dummy buffer
8745  if (scratch != buffer) xml_memory::deallocate(scratch);
8746 
8747  return true;
8748  }
8750 
8751 // Internal node set class
8753  PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end)
8754  {
8755  if (end - begin < 2)
8756  return xpath_node_set::type_sorted;
8757 
8759 
8760  bool first = cmp(begin[0], begin[1]);
8761 
8762  for (const xpath_node* it = begin + 1; it + 1 < end; ++it)
8763  if (cmp(it[0], it[1]) != first)
8764  return xpath_node_set::type_unsorted;
8765 
8766  return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse;
8767  }
8768 
8769  PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
8770  {
8771  xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
8772 
8773  if (type == xpath_node_set::type_unsorted)
8774  {
8775  xpath_node_set::type_t sorted = xpath_get_order(begin, end);
8776 
8777  if (sorted == xpath_node_set::type_unsorted)
8778  {
8779  sort(begin, end, document_order_comparator());
8780 
8781  type = xpath_node_set::type_sorted;
8782  }
8783  else
8784  type = sorted;
8785  }
8786 
8787  if (type != order) reverse(begin, end);
8788 
8789  return order;
8790  }
8791 
8792  PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
8793  {
8794  if (begin == end) return xpath_node();
8795 
8796  switch (type)
8797  {
8798  case xpath_node_set::type_sorted:
8799  return *begin;
8800 
8801  case xpath_node_set::type_sorted_reverse:
8802  return *(end - 1);
8803 
8804  case xpath_node_set::type_unsorted:
8805  return *min_element(begin, end, document_order_comparator());
8806 
8807  default:
8808  assert(false && "Invalid node set type"); // unreachable
8809  return xpath_node();
8810  }
8811  }
8812 
8814  {
8815  xpath_node_set::type_t _type;
8816 
8817  xpath_node* _begin;
8818  xpath_node* _end;
8819  xpath_node* _eos;
8820 
8821  public:
8822  xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0)
8823  {
8824  }
8825 
8826  xpath_node* begin() const
8827  {
8828  return _begin;
8829  }
8830 
8831  xpath_node* end() const
8832  {
8833  return _end;
8834  }
8835 
8836  bool empty() const
8837  {
8838  return _begin == _end;
8839  }
8840 
8841  size_t size() const
8842  {
8843  return static_cast<size_t>(_end - _begin);
8844  }
8845 
8846  xpath_node first() const
8847  {
8848  return xpath_first(_begin, _end, _type);
8849  }
8850 
8851  void push_back_grow(const xpath_node& node, xpath_allocator* alloc);
8852 
8853  void push_back(const xpath_node& node, xpath_allocator* alloc)
8854  {
8855  if (_end != _eos)
8856  *_end++ = node;
8857  else
8858  push_back_grow(node, alloc);
8859  }
8860 
8861  void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)
8862  {
8863  if (begin_ == end_) return;
8864 
8865  size_t size_ = static_cast<size_t>(_end - _begin);
8866  size_t capacity = static_cast<size_t>(_eos - _begin);
8867  size_t count = static_cast<size_t>(end_ - begin_);
8868 
8869  if (size_ + count > capacity)
8870  {
8871  // reallocate the old array or allocate a new one
8872  xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
8873  if (!data) return;
8874 
8875  // finalize
8876  _begin = data;
8877  _end = data + size_;
8878  _eos = data + size_ + count;
8879  }
8880 
8881  memcpy(_end, begin_, count * sizeof(xpath_node));
8882  _end += count;
8883  }
8884 
8885  void sort_do()
8886  {
8887  _type = xpath_sort(_begin, _end, _type, false);
8888  }
8889 
8890  void truncate(xpath_node* pos)
8891  {
8892  assert(_begin <= pos && pos <= _end);
8893 
8894  _end = pos;
8895  }
8896 
8898  {
8899  if (_type == xpath_node_set::type_unsorted && _end - _begin > 2)
8900  {
8901  xpath_allocator_capture cr(alloc);
8902 
8903  size_t size_ = static_cast<size_t>(_end - _begin);
8904 
8905  size_t hash_size = 1;
8906  while (hash_size < size_ + size_ / 2) hash_size *= 2;
8907 
8908  const void** hash_data = static_cast<const void**>(alloc->allocate(hash_size * sizeof(void**)));
8909  if (!hash_data) return;
8910 
8911  memset(hash_data, 0, hash_size * sizeof(const void**));
8912 
8913  xpath_node* write = _begin;
8914 
8915  for (xpath_node* it = _begin; it != _end; ++it)
8916  {
8917  const void* attr = it->attribute().internal_object();
8918  const void* node = it->node().internal_object();
8919  const void* key = attr ? attr : node;
8920 
8921  if (key && hash_insert(hash_data, hash_size, key))
8922  {
8923  *write++ = *it;
8924  }
8925  }
8926 
8927  _end = write;
8928  }
8929  else
8930  {
8931  _end = unique(_begin, _end);
8932  }
8933  }
8934 
8935  xpath_node_set::type_t type() const
8936  {
8937  return _type;
8938  }
8939 
8940  void set_type(xpath_node_set::type_t value)
8941  {
8942  _type = value;
8943  }
8944  };
8945 
8947  {
8948  size_t capacity = static_cast<size_t>(_eos - _begin);
8949 
8950  // get new capacity (1.5x rule)
8951  size_t new_capacity = capacity + capacity / 2 + 1;
8952 
8953  // reallocate the old array or allocate a new one
8954  xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
8955  if (!data) return;
8956 
8957  // finalize
8958  _begin = data;
8959  _end = data + capacity;
8960  _eos = data + new_capacity;
8961 
8962  // push
8963  *_end++ = node;
8964  }
8966 
8969  {
8970  xpath_node n;
8971  size_t position, size;
8972 
8973  xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_)
8974  {
8975  }
8976  };
8977 
8979  {
9006  lex_eof
9007  };
9008 
9010  {
9011  const char_t* begin;
9012  const char_t* end;
9013 
9015  {
9016  }
9017 
9018  bool operator==(const char_t* other) const
9019  {
9020  size_t length = static_cast<size_t>(end - begin);
9021 
9022  return strequalrange(other, begin, length);
9023  }
9024  };
9025 
9027  {
9028  const char_t* _cur;
9031 
9033 
9034  public:
9035  explicit xpath_lexer(const char_t* query): _cur(query)
9036  {
9037  next();
9038  }
9039 
9040  const char_t* state() const
9041  {
9042  return _cur;
9043  }
9044 
9045  void next()
9046  {
9047  const char_t* cur = _cur;
9048 
9049  while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
9050 
9051  // save lexeme position for error reporting
9052  _cur_lexeme_pos = cur;
9053 
9054  switch (*cur)
9055  {
9056  case 0:
9057  _cur_lexeme = lex_eof;
9058  break;
9059 
9060  case '>':
9061  if (*(cur+1) == '=')
9062  {
9063  cur += 2;
9065  }
9066  else
9067  {
9068  cur += 1;
9070  }
9071  break;
9072 
9073  case '<':
9074  if (*(cur+1) == '=')
9075  {
9076  cur += 2;
9078  }
9079  else
9080  {
9081  cur += 1;
9083  }
9084  break;
9085 
9086  case '!':
9087  if (*(cur+1) == '=')
9088  {
9089  cur += 2;
9091  }
9092  else
9093  {
9095  }
9096  break;
9097 
9098  case '=':
9099  cur += 1;
9101 
9102  break;
9103 
9104  case '+':
9105  cur += 1;
9107 
9108  break;
9109 
9110  case '-':
9111  cur += 1;
9113 
9114  break;
9115 
9116  case '*':
9117  cur += 1;
9119 
9120  break;
9121 
9122  case '|':
9123  cur += 1;
9125 
9126  break;
9127 
9128  case '$':
9129  cur += 1;
9130 
9132  {
9134 
9135  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9136 
9137  if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
9138  {
9139  cur++; // :
9140 
9141  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9142  }
9143 
9144  _cur_lexeme_contents.end = cur;
9145 
9147  }
9148  else
9149  {
9151  }
9152 
9153  break;
9154 
9155  case '(':
9156  cur += 1;
9158 
9159  break;
9160 
9161  case ')':
9162  cur += 1;
9164 
9165  break;
9166 
9167  case '[':
9168  cur += 1;
9170 
9171  break;
9172 
9173  case ']':
9174  cur += 1;
9176 
9177  break;
9178 
9179  case ',':
9180  cur += 1;
9182 
9183  break;
9184 
9185  case '/':
9186  if (*(cur+1) == '/')
9187  {
9188  cur += 2;
9190  }
9191  else
9192  {
9193  cur += 1;
9195  }
9196  break;
9197 
9198  case '.':
9199  if (*(cur+1) == '.')
9200  {
9201  cur += 2;
9203  }
9204  else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
9205  {
9206  _cur_lexeme_contents.begin = cur; // .
9207 
9208  ++cur;
9209 
9210  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9211 
9212  _cur_lexeme_contents.end = cur;
9213 
9215  }
9216  else
9217  {
9218  cur += 1;
9219  _cur_lexeme = lex_dot;
9220  }
9221  break;
9222 
9223  case '@':
9224  cur += 1;
9226 
9227  break;
9228 
9229  case '"':
9230  case '\'':
9231  {
9232  char_t terminator = *cur;
9233 
9234  ++cur;
9235 
9237  while (*cur && *cur != terminator) cur++;
9238  _cur_lexeme_contents.end = cur;
9239 
9240  if (!*cur)
9242  else
9243  {
9244  cur += 1;
9246  }
9247 
9248  break;
9249  }
9250 
9251  case ':':
9252  if (*(cur+1) == ':')
9253  {
9254  cur += 2;
9256  }
9257  else
9258  {
9260  }
9261  break;
9262 
9263  default:
9264  if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
9265  {
9267 
9268  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9269 
9270  if (*cur == '.')
9271  {
9272  cur++;
9273 
9274  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9275  }
9276 
9277  _cur_lexeme_contents.end = cur;
9278 
9280  }
9281  else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
9282  {
9284 
9285  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9286 
9287  if (cur[0] == ':')
9288  {
9289  if (cur[1] == '*') // namespace test ncname:*
9290  {
9291  cur += 2; // :*
9292  }
9293  else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
9294  {
9295  cur++; // :
9296 
9297  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9298  }
9299  }
9300 
9301  _cur_lexeme_contents.end = cur;
9302 
9304  }
9305  else
9306  {
9308  }
9309  }
9310 
9311  _cur = cur;
9312  }
9313 
9315  {
9316  return _cur_lexeme;
9317  }
9318 
9319  const char_t* current_pos() const
9320  {
9321  return _cur_lexeme_pos;
9322  }
9323 
9325  {
9327 
9328  return _cur_lexeme_contents;
9329  }
9330  };
9331 
9333  {
9335  ast_op_or, // left or right
9336  ast_op_and, // left and right
9337  ast_op_equal, // left = right
9338  ast_op_not_equal, // left != right
9339  ast_op_less, // left < right
9340  ast_op_greater, // left > right
9341  ast_op_less_or_equal, // left <= right
9342  ast_op_greater_or_equal, // left >= right
9343  ast_op_add, // left + right
9344  ast_op_subtract, // left - right
9345  ast_op_multiply, // left * right
9346  ast_op_divide, // left / right
9347  ast_op_mod, // left % right
9348  ast_op_negate, // left - right
9349  ast_op_union, // left | right
9350  ast_predicate, // apply predicate to set; next points to next predicate
9351  ast_filter, // select * from left where right
9352  ast_string_constant, // string constant
9353  ast_number_constant, // number constant
9354  ast_variable, // variable
9355  ast_func_last, // last()
9356  ast_func_position, // position()
9357  ast_func_count, // count(left)
9358  ast_func_id, // id(left)
9359  ast_func_local_name_0, // local-name()
9360  ast_func_local_name_1, // local-name(left)
9361  ast_func_namespace_uri_0, // namespace-uri()
9362  ast_func_namespace_uri_1, // namespace-uri(left)
9363  ast_func_name_0, // name()
9364  ast_func_name_1, // name(left)
9365  ast_func_string_0, // string()
9366  ast_func_string_1, // string(left)
9367  ast_func_concat, // concat(left, right, siblings)
9368  ast_func_starts_with, // starts_with(left, right)
9369  ast_func_contains, // contains(left, right)
9370  ast_func_substring_before, // substring-before(left, right)
9371  ast_func_substring_after, // substring-after(left, right)
9372  ast_func_substring_2, // substring(left, right)
9373  ast_func_substring_3, // substring(left, right, third)
9374  ast_func_string_length_0, // string-length()
9375  ast_func_string_length_1, // string-length(left)
9376  ast_func_normalize_space_0, // normalize-space()
9377  ast_func_normalize_space_1, // normalize-space(left)
9378  ast_func_translate, // translate(left, right, third)
9379  ast_func_boolean, // boolean(left)
9380  ast_func_not, // not(left)
9381  ast_func_true, // true()
9382  ast_func_false, // false()
9383  ast_func_lang, // lang(left)
9384  ast_func_number_0, // number()
9385  ast_func_number_1, // number(left)
9386  ast_func_sum, // sum(left)
9387  ast_func_floor, // floor(left)
9388  ast_func_ceiling, // ceiling(left)
9389  ast_func_round, // round(left)
9390  ast_step, // process set left with step
9391  ast_step_root, // select root node
9392 
9393  ast_opt_translate_table, // translate(left, right, third) where right/third are constants
9394  ast_opt_compare_attribute // @name = 'string'
9395  };
9396 
9397  enum axis_t
9398  {
9411  axis_self
9412  };
9413 
9415  {
9425  };
9426 
9428  {
9433  };
9434 
9436  {
9440  };
9441 
9442  template <axis_t N> struct axis_to_type
9443  {
9444  static const axis_t axis;
9445  };
9446 
9447  template <axis_t N> const axis_t axis_to_type<N>::axis = N;
9448 
9450  {
9451  private:
9452  // node type
9453  char _type;
9454  char _rettype;
9455 
9456  // for ast_step
9457  char _axis;
9458 
9459  // for ast_step/ast_predicate/ast_filter
9460  char _test;
9461 
9462  // tree node structure
9466 
9467  union
9468  {
9469  // value for ast_string_constant
9470  const char_t* string;
9471  // value for ast_number_constant
9472  double number;
9473  // variable for ast_variable
9474  xpath_variable* variable;
9475  // node test for ast_step (node name/namespace/node type/pi target)
9477  // table for ast_opt_translate_table
9478  const unsigned char* table;
9480 
9483 
9484  template <class Comp> static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
9485  {
9486  xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
9487 
9488  if (lt != xpath_type_node_set && rt != xpath_type_node_set)
9489  {
9490  if (lt == xpath_type_boolean || rt == xpath_type_boolean)
9491  return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
9492  else if (lt == xpath_type_number || rt == xpath_type_number)
9493  return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
9494  else if (lt == xpath_type_string || rt == xpath_type_string)
9495  {
9496  xpath_allocator_capture cr(stack.result);
9497 
9498  xpath_string ls = lhs->eval_string(c, stack);
9499  xpath_string rs = rhs->eval_string(c, stack);
9500 
9501  return comp(ls, rs);
9502  }
9503  }
9504  else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
9505  {
9506  xpath_allocator_capture cr(stack.result);
9507 
9510 
9511  for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9512  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9513  {
9514  xpath_allocator_capture cri(stack.result);
9515 
9516  if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
9517  return true;
9518  }
9519 
9520  return false;
9521  }
9522  else
9523  {
9524  if (lt == xpath_type_node_set)
9525  {
9526  swap(lhs, rhs);
9527  swap(lt, rt);
9528  }
9529 
9530  if (lt == xpath_type_boolean)
9531  return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
9532  else if (lt == xpath_type_number)
9533  {
9534  xpath_allocator_capture cr(stack.result);
9535 
9536  double l = lhs->eval_number(c, stack);
9538 
9539  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9540  {
9541  xpath_allocator_capture cri(stack.result);
9542 
9543  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9544  return true;
9545  }
9546 
9547  return false;
9548  }
9549  else if (lt == xpath_type_string)
9550  {
9551  xpath_allocator_capture cr(stack.result);
9552 
9553  xpath_string l = lhs->eval_string(c, stack);
9555 
9556  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9557  {
9558  xpath_allocator_capture cri(stack.result);
9559 
9560  if (comp(l, string_value(*ri, stack.result)))
9561  return true;
9562  }
9563 
9564  return false;
9565  }
9566  }
9567 
9568  assert(false && "Wrong types"); // unreachable
9569  return false;
9570  }
9571 
9572  static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval)
9573  {
9574  return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any;
9575  }
9576 
9577  template <class Comp> static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
9578  {
9579  xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
9580 
9581  if (lt != xpath_type_node_set && rt != xpath_type_node_set)
9582  return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
9583  else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
9584  {
9585  xpath_allocator_capture cr(stack.result);
9586 
9589 
9590  for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9591  {
9592  xpath_allocator_capture cri(stack.result);
9593 
9594  double l = convert_string_to_number(string_value(*li, stack.result).c_str());
9595 
9596  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9597  {
9598  xpath_allocator_capture crii(stack.result);
9599 
9600  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9601  return true;
9602  }
9603  }
9604 
9605  return false;
9606  }
9607  else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
9608  {
9609  xpath_allocator_capture cr(stack.result);
9610 
9611  double l = lhs->eval_number(c, stack);
9613 
9614  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9615  {
9616  xpath_allocator_capture cri(stack.result);
9617 
9618  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9619  return true;
9620  }
9621 
9622  return false;
9623  }
9624  else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
9625  {
9626  xpath_allocator_capture cr(stack.result);
9627 
9629  double r = rhs->eval_number(c, stack);
9630 
9631  for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9632  {
9633  xpath_allocator_capture cri(stack.result);
9634 
9635  if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
9636  return true;
9637  }
9638 
9639  return false;
9640  }
9641  else
9642  {
9643  assert(false && "Wrong types"); // unreachable
9644  return false;
9645  }
9646  }
9647 
9648  static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)
9649  {
9650  assert(ns.size() >= first);
9651  assert(expr->rettype() != xpath_type_number);
9652 
9653  size_t i = 1;
9654  size_t size = ns.size() - first;
9655 
9656  xpath_node* last = ns.begin() + first;
9657 
9658  // remove_if... or well, sort of
9659  for (xpath_node* it = last; it != ns.end(); ++it, ++i)
9660  {
9661  xpath_context c(*it, i, size);
9662 
9663  if (expr->eval_boolean(c, stack))
9664  {
9665  *last++ = *it;
9666 
9667  if (once) break;
9668  }
9669  }
9670 
9671  ns.truncate(last);
9672  }
9673 
9674  static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)
9675  {
9676  assert(ns.size() >= first);
9677  assert(expr->rettype() == xpath_type_number);
9678 
9679  size_t i = 1;
9680  size_t size = ns.size() - first;
9681 
9682  xpath_node* last = ns.begin() + first;
9683 
9684  // remove_if... or well, sort of
9685  for (xpath_node* it = last; it != ns.end(); ++it, ++i)
9686  {
9687  xpath_context c(*it, i, size);
9688 
9689  if (expr->eval_number(c, stack) == i)
9690  {
9691  *last++ = *it;
9692 
9693  if (once) break;
9694  }
9695  }
9696 
9697  ns.truncate(last);
9698  }
9699 
9700  static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)
9701  {
9702  assert(ns.size() >= first);
9703  assert(expr->rettype() == xpath_type_number);
9704 
9705  size_t size = ns.size() - first;
9706 
9707  xpath_node* last = ns.begin() + first;
9708 
9709  xpath_context c(xpath_node(), 1, size);
9710 
9711  double er = expr->eval_number(c, stack);
9712 
9713  if (er >= 1.0 && er <= size)
9714  {
9715  size_t eri = static_cast<size_t>(er);
9716 
9717  if (er == eri)
9718  {
9719  xpath_node r = last[eri - 1];
9720 
9721  *last++ = r;
9722  }
9723  }
9724 
9725  ns.truncate(last);
9726  }
9727 
9728  void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once)
9729  {
9730  if (ns.size() == first) return;
9731 
9732  assert(_type == ast_filter || _type == ast_predicate);
9733 
9735  apply_predicate_number_const(ns, first, _right, stack);
9736  else if (_right->rettype() == xpath_type_number)
9737  apply_predicate_number(ns, first, _right, stack, once);
9738  else
9739  apply_predicate_boolean(ns, first, _right, stack, once);
9740  }
9741 
9742  void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval)
9743  {
9744  if (ns.size() == first) return;
9745 
9746  bool last_once = eval_once(ns.type(), eval);
9747 
9748  for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
9749  pred->apply_predicate(ns, first, stack, !pred->_next && last_once);
9750  }
9751 
9752  bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc)
9753  {
9754  assert(a);
9755 
9756  const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT("");
9757 
9758  switch (_test)
9759  {
9760  case nodetest_name:
9761  if (strequal(name, _data.nodetest) && is_xpath_attribute(name))
9762  {
9763  ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9764  return true;
9765  }
9766  break;
9767 
9768  case nodetest_type_node:
9769  case nodetest_all:
9770  if (is_xpath_attribute(name))
9771  {
9772  ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9773  return true;
9774  }
9775  break;
9776 
9778  if (starts_with(name, _data.nodetest) && is_xpath_attribute(name))
9779  {
9780  ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9781  return true;
9782  }
9783  break;
9784 
9785  default:
9786  ;
9787  }
9788 
9789  return false;
9790  }
9791 
9792  bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc)
9793  {
9794  assert(n);
9795 
9796  xml_node_type type = PUGI__NODETYPE(n);
9797 
9798  switch (_test)
9799  {
9800  case nodetest_name:
9801  if (type == node_element && n->name && strequal(n->name, _data.nodetest))
9802  {
9803  ns.push_back(xml_node(n), alloc);
9804  return true;
9805  }
9806  break;
9807 
9808  case nodetest_type_node:
9809  ns.push_back(xml_node(n), alloc);
9810  return true;
9811 
9812  case nodetest_type_comment:
9813  if (type == node_comment)
9814  {
9815  ns.push_back(xml_node(n), alloc);
9816  return true;
9817  }
9818  break;
9819 
9820  case nodetest_type_text:
9821  if (type == node_pcdata || type == node_cdata)
9822  {
9823  ns.push_back(xml_node(n), alloc);
9824  return true;
9825  }
9826  break;
9827 
9828  case nodetest_type_pi:
9829  if (type == node_pi)
9830  {
9831  ns.push_back(xml_node(n), alloc);
9832  return true;
9833  }
9834  break;
9835 
9836  case nodetest_pi:
9837  if (type == node_pi && n->name && strequal(n->name, _data.nodetest))
9838  {
9839  ns.push_back(xml_node(n), alloc);
9840  return true;
9841  }
9842  break;
9843 
9844  case nodetest_all:
9845  if (type == node_element)
9846  {
9847  ns.push_back(xml_node(n), alloc);
9848  return true;
9849  }
9850  break;
9851 
9853  if (type == node_element && n->name && starts_with(n->name, _data.nodetest))
9854  {
9855  ns.push_back(xml_node(n), alloc);
9856  return true;
9857  }
9858  break;
9859 
9860  default:
9861  assert(false && "Unknown axis"); // unreachable
9862  }
9863 
9864  return false;
9865  }
9866 
9867  template <class T> void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T)
9868  {
9869  const axis_t axis = T::axis;
9870 
9871  switch (axis)
9872  {
9873  case axis_attribute:
9874  {
9875  for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute)
9876  if (step_push(ns, a, n, alloc) & once)
9877  return;
9878 
9879  break;
9880  }
9881 
9882  case axis_child:
9883  {
9884  for (xml_node_struct* c = n->first_child; c; c = c->next_sibling)
9885  if (step_push(ns, c, alloc) & once)
9886  return;
9887 
9888  break;
9889  }
9890 
9891  case axis_descendant:
9893  {
9894  if (axis == axis_descendant_or_self)
9895  if (step_push(ns, n, alloc) & once)
9896  return;
9897 
9898  xml_node_struct* cur = n->first_child;
9899 
9900  while (cur)
9901  {
9902  if (step_push(ns, cur, alloc) & once)
9903  return;
9904 
9905  if (cur->first_child)
9906  cur = cur->first_child;
9907  else
9908  {
9909  while (!cur->next_sibling)
9910  {
9911  cur = cur->parent;
9912 
9913  if (cur == n) return;
9914  }
9915 
9916  cur = cur->next_sibling;
9917  }
9918  }
9919 
9920  break;
9921  }
9922 
9924  {
9925  for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling)
9926  if (step_push(ns, c, alloc) & once)
9927  return;
9928 
9929  break;
9930  }
9931 
9933  {
9934  for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c)
9935  if (step_push(ns, c, alloc) & once)
9936  return;
9937 
9938  break;
9939  }
9940 
9941  case axis_following:
9942  {
9943  xml_node_struct* cur = n;
9944 
9945  // exit from this node so that we don't include descendants
9946  while (!cur->next_sibling)
9947  {
9948  cur = cur->parent;
9949 
9950  if (!cur) return;
9951  }
9952 
9953  cur = cur->next_sibling;
9954 
9955  while (cur)
9956  {
9957  if (step_push(ns, cur, alloc) & once)
9958  return;
9959 
9960  if (cur->first_child)
9961  cur = cur->first_child;
9962  else
9963  {
9964  while (!cur->next_sibling)
9965  {
9966  cur = cur->parent;
9967 
9968  if (!cur) return;
9969  }
9970 
9971  cur = cur->next_sibling;
9972  }
9973  }
9974 
9975  break;
9976  }
9977 
9978  case axis_preceding:
9979  {
9980  xml_node_struct* cur = n;
9981 
9982  // exit from this node so that we don't include descendants
9983  while (!cur->prev_sibling_c->next_sibling)
9984  {
9985  cur = cur->parent;
9986 
9987  if (!cur) return;
9988  }
9989 
9990  cur = cur->prev_sibling_c;
9991 
9992  while (cur)
9993  {
9994  if (cur->first_child)
9995  cur = cur->first_child->prev_sibling_c;
9996  else
9997  {
9998  // leaf node, can't be ancestor
9999  if (step_push(ns, cur, alloc) & once)
10000  return;
10001 
10002  while (!cur->prev_sibling_c->next_sibling)
10003  {
10004  cur = cur->parent;
10005 
10006  if (!cur) return;
10007 
10008  if (!node_is_ancestor(cur, n))
10009  if (step_push(ns, cur, alloc) & once)
10010  return;
10011  }
10012 
10013  cur = cur->prev_sibling_c;
10014  }
10015  }
10016 
10017  break;
10018  }
10019 
10020  case axis_ancestor:
10021  case axis_ancestor_or_self:
10022  {
10023  if (axis == axis_ancestor_or_self)
10024  if (step_push(ns, n, alloc) & once)
10025  return;
10026 
10027  xml_node_struct* cur = n->parent;
10028 
10029  while (cur)
10030  {
10031  if (step_push(ns, cur, alloc) & once)
10032  return;
10033 
10034  cur = cur->parent;
10035  }
10036 
10037  break;
10038  }
10039 
10040  case axis_self:
10041  {
10042  step_push(ns, n, alloc);
10043 
10044  break;
10045  }
10046 
10047  case axis_parent:
10048  {
10049  if (n->parent)
10050  step_push(ns, n->parent, alloc);
10051 
10052  break;
10053  }
10054 
10055  default:
10056  assert(false && "Unimplemented axis"); // unreachable
10057  }
10058  }
10059 
10060  template <class T> void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v)
10061  {
10062  const axis_t axis = T::axis;
10063 
10064  switch (axis)
10065  {
10066  case axis_ancestor:
10067  case axis_ancestor_or_self:
10068  {
10069  if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test
10070  if (step_push(ns, a, p, alloc) & once)
10071  return;
10072 
10073  xml_node_struct* cur = p;
10074 
10075  while (cur)
10076  {
10077  if (step_push(ns, cur, alloc) & once)
10078  return;
10079 
10080  cur = cur->parent;
10081  }
10082 
10083  break;
10084  }
10085 
10087  case axis_self:
10088  {
10089  if (_test == nodetest_type_node) // reject attributes based on principal node type test
10090  step_push(ns, a, p, alloc);
10091 
10092  break;
10093  }
10094 
10095  case axis_following:
10096  {
10097  xml_node_struct* cur = p;
10098 
10099  while (cur)
10100  {
10101  if (cur->first_child)
10102  cur = cur->first_child;
10103  else
10104  {
10105  while (!cur->next_sibling)
10106  {
10107  cur = cur->parent;
10108 
10109  if (!cur) return;
10110  }
10111 
10112  cur = cur->next_sibling;
10113  }
10114 
10115  if (step_push(ns, cur, alloc) & once)
10116  return;
10117  }
10118 
10119  break;
10120  }
10121 
10122  case axis_parent:
10123  {
10124  step_push(ns, p, alloc);
10125 
10126  break;
10127  }
10128 
10129  case axis_preceding:
10130  {
10131  // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding
10132  step_fill(ns, p, alloc, once, v);
10133  break;
10134  }
10135 
10136  default:
10137  assert(false && "Unimplemented axis"); // unreachable
10138  }
10139  }
10140 
10141  template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v)
10142  {
10143  const axis_t axis = T::axis;
10144  const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
10145 
10146  if (xn.node())
10147  step_fill(ns, xn.node().internal_object(), alloc, once, v);
10148  else if (axis_has_attributes && xn.attribute() && xn.parent())
10149  step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v);
10150  }
10151 
10152  template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v)
10153  {
10154  const axis_t axis = T::axis;
10155  const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);
10156  const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
10157 
10158  bool once =
10159  (axis == axis_attribute && _test == nodetest_name) ||
10160  (!_right && eval_once(axis_type, eval)) ||
10161  // coverity[mixed_enums]
10163 
10164  xpath_node_set_raw ns;
10165  ns.set_type(axis_type);
10166 
10167  if (_left)
10168  {
10170 
10171  // self axis preserves the original order
10172  if (axis == axis_self) ns.set_type(s.type());
10173 
10174  for (const xpath_node* it = s.begin(); it != s.end(); ++it)
10175  {
10176  size_t size = ns.size();
10177 
10178  // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes
10179  if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
10180 
10181  step_fill(ns, *it, stack.result, once, v);
10182  if (_right) apply_predicates(ns, size, stack, eval);
10183  }
10184  }
10185  else
10186  {
10187  step_fill(ns, c.n, stack.result, once, v);
10188  if (_right) apply_predicates(ns, 0, stack, eval);
10189  }
10190 
10191  // child, attribute and self axes always generate unique set of nodes
10192  // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice
10193  if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)
10194  ns.remove_duplicates(stack.temp);
10195 
10196  return ns;
10197  }
10198 
10199  public:
10200  xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value):
10201  _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10202  {
10203  assert(type == ast_string_constant);
10204  _data.string = value;
10205  }
10206 
10207  xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value):
10208  _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10209  {
10210  assert(type == ast_number_constant);
10211  _data.number = value;
10212  }
10213 
10214  xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):
10215  _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10216  {
10217  assert(type == ast_variable);
10218  _data.variable = value;
10219  }
10220 
10222  _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
10223  {
10224  }
10225 
10226  xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents):
10227  _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(0), _next(0)
10228  {
10229  assert(type == ast_step);
10230  _data.nodetest = contents;
10231  }
10232 
10234  _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast<char>(test)), _left(left), _right(right), _next(0)
10235  {
10236  assert(type == ast_filter || type == ast_predicate);
10237  }
10238 
10240  {
10241  _next = value;
10242  }
10243 
10245  {
10246  _right = value;
10247  }
10248 
10249  bool eval_boolean(const xpath_context& c, const xpath_stack& stack)
10250  {
10251  switch (_type)
10252  {
10253  case ast_op_or:
10254  return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
10255 
10256  case ast_op_and:
10257  return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
10258 
10259  case ast_op_equal:
10260  return compare_eq(_left, _right, c, stack, equal_to());
10261 
10262  case ast_op_not_equal:
10263  return compare_eq(_left, _right, c, stack, not_equal_to());
10264 
10265  case ast_op_less:
10266  return compare_rel(_left, _right, c, stack, less());
10267 
10268  case ast_op_greater:
10269  return compare_rel(_right, _left, c, stack, less());
10270 
10271  case ast_op_less_or_equal:
10272  return compare_rel(_left, _right, c, stack, less_equal());
10273 
10275  return compare_rel(_right, _left, c, stack, less_equal());
10276 
10277  case ast_func_starts_with:
10278  {
10279  xpath_allocator_capture cr(stack.result);
10280 
10281  xpath_string lr = _left->eval_string(c, stack);
10282  xpath_string rr = _right->eval_string(c, stack);
10283 
10284  return starts_with(lr.c_str(), rr.c_str());
10285  }
10286 
10287  case ast_func_contains:
10288  {
10289  xpath_allocator_capture cr(stack.result);
10290 
10291  xpath_string lr = _left->eval_string(c, stack);
10292  xpath_string rr = _right->eval_string(c, stack);
10293 
10294  return find_substring(lr.c_str(), rr.c_str()) != 0;
10295  }
10296 
10297  case ast_func_boolean:
10298  return _left->eval_boolean(c, stack);
10299 
10300  case ast_func_not:
10301  return !_left->eval_boolean(c, stack);
10302 
10303  case ast_func_true:
10304  return true;
10305 
10306  case ast_func_false:
10307  return false;
10308 
10309  case ast_func_lang:
10310  {
10311  if (c.n.attribute()) return false;
10312 
10313  xpath_allocator_capture cr(stack.result);
10314 
10315  xpath_string lang = _left->eval_string(c, stack);
10316 
10317  for (xml_node n = c.n.node(); n; n = n.parent())
10318  {
10319  xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
10320 
10321  if (a)
10322  {
10323  const char_t* value = a.value();
10324 
10325  // strnicmp / strncasecmp is not portable
10326  for (const char_t* lit = lang.c_str(); *lit; ++lit)
10327  {
10328  if (tolower_ascii(*lit) != tolower_ascii(*value)) return false;
10329  ++value;
10330  }
10331 
10332  return *value == 0 || *value == '-';
10333  }
10334  }
10335 
10336  return false;
10337  }
10338 
10340  {
10341  const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string();
10342 
10343  xml_attribute attr = c.n.node().attribute(_left->_data.nodetest);
10344 
10345  return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name());
10346  }
10347 
10348  case ast_variable:
10349  {
10350  assert(_rettype == _data.variable->type());
10351 
10353  return _data.variable->get_boolean();
10354  }
10355 
10356  // fallthrough
10357  default:
10358  {
10359  switch (_rettype)
10360  {
10361  case xpath_type_number:
10362  return convert_number_to_boolean(eval_number(c, stack));
10363 
10364  case xpath_type_string:
10365  {
10366  xpath_allocator_capture cr(stack.result);
10367 
10368  return !eval_string(c, stack).empty();
10369  }
10370 
10371  case xpath_type_node_set:
10372  {
10373  xpath_allocator_capture cr(stack.result);
10374 
10375  return !eval_node_set(c, stack, nodeset_eval_any).empty();
10376  }
10377 
10378  default:
10379  assert(false && "Wrong expression for return type boolean"); // unreachable
10380  return false;
10381  }
10382  }
10383  }
10384  }
10385 
10386  double eval_number(const xpath_context& c, const xpath_stack& stack)
10387  {
10388  switch (_type)
10389  {
10390  case ast_op_add:
10391  return _left->eval_number(c, stack) + _right->eval_number(c, stack);
10392 
10393  case ast_op_subtract:
10394  return _left->eval_number(c, stack) - _right->eval_number(c, stack);
10395 
10396  case ast_op_multiply:
10397  return _left->eval_number(c, stack) * _right->eval_number(c, stack);
10398 
10399  case ast_op_divide:
10400  return _left->eval_number(c, stack) / _right->eval_number(c, stack);
10401 
10402  case ast_op_mod:
10403  return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
10404 
10405  case ast_op_negate:
10406  return -_left->eval_number(c, stack);
10407 
10408  case ast_number_constant:
10409  return _data.number;
10410 
10411  case ast_func_last:
10412  return static_cast<double>(c.size);
10413 
10414  case ast_func_position:
10415  return static_cast<double>(c.position);
10416 
10417  case ast_func_count:
10418  {
10419  xpath_allocator_capture cr(stack.result);
10420 
10421  return static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size());
10422  }
10423 
10425  {
10426  xpath_allocator_capture cr(stack.result);
10427 
10428  return static_cast<double>(string_value(c.n, stack.result).length());
10429  }
10430 
10432  {
10433  xpath_allocator_capture cr(stack.result);
10434 
10435  return static_cast<double>(_left->eval_string(c, stack).length());
10436  }
10437 
10438  case ast_func_number_0:
10439  {
10440  xpath_allocator_capture cr(stack.result);
10441 
10442  return convert_string_to_number(string_value(c.n, stack.result).c_str());
10443  }
10444 
10445  case ast_func_number_1:
10446  return _left->eval_number(c, stack);
10447 
10448  case ast_func_sum:
10449  {
10450  xpath_allocator_capture cr(stack.result);
10451 
10452  double r = 0;
10453 
10455 
10456  for (const xpath_node* it = ns.begin(); it != ns.end(); ++it)
10457  {
10458  xpath_allocator_capture cri(stack.result);
10459 
10460  r += convert_string_to_number(string_value(*it, stack.result).c_str());
10461  }
10462 
10463  return r;
10464  }
10465 
10466  case ast_func_floor:
10467  {
10468  double r = _left->eval_number(c, stack);
10469 
10470  return r == r ? floor(r) : r;
10471  }
10472 
10473  case ast_func_ceiling:
10474  {
10475  double r = _left->eval_number(c, stack);
10476 
10477  return r == r ? ceil(r) : r;
10478  }
10479 
10480  case ast_func_round:
10481  return round_nearest_nzero(_left->eval_number(c, stack));
10482 
10483  case ast_variable:
10484  {
10485  assert(_rettype == _data.variable->type());
10486 
10487  if (_rettype == xpath_type_number)
10488  return _data.variable->get_number();
10489  }
10490 
10491  // fallthrough
10492  default:
10493  {
10494  switch (_rettype)
10495  {
10496  case xpath_type_boolean:
10497  return eval_boolean(c, stack) ? 1 : 0;
10498 
10499  case xpath_type_string:
10500  {
10501  xpath_allocator_capture cr(stack.result);
10502 
10503  return convert_string_to_number(eval_string(c, stack).c_str());
10504  }
10505 
10506  case xpath_type_node_set:
10507  {
10508  xpath_allocator_capture cr(stack.result);
10509 
10510  return convert_string_to_number(eval_string(c, stack).c_str());
10511  }
10512 
10513  default:
10514  assert(false && "Wrong expression for return type number"); // unreachable
10515  return 0;
10516  }
10517 
10518  }
10519  }
10520  }
10521 
10523  {
10524  assert(_type == ast_func_concat);
10525 
10526  xpath_allocator_capture ct(stack.temp);
10527 
10528  // count the string number
10529  size_t count = 1;
10530  for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
10531 
10532  // allocate a buffer for temporary string objects
10533  xpath_string* buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string)));
10534  if (!buffer) return xpath_string();
10535 
10536  // evaluate all strings to temporary stack
10537  xpath_stack swapped_stack = {stack.temp, stack.result};
10538 
10539  buffer[0] = _left->eval_string(c, swapped_stack);
10540 
10541  size_t pos = 1;
10542  for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
10543  assert(pos == count);
10544 
10545  // get total length
10546  size_t length = 0;
10547  for (size_t i = 0; i < count; ++i) length += buffer[i].length();
10548 
10549  // create final string
10550  char_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t)));
10551  if (!result) return xpath_string();
10552 
10553  char_t* ri = result;
10554 
10555  for (size_t j = 0; j < count; ++j)
10556  for (const char_t* bi = buffer[j].c_str(); *bi; ++bi)
10557  *ri++ = *bi;
10558 
10559  *ri = 0;
10560 
10561  return xpath_string::from_heap_preallocated(result, ri);
10562  }
10563 
10565  {
10566  switch (_type)
10567  {
10568  case ast_string_constant:
10569  return xpath_string::from_const(_data.string);
10570 
10571  case ast_func_local_name_0:
10572  {
10573  xpath_node na = c.n;
10574 
10576  }
10577 
10578  case ast_func_local_name_1:
10579  {
10580  xpath_allocator_capture cr(stack.result);
10581 
10583  xpath_node na = ns.first();
10584 
10586  }
10587 
10588  case ast_func_name_0:
10589  {
10590  xpath_node na = c.n;
10591 
10593  }
10594 
10595  case ast_func_name_1:
10596  {
10597  xpath_allocator_capture cr(stack.result);
10598 
10600  xpath_node na = ns.first();
10601 
10603  }
10604 
10606  {
10607  xpath_node na = c.n;
10608 
10610  }
10611 
10613  {
10614  xpath_allocator_capture cr(stack.result);
10615 
10617  xpath_node na = ns.first();
10618 
10620  }
10621 
10622  case ast_func_string_0:
10623  return string_value(c.n, stack.result);
10624 
10625  case ast_func_string_1:
10626  return _left->eval_string(c, stack);
10627 
10628  case ast_func_concat:
10629  return eval_string_concat(c, stack);
10630 
10632  {
10633  xpath_allocator_capture cr(stack.temp);
10634 
10635  xpath_stack swapped_stack = {stack.temp, stack.result};
10636 
10637  xpath_string s = _left->eval_string(c, swapped_stack);
10638  xpath_string p = _right->eval_string(c, swapped_stack);
10639 
10640  const char_t* pos = find_substring(s.c_str(), p.c_str());
10641 
10642  return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string();
10643  }
10644 
10646  {
10647  xpath_allocator_capture cr(stack.temp);
10648 
10649  xpath_stack swapped_stack = {stack.temp, stack.result};
10650 
10651  xpath_string s = _left->eval_string(c, swapped_stack);
10652  xpath_string p = _right->eval_string(c, swapped_stack);
10653 
10654  const char_t* pos = find_substring(s.c_str(), p.c_str());
10655  if (!pos) return xpath_string();
10656 
10657  const char_t* rbegin = pos + p.length();
10658  const char_t* rend = s.c_str() + s.length();
10659 
10660  return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
10661  }
10662 
10663  case ast_func_substring_2:
10664  {
10665  xpath_allocator_capture cr(stack.temp);
10666 
10667  xpath_stack swapped_stack = {stack.temp, stack.result};
10668 
10669  xpath_string s = _left->eval_string(c, swapped_stack);
10670  size_t s_length = s.length();
10671 
10672  double first = round_nearest(_right->eval_number(c, stack));
10673 
10674  if (is_nan(first)) return xpath_string(); // NaN
10675  else if (first >= s_length + 1) return xpath_string();
10676 
10677  size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
10678  assert(1 <= pos && pos <= s_length + 1);
10679 
10680  const char_t* rbegin = s.c_str() + (pos - 1);
10681  const char_t* rend = s.c_str() + s.length();
10682 
10683  return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
10684  }
10685 
10686  case ast_func_substring_3:
10687  {
10688  xpath_allocator_capture cr(stack.temp);
10689 
10690  xpath_stack swapped_stack = {stack.temp, stack.result};
10691 
10692  xpath_string s = _left->eval_string(c, swapped_stack);
10693  size_t s_length = s.length();
10694 
10695  double first = round_nearest(_right->eval_number(c, stack));
10696  double last = first + round_nearest(_right->_next->eval_number(c, stack));
10697 
10698  if (is_nan(first) || is_nan(last)) return xpath_string();
10699  else if (first >= s_length + 1) return xpath_string();
10700  else if (first >= last) return xpath_string();
10701  else if (last < 1) return xpath_string();
10702 
10703  size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
10704  size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last);
10705 
10706  assert(1 <= pos && pos <= end && end <= s_length + 1);
10707  const char_t* rbegin = s.c_str() + (pos - 1);
10708  const char_t* rend = s.c_str() + (end - 1);
10709 
10710  return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result);
10711  }
10712 
10714  {
10715  xpath_string s = string_value(c.n, stack.result);
10716 
10717  char_t* begin = s.data(stack.result);
10718  if (!begin) return xpath_string();
10719 
10720  char_t* end = normalize_space(begin);
10721 
10722  return xpath_string::from_heap_preallocated(begin, end);
10723  }
10724 
10726  {
10727  xpath_string s = _left->eval_string(c, stack);
10728 
10729  char_t* begin = s.data(stack.result);
10730  if (!begin) return xpath_string();
10731 
10732  char_t* end = normalize_space(begin);
10733 
10734  return xpath_string::from_heap_preallocated(begin, end);
10735  }
10736 
10737  case ast_func_translate:
10738  {
10739  xpath_allocator_capture cr(stack.temp);
10740 
10741  xpath_stack swapped_stack = {stack.temp, stack.result};
10742 
10743  xpath_string s = _left->eval_string(c, stack);
10744  xpath_string from = _right->eval_string(c, swapped_stack);
10745  xpath_string to = _right->_next->eval_string(c, swapped_stack);
10746 
10747  char_t* begin = s.data(stack.result);
10748  if (!begin) return xpath_string();
10749 
10750  char_t* end = translate(begin, from.c_str(), to.c_str(), to.length());
10751 
10752  return xpath_string::from_heap_preallocated(begin, end);
10753  }
10754 
10756  {
10757  xpath_string s = _left->eval_string(c, stack);
10758 
10759  char_t* begin = s.data(stack.result);
10760  if (!begin) return xpath_string();
10761 
10762  char_t* end = translate_table(begin, _data.table);
10763 
10764  return xpath_string::from_heap_preallocated(begin, end);
10765  }
10766 
10767  case ast_variable:
10768  {
10769  assert(_rettype == _data.variable->type());
10770 
10771  if (_rettype == xpath_type_string)
10772  return xpath_string::from_const(_data.variable->get_string());
10773  }
10774 
10775  // fallthrough
10776  default:
10777  {
10778  switch (_rettype)
10779  {
10780  case xpath_type_boolean:
10781  return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
10782 
10783  case xpath_type_number:
10784  return convert_number_to_string(eval_number(c, stack), stack.result);
10785 
10786  case xpath_type_node_set:
10787  {
10788  xpath_allocator_capture cr(stack.temp);
10789 
10790  xpath_stack swapped_stack = {stack.temp, stack.result};
10791 
10792  xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first);
10793  return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
10794  }
10795 
10796  default:
10797  assert(false && "Wrong expression for return type string"); // unreachable
10798  return xpath_string();
10799  }
10800  }
10801  }
10802  }
10803 
10805  {
10806  switch (_type)
10807  {
10808  case ast_op_union:
10809  {
10810  xpath_allocator_capture cr(stack.temp);
10811 
10812  xpath_stack swapped_stack = {stack.temp, stack.result};
10813 
10814  xpath_node_set_raw ls = _left->eval_node_set(c, stack, eval);
10815  xpath_node_set_raw rs = _right->eval_node_set(c, swapped_stack, eval);
10816 
10817  // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
10818  ls.set_type(xpath_node_set::type_unsorted);
10819 
10820  ls.append(rs.begin(), rs.end(), stack.result);
10821  ls.remove_duplicates(stack.temp);
10822 
10823  return ls;
10824  }
10825 
10826  case ast_filter:
10827  {
10829 
10830  // either expression is a number or it contains position() call; sort by document order
10831  if (_test != predicate_posinv) set.sort_do();
10832 
10833  bool once = eval_once(set.type(), eval);
10834 
10835  apply_predicate(set, 0, stack, once);
10836 
10837  return set;
10838  }
10839 
10840  case ast_func_id:
10841  return xpath_node_set_raw();
10842 
10843  case ast_step:
10844  {
10845  switch (_axis)
10846  {
10847  case axis_ancestor:
10848  return step_do(c, stack, eval, axis_to_type<axis_ancestor>());
10849 
10850  case axis_ancestor_or_self:
10851  return step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>());
10852 
10853  case axis_attribute:
10854  return step_do(c, stack, eval, axis_to_type<axis_attribute>());
10855 
10856  case axis_child:
10857  return step_do(c, stack, eval, axis_to_type<axis_child>());
10858 
10859  case axis_descendant:
10860  return step_do(c, stack, eval, axis_to_type<axis_descendant>());
10861 
10863  return step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>());
10864 
10865  case axis_following:
10866  return step_do(c, stack, eval, axis_to_type<axis_following>());
10867 
10869  return step_do(c, stack, eval, axis_to_type<axis_following_sibling>());
10870 
10871  case axis_namespace:
10872  // namespaced axis is not supported
10873  return xpath_node_set_raw();
10874 
10875  case axis_parent:
10876  return step_do(c, stack, eval, axis_to_type<axis_parent>());
10877 
10878  case axis_preceding:
10879  return step_do(c, stack, eval, axis_to_type<axis_preceding>());
10880 
10882  return step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>());
10883 
10884  case axis_self:
10885  return step_do(c, stack, eval, axis_to_type<axis_self>());
10886 
10887  default:
10888  assert(false && "Unknown axis"); // unreachable
10889  return xpath_node_set_raw();
10890  }
10891  }
10892 
10893  case ast_step_root:
10894  {
10895  assert(!_right); // root step can't have any predicates
10896 
10897  xpath_node_set_raw ns;
10898 
10899  ns.set_type(xpath_node_set::type_sorted);
10900 
10901  if (c.n.node()) ns.push_back(c.n.node().root(), stack.result);
10902  else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);
10903 
10904  return ns;
10905  }
10906 
10907  case ast_variable:
10908  {
10909  assert(_rettype == _data.variable->type());
10910 
10912  {
10913  const xpath_node_set& s = _data.variable->get_node_set();
10914 
10915  xpath_node_set_raw ns;
10916 
10917  ns.set_type(s.type());
10918  ns.append(s.begin(), s.end(), stack.result);
10919 
10920  return ns;
10921  }
10922  }
10923 
10924  // fallthrough
10925  default:
10926  assert(false && "Wrong expression for return type node set"); // unreachable
10927  return xpath_node_set_raw();
10928  }
10929  }
10930 
10932  {
10933  if (_left)
10934  _left->optimize(alloc);
10935 
10936  if (_right)
10937  _right->optimize(alloc);
10938 
10939  if (_next)
10940  _next->optimize(alloc);
10941 
10942  // coverity[var_deref_model]
10943  optimize_self(alloc);
10944  }
10945 
10947  {
10948  // Rewrite [position()=expr] with [expr]
10949  // Note that this step has to go before classification to recognize [position()=1]
10950  if ((_type == ast_filter || _type == ast_predicate) &&
10951  _right && // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate)
10953  {
10954  _right = _right->_right;
10955  }
10956 
10957  // Classify filter/predicate ops to perform various optimizations during evaluation
10958  if ((_type == ast_filter || _type == ast_predicate) && _right) // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate)
10959  {
10960  assert(_test == predicate_default);
10961 
10962  if (_right->_type == ast_number_constant && _right->_data.number == 1.0)
10968  }
10969 
10970  // Rewrite descendant-or-self::node()/child::foo with descendant::foo
10971  // The former is a full form of //foo, the latter is much faster since it executes the node test immediately
10972  // Do a similar kind of rewrite for self/descendant/descendant-or-self axes
10973  // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1])
10976  is_posinv_step())
10977  {
10978  if (_axis == axis_child || _axis == axis_descendant)
10980  else
10982 
10983  _left = _left->_left;
10984  }
10985 
10986  // Use optimized lookup table implementation for translate() with constant arguments
10987  if (_type == ast_func_translate &&
10988  _right && // workaround for clang static analyzer (_right is never null for ast_func_translate)
10990  {
10991  unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string);
10992 
10993  if (table)
10994  {
10996  _data.table = table;
10997  }
10998  }
10999 
11000  // Use optimized path for @attr = 'value' or @attr = $value
11001  if (_type == ast_op_equal &&
11002  _left && _right && // workaround for clang static analyzer and Coverity (_left and _right are never null for ast_op_equal)
11003  // coverity[mixed_enums]
11006  {
11008  }
11009  }
11010 
11011  bool is_posinv_expr() const
11012  {
11013  switch (_type)
11014  {
11015  case ast_func_position:
11016  case ast_func_last:
11017  return false;
11018 
11019  case ast_string_constant:
11020  case ast_number_constant:
11021  case ast_variable:
11022  return true;
11023 
11024  case ast_step:
11025  case ast_step_root:
11026  return true;
11027 
11028  case ast_predicate:
11029  case ast_filter:
11030  return true;
11031 
11032  default:
11033  if (_left && !_left->is_posinv_expr()) return false;
11034 
11035  for (xpath_ast_node* n = _right; n; n = n->_next)
11036  if (!n->is_posinv_expr()) return false;
11037 
11038  return true;
11039  }
11040  }
11041 
11042  bool is_posinv_step() const
11043  {
11044  assert(_type == ast_step);
11045 
11046  for (xpath_ast_node* n = _right; n; n = n->_next)
11047  {
11048  assert(n->_type == ast_predicate);
11049 
11050  if (n->_test != predicate_posinv)
11051  return false;
11052  }
11053 
11054  return true;
11055  }
11056 
11058  {
11059  return static_cast<xpath_value_type>(_rettype);
11060  }
11061  };
11062 
11064  {
11067 
11068  const char_t* _query;
11069  xpath_variable_set* _variables;
11070 
11071  xpath_parse_result* _result;
11072 
11074 
11075  xpath_ast_node* error(const char* message)
11076  {
11077  _result->error = message;
11078  _result->offset = _lexer.current_pos() - _query;
11079 
11080  return 0;
11081  }
11082 
11084  {
11085  assert(_alloc->_error);
11086  *_alloc->_error = true;
11087 
11088  return 0;
11089  }
11090 
11091  void* alloc_node()
11092  {
11093  return _alloc->allocate(sizeof(xpath_ast_node));
11094  }
11095 
11097  {
11098  void* memory = alloc_node();
11099  return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
11100  }
11101 
11103  {
11104  void* memory = alloc_node();
11105  return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
11106  }
11107 
11108  xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value)
11109  {
11110  void* memory = alloc_node();
11111  return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
11112  }
11113 
11115  {
11116  void* memory = alloc_node();
11117  return memory ? new (memory) xpath_ast_node(type, rettype, left, right) : 0;
11118  }
11119 
11120  xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents)
11121  {
11122  void* memory = alloc_node();
11123  return memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : 0;
11124  }
11125 
11127  {
11128  void* memory = alloc_node();
11129  return memory ? new (memory) xpath_ast_node(type, left, right, test) : 0;
11130  }
11131 
11133  {
11134  if (!value.begin)
11135  return PUGIXML_TEXT("");
11136 
11137  size_t length = static_cast<size_t>(value.end - value.begin);
11138 
11139  char_t* c = static_cast<char_t*>(_alloc->allocate((length + 1) * sizeof(char_t)));
11140  if (!c) return 0;
11141 
11142  memcpy(c, value.begin, length * sizeof(char_t));
11143  c[length] = 0;
11144 
11145  return c;
11146  }
11147 
11149  {
11150  switch (name.begin[0])
11151  {
11152  case 'b':
11153  if (name == PUGIXML_TEXT("boolean") && argc == 1)
11155 
11156  break;
11157 
11158  case 'c':
11159  if (name == PUGIXML_TEXT("count") && argc == 1)
11160  {
11161  if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11162  return alloc_node(ast_func_count, xpath_type_number, args[0]);
11163  }
11164  else if (name == PUGIXML_TEXT("contains") && argc == 2)
11165  return alloc_node(ast_func_contains, xpath_type_boolean, args[0], args[1]);
11166  else if (name == PUGIXML_TEXT("concat") && argc >= 2)
11167  return alloc_node(ast_func_concat, xpath_type_string, args[0], args[1]);
11168  else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
11169  return alloc_node(ast_func_ceiling, xpath_type_number, args[0]);
11170 
11171  break;
11172 
11173  case 'f':
11174  if (name == PUGIXML_TEXT("false") && argc == 0)
11176  else if (name == PUGIXML_TEXT("floor") && argc == 1)
11177  return alloc_node(ast_func_floor, xpath_type_number, args[0]);
11178 
11179  break;
11180 
11181  case 'i':
11182  if (name == PUGIXML_TEXT("id") && argc == 1)
11183  return alloc_node(ast_func_id, xpath_type_node_set, args[0]);
11184 
11185  break;
11186 
11187  case 'l':
11188  if (name == PUGIXML_TEXT("last") && argc == 0)
11190  else if (name == PUGIXML_TEXT("lang") && argc == 1)
11191  return alloc_node(ast_func_lang, xpath_type_boolean, args[0]);
11192  else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
11193  {
11194  if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11196  }
11197 
11198  break;
11199 
11200  case 'n':
11201  if (name == PUGIXML_TEXT("name") && argc <= 1)
11202  {
11203  if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11204  return alloc_node(argc == 0 ? ast_func_name_0 : ast_func_name_1, xpath_type_string, args[0]);
11205  }
11206  else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1)
11207  {
11208  if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11210  }
11211  else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
11212  return alloc_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);
11213  else if (name == PUGIXML_TEXT("not") && argc == 1)
11214  return alloc_node(ast_func_not, xpath_type_boolean, args[0]);
11215  else if (name == PUGIXML_TEXT("number") && argc <= 1)
11216  return alloc_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
11217 
11218  break;
11219 
11220  case 'p':
11221  if (name == PUGIXML_TEXT("position") && argc == 0)
11223 
11224  break;
11225 
11226  case 'r':
11227  if (name == PUGIXML_TEXT("round") && argc == 1)
11228  return alloc_node(ast_func_round, xpath_type_number, args[0]);
11229 
11230  break;
11231 
11232  case 's':
11233  if (name == PUGIXML_TEXT("string") && argc <= 1)
11234  return alloc_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
11235  else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
11237  else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
11238  return alloc_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
11239  else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
11240  return alloc_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
11241  else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
11242  return alloc_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
11243  else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
11244  return alloc_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
11245  else if (name == PUGIXML_TEXT("sum") && argc == 1)
11246  {
11247  if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11248  return alloc_node(ast_func_sum, xpath_type_number, args[0]);
11249  }
11250 
11251  break;
11252 
11253  case 't':
11254  if (name == PUGIXML_TEXT("translate") && argc == 3)
11255  return alloc_node(ast_func_translate, xpath_type_string, args[0], args[1]);
11256  else if (name == PUGIXML_TEXT("true") && argc == 0)
11258 
11259  break;
11260 
11261  default:
11262  break;
11263  }
11264 
11265  return error("Unrecognized function or wrong parameter count");
11266  }
11267 
11269  {
11270  specified = true;
11271 
11272  switch (name.begin[0])
11273  {
11274  case 'a':
11275  if (name == PUGIXML_TEXT("ancestor"))
11276  return axis_ancestor;
11277  else if (name == PUGIXML_TEXT("ancestor-or-self"))
11278  return axis_ancestor_or_self;
11279  else if (name == PUGIXML_TEXT("attribute"))
11280  return axis_attribute;
11281 
11282  break;
11283 
11284  case 'c':
11285  if (name == PUGIXML_TEXT("child"))
11286  return axis_child;
11287 
11288  break;
11289 
11290  case 'd':
11291  if (name == PUGIXML_TEXT("descendant"))
11292  return axis_descendant;
11293  else if (name == PUGIXML_TEXT("descendant-or-self"))
11294  return axis_descendant_or_self;
11295 
11296  break;
11297 
11298  case 'f':
11299  if (name == PUGIXML_TEXT("following"))
11300  return axis_following;
11301  else if (name == PUGIXML_TEXT("following-sibling"))
11302  return axis_following_sibling;
11303 
11304  break;
11305 
11306  case 'n':
11307  if (name == PUGIXML_TEXT("namespace"))
11308  return axis_namespace;
11309 
11310  break;
11311 
11312  case 'p':
11313  if (name == PUGIXML_TEXT("parent"))
11314  return axis_parent;
11315  else if (name == PUGIXML_TEXT("preceding"))
11316  return axis_preceding;
11317  else if (name == PUGIXML_TEXT("preceding-sibling"))
11318  return axis_preceding_sibling;
11319 
11320  break;
11321 
11322  case 's':
11323  if (name == PUGIXML_TEXT("self"))
11324  return axis_self;
11325 
11326  break;
11327 
11328  default:
11329  break;
11330  }
11331 
11332  specified = false;
11333  return axis_child;
11334  }
11335 
11337  {
11338  switch (name.begin[0])
11339  {
11340  case 'c':
11341  if (name == PUGIXML_TEXT("comment"))
11342  return nodetest_type_comment;
11343 
11344  break;
11345 
11346  case 'n':
11347  if (name == PUGIXML_TEXT("node"))
11348  return nodetest_type_node;
11349 
11350  break;
11351 
11352  case 'p':
11353  if (name == PUGIXML_TEXT("processing-instruction"))
11354  return nodetest_type_pi;
11355 
11356  break;
11357 
11358  case 't':
11359  if (name == PUGIXML_TEXT("text"))
11360  return nodetest_type_text;
11361 
11362  break;
11363 
11364  default:
11365  break;
11366  }
11367 
11368  return nodetest_none;
11369  }
11370 
11371  // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
11373  {
11374  switch (_lexer.current())
11375  {
11376  case lex_var_ref:
11377  {
11379 
11380  if (!_variables)
11381  return error("Unknown variable: variable set is not provided");
11382 
11383  xpath_variable* var = 0;
11384  if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var))
11385  return error_oom();
11386 
11387  if (!var)
11388  return error("Unknown variable: variable set does not contain the given name");
11389 
11390  _lexer.next();
11391 
11392  return alloc_node(ast_variable, var->type(), var);
11393  }
11394 
11395  case lex_open_brace:
11396  {
11397  _lexer.next();
11398 
11400  if (!n) return 0;
11401 
11402  if (_lexer.current() != lex_close_brace)
11403  return error("Expected ')' to match an opening '('");
11404 
11405  _lexer.next();
11406 
11407  return n;
11408  }
11409 
11410  case lex_quoted_string:
11411  {
11412  const char_t* value = alloc_string(_lexer.contents());
11413  if (!value) return 0;
11414 
11415  _lexer.next();
11416 
11418  }
11419 
11420  case lex_number:
11421  {
11422  double value = 0;
11423 
11425  return error_oom();
11426 
11427  _lexer.next();
11428 
11430  }
11431 
11432  case lex_string:
11433  {
11434  xpath_ast_node* args[2] = {0};
11435  size_t argc = 0;
11436 
11437  xpath_lexer_string function = _lexer.contents();
11438  _lexer.next();
11439 
11440  xpath_ast_node* last_arg = 0;
11441 
11442  if (_lexer.current() != lex_open_brace)
11443  return error("Unrecognized function call");
11444  _lexer.next();
11445 
11446  while (_lexer.current() != lex_close_brace)
11447  {
11448  if (argc > 0)
11449  {
11450  if (_lexer.current() != lex_comma)
11451  return error("No comma between function arguments");
11452  _lexer.next();
11453  }
11454 
11456  if (!n) return 0;
11457 
11458  if (argc < 2) args[argc] = n;
11459  else last_arg->set_next(n);
11460 
11461  argc++;
11462  last_arg = n;
11463  }
11464 
11465  _lexer.next();
11466 
11467  return parse_function(function, argc, args);
11468  }
11469 
11470  default:
11471  return error("Unrecognizable primary expression");
11472  }
11473  }
11474 
11475  // FilterExpr ::= PrimaryExpr | FilterExpr Predicate
11476  // Predicate ::= '[' PredicateExpr ']'
11477  // PredicateExpr ::= Expr
11479  {
11481  if (!n) return 0;
11482 
11483  while (_lexer.current() == lex_open_square_brace)
11484  {
11485  _lexer.next();
11486 
11487  if (n->rettype() != xpath_type_node_set)
11488  return error("Predicate has to be applied to node set");
11489 
11490  xpath_ast_node* expr = parse_expression();
11491  if (!expr) return 0;
11492 
11493  n = alloc_node(ast_filter, n, expr, predicate_default);
11494  if (!n) return 0;
11495 
11497  return error("Expected ']' to match an opening '['");
11498 
11499  _lexer.next();
11500  }
11501 
11502  return n;
11503  }
11504 
11505  // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
11506  // AxisSpecifier ::= AxisName '::' | '@'?
11507  // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
11508  // NameTest ::= '*' | NCName ':' '*' | QName
11509  // AbbreviatedStep ::= '.' | '..'
11511  {
11512  if (set && set->rettype() != xpath_type_node_set)
11513  return error("Step has to be applied to node set");
11514 
11515  bool axis_specified = false;
11516  axis_t axis = axis_child; // implied child axis
11517 
11519  {
11520  axis = axis_attribute;
11521  axis_specified = true;
11522 
11523  _lexer.next();
11524  }
11525  else if (_lexer.current() == lex_dot)
11526  {
11527  _lexer.next();
11528 
11530  return error("Predicates are not allowed after an abbreviated step");
11531 
11532  return alloc_node(ast_step, set, axis_self, nodetest_type_node, 0);
11533  }
11534  else if (_lexer.current() == lex_double_dot)
11535  {
11536  _lexer.next();
11537 
11539  return error("Predicates are not allowed after an abbreviated step");
11540 
11542  }
11543 
11544  nodetest_t nt_type = nodetest_none;
11545  xpath_lexer_string nt_name;
11546 
11547  if (_lexer.current() == lex_string)
11548  {
11549  // node name test
11550  nt_name = _lexer.contents();
11551  _lexer.next();
11552 
11553  // was it an axis name?
11554  if (_lexer.current() == lex_double_colon)
11555  {
11556  // parse axis name
11557  if (axis_specified)
11558  return error("Two axis specifiers in one step");
11559 
11560  axis = parse_axis_name(nt_name, axis_specified);
11561 
11562  if (!axis_specified)
11563  return error("Unknown axis");
11564 
11565  // read actual node test
11566  _lexer.next();
11567 
11568  if (_lexer.current() == lex_multiply)
11569  {
11570  nt_type = nodetest_all;
11571  nt_name = xpath_lexer_string();
11572  _lexer.next();
11573  }
11574  else if (_lexer.current() == lex_string)
11575  {
11576  nt_name = _lexer.contents();
11577  _lexer.next();
11578  }
11579  else
11580  {
11581  return error("Unrecognized node test");
11582  }
11583  }
11584 
11585  if (nt_type == nodetest_none)
11586  {
11587  // node type test or processing-instruction
11588  if (_lexer.current() == lex_open_brace)
11589  {
11590  _lexer.next();
11591 
11592  if (_lexer.current() == lex_close_brace)
11593  {
11594  _lexer.next();
11595 
11596  nt_type = parse_node_test_type(nt_name);
11597 
11598  if (nt_type == nodetest_none)
11599  return error("Unrecognized node type");
11600 
11601  nt_name = xpath_lexer_string();
11602  }
11603  else if (nt_name == PUGIXML_TEXT("processing-instruction"))
11604  {
11605  if (_lexer.current() != lex_quoted_string)
11606  return error("Only literals are allowed as arguments to processing-instruction()");
11607 
11608  nt_type = nodetest_pi;
11609  nt_name = _lexer.contents();
11610  _lexer.next();
11611 
11612  if (_lexer.current() != lex_close_brace)
11613  return error("Unmatched brace near processing-instruction()");
11614  _lexer.next();
11615  }
11616  else
11617  {
11618  return error("Unmatched brace near node type test");
11619  }
11620  }
11621  // QName or NCName:*
11622  else
11623  {
11624  if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:*
11625  {
11626  nt_name.end--; // erase *
11627 
11628  nt_type = nodetest_all_in_namespace;
11629  }
11630  else
11631  {
11632  nt_type = nodetest_name;
11633  }
11634  }
11635  }
11636  }
11637  else if (_lexer.current() == lex_multiply)
11638  {
11639  nt_type = nodetest_all;
11640  _lexer.next();
11641  }
11642  else
11643  {
11644  return error("Unrecognized node test");
11645  }
11646 
11647  const char_t* nt_name_copy = alloc_string(nt_name);
11648  if (!nt_name_copy) return 0;
11649 
11650  xpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy);
11651  if (!n) return 0;
11652 
11653  xpath_ast_node* last = 0;
11654 
11655  while (_lexer.current() == lex_open_square_brace)
11656  {
11657  _lexer.next();
11658 
11659  xpath_ast_node* expr = parse_expression();
11660  if (!expr) return 0;
11661 
11663  if (!pred) return 0;
11664 
11666  return error("Expected ']' to match an opening '['");
11667  _lexer.next();
11668 
11669  if (last) last->set_next(pred);
11670  else n->set_right(pred);
11671 
11672  last = pred;
11673  }
11674 
11675  return n;
11676  }
11677 
11678  // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
11680  {
11681  xpath_ast_node* n = parse_step(set);
11682  if (!n) return 0;
11683 
11684  while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
11685  {
11686  lexeme_t l = _lexer.current();
11687  _lexer.next();
11688 
11689  if (l == lex_double_slash)
11690  {
11692  if (!n) return 0;
11693  }
11694 
11695  n = parse_step(n);
11696  if (!n) return 0;
11697  }
11698 
11699  return n;
11700  }
11701 
11702  // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
11703  // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
11705  {
11706  if (_lexer.current() == lex_slash)
11707  {
11708  _lexer.next();
11709 
11711  if (!n) return 0;
11712 
11713  // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path
11714  lexeme_t l = _lexer.current();
11715 
11716  if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
11717  return parse_relative_location_path(n);
11718  else
11719  return n;
11720  }
11721  else if (_lexer.current() == lex_double_slash)
11722  {
11723  _lexer.next();
11724 
11726  if (!n) return 0;
11727 
11729  if (!n) return 0;
11730 
11731  return parse_relative_location_path(n);
11732  }
11733 
11734  // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1
11735  return parse_relative_location_path(0);
11736  }
11737 
11738  // PathExpr ::= LocationPath
11739  // | FilterExpr
11740  // | FilterExpr '/' RelativeLocationPath
11741  // | FilterExpr '//' RelativeLocationPath
11742  // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
11743  // UnaryExpr ::= UnionExpr | '-' UnaryExpr
11745  {
11746  // Clarification.
11747  // PathExpr begins with either LocationPath or FilterExpr.
11748  // FilterExpr begins with PrimaryExpr
11749  // PrimaryExpr begins with '$' in case of it being a variable reference,
11750  // '(' in case of it being an expression, string literal, number constant or
11751  // function call.
11754  _lexer.current() == lex_string)
11755  {
11756  if (_lexer.current() == lex_string)
11757  {
11758  // This is either a function call, or not - if not, we shall proceed with location path
11759  const char_t* state = _lexer.state();
11760 
11761  while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
11762 
11763  if (*state != '(')
11764  return parse_location_path();
11765 
11766  // This looks like a function call; however this still can be a node-test. Check it.
11768  return parse_location_path();
11769  }
11770 
11772  if (!n) return 0;
11773 
11775  {
11776  lexeme_t l = _lexer.current();
11777  _lexer.next();
11778 
11779  if (l == lex_double_slash)
11780  {
11781  if (n->rettype() != xpath_type_node_set)
11782  return error("Step has to be applied to node set");
11783 
11785  if (!n) return 0;
11786  }
11787 
11788  // select from location path
11789  return parse_relative_location_path(n);
11790  }
11791 
11792  return n;
11793  }
11794  else if (_lexer.current() == lex_minus)
11795  {
11796  _lexer.next();
11797 
11798  // precedence 7+ - only parses union expressions
11800  if (!n) return 0;
11801 
11803  }
11804  else
11805  {
11806  return parse_location_path();
11807  }
11808  }
11809 
11811  {
11815 
11817  {
11818  }
11819 
11820  binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_)
11821  {
11822  }
11823 
11825  {
11826  switch (lexer.current())
11827  {
11828  case lex_string:
11829  if (lexer.contents() == PUGIXML_TEXT("or"))
11831  else if (lexer.contents() == PUGIXML_TEXT("and"))
11833  else if (lexer.contents() == PUGIXML_TEXT("div"))
11835  else if (lexer.contents() == PUGIXML_TEXT("mod"))
11837  else
11838  return binary_op_t();
11839 
11840  case lex_equal:
11842 
11843  case lex_not_equal:
11845 
11846  case lex_less:
11848 
11849  case lex_greater:
11851 
11852  case lex_less_or_equal:
11854 
11855  case lex_greater_or_equal:
11857 
11858  case lex_plus:
11860 
11861  case lex_minus:
11863 
11864  case lex_multiply:
11866 
11867  case lex_union:
11869 
11870  default:
11871  return binary_op_t();
11872  }
11873  }
11874  };
11875 
11877  {
11879 
11880  while (op.asttype != ast_unknown && op.precedence >= limit)
11881  {
11882  _lexer.next();
11883 
11885  if (!rhs) return 0;
11886 
11888 
11889  while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)
11890  {
11891  rhs = parse_expression_rec(rhs, nextop.precedence);
11892  if (!rhs) return 0;
11893 
11894  nextop = binary_op_t::parse(_lexer);
11895  }
11896 
11897  if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))
11898  return error("Union operator has to be applied to node sets");
11899 
11900  lhs = alloc_node(op.asttype, op.rettype, lhs, rhs);
11901  if (!lhs) return 0;
11902 
11903  op = binary_op_t::parse(_lexer);
11904  }
11905 
11906  return lhs;
11907  }
11908 
11909  // Expr ::= OrExpr
11910  // OrExpr ::= AndExpr | OrExpr 'or' AndExpr
11911  // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
11912  // EqualityExpr ::= RelationalExpr
11913  // | EqualityExpr '=' RelationalExpr
11914  // | EqualityExpr '!=' RelationalExpr
11915  // RelationalExpr ::= AdditiveExpr
11916  // | RelationalExpr '<' AdditiveExpr
11917  // | RelationalExpr '>' AdditiveExpr
11918  // | RelationalExpr '<=' AdditiveExpr
11919  // | RelationalExpr '>=' AdditiveExpr
11920  // AdditiveExpr ::= MultiplicativeExpr
11921  // | AdditiveExpr '+' MultiplicativeExpr
11922  // | AdditiveExpr '-' MultiplicativeExpr
11923  // MultiplicativeExpr ::= UnaryExpr
11924  // | MultiplicativeExpr '*' UnaryExpr
11925  // | MultiplicativeExpr 'div' UnaryExpr
11926  // | MultiplicativeExpr 'mod' UnaryExpr
11928  {
11930  if (!n) return 0;
11931 
11932  return parse_expression_rec(n, limit);
11933  }
11934 
11935  xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result)
11936  {
11937  }
11938 
11940  {
11942  if (!n) return 0;
11943 
11944  // check if there are unparsed tokens left
11945  if (_lexer.current() != lex_eof)
11946  return error("Incorrect query");
11947 
11948  return n;
11949  }
11950 
11951  static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)
11952  {
11953  xpath_parser parser(query, variables, alloc, result);
11954 
11955  return parser.parse();
11956  }
11957  };
11958 
11960  {
11962  {
11963  void* memory = xml_memory::allocate(sizeof(xpath_query_impl));
11964  if (!memory) return 0;
11965 
11966  return new (memory) xpath_query_impl();
11967  }
11968 
11969  static void destroy(xpath_query_impl* impl)
11970  {
11971  // free all allocated pages
11972  impl->alloc.release();
11973 
11974  // free allocator memory (with the first page)
11975  xml_memory::deallocate(impl);
11976  }
11977 
11979  {
11980  block.next = 0;
11981  block.capacity = sizeof(block.data);
11982  }
11983 
11987  bool oom;
11988  };
11989 
11991  {
11992  if (!impl) return 0;
11993 
11994  if (impl->root->rettype() != xpath_type_node_set)
11995  {
11996  #ifdef PUGIXML_NO_EXCEPTIONS
11997  return 0;
11998  #else
11999  xpath_parse_result res;
12000  res.error = "Expression does not evaluate to node set";
12001 
12002  throw xpath_exception(res);
12003  #endif
12004  }
12005 
12006  return impl->root;
12007  }
12009 
12010 namespace pugi
12011 {
12012 #ifndef PUGIXML_NO_EXCEPTIONS
12014  {
12015  assert(_result.error);
12016  }
12017 
12018  PUGI__FN const char* xpath_exception::what() const throw()
12019  {
12020  return _result.error;
12021  }
12022 
12024  {
12025  return _result;
12026  }
12027 #endif
12028 
12030  {
12031  }
12032 
12033  PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_)
12034  {
12035  }
12036 
12037  PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
12038  {
12039  }
12040 
12042  {
12043  return _attribute ? xml_node() : _node;
12044  }
12045 
12047  {
12048  return _attribute;
12049  }
12050 
12052  {
12053  return _attribute ? _node : _node.parent();
12054  }
12055 
12057  {
12058  }
12059 
12060  PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const
12061  {
12062  return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
12063  }
12064 
12066  {
12067  return !(_node || _attribute);
12068  }
12069 
12071  {
12072  return _node == n._node && _attribute == n._attribute;
12073  }
12074 
12076  {
12077  return _node != n._node || _attribute != n._attribute;
12078  }
12079 
12080 #ifdef __BORLANDC__
12081  PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs)
12082  {
12083  return (bool)lhs && rhs;
12084  }
12085 
12086  PUGI__FN bool operator||(const xpath_node& lhs, bool rhs)
12087  {
12088  return (bool)lhs || rhs;
12089  }
12090 #endif
12091 
12093  {
12094  assert(begin_ <= end_);
12095 
12096  size_t size_ = static_cast<size_t>(end_ - begin_);
12097 
12098  // use internal buffer for 0 or 1 elements, heap buffer otherwise
12099  xpath_node* storage = (size_ <= 1) ? _storage : static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
12100 
12101  if (!storage)
12102  {
12103  #ifdef PUGIXML_NO_EXCEPTIONS
12104  return;
12105  #else
12106  throw std::bad_alloc();
12107  #endif
12108  }
12109 
12110  // deallocate old buffer
12111  if (_begin != _storage)
12112  impl::xml_memory::deallocate(_begin);
12113 
12114  // size check is necessary because for begin_ = end_ = nullptr, memcpy is UB
12115  if (size_)
12116  memcpy(storage, begin_, size_ * sizeof(xpath_node));
12117 
12118  _begin = storage;
12119  _end = storage + size_;
12120  _type = type_;
12121  }
12122 
12123 #ifdef PUGIXML_HAS_MOVE
12125  {
12126  _type = rhs._type;
12127  _storage[0] = rhs._storage[0];
12128  _begin = (rhs._begin == rhs._storage) ? _storage : rhs._begin;
12129  _end = _begin + (rhs._end - rhs._begin);
12130 
12131  rhs._type = type_unsorted;
12132  rhs._begin = rhs._storage;
12133  rhs._end = rhs._storage;
12134  }
12135 #endif
12136 
12137  PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage)
12138  {
12139  }
12140 
12141  PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage)
12142  {
12143  _assign(begin_, end_, type_);
12144  }
12145 
12147  {
12148  if (_begin != _storage)
12149  impl::xml_memory::deallocate(_begin);
12150  }
12151 
12152  PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage)
12153  {
12154  _assign(ns._begin, ns._end, ns._type);
12155  }
12156 
12158  {
12159  if (this == &ns) return *this;
12160 
12161  _assign(ns._begin, ns._end, ns._type);
12162 
12163  return *this;
12164  }
12165 
12166 #ifdef PUGIXML_HAS_MOVE
12167  PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage)
12168  {
12169  _move(rhs);
12170  }
12171 
12172  PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT
12173  {
12174  if (this == &rhs) return *this;
12175 
12176  if (_begin != _storage)
12177  impl::xml_memory::deallocate(_begin);
12178 
12179  _move(rhs);
12180 
12181  return *this;
12182  }
12183 #endif
12184 
12186  {
12187  return _type;
12188  }
12189 
12191  {
12192  return _end - _begin;
12193  }
12194 
12196  {
12197  return _begin == _end;
12198  }
12199 
12201  {
12202  assert(index < size());
12203  return _begin[index];
12204  }
12205 
12207  {
12208  return _begin;
12209  }
12210 
12212  {
12213  return _end;
12214  }
12215 
12217  {
12219  }
12220 
12222  {
12223  return impl::xpath_first(_begin, _end, _type);
12224  }
12225 
12226  PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
12227  {
12228  }
12229 
12230  PUGI__FN xpath_parse_result::operator bool() const
12231  {
12232  return error == 0;
12233  }
12234 
12236  {
12237  return error ? error : "No error";
12238  }
12239 
12241  {
12242  }
12243 
12245  {
12246  switch (_type)
12247  {
12248  case xpath_type_node_set:
12249  return static_cast<const impl::xpath_variable_node_set*>(this)->name;
12250 
12251  case xpath_type_number:
12252  return static_cast<const impl::xpath_variable_number*>(this)->name;
12253 
12254  case xpath_type_string:
12255  return static_cast<const impl::xpath_variable_string*>(this)->name;
12256 
12257  case xpath_type_boolean:
12258  return static_cast<const impl::xpath_variable_boolean*>(this)->name;
12259 
12260  default:
12261  assert(false && "Invalid variable type"); // unreachable
12262  return 0;
12263  }
12264  }
12265 
12267  {
12268  return _type;
12269  }
12270 
12272  {
12273  return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
12274  }
12275 
12277  {
12278  return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();
12279  }
12280 
12282  {
12283  const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0;
12284  return value ? value : PUGIXML_TEXT("");
12285  }
12286 
12288  {
12289  return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
12290  }
12291 
12293  {
12294  if (_type != xpath_type_boolean) return false;
12295 
12296  static_cast<impl::xpath_variable_boolean*>(this)->value = value;
12297  return true;
12298  }
12299 
12300  PUGI__FN bool xpath_variable::set(double value)
12301  {
12302  if (_type != xpath_type_number) return false;
12303 
12304  static_cast<impl::xpath_variable_number*>(this)->value = value;
12305  return true;
12306  }
12307 
12309  {
12310  if (_type != xpath_type_string) return false;
12311 
12312  impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);
12313 
12314  // duplicate string
12315  size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
12316 
12317  char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));
12318  if (!copy) return false;
12319 
12320  memcpy(copy, value, size);
12321 
12322  // replace old string
12323  if (var->value) impl::xml_memory::deallocate(var->value);
12324  var->value = copy;
12325 
12326  return true;
12327  }
12328 
12330  {
12331  if (_type != xpath_type_node_set) return false;
12332 
12333  static_cast<impl::xpath_variable_node_set*>(this)->value = value;
12334  return true;
12335  }
12336 
12338  {
12339  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12340  _data[i] = 0;
12341  }
12342 
12344  {
12345  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12346  _destroy(_data[i]);
12347  }
12348 
12350  {
12351  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12352  _data[i] = 0;
12353 
12354  _assign(rhs);
12355  }
12356 
12358  {
12359  if (this == &rhs) return *this;
12360 
12361  _assign(rhs);
12362 
12363  return *this;
12364  }
12365 
12366 #ifdef PUGIXML_HAS_MOVE
12368  {
12369  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12370  {
12371  _data[i] = rhs._data[i];
12372  rhs._data[i] = 0;
12373  }
12374  }
12375 
12376  PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT
12377  {
12378  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12379  {
12380  _destroy(_data[i]);
12381 
12382  _data[i] = rhs._data[i];
12383  rhs._data[i] = 0;
12384  }
12385 
12386  return *this;
12387  }
12388 #endif
12389 
12391  {
12392  xpath_variable_set temp;
12393 
12394  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12395  if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))
12396  return;
12397 
12398  _swap(temp);
12399  }
12400 
12402  {
12403  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12404  {
12405  xpath_variable* chain = _data[i];
12406 
12407  _data[i] = rhs._data[i];
12408  rhs._data[i] = chain;
12409  }
12410  }
12411 
12413  {
12414  const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
12415  size_t hash = impl::hash_string(name) % hash_size;
12416 
12417  // look for existing variable
12418  for (xpath_variable* var = _data[hash]; var; var = var->_next)
12419  if (impl::strequal(var->name(), name))
12420  return var;
12421 
12422  return 0;
12423  }
12424 
12426  {
12427  xpath_variable* last = 0;
12428 
12429  while (var)
12430  {
12431  // allocate storage for new variable
12432  xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
12433  if (!nvar) return false;
12434 
12435  // link the variable to the result immediately to handle failures gracefully
12436  if (last)
12437  last->_next = nvar;
12438  else
12439  *out_result = nvar;
12440 
12441  last = nvar;
12442 
12443  // copy the value; this can fail due to out-of-memory conditions
12444  if (!impl::copy_xpath_variable(nvar, var)) return false;
12445 
12446  var = var->_next;
12447  }
12448 
12449  return true;
12450  }
12451 
12453  {
12454  while (var)
12455  {
12456  xpath_variable* next = var->_next;
12457 
12459 
12460  var = next;
12461  }
12462  }
12463 
12465  {
12466  const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
12467  size_t hash = impl::hash_string(name) % hash_size;
12468 
12469  // look for existing variable
12470  for (xpath_variable* var = _data[hash]; var; var = var->_next)
12471  if (impl::strequal(var->name(), name))
12472  return var->type() == type ? var : 0;
12473 
12474  // add new variable
12475  xpath_variable* result = impl::new_xpath_variable(type, name);
12476 
12477  if (result)
12478  {
12479  result->_next = _data[hash];
12480 
12481  _data[hash] = result;
12482  }
12483 
12484  return result;
12485  }
12486 
12487  PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value)
12488  {
12490  return var ? var->set(value) : false;
12491  }
12492 
12493  PUGI__FN bool xpath_variable_set::set(const char_t* name, double value)
12494  {
12496  return var ? var->set(value) : false;
12497  }
12498 
12500  {
12502  return var ? var->set(value) : false;
12503  }
12504 
12506  {
12508  return var ? var->set(value) : false;
12509  }
12510 
12512  {
12513  return _find(name);
12514  }
12515 
12517  {
12518  return _find(name);
12519  }
12520 
12521  PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
12522  {
12523  impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
12524 
12525  if (!qimpl)
12526  {
12527  #ifdef PUGIXML_NO_EXCEPTIONS
12528  _result.error = "Out of memory";
12529  #else
12530  throw std::bad_alloc();
12531  #endif
12532  }
12533  else
12534  {
12535  using impl::auto_deleter; // MSVC7 workaround
12536  auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);
12537 
12538  qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
12539 
12540  if (qimpl->root)
12541  {
12542  qimpl->root->optimize(&qimpl->alloc);
12543 
12544  _impl = impl.release();
12545  _result.error = 0;
12546  }
12547  else
12548  {
12549  #ifdef PUGIXML_NO_EXCEPTIONS
12550  if (qimpl->oom) _result.error = "Out of memory";
12551  #else
12552  if (qimpl->oom) throw std::bad_alloc();
12553  throw xpath_exception(_result);
12554  #endif
12555  }
12556  }
12557  }
12558 
12560  {
12561  }
12562 
12564  {
12565  if (_impl)
12566  impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
12567  }
12568 
12569 #ifdef PUGIXML_HAS_MOVE
12571  {
12572  _impl = rhs._impl;
12573  _result = rhs._result;
12574  rhs._impl = 0;
12575  rhs._result = xpath_parse_result();
12576  }
12577 
12578  PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT
12579  {
12580  if (this == &rhs) return *this;
12581 
12582  if (_impl)
12583  impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
12584 
12585  _impl = rhs._impl;
12586  _result = rhs._result;
12587  rhs._impl = 0;
12588  rhs._result = xpath_parse_result();
12589 
12590  return *this;
12591  }
12592 #endif
12593 
12595  {
12596  if (!_impl) return xpath_type_none;
12597 
12598  return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();
12599  }
12600 
12602  {
12603  if (!_impl) return false;
12604 
12605  impl::xpath_context c(n, 1, 1);
12606  impl::xpath_stack_data sd;
12607 
12608  bool r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
12609 
12610  if (sd.oom)
12611  {
12612  #ifdef PUGIXML_NO_EXCEPTIONS
12613  return false;
12614  #else
12615  throw std::bad_alloc();
12616  #endif
12617  }
12618 
12619  return r;
12620  }
12621 
12623  {
12624  if (!_impl) return impl::gen_nan();
12625 
12626  impl::xpath_context c(n, 1, 1);
12627  impl::xpath_stack_data sd;
12628 
12629  double r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
12630 
12631  if (sd.oom)
12632  {
12633  #ifdef PUGIXML_NO_EXCEPTIONS
12634  return impl::gen_nan();
12635  #else
12636  throw std::bad_alloc();
12637  #endif
12638  }
12639 
12640  return r;
12641  }
12642 
12643 #ifndef PUGIXML_NO_STL
12645  {
12646  if (!_impl) return string_t();
12647 
12648  impl::xpath_context c(n, 1, 1);
12649  impl::xpath_stack_data sd;
12650 
12651  impl::xpath_string r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_string(c, sd.stack);
12652 
12653  if (sd.oom)
12654  {
12655  #ifdef PUGIXML_NO_EXCEPTIONS
12656  return string_t();
12657  #else
12658  throw std::bad_alloc();
12659  #endif
12660  }
12661 
12662  return string_t(r.c_str(), r.length());
12663  }
12664 #endif
12665 
12666  PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
12667  {
12668  impl::xpath_context c(n, 1, 1);
12669  impl::xpath_stack_data sd;
12670 
12671  impl::xpath_string r = _impl ? static_cast<impl::xpath_query_impl*>(_impl)->root->eval_string(c, sd.stack) : impl::xpath_string();
12672 
12673  if (sd.oom)
12674  {
12675  #ifdef PUGIXML_NO_EXCEPTIONS
12676  r = impl::xpath_string();
12677  #else
12678  throw std::bad_alloc();
12679  #endif
12680  }
12681 
12682  size_t full_size = r.length() + 1;
12683 
12684  if (capacity > 0)
12685  {
12686  size_t size = (full_size < capacity) ? full_size : capacity;
12687  assert(size > 0);
12688 
12689  memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
12690  buffer[size - 1] = 0;
12691  }
12692 
12693  return full_size;
12694  }
12695 
12697  {
12698  impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
12699  if (!root) return xpath_node_set();
12700 
12701  impl::xpath_context c(n, 1, 1);
12702  impl::xpath_stack_data sd;
12703 
12704  impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
12705 
12706  if (sd.oom)
12707  {
12708  #ifdef PUGIXML_NO_EXCEPTIONS
12709  return xpath_node_set();
12710  #else
12711  throw std::bad_alloc();
12712  #endif
12713  }
12714 
12715  return xpath_node_set(r.begin(), r.end(), r.type());
12716  }
12717 
12719  {
12720  impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
12721  if (!root) return xpath_node();
12722 
12723  impl::xpath_context c(n, 1, 1);
12724  impl::xpath_stack_data sd;
12725 
12726  impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);
12727 
12728  if (sd.oom)
12729  {
12730  #ifdef PUGIXML_NO_EXCEPTIONS
12731  return xpath_node();
12732  #else
12733  throw std::bad_alloc();
12734  #endif
12735  }
12736 
12737  return r.first();
12738  }
12739 
12741  {
12742  return _result;
12743  }
12744 
12746  {
12747  }
12748 
12749  PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
12750  {
12751  return _impl ? unspecified_bool_xpath_query : 0;
12752  }
12753 
12755  {
12756  return !_impl;
12757  }
12758 
12760  {
12761  xpath_query q(query, variables);
12762  return q.evaluate_node(*this);
12763  }
12764 
12766  {
12767  return query.evaluate_node(*this);
12768  }
12769 
12771  {
12772  xpath_query q(query, variables);
12773  return q.evaluate_node_set(*this);
12774  }
12775 
12777  {
12778  return query.evaluate_node_set(*this);
12779  }
12780 
12782  {
12783  xpath_query q(query, variables);
12784  return q.evaluate_node(*this);
12785  }
12786 
12788  {
12789  return query.evaluate_node(*this);
12790  }
12791 }
12792 
12793 #endif
12794 
12795 #ifdef __BORLANDC__
12796 # pragma option pop
12797 #endif
12798 
12799 // Intel C++ does not properly keep warning state for function templates,
12800 // so popping warning state at the end of translation unit leads to warnings in the middle.
12801 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
12802 # pragma warning(pop)
12803 #endif
12804 
12805 #if defined(_MSC_VER) && defined(__c2__)
12806 # pragma clang diagnostic pop
12807 #endif
12808 
12809 // Undefine all local macros (makes sure we're not leaking macros in header-only mode)
12810 #undef PUGI__NO_INLINE
12811 #undef PUGI__UNLIKELY
12812 #undef PUGI__STATIC_ASSERT
12813 #undef PUGI__DMC_VOLATILE
12814 #undef PUGI__UNSIGNED_OVERFLOW
12815 #undef PUGI__MSVC_CRT_VERSION
12816 #undef PUGI__SNPRINTF
12817 #undef PUGI__NS_BEGIN
12818 #undef PUGI__NS_END
12819 #undef PUGI__FN
12820 #undef PUGI__FN_NO_INLINE
12821 #undef PUGI__GETHEADER_IMPL
12822 #undef PUGI__GETPAGE_IMPL
12823 #undef PUGI__GETPAGE
12824 #undef PUGI__NODETYPE
12825 #undef PUGI__IS_CHARTYPE_IMPL
12826 #undef PUGI__IS_CHARTYPE
12827 #undef PUGI__IS_CHARTYPEX
12828 #undef PUGI__ENDSWITH
12829 #undef PUGI__SKIPWS
12830 #undef PUGI__OPTSET
12831 #undef PUGI__PUSHNODE
12832 #undef PUGI__POPNODE
12833 #undef PUGI__SCANFOR
12834 #undef PUGI__SCANWHILE
12835 #undef PUGI__SCANWHILE_UNROLL
12836 #undef PUGI__ENDSEG
12837 #undef PUGI__THROW_ERROR
12838 #undef PUGI__CHECK_ERROR
12839 
12840 #endif
12841 
xpath_variable_string::~xpath_variable_string
~xpath_variable_string()
Definition: pugixml.cpp:8596
pugi::status_bad_cdata
@ status_bad_cdata
Definition: pugixml.hpp:964
xpath_parser::_lexer
xpath_lexer _lexer
Definition: pugixml.cpp:11066
xpath_parser::alloc_node
xpath_ast_node * alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node *left=0, xpath_ast_node *right=0)
Definition: pugixml.cpp:11114
pugi::xpath_node::_node
xml_node _node
Definition: pugixml.hpp:1292
xml_buffered_writer::data_char
char_t data_char[bufcapacity]
Definition: pugixml.cpp:3898
pugi::xpath_variable_set::_data
xpath_variable * _data[64]
Definition: pugixml.hpp:1147
pugi::xml_node::select_single_node
PUGIXML_DEPRECATED xpath_node select_single_node(const char_t *query, xpath_variable_set *variables=0) const
Definition: pugixml.cpp:12781
xpath_context
Definition: pugixml.cpp:8969
opt_true::value
@ value
Definition: pugixml.cpp:1432
utf16_writer::any
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:1551
ast_opt_translate_table
@ ast_opt_translate_table
Definition: pugixml.cpp:9393
pugi::parse_ws_pcdata
const unsigned int parse_ws_pcdata
Definition: pugixml.hpp:168
strlength
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN size_t strlength(const char_t *s)
Definition: pugixml.cpp:212
ast_type_t
ast_type_t
Definition: pugixml.cpp:9333
utf32_counter
Definition: pugixml.cpp:1558
pugi::xml_attribute
Definition: pugixml.hpp:349
wchar_selector< 4 >::type
uint32_t type
Definition: pugixml.cpp:1797
check_string_to_number_format
PUGI__FN bool check_string_to_number_format(const char_t *string)
Definition: pugixml.cpp:8294
pugi::xpath_exception::xpath_exception
xpath_exception(const xpath_parse_result &result)
Definition: pugixml.cpp:12013
strcpy_insitu_allow
bool strcpy_insitu_allow(size_t length, const Header &header, uintptr_t header_mask, char_t *target)
Definition: pugixml.cpp:2339
node_is_ancestor
PUGI__FN bool node_is_ancestor(xml_node_struct *parent, xml_node_struct *node)
Definition: pugixml.cpp:8018
xpath_string::from_heap
static xpath_string from_heap(const char_t *begin, const char_t *end, xpath_allocator *alloc)
Definition: pugixml.cpp:7758
pugi::parse_cdata
const unsigned int parse_cdata
Definition: pugixml.hpp:164
pugi::string_t
std::basic_string< PUGIXML_CHAR, std::char_traits< PUGIXML_CHAR >, std::allocator< PUGIXML_CHAR > > string_t
Definition: pugixml.hpp:130
PUGIXML_NOEXCEPT
#define PUGIXML_NOEXCEPT
Definition: pugixml.hpp:92
xpath_stack_data::temp
xpath_allocator temp
Definition: pugixml.cpp:7701
PUGI__GETPAGE
#define PUGI__GETPAGE(n)
Definition: pugixml.cpp:453
pugi::xpath_node_set::end
const_iterator end() const
Definition: pugixml.cpp:12211
pugi::status_bad_attribute
@ status_bad_attribute
Definition: pugixml.hpp:968
utf16_decoder::type
uint16_t type
Definition: pugixml.cpp:1688
axis_descendant
@ axis_descendant
Definition: pugixml.cpp:9403
PUGI__IS_CHARTYPE
#define PUGI__IS_CHARTYPE(c, ct)
Definition: pugixml.cpp:1898
xpath_parser::binary_op_t
Definition: pugixml.cpp:11811
pugi::xml_attribute_iterator::operator--
const xml_attribute_iterator & operator--()
Definition: pugixml.cpp:6727
namespace_uri
PUGI__FN const char_t * namespace_uri(xml_node node)
Definition: pugixml.cpp:8409
pugi::parse_ws_pcdata_single
const unsigned int parse_ws_pcdata_single
Definition: pugixml.hpp:191
xpath_lexer_string::operator==
bool operator==(const char_t *other) const
Definition: pugixml.cpp:9018
pugi::xml_node::previous_sibling
xml_node previous_sibling() const
Definition: pugixml.cpp:5576
pugi::xml_attribute::as_string
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition: pugixml.cpp:5170
pugi::xpath_variable_set::xpath_variable_set
xpath_variable_set()
Definition: pugixml.cpp:12337
utf8_decoder::type
uint8_t type
Definition: pugixml.cpp:1621
copy_xpath_variable
PUGI__FN bool copy_xpath_variable(xpath_variable *lhs, const xpath_variable *rhs)
Definition: pugixml.cpp:8704
pugi::xml_text::as_bool
bool as_bool(bool def=false) const
Definition: pugixml.cpp:6444
pugi::status_io_error
@ status_io_error
Definition: pugixml.hpp:956
axis_ancestor_or_self
@ axis_ancestor_or_self
Definition: pugixml.cpp:9400
pugi::xml_node_iterator::xml_node_iterator
xml_node_iterator()
Definition: pugixml.cpp:6618
xpath_node_set_raw::end
xpath_node * end() const
Definition: pugixml.cpp:8831
strconv_attribute_impl::parse_wconv
static char_t * parse_wconv(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2782
xpath_allocator::_error
bool * _error
Definition: pugixml.cpp:7551
xpath_ast_node::xpath_ast_node
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node *left=0, xpath_ast_node *right=0)
Definition: pugixml.cpp:10221
pugi::xml_node::last_child
xml_node last_child() const
Definition: pugixml.cpp:5634
xpath_query_impl::alloc
xpath_allocator alloc
Definition: pugixml.cpp:11985
strconv_escape
PUGI__FN char_t * strconv_escape(char_t *s, gap &g)
Definition: pugixml.cpp:2446
pugi::xpath_variable_set::operator=
xpath_variable_set & operator=(const xpath_variable_set &rhs)
Definition: pugixml.cpp:12357
strcpy_insitu
PUGI__FN bool strcpy_insitu(String &dest, Header &header, uintptr_t header_mask, const char_t *source, size_t source_length)
Definition: pugixml.cpp:2356
xpath_ast_node::optimize_self
void optimize_self(xpath_allocator *alloc)
Definition: pugixml.cpp:10946
document_order_comparator::operator()
bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
Definition: pugixml.cpp:8058
pugi::xml_node_struct::prev_sibling_c
xml_node_struct * prev_sibling_c
Definition: pugixml.cpp:1126
ast_func_translate
@ ast_func_translate
Definition: pugixml.cpp:9378
xpath_parser::alloc_string
const char_t * alloc_string(const xpath_lexer_string &value)
Definition: pugixml.cpp:11132
xpath_parser::binary_op_t::precedence
int precedence
Definition: pugixml.cpp:11814
xpath_parser::parse
xpath_ast_node * parse()
Definition: pugixml.cpp:11939
pugi::xml_text::xml_node
friend class xml_node
Definition: pugixml.hpp:711
pugi::xml_node::select_node
xpath_node select_node(const char_t *query, xpath_variable_set *variables=0) const
Definition: pugixml.cpp:12759
pugi::xml_node_iterator::operator->
xml_node * operator->() const
Definition: pugixml.cpp:6646
pugi::xpath_node::xpath_node
xpath_node()
Definition: pugixml.cpp:12029
convert_path_heap
PUGI__FN char * convert_path_heap(const wchar_t *str)
Definition: pugixml.cpp:4979
ast_func_last
@ ast_func_last
Definition: pugixml.cpp:9355
node_output_comment
PUGI__FN void node_output_comment(xml_buffered_writer &writer, const char_t *s)
Definition: pugixml.cpp:4028
xml_allocator::_root
xml_memory_page * _root
Definition: pugixml.cpp:699
pugi::xml_node_iterator::_wrap
xml_node _wrap
Definition: pugixml.hpp:803
pugi::get_memory_allocation_function
allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
Definition: pugixml.cpp:7259
lex_less
@ lex_less
Definition: pugixml.cpp:8983
pugi::xpath_variable_set::_assign
void _assign(const xpath_variable_set &rhs)
Definition: pugixml.cpp:12390
pugi::xml_node::empty
bool empty() const
Definition: pugixml.cpp:5477
pugi::xpath_node
Definition: pugixml.hpp:1290
pugi::xml_named_node_iterator::_parent
xml_node _parent
Definition: pugixml.hpp:918
pugi::xml_attribute::as_float
float as_float(float def=0) const
Definition: pugixml.cpp:5190
pugi::xpath_node_set::_move
void _move(xpath_node_set &rhs) PUGIXML_NOEXCEPT
get_document
xml_document_struct & get_document(const Object *object)
Definition: pugixml.cpp:1163
pugi::xpath_exception::what
virtual const char * what() const PUGIXML_OVERRIDE
Definition: pugixml.cpp:12018
wchar_selector< 2 >::counter
utf16_counter counter
Definition: pugixml.cpp:1790
xpath_node_set_raw::sort_do
void sort_do()
Definition: pugixml.cpp:8885
document_buffer_order
PUGI__FN const void * document_buffer_order(const xpath_node &xnode)
Definition: pugixml.cpp:8025
pugi::xml_text::as_int
int as_int(int def=0) const
Definition: pugixml.cpp:6416
pugi::xml_node::offset_debug
ptrdiff_t offset_debug() const
Definition: pugixml.cpp:6309
xpath_variable_boolean::name
char_t name[1]
Definition: pugixml.cpp:8577
pugi::xml_node::select_nodes
xpath_node_set select_nodes(const char_t *query, xpath_variable_set *variables=0) const
Definition: pugixml.cpp:12770
PUGI__IS_CHARTYPEX
#define PUGI__IS_CHARTYPEX(c, ct)
Definition: pugixml.cpp:1899
auto_deleter::release
T * release()
Definition: pugixml.cpp:278
ast_func_starts_with
@ ast_func_starts_with
Definition: pugixml.cpp:9368
pugi::format_indent
const unsigned int format_indent
Definition: pugixml.hpp:233
xpath_variable_node_set::name
char_t name[1]
Definition: pugixml.cpp:8612
pugi::xml_document::load_file
xml_parse_result load_file(const char *path, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7115
node_output_start
PUGI__FN bool node_output_start(xml_buffered_writer &writer, xml_node_struct *node, const char_t *indent, size_t indent_length, unsigned int flags, unsigned int depth)
Definition: pugixml.cpp:4102
pugi::xpath_variable::set
bool set(bool value)
Definition: pugixml.cpp:12292
pugi::node_null
@ node_null
Definition: pugixml.hpp:140
xpath_parser::_alloc
xpath_allocator * _alloc
Definition: pugixml.cpp:11065
pugi::xml_node::attributes_end
attribute_iterator attributes_end() const
Definition: pugixml.cpp:5427
utf8_counter::value_type
size_t value_type
Definition: pugixml.cpp:1450
round_nearest_nzero
PUGI__FN double round_nearest_nzero(double value)
Definition: pugixml.cpp:8366
ct_space
@ ct_space
Definition: pugixml.cpp:1833
pugi::xml_named_node_iterator::operator--
const xml_named_node_iterator & operator--()
Definition: pugixml.cpp:6788
pugi::xml_node::insert_move_before
xml_node insert_move_before(const xml_node &moved, const xml_node &node)
Definition: pugixml.cpp:6025
xpath_parser::parse_path_or_unary_expression
xpath_ast_node * parse_path_or_unary_expression()
Definition: pugixml.cpp:11744
pugi::xpath_node_set::_type
type_t _type
Definition: pugixml.hpp:1389
xpath_variable_string
Definition: pugixml.cpp:8591
xpath_parser::parse_expression
xpath_ast_node * parse_expression(int limit=0)
Definition: pugixml.cpp:11927
ast_number_constant
@ ast_number_constant
Definition: pugixml.cpp:9353
xml_memory
xml_memory_management_function_storage< int > xml_memory
Definition: pugixml.cpp:206
dummy_node_set
static const xpath_node_set dummy_node_set
Definition: pugixml.cpp:8615
xpath_string::from_const
static xpath_string from_const(const char_t *str)
Definition: pugixml.cpp:7746
destroy_attribute
void destroy_attribute(xml_attribute_struct *a, xml_allocator &alloc)
Definition: pugixml.cpp:1191
pugi::xml_node::children
xml_object_range< xml_node_iterator > children() const
Definition: pugixml.cpp:5432
xpath_lexer_string::end
const char_t * end
Definition: pugixml.cpp:9012
append_attribute
void append_attribute(xml_attribute_struct *attr, xml_node_struct *node)
Definition: pugixml.cpp:1323
xpath_stack_data::blocks
xpath_memory_block blocks[2]
Definition: pugixml.cpp:7699
pugi::xml_attribute::name
const char_t * name() const
Definition: pugixml.cpp:5217
xpath_sort
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:8769
ast_op_add
@ ast_op_add
Definition: pugixml.cpp:9343
pugi::status_bad_doctype
@ status_bad_doctype
Definition: pugixml.hpp:965
pugi::xml_attribute_struct
Definition: pugixml.cpp:1095
get_write_native_encoding
PUGI__FN xml_encoding get_write_native_encoding()
Definition: pugixml.cpp:3554
xpath_node_set_raw::push_back
void push_back(const xpath_node &node, xpath_allocator *alloc)
Definition: pugixml.cpp:8853
xpath_memory_block_alignment
static const uintptr_t xpath_memory_block_alignment
Definition: pugixml.cpp:7533
pugi::xpath_node_set::type_t
type_t
Definition: pugixml.hpp:1335
xml_buffered_writer::write_direct
void write_direct(const char_t *data, size_t length)
Definition: pugixml.cpp:3728
xml_memory_management_function_storage
Definition: pugixml.cpp:196
xpath_ast_node::nodetest
const char_t * nodetest
Definition: pugixml.cpp:9476
xpath_ast_node::string
const char_t * string
Definition: pugixml.cpp:9470
pugi::xml_attribute::operator==
bool operator==(const xml_attribute &r) const
Definition: pugixml.cpp:5130
is_text_node
bool is_text_node(xml_node_struct *node)
Definition: pugixml.cpp:4481
pugi::xpath_node_set
Definition: pugixml.hpp:1331
pugi::status_bad_comment
@ status_bad_comment
Definition: pugixml.hpp:963
find_char
PUGI__FN const char_t * find_char(const char_t *s, char_t c)
Definition: pugixml.cpp:7872
ast_op_divide
@ ast_op_divide
Definition: pugixml.cpp:9346
xml_stream_chunk
Definition: pugixml.cpp:4825
xml_buffered_writer::writer
xml_writer & writer
Definition: pugixml.cpp:3901
pugi::xml_node::parent
xml_node parent() const
Definition: pugixml.cpp:5584
pugi::node_comment
@ node_comment
Definition: pugixml.hpp:145
pugi::xml_node::append_copy
xml_attribute append_copy(const xml_attribute &proto)
Definition: pugixml.cpp:5729
xpath_lexer::next
void next()
Definition: pugixml.cpp:9045
name_null_sentry::name
char_t * name
Definition: pugixml.cpp:5033
lex_axis_attribute
@ lex_axis_attribute
Definition: pugixml.cpp:9002
ast_op_equal
@ ast_op_equal
Definition: pugixml.cpp:9337
xpath_context::position
size_t position
Definition: pugixml.cpp:8971
ast_func_name_0
@ ast_func_name_0
Definition: pugixml.cpp:9363
equal_to
Definition: pugixml.cpp:7316
zero_terminate_buffer
PUGI__FN size_t zero_terminate_buffer(void *buffer, size_t size, xml_encoding encoding)
Definition: pugixml.cpp:4765
pugi::xpath_variable::xpath_variable
xpath_variable(xpath_value_type type)
Definition: pugixml.cpp:12240
not_equal_to
Definition: pugixml.cpp:7324
xpath_node_set_raw::truncate
void truncate(xpath_node *pos)
Definition: pugixml.cpp:8890
pugi::node_cdata
@ node_cdata
Definition: pugixml.hpp:144
pugi::parse_declaration
const unsigned int parse_declaration
Definition: pugixml.hpp:183
strconv_attribute_t
char_t *(* strconv_attribute_t)(char_t *, char_t)
Definition: pugixml.cpp:2726
xpath_allocator
Definition: pugixml.cpp:7548
pugi::as_wide
std::basic_string< wchar_t, std::char_traits< wchar_t >, std::allocator< wchar_t > > PUGIXML_FUNCTION as_wide(const char *str)
Definition: pugixml.cpp:7240
pugi::xml_writer_stream::wide_stream
std::basic_ostream< wchar_t, std::char_traits< wchar_t > > * wide_stream
Definition: pugixml.hpp:343
pugi::xml_node::set_value
bool set_value(const char_t *rhs)
Definition: pugixml.cpp:5649
xml_memory_page::busy_size
size_t busy_size
Definition: pugixml.cpp:484
xpath_ast_node::apply_predicate_number
static void apply_predicate_number(xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack, bool once)
Definition: pugixml.cpp:9674
wchar_selector< 2 >::decoder
utf16_decoder< opt_false > decoder
Definition: pugixml.cpp:1792
xpath_parser::binary_op_t::binary_op_t
binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_)
Definition: pugixml.cpp:11820
pugi::xpath_node_set::sort
void sort(bool reverse=false)
Definition: pugixml.cpp:12216
xpath_parser::alloc_node
xpath_ast_node * alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable *value)
Definition: pugixml.cpp:11108
xml_parser::parse_doctype_group
char_t * parse_doctype_group(char_t *s, char_t endch)
Definition: pugixml.cpp:2993
pugi::xpath_query::xpath_query
xpath_query()
Definition: pugixml.cpp:12559
namespace_uri_predicate::operator()
bool operator()(xml_attribute a) const
Definition: pugixml.cpp:8399
xpath_node_set_raw::set_type
void set_type(xpath_node_set::type_t value)
Definition: pugixml.cpp:8940
utf8_writer::any
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:1508
load_stream_data_seek
PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream< T > &stream, void **out_buffer, size_t *out_size)
Definition: pugixml.cpp:4911
pugi::xpath_variable::get_string
const char_t * get_string() const
Definition: pugixml.cpp:12281
xpath_node_set_raw::first
xpath_node first() const
Definition: pugixml.cpp:8846
xpath_ast_node::step_fill
void step_fill(xpath_node_set_raw &ns, xml_attribute_struct *a, xml_node_struct *p, xpath_allocator *alloc, bool once, T v)
Definition: pugixml.cpp:10060
xpath_parser::alloc_node
xpath_ast_node * alloc_node(ast_type_t type, xpath_value_type rettype, double value)
Definition: pugixml.cpp:11102
pugi::xml_text::get
const char_t * get() const
Definition: pugixml.cpp:6402
lex_quoted_string
@ lex_quoted_string
Definition: pugixml.cpp:8994
pugi::xml_attribute_iterator::_parent
xml_node _parent
Definition: pugixml.hpp:846
destroy_node
void destroy_node(xml_node_struct *n, xml_allocator &alloc)
Definition: pugixml.cpp:1202
as_utf8_begin
PUGI__FN size_t as_utf8_begin(const wchar_t *str, size_t length)
Definition: pugixml.cpp:2280
pugi::xpath_parse_result
Definition: pugixml.hpp:1091
xpath_string::_length_heap
size_t _length_heap
Definition: pugixml.cpp:7728
pugi::xml_text::_data_new
xml_node_struct * _data_new()
Definition: pugixml.cpp:6371
pugi::xml_tree_walker::for_each
virtual bool for_each(xml_node &node)=0
xml_memory_string_header
Definition: pugixml.cpp:503
pugi::xml_named_node_iterator::operator++
const xml_named_node_iterator & operator++()
Definition: pugixml.cpp:6774
xpath_variable_number::value
double value
Definition: pugixml.cpp:8586
xml_parser::alloc
xml_allocator * alloc
Definition: pugixml.cpp:2914
xpath_ast_node::operator=
xpath_ast_node & operator=(const xpath_ast_node &)
gap::gap
gap()
Definition: pugixml.cpp:2409
xml_memory_page_type_mask
static const uintptr_t xml_memory_page_type_mask
Definition: pugixml.cpp:438
lex_close_brace
@ lex_close_brace
Definition: pugixml.cpp:8993
xpath_node_set_raw::empty
bool empty() const
Definition: pugixml.cpp:8836
pugi::xml_text::data
xml_node data() const
Definition: pugixml.cpp:6601
xpath_string::operator!=
bool operator!=(const xpath_string &o) const
Definition: pugixml.cpp:7848
pugi::xml_text::empty
bool empty() const
Definition: pugixml.cpp:6397
lex_double_dot
@ lex_double_dot
Definition: pugixml.cpp:9004
pugi::xpath_query::result
const xpath_parse_result & result() const
Definition: pugixml.cpp:12740
is_xpath_attribute
bool is_xpath_attribute(const char_t *name)
Definition: pugixml.cpp:8565
pugi::xml_node::attributes_begin
attribute_iterator attributes_begin() const
Definition: pugixml.cpp:5422
pugi::xpath_exception
Definition: pugixml.hpp:1269
latin1_writer::value_type
uint8_t * value_type
Definition: pugixml.cpp:1600
pugi::xpath_query::evaluate_boolean
bool evaluate_boolean(const xpath_node &n) const
Definition: pugixml.cpp:12601
ast_func_local_name_1
@ ast_func_local_name_1
Definition: pugixml.cpp:9360
pugi::format_write_bom
const unsigned int format_write_bom
Definition: pugixml.hpp:236
pugi::xml_writer_file::write
virtual void write(const void *data, size_t size) PUGIXML_OVERRIDE
Definition: pugixml.cpp:5053
xpath_lexer::contents
const xpath_lexer_string & contents() const
Definition: pugixml.cpp:9324
xml_buffered_writer::xml_buffered_writer
xml_buffered_writer(xml_writer &writer_, xml_encoding user_encoding)
Definition: pugixml.cpp:3698
not_equal_to::operator()
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:7325
pugi::unspecified_bool_xpath_node
static PUGI__FN void unspecified_bool_xpath_node(xpath_node ***)
Definition: pugixml.cpp:12056
xpath_ast_node::_right
xpath_ast_node * _right
Definition: pugixml.cpp:9464
ast_func_id
@ ast_func_id
Definition: pugixml.cpp:9358
lex_dot
@ lex_dot
Definition: pugixml.cpp:9003
pugi::xml_node::traverse
bool traverse(xml_tree_walker &walker)
Definition: pugixml.cpp:6225
xml_parser::parse_doctype_primitive
char_t * parse_doctype_primitive(char_t *s)
Definition: pugixml.cpp:2929
pugi::xpath_node_set::begin
const_iterator begin() const
Definition: pugixml.cpp:12206
xpath_ast_node::xpath_ast_node
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value)
Definition: pugixml.cpp:10207
strconv_comment
PUGI__FN char_t * strconv_comment(char_t *s, char_t endch)
Definition: pugixml.cpp:2599
ast_op_less
@ ast_op_less
Definition: pugixml.cpp:9339
xpath_parser::parse
static xpath_ast_node * parse(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
Definition: pugixml.cpp:11951
pugi::xml_document::_destroy
void _destroy()
Definition: pugixml.cpp:6936
pugi::xml_node::child_value
const char_t * child_value() const
Definition: pugixml.cpp:5599
pugi::xpath_variable::get_number
double get_number() const
Definition: pugixml.cpp:12276
xpath_ast_node
Definition: pugixml.cpp:9450
ast_op_union
@ ast_op_union
Definition: pugixml.cpp:9349
pugi::xml_node::internal_object
xml_node_struct * internal_object() const
Definition: pugixml.cpp:6277
pugi::encoding_utf16_le
@ encoding_utf16_le
Definition: pugixml.hpp:220
pugi::xml_node::insert_child_before
xml_node insert_child_before(xml_node_type type, const xml_node &node)
Definition: pugixml.cpp:5833
pugi::xml_node::insert_child_after
xml_node insert_child_after(xml_node_type type, const xml_node &node)
Definition: pugixml.cpp:5851
xpath_allocator::_root
xpath_memory_block * _root
Definition: pugixml.cpp:7549
PUGI__CHECK_ERROR
#define PUGI__CHECK_ERROR(err, m)
Definition: pugixml.cpp:2597
ast_op_not_equal
@ ast_op_not_equal
Definition: pugixml.cpp:9338
lex_comma
@ lex_comma
Definition: pugixml.cpp:9001
uhal::tests::j
std::vector< uint32_t >::const_iterator j
Definition: test_rawclient.cpp:113
pugi::xml_node::insert_copy_after
xml_attribute insert_copy_after(const xml_attribute &proto, const xml_attribute &attr)
Definition: pugixml.cpp:5763
pugi::xml_named_node_iterator::_wrap
xml_node _wrap
Definition: pugixml.hpp:917
pugi::xpath_node::_attribute
xml_attribute _attribute
Definition: pugixml.hpp:1293
pugi::xml_attribute::operator>=
bool operator>=(const xml_attribute &r) const
Definition: pugixml.cpp:5155
PUGI__GETHEADER_IMPL
#define PUGI__GETHEADER_IMPL(object, page, flags)
Definition: pugixml.cpp:448
ast_func_substring_after
@ ast_func_substring_after
Definition: pugixml.cpp:9371
xpath_ast_node::rettype
xpath_value_type rettype() const
Definition: pugixml.cpp:11057
xml_parser::parse_doctype_ignore
char_t * parse_doctype_ignore(char_t *s)
Definition: pugixml.cpp:2962
xml_buffered_writer::write_buffer
void write_buffer(const char_t *data, size_t length)
Definition: pugixml.cpp:3767
xml_parser::has_element_node_siblings
static bool has_element_node_siblings(xml_node_struct *node)
Definition: pugixml.cpp:3493
insert_attribute_before
void insert_attribute_before(xml_attribute_struct *attr, xml_attribute_struct *place, xml_node_struct *node)
Definition: pugixml.cpp:1370
xml_buffered_writer::write
void write(char_t d0, char_t d1)
Definition: pugixml.cpp:3816
xml_allocator::xml_allocator
xml_allocator(xml_memory_page *root)
Definition: pugixml.cpp:510
pugi::xml_document::~xml_document
~xml_document()
Definition: pugixml.cpp:6855
pugi::xml_node_iterator::operator*
xml_node & operator*() const
Definition: pugixml.cpp:6640
pugi::xml_node::prepend_copy
xml_attribute prepend_copy(const xml_attribute &proto)
Definition: pugixml.cpp:5746
xml_buffered_writer::write
void write(char_t d0, char_t d1, char_t d2)
Definition: pugixml.cpp:3826
evaluate_node_set_prepare
PUGI__FN impl::xpath_ast_node * evaluate_node_set_prepare(xpath_query_impl *impl)
Definition: pugixml.cpp:11990
indent_flags_t
indent_flags_t
Definition: pugixml.cpp:4231
pugi::encoding_utf16
@ encoding_utf16
Definition: pugixml.hpp:222
pugi::xml_text::unspecified_bool_type
void(* unspecified_bool_type)(xml_text ***)
Definition: pugixml.hpp:715
insertion_sort
PUGI__FN void insertion_sort(T *begin, T *end, const Pred &pred)
Definition: pugixml.cpp:7396
xml_memory_page::next
xml_memory_page * next
Definition: pugixml.cpp:482
lex_union
@ lex_union
Definition: pugixml.cpp:8990
swap
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7347
xpath_variable_string::value
char_t * value
Definition: pugixml.cpp:8601
pugi::format_save_file_text
const unsigned int format_save_file_text
Definition: pugixml.hpp:248
pugi::xml_node_struct::first_attribute
xml_attribute_struct * first_attribute
Definition: pugixml.cpp:1129
name_null_sentry
Definition: pugixml.cpp:5031
convert_buffer_latin1
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:2208
opt_false::value
@ value
Definition: pugixml.cpp:1427
lex_plus
@ lex_plus
Definition: pugixml.cpp:8987
utf16_writer::low
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1533
convert_buffer_generic
PUGI__FN bool convert_buffer_generic(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, D)
Definition: pugixml.cpp:2174
pugi::xml_attribute_struct::name
char_t * name
Definition: pugixml.cpp:1103
strconv_pcdata_impl::parse
static char_t * parse(char_t *s)
Definition: pugixml.cpp:2659
xpath_lexer::_cur
const char_t * _cur
Definition: pugixml.cpp:9028
ctx_start_symbol
@ ctx_start_symbol
Definition: pugixml.cpp:1865
pugi::xml_tree_walker::depth
int depth() const
Definition: pugixml.cpp:5093
ast_func_namespace_uri_1
@ ast_func_namespace_uri_1
Definition: pugixml.cpp:9362
xml_buffered_writer::bufcapacitybytes
@ bufcapacitybytes
Definition: pugixml.cpp:3881
make_parse_result
xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset=0)
Definition: pugixml.cpp:2903
pugi::xml_parse_result::status
xml_parse_status status
Definition: pugixml.hpp:981
sort
PUGI__FN void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7457
xpath_node_set_raw::_type
xpath_node_set::type_t _type
Definition: pugixml.cpp:8815
xpath_variable_boolean
Definition: pugixml.cpp:8571
ast_func_position
@ ast_func_position
Definition: pugixml.cpp:9356
xpath_stack
Definition: pugixml.cpp:7692
xpath_context::xpath_context
xpath_context(const xpath_node &n_, size_t position_, size_t size_)
Definition: pugixml.cpp:8973
pugi::xpath_node_set::empty
bool empty() const
Definition: pugixml.cpp:12195
xml_allocator
Definition: pugixml.cpp:509
xpath_memory_block::next
xpath_memory_block * next
Definition: pugixml.cpp:7537
node_output
PUGI__FN void node_output(xml_buffered_writer &writer, xml_node_struct *root, const char_t *indent, unsigned int flags, unsigned int depth)
Definition: pugixml.cpp:4236
xpath_variable_number
Definition: pugixml.cpp:8581
pugi::node_document
@ node_document
Definition: pugixml.hpp:141
pugi::xml_node::append_move
xml_node append_move(const xml_node &moved)
Definition: pugixml.cpp:5975
axis_ancestor
@ axis_ancestor
Definition: pugixml.cpp:9399
node_copy_attribute
PUGI__FN void node_copy_attribute(xml_attribute_struct *da, xml_attribute_struct *sa)
Definition: pugixml.cpp:4472
xpath_ast_node::variable
xpath_variable * variable
Definition: pugixml.cpp:9474
xpath_query_impl::block
xpath_memory_block block
Definition: pugixml.cpp:11986
xml_allocator::_busy_size
size_t _busy_size
Definition: pugixml.cpp:700
equal_to::operator()
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:7317
pugi::parse_escapes
const unsigned int parse_escapes
Definition: pugixml.hpp:171
utf32_counter::low
static value_type low(value_type result, uint32_t)
Definition: pugixml.cpp:1561
auto_deleter::~auto_deleter
~auto_deleter()
Definition: pugixml.cpp:273
chartype_table
static const unsigned char chartype_table[256]
Definition: pugixml.cpp:1840
pugi::unspecified_bool_xml_attribute
static PUGI__FN void unspecified_bool_xml_attribute(xml_attribute ***)
Definition: pugixml.cpp:5116
node_output_attributes
PUGI__FN void node_output_attributes(xml_buffered_writer &writer, xml_node_struct *node, const char_t *indent, size_t indent_length, unsigned int flags, unsigned int depth)
Definition: pugixml.cpp:4074
pugi::xml_attribute::operator!=
bool operator!=(const xml_attribute &r) const
Definition: pugixml.cpp:5135
is_attribute_of
PUGI__FN bool is_attribute_of(xml_attribute_struct *attr, xml_node_struct *node)
Definition: pugixml.cpp:4342
auto_deleter::data
T * data
Definition: pugixml.cpp:266
xpath_lexer::current_pos
const char_t * current_pos() const
Definition: pugixml.cpp:9319
xml_buffered_writer
Definition: pugixml.cpp:3693
convert_string_to_number
PUGI__FN double convert_string_to_number(const char_t *string)
Definition: pugixml.cpp:8324
utf32_counter::high
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:1566
unique
PUGI__FN I unique(I begin, I end)
Definition: pugixml.cpp:7371
pugi::xml_document::xml_document
xml_document()
Definition: pugixml.cpp:6850
xml_parser::xml_parser
xml_parser(xml_allocator *alloc_)
Definition: pugixml.cpp:2918
uhal::insert
void insert(std::ostream &aStr, const U &aU)
Definition: LogLevels.hpp:25
xml_allocator::deallocate_memory
void deallocate_memory(void *ptr, size_t size, xml_memory_page *page)
Definition: pugixml.cpp:593
xpath_stack_data::result
xpath_allocator result
Definition: pugixml.cpp:7700
pugi::parse_wconv_attribute
const unsigned int parse_wconv_attribute
Definition: pugixml.hpp:177
xml_document_struct::xml_document_struct
xml_document_struct(xml_memory_page *page)
Definition: pugixml.cpp:1143
utf32_decoder
Definition: pugixml.cpp:1739
namespace_uri_predicate::prefix
const char_t * prefix
Definition: pugixml.cpp:8388
axis_preceding
@ axis_preceding
Definition: pugixml.cpp:9409
pugi::xml_writer_stream::narrow_stream
std::basic_ostream< char, std::char_traits< char > > * narrow_stream
Definition: pugixml.hpp:342
xpath_string::operator==
bool operator==(const xpath_string &o) const
Definition: pugixml.cpp:7843
xpath_ast_node::number
double number
Definition: pugixml.cpp:9472
auto_deleter::auto_deleter
auto_deleter(T *data_, D deleter_)
Definition: pugixml.cpp:269
pugi::xpath_variable::get_node_set
const xpath_node_set & get_node_set() const
Definition: pugixml.cpp:12287
setupTemplate._name
string _name
Definition: setupTemplate.py:8
pugi::parse_doctype
const unsigned int parse_doctype
Definition: pugixml.hpp:186
xpath_ast_node::eval_string
xpath_string eval_string(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:10564
xpath_variable_string::xpath_variable_string
xpath_variable_string()
Definition: pugixml.cpp:8592
ast_op_negate
@ ast_op_negate
Definition: pugixml.cpp:9348
pugi::xml_attribute::_attr
xml_attribute_struct * _attr
Definition: pugixml.hpp:354
lex_none
@ lex_none
Definition: pugixml.cpp:8980
nodetest_none
@ nodetest_none
Definition: pugixml.cpp:9416
pugi::xml_attribute::previous_attribute
xml_attribute previous_attribute() const
Definition: pugixml.cpp:5165
xpath_node_set_raw::append
void append(const xpath_node *begin_, const xpath_node *end_, xpath_allocator *alloc)
Definition: pugixml.cpp:8861
lex_equal
@ lex_equal
Definition: pugixml.cpp:8981
pugi::xml_node::last_attribute
xml_attribute last_attribute() const
Definition: pugixml.cpp:5624
pugi::xml_node::value
const char_t * value() const
Definition: pugixml.cpp:5492
xpath_lexer::_cur_lexeme_pos
const char_t * _cur_lexeme_pos
Definition: pugixml.cpp:9029
xml_buffered_writer::write
void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
Definition: pugixml.cpp:3862
pugi::xpath_variable::name
const char_t * name() const
Definition: pugixml.cpp:12244
convert_number_to_mantissa_exponent
PUGI__FN void convert_number_to_mantissa_exponent(double value, char(&buffer)[32], char **out_mantissa, int *out_exponent)
Definition: pugixml.cpp:8198
ast_func_local_name_0
@ ast_func_local_name_0
Definition: pugixml.cpp:9359
qualified_name
PUGI__FN const char_t * qualified_name(const xpath_node &node)
Definition: pugixml.cpp:8373
xpath_allocator::_root_size
size_t _root_size
Definition: pugixml.cpp:7550
pugi::format_raw
const unsigned int format_raw
Definition: pugixml.hpp:239
pugi::xpath_node::unspecified_bool_type
void(* unspecified_bool_type)(xpath_node ***)
Definition: pugixml.hpp:1295
pugi::status_bad_start_element
@ status_bad_start_element
Definition: pugixml.hpp:967
xpath_context::size
size_t size
Definition: pugixml.cpp:8971
pugi::xpath_query::operator!
bool operator!() const
Definition: pugixml.cpp:12754
starts_with
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN bool starts_with(const char_t *string, const char_t *pattern)
Definition: pugixml.cpp:7861
latin1_decoder::type
uint8_t type
Definition: pugixml.cpp:1770
pugi::xml_node::attributes
xml_object_range< xml_attribute_iterator > attributes() const
Definition: pugixml.cpp:5442
setupTemplate.name
name
Definition: setupTemplate.py:32
normalize_space
PUGI__FN char_t * normalize_space(char_t *buffer)
Definition: pugixml.cpp:8453
ast_func_string_1
@ ast_func_string_1
Definition: pugixml.cpp:9366
pugi::xpath_node_set::xpath_node_set
xpath_node_set()
Definition: pugixml.cpp:12137
set_value_ascii
PUGI__FN bool set_value_ascii(String &dest, Header &header, uintptr_t header_mask, char *buf)
Definition: pugixml.cpp:4642
xpath_parser
Definition: pugixml.cpp:11064
xpath_ast_node::eval_boolean
bool eval_boolean(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:10249
utf8_counter::high
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:1462
append_new_attribute
PUGI__FN_NO_INLINE xml_attribute_struct * append_new_attribute(xml_node_struct *node, xml_allocator &alloc)
Definition: pugixml.cpp:1410
pugi::xml_node::remove_child
bool remove_child(const xml_node &n)
Definition: pugixml.cpp:6067
pugi::xml_tree_walker::xml_tree_walker
xml_tree_walker()
Definition: pugixml.cpp:5085
pugi::xml_node::prepend_attribute
xml_attribute prepend_attribute(const char_t *name)
Definition: pugixml.cpp:5676
xpath_ast_node::_test
char _test
Definition: pugixml.cpp:9460
xpath_ast_node::is_posinv_expr
bool is_posinv_expr() const
Definition: pugixml.cpp:11011
latin1_writer::low
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1602
axis_namespace
@ axis_namespace
Definition: pugixml.cpp:9407
pugi::xpath_parse_result::description
const char * description() const
Definition: pugixml.cpp:12235
pugi::xpath_exception::_result
xpath_parse_result _result
Definition: pugixml.hpp:1271
nodetest_all
@ nodetest_all
Definition: pugixml.cpp:9423
pugi::xml_text
Definition: pugixml.hpp:710
lex_not_equal
@ lex_not_equal
Definition: pugixml.cpp:8982
ast_func_number_1
@ ast_func_number_1
Definition: pugixml.cpp:9385
xpath_ast_node::xpath_ast_node
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t *value)
Definition: pugixml.cpp:10200
nodetest_type_comment
@ nodetest_type_comment
Definition: pugixml.cpp:9419
pugi::xml_document::load
xml_parse_result load(std::basic_istream< char, std::char_traits< char > > &stream, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7083
ast_func_boolean
@ ast_func_boolean
Definition: pugixml.cpp:9379
xpath_string::append
void append(const xpath_string &o, xpath_allocator *alloc)
Definition: pugixml.cpp:7775
pugi::xml_node::first_child
xml_node first_child() const
Definition: pugixml.cpp:5629
pugi::parse_pi
const unsigned int parse_pi
Definition: pugixml.hpp:158
xpath_string::_buffer
const char_t * _buffer
Definition: pugixml.cpp:7726
pugi::xml_attribute_iterator::operator!=
bool operator!=(const xml_attribute_iterator &rhs) const
Definition: pugixml.cpp:6696
lex_eof
@ lex_eof
Definition: pugixml.cpp:9006
pugixml.hpp
pugi::xpath_node_set::_storage
xpath_node _storage[1]
Definition: pugixml.hpp:1391
xpath_ast_node::_axis
char _axis
Definition: pugixml.cpp:9457
xpath_parser::parse_primary_expression
xpath_ast_node * parse_primary_expression()
Definition: pugixml.cpp:11372
predicate_constant
@ predicate_constant
Definition: pugixml.cpp:9431
pugi::xml_attribute_struct::value
char_t * value
Definition: pugixml.cpp:1104
get_variable_scratch
PUGI__FN bool get_variable_scratch(char_t(&buffer)[32], xpath_variable_set *set, const char_t *begin, const char_t *end, xpath_variable **out_result)
Definition: pugixml.cpp:8726
ast_func_concat
@ ast_func_concat
Definition: pugixml.cpp:9367
ct_symbol
@ ct_symbol
Definition: pugixml.cpp:1836
pugi::xml_attribute::as_bool
bool as_bool(bool def=false) const
Definition: pugixml.cpp:5195
utf32_decoder::process
static Traits::value_type process(const uint32_t *data, size_t size, typename Traits::value_type result, Traits)
Definition: pugixml.cpp:1742
xpath_node_set_raw::_end
xpath_node * _end
Definition: pugixml.cpp:8818
xml_buffered_writer::flush
void flush(const char_t *data, size_t size)
Definition: pugixml.cpp:3710
indent_newline
@ indent_newline
Definition: pugixml.cpp:4232
pugi::xml_node::child
xml_node child(const char_t *name) const
Definition: pugixml.cpp:5497
axis_following_sibling
@ axis_following_sibling
Definition: pugixml.cpp:9406
lex_number
@ lex_number
Definition: pugixml.cpp:8995
xpath_parser::alloc_node
xpath_ast_node * alloc_node(ast_type_t type, xpath_value_type rettype, const char_t *value)
Definition: pugixml.cpp:11096
pugi::xml_node::path
string_t path(char_t delimiter='/') const
Definition: pugixml.cpp:6143
namespace_uri_predicate::prefix_length
size_t prefix_length
Definition: pugixml.cpp:8389
xpath_ast_node::optimize
void optimize(xpath_allocator *alloc)
Definition: pugixml.cpp:10931
xpath_parser::parse_function
xpath_ast_node * parse_function(const xpath_lexer_string &name, size_t argc, xpath_ast_node *args[2])
Definition: pugixml.cpp:11148
pugi::xml_node::operator!
bool operator!() const
Definition: pugixml.cpp:5407
ast_func_number_0
@ ast_func_number_0
Definition: pugixml.cpp:9384
pugi::xpath_exception::result
const xpath_parse_result & result() const
Definition: pugixml.cpp:12023
pugi::xpath_node::parent
xml_node parent() const
Definition: pugixml.cpp:12051
xpath_memory_page_size
PUGI__NS_END static PUGI__NS_BEGIN const size_t xpath_memory_page_size
Definition: pugixml.cpp:7525
xml_stream_chunk::xml_stream_chunk
xml_stream_chunk()
Definition: pugixml.cpp:4847
xpath_allocator::release
void release()
Definition: pugixml.cpp:7660
xml_buffered_writer::xml_buffered_writer
xml_buffered_writer(const xml_buffered_writer &)
xpath_node_set_raw::push_back_grow
void push_back_grow(const xpath_node &node, xpath_allocator *alloc)
Definition: pugixml.cpp:8946
PUGIXML_TEXT
#define PUGIXML_TEXT(t)
Definition: pugixml.hpp:119
nodetest_type_node
@ nodetest_type_node
Definition: pugixml.cpp:9418
lex_double_colon
@ lex_double_colon
Definition: pugixml.cpp:9005
lex_open_brace
@ lex_open_brace
Definition: pugixml.cpp:8992
pugi::parse_embed_pcdata
const unsigned int parse_embed_pcdata
Definition: pugixml.hpp:203
xpath_parser::parse_axis_name
axis_t parse_axis_name(const xpath_lexer_string &name, bool &specified)
Definition: pugixml.cpp:11268
xpath_ast_node::_type
char _type
Definition: pugixml.cpp:9453
pugi::xml_node_struct::parent
xml_node_struct * parent
Definition: pugixml.cpp:1122
utf8_decoder
Definition: pugixml.cpp:1620
get_valid_length
PUGI__FN size_t get_valid_length(const char_t *data, size_t length)
Definition: pugixml.cpp:3652
get_mutable_buffer
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:2040
pugi::xml_node::operator>=
bool operator>=(const xml_node &r) const
Definition: pugixml.cpp:5472
node_output_simple
PUGI__FN void node_output_simple(xml_buffered_writer &writer, xml_node_struct *node, unsigned int flags)
Definition: pugixml.cpp:4174
pugi::xpath_node_set::size
size_t size() const
Definition: pugixml.cpp:12190
strconv_cdata
PUGI__FN char_t * strconv_cdata(char_t *s, char_t endch)
Definition: pugixml.cpp:2627
pugi::xml_node::insert_attribute_before
xml_attribute insert_attribute_before(const char_t *name, const xml_attribute &attr)
Definition: pugixml.cpp:5711
utf16_writer::value_type
uint16_t * value_type
Definition: pugixml.cpp:1531
node_output_end
PUGI__FN void node_output_end(xml_buffered_writer &writer, xml_node_struct *node)
Definition: pugixml.cpp:4164
pugi::xml_node::remove_attribute
bool remove_attribute(const xml_attribute &a)
Definition: pugixml.cpp:6048
utf16_decoder::process
static Traits::value_type process(const uint16_t *data, size_t size, typename Traits::value_type result, Traits)
Definition: pugixml.cpp:1690
pugi::xpath_query::~xpath_query
~xpath_query()
Definition: pugixml.cpp:12563
xml_memory_page
Definition: pugixml.cpp:459
ast_func_substring_3
@ ast_func_substring_3
Definition: pugixml.cpp:9373
PUGI__DMC_VOLATILE
#define PUGI__DMC_VOLATILE
Definition: pugixml.cpp:106
ast_op_greater
@ ast_op_greater
Definition: pugixml.cpp:9340
is_little_endian
PUGI__FN bool is_little_endian()
Definition: pugixml.cpp:1901
pugi::xml_text::_root
xml_node_struct * _root
Definition: pugixml.hpp:713
pugi::xpath_type_none
@ xpath_type_none
Definition: pugixml.hpp:1082
pugi::xml_node::iterator
xml_node_iterator iterator
Definition: pugixml.hpp:676
pugi::xml_attribute_iterator::operator*
xml_attribute & operator*() const
Definition: pugixml.cpp:6701
auto_deleter
Definition: pugixml.cpp:263
pugi::xpath_node_set::first
xpath_node first() const
Definition: pugixml.cpp:12221
predicate_default
@ predicate_default
Definition: pugixml.cpp:9429
text_output_indent
PUGI__FN void text_output_indent(xml_buffered_writer &writer, const char_t *indent, size_t indent_length, unsigned int depth)
Definition: pugixml.cpp:3988
pugi::xml_node::operator!=
bool operator!=(const xml_node &r) const
Definition: pugixml.cpp:5452
ast_step
@ ast_step
Definition: pugixml.cpp:9390
ctx_symbol
@ ctx_symbol
Definition: pugixml.cpp:1867
xpath_query_impl::oom
bool oom
Definition: pugixml.cpp:11987
xpath_variable_node_set::xpath_variable_node_set
xpath_variable_node_set()
Definition: pugixml.cpp:8607
pugi::xml_attribute::internal_object
xml_attribute_struct * internal_object() const
Definition: pugixml.cpp:5232
pugi::status_ok
@ status_ok
Definition: pugixml.hpp:953
pugi::status_internal_error
@ status_internal_error
Definition: pugixml.hpp:958
less::operator()
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:7333
pugi::xml_node::find_child_by_attribute
xml_node find_child_by_attribute(const char_t *name, const char_t *attr_name, const char_t *attr_value) const
Definition: pugixml.cpp:6115
utf8_decoder::process
static Traits::value_type process(const uint8_t *data, size_t size, typename Traits::value_type result, Traits)
Definition: pugixml.cpp:1623
xpath_parser::_query
const char_t * _query
Definition: pugixml.cpp:11068
nodeset_eval_all
@ nodeset_eval_all
Definition: pugixml.cpp:9437
PUGI__POPNODE
#define PUGI__POPNODE()
Definition: pugixml.cpp:2591
ast_func_contains
@ ast_func_contains
Definition: pugixml.cpp:9369
pugi::xml_attribute::as_double
double as_double(double def=0) const
Definition: pugixml.cpp:5185
opt_false
Definition: pugixml.cpp:1426
xpath_string::data
char_t * data(xpath_allocator *alloc)
Definition: pugixml.cpp:7820
node_output_pi_value
PUGI__FN void node_output_pi_value(xml_buffered_writer &writer, const char_t *s)
Definition: pugixml.cpp:4053
lex_close_square_brace
@ lex_close_square_brace
Definition: pugixml.cpp:8999
xpath_string::xpath_string
xpath_string()
Definition: pugixml.cpp:7771
ast_opt_compare_attribute
@ ast_opt_compare_attribute
Definition: pugixml.cpp:9394
nodetest_name
@ nodetest_name
Definition: pugixml.cpp:9417
pugi::xml_node::name
const char_t * name() const
Definition: pugixml.cpp:5482
pugi::xml_attribute_iterator::xml_attribute_iterator
xml_attribute_iterator()
Definition: pugixml.cpp:6679
pugi::xml_text::_data
xml_node_struct * _data() const
Definition: pugixml.cpp:6356
ast_op_greater_or_equal
@ ast_op_greater_or_equal
Definition: pugixml.cpp:9342
xpath_parser::alloc_node
xpath_ast_node * alloc_node(ast_type_t type, xpath_ast_node *left, xpath_ast_node *right, predicate_t test)
Definition: pugixml.cpp:11126
xml_buffered_writer::encoding
xml_encoding encoding
Definition: pugixml.cpp:3903
xml_parser::parse_skip_bom
static char_t * parse_skip_bom(char_t *s)
Definition: pugixml.cpp:3487
pugi::xml_node::first_attribute
xml_attribute first_attribute() const
Definition: pugixml.cpp:5619
ast_variable
@ ast_variable
Definition: pugixml.cpp:9354
gen_nan
PUGI__FN double gen_nan()
Definition: pugixml.cpp:8110
convert_buffer
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:2245
xpath_ast_node::apply_predicates
void apply_predicates(xpath_node_set_raw &ns, size_t first, const xpath_stack &stack, nodeset_eval_t eval)
Definition: pugixml.cpp:9742
pugi::xml_node_struct::header
uintptr_t header
Definition: pugixml.cpp:1117
ast_filter
@ ast_filter
Definition: pugixml.cpp:9351
nodeset_eval_any
@ nodeset_eval_any
Definition: pugixml.cpp:9438
xml_memory_management_function_storage::deallocate
static deallocation_function deallocate
Definition: pugixml.cpp:198
xpath_ast_node::eval_number
double eval_number(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:10386
xml_document_struct::extra_buffers
xml_extra_buffer * extra_buffers
Definition: pugixml.cpp:1149
pugi::xml_document::_buffer
char_t * _buffer
Definition: pugixml.hpp:1003
predicate_t
predicate_t
Definition: pugixml.cpp:9428
pugi::xml_node::begin
iterator begin() const
Definition: pugixml.cpp:5412
PUGI__SCANWHILE
#define PUGI__SCANWHILE(X)
Definition: pugixml.cpp:2593
xpath_query_impl::root
xpath_ast_node * root
Definition: pugixml.cpp:11984
wchar_selector
Definition: pugixml.cpp:1785
pugi::xml_document::_create
void _create()
Definition: pugixml.cpp:6893
pugi::xml_writer_stream::write
virtual void write(const void *data, size_t size) PUGIXML_OVERRIDE
Definition: pugixml.cpp:5068
as_utf8_end
PUGI__FN void as_utf8_end(char *buffer, size_t size, const wchar_t *str, size_t length)
Definition: pugixml.cpp:2286
get_value_bool
PUGI__FN bool get_value_bool(const char_t *value)
Definition: pugixml.cpp:4599
get_allocator
xml_allocator & get_allocator(const Object *object)
Definition: pugixml.cpp:1156
xml_extra_buffer::buffer
char_t * buffer
Definition: pugixml.cpp:1137
translate
PUGI__FN char_t * translate(char_t *buffer, const char_t *from, const char_t *to, size_t to_length)
Definition: pugixml.cpp:8481
xpath_ast_node::_data
union xpath_ast_node::@6 _data
xml_buffered_writer::write
void write(char_t d0)
Definition: pugixml.cpp:3807
wchar_writer
wchar_selector< sizeof(wchar_t)>::writer wchar_writer
Definition: pugixml.cpp:1804
pugi::xpath_value_type
xpath_value_type
Definition: pugixml.hpp:1081
xpath_lexer_string
Definition: pugixml.cpp:9010
pugi::xpath_type_number
@ xpath_type_number
Definition: pugixml.hpp:1084
pugi::xpath_node::node
xml_node node() const
Definition: pugixml.cpp:12041
xpath_ast_node::step_fill
void step_fill(xpath_node_set_raw &ns, const xpath_node &xn, xpath_allocator *alloc, bool once, T v)
Definition: pugixml.cpp:10141
xpath_string::duplicate_string
static char_t * duplicate_string(const char_t *string, size_t length, xpath_allocator *alloc)
Definition: pugixml.cpp:7730
pugi::xml_parse_result::description
const char * description() const
Definition: pugixml.cpp:6819
xpath_query_impl::create
static xpath_query_impl * create()
Definition: pugixml.cpp:11961
xpath_allocator_capture
Definition: pugixml.cpp:7677
ast_op_multiply
@ ast_op_multiply
Definition: pugixml.cpp:9345
xml_buffered_writer::buffer
char_t buffer[bufcapacity]
Definition: pugixml.cpp:3891
xpath_node_set_raw::_begin
xpath_node * _begin
Definition: pugixml.cpp:8817
axis_following
@ axis_following
Definition: pugixml.cpp:9405
xml_buffered_writer::scratch
union xml_buffered_writer::@3 scratch
pugi::xml_attribute_struct::header
uintptr_t header
Definition: pugixml.cpp:1101
pugi::xml_tree_walker::~xml_tree_walker
virtual ~xml_tree_walker()
Definition: pugixml.cpp:5089
xml_allocator::deallocate_page
static void deallocate_page(xml_memory_page *page)
Definition: pugixml.cpp:534
xpath_query_impl::destroy
static void destroy(xpath_query_impl *impl)
Definition: pugixml.cpp:11969
ast_func_lang
@ ast_func_lang
Definition: pugixml.cpp:9383
xml_memory_string_header::page_offset
uint16_t page_offset
Definition: pugixml.cpp:504
pugi::xml_attribute::operator<
bool operator<(const xml_attribute &r) const
Definition: pugixml.cpp:5140
pugi::xml_writer_stream::xml_writer_stream
xml_writer_stream(std::basic_ostream< char, std::char_traits< char > > &stream)
Definition: pugixml.cpp:5060
nodetest_type_text
@ nodetest_type_text
Definition: pugixml.cpp:9421
ast_func_true
@ ast_func_true
Definition: pugixml.cpp:9381
xml_stream_chunk::destroy
static void destroy(xml_stream_chunk *chunk)
Definition: pugixml.cpp:4834
pugi::xml_attribute::set_name
bool set_name(const char_t *rhs)
Definition: pugixml.cpp:5299
xpath_memory_block::data
char data[xpath_memory_page_size]
Definition: pugixml.cpp:7542
PUGI__STATIC_ASSERT
#define PUGI__STATIC_ASSERT(cond)
Definition: pugixml.cpp:100
set_value_bool
PUGI__FN bool set_value_bool(String &dest, Header &header, uintptr_t header_mask, bool value)
Definition: pugixml.cpp:4686
node_is_before
PUGI__FN bool node_is_before(xml_node_struct *ln, xml_node_struct *rn)
Definition: pugixml.cpp:7975
pugi::xml_document::load_buffer_inplace_own
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:7149
round_nearest
PUGI__FN double round_nearest(double value)
Definition: pugixml.cpp:8361
PUGI__ENDSEG
#define PUGI__ENDSEG()
Definition: pugixml.cpp:2595
auto_deleter::deleter
D deleter
Definition: pugixml.cpp:267
xml_memory_page_contents_shared_mask
static const uintptr_t xml_memory_page_contents_shared_mask
Definition: pugixml.cpp:435
xml_memory_page::allocator
xml_allocator * allocator
Definition: pugixml.cpp:479
pugi::xml_node::end
iterator end() const
Definition: pugixml.cpp:5417
pugi::xml_document::_memory
char _memory[192]
Definition: pugixml.hpp:1005
pugi::xml_node::hash_value
size_t hash_value() const
Definition: pugixml.cpp:6272
save_file_impl
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:5020
delete_xpath_variable
PUGI__FN void delete_xpath_variable(T *var)
Definition: pugixml.cpp:8673
axis_to_type::axis
static const axis_t axis
Definition: pugixml.cpp:9444
pugi::xml_tree_walker::end
virtual bool end(xml_node &node)
Definition: pugixml.cpp:5103
xml_memory_management_function_storage::allocate
static allocation_function allocate
Definition: pugixml.cpp:197
pugi::format_indent_attributes
const unsigned int format_indent_attributes
Definition: pugixml.hpp:251
xpath_parser::parse_expression_rec
xpath_ast_node * parse_expression_rec(xpath_ast_node *lhs, int limit)
Definition: pugixml.cpp:11876
median3
I median3(I first, I middle, I last, const Pred &pred)
Definition: pugixml.cpp:7418
xpath_memory_block
Definition: pugixml.cpp:7536
xpath_ast_node::_rettype
char _rettype
Definition: pugixml.cpp:9454
pugi::xml_node::append_child
xml_node append_child(xml_node_type type=node_element)
Definition: pugixml.cpp:5799
PUGI__UNLIKELY
#define PUGI__UNLIKELY(cond)
Definition: pugixml.cpp:96
xpath_first
PUGI__FN xpath_node xpath_first(const xpath_node *begin, const xpath_node *end, xpath_node_set::type_t type)
Definition: pugixml.cpp:8792
nodetest_type_pi
@ nodetest_type_pi
Definition: pugixml.cpp:9420
xpath_parser::binary_op_t::rettype
xpath_value_type rettype
Definition: pugixml.cpp:11813
ctx_special_attr
@ ctx_special_attr
Definition: pugixml.cpp:1864
xpath_query_impl::xpath_query_impl
xpath_query_impl()
Definition: pugixml.cpp:11978
as_wide_impl
PUGI__FN std::basic_string< wchar_t > as_wide_impl(const char *str, size_t size)
Definition: pugixml.cpp:2313
append_new_node
PUGI__FN_NO_INLINE xml_node_struct * append_new_node(xml_node_struct *node, xml_allocator &alloc, xml_node_type type=node_element)
Definition: pugixml.cpp:1398
remove_attribute
void remove_attribute(xml_attribute_struct *attr, xml_node_struct *node)
Definition: pugixml.cpp:1382
pugi::xml_document::save
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:7156
ast_op_less_or_equal
@ ast_op_less_or_equal
Definition: pugixml.cpp:9341
pugi::xml_attribute::set_value
bool set_value(const char_t *rhs)
Definition: pugixml.cpp:5306
ct_parse_cdata
@ ct_parse_cdata
Definition: pugixml.cpp:1834
document_order_comparator
Definition: pugixml.cpp:8057
strconv_pcdata_impl
Definition: pugixml.cpp:2658
pugi::xml_node
Definition: pugixml.hpp:455
xpath_ast_node::xpath_ast_node
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable *value)
Definition: pugixml.cpp:10214
namespace_uri_predicate
Definition: pugixml.cpp:8387
pugi::xml_writer_file::xml_writer_file
xml_writer_file(void *file)
Definition: pugixml.cpp:5049
pugi::xpath_variable_set
Definition: pugixml.hpp:1145
ct_parse_attr_ws
@ ct_parse_attr_ws
Definition: pugixml.cpp:1832
pugi::encoding_utf32_be
@ encoding_utf32_be
Definition: pugixml.hpp:224
nodetest_t
nodetest_t
Definition: pugixml.cpp:9415
ast_func_substring_2
@ ast_func_substring_2
Definition: pugixml.cpp:9372
pugi::status_bad_pcdata
@ status_bad_pcdata
Definition: pugixml.hpp:966
PUGI__NS_END
#define PUGI__NS_END
Definition: pugixml.cpp:160
wchar_selector< 4 >::writer
utf32_writer writer
Definition: pugixml.cpp:1799
xpath_stack_data::xpath_stack_data
xpath_stack_data()
Definition: pugixml.cpp:7705
pugi::xml_attribute::value
const char_t * value() const
Definition: pugixml.cpp:5222
lex_greater_or_equal
@ lex_greater_or_equal
Definition: pugixml.cpp:8986
xml_stream_chunk::data
T data[xml_memory_page_size/sizeof(T)]
Definition: pugixml.cpp:4854
pugi::status_bad_pi
@ status_bad_pi
Definition: pugixml.hpp:962
ast_func_substring_before
@ ast_func_substring_before
Definition: pugixml.cpp:9370
append_node
void append_node(xml_node_struct *child, xml_node_struct *node)
Definition: pugixml.cpp:1231
xpath_ast_node::_left
xpath_ast_node * _left
Definition: pugixml.cpp:9463
xpath_parser::_variables
xpath_variable_set * _variables
Definition: pugixml.cpp:11069
hash_string
PUGI__FN PUGI__UNSIGNED_OVERFLOW unsigned int hash_string(const char_t *str)
Definition: pugixml.cpp:8617
pugi::xml_node_iterator::operator--
const xml_node_iterator & operator--()
Definition: pugixml.cpp:6666
pugi::xpath_variable_set::add
xpath_variable * add(const char_t *name, xpath_value_type type)
Definition: pugixml.cpp:12464
default_allocate
PUGI__NS_BEGIN PUGI__FN void * default_allocate(size_t size)
Definition: pugixml.cpp:184
pugi::xml_node::operator>
bool operator>(const xml_node &r) const
Definition: pugixml.cpp:5462
xpath_lexer_string::begin
const char_t * begin
Definition: pugixml.cpp:9011
xpath_parser::binary_op_t::binary_op_t
binary_op_t()
Definition: pugixml.cpp:11816
xpath_ast_node::compare_eq
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:9484
pugi::xpath_query::evaluate_number
double evaluate_number(const xpath_node &n) const
Definition: pugixml.cpp:12622
PUGI__FN
#define PUGI__FN
Definition: pugixml.cpp:162
name_null_sentry::node
xml_node_struct * node
Definition: pugixml.cpp:5032
set_value_convert
PUGI__FN bool set_value_convert(String &dest, Header &header, uintptr_t header_mask, float value)
Definition: pugixml.cpp:4668
has_declaration
PUGI__FN bool has_declaration(xml_node_struct *node)
Definition: pugixml.cpp:4329
string_value
PUGI__FN xpath_string string_value(const xpath_node &na, xpath_allocator *alloc)
Definition: pugixml.cpp:7897
xpath_lexer::current
lexeme_t current() const
Definition: pugixml.cpp:9314
wchar_selector< 2 >::type
uint16_t type
Definition: pugixml.cpp:1789
ast_func_normalize_space_0
@ ast_func_normalize_space_0
Definition: pugixml.cpp:9376
pugi::xml_node_iterator
Definition: pugixml.hpp:799
utf16_writer
Definition: pugixml.cpp:1530
pugi::xpath_node::attribute
xml_attribute attribute() const
Definition: pugixml.cpp:12046
axis_preceding_sibling
@ axis_preceding_sibling
Definition: pugixml.cpp:9410
xpath_stack::result
xpath_allocator * result
Definition: pugixml.cpp:7693
allocate_attribute
PUGI__NS_END PUGI__NS_BEGIN xml_attribute_struct * allocate_attribute(xml_allocator &alloc)
Definition: pugixml.cpp:1173
pugi::xml_node::prepend_child
xml_node prepend_child(xml_node_type type=node_element)
Definition: pugixml.cpp:5816
allocate_node
xml_node_struct * allocate_node(xml_allocator &alloc, xml_node_type type)
Definition: pugixml.cpp:1182
less_equal
Definition: pugixml.cpp:7340
pugi::xml_text::operator!
bool operator!() const
Definition: pugixml.cpp:6392
pugi::xml_node::append_attribute
xml_attribute append_attribute(const char_t *name)
Definition: pugixml.cpp:5659
pugi::parse_comments
const unsigned int parse_comments
Definition: pugixml.hpp:161
utf8_writer::low
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1473
name_null_sentry::~name_null_sentry
~name_null_sentry()
Definition: pugixml.cpp:5040
utf32_writer::low
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1576
pugi::status_file_not_found
@ status_file_not_found
Definition: pugixml.hpp:955
xpath_ast_node::table
const unsigned char * table
Definition: pugixml.cpp:9478
pugi::xml_parse_result::xml_parse_result
xml_parse_result()
Definition: pugixml.cpp:6810
pugi::xml_attribute::empty
bool empty() const
Definition: pugixml.cpp:5212
strconv_pcdata_t
char_t *(* strconv_pcdata_t)(char_t *)
Definition: pugixml.cpp:2655
pugi::status_bad_end_element
@ status_bad_end_element
Definition: pugixml.hpp:969
xpath_parser::parse_relative_location_path
xpath_ast_node * parse_relative_location_path(xpath_ast_node *set)
Definition: pugixml.cpp:11679
utf8_writer
Definition: pugixml.cpp:1470
utf16_decoder
Definition: pugixml.cpp:1687
pugi::xml_node::operator==
bool operator==(const xml_node &r) const
Definition: pugixml.cpp:5447
auto_deleter::D
void(* D)(T *)
Definition: pugixml.cpp:264
get_file_size
PUGI__FN xml_parse_status get_file_size(FILE *file, size_t &out_result)
Definition: pugixml.cpp:4725
partition3
PUGI__FN void partition3(T *begin, T *end, T pivot, const Pred &pred, T **out_eqbeg, T **out_eqend)
Definition: pugixml.cpp:7430
xpath_parser::parse_node_test_type
nodetest_t parse_node_test_type(const xpath_lexer_string &name)
Definition: pugixml.cpp:11336
pugi::xml_named_node_iterator::operator!=
bool operator!=(const xml_named_node_iterator &rhs) const
Definition: pugixml.cpp:6757
xpath_ast_node::compare_rel
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:9577
pugi::xml_document::operator=
xml_document & operator=(const xml_document &)
convert_buffer_output_generic
PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t *data, size_t length, D, T)
Definition: pugixml.cpp:3581
xpath_parser::_scratch
char_t _scratch[32]
Definition: pugixml.cpp:11073
pugi::xml_node::set_name
bool set_name(const char_t *rhs)
Definition: pugixml.cpp:5639
pugi::format_skip_control_chars
const unsigned int format_skip_control_chars
Definition: pugixml.hpp:257
pugi::xpath_node_set::operator[]
const xpath_node & operator[](size_t index) const
Definition: pugixml.cpp:12200
pugi::format_attribute_single_quote
const unsigned int format_attribute_single_quote
Definition: pugixml.hpp:260
xml_buffered_writer::data_u8
uint8_t data_u8[4 *bufcapacity]
Definition: pugixml.cpp:3895
pugi::xml_attribute::next_attribute
xml_attribute next_attribute() const
Definition: pugixml.cpp:5160
pugi::xml_node_struct
Definition: pugixml.cpp:1111
xml_allocator::allocate_memory_oob
void * allocate_memory_oob(size_t size, xml_memory_page *&out_page)
Definition: pugixml.cpp:707
convert_number_to_string
PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator *alloc)
Definition: pugixml.cpp:8227
xml_allocator::deallocate_string
void deallocate_string(char_t *string)
Definition: pugixml.cpp:671
pugi::xpath_query::return_type
xpath_value_type return_type() const
Definition: pugixml.cpp:12594
xml_memory_string_header::full_size
uint16_t full_size
Definition: pugixml.cpp:505
xml_parser::parse_question
char_t * parse_question(char_t *s, xml_node_struct *&ref_cursor, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:3148
pugi::xpath_type_boolean
@ xpath_type_boolean
Definition: pugixml.hpp:1086
axis_parent
@ axis_parent
Definition: pugixml.cpp:9408
ast_func_normalize_space_1
@ ast_func_normalize_space_1
Definition: pugixml.cpp:9377
uhal::tests::c
ClientInterface * c
Definition: test_rawclient.cpp:94
pugi::xml_text::as_uint
unsigned int as_uint(unsigned int def=0) const
Definition: pugixml.cpp:6423
pugi::xml_attribute_struct::prev_attribute_c
xml_attribute_struct * prev_attribute_c
Definition: pugixml.cpp:1106
pugi::xml_attribute::hash_value
size_t hash_value() const
Definition: pugixml.cpp:5227
reverse
PUGI__FN void reverse(I begin, I end)
Definition: pugixml.cpp:7365
pugi::xml_attribute::as_uint
unsigned int as_uint(unsigned int def=0) const
Definition: pugixml.cpp:5180
pugi::xpath_variable_set::_clone
static bool _clone(xpath_variable *var, xpath_variable **out_result)
Definition: pugixml.cpp:12425
strequal
PUGI__FN bool strequal(const char_t *src, const char_t *dst)
Definition: pugixml.cpp:224
xpath_parser::parse_filter_expression
xpath_ast_node * parse_filter_expression()
Definition: pugixml.cpp:11478
node_copy_contents
PUGI__FN void node_copy_contents(xml_node_struct *dn, xml_node_struct *sn, xml_allocator *shared_alloc)
Definition: pugixml.cpp:4409
lex_multiply
@ lex_multiply
Definition: pugixml.cpp:8989
xml_memory_page_value_allocated_mask
static const uintptr_t xml_memory_page_value_allocated_mask
Definition: pugixml.cpp:437
PUGI__SNPRINTF
#define PUGI__SNPRINTF
Definition: pugixml.cpp:145
pugi::unspecified_bool_xpath_query
static PUGI__FN void unspecified_bool_xpath_query(xpath_query ***)
Definition: pugixml.cpp:12745
ast_func_not
@ ast_func_not
Definition: pugixml.cpp:9380
pugi::xml_node::unspecified_bool_type
void(* unspecified_bool_type)(xml_node ***)
Definition: pugixml.hpp:463
xml_allocator::allocate_string
char_t * allocate_string(size_t length)
Definition: pugixml.cpp:637
xml_allocator::allocate_memory
void * allocate_memory(size_t size, xml_memory_page *&out_page)
Definition: pugixml.cpp:541
xpath_stack_data
Definition: pugixml.cpp:7698
convert_number_to_boolean
PUGI__FN bool convert_number_to_boolean(double value)
Definition: pugixml.cpp:8170
pugi::xml_attribute_struct::xml_attribute_struct
xml_attribute_struct(impl::xml_memory_page *page)
Definition: pugixml.cpp:1096
utf32_writer
Definition: pugixml.cpp:1573
pugi::xml_node_struct::first_child
xml_node_struct * first_child
Definition: pugixml.cpp:1124
nodetest_pi
@ nodetest_pi
Definition: pugixml.cpp:9422
utf8_writer::value_type
uint8_t * value_type
Definition: pugixml.cpp:1471
pugi::xml_node::attribute_iterator
xml_attribute_iterator attribute_iterator
Definition: pugixml.hpp:682
pugi::xml_node_struct::value
char_t * value
Definition: pugixml.cpp:1120
new_xpath_variable
PUGI__FN T * new_xpath_variable(const char_t *name)
Definition: pugixml.cpp:8636
xpath_variable_boolean::value
bool value
Definition: pugixml.cpp:8576
pugi::xml_node::next_sibling
xml_node next_sibling() const
Definition: pugixml.cpp:5528
latin1_decoder
Definition: pugixml.cpp:1769
ast_func_count
@ ast_func_count
Definition: pugixml.cpp:9357
pugi::node_pcdata
@ node_pcdata
Definition: pugixml.hpp:143
xpath_parser::alloc_node
xpath_ast_node * alloc_node(ast_type_t type, xpath_ast_node *left, axis_t axis, nodetest_t test, const char_t *contents)
Definition: pugixml.cpp:11120
xml_parser::error_status
xml_parse_status error_status
Definition: pugixml.cpp:2916
pugi::xml_tree_walker::_depth
int _depth
Definition: pugixml.hpp:930
pugi::parse_fragment
const unsigned int parse_fragment
Definition: pugixml.hpp:198
latin1_decoder::process
static Traits::value_type process(const uint8_t *data, size_t size, typename Traits::value_type result, Traits)
Definition: pugixml.cpp:1772
PUGI__SKIPWS
#define PUGI__SKIPWS()
Definition: pugixml.cpp:2588
xml_buffered_writer::write
void write(char_t d0, char_t d1, char_t d2, char_t d3)
Definition: pugixml.cpp:3837
pugi::xpath_node_set::type
type_t type() const
Definition: pugixml.cpp:12185
integer_to_string
PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t * integer_to_string(char_t *begin, char_t *end, U value, bool negative)
Definition: pugixml.cpp:4620
strequalrange
PUGI__FN bool strequalrange(const char_t *lhs, const char_t *rhs, size_t count)
Definition: pugixml.cpp:236
pugi::xml_text::as_float
float as_float(float def=0) const
Definition: pugixml.cpp:6437
pugi::xml_text::as_double
double as_double(double def=0) const
Definition: pugixml.cpp:6430
pugi::xml_node_iterator::operator!=
bool operator!=(const xml_node_iterator &rhs) const
Definition: pugixml.cpp:6635
xpath_ast_node::eval_once
static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval)
Definition: pugixml.cpp:9572
xml_parser::parse
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:3505
string_to_integer
PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(const char_t *value, U minv, U maxv)
Definition: pugixml.cpp:4489
xpath_get_order
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node *begin, const xpath_node *end)
Definition: pugixml.cpp:8753
pugi::xml_tree_walker::begin
virtual bool begin(xml_node &node)
Definition: pugixml.cpp:5098
pugi::xml_named_node_iterator::operator->
xml_node * operator->() const
Definition: pugixml.cpp:6768
pugi::xpath_node::operator==
bool operator==(const xpath_node &n) const
Definition: pugixml.cpp:12070
xpath_ast_node::set_next
void set_next(xpath_ast_node *value)
Definition: pugixml.cpp:10239
xpath_ast_node::step_do
xpath_node_set_raw step_do(const xpath_context &c, const xpath_stack &stack, nodeset_eval_t eval, T v)
Definition: pugixml.cpp:10152
xml_buffered_writer::flush
size_t flush()
Definition: pugixml.cpp:3703
xml_parser
Definition: pugixml.cpp:2913
open_file_wide
PUGI__FN FILE * open_file_wide(const wchar_t *path, const wchar_t *mode)
Definition: pugixml.cpp:5000
PUGI__NS_BEGIN
#define PUGI__NS_BEGIN
Definition: pugixml.cpp:159
xml_buffered_writer::bufcapacity
@ bufcapacity
Definition: pugixml.cpp:3888
utf16_writer::high
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:1540
xpath_string::length
size_t length() const
Definition: pugixml.cpp:7815
pugi::xpath_node_set::_assign
void _assign(const_iterator begin, const_iterator end, type_t type)
Definition: pugixml.cpp:12092
pugi::xml_attribute::unspecified_bool_type
void(* unspecified_bool_type)(xml_attribute ***)
Definition: pugixml.hpp:356
name_null_sentry::name_null_sentry
name_null_sentry(xml_node_struct *node_)
Definition: pugixml.cpp:5035
tolower_ascii
PUGI__FN char_t tolower_ascii(char_t ch)
Definition: pugixml.cpp:7892
lex_string
@ lex_string
Definition: pugixml.cpp:9000
pugi::xml_object_range
Definition: pugixml.hpp:291
xpath_allocator::allocate
void * allocate(size_t size)
Definition: pugixml.cpp:7557
PUGI__NODETYPE
#define PUGI__NODETYPE(n)
Definition: pugixml.cpp:454
allow_insert_attribute
PUGI__FN bool allow_insert_attribute(xml_node_type parent)
Definition: pugixml.cpp:4351
get_buffer_encoding
PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void *contents, size_t size)
Definition: pugixml.cpp:2020
xpath_variable_string::name
char_t name[1]
Definition: pugixml.cpp:8602
xpath_parser::error
xpath_ast_node * error(const char *message)
Definition: pugixml.cpp:11075
pugi::encoding_wchar
@ encoding_wchar
Definition: pugixml.hpp:226
utf16_counter::high
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:1523
pugi::node_declaration
@ node_declaration
Definition: pugixml.hpp:147
get_strconv_attribute
PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
Definition: pugixml.cpp:2877
pugi::xml_attribute_iterator::operator==
bool operator==(const xml_attribute_iterator &rhs) const
Definition: pugixml.cpp:6691
pugi::xml_writer_stream
Definition: pugixml.hpp:333
xpath_variable_node_set::value
xpath_node_set value
Definition: pugixml.cpp:8611
load_buffer_impl
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:4691
pugi::deallocation_function
void(* deallocation_function)(void *ptr)
Definition: pugixml.hpp:1415
strconv_attribute_impl::parse_simple
static char_t * parse_simple(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2850
truncate_zeros
PUGI__FN void truncate_zeros(char *begin, char *end)
Definition: pugixml.cpp:8175
ct_parse_comment
@ ct_parse_comment
Definition: pugixml.cpp:1835
pugi::xpath_query::evaluate_node_set
xpath_node_set evaluate_node_set(const xpath_node &n) const
Definition: pugixml.cpp:12696
pugi::set_memory_management_functions
void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
Definition: pugixml.cpp:7253
axis_to_type
Definition: pugixml.cpp:9443
pugi::xml_node::operator<
bool operator<(const xml_node &r) const
Definition: pugixml.cpp:5457
utf32_decoder::type
uint32_t type
Definition: pugixml.cpp:1740
pugi::xpath_node::operator!
bool operator!() const
Definition: pugixml.cpp:12065
xml_parser::parse_exclamation
char_t * parse_exclamation(char_t *s, xml_node_struct *cursor, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:3039
ast_func_floor
@ ast_func_floor
Definition: pugixml.cpp:9387
pugi::xml_node::first_element_by_path
xml_node first_element_by_path(const char_t *path, char_t delimiter='/') const
Definition: pugixml.cpp:6178
pugi::xpath_type_node_set
@ xpath_type_node_set
Definition: pugixml.hpp:1083
pugi::encoding_utf32
@ encoding_utf32
Definition: pugixml.hpp:225
xml_buffered_writer::bufsize
size_t bufsize
Definition: pugixml.cpp:3902
pugi::xml_node_struct::xml_node_struct
xml_node_struct(impl::xml_memory_page *page, xml_node_type type)
Definition: pugixml.cpp:1112
PUGIXML_NOEXCEPT_IF_NOT_COMPACT
#define PUGIXML_NOEXCEPT_IF_NOT_COMPACT
Definition: pugixml.hpp:100
pugi::xml_node_iterator::operator++
const xml_node_iterator & operator++()
Definition: pugixml.cpp:6652
xpath_memory_block::alignment
double alignment
Definition: pugixml.cpp:7543
convert_string_to_number_scratch
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:8337
PUGI__FN_NO_INLINE
#define PUGI__FN_NO_INLINE
Definition: pugixml.cpp:163
pugi::xpath_query::unspecified_bool_type
void(* unspecified_bool_type)(xpath_query ***)
Definition: pugixml.hpp:1193
PUGI__SCANCHAR
#define PUGI__SCANCHAR(ch)
ct_parse_attr
@ ct_parse_attr
Definition: pugixml.cpp:1831
lex_minus
@ lex_minus
Definition: pugixml.cpp:8988
wchar_decoder::process
static Traits::value_type process(const wchar_t *data, size_t size, typename Traits::value_type result, Traits traits)
Definition: pugixml.cpp:1810
pugi::encoding_latin1
@ encoding_latin1
Definition: pugixml.hpp:227
pugi::xml_attribute_struct::next_attribute
xml_attribute_struct * next_attribute
Definition: pugixml.cpp:1107
prepend_attribute
void prepend_attribute(xml_attribute_struct *attr, xml_node_struct *node)
Definition: pugixml.cpp:1342
ast_func_namespace_uri_0
@ ast_func_namespace_uri_0
Definition: pugixml.cpp:9361
pugi::unspecified_bool_xml_node
static PUGI__FN void unspecified_bool_xml_node(xml_node ***)
Definition: pugixml.cpp:5398
PUGI__ENDSWITH
#define PUGI__ENDSWITH(c, e)
Definition: pugixml.cpp:2587
lex_open_square_brace
@ lex_open_square_brace
Definition: pugixml.cpp:8998
pugi::xml_node::append_buffer
xml_parse_result append_buffer(const void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:6080
xpath_lexer::_cur_lexeme_contents
xpath_lexer_string _cur_lexeme_contents
Definition: pugixml.cpp:9030
xpath_context::n
xpath_node n
Definition: pugixml.cpp:8970
less
Definition: pugixml.cpp:7332
gap::end
char_t * end
Definition: pugixml.cpp:2406
pugi::xml_document::load_buffer
xml_parse_result load_buffer(const void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7135
xpath_stack_data::stack
xpath_stack stack
Definition: pugixml.cpp:7702
pugi::xml_named_node_iterator::operator*
xml_node & operator*() const
Definition: pugixml.cpp:6762
xpath_node_set_raw
Definition: pugixml.cpp:8814
pugi::xml_attribute_iterator::operator++
const xml_attribute_iterator & operator++()
Definition: pugixml.cpp:6713
pugi::xml_attribute::operator<=
bool operator<=(const xml_attribute &r) const
Definition: pugixml.cpp:5150
pugi::encoding_utf8
@ encoding_utf8
Definition: pugixml.hpp:219
pugi::xml_document::reset
void reset()
Definition: pugixml.cpp:6879
allow_move
PUGI__FN bool allow_move(xml_node parent, xml_node child)
Definition: pugixml.cpp:4365
lexeme_t
lexeme_t
Definition: pugixml.cpp:8979
pugi::node_pi
@ node_pi
Definition: pugixml.hpp:146
pugi::xpath_node::operator!=
bool operator!=(const xpath_node &n) const
Definition: pugixml.cpp:12075
pugi::xml_node_iterator::operator==
bool operator==(const xml_node_iterator &rhs) const
Definition: pugixml.cpp:6630
xml_memory_page_value_allocated_or_shared_mask
static const uintptr_t xml_memory_page_value_allocated_or_shared_mask
Definition: pugixml.cpp:442
ast_func_false
@ ast_func_false
Definition: pugixml.cpp:9382
xpath_ast_node::is_posinv_step
bool is_posinv_step() const
Definition: pugixml.cpp:11042
pugi::xml_tree_walker
Definition: pugixml.hpp:926
translate_table
PUGI__FN char_t * translate_table(char_t *buffer, const unsigned char *table)
Definition: pugixml.cpp:8535
pugi::xml_node::attribute
xml_attribute attribute(const char_t *name) const
Definition: pugixml.cpp:5507
remove_node
void remove_node(xml_node_struct *node)
Definition: pugixml.cpp:1304
xpath_allocator::reallocate
void * reallocate(void *ptr, size_t old_size, size_t new_size)
Definition: pugixml.cpp:7594
xpath_node_set_raw::begin
xpath_node * begin() const
Definition: pugixml.cpp:8826
wchar_decoder::type
wchar_t type
Definition: pugixml.cpp:1808
xpath_allocator_capture::_target
xpath_allocator * _target
Definition: pugixml.cpp:7687
xpath_parser::alloc_node
void * alloc_node()
Definition: pugixml.cpp:11091
pugi::xml_node_struct::name
char_t * name
Definition: pugixml.cpp:1119
wchar_selector< 4 >::counter
utf32_counter counter
Definition: pugixml.cpp:1798
chartypex_t
chartypex_t
Definition: pugixml.cpp:1862
xpath_ast_node::apply_predicate_number_const
static void apply_predicate_number_const(xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack)
Definition: pugixml.cpp:9700
nodeset_eval_first
@ nodeset_eval_first
Definition: pugixml.cpp:9439
pugi::encoding_utf32_le
@ encoding_utf32_le
Definition: pugixml.hpp:223
axis_t
axis_t
Definition: pugixml.cpp:9398
pugi::xml_attribute_iterator
Definition: pugixml.hpp:841
node_is_before_sibling
PUGI__FN bool node_is_before_sibling(xml_node_struct *ln, xml_node_struct *rn)
Definition: pugixml.cpp:7951
xpath_lexer
Definition: pugixml.cpp:9027
pugi::encoding_auto
@ encoding_auto
Definition: pugixml.hpp:218
xml_parser::error_offset
char_t * error_offset
Definition: pugixml.cpp:2915
pugi::xml_node::insert_attribute_after
xml_attribute insert_attribute_after(const char_t *name, const xml_attribute &attr)
Definition: pugixml.cpp:5693
wchar_selector< 4 >::decoder
utf32_decoder< opt_false > decoder
Definition: pugixml.cpp:1800
pugi::xml_node::insert_copy_before
xml_attribute insert_copy_before(const xml_attribute &proto, const xml_attribute &attr)
Definition: pugixml.cpp:5781
pugi::xml_attribute::operator=
xml_attribute & operator=(const char_t *rhs)
Definition: pugixml.cpp:5237
opt_true
Definition: pugixml.cpp:1431
PUGI__GETPAGE_IMPL
#define PUGI__GETPAGE_IMPL(header)
Definition: pugixml.cpp:450
wchar_counter
wchar_selector< sizeof(wchar_t)>::counter wchar_counter
Definition: pugixml.cpp:1803
uhal::tests::total
uint32_t total
Definition: test_rawclient.cpp:158
pugi::get_memory_deallocation_function
deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
Definition: pugixml.cpp:7264
xml_memory_block_alignment
PUGI__NS_END static PUGI__NS_BEGIN const uintptr_t xml_memory_block_alignment
Definition: pugixml.cpp:431
nodetest_all_in_namespace
@ nodetest_all_in_namespace
Definition: pugixml.cpp:9424
pugi::xml_named_node_iterator::operator==
bool operator==(const xml_named_node_iterator &rhs) const
Definition: pugixml.cpp:6752
xpath_ast_node::eval_node_set
xpath_node_set_raw eval_node_set(const xpath_context &c, const xpath_stack &stack, nodeset_eval_t eval)
Definition: pugixml.cpp:10804
pugi::xml_attribute_iterator::_wrap
xml_attribute _wrap
Definition: pugixml.hpp:845
ast_func_name_1
@ ast_func_name_1
Definition: pugixml.cpp:9364
pugi::xml_attribute::xml_attribute
xml_attribute()
Definition: pugixml.cpp:5108
pugi::xpath_query::evaluate_string
string_t evaluate_string(const xpath_node &n) const
Definition: pugixml.cpp:12644
guess_buffer_encoding
PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t *data, size_t size)
Definition: pugixml.cpp:1972
xml_stream_chunk::size
size_t size
Definition: pugixml.cpp:4852
xpath_string::empty
bool empty() const
Definition: pugixml.cpp:7838
pugi::xml_node::xml_named_node_iterator
friend class xml_named_node_iterator
Definition: pugixml.hpp:458
ast_func_string_0
@ ast_func_string_0
Definition: pugixml.cpp:9365
xpath_ast_node::apply_predicate
void apply_predicate(xpath_node_set_raw &ns, size_t first, const xpath_stack &stack, bool once)
Definition: pugixml.cpp:9728
xpath_parser::xpath_parser
xpath_parser(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
Definition: pugixml.cpp:11935
pugi::xpath_node_set::_end
xpath_node * _end
Definition: pugixml.hpp:1394
xpath_allocator::revert
void revert(const xpath_allocator &state)
Definition: pugixml.cpp:7641
xml_allocator::allocate_page
xml_memory_page * allocate_page(size_t data_size)
Definition: pugixml.cpp:517
xpath_query_impl
Definition: pugixml.cpp:11960
pugi::xml_node::xml_node
xml_node()
Definition: pugixml.cpp:5390
pugi::format_no_declaration
const unsigned int format_no_declaration
Definition: pugixml.hpp:242
pugi::xml_node::print
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:6282
text_output
PUGI__FN void text_output(xml_buffered_writer &writer, const char_t *s, chartypex_t type, unsigned int flags)
Definition: pugixml.cpp:3958
PUGI__SCANCHARTYPE
#define PUGI__SCANCHARTYPE(ct)
utf32_writer::any
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:1590
PUGI__UNSIGNED_OVERFLOW
#define PUGI__UNSIGNED_OVERFLOW
Definition: pugixml.cpp:117
ast_func_string_length_0
@ ast_func_string_length_0
Definition: pugixml.cpp:9374
get_value_uint
PUGI__FN unsigned int get_value_uint(const char_t *value)
Definition: pugixml.cpp:4576
pugi::xpath_variable::_type
xpath_value_type _type
Definition: pugixml.hpp:1114
xpath_variable_boolean::xpath_variable_boolean
xpath_variable_boolean()
Definition: pugixml.cpp:8572
as_utf8_impl
PUGI__FN std::string as_utf8_impl(const wchar_t *str, size_t length)
Definition: pugixml.cpp:2298
pugi::xml_attribute::operator>
bool operator>(const xml_attribute &r) const
Definition: pugixml.cpp:5145
xpath_lexer_string::xpath_lexer_string
xpath_lexer_string()
Definition: pugixml.cpp:9014
min_element
PUGI__FN I min_element(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7354
strlength_wide
PUGI__FN size_t strlength_wide(const wchar_t *s)
Definition: pugixml.cpp:246
pugi::xml_text::operator=
xml_text & operator=(const char_t *rhs)
Definition: pugixml.cpp:6539
ast_func_ceiling
@ ast_func_ceiling
Definition: pugixml.cpp:9388
PUGI__OPTSET
#define PUGI__OPTSET(OPT)
Definition: pugixml.cpp:2589
get_latin1_7bit_prefix_length
PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t *data, size_t size)
Definition: pugixml.cpp:2199
insert_node_before
void insert_node_before(xml_node_struct *child, xml_node_struct *node)
Definition: pugixml.cpp:1287
latin1_writer::high
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:1609
gap::push
void push(char_t *&s, size_t count)
Definition: pugixml.cpp:2415
xpath_lexer::_cur_lexeme
lexeme_t _cur_lexeme
Definition: pugixml.cpp:9032
ast_func_round
@ ast_func_round
Definition: pugixml.cpp:9389
get_wchar_encoding
PUGI__FN xml_encoding get_wchar_encoding()
Definition: pugixml.cpp:1908
pugi::xpath_variable::type
xpath_value_type type() const
Definition: pugixml.cpp:12266
pugi::xpath_node_set::_begin
xpath_node * _begin
Definition: pugixml.hpp:1393
pugi::xml_document
Definition: pugixml.hpp:1001
get_value_float
PUGI__FN float get_value_float(const char_t *value)
Definition: pugixml.cpp:4590
get_value_double
PUGI__FN double get_value_double(const char_t *value)
Definition: pugixml.cpp:4581
get_strconv_pcdata
PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
Definition: pugixml.cpp:2708
pugi::xpath_node_set::operator=
xpath_node_set & operator=(const xpath_node_set &ns)
Definition: pugixml.cpp:12157
allow_insert_child
PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child)
Definition: pugixml.cpp:4356
text_output_cdata
PUGI__FN void text_output_cdata(xml_buffered_writer &writer, const char_t *s)
Definition: pugixml.cpp:3966
xpath_variable_node_set
Definition: pugixml.cpp:8606
pugi::parse_wnorm_attribute
const unsigned int parse_wnorm_attribute
Definition: pugixml.hpp:180
pugi::parse_trim_pcdata
const unsigned int parse_trim_pcdata
Definition: pugixml.hpp:194
pugi::as_utf8
std::basic_string< char, std::char_traits< char >, std::allocator< char > > PUGIXML_FUNCTION as_utf8(const wchar_t *str)
Definition: pugixml.cpp:7228
pugi::format_no_escapes
const unsigned int format_no_escapes
Definition: pugixml.hpp:245
axis_attribute
@ axis_attribute
Definition: pugixml.cpp:9401
xpath_allocator_capture::~xpath_allocator_capture
~xpath_allocator_capture()
Definition: pugixml.cpp:7682
xml_buffered_writer::operator=
xml_buffered_writer & operator=(const xml_buffered_writer &)
pugi::xml_node_struct::next_sibling
xml_node_struct * next_sibling
Definition: pugixml.cpp:1127
pugi::xml_encoding
xml_encoding
Definition: pugixml.hpp:217
insert_node_after
void insert_node_after(xml_node_struct *child, xml_node_struct *node)
Definition: pugixml.cpp:1270
utf8_writer::high
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:1498
ast_step_root
@ ast_step_root
Definition: pugixml.cpp:9391
xml_extra_buffer::next
xml_extra_buffer * next
Definition: pugixml.cpp:1138
xpath_ast_node::xpath_ast_node
xpath_ast_node(ast_type_t type, xpath_ast_node *left, xpath_ast_node *right, predicate_t test)
Definition: pugixml.cpp:10233
lex_var_ref
@ lex_var_ref
Definition: pugixml.cpp:8991
xpath_allocator_capture::_state
xpath_allocator _state
Definition: pugixml.cpp:7688
gap::size
size_t size
Definition: pugixml.cpp:2407
xpath_parser::binary_op_t::asttype
ast_type_t asttype
Definition: pugixml.cpp:11812
xpath_node_set_raw::remove_duplicates
void remove_duplicates(xpath_allocator *alloc)
Definition: pugixml.cpp:8897
load_stream_data_noseek
PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream< T > &stream, void **out_buffer, size_t *out_size)
Definition: pugixml.cpp:4857
xpath_string::xpath_string
xpath_string(const char_t *buffer, bool uses_heap_, size_t length_heap)
Definition: pugixml.cpp:7741
insert_attribute_after
void insert_attribute_after(xml_attribute_struct *attr, xml_attribute_struct *place, xml_node_struct *node)
Definition: pugixml.cpp:1358
xpath_stack_data::oom
bool oom
Definition: pugixml.cpp:7703
xpath_string::from_heap_preallocated
static xpath_string from_heap_preallocated(const char_t *begin, const char_t *end)
Definition: pugixml.cpp:7751
lex_greater
@ lex_greater
Definition: pugixml.cpp:8984
pugi::xml_document::save_file
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:7200
xml_memory_page::prev
xml_memory_page * prev
Definition: pugixml.cpp:481
ast_op_and
@ ast_op_and
Definition: pugixml.cpp:9336
pugi::node_element
@ node_element
Definition: pugixml.hpp:142
pugi::xpath_parse_result::xpath_parse_result
xpath_parse_result()
Definition: pugixml.cpp:12226
xpath_parser::error_oom
xpath_ast_node * error_oom()
Definition: pugixml.cpp:11083
utf32_counter::value_type
size_t value_type
Definition: pugixml.cpp:1559
pugi::status_end_element_mismatch
@ status_end_element_mismatch
Definition: pugixml.hpp:970
xpath_node_set_raw::size
size_t size() const
Definition: pugixml.cpp:8841
pugi::xml_text::xml_text
xml_text()
Definition: pugixml.cpp:6379
gap::flush
char_t * flush(char_t *s)
Definition: pugixml.cpp:2432
get_value_int
PUGI__FN int get_value_int(const char_t *value)
Definition: pugixml.cpp:4571
parse_declaration_encoding
PUGI__FN bool parse_declaration_encoding(const uint8_t *data, size_t size, const uint8_t *&out_encoding, size_t &out_length)
Definition: pugixml.cpp:1918
pugi::xml_text::set
bool set(const char_t *rhs)
Definition: pugixml.cpp:6467
xpath_parser::binary_op_t::parse
static binary_op_t parse(xpath_lexer &lexer)
Definition: pugixml.cpp:11824
pugi::status_no_document_element
@ status_no_document_element
Definition: pugixml.hpp:974
ast_func_sum
@ ast_func_sum
Definition: pugixml.cpp:9386
pugi::xml_named_node_iterator
Definition: pugixml.hpp:883
chartype_t
chartype_t
Definition: pugixml.cpp:1829
namespace_uri_predicate::namespace_uri_predicate
namespace_uri_predicate(const char_t *name)
Definition: pugixml.cpp:8391
xml_memory_page_size
static const size_t xml_memory_page_size
Definition: pugixml.cpp:494
pugi::xml_document::load_buffer_inplace
xml_parse_result load_buffer_inplace(void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7142
utf8_counter
Definition: pugixml.cpp:1449
xpath_ast_node::_next
xpath_ast_node * _next
Definition: pugixml.cpp:9465
lex_slash
@ lex_slash
Definition: pugixml.cpp:8996
pugi::xml_writer
Definition: pugixml.hpp:309
pugi::xml_node::prepend_move
xml_node prepend_move(const xml_node &moved)
Definition: pugixml.cpp:5991
prepend_node
void prepend_node(xml_node_struct *child, xml_node_struct *node)
Definition: pugixml.cpp:1252
pugi::node_doctype
@ node_doctype
Definition: pugixml.hpp:148
PUGI__SCANFOR
#define PUGI__SCANFOR(X)
Definition: pugixml.cpp:2592
node_copy_string
PUGI__FN void node_copy_string(String &dest, Header &header, uintptr_t header_mask, char_t *source, Header &source_header, xml_allocator *alloc)
Definition: pugixml.cpp:4390
pugi::xpath_variable_set::_destroy
static void _destroy(xpath_variable *var)
Definition: pugixml.cpp:12452
xml_document_struct
Definition: pugixml.cpp:1142
pugi::xpath_query::_result
xpath_parse_result _result
Definition: pugixml.hpp:1191
utf16_counter::value_type
size_t value_type
Definition: pugixml.cpp:1516
indent_indent
@ indent_indent
Definition: pugixml.cpp:4233
xpath_allocator::xpath_allocator
xpath_allocator(xpath_memory_block *root, bool *error=0)
Definition: pugixml.cpp:7553
xpath_lexer::xpath_lexer
xpath_lexer(const char_t *query)
Definition: pugixml.cpp:9035
xml_memory_page::construct
static xml_memory_page * construct(void *memory)
Definition: pugixml.cpp:460
axis_descendant_or_self
@ axis_descendant_or_self
Definition: pugixml.cpp:9404
lex_less_or_equal
@ lex_less_or_equal
Definition: pugixml.cpp:8985
xpath_ast_node::step_push
bool step_push(xpath_node_set_raw &ns, xml_node_struct *n, xpath_allocator *alloc)
Definition: pugixml.cpp:9792
ast_string_constant
@ ast_string_constant
Definition: pugixml.cpp:9352
pugi
Definition: pugixml.hpp:124
get_write_encoding
PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
Definition: pugixml.cpp:3563
less_equal::operator()
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:7341
set_value_integer
PUGI__FN bool set_value_integer(String &dest, Header &header, uintptr_t header_mask, U value, bool negative)
Definition: pugixml.cpp:4658
local_name
PUGI__FN const char_t * local_name(const xpath_node &node)
Definition: pugixml.cpp:8378
ast_unknown
@ ast_unknown
Definition: pugixml.cpp:9334
ast_op_subtract
@ ast_op_subtract
Definition: pugixml.cpp:9344
xpath_ast_node::set_right
void set_right(xpath_ast_node *value)
Definition: pugixml.cpp:10244
xpath_parser::parse_location_path
xpath_ast_node * parse_location_path()
Definition: pugixml.cpp:11704
ast_op_mod
@ ast_op_mod
Definition: pugixml.cpp:9347
PUGI__PUSHNODE
#define PUGI__PUSHNODE(TYPE)
Definition: pugixml.cpp:2590
pugi::xpath_query
Definition: pugixml.hpp:1188
PUGI__THROW_ERROR
#define PUGI__THROW_ERROR(err, m)
Definition: pugixml.cpp:2596
ct_start_symbol
@ ct_start_symbol
Definition: pugixml.cpp:1837
pugi::xpath_parse_result::error
const char * error
Definition: pugixml.hpp:1093
xpath_string
Definition: pugixml.cpp:7725
load_file_impl
PUGI__FN xml_parse_result load_file_impl(xml_document_struct *doc, FILE *file, unsigned int options, xml_encoding encoding, char_t **out_buffer)
Definition: pugixml.cpp:4789
pugi::xml_document::_move
void _move(xml_document &rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
xml_buffered_writer::data_u16
uint16_t data_u16[2 *bufcapacity]
Definition: pugixml.cpp:3896
pugi::unspecified_bool_xml_text
static PUGI__FN void unspecified_bool_xml_text(xml_text ***)
Definition: pugixml.cpp:6383
xpath_variable_number::xpath_variable_number
xpath_variable_number()
Definition: pugixml.cpp:8582
uhal::tests::write
c write(addr, xx[0])
xml_stream_chunk::create
static xml_stream_chunk * create()
Definition: pugixml.cpp:4826
wchar_decoder
Definition: pugixml.cpp:1807
translate_table_generate
PUGI__FN unsigned char * translate_table_generate(xpath_allocator *alloc, const char_t *from, const char_t *to)
Definition: pugixml.cpp:8503
pugi::xpath_query::evaluate_node
xpath_node evaluate_node(const xpath_node &n) const
Definition: pugixml.cpp:12718
xpath_ast_node::apply_predicate_boolean
static void apply_predicate_boolean(xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack, bool once)
Definition: pugixml.cpp:9648
ast_func_string_length_1
@ ast_func_string_length_1
Definition: pugixml.cpp:9375
xml_memory_page_name_allocated_mask
static const uintptr_t xml_memory_page_name_allocated_mask
Definition: pugixml.cpp:436
pugi::status_append_invalid_root
@ status_append_invalid_root
Definition: pugixml.hpp:972
xml_allocator::reserve
bool reserve()
Definition: pugixml.cpp:690
pugi::format_no_empty_element_tags
const unsigned int format_no_empty_element_tags
Definition: pugixml.hpp:254
pugi::xml_document::load_string
xml_parse_result load_string(const char_t *contents, unsigned int options=parse_default)
Definition: pugixml.cpp:7098
pugi::xml_parse_status
xml_parse_status
Definition: pugixml.hpp:952
pugi::xpath_variable_set::_swap
void _swap(xpath_variable_set &rhs)
Definition: pugixml.cpp:12401
xpath_node_set_raw::_eos
xpath_node * _eos
Definition: pugixml.cpp:8819
ct_parse_pcdata
@ ct_parse_pcdata
Definition: pugixml.cpp:1830
pugi::xml_node::type
xml_node_type type() const
Definition: pugixml.cpp:5487
xpath_variable_number::name
char_t name[1]
Definition: pugixml.cpp:8587
pugi::xpath_variable_set::_find
xpath_variable * _find(const char_t *name) const
Definition: pugixml.cpp:12412
pugi::xpath_variable_set::~xpath_variable_set
~xpath_variable_set()
Definition: pugixml.cpp:12343
pugi::xml_attribute::operator!
bool operator!() const
Definition: pugixml.cpp:5125
pugi::char_t
PUGIXML_CHAR char_t
Definition: pugixml.hpp:126
ctx_digit
@ ctx_digit
Definition: pugixml.cpp:1866
PUGI__SCANWHILE_UNROLL
#define PUGI__SCANWHILE_UNROLL(X)
Definition: pugixml.cpp:2594
pugi::xml_named_node_iterator::xml_named_node_iterator
xml_named_node_iterator()
Definition: pugixml.cpp:6740
pugi::status_out_of_memory
@ status_out_of_memory
Definition: pugixml.hpp:957
strconv_attribute_impl::parse_wnorm
static char_t * parse_wnorm(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2730
pugi::xpath_variable
Definition: pugixml.hpp:1110
xpath_string::c_str
const char_t * c_str() const
Definition: pugixml.cpp:7810
utf16_counter
Definition: pugixml.cpp:1515
pugi::xpath_variable::_next
xpath_variable * _next
Definition: pugixml.hpp:1115
pugi::xml_node::text
xml_text text() const
Definition: pugixml.cpp:5594
latin1_writer
Definition: pugixml.cpp:1599
text_output_escaped
PUGI__FN void text_output_escaped(xml_buffered_writer &writer, const char_t *s, chartypex_t type, unsigned int flags)
Definition: pugixml.cpp:3906
pugi::xml_text::as_string
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition: pugixml.cpp:6409
ast_op_or
@ ast_op_or
Definition: pugixml.cpp:9335
lex_double_slash
@ lex_double_slash
Definition: pugixml.cpp:8997
pugi::xpath_variable::get_boolean
bool get_boolean() const
Definition: pugixml.cpp:12271
PUGIXML_FUNCTION
#define PUGIXML_FUNCTION
Definition: pugixml.hpp:64
find_substring
PUGI__FN const char_t * find_substring(const char_t *s, const char_t *p)
Definition: pugixml.cpp:7881
pugi::xml_node::_root
xml_node_struct * _root
Definition: pugixml.hpp:461
xpath_ast_node::xpath_ast_node
xpath_ast_node(ast_type_t type, xpath_ast_node *left, axis_t axis, nodetest_t test, const char_t *contents)
Definition: pugixml.cpp:10226
pugi::parse_eol
const unsigned int parse_eol
Definition: pugixml.hpp:174
xpath_lexer::state
const char_t * state() const
Definition: pugixml.cpp:9040
hash_insert
PUGI__FN bool hash_insert(const void **table, size_t size, const void *key)
Definition: pugixml.cpp:7487
xpath_ast_node::eval_string_concat
xpath_string eval_string_concat(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:10522
pugi::xpath_variable_set::get
xpath_variable * get(const char_t *name)
Definition: pugixml.cpp:12511
pugi::xml_attribute_iterator::operator->
xml_attribute * operator->() const
Definition: pugixml.cpp:6707
axis_self
@ axis_self
Definition: pugixml.cpp:9411
xml_buffered_writer::data_u32
uint32_t data_u32[bufcapacity]
Definition: pugixml.cpp:3897
load_stream_impl
PUGI__FN xml_parse_result load_stream_impl(xml_document_struct *doc, std::basic_istream< T > &stream, unsigned int options, xml_encoding encoding, char_t **out_buffer)
Definition: pugixml.cpp:4947
default_deallocate
PUGI__FN void default_deallocate(void *ptr)
Definition: pugixml.cpp:189
xpath_parser::parse_step
xpath_ast_node * parse_step(xpath_ast_node *set)
Definition: pugixml.cpp:11510
xpath_node_set_raw::xpath_node_set_raw
xpath_node_set_raw()
Definition: pugixml.cpp:8822
xml_buffered_writer::write_string
void write_string(const char_t *data)
Definition: pugixml.cpp:3782
pugi::xml_node::insert_move_after
xml_node insert_move_after(const xml_node &moved, const xml_node &node)
Definition: pugixml.cpp:6007
xml_buffered_writer::write
void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
Definition: pugixml.cpp:3849
is_nan
PUGI__FN bool is_nan(double value)
Definition: pugixml.cpp:8125
pugi::xml_node::operator<=
bool operator<=(const xml_node &r) const
Definition: pugixml.cpp:5467
pugi::xml_parse_result
Definition: pugixml.hpp:979
pugi::xml_named_node_iterator::_name
const char_t * _name
Definition: pugixml.hpp:919
predicate_posinv
@ predicate_posinv
Definition: pugixml.cpp:9430
xpath_string::uses_heap
bool uses_heap() const
Definition: pugixml.cpp:7853
utf8_counter::low
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1452
xml_document_struct::buffer
const char_t * buffer
Definition: pugixml.cpp:1147
xml_stream_chunk::next
xml_stream_chunk * next
Definition: pugixml.cpp:4851
xml_allocator::allocate_object
void * allocate_object(size_t size, xml_memory_page *&out_page)
Definition: pugixml.cpp:587
node_copy_tree
PUGI__FN void node_copy_tree(xml_node_struct *dn, xml_node_struct *sn)
Definition: pugixml.cpp:4426
convert_buffer_output
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:3668
ctx_special_pcdata
@ ctx_special_pcdata
Definition: pugixml.cpp:1863
xpath_ast_node::step_fill
void step_fill(xpath_node_set_raw &ns, xml_node_struct *n, xpath_allocator *alloc, bool once, T)
Definition: pugixml.cpp:9867
xml_extra_buffer
Definition: pugixml.cpp:1136
strconv_attribute_impl
Definition: pugixml.cpp:2729
xpath_parser::_result
xpath_parse_result * _result
Definition: pugixml.cpp:11071
pugi::xpath_variable_set::set
bool set(const char_t *name, bool value)
Definition: pugixml.cpp:12487
xpath_stack_data::~xpath_stack_data
~xpath_stack_data()
Definition: pugixml.cpp:7714
pugi::xpath_query::operator=
xpath_query & operator=(const xpath_query &)
xpath_allocator_capture::xpath_allocator_capture
xpath_allocator_capture(xpath_allocator *alloc)
Definition: pugixml.cpp:7678
pugi::status_unrecognized_tag
@ status_unrecognized_tag
Definition: pugixml.hpp:960
convert_number_to_string_special
PUGI__FN const char_t * convert_number_to_string_special(double value)
Definition: pugixml.cpp:8138
predicate_constant_one
@ predicate_constant_one
Definition: pugixml.cpp:9432
ast_predicate
@ ast_predicate
Definition: pugixml.cpp:9350
xpath_ast_node::xpath_ast_node
xpath_ast_node(const xpath_ast_node &)
utf16_counter::low
static value_type low(value_type result, uint32_t)
Definition: pugixml.cpp:1518
pugi::xml_writer_file::file
void * file
Definition: pugixml.hpp:327
strconv_attribute_impl::parse_eol
static char_t * parse_eol(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2818
pugi::xml_node_iterator::_parent
xml_node _parent
Definition: pugixml.hpp:804
pugi::xpath_node_set::~xpath_node_set
~xpath_node_set()
Definition: pugixml.cpp:12146
utf32_writer::high
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:1583
pugi::allocation_function
void *(* allocation_function)(size_t size)
Definition: pugixml.hpp:1412
xml_memory_page_name_allocated_or_shared_mask
static const uintptr_t xml_memory_page_name_allocated_or_shared_mask
Definition: pugixml.cpp:441
wchar_selector< 2 >::writer
utf16_writer writer
Definition: pugixml.cpp:1791
endian_swap
PUGI__NS_END PUGI__NS_BEGIN uint16_t endian_swap(uint16_t value)
Definition: pugixml.cpp:1438
axis_child
@ axis_child
Definition: pugixml.cpp:9402
pugi::xml_document::document_element
xml_node document_element() const
Definition: pugixml.cpp:7216
pugi::xpath_query::_impl
void * _impl
Definition: pugixml.hpp:1190
xpath_memory_block::capacity
size_t capacity
Definition: pugixml.cpp:7538
xpath_stack::temp
xpath_allocator * temp
Definition: pugixml.cpp:7694
pugi::encoding_utf16_be
@ encoding_utf16_be
Definition: pugixml.hpp:221
utf32_writer::value_type
uint32_t * value_type
Definition: pugixml.cpp:1574
pugi::xml_attribute::as_int
int as_int(int def=0) const
Definition: pugixml.cpp:5175
gap
Definition: pugixml.cpp:2405
nodeset_eval_t
nodeset_eval_t
Definition: pugixml.cpp:9436
xml_parser::parse_tree
char_t * parse_tree(char_t *s, xml_node_struct *root, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:3242
xml_memory_page::freed_size
size_t freed_size
Definition: pugixml.cpp:485
pugi::xpath_type_string
@ xpath_type_string
Definition: pugixml.hpp:1085
pugi::xml_node_type
xml_node_type
Definition: pugixml.hpp:139
xpath_ast_node::step_push
bool step_push(xpath_node_set_raw &ns, xml_attribute_struct *a, xml_node_struct *parent, xpath_allocator *alloc)
Definition: pugixml.cpp:9752
close_file
PUGI__FN void close_file(FILE *file)
Definition: pugixml.cpp:4818
pugi::xml_node::root
xml_node root() const
Definition: pugixml.cpp:5589
chartypex_table
static const unsigned char chartypex_table[256]
Definition: pugixml.cpp:1870
xpath_node_set_raw::type
xpath_node_set::type_t type() const
Definition: pugixml.cpp:8935
xpath_string::_uses_heap
bool _uses_heap
Definition: pugixml.cpp:7727