HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pugixml.cpp
Go to the documentation of this file.
1 /**
2  * pugixml parser - version 1.12
3  * --------------------------------------------------------
4  * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
5  * Report bugs and download new versions at https://pugixml.org/
6  *
7  * This library is distributed under the MIT License. See notice at the end
8  * of this file.
9  *
10  * This work is based on the pugxml parser, which is:
11  * Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
12  */
13 // clang-format off
14 
15 #ifndef SOURCE_PUGIXML_CPP
16 #define SOURCE_PUGIXML_CPP
17 
18 #include "pugixml.hpp"
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <assert.h>
24 #include <limits.h>
25 
26 #ifdef PUGIXML_WCHAR_MODE
27 # include <wchar.h>
28 #endif
29 
30 #ifndef PUGIXML_NO_XPATH
31 # include <math.h>
32 # include <float.h>
33 #endif
34 
35 #ifndef PUGIXML_NO_STL
36 # include <istream>
37 # include <ostream>
38 # include <string>
39 #endif
40 
41 // For placement new
42 #include <new>
43 
44 #ifdef _MSC_VER
45 # pragma warning(push)
46 # pragma warning(disable: 4127) // conditional expression is constant
47 # pragma warning(disable: 4324) // structure was padded due to __declspec(align())
48 # pragma warning(disable: 4702) // unreachable code
49 # pragma warning(disable: 4996) // this function or variable may be unsafe
50 #endif
51 
52 #if defined(_MSC_VER) && defined(__c2__)
53 # pragma clang diagnostic push
54 # pragma clang diagnostic ignored "-Wdeprecated" // this function or variable may be unsafe
55 #endif
56 
57 #ifdef __INTEL_COMPILER
58 # pragma warning(disable: 177) // function was declared but never referenced
59 # pragma warning(disable: 279) // controlling expression is constant
60 # pragma warning(disable: 1478 1786) // function was declared "deprecated"
61 # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type
62 #endif
63 
64 #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
65 # pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away
66 #endif
67 
68 #ifdef __BORLANDC__
69 # pragma option push
70 # pragma warn -8008 // condition is always false
71 # pragma warn -8066 // unreachable code
72 #endif
73 
74 #ifdef __SNC__
75 // Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug
76 # pragma diag_suppress=178 // function was declared but never referenced
77 # pragma diag_suppress=237 // controlling expression is constant
78 #endif
79 
80 #ifdef __TI_COMPILER_VERSION__
81 # pragma diag_suppress 179 // function was declared but never referenced
82 #endif
83 
84 // Inlining controls
85 #if defined(_MSC_VER) && _MSC_VER >= 1300
86 # define PUGI__NO_INLINE __declspec(noinline)
87 #elif defined(__GNUC__)
88 # define PUGI__NO_INLINE __attribute__((noinline))
89 #else
90 # define PUGI__NO_INLINE
91 #endif
92 
93 // Branch weight controls
94 #if defined(__GNUC__) && !defined(__c2__)
95 # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0)
96 #else
97 # define PUGI__UNLIKELY(cond) (cond)
98 #endif
99 
100 // Simple static assertion
101 #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
102 
103 // Digital Mars C++ bug workaround for passing char loaded from memory via stack
104 #ifdef __DMC__
105 # define PUGI__DMC_VOLATILE volatile
106 #else
107 # define PUGI__DMC_VOLATILE
108 #endif
109 
110 // 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
111 #if defined(__clang__) && defined(__has_attribute)
112 # if __has_attribute(no_sanitize)
113 # define PUGI__UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow")))
114 # else
115 # define PUGI__UNSIGNED_OVERFLOW
116 # endif
117 #else
118 # define PUGI__UNSIGNED_OVERFLOW
119 #endif
120 
121 // 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)
122 #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
123 using std::memcpy;
124 using std::memmove;
125 using std::memset;
126 #endif
127 
128 // Some MinGW/GCC versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions from limits.h in some configurations
129 #if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX)
130 # define LLONG_MIN (-LLONG_MAX - 1LL)
131 # define LLONG_MAX __LONG_LONG_MAX__
132 # define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
133 #endif
134 
135 // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features
136 #if defined(_MSC_VER) && !defined(__S3E__) && !defined(_WIN32_WCE)
137 # define PUGI__MSVC_CRT_VERSION _MSC_VER
138 #elif defined(_WIN32_WCE)
139 # define PUGI__MSVC_CRT_VERSION 1310 // MSVC7.1
140 #endif
141 
142 // Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size.
143 #if __cplusplus >= 201103
144 # define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
145 #elif defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
146 # define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__)
147 #else
148 # define PUGI__SNPRINTF sprintf
149 #endif
150 
151 // 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.
152 #ifdef PUGIXML_HEADER_ONLY
153 # define PUGI__NS_BEGIN OIIO_NAMESPACE_BEGIN namespace pugi { namespace impl {
154 # define PUGI__NS_END } } OIIO_NAMESPACE_END
155 # define PUGI__FN inline
156 # define PUGI__FN_NO_INLINE inline
157 #else
158 # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
159 # define PUGI__NS_BEGIN OIIO_NAMESPACE_BEGIN namespace pugi { namespace impl {
160 # define PUGI__NS_END } } OIIO_NAMESPACE_END
161 # else
162 # define PUGI__NS_BEGIN OIIO_NAMESPACE_BEGIN namespace pugi { namespace impl { namespace {
163 # define PUGI__NS_END } } } OIIO_NAMESPACE_END
164 # endif
165 # define PUGI__FN
166 # define PUGI__FN_NO_INLINE PUGI__NO_INLINE
167 #endif
168 
169 // uintptr_t
170 #if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561)
171 OIIO_NAMESPACE_BEGIN namespace pugi
172 {
173 # ifndef _UINTPTR_T_DEFINED
174  typedef size_t uintptr_t;
175 # endif
176 
177  typedef unsigned __int8 uint8_t;
178  typedef unsigned __int16 uint16_t;
179  typedef unsigned __int32 uint32_t;
181 #else
182 # include <stdint.h>
183 #endif
184 
185 // Memory allocation
188  {
189  return malloc(size);
190  }
191 
193  {
194  free(ptr);
195  }
196 
197  template <typename T>
199  {
202  };
203 
204  // Global allocation functions are stored in class statics so that in header mode linker deduplicates them
205  // Without a template<> we'll get multiple definitions of the same static
208 
211 
212 // String utilities
214  // Get string length
215  PUGI__FN size_t strlength(const char_t* s)
216  {
217  assert(s);
218 
219  #ifdef PUGIXML_WCHAR_MODE
220  return wcslen(s);
221  #else
222  return strlen(s);
223  #endif
224  }
225 
226  // Compare two strings
227  PUGI__FN bool strequal(const char_t* src, const char_t* dst)
228  {
229  assert(src && dst);
230 
231  #ifdef PUGIXML_WCHAR_MODE
232  return wcscmp(src, dst) == 0;
233  #else
234  return strcmp(src, dst) == 0;
235  #endif
236  }
237 
238  // Compare lhs with [rhs_begin, rhs_end)
239  PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
240  {
241  for (size_t i = 0; i < count; ++i)
242  if (lhs[i] != rhs[i])
243  return false;
244 
245  return lhs[count] == 0;
246  }
247 
248  // Get length of wide string, even if CRT lacks wide character support
249  PUGI__FN size_t strlength_wide(const wchar_t* s)
250  {
251  assert(s);
252 
253  #ifdef PUGIXML_WCHAR_MODE
254  return wcslen(s);
255  #else
256  const wchar_t* end = s;
257  while (*end) end++;
258  return static_cast<size_t>(end - s);
259  #endif
260  }
262 
263 // auto_ptr-like object for exception recovery
265  template <typename T> struct auto_deleter
266  {
267  typedef void (*D)(T*);
268 
269  T* data;
271 
272  auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_)
273  {
274  }
275 
277  {
278  if (data) deleter(data);
279  }
280 
282  {
283  T* result = data;
284  data = 0;
285  return result;
286  }
287  };
289 
290 #ifdef PUGIXML_COMPACT
292  class compact_hash_table
293  {
294  public:
295  compact_hash_table(): _items(0), _capacity(0), _count(0)
296  {
297  }
298 
299  void clear()
300  {
301  if (_items)
302  {
303  xml_memory::deallocate(_items);
304  _items = 0;
305  _capacity = 0;
306  _count = 0;
307  }
308  }
309 
310  void* find(const void* key)
311  {
312  if (_capacity == 0) return 0;
313 
314  item_t* item = get_item(key);
315  assert(item);
316  assert(item->key == key || (item->key == 0 && item->value == 0));
317 
318  return item->value;
319  }
320 
321  void insert(const void* key, void* value)
322  {
323  assert(_capacity != 0 && _count < _capacity - _capacity / 4);
324 
325  item_t* item = get_item(key);
326  assert(item);
327 
328  if (item->key == 0)
329  {
330  _count++;
331  item->key = key;
332  }
333 
334  item->value = value;
335  }
336 
337  bool reserve(size_t extra = 16)
338  {
339  if (_count + extra >= _capacity - _capacity / 4)
340  return rehash(_count + extra);
341 
342  return true;
343  }
344 
345  private:
346  struct item_t
347  {
348  const void* key;
349  void* value;
350  };
351 
352  item_t* _items;
353  size_t _capacity;
354 
355  size_t _count;
356 
357  bool rehash(size_t count);
358 
359  item_t* get_item(const void* key)
360  {
361  assert(key);
362  assert(_capacity > 0);
363 
364  size_t hashmod = _capacity - 1;
365  size_t bucket = hash(key) & hashmod;
366 
367  for (size_t probe = 0; probe <= hashmod; ++probe)
368  {
369  item_t& probe_item = _items[bucket];
370 
371  if (probe_item.key == key || probe_item.key == 0)
372  return &probe_item;
373 
374  // hash collision, quadratic probing
375  bucket = (bucket + probe + 1) & hashmod;
376  }
377 
378  assert(false && "Hash table is full"); // unreachable
379  return 0;
380  }
381 
382  static PUGI__UNSIGNED_OVERFLOW unsigned int hash(const void* key)
383  {
384  unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key) & 0xffffffff);
385 
386  // MurmurHash3 32-bit finalizer
387  h ^= h >> 16;
388  h *= 0x85ebca6bu;
389  h ^= h >> 13;
390  h *= 0xc2b2ae35u;
391  h ^= h >> 16;
392 
393  return h;
394  }
395  };
396 
397  PUGI__FN_NO_INLINE bool compact_hash_table::rehash(size_t count)
398  {
399  size_t capacity = 32;
400  while (count >= capacity - capacity / 4)
401  capacity *= 2;
402 
403  compact_hash_table rt;
404  rt._capacity = capacity;
405  rt._items = static_cast<item_t*>(xml_memory::allocate(sizeof(item_t) * capacity));
406 
407  if (!rt._items)
408  return false;
409 
410  memset(rt._items, 0, sizeof(item_t) * capacity);
411 
412  for (size_t i = 0; i < _capacity; ++i)
413  if (_items[i].key)
414  rt.insert(_items[i].key, _items[i].value);
415 
416  if (_items)
417  xml_memory::deallocate(_items);
418 
419  _capacity = capacity;
420  _items = rt._items;
421 
422  assert(_count == rt._count);
423 
424  return true;
425  }
426 
428 #endif
429 
431 #ifdef PUGIXML_COMPACT
432  static const uintptr_t xml_memory_block_alignment = 4;
433 #else
434  static const uintptr_t xml_memory_block_alignment = sizeof(void*);
435 #endif
436 
437  // extra metadata bits
438  static const uintptr_t xml_memory_page_contents_shared_mask = 64;
439  static const uintptr_t xml_memory_page_name_allocated_mask = 32;
440  static const uintptr_t xml_memory_page_value_allocated_mask = 16;
441  static const uintptr_t xml_memory_page_type_mask = 15;
442 
443  // combined masks for string uniqueness
444  static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask;
445  static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask;
446 
447 #ifdef PUGIXML_COMPACT
448  #define PUGI__GETHEADER_IMPL(object, page, flags) // unused
449  #define PUGI__GETPAGE_IMPL(header) (header).get_page()
450 #else
451  #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))
452  // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
453  #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))))
454 #endif
455 
456  #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header)
457  #define PUGI__NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
458 
459  struct xml_allocator;
460 
462  {
464  {
465  xml_memory_page* result = static_cast<xml_memory_page*>(memory);
466 
467  result->allocator = 0;
468  result->prev = 0;
469  result->next = 0;
470  result->busy_size = 0;
471  result->freed_size = 0;
472 
473  #ifdef PUGIXML_COMPACT
474  result->compact_string_base = 0;
475  result->compact_shared_parent = 0;
476  result->compact_page_marker = 0;
477  #endif
478 
479  return result;
480  }
481 
483 
486 
487  size_t busy_size;
488  size_t freed_size;
489 
490  #ifdef PUGIXML_COMPACT
491  char_t* compact_string_base;
492  void* compact_shared_parent;
493  uint32_t* compact_page_marker;
494  #endif
495  };
496 
497  static const size_t xml_memory_page_size =
498  #ifdef PUGIXML_MEMORY_PAGE_SIZE
499  (PUGIXML_MEMORY_PAGE_SIZE)
500  #else
501  32768
502  #endif
503  - sizeof(xml_memory_page);
504 
506  {
507  uint16_t page_offset; // offset from page->data
508  uint16_t full_size; // 0 if string occupies whole page
509  };
510 
512  {
513  xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
514  {
515  #ifdef PUGIXML_COMPACT
516  _hash = 0;
517  #endif
518  }
519 
520  xml_memory_page* allocate_page(size_t data_size)
521  {
522  size_t size = sizeof(xml_memory_page) + data_size;
523 
524  // allocate block with some alignment, leaving memory for worst-case padding
525  void* memory = xml_memory::allocate(size);
526  if (!memory) return 0;
527 
528  // prepare page structure
530  assert(page);
531 
532  assert(this == _root->allocator);
533  page->allocator = this;
534 
535  return page;
536  }
537 
538  static void deallocate_page(xml_memory_page* page)
539  {
541  }
542 
543  void* allocate_memory_oob(size_t size, xml_memory_page*& out_page);
544 
545  void* allocate_memory(size_t size, xml_memory_page*& out_page)
546  {
547  if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size))
548  return allocate_memory_oob(size, out_page);
549 
550  void* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size;
551 
552  _busy_size += size;
553 
554  out_page = _root;
555 
556  return buf;
557  }
558 
559  #ifdef PUGIXML_COMPACT
560  void* allocate_object(size_t size, xml_memory_page*& out_page)
561  {
562  void* result = allocate_memory(size + sizeof(uint32_t), out_page);
563  if (!result) return 0;
564 
565  // adjust for marker
566  ptrdiff_t offset = static_cast<char*>(result) - reinterpret_cast<char*>(out_page->compact_page_marker);
567 
568  if (PUGI__UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment))
569  {
570  // insert new marker
571  uint32_t* marker = static_cast<uint32_t*>(result);
572 
573  *marker = static_cast<uint32_t>(reinterpret_cast<char*>(marker) - reinterpret_cast<char*>(out_page));
574  out_page->compact_page_marker = marker;
575 
576  // since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block
577  // this will make sure deallocate_memory correctly tracks the size
578  out_page->freed_size += sizeof(uint32_t);
579 
580  return marker + 1;
581  }
582  else
583  {
584  // roll back uint32_t part
585  _busy_size -= sizeof(uint32_t);
586 
587  return result;
588  }
589  }
590  #else
591  void* allocate_object(size_t size, xml_memory_page*& out_page)
592  {
593  return allocate_memory(size, out_page);
594  }
595  #endif
596 
597  void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
598  {
599  if (page == _root) page->busy_size = _busy_size;
600 
601  assert(ptr >= reinterpret_cast<char*>(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast<char*>(page) + sizeof(xml_memory_page) + page->busy_size);
602  (void)!ptr;
603 
604  page->freed_size += size;
605  assert(page->freed_size <= page->busy_size);
606 
607  if (page->freed_size == page->busy_size)
608  {
609  if (page->next == 0)
610  {
611  assert(_root == page);
612 
613  // top page freed, just reset sizes
614  page->busy_size = 0;
615  page->freed_size = 0;
616 
617  #ifdef PUGIXML_COMPACT
618  // reset compact state to maximize efficiency
619  page->compact_string_base = 0;
620  page->compact_shared_parent = 0;
621  page->compact_page_marker = 0;
622  #endif
623 
624  _busy_size = 0;
625  }
626  else
627  {
628  assert(_root != page);
629  assert(page->prev);
630 
631  // remove from the list
632  page->prev->next = page->next;
633  page->next->prev = page->prev;
634 
635  // deallocate
636  deallocate_page(page);
637  }
638  }
639  }
640 
642  {
643  static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment;
644 
645  PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
646 
647  // allocate memory for string and header block
648  size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
649 
650  // round size up to block alignment boundary
651  size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1);
652 
653  xml_memory_page* page;
654  xml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page));
655 
656  if (!header) return 0;
657 
658  // setup header
659  ptrdiff_t page_offset = reinterpret_cast<char*>(header) - reinterpret_cast<char*>(page) - sizeof(xml_memory_page);
660 
661  assert(page_offset % xml_memory_block_alignment == 0);
662  assert(page_offset >= 0 && static_cast<size_t>(page_offset) < max_encoded_offset);
663  header->page_offset = static_cast<uint16_t>(static_cast<size_t>(page_offset) / xml_memory_block_alignment);
664 
665  // full_size == 0 for large strings that occupy the whole page
666  assert(full_size % xml_memory_block_alignment == 0);
667  assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0));
668  header->full_size = static_cast<uint16_t>(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0);
669 
670  // round-trip through void* to avoid 'cast increases required alignment of target type' warning
671  // header is guaranteed a pointer-sized alignment, which should be enough for char_t
672  return static_cast<char_t*>(static_cast<void*>(header + 1));
673  }
674 
675  void deallocate_string(char_t* string)
676  {
677  // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
678  // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string
679 
680  // get header
681  xml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1;
682  assert(header);
683 
684  // deallocate
685  size_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment;
686  xml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset));
687 
688  // if full_size == 0 then this string occupies the whole page
689  size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment;
690 
691  deallocate_memory(header, full_size, page);
692  }
693 
694  bool reserve()
695  {
696  #ifdef PUGIXML_COMPACT
697  return _hash->reserve();
698  #else
699  return true;
700  #endif
701  }
702 
704  size_t _busy_size;
705 
706  #ifdef PUGIXML_COMPACT
707  compact_hash_table* _hash;
708  #endif
709  };
710 
712  {
713  const size_t large_allocation_threshold = xml_memory_page_size / 4;
714 
715  xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
716  out_page = page;
717 
718  if (!page) return 0;
719 
720  if (size <= large_allocation_threshold)
721  {
723 
724  // insert page at the end of linked list
725  page->prev = _root;
726  _root->next = page;
727  _root = page;
728 
729  _busy_size = size;
730  }
731  else
732  {
733  // insert page before the end of linked list, so that it is deleted as soon as possible
734  // the last page is not deleted even if it's empty (see deallocate_memory)
735  assert(_root->prev);
736 
737  page->prev = _root->prev;
738  page->next = _root;
739 
740  _root->prev->next = page;
741  _root->prev = page;
742 
743  page->busy_size = size;
744  }
745 
746  return reinterpret_cast<char*>(page) + sizeof(xml_memory_page);
747  }
749 
750 #ifdef PUGIXML_COMPACT
752  static const uintptr_t compact_alignment_log2 = 2;
753  static const uintptr_t compact_alignment = 1 << compact_alignment_log2;
754 
755  class compact_header
756  {
757  public:
758  compact_header(xml_memory_page* page, unsigned int flags)
759  {
760  PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
761 
762  ptrdiff_t offset = (reinterpret_cast<char*>(this) - reinterpret_cast<char*>(page->compact_page_marker));
763  assert(offset % compact_alignment == 0 && static_cast<uintptr_t>(offset) < 256 * compact_alignment);
764 
765  _page = static_cast<unsigned char>(offset >> compact_alignment_log2);
766  _flags = static_cast<unsigned char>(flags);
767  }
768 
769  void operator&=(uintptr_t mod)
770  {
771  _flags &= static_cast<unsigned char>(mod);
772  }
773 
774  void operator|=(uintptr_t mod)
775  {
776  _flags |= static_cast<unsigned char>(mod);
777  }
778 
780  {
781  return _flags & mod;
782  }
783 
784  xml_memory_page* get_page() const
785  {
786  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
787  const char* page_marker = reinterpret_cast<const char*>(this) - (_page << compact_alignment_log2);
788  const char* page = page_marker - *reinterpret_cast<const uint32_t*>(static_cast<const void*>(page_marker));
789 
790  return const_cast<xml_memory_page*>(reinterpret_cast<const xml_memory_page*>(static_cast<const void*>(page)));
791  }
792 
793  private:
794  unsigned char _page;
795  unsigned char _flags;
796  };
797 
798  PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset)
799  {
800  const compact_header* header = reinterpret_cast<const compact_header*>(static_cast<const char*>(object) - header_offset);
801 
802  return header->get_page();
803  }
804 
805  template <int header_offset, typename T> PUGI__FN_NO_INLINE T* compact_get_value(const void* object)
806  {
807  return static_cast<T*>(compact_get_page(object, header_offset)->allocator->_hash->find(object));
808  }
809 
810  template <int header_offset, typename T> PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value)
811  {
812  compact_get_page(object, header_offset)->allocator->_hash->insert(object, value);
813  }
814 
815  template <typename T, int header_offset, int start = -126> class compact_pointer
816  {
817  public:
818  compact_pointer(): _data(0)
819  {
820  }
821 
822  void operator=(const compact_pointer& rhs)
823  {
824  *this = rhs + 0;
825  }
826 
827  void operator=(T* value)
828  {
829  if (value)
830  {
831  // value is guaranteed to be compact-aligned; 'this' is not
832  // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
833  // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
834  // compensate for arithmetic shift rounding for negative values
835  ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
836  ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start;
837 
838  if (static_cast<uintptr_t>(offset) <= 253)
839  _data = static_cast<unsigned char>(offset + 1);
840  else
841  {
842  compact_set_value<header_offset>(this, value);
843 
844  _data = 255;
845  }
846  }
847  else
848  _data = 0;
849  }
850 
851  operator T*() const
852  {
853  if (_data)
854  {
855  if (_data < 255)
856  {
857  uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
858 
859  return reinterpret_cast<T*>(base + (_data - 1 + start) * compact_alignment);
860  }
861  else
862  return compact_get_value<header_offset, T>(this);
863  }
864  else
865  return 0;
866  }
867 
868  T* operator->() const
869  {
870  return *this;
871  }
872 
873  private:
874  unsigned char _data;
875  };
876 
877  template <typename T, int header_offset> class compact_pointer_parent
878  {
879  public:
880  compact_pointer_parent(): _data(0)
881  {
882  }
883 
884  void operator=(const compact_pointer_parent& rhs)
885  {
886  *this = rhs + 0;
887  }
888 
889  void operator=(T* value)
890  {
891  if (value)
892  {
893  // value is guaranteed to be compact-aligned; 'this' is not
894  // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
895  // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
896  // compensate for arithmetic shift behavior for negative values
897  ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
898  ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533;
899 
900  if (static_cast<uintptr_t>(offset) <= 65533)
901  {
902  _data = static_cast<unsigned short>(offset + 1);
903  }
904  else
905  {
906  xml_memory_page* page = compact_get_page(this, header_offset);
907 
908  if (PUGI__UNLIKELY(page->compact_shared_parent == 0))
909  page->compact_shared_parent = value;
910 
911  if (page->compact_shared_parent == value)
912  {
913  _data = 65534;
914  }
915  else
916  {
917  compact_set_value<header_offset>(this, value);
918 
919  _data = 65535;
920  }
921  }
922  }
923  else
924  {
925  _data = 0;
926  }
927  }
928 
929  operator T*() const
930  {
931  if (_data)
932  {
933  if (_data < 65534)
934  {
935  uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
936 
937  return reinterpret_cast<T*>(base + (_data - 1 - 65533) * compact_alignment);
938  }
939  else if (_data == 65534)
940  return static_cast<T*>(compact_get_page(this, header_offset)->compact_shared_parent);
941  else
942  return compact_get_value<header_offset, T>(this);
943  }
944  else
945  return 0;
946  }
947 
948  T* operator->() const
949  {
950  return *this;
951  }
952 
953  private:
954  uint16_t _data;
955  };
956 
957  template <int header_offset, int base_offset> class compact_string
958  {
959  public:
960  compact_string(): _data(0)
961  {
962  }
963 
964  void operator=(const compact_string& rhs)
965  {
966  *this = rhs + 0;
967  }
968 
969  void operator=(char_t* value)
970  {
971  if (value)
972  {
973  xml_memory_page* page = compact_get_page(this, header_offset);
974 
975  if (PUGI__UNLIKELY(page->compact_string_base == 0))
976  page->compact_string_base = value;
977 
978  ptrdiff_t offset = value - page->compact_string_base;
979 
980  if (static_cast<uintptr_t>(offset) < (65535 << 7))
981  {
982  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
983  uint16_t* base = reinterpret_cast<uint16_t*>(static_cast<void*>(reinterpret_cast<char*>(this) - base_offset));
984 
985  if (*base == 0)
986  {
987  *base = static_cast<uint16_t>((offset >> 7) + 1);
988  _data = static_cast<unsigned char>((offset & 127) + 1);
989  }
990  else
991  {
992  ptrdiff_t remainder = offset - ((*base - 1) << 7);
993 
994  if (static_cast<uintptr_t>(remainder) <= 253)
995  {
996  _data = static_cast<unsigned char>(remainder + 1);
997  }
998  else
999  {
1000  compact_set_value<header_offset>(this, value);
1001 
1002  _data = 255;
1003  }
1004  }
1005  }
1006  else
1007  {
1008  compact_set_value<header_offset>(this, value);
1009 
1010  _data = 255;
1011  }
1012  }
1013  else
1014  {
1015  _data = 0;
1016  }
1017  }
1018 
1019  operator char_t*() const
1020  {
1021  if (_data)
1022  {
1023  if (_data < 255)
1024  {
1025  xml_memory_page* page = compact_get_page(this, header_offset);
1026 
1027  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
1028  const uint16_t* base = reinterpret_cast<const uint16_t*>(static_cast<const void*>(reinterpret_cast<const char*>(this) - base_offset));
1029  assert(*base);
1030 
1031  ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);
1032 
1033  return page->compact_string_base + offset;
1034  }
1035  else
1036  {
1037  return compact_get_value<header_offset, char_t>(this);
1038  }
1039  }
1040  else
1041  return 0;
1042  }
1043 
1044  private:
1045  unsigned char _data;
1046  };
1048 #endif
1049 
1050 #ifdef PUGIXML_COMPACT
1051 OIIO_NAMESPACE_BEGIN namespace pugi
1052 {
1053  struct xml_attribute_struct
1054  {
1055  xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)
1056  {
1057  PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8);
1058  }
1059 
1060  impl::compact_header header;
1061 
1062  uint16_t namevalue_base;
1063 
1064  impl::compact_string<4, 2> name;
1065  impl::compact_string<5, 3> value;
1066 
1067  impl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c;
1068  impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute;
1069  };
1070 
1071  struct xml_node_struct
1072  {
1073  xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0)
1074  {
1075  PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12);
1076  }
1077 
1078  impl::compact_header header;
1079 
1080  uint16_t namevalue_base;
1081 
1082  impl::compact_string<4, 2> name;
1083  impl::compact_string<5, 3> value;
1084 
1085  impl::compact_pointer_parent<xml_node_struct, 6> parent;
1086 
1087  impl::compact_pointer<xml_node_struct, 8, 0> first_child;
1088 
1089  impl::compact_pointer<xml_node_struct, 9> prev_sibling_c;
1090  impl::compact_pointer<xml_node_struct, 10, 0> next_sibling;
1091 
1092  impl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute;
1093  };
1095 #else
1096 OIIO_NAMESPACE_BEGIN namespace pugi
1097 {
1099  {
1100  xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0)
1101  {
1102  header = PUGI__GETHEADER_IMPL(this, page, 0);
1103  }
1104 
1106 
1109 
1112  };
1113 
1115  {
1116  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)
1117  {
1118  header = PUGI__GETHEADER_IMPL(this, page, type);
1119  }
1120 
1122 
1125 
1127 
1129 
1132 
1134  };
1136 #endif
1137 
1140  {
1143  };
1144 
1145  struct xml_document_struct: public xml_node_struct, public xml_allocator
1146  {
1148  {
1149  }
1150 
1151  const char_t* buffer;
1152 
1154 
1155  #ifdef PUGIXML_COMPACT
1156  compact_hash_table hash;
1157  #endif
1158  };
1159 
1160  template <typename Object> inline xml_allocator& get_allocator(const Object* object)
1161  {
1162  assert(object);
1163 
1164  return *PUGI__GETPAGE(object)->allocator;
1165  }
1166 
1167  template <typename Object> inline xml_document_struct& get_document(const Object* object)
1168  {
1169  assert(object);
1170 
1171  return *static_cast<xml_document_struct*>(PUGI__GETPAGE(object)->allocator);
1172  }
1174 
1175 // Low-level DOM operations
1177  inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
1178  {
1179  xml_memory_page* page;
1180  void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page);
1181  if (!memory) return 0;
1182 
1183  return new (memory) xml_attribute_struct(page);
1184  }
1185 
1186  inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type)
1187  {
1188  xml_memory_page* page;
1189  void* memory = alloc.allocate_object(sizeof(xml_node_struct), page);
1190  if (!memory) return 0;
1191 
1192  return new (memory) xml_node_struct(page, type);
1193  }
1194 
1195  inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
1196  {
1197  if (a->header & impl::xml_memory_page_name_allocated_mask)
1198  alloc.deallocate_string(a->name);
1199 
1200  if (a->header & impl::xml_memory_page_value_allocated_mask)
1201  alloc.deallocate_string(a->value);
1202 
1203  alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a));
1204  }
1205 
1206  inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
1207  {
1208  if (n->header & impl::xml_memory_page_name_allocated_mask)
1209  alloc.deallocate_string(n->name);
1210 
1211  if (n->header & impl::xml_memory_page_value_allocated_mask)
1212  alloc.deallocate_string(n->value);
1213 
1214  for (xml_attribute_struct* attr = n->first_attribute; attr; )
1215  {
1216  xml_attribute_struct* next = attr->next_attribute;
1217 
1218  destroy_attribute(attr, alloc);
1219 
1220  attr = next;
1221  }
1222 
1223  for (xml_node_struct* child = n->first_child; child; )
1224  {
1225  xml_node_struct* next = child->next_sibling;
1226 
1227  destroy_node(child, alloc);
1228 
1229  child = next;
1230  }
1231 
1232  alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n));
1233  }
1234 
1235  inline void append_node(xml_node_struct* child, xml_node_struct* node)
1236  {
1237  child->parent = node;
1238 
1239  xml_node_struct* head = node->first_child;
1240 
1241  if (head)
1242  {
1243  xml_node_struct* tail = head->prev_sibling_c;
1244 
1245  tail->next_sibling = child;
1246  child->prev_sibling_c = tail;
1247  head->prev_sibling_c = child;
1248  }
1249  else
1250  {
1251  node->first_child = child;
1252  child->prev_sibling_c = child;
1253  }
1254  }
1255 
1256  inline void prepend_node(xml_node_struct* child, xml_node_struct* node)
1257  {
1258  child->parent = node;
1259 
1260  xml_node_struct* head = node->first_child;
1261 
1262  if (head)
1263  {
1264  child->prev_sibling_c = head->prev_sibling_c;
1265  head->prev_sibling_c = child;
1266  }
1267  else
1268  child->prev_sibling_c = child;
1269 
1270  child->next_sibling = head;
1271  node->first_child = child;
1272  }
1273 
1274  inline void insert_node_after(xml_node_struct* child, xml_node_struct* node)
1275  {
1276  xml_node_struct* parent = node->parent;
1277 
1278  child->parent = parent;
1279 
1280  if (node->next_sibling)
1281  node->next_sibling->prev_sibling_c = child;
1282  else
1283  parent->first_child->prev_sibling_c = child;
1284 
1285  child->next_sibling = node->next_sibling;
1286  child->prev_sibling_c = node;
1287 
1288  node->next_sibling = child;
1289  }
1290 
1291  inline void insert_node_before(xml_node_struct* child, xml_node_struct* node)
1292  {
1293  xml_node_struct* parent = node->parent;
1294 
1295  child->parent = parent;
1296 
1297  if (node->prev_sibling_c->next_sibling)
1298  node->prev_sibling_c->next_sibling = child;
1299  else
1300  parent->first_child = child;
1301 
1302  child->prev_sibling_c = node->prev_sibling_c;
1303  child->next_sibling = node;
1304 
1305  node->prev_sibling_c = child;
1306  }
1307 
1308  inline void remove_node(xml_node_struct* node)
1309  {
1310  xml_node_struct* parent = node->parent;
1311 
1312  if (node->next_sibling)
1313  node->next_sibling->prev_sibling_c = node->prev_sibling_c;
1314  else
1315  parent->first_child->prev_sibling_c = node->prev_sibling_c;
1316 
1317  if (node->prev_sibling_c->next_sibling)
1318  node->prev_sibling_c->next_sibling = node->next_sibling;
1319  else
1320  parent->first_child = node->next_sibling;
1321 
1322  node->parent = 0;
1323  node->prev_sibling_c = 0;
1324  node->next_sibling = 0;
1325  }
1326 
1327  inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1328  {
1329  xml_attribute_struct* head = node->first_attribute;
1330 
1331  if (head)
1332  {
1333  xml_attribute_struct* tail = head->prev_attribute_c;
1334 
1335  tail->next_attribute = attr;
1336  attr->prev_attribute_c = tail;
1337  head->prev_attribute_c = attr;
1338  }
1339  else
1340  {
1341  node->first_attribute = attr;
1342  attr->prev_attribute_c = attr;
1343  }
1344  }
1345 
1346  inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1347  {
1348  xml_attribute_struct* head = node->first_attribute;
1349 
1350  if (head)
1351  {
1352  attr->prev_attribute_c = head->prev_attribute_c;
1353  head->prev_attribute_c = attr;
1354  }
1355  else
1356  attr->prev_attribute_c = attr;
1357 
1358  attr->next_attribute = head;
1359  node->first_attribute = attr;
1360  }
1361 
1362  inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
1363  {
1364  if (place->next_attribute)
1365  place->next_attribute->prev_attribute_c = attr;
1366  else
1367  node->first_attribute->prev_attribute_c = attr;
1368 
1369  attr->next_attribute = place->next_attribute;
1370  attr->prev_attribute_c = place;
1371  place->next_attribute = attr;
1372  }
1373 
1374  inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
1375  {
1376  if (place->prev_attribute_c->next_attribute)
1377  place->prev_attribute_c->next_attribute = attr;
1378  else
1379  node->first_attribute = attr;
1380 
1381  attr->prev_attribute_c = place->prev_attribute_c;
1382  attr->next_attribute = place;
1383  place->prev_attribute_c = attr;
1384  }
1385 
1386  inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1387  {
1388  if (attr->next_attribute)
1389  attr->next_attribute->prev_attribute_c = attr->prev_attribute_c;
1390  else
1391  node->first_attribute->prev_attribute_c = attr->prev_attribute_c;
1392 
1393  if (attr->prev_attribute_c->next_attribute)
1394  attr->prev_attribute_c->next_attribute = attr->next_attribute;
1395  else
1396  node->first_attribute = attr->next_attribute;
1397 
1398  attr->prev_attribute_c = 0;
1399  attr->next_attribute = 0;
1400  }
1401 
1402  PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
1403  {
1404  if (!alloc.reserve()) return 0;
1405 
1406  xml_node_struct* child = allocate_node(alloc, type);
1407  if (!child) return 0;
1408 
1409  append_node(child, node);
1410 
1411  return child;
1412  }
1413 
1414  PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)
1415  {
1416  if (!alloc.reserve()) return 0;
1417 
1418  xml_attribute_struct* attr = allocate_attribute(alloc);
1419  if (!attr) return 0;
1420 
1421  append_attribute(attr, node);
1422 
1423  return attr;
1424  }
1426 
1427 // Helper classes for code generation
1429  struct opt_false
1430  {
1431  enum { value = 0 };
1432  };
1433 
1434  struct opt_true
1435  {
1436  enum { value = 1 };
1437  };
1439 
1440 // Unicode utilities
1442  inline uint16_t endian_swap(uint16_t value)
1443  {
1444  return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
1445  }
1446 
1447  inline uint32_t endian_swap(uint32_t value)
1448  {
1449  return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
1450  }
1451 
1453  {
1454  typedef size_t value_type;
1455 
1456  static value_type low(value_type result, uint32_t ch)
1457  {
1458  // U+0000..U+007F
1459  if (ch < 0x80) return result + 1;
1460  // U+0080..U+07FF
1461  else if (ch < 0x800) return result + 2;
1462  // U+0800..U+FFFF
1463  else return result + 3;
1464  }
1465 
1466  static value_type high(value_type result, uint32_t)
1467  {
1468  // U+10000..U+10FFFF
1469  return result + 4;
1470  }
1471  };
1472 
1474  {
1475  typedef uint8_t* value_type;
1476 
1477  static value_type low(value_type result, uint32_t ch)
1478  {
1479  // U+0000..U+007F
1480  if (ch < 0x80)
1481  {
1482  *result = static_cast<uint8_t>(ch);
1483  return result + 1;
1484  }
1485  // U+0080..U+07FF
1486  else if (ch < 0x800)
1487  {
1488  result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));
1489  result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
1490  return result + 2;
1491  }
1492  // U+0800..U+FFFF
1493  else
1494  {
1495  result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));
1496  result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
1497  result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
1498  return result + 3;
1499  }
1500  }
1501 
1502  static value_type high(value_type result, uint32_t ch)
1503  {
1504  // U+10000..U+10FFFF
1505  result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));
1506  result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));
1507  result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
1508  result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
1509  return result + 4;
1510  }
1511 
1512  static value_type any(value_type result, uint32_t ch)
1513  {
1514  return (ch < 0x10000) ? low(result, ch) : high(result, ch);
1515  }
1516  };
1517 
1519  {
1520  typedef size_t value_type;
1521 
1522  static value_type low(value_type result, uint32_t)
1523  {
1524  return result + 1;
1525  }
1526 
1527  static value_type high(value_type result, uint32_t)
1528  {
1529  return result + 2;
1530  }
1531  };
1532 
1534  {
1535  typedef uint16_t* value_type;
1536 
1537  static value_type low(value_type result, uint32_t ch)
1538  {
1539  *result = static_cast<uint16_t>(ch);
1540 
1541  return result + 1;
1542  }
1543 
1544  static value_type high(value_type result, uint32_t ch)
1545  {
1546  uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10;
1547  uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff;
1548 
1549  result[0] = static_cast<uint16_t>(0xD800 + msh);
1550  result[1] = static_cast<uint16_t>(0xDC00 + lsh);
1551 
1552  return result + 2;
1553  }
1554 
1555  static value_type any(value_type result, uint32_t ch)
1556  {
1557  return (ch < 0x10000) ? low(result, ch) : high(result, ch);
1558  }
1559  };
1560 
1562  {
1563  typedef size_t value_type;
1564 
1565  static value_type low(value_type result, uint32_t)
1566  {
1567  return result + 1;
1568  }
1569 
1570  static value_type high(value_type result, uint32_t)
1571  {
1572  return result + 1;
1573  }
1574  };
1575 
1577  {
1578  typedef uint32_t* value_type;
1579 
1580  static value_type low(value_type result, uint32_t ch)
1581  {
1582  *result = ch;
1583 
1584  return result + 1;
1585  }
1586 
1587  static value_type high(value_type result, uint32_t ch)
1588  {
1589  *result = ch;
1590 
1591  return result + 1;
1592  }
1593 
1594  static value_type any(value_type result, uint32_t ch)
1595  {
1596  *result = ch;
1597 
1598  return result + 1;
1599  }
1600  };
1601 
1603  {
1604  typedef uint8_t* value_type;
1605 
1606  static value_type low(value_type result, uint32_t ch)
1607  {
1608  *result = static_cast<uint8_t>(ch > 255 ? '?' : ch);
1609 
1610  return result + 1;
1611  }
1612 
1613  static value_type high(value_type result, uint32_t ch)
1614  {
1615  (void)ch;
1616 
1617  *result = '?';
1618 
1619  return result + 1;
1620  }
1621  };
1622 
1624  {
1625  typedef uint8_t type;
1626 
1627  template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
1628  {
1629  const uint8_t utf8_byte_mask = 0x3f;
1630 
1631  while (size)
1632  {
1633  uint8_t lead = *data;
1634 
1635  // 0xxxxxxx -> U+0000..U+007F
1636  if (lead < 0x80)
1637  {
1638  result = Traits::low(result, lead);
1639  data += 1;
1640  size -= 1;
1641 
1642  // process aligned single-byte (ascii) blocks
1643  if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
1644  {
1645  // round-trip through void* to silence 'cast increases required alignment of target type' warnings
1646  while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)
1647  {
1648  result = Traits::low(result, data[0]);
1649  result = Traits::low(result, data[1]);
1650  result = Traits::low(result, data[2]);
1651  result = Traits::low(result, data[3]);
1652  data += 4;
1653  size -= 4;
1654  }
1655  }
1656  }
1657  // 110xxxxx -> U+0080..U+07FF
1658  else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
1659  {
1660  result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
1661  data += 2;
1662  size -= 2;
1663  }
1664  // 1110xxxx -> U+0800-U+FFFF
1665  else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
1666  {
1667  result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
1668  data += 3;
1669  size -= 3;
1670  }
1671  // 11110xxx -> U+10000..U+10FFFF
1672  else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
1673  {
1674  result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
1675  data += 4;
1676  size -= 4;
1677  }
1678  // 10xxxxxx or 11111xxx -> invalid
1679  else
1680  {
1681  data += 1;
1682  size -= 1;
1683  }
1684  }
1685 
1686  return result;
1687  }
1688  };
1689 
1690  template <typename opt_swap> struct utf16_decoder
1691  {
1692  typedef uint16_t type;
1693 
1694  template <typename Traits> static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits)
1695  {
1696  while (size)
1697  {
1698  uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
1699 
1700  // U+0000..U+D7FF
1701  if (lead < 0xD800)
1702  {
1703  result = Traits::low(result, lead);
1704  data += 1;
1705  size -= 1;
1706  }
1707  // U+E000..U+FFFF
1708  else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
1709  {
1710  result = Traits::low(result, lead);
1711  data += 1;
1712  size -= 1;
1713  }
1714  // surrogate pair lead
1715  else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
1716  {
1717  uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
1718 
1719  if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
1720  {
1721  result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
1722  data += 2;
1723  size -= 2;
1724  }
1725  else
1726  {
1727  data += 1;
1728  size -= 1;
1729  }
1730  }
1731  else
1732  {
1733  data += 1;
1734  size -= 1;
1735  }
1736  }
1737 
1738  return result;
1739  }
1740  };
1741 
1742  template <typename opt_swap> struct utf32_decoder
1743  {
1744  typedef uint32_t type;
1745 
1746  template <typename Traits> static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits)
1747  {
1748  while (size)
1749  {
1750  uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
1751 
1752  // U+0000..U+FFFF
1753  if (lead < 0x10000)
1754  {
1755  result = Traits::low(result, lead);
1756  data += 1;
1757  size -= 1;
1758  }
1759  // U+10000..U+10FFFF
1760  else
1761  {
1762  result = Traits::high(result, lead);
1763  data += 1;
1764  size -= 1;
1765  }
1766  }
1767 
1768  return result;
1769  }
1770  };
1771 
1773  {
1774  typedef uint8_t type;
1775 
1776  template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
1777  {
1778  while (size)
1779  {
1780  result = Traits::low(result, *data);
1781  data += 1;
1782  size -= 1;
1783  }
1784 
1785  return result;
1786  }
1787  };
1788 
1789  template <size_t size> struct wchar_selector;
1790 
1791  template <> struct wchar_selector<2>
1792  {
1793  typedef uint16_t type;
1797  };
1798 
1799  template <> struct wchar_selector<4>
1800  {
1801  typedef uint32_t type;
1805  };
1806 
1809 
1811  {
1812  typedef wchar_t type;
1813 
1814  template <typename Traits> static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits)
1815  {
1817 
1818  return decoder::process(reinterpret_cast<const typename decoder::type*>(data), size, result, traits);
1819  }
1820  };
1821 
1822 #ifdef PUGIXML_WCHAR_MODE
1823  PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
1824  {
1825  for (size_t i = 0; i < length; ++i)
1826  result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
1827  }
1828 #endif
1830 
1833  {
1834  ct_parse_pcdata = 1, // \0, &, \r, <
1835  ct_parse_attr = 2, // \0, &, \r, ', "
1836  ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab
1837  ct_space = 8, // \r, \n, space, tab
1838  ct_parse_cdata = 16, // \0, ], >, \r
1839  ct_parse_comment = 32, // \0, -, >, \r
1840  ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .
1841  ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, :
1842  };
1843 
1844  static const unsigned char chartype_table[256] =
1845  {
1846  55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15
1847  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
1848  8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47
1849  64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63
1850  0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79
1851  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95
1852  0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111
1853  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127
1854 
1855  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+
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  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1860  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1861  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1862  192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
1863  };
1864 
1866  {
1867  ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
1868  ctx_special_attr = 2, // Any symbol >= 0 and < 32, &, <, ", '
1869  ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _
1870  ctx_digit = 8, // 0-9
1871  ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
1872  };
1873 
1874  static const unsigned char chartypex_table[256] =
1875  {
1876  3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, // 0-15
1877  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31
1878  0, 0, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47
1879  24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 1, 0, // 48-63
1880 
1881  0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79
1882  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95
1883  0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111
1884  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127
1885 
1886  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+
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  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1891  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1892  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1893  20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
1894  };
1895 
1896 #ifdef PUGIXML_WCHAR_MODE
1897  #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
1898 #else
1899  #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
1900 #endif
1901 
1902  #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
1903  #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
1904 
1906  {
1907  unsigned int ui = 1;
1908 
1909  return *reinterpret_cast<unsigned char*>(&ui) == 1;
1910  }
1911 
1913  {
1914  PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
1915 
1916  if (sizeof(wchar_t) == 2)
1918  else
1920  }
1921 
1922  PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length)
1923  {
1924  #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
1925  #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; }
1926 
1927  // check if we have a non-empty XML declaration
1928  if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space)))
1929  return false;
1930 
1931  // scan XML declaration until the encoding field
1932  for (size_t i = 6; i + 1 < size; ++i)
1933  {
1934  // declaration can not contain ? in quoted values
1935  if (data[i] == '?')
1936  return false;
1937 
1938  if (data[i] == 'e' && data[i + 1] == 'n')
1939  {
1940  size_t offset = i;
1941 
1942  // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed
1945 
1946  // S? = S?
1948  PUGI__SCANCHAR('=');
1950 
1951  // the only two valid delimiters are ' and "
1952  uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\'';
1953 
1954  PUGI__SCANCHAR(delimiter);
1955 
1956  size_t start = offset;
1957 
1958  out_encoding = data + offset;
1959 
1961 
1962  out_length = offset - start;
1963 
1964  PUGI__SCANCHAR(delimiter);
1965 
1966  return true;
1967  }
1968  }
1969 
1970  return false;
1971 
1972  #undef PUGI__SCANCHAR
1973  #undef PUGI__SCANCHARTYPE
1974  }
1975 
1976  PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size)
1977  {
1978  // skip encoding autodetection if input buffer is too small
1979  if (size < 4) return encoding_utf8;
1980 
1981  uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1982 
1983  // look for BOM in first few bytes
1984  if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be;
1985  if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le;
1986  if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be;
1987  if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le;
1988  if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8;
1989 
1990  // look for <, <? or <?xm in various encodings
1991  if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be;
1992  if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le;
1993  if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be;
1994  if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le;
1995 
1996  // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)
1997  if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be;
1998  if (d0 == 0x3c && d1 == 0) return encoding_utf16_le;
1999 
2000  // no known BOM detected; parse declaration
2001  const uint8_t* enc = 0;
2002  size_t enc_length = 0;
2003 
2004  if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length))
2005  {
2006  // iso-8859-1 (case-insensitive)
2007  if (enc_length == 10
2008  && (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o'
2009  && enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9'
2010  && enc[8] == '-' && enc[9] == '1')
2011  return encoding_latin1;
2012 
2013  // latin1 (case-insensitive)
2014  if (enc_length == 6
2015  && (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't'
2016  && (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n'
2017  && enc[5] == '1')
2018  return encoding_latin1;
2019  }
2020 
2021  return encoding_utf8;
2022  }
2023 
2024  PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
2025  {
2026  // replace wchar encoding with utf implementation
2027  if (encoding == encoding_wchar) return get_wchar_encoding();
2028 
2029  // replace utf16 encoding with utf16 with specific endianness
2031 
2032  // replace utf32 encoding with utf32 with specific endianness
2034 
2035  // only do autodetection if no explicit encoding is requested
2036  if (encoding != encoding_auto) return encoding;
2037 
2038  // try to guess encoding (based on XML specification, Appendix F.1)
2039  const uint8_t* data = static_cast<const uint8_t*>(contents);
2040 
2041  return guess_buffer_encoding(data, size);
2042  }
2043 
2044  PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
2045  {
2046  size_t length = size / sizeof(char_t);
2047 
2048  if (is_mutable)
2049  {
2050  out_buffer = static_cast<char_t*>(const_cast<void*>(contents));
2051  out_length = length;
2052  }
2053  else
2054  {
2055  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2056  if (!buffer) return false;
2057 
2058  if (contents)
2059  memcpy(buffer, contents, length * sizeof(char_t));
2060  else
2061  assert(length == 0);
2062 
2063  buffer[length] = 0;
2064 
2065  out_buffer = buffer;
2066  out_length = length + 1;
2067  }
2068 
2069  return true;
2070  }
2071 
2072 #ifdef PUGIXML_WCHAR_MODE
2073  PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
2074  {
2075  return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
2076  (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
2077  }
2078 
2079  PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
2080  {
2081  const char_t* data = static_cast<const char_t*>(contents);
2082  size_t length = size / sizeof(char_t);
2083 
2084  if (is_mutable)
2085  {
2086  char_t* buffer = const_cast<char_t*>(data);
2087 
2088  convert_wchar_endian_swap(buffer, data, length);
2089 
2090  out_buffer = buffer;
2091  out_length = length;
2092  }
2093  else
2094  {
2095  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2096  if (!buffer) return false;
2097 
2098  convert_wchar_endian_swap(buffer, data, length);
2099  buffer[length] = 0;
2100 
2101  out_buffer = buffer;
2102  out_length = length + 1;
2103  }
2104 
2105  return true;
2106  }
2107 
2108  template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
2109  {
2110  const typename D::type* data = static_cast<const typename D::type*>(contents);
2111  size_t data_length = size / sizeof(typename D::type);
2112 
2113  // first pass: get length in wchar_t units
2114  size_t length = D::process(data, data_length, 0, wchar_counter());
2115 
2116  // allocate buffer of suitable length
2117  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2118  if (!buffer) return false;
2119 
2120  // second pass: convert utf16 input to wchar_t
2121  wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
2122  wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer());
2123 
2124  assert(oend == obegin + length);
2125  *oend = 0;
2126 
2127  out_buffer = buffer;
2128  out_length = length + 1;
2129 
2130  return true;
2131  }
2132 
2133  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)
2134  {
2135  // get native encoding
2136  xml_encoding wchar_encoding = get_wchar_encoding();
2137 
2138  // fast path: no conversion required
2139  if (encoding == wchar_encoding)
2140  return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2141 
2142  // only endian-swapping is required
2143  if (need_endian_swap_utf(encoding, wchar_encoding))
2144  return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
2145 
2146  // source encoding is utf8
2147  if (encoding == encoding_utf8)
2148  return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder());
2149 
2150  // source encoding is utf16
2151  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2152  {
2154 
2155  return (native_encoding == encoding) ?
2156  convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
2157  convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
2158  }
2159 
2160  // source encoding is utf32
2161  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2162  {
2164 
2165  return (native_encoding == encoding) ?
2166  convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
2167  convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
2168  }
2169 
2170  // source encoding is latin1
2171  if (encoding == encoding_latin1)
2172  return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder());
2173 
2174  assert(false && "Invalid encoding"); // unreachable
2175  return false;
2176  }
2177 #else
2178  template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
2179  {
2180  const typename D::type* data = static_cast<const typename D::type*>(contents);
2181  size_t data_length = size / sizeof(typename D::type);
2182 
2183  // first pass: get length in utf8 units
2184  size_t length = D::process(data, data_length, 0, utf8_counter());
2185 
2186  // allocate buffer of suitable length
2187  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2188  if (!buffer) return false;
2189 
2190  // second pass: convert utf16 input to utf8
2191  uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
2192  uint8_t* oend = D::process(data, data_length, obegin, utf8_writer());
2193 
2194  assert(oend == obegin + length);
2195  *oend = 0;
2196 
2197  out_buffer = buffer;
2198  out_length = length + 1;
2199 
2200  return true;
2201  }
2202 
2203  PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
2204  {
2205  for (size_t i = 0; i < size; ++i)
2206  if (data[i] > 127)
2207  return i;
2208 
2209  return size;
2210  }
2211 
2212  PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
2213  {
2214  const uint8_t* data = static_cast<const uint8_t*>(contents);
2215  size_t data_length = size;
2216 
2217  // get size of prefix that does not need utf8 conversion
2218  size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
2219  assert(prefix_length <= data_length);
2220 
2221  const uint8_t* postfix = data + prefix_length;
2222  size_t postfix_length = data_length - prefix_length;
2223 
2224  // if no conversion is needed, just return the original buffer
2225  if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2226 
2227  // first pass: get length in utf8 units
2228  size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter());
2229 
2230  // allocate buffer of suitable length
2231  char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
2232  if (!buffer) return false;
2233 
2234  // second pass: convert latin1 input to utf8
2235  memcpy(buffer, data, prefix_length);
2236 
2237  uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
2238  uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer());
2239 
2240  assert(oend == obegin + length);
2241  *oend = 0;
2242 
2243  out_buffer = buffer;
2244  out_length = length + 1;
2245 
2246  return true;
2247  }
2248 
2249  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)
2250  {
2251  // fast path: no conversion required
2252  if (encoding == encoding_utf8)
2253  return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2254 
2255  // source encoding is utf16
2256  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2257  {
2259 
2260  return (native_encoding == encoding) ?
2261  convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
2262  convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
2263  }
2264 
2265  // source encoding is utf32
2266  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2267  {
2269 
2270  return (native_encoding == encoding) ?
2271  convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
2272  convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
2273  }
2274 
2275  // source encoding is latin1
2276  if (encoding == encoding_latin1)
2277  return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
2278 
2279  assert(false && "Invalid encoding"); // unreachable
2280  return false;
2281  }
2282 #endif
2283 
2284  PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length)
2285  {
2286  // get length in utf8 characters
2287  return wchar_decoder::process(str, length, 0, utf8_counter());
2288  }
2289 
2290  PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
2291  {
2292  // convert to utf8
2293  uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
2294  uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer());
2295 
2296  assert(begin + size == end);
2297  (void)!end;
2298  (void)!size;
2299  }
2300 
2301 #ifndef PUGIXML_NO_STL
2302  PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length)
2303  {
2304  // first pass: get length in utf8 characters
2305  size_t size = as_utf8_begin(str, length);
2306 
2307  // allocate resulting string
2308  std::string result;
2309  result.resize(size);
2310 
2311  // second pass: convert to utf8
2312  if (size > 0) as_utf8_end(&result[0], size, str, length);
2313 
2314  return result;
2315  }
2316 
2317  PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)
2318  {
2319  const uint8_t* data = reinterpret_cast<const uint8_t*>(str);
2320 
2321  // first pass: get length in wchar_t units
2322  size_t length = utf8_decoder::process(data, size, 0, wchar_counter());
2323 
2324  // allocate resulting string
2326  result.resize(length);
2327 
2328  // second pass: convert to wchar_t
2329  if (length > 0)
2330  {
2331  wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
2333 
2334  assert(begin + length == end);
2335  (void)!end;
2336  }
2337 
2338  return result;
2339  }
2340 #endif
2341 
2342  template <typename Header>
2343  inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target)
2344  {
2345  // never reuse shared memory
2346  if (header & xml_memory_page_contents_shared_mask) return false;
2347 
2348  size_t target_length = strlength(target);
2349 
2350  // always reuse document buffer memory if possible
2351  if ((header & header_mask) == 0) return target_length >= length;
2352 
2353  // reuse heap memory if waste is not too great
2354  const size_t reuse_threshold = 32;
2355 
2356  return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
2357  }
2358 
2359  template <typename String, typename Header>
2360  PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length)
2361  {
2362  if (source_length == 0)
2363  {
2364  // empty string and null pointer are equivalent, so just deallocate old memory
2365  xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
2366 
2367  if (header & header_mask) alloc->deallocate_string(dest);
2368 
2369  // mark the string as not allocated
2370  dest = 0;
2371  header &= ~header_mask;
2372 
2373  return true;
2374  }
2375  else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest))
2376  {
2377  // we can reuse old buffer, so just copy the new data (including zero terminator)
2378  memcpy(dest, source, source_length * sizeof(char_t));
2379  dest[source_length] = 0;
2380 
2381  return true;
2382  }
2383  else
2384  {
2385  xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
2386 
2387  if (!alloc->reserve()) return false;
2388 
2389  // allocate new buffer
2390  char_t* buf = alloc->allocate_string(source_length + 1);
2391  if (!buf) return false;
2392 
2393  // copy the string (including zero terminator)
2394  memcpy(buf, source, source_length * sizeof(char_t));
2395  buf[source_length] = 0;
2396 
2397  // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
2398  if (header & header_mask) alloc->deallocate_string(dest);
2399 
2400  // the string is now allocated, so set the flag
2401  dest = buf;
2402  header |= header_mask;
2403 
2404  return true;
2405  }
2406  }
2407 
2408  struct gap
2409  {
2411  size_t size;
2412 
2413  gap(): end(0), size(0)
2414  {
2415  }
2416 
2417  // Push new gap, move s count bytes further (skipping the gap).
2418  // Collapse previous gap.
2419  void push(char_t*& s, size_t count)
2420  {
2421  if (end) // there was a gap already; collapse it
2422  {
2423  // Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
2424  assert(s >= end);
2425  memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
2426  }
2427 
2428  s += count; // end of current gap
2429 
2430  // "merge" two gaps
2431  end = s;
2432  size += count;
2433  }
2434 
2435  // Collapse all gaps, return past-the-end pointer
2437  {
2438  if (end)
2439  {
2440  // Move [old_gap_end, current_pos) to [old_gap_start, ...)
2441  assert(s >= end);
2442  memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
2443 
2444  return s - size;
2445  }
2446  else return s;
2447  }
2448  };
2449 
2451  {
2452  char_t* stre = s + 1;
2453 
2454  switch (*stre)
2455  {
2456  case '#': // &#...
2457  {
2458  unsigned int ucsc = 0;
2459 
2460  if (stre[1] == 'x') // &#x... (hex code)
2461  {
2462  stre += 2;
2463 
2464  char_t ch = *stre;
2465 
2466  if (ch == ';') return stre;
2467 
2468  for (;;)
2469  {
2470  if (static_cast<unsigned int>(ch - '0') <= 9)
2471  ucsc = 16 * ucsc + (ch - '0');
2472  else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)
2473  ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);
2474  else if (ch == ';')
2475  break;
2476  else // cancel
2477  return stre;
2478 
2479  ch = *++stre;
2480  }
2481 
2482  ++stre;
2483  }
2484  else // &#... (dec code)
2485  {
2486  char_t ch = *++stre;
2487 
2488  if (ch == ';') return stre;
2489 
2490  for (;;)
2491  {
2492  if (static_cast<unsigned int>(ch - '0') <= 9)
2493  ucsc = 10 * ucsc + (ch - '0');
2494  else if (ch == ';')
2495  break;
2496  else // cancel
2497  return stre;
2498 
2499  ch = *++stre;
2500  }
2501 
2502  ++stre;
2503  }
2504 
2505  #ifdef PUGIXML_WCHAR_MODE
2506  s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
2507  #else
2508  s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));
2509  #endif
2510 
2511  g.push(s, stre - s);
2512  return stre;
2513  }
2514 
2515  case 'a': // &a
2516  {
2517  ++stre;
2518 
2519  if (*stre == 'm') // &am
2520  {
2521  if (*++stre == 'p' && *++stre == ';') // &amp;
2522  {
2523  *s++ = '&';
2524  ++stre;
2525 
2526  g.push(s, stre - s);
2527  return stre;
2528  }
2529  }
2530  else if (*stre == 'p') // &ap
2531  {
2532  if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // &apos;
2533  {
2534  *s++ = '\'';
2535  ++stre;
2536 
2537  g.push(s, stre - s);
2538  return stre;
2539  }
2540  }
2541  break;
2542  }
2543 
2544  case 'g': // &g
2545  {
2546  if (*++stre == 't' && *++stre == ';') // &gt;
2547  {
2548  *s++ = '>';
2549  ++stre;
2550 
2551  g.push(s, stre - s);
2552  return stre;
2553  }
2554  break;
2555  }
2556 
2557  case 'l': // &l
2558  {
2559  if (*++stre == 't' && *++stre == ';') // &lt;
2560  {
2561  *s++ = '<';
2562  ++stre;
2563 
2564  g.push(s, stre - s);
2565  return stre;
2566  }
2567  break;
2568  }
2569 
2570  case 'q': // &q
2571  {
2572  if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // &quot;
2573  {
2574  *s++ = '"';
2575  ++stre;
2576 
2577  g.push(s, stre - s);
2578  return stre;
2579  }
2580  break;
2581  }
2582 
2583  default:
2584  break;
2585  }
2586 
2587  return stre;
2588  }
2589 
2590  // Parser utilities
2591  #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
2592  #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
2593  #define PUGI__OPTSET(OPT) ( optmsk & (OPT) )
2594  #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
2595  #define PUGI__POPNODE() { cursor = cursor->parent; }
2596  #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
2597  #define PUGI__SCANWHILE(X) { while (X) ++s; }
2598  #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; } }
2599  #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; }
2600  #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t*>(0)
2601  #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); }
2602 
2604  {
2605  gap g;
2606 
2607  while (true)
2608  {
2610 
2611  if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
2612  {
2613  *s++ = '\n'; // replace first one with 0x0a
2614 
2615  if (*s == '\n') g.push(s, 1);
2616  }
2617  else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here
2618  {
2619  *g.flush(s) = 0;
2620 
2621  return s + (s[2] == '>' ? 3 : 2);
2622  }
2623  else if (*s == 0)
2624  {
2625  return 0;
2626  }
2627  else ++s;
2628  }
2629  }
2630 
2632  {
2633  gap g;
2634 
2635  while (true)
2636  {
2638 
2639  if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
2640  {
2641  *s++ = '\n'; // replace first one with 0x0a
2642 
2643  if (*s == '\n') g.push(s, 1);
2644  }
2645  else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here
2646  {
2647  *g.flush(s) = 0;
2648 
2649  return s + 1;
2650  }
2651  else if (*s == 0)
2652  {
2653  return 0;
2654  }
2655  else ++s;
2656  }
2657  }
2658 
2659  typedef char_t* (*strconv_pcdata_t)(char_t*);
2660 
2661  template <typename opt_trim, typename opt_eol, typename opt_escape> struct strconv_pcdata_impl
2662  {
2663  static char_t* parse(char_t* s)
2664  {
2665  gap g;
2666 
2667  char_t* begin = s;
2668 
2669  while (true)
2670  {
2672 
2673  if (*s == '<') // PCDATA ends here
2674  {
2675  char_t* end = g.flush(s);
2676 
2677  if (opt_trim::value)
2678  while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2679  --end;
2680 
2681  *end = 0;
2682 
2683  return s + 1;
2684  }
2685  else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
2686  {
2687  *s++ = '\n'; // replace first one with 0x0a
2688 
2689  if (*s == '\n') g.push(s, 1);
2690  }
2691  else if (opt_escape::value && *s == '&')
2692  {
2693  s = strconv_escape(s, g);
2694  }
2695  else if (*s == 0)
2696  {
2697  char_t* end = g.flush(s);
2698 
2699  if (opt_trim::value)
2700  while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2701  --end;
2702 
2703  *end = 0;
2704 
2705  return s;
2706  }
2707  else ++s;
2708  }
2709  }
2710  };
2711 
2713  {
2714  PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
2715 
2716  switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (trim eol escapes); this simultaneously checks 3 options from assertion above
2717  {
2726  default: assert(false); return 0; // unreachable
2727  }
2728  }
2729 
2730  typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
2731 
2732  template <typename opt_escape> struct strconv_attribute_impl
2733  {
2734  static char_t* parse_wnorm(char_t* s, char_t end_quote)
2735  {
2736  gap g;
2737 
2738  // trim leading whitespaces
2739  if (PUGI__IS_CHARTYPE(*s, ct_space))
2740  {
2741  char_t* str = s;
2742 
2743  do ++str;
2744  while (PUGI__IS_CHARTYPE(*str, ct_space));
2745 
2746  g.push(s, str - s);
2747  }
2748 
2749  while (true)
2750  {
2752 
2753  if (*s == end_quote)
2754  {
2755  char_t* str = g.flush(s);
2756 
2757  do *str-- = 0;
2758  while (PUGI__IS_CHARTYPE(*str, ct_space));
2759 
2760  return s + 1;
2761  }
2762  else if (PUGI__IS_CHARTYPE(*s, ct_space))
2763  {
2764  *s++ = ' ';
2765 
2766  if (PUGI__IS_CHARTYPE(*s, ct_space))
2767  {
2768  char_t* str = s + 1;
2769  while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
2770 
2771  g.push(s, str - s);
2772  }
2773  }
2774  else if (opt_escape::value && *s == '&')
2775  {
2776  s = strconv_escape(s, g);
2777  }
2778  else if (!*s)
2779  {
2780  return 0;
2781  }
2782  else ++s;
2783  }
2784  }
2785 
2786  static char_t* parse_wconv(char_t* s, char_t end_quote)
2787  {
2788  gap g;
2789 
2790  while (true)
2791  {
2793 
2794  if (*s == end_quote)
2795  {
2796  *g.flush(s) = 0;
2797 
2798  return s + 1;
2799  }
2800  else if (PUGI__IS_CHARTYPE(*s, ct_space))
2801  {
2802  if (*s == '\r')
2803  {
2804  *s++ = ' ';
2805 
2806  if (*s == '\n') g.push(s, 1);
2807  }
2808  else *s++ = ' ';
2809  }
2810  else if (opt_escape::value && *s == '&')
2811  {
2812  s = strconv_escape(s, g);
2813  }
2814  else if (!*s)
2815  {
2816  return 0;
2817  }
2818  else ++s;
2819  }
2820  }
2821 
2822  static char_t* parse_eol(char_t* s, char_t end_quote)
2823  {
2824  gap g;
2825 
2826  while (true)
2827  {
2829 
2830  if (*s == end_quote)
2831  {
2832  *g.flush(s) = 0;
2833 
2834  return s + 1;
2835  }
2836  else if (*s == '\r')
2837  {
2838  *s++ = '\n';
2839 
2840  if (*s == '\n') g.push(s, 1);
2841  }
2842  else if (opt_escape::value && *s == '&')
2843  {
2844  s = strconv_escape(s, g);
2845  }
2846  else if (!*s)
2847  {
2848  return 0;
2849  }
2850  else ++s;
2851  }
2852  }
2853 
2854  static char_t* parse_simple(char_t* s, char_t end_quote)
2855  {
2856  gap g;
2857 
2858  while (true)
2859  {
2861 
2862  if (*s == end_quote)
2863  {
2864  *g.flush(s) = 0;
2865 
2866  return s + 1;
2867  }
2868  else if (opt_escape::value && *s == '&')
2869  {
2870  s = strconv_escape(s, g);
2871  }
2872  else if (!*s)
2873  {
2874  return 0;
2875  }
2876  else ++s;
2877  }
2878  }
2879  };
2880 
2882  {
2884 
2885  switch ((optmask >> 4) & 15) // get bitmask for flags (wnorm wconv eol escapes); this simultaneously checks 4 options from assertion above
2886  {
2903  default: assert(false); return 0; // unreachable
2904  }
2905  }
2906 
2907  inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
2908  {
2909  xml_parse_result result;
2910  result.status = status;
2911  result.offset = offset;
2912 
2913  return result;
2914  }
2915 
2916  struct xml_parser
2917  {
2919  char_t* error_offset;
2921 
2923  {
2924  }
2925 
2926  // DOCTYPE consists of nested sections of the following possible types:
2927  // <!-- ... -->, <? ... ?>, "...", '...'
2928  // <![...]]>
2929  // <!...>
2930  // First group can not contain nested groups
2931  // Second group can contain nested groups of the same type
2932  // Third group can contain all other groups
2933  char_t* parse_doctype_primitive(char_t* s)
2934  {
2935  if (*s == '"' || *s == '\'')
2936  {
2937  // quoted string
2938  char_t ch = *s++;
2939  PUGI__SCANFOR(*s == ch);
2941 
2942  s++;
2943  }
2944  else if (s[0] == '<' && s[1] == '?')
2945  {
2946  // <? ... ?>
2947  s += 2;
2948  PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
2950 
2951  s += 2;
2952  }
2953  else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')
2954  {
2955  s += 4;
2956  PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
2958 
2959  s += 3;
2960  }
2962 
2963  return s;
2964  }
2965 
2966  char_t* parse_doctype_ignore(char_t* s)
2967  {
2968  size_t depth = 0;
2969 
2970  assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
2971  s += 3;
2972 
2973  while (*s)
2974  {
2975  if (s[0] == '<' && s[1] == '!' && s[2] == '[')
2976  {
2977  // nested ignore section
2978  s += 3;
2979  depth++;
2980  }
2981  else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
2982  {
2983  // ignore section end
2984  s += 3;
2985 
2986  if (depth == 0)
2987  return s;
2988 
2989  depth--;
2990  }
2991  else s++;
2992  }
2993 
2995  }
2996 
2997  char_t* parse_doctype_group(char_t* s, char_t endch)
2998  {
2999  size_t depth = 0;
3000 
3001  assert((s[0] == '<' || s[0] == 0) && s[1] == '!');
3002  s += 2;
3003 
3004  while (*s)
3005  {
3006  if (s[0] == '<' && s[1] == '!' && s[2] != '-')
3007  {
3008  if (s[2] == '[')
3009  {
3010  // ignore
3011  s = parse_doctype_ignore(s);
3012  if (!s) return s;
3013  }
3014  else
3015  {
3016  // some control group
3017  s += 2;
3018  depth++;
3019  }
3020  }
3021  else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
3022  {
3023  // unknown tag (forbidden), or some primitive group
3024  s = parse_doctype_primitive(s);
3025  if (!s) return s;
3026  }
3027  else if (*s == '>')
3028  {
3029  if (depth == 0)
3030  return s;
3031 
3032  depth--;
3033  s++;
3034  }
3035  else s++;
3036  }
3037 
3038  if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
3039 
3040  return s;
3041  }
3042 
3043  char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch)
3044  {
3045  // parse node contents, starting with exclamation mark
3046  ++s;
3047 
3048  if (*s == '-') // '<!-...'
3049  {
3050  ++s;
3051 
3052  if (*s == '-') // '<!--...'
3053  {
3054  ++s;
3055 
3057  {
3058  PUGI__PUSHNODE(node_comment); // Append a new node on the tree.
3059  cursor->value = s; // Save the offset.
3060  }
3061 
3063  {
3064  s = strconv_comment(s, endch);
3065 
3066  if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
3067  }
3068  else
3069  {
3070  // Scan for terminating '-->'.
3071  PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>'));
3073 
3075  *s = 0; // Zero-terminate this segment at the first terminating '-'.
3076 
3077  s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
3078  }
3079  }
3081  }
3082  else if (*s == '[')
3083  {
3084  // '<![CDATA[...'
3085  if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')
3086  {
3087  ++s;
3088 
3090  {
3091  PUGI__PUSHNODE(node_cdata); // Append a new node on the tree.
3092  cursor->value = s; // Save the offset.
3093 
3094  if (PUGI__OPTSET(parse_eol))
3095  {
3096  s = strconv_cdata(s, endch);
3097 
3098  if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
3099  }
3100  else
3101  {
3102  // Scan for terminating ']]>'.
3103  PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
3105 
3106  *s++ = 0; // Zero-terminate this segment.
3107  }
3108  }
3109  else // Flagged for discard, but we still have to scan for the terminator.
3110  {
3111  // Scan for terminating ']]>'.
3112  PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
3114 
3115  ++s;
3116  }
3117 
3118  s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
3119  }
3121  }
3122  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'))
3123  {
3124  s -= 2;
3125 
3126  if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
3127 
3128  char_t* mark = s + 9;
3129 
3130  s = parse_doctype_group(s, endch);
3131  if (!s) return s;
3132 
3133  assert((*s == 0 && endch == '>') || *s == '>');
3134  if (*s) *s++ = 0;
3135 
3137  {
3138  while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
3139 
3141 
3142  cursor->value = mark;
3143  }
3144  }
3145  else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s);
3146  else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s);
3148 
3149  return s;
3150  }
3151 
3152  char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch)
3153  {
3154  // load into registers
3155  xml_node_struct* cursor = ref_cursor;
3156  char_t ch = 0;
3157 
3158  // parse node contents, starting with question mark
3159  ++s;
3160 
3161  // read PI target
3162  char_t* target = s;
3163 
3165 
3168 
3169  // determine node type; stricmp / strcasecmp is not portable
3170  bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
3171 
3172  if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
3173  {
3174  if (declaration)
3175  {
3176  // disallow non top-level declarations
3177  if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
3178 
3180  }
3181  else
3182  {
3184  }
3185 
3186  cursor->name = target;
3187 
3188  PUGI__ENDSEG();
3189 
3190  // parse value/attributes
3191  if (ch == '?')
3192  {
3193  // empty node
3194  if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s);
3195  s += (*s == '>');
3196 
3197  PUGI__POPNODE();
3198  }
3199  else if (PUGI__IS_CHARTYPE(ch, ct_space))
3200  {
3201  PUGI__SKIPWS();
3202 
3203  // scan for tag end
3204  char_t* value = s;
3205 
3206  PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
3208 
3209  if (declaration)
3210  {
3211  // replace ending ? with / so that 'element' terminates properly
3212  *s = '/';
3213 
3214  // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES
3215  s = value;
3216  }
3217  else
3218  {
3219  // store value and step over >
3220  cursor->value = value;
3221 
3222  PUGI__POPNODE();
3223 
3224  PUGI__ENDSEG();
3225 
3226  s += (*s == '>');
3227  }
3228  }
3230  }
3231  else
3232  {
3233  // scan for tag end
3234  PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
3236 
3237  s += (s[1] == '>' ? 2 : 1);
3238  }
3239 
3240  // store from registers
3241  ref_cursor = cursor;
3242 
3243  return s;
3244  }
3245 
3246  char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch)
3247  {
3248  strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
3249  strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
3250 
3251  char_t ch = 0;
3252  xml_node_struct* cursor = root;
3253  char_t* mark = s;
3254 
3255  while (*s != 0)
3256  {
3257  if (*s == '<')
3258  {
3259  ++s;
3260 
3261  LOC_TAG:
3262  if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
3263  {
3264  PUGI__PUSHNODE(node_element); // Append a new node to the tree.
3265 
3266  cursor->name = s;
3267 
3268  PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
3269  PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
3270 
3271  if (ch == '>')
3272  {
3273  // end of tag
3274  }
3275  else if (PUGI__IS_CHARTYPE(ch, ct_space))
3276  {
3277  LOC_ATTRIBUTES:
3278  while (true)
3279  {
3280  PUGI__SKIPWS(); // Eat any whitespace.
3281 
3282  if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
3283  {
3284  xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute.
3286 
3287  a->name = s; // Save the offset.
3288 
3289  PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
3290  PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
3291 
3292  if (PUGI__IS_CHARTYPE(ch, ct_space))
3293  {
3294  PUGI__SKIPWS(); // Eat any whitespace.
3295 
3296  ch = *s;
3297  ++s;
3298  }
3299 
3300  if (ch == '=') // '<... #=...'
3301  {
3302  PUGI__SKIPWS(); // Eat any whitespace.
3303 
3304  if (*s == '"' || *s == '\'') // '<... #="...'
3305  {
3306  ch = *s; // Save quote char to avoid breaking on "''" -or- '""'.
3307  ++s; // Step over the quote.
3308  a->value = s; // Save the offset.
3309 
3310  s = strconv_attribute(s, ch);
3311 
3312  if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
3313 
3314  // After this line the loop continues from the start;
3315  // Whitespaces, / and > are ok, symbols and EOF are wrong,
3316  // everything else will be detected
3318  }
3320  }
3322  }
3323  else if (*s == '/')
3324  {
3325  ++s;
3326 
3327  if (*s == '>')
3328  {
3329  PUGI__POPNODE();
3330  s++;
3331  break;
3332  }
3333  else if (*s == 0 && endch == '>')
3334  {
3335  PUGI__POPNODE();
3336  break;
3337  }
3339  }
3340  else if (*s == '>')
3341  {
3342  ++s;
3343 
3344  break;
3345  }
3346  else if (*s == 0 && endch == '>')
3347  {
3348  break;
3349  }
3351  }
3352 
3353  // !!!
3354  }
3355  else if (ch == '/') // '<#.../'
3356  {
3358 
3359  PUGI__POPNODE(); // Pop.
3360 
3361  s += (*s == '>');
3362  }
3363  else if (ch == 0)
3364  {
3365  // we stepped over null terminator, backtrack & handle closing tag
3366  --s;
3367 
3368  if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s);
3369  }
3371  }
3372  else if (*s == '/')
3373  {
3374  ++s;
3375 
3376  mark = s;
3377 
3378  char_t* name = cursor->name;
3380 
3381  while (PUGI__IS_CHARTYPE(*s, ct_symbol))
3382  {
3383  if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
3384  }
3385 
3386  if (*name)
3387  {
3388  if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
3390  }
3391 
3392  PUGI__POPNODE(); // Pop.
3393 
3394  PUGI__SKIPWS();
3395 
3396  if (*s == 0)
3397  {
3398  if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
3399  }
3400  else
3401  {
3402  if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
3403  ++s;
3404  }
3405  }
3406  else if (*s == '?') // '<?...'
3407  {
3408  s = parse_question(s, cursor, optmsk, endch);
3409  if (!s) return s;
3410 
3411  assert(cursor);
3412  if (PUGI__NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES;
3413  }
3414  else if (*s == '!') // '<!...'
3415  {
3416  s = parse_exclamation(s, cursor, optmsk, endch);
3417  if (!s) return s;
3418  }
3419  else if (*s == 0 && endch == '?') PUGI__THROW_ERROR(status_bad_pi, s);
3421  }
3422  else
3423  {
3424  mark = s; // Save this offset while searching for a terminator.
3425 
3426  PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
3427 
3428  if (*s == '<' || !*s)
3429  {
3430  // We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one
3431  assert(mark != s);
3432 
3434  {
3435  continue;
3436  }
3438  {
3439  if (s[0] != '<' || s[1] != '/' || cursor->first_child) continue;
3440  }
3441  }
3442 
3444  s = mark;
3445 
3446  if (cursor->parent || PUGI__OPTSET(parse_fragment))
3447  {
3448  if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value)
3449  {
3450  cursor->value = s; // Save the offset.
3451  }
3452  else
3453  {
3454  PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree.
3455 
3456  cursor->value = s; // Save the offset.
3457 
3458  PUGI__POPNODE(); // Pop since this is a standalone.
3459  }
3460 
3461  s = strconv_pcdata(s);
3462 
3463  if (!*s) break;
3464  }
3465  else
3466  {
3467  PUGI__SCANFOR(*s == '<'); // '...<'
3468  if (!*s) break;
3469 
3470  ++s;
3471  }
3472 
3473  // We're after '<'
3474  goto LOC_TAG;
3475  }
3476  }
3477 
3478  // check that last tag is closed
3479  if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s);
3480 
3481  return s;
3482  }
3483 
3484  #ifdef PUGIXML_WCHAR_MODE
3485  static char_t* parse_skip_bom(char_t* s)
3486  {
3487  unsigned int bom = 0xfeff;
3488  return (s[0] == static_cast<wchar_t>(bom)) ? s + 1 : s;
3489  }
3490  #else
3491  static char_t* parse_skip_bom(char_t* s)
3492  {
3493  return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s;
3494  }
3495  #endif
3496 
3497  static bool has_element_node_siblings(xml_node_struct* node)
3498  {
3499  while (node)
3500  {
3501  if (PUGI__NODETYPE(node) == node_element) return true;
3502 
3503  node = node->next_sibling;
3504  }
3505 
3506  return false;
3507  }
3508 
3509  static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk)
3510  {
3511  // early-out for empty documents
3512  if (length == 0)
3514 
3515  // get last child of the root before parsing
3516  xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
3517 
3518  // create parser on stack
3519  xml_parser parser(static_cast<xml_allocator*>(xmldoc));
3520 
3521  // save last character and make buffer zero-terminated (speeds up parsing)
3522  char_t endch = buffer[length - 1];
3523  buffer[length - 1] = 0;
3524 
3525  // skip BOM to make sure it does not end up as part of parse output
3526  char_t* buffer_data = parse_skip_bom(buffer);
3527 
3528  // perform actual parsing
3529  parser.parse_tree(buffer_data, root, optmsk, endch);
3530 
3531  xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
3532  assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
3533 
3534  if (result)
3535  {
3536  // since we removed last character, we have to handle the only possible false positive (stray <)
3537  if (endch == '<')
3538  return make_parse_result(status_unrecognized_tag, length - 1);
3539 
3540  // check if there are any element nodes parsed
3541  xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0;
3542 
3543  if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
3544  return make_parse_result(status_no_document_element, length - 1);
3545  }
3546  else
3547  {
3548  // roll back offset if it occurs on a null terminator in the source buffer
3549  if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0)
3550  result.offset--;
3551  }
3552 
3553  return result;
3554  }
3555  };
3556 
3557  // Output facilities
3559  {
3560  #ifdef PUGIXML_WCHAR_MODE
3561  return get_wchar_encoding();
3562  #else
3563  return encoding_utf8;
3564  #endif
3565  }
3566 
3568  {
3569  // replace wchar encoding with utf implementation
3570  if (encoding == encoding_wchar) return get_wchar_encoding();
3571 
3572  // replace utf16 encoding with utf16 with specific endianness
3574 
3575  // replace utf32 encoding with utf32 with specific endianness
3577 
3578  // only do autodetection if no explicit encoding is requested
3579  if (encoding != encoding_auto) return encoding;
3580 
3581  // assume utf8 encoding
3582  return encoding_utf8;
3583  }
3584 
3585  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)
3586  {
3587  PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
3588 
3589  typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
3590 
3591  return static_cast<size_t>(end - dest) * sizeof(*dest);
3592  }
3593 
3594  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)
3595  {
3596  PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
3597 
3598  typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
3599 
3600  if (opt_swap)
3601  {
3602  for (typename T::value_type i = dest; i != end; ++i)
3603  *i = endian_swap(*i);
3604  }
3605 
3606  return static_cast<size_t>(end - dest) * sizeof(*dest);
3607  }
3608 
3609 #ifdef PUGIXML_WCHAR_MODE
3610  PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
3611  {
3612  if (length < 1) return 0;
3613 
3614  // discard last character if it's the lead of a surrogate pair
3615  return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
3616  }
3617 
3618  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)
3619  {
3620  // only endian-swapping is required
3621  if (need_endian_swap_utf(encoding, get_wchar_encoding()))
3622  {
3623  convert_wchar_endian_swap(r_char, data, length);
3624 
3625  return length * sizeof(char_t);
3626  }
3627 
3628  // convert to utf8
3629  if (encoding == encoding_utf8)
3630  return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer());
3631 
3632  // convert to utf16
3633  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3634  {
3636 
3637  return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding);
3638  }
3639 
3640  // convert to utf32
3641  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3642  {
3644 
3645  return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding);
3646  }
3647 
3648  // convert to latin1
3649  if (encoding == encoding_latin1)
3650  return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer());
3651 
3652  assert(false && "Invalid encoding"); // unreachable
3653  return 0;
3654  }
3655 #else
3656  PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
3657  {
3658  if (length < 5) return 0;
3659 
3660  for (size_t i = 1; i <= 4; ++i)
3661  {
3662  uint8_t ch = static_cast<uint8_t>(data[length - i]);
3663 
3664  // either a standalone character or a leading one
3665  if ((ch & 0xc0) != 0x80) return length - i;
3666  }
3667 
3668  // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk
3669  return length;
3670  }
3671 
3672  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)
3673  {
3674  if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3675  {
3677 
3678  return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding);
3679  }
3680 
3681  if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3682  {
3684 
3685  return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding);
3686  }
3687 
3688  if (encoding == encoding_latin1)
3689  return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer());
3690 
3691  assert(false && "Invalid encoding"); // unreachable
3692  return 0;
3693  }
3694 #endif
3695 
3697  {
3699  xml_buffered_writer& operator=(const xml_buffered_writer&);
3700 
3701  public:
3702  xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
3703  {
3705  }
3706 
3707  size_t flush()
3708  {
3709  flush(buffer, bufsize);
3710  bufsize = 0;
3711  return 0;
3712  }
3713 
3714  void flush(const char_t* data, size_t size)
3715  {
3716  if (size == 0) return;
3717 
3718  // fast path, just write data
3719  if (encoding == get_write_native_encoding())
3720  writer.write(data, size * sizeof(char_t));
3721  else
3722  {
3723  // convert chunk
3724  size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);
3725  assert(result <= sizeof(scratch));
3726 
3727  // write data
3728  writer.write(scratch.data_u8, result);
3729  }
3730  }
3731 
3732  void write_direct(const char_t* data, size_t length)
3733  {
3734  // flush the remaining buffer contents
3735  flush();
3736 
3737  // handle large chunks
3738  if (length > bufcapacity)
3739  {
3740  if (encoding == get_write_native_encoding())
3741  {
3742  // fast path, can just write data chunk
3743  writer.write(data, length * sizeof(char_t));
3744  return;
3745  }
3746 
3747  // need to convert in suitable chunks
3748  while (length > bufcapacity)
3749  {
3750  // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer
3751  // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
3752  size_t chunk_size = get_valid_length(data, bufcapacity);
3753  assert(chunk_size);
3754 
3755  // convert chunk and write
3756  flush(data, chunk_size);
3757 
3758  // iterate
3759  data += chunk_size;
3760  length -= chunk_size;
3761  }
3762 
3763  // small tail is copied below
3764  bufsize = 0;
3765  }
3766 
3767  memcpy(buffer + bufsize, data, length * sizeof(char_t));
3768  bufsize += length;
3769  }
3770 
3771  void write_buffer(const char_t* data, size_t length)
3772  {
3773  size_t offset = bufsize;
3774 
3775  if (offset + length <= bufcapacity)
3776  {
3777  memcpy(buffer + offset, data, length * sizeof(char_t));
3778  bufsize = offset + length;
3779  }
3780  else
3781  {
3782  write_direct(data, length);
3783  }
3784  }
3785 
3786  void write_string(const char_t* data)
3787  {
3788  // write the part of the string that fits in the buffer
3789  size_t offset = bufsize;
3790 
3791  while (*data && offset < bufcapacity)
3792  buffer[offset++] = *data++;
3793 
3794  // write the rest
3795  if (offset < bufcapacity)
3796  {
3797  bufsize = offset;
3798  }
3799  else
3800  {
3801  // backtrack a bit if we have split the codepoint
3802  size_t length = offset - bufsize;
3803  size_t extra = length - get_valid_length(data - length, length);
3804 
3805  bufsize = offset - extra;
3806 
3807  write_direct(data - extra, strlength(data) + extra);
3808  }
3809  }
3810 
3811  void write(char_t d0)
3812  {
3813  size_t offset = bufsize;
3814  if (offset > bufcapacity - 1) offset = flush();
3815 
3816  buffer[offset + 0] = d0;
3817  bufsize = offset + 1;
3818  }
3819 
3820  void write(char_t d0, char_t d1)
3821  {
3822  size_t offset = bufsize;
3823  if (offset > bufcapacity - 2) offset = flush();
3824 
3825  buffer[offset + 0] = d0;
3826  buffer[offset + 1] = d1;
3827  bufsize = offset + 2;
3828  }
3829 
3830  void write(char_t d0, char_t d1, char_t d2)
3831  {
3832  size_t offset = bufsize;
3833  if (offset > bufcapacity - 3) offset = flush();
3834 
3835  buffer[offset + 0] = d0;
3836  buffer[offset + 1] = d1;
3837  buffer[offset + 2] = d2;
3838  bufsize = offset + 3;
3839  }
3840 
3841  void write(char_t d0, char_t d1, char_t d2, char_t d3)
3842  {
3843  size_t offset = bufsize;
3844  if (offset > bufcapacity - 4) offset = flush();
3845 
3846  buffer[offset + 0] = d0;
3847  buffer[offset + 1] = d1;
3848  buffer[offset + 2] = d2;
3849  buffer[offset + 3] = d3;
3850  bufsize = offset + 4;
3851  }
3852 
3853  void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
3854  {
3855  size_t offset = bufsize;
3856  if (offset > bufcapacity - 5) offset = flush();
3857 
3858  buffer[offset + 0] = d0;
3859  buffer[offset + 1] = d1;
3860  buffer[offset + 2] = d2;
3861  buffer[offset + 3] = d3;
3862  buffer[offset + 4] = d4;
3863  bufsize = offset + 5;
3864  }
3865 
3866  void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
3867  {
3868  size_t offset = bufsize;
3869  if (offset > bufcapacity - 6) offset = flush();
3870 
3871  buffer[offset + 0] = d0;
3872  buffer[offset + 1] = d1;
3873  buffer[offset + 2] = d2;
3874  buffer[offset + 3] = d3;
3875  buffer[offset + 4] = d4;
3876  buffer[offset + 5] = d5;
3877  bufsize = offset + 6;
3878  }
3879 
3880  // utf8 maximum expansion: x4 (-> utf32)
3881  // utf16 maximum expansion: x2 (-> utf32)
3882  // utf32 maximum expansion: x1
3883  enum
3884  {
3886  #ifdef PUGIXML_MEMORY_OUTPUT_STACK
3887  PUGIXML_MEMORY_OUTPUT_STACK
3888  #else
3889  10240
3890  #endif
3891  ,
3893  };
3894 
3895  char_t buffer[bufcapacity];
3896 
3897  union
3898  {
3899  uint8_t data_u8[4 * bufcapacity];
3900  uint16_t data_u16[2 * bufcapacity];
3903  } scratch;
3904 
3905  xml_writer& writer;
3906  size_t bufsize;
3908  };
3909 
3910  PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
3911  {
3912  while (*s)
3913  {
3914  const char_t* prev = s;
3915 
3916  // While *s is a usual symbol
3918 
3919  writer.write_buffer(prev, static_cast<size_t>(s - prev));
3920 
3921  switch (*s)
3922  {
3923  case 0: break;
3924  case '&':
3925  writer.write('&', 'a', 'm', 'p', ';');
3926  ++s;
3927  break;
3928  case '<':
3929  writer.write('&', 'l', 't', ';');
3930  ++s;
3931  break;
3932  case '>':
3933  writer.write('&', 'g', 't', ';');
3934  ++s;
3935  break;
3936  case '"':
3937  if (flags & format_attribute_single_quote)
3938  writer.write('"');
3939  else
3940  writer.write('&', 'q', 'u', 'o', 't', ';');
3941  ++s;
3942  break;
3943  case '\'':
3944  if (flags & format_attribute_single_quote)
3945  writer.write('&', 'a', 'p', 'o', 's', ';');
3946  else
3947  writer.write('\'');
3948  ++s;
3949  break;
3950  default: // s is not a usual symbol
3951  {
3952  unsigned int ch = static_cast<unsigned int>(*s++);
3953  assert(ch < 32);
3954 
3955  if (!(flags & format_skip_control_chars))
3956  writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');
3957  }
3958  }
3959  }
3960  }
3961 
3962  PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
3963  {
3964  if (flags & format_no_escapes)
3965  writer.write_string(s);
3966  else
3967  text_output_escaped(writer, s, type, flags);
3968  }
3969 
3970  PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s)
3971  {
3972  do
3973  {
3974  writer.write('<', '!', '[', 'C', 'D');
3975  writer.write('A', 'T', 'A', '[');
3976 
3977  const char_t* prev = s;
3978 
3979  // look for ]]> sequence - we can't output it as is since it terminates CDATA
3980  while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s;
3981 
3982  // skip ]] if we stopped at ]]>, > will go to the next CDATA section
3983  if (*s) s += 2;
3984 
3985  writer.write_buffer(prev, static_cast<size_t>(s - prev));
3986 
3987  writer.write(']', ']', '>');
3988  }
3989  while (*s);
3990  }
3991 
3992  PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth)
3993  {
3994  switch (indent_length)
3995  {
3996  case 1:
3997  {
3998  for (unsigned int i = 0; i < depth; ++i)
3999  writer.write(indent[0]);
4000  break;
4001  }
4002 
4003  case 2:
4004  {
4005  for (unsigned int i = 0; i < depth; ++i)
4006  writer.write(indent[0], indent[1]);
4007  break;
4008  }
4009 
4010  case 3:
4011  {
4012  for (unsigned int i = 0; i < depth; ++i)
4013  writer.write(indent[0], indent[1], indent[2]);
4014  break;
4015  }
4016 
4017  case 4:
4018  {
4019  for (unsigned int i = 0; i < depth; ++i)
4020  writer.write(indent[0], indent[1], indent[2], indent[3]);
4021  break;
4022  }
4023 
4024  default:
4025  {
4026  for (unsigned int i = 0; i < depth; ++i)
4027  writer.write_buffer(indent, indent_length);
4028  }
4029  }
4030  }
4031 
4032  PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s)
4033  {
4034  writer.write('<', '!', '-', '-');
4035 
4036  while (*s)
4037  {
4038  const char_t* prev = s;
4039 
4040  // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body
4041  while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s;
4042 
4043  writer.write_buffer(prev, static_cast<size_t>(s - prev));
4044 
4045  if (*s)
4046  {
4047  assert(*s == '-');
4048 
4049  writer.write('-', ' ');
4050  ++s;
4051  }
4052  }
4053 
4054  writer.write('-', '-', '>');
4055  }
4056 
4057  PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s)
4058  {
4059  while (*s)
4060  {
4061  const char_t* prev = s;
4062 
4063  // look for ?> sequence - we can't output it since ?> terminates PI
4064  while (*s && !(s[0] == '?' && s[1] == '>')) ++s;
4065 
4066  writer.write_buffer(prev, static_cast<size_t>(s - prev));
4067 
4068  if (*s)
4069  {
4070  assert(s[0] == '?' && s[1] == '>');
4071 
4072  writer.write('?', ' ', '>');
4073  s += 2;
4074  }
4075  }
4076  }
4077 
4078  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)
4079  {
4080  const char_t* default_name = PUGIXML_TEXT(":anonymous");
4081  const char_t enquotation_char = (flags & format_attribute_single_quote) ? '\'' : '"';
4082 
4083  for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
4084  {
4086  {
4087  writer.write('\n');
4088 
4089  text_output_indent(writer, indent, indent_length, depth + 1);
4090  }
4091  else
4092  {
4093  writer.write(' ');
4094  }
4095 
4096  writer.write_string(a->name ? a->name + 0 : default_name);
4097  writer.write('=', enquotation_char);
4098 
4099  if (a->value)
4100  text_output(writer, a->value, ctx_special_attr, flags);
4101 
4102  writer.write(enquotation_char);
4103  }
4104  }
4105 
4106  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)
4107  {
4108  const char_t* default_name = PUGIXML_TEXT(":anonymous");
4109  const char_t* name = node->name ? node->name + 0 : default_name;
4110 
4111  writer.write('<');
4112  writer.write_string(name);
4113 
4114  if (node->first_attribute)
4115  node_output_attributes(writer, node, indent, indent_length, flags, depth);
4116 
4117  // element nodes can have value if parse_embed_pcdata was used
4118  if (!node->value)
4119  {
4120  if (!node->first_child)
4121  {
4122  if (flags & format_no_empty_element_tags)
4123  {
4124  writer.write('>', '<', '/');
4125  writer.write_string(name);
4126  writer.write('>');
4127 
4128  return false;
4129  }
4130  else
4131  {
4132  if ((flags & format_raw) == 0)
4133  writer.write(' ');
4134 
4135  writer.write('/', '>');
4136 
4137  return false;
4138  }
4139  }
4140  else
4141  {
4142  writer.write('>');
4143 
4144  return true;
4145  }
4146  }
4147  else
4148  {
4149  writer.write('>');
4150 
4151  text_output(writer, node->value, ctx_special_pcdata, flags);
4152 
4153  if (!node->first_child)
4154  {
4155  writer.write('<', '/');
4156  writer.write_string(name);
4157  writer.write('>');
4158 
4159  return false;
4160  }
4161  else
4162  {
4163  return true;
4164  }
4165  }
4166  }
4167 
4168  PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node)
4169  {
4170  const char_t* default_name = PUGIXML_TEXT(":anonymous");
4171  const char_t* name = node->name ? node->name + 0 : default_name;
4172 
4173  writer.write('<', '/');
4174  writer.write_string(name);
4175  writer.write('>');
4176  }
4177 
4178  PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)
4179  {
4180  const char_t* default_name = PUGIXML_TEXT(":anonymous");
4181 
4182  switch (PUGI__NODETYPE(node))
4183  {
4184  case node_pcdata:
4185  text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags);
4186  break;
4187 
4188  case node_cdata:
4189  text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
4190  break;
4191 
4192  case node_comment:
4193  node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
4194  break;
4195 
4196  case node_pi:
4197  writer.write('<', '?');
4198  writer.write_string(node->name ? node->name + 0 : default_name);
4199 
4200  if (node->value)
4201  {
4202  writer.write(' ');
4203  node_output_pi_value(writer, node->value);
4204  }
4205 
4206  writer.write('?', '>');
4207  break;
4208 
4209  case node_declaration:
4210  writer.write('<', '?');
4211  writer.write_string(node->name ? node->name + 0 : default_name);
4212  node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0);
4213  writer.write('?', '>');
4214  break;
4215 
4216  case node_doctype:
4217  writer.write('<', '!', 'D', 'O', 'C');
4218  writer.write('T', 'Y', 'P', 'E');
4219 
4220  if (node->value)
4221  {
4222  writer.write(' ');
4223  writer.write_string(node->value);
4224  }
4225 
4226  writer.write('>');
4227  break;
4228 
4229  default:
4230  assert(false && "Invalid node type"); // unreachable
4231  }
4232  }
4233 
4235  {
4238  };
4239 
4240  PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth)
4241  {
4242  size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0;
4243  unsigned int indent_flags = indent_indent;
4244 
4245  xml_node_struct* node = root;
4246 
4247  do
4248  {
4249  assert(node);
4250 
4251  // begin writing current node
4252  if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata)
4253  {
4254  node_output_simple(writer, node, flags);
4255 
4256  indent_flags = 0;
4257  }
4258  else
4259  {
4260  if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4261  writer.write('\n');
4262 
4263  if ((indent_flags & indent_indent) && indent_length)
4264  text_output_indent(writer, indent, indent_length, depth);
4265 
4266  if (PUGI__NODETYPE(node) == node_element)
4267  {
4268  indent_flags = indent_newline | indent_indent;
4269 
4270  if (node_output_start(writer, node, indent, indent_length, flags, depth))
4271  {
4272  // element nodes can have value if parse_embed_pcdata was used
4273  if (node->value)
4274  indent_flags = 0;
4275 
4276  node = node->first_child;
4277  depth++;
4278  continue;
4279  }
4280  }
4281  else if (PUGI__NODETYPE(node) == node_document)
4282  {
4283  indent_flags = indent_indent;
4284 
4285  if (node->first_child)
4286  {
4287  node = node->first_child;
4288  continue;
4289  }
4290  }
4291  else
4292  {
4293  node_output_simple(writer, node, flags);
4294 
4295  indent_flags = indent_newline | indent_indent;
4296  }
4297  }
4298 
4299  // continue to the next node
4300  while (node != root)
4301  {
4302  if (node->next_sibling)
4303  {
4304  node = node->next_sibling;
4305  break;
4306  }
4307 
4308  node = node->parent;
4309 
4310  // write closing node
4311  if (PUGI__NODETYPE(node) == node_element)
4312  {
4313  depth--;
4314 
4315  if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4316  writer.write('\n');
4317 
4318  if ((indent_flags & indent_indent) && indent_length)
4319  text_output_indent(writer, indent, indent_length, depth);
4320 
4321  node_output_end(writer, node);
4322 
4323  indent_flags = indent_newline | indent_indent;
4324  }
4325  }
4326  }
4327  while (node != root);
4328 
4329  if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4330  writer.write('\n');
4331  }
4332 
4333  PUGI__FN bool has_declaration(xml_node_struct* node)
4334  {
4335  for (xml_node_struct* child = node->first_child; child; child = child->next_sibling)
4336  {
4338 
4339  if (type == node_declaration) return true;
4340  if (type == node_element) return false;
4341  }
4342 
4343  return false;
4344  }
4345 
4346  PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node)
4347  {
4348  for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
4349  if (a == attr)
4350  return true;
4351 
4352  return false;
4353  }
4354 
4356  {
4357  return parent == node_element || parent == node_declaration;
4358  }
4359 
4361  {
4362  if (parent != node_document && parent != node_element) return false;
4363  if (child == node_document || child == node_null) return false;
4364  if (parent != node_document && (child == node_declaration || child == node_doctype)) return false;
4365 
4366  return true;
4367  }
4368 
4369  PUGI__FN bool allow_move(xml_node parent, xml_node child)
4370  {
4371  // check that child can be a child of parent
4372  if (!allow_insert_child(parent.type(), child.type()))
4373  return false;
4374 
4375  // check that node is not moved between documents
4376  if (parent.root() != child.root())
4377  return false;
4378 
4379  // check that new parent is not in the child subtree
4380  xml_node cur = parent;
4381 
4382  while (cur)
4383  {
4384  if (cur == child)
4385  return false;
4386 
4387  cur = cur.parent();
4388  }
4389 
4390  return true;
4391  }
4392 
4393  template <typename String, typename Header>
4394  PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)
4395  {
4396  assert(!dest && (header & header_mask) == 0);
4397 
4398  if (source)
4399  {
4400  if (alloc && (source_header & header_mask) == 0)
4401  {
4402  dest = source;
4403 
4404  // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared
4405  header |= xml_memory_page_contents_shared_mask;
4406  source_header |= xml_memory_page_contents_shared_mask;
4407  }
4408  else
4409  strcpy_insitu(dest, header, header_mask, source, strlength(source));
4410  }
4411  }
4412 
4413  PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc)
4414  {
4415  node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc);
4416  node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc);
4417 
4418  for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute)
4419  {
4420  xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn));
4421 
4422  if (da)
4423  {
4424  node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
4425  node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
4426  }
4427  }
4428  }
4429 
4430  PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)
4431  {
4432  xml_allocator& alloc = get_allocator(dn);
4433  xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0;
4434 
4435  node_copy_contents(dn, sn, shared_alloc);
4436 
4437  xml_node_struct* dit = dn;
4438  xml_node_struct* sit = sn->first_child;
4439 
4440  while (sit && sit != sn)
4441  {
4442  // loop invariant: dit is inside the subtree rooted at dn
4443  assert(dit);
4444 
4445  // when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop
4446  if (sit != dn)
4447  {
4448  xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit));
4449 
4450  if (copy)
4451  {
4452  node_copy_contents(copy, sit, shared_alloc);
4453 
4454  if (sit->first_child)
4455  {
4456  dit = copy;
4457  sit = sit->first_child;
4458  continue;
4459  }
4460  }
4461  }
4462 
4463  // continue to the next node
4464  do
4465  {
4466  if (sit->next_sibling)
4467  {
4468  sit = sit->next_sibling;
4469  break;
4470  }
4471 
4472  sit = sit->parent;
4473  dit = dit->parent;
4474 
4475  // loop invariant: dit is inside the subtree rooted at dn while sit is inside sn
4476  assert(sit == sn || dit);
4477  }
4478  while (sit != sn);
4479  }
4480 
4481  assert(!sit || dit == dn->parent);
4482  }
4483 
4484  PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
4485  {
4486  xml_allocator& alloc = get_allocator(da);
4487  xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0;
4488 
4489  node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
4490  node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
4491  }
4492 
4493  inline bool is_text_node(xml_node_struct* node)
4494  {
4496 
4497  return type == node_pcdata || type == node_cdata;
4498  }
4499 
4500  // get value with conversion functions
4501  template <typename U> PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv)
4502  {
4503  U result = 0;
4504  const char_t* s = value;
4505 
4506  while (PUGI__IS_CHARTYPE(*s, ct_space))
4507  s++;
4508 
4509  bool negative = (*s == '-');
4510 
4511  s += (*s == '+' || *s == '-');
4512 
4513  bool overflow = false;
4514 
4515  if (s[0] == '0' && (s[1] | ' ') == 'x')
4516  {
4517  s += 2;
4518 
4519  // since overflow detection relies on length of the sequence skip leading zeros
4520  while (*s == '0')
4521  s++;
4522 
4523  const char_t* start = s;
4524 
4525  for (;;)
4526  {
4527  if (static_cast<unsigned>(*s - '0') < 10)
4528  result = result * 16 + (*s - '0');
4529  else if (static_cast<unsigned>((*s | ' ') - 'a') < 6)
4530  result = result * 16 + ((*s | ' ') - 'a' + 10);
4531  else
4532  break;
4533 
4534  s++;
4535  }
4536 
4537  size_t digits = static_cast<size_t>(s - start);
4538 
4539  overflow = digits > sizeof(U) * 2;
4540  }
4541  else
4542  {
4543  // since overflow detection relies on length of the sequence skip leading zeros
4544  while (*s == '0')
4545  s++;
4546 
4547  const char_t* start = s;
4548 
4549  for (;;)
4550  {
4551  if (static_cast<unsigned>(*s - '0') < 10)
4552  result = result * 10 + (*s - '0');
4553  else
4554  break;
4555 
4556  s++;
4557  }
4558 
4559  size_t digits = static_cast<size_t>(s - start);
4560 
4561  PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);
4562 
4563  const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
4564  const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6';
4565  const size_t high_bit = sizeof(U) * 8 - 1;
4566 
4567  overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit)));
4568  }
4569 
4570  if (negative)
4571  {
4572  // Workaround for crayc++ CC-3059: Expected no overflow in routine.
4573  #ifdef _CRAYC
4574  return (overflow || result > ~minv + 1) ? minv : ~result + 1;
4575  #else
4576  return (overflow || result > 0 - minv) ? minv : 0 - result;
4577  #endif
4578  }
4579  else
4580  return (overflow || result > maxv) ? maxv : result;
4581  }
4582 
4583  PUGI__FN int get_value_int(const char_t* value)
4584  {
4585  return string_to_integer<unsigned int>(value, static_cast<unsigned int>(INT_MIN), INT_MAX);
4586  }
4587 
4588  PUGI__FN unsigned int get_value_uint(const char_t* value)
4589  {
4590  return string_to_integer<unsigned int>(value, 0, UINT_MAX);
4591  }
4592 
4593  PUGI__FN double get_value_double(const char_t* value)
4594  {
4595  #ifdef PUGIXML_WCHAR_MODE
4596  return wcstod(value, 0);
4597  #else
4598  return strtod(value, 0);
4599  #endif
4600  }
4601 
4602  PUGI__FN float get_value_float(const char_t* value)
4603  {
4604  #ifdef PUGIXML_WCHAR_MODE
4605  return static_cast<float>(wcstod(value, 0));
4606  #else
4607  return static_cast<float>(strtod(value, 0));
4608  #endif
4609  }
4610 
4611  PUGI__FN bool get_value_bool(const char_t* value)
4612  {
4613  // only look at first char
4614  char_t first = *value;
4615 
4616  // 1*, t* (true), T* (True), y* (yes), Y* (YES)
4617  return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
4618  }
4619 
4620 #ifdef PUGIXML_HAS_LONG_LONG
4621  PUGI__FN long long get_value_llong(const char_t* value)
4622  {
4623  return string_to_integer<unsigned long long>(value, static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);
4624  }
4625 
4626  PUGI__FN unsigned long long get_value_ullong(const char_t* value)
4627  {
4628  return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);
4629  }
4630 #endif
4631 
4632  template <typename U> PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative)
4633  {
4634  char_t* result = end - 1;
4635  U rest = negative ? 0 - value : value;
4636 
4637  do
4638  {
4639  *result-- = static_cast<char_t>('0' + (rest % 10));
4640  rest /= 10;
4641  }
4642  while (rest);
4643 
4644  assert(result >= begin);
4645  (void)begin;
4646 
4647  *result = '-';
4648 
4649  return result + !negative;
4650  }
4651 
4652  // set value with conversion functions
4653  template <typename String, typename Header>
4654  PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf)
4655  {
4656  #ifdef PUGIXML_WCHAR_MODE
4657  char_t wbuf[128];
4658  assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0]));
4659 
4660  size_t offset = 0;
4661  for (; buf[offset]; ++offset) wbuf[offset] = buf[offset];
4662 
4663  return strcpy_insitu(dest, header, header_mask, wbuf, offset);
4664  #else
4665  return strcpy_insitu(dest, header, header_mask, buf, strlen(buf));
4666  #endif
4667  }
4668 
4669  template <typename U, typename String, typename Header>
4670  PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative)
4671  {
4672  char_t buf[64];
4673  char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
4674  char_t* begin = integer_to_string(buf, end, value, negative);
4675 
4676  return strcpy_insitu(dest, header, header_mask, begin, end - begin);
4677  }
4678 
4679  template <typename String, typename Header>
4680  PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision)
4681  {
4682  char buf[128];
4683  PUGI__SNPRINTF(buf, "%.*g", precision, double(value));
4684 
4685  return set_value_ascii(dest, header, header_mask, buf);
4686  }
4687 
4688  template <typename String, typename Header>
4689  PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision)
4690  {
4691  char buf[128];
4692  PUGI__SNPRINTF(buf, "%.*g", precision, value);
4693 
4694  return set_value_ascii(dest, header, header_mask, buf);
4695  }
4696 
4697  template <typename String, typename Header>
4698  PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value)
4699  {
4700  return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5);
4701  }
4702 
4703  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)
4704  {
4705  // check input buffer
4706  if (!contents && size) return make_parse_result(status_io_error);
4707 
4708  // get actual encoding
4709  xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
4710 
4711  // get private buffer
4712  char_t* buffer = 0;
4713  size_t length = 0;
4714 
4715  // coverity[var_deref_model]
4716  if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
4717 
4718  // delete original buffer if we performed a conversion
4719  if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
4720 
4721  // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
4722  if (own || buffer != contents) *out_buffer = buffer;
4723 
4724  // store buffer for offset_debug
4725  doc->buffer = buffer;
4726 
4727  // parse
4728  xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
4729 
4730  // remember encoding
4731  res.encoding = buffer_encoding;
4732 
4733  return res;
4734  }
4735 
4736  // 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
4737  PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
4738  {
4739  #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
4740  // there are 64-bit versions of fseek/ftell, let's use them
4741  typedef __int64 length_type;
4742 
4743  _fseeki64(file, 0, SEEK_END);
4744  length_type length = _ftelli64(file);
4745  _fseeki64(file, 0, SEEK_SET);
4746  #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))
4747  // there are 64-bit versions of fseek/ftell, let's use them
4748  typedef off64_t length_type;
4749 
4750  fseeko64(file, 0, SEEK_END);
4751  length_type length = ftello64(file);
4752  fseeko64(file, 0, SEEK_SET);
4753  #else
4754  // 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.
4755  typedef long length_type;
4756 
4757  fseek(file, 0, SEEK_END);
4758  length_type length = ftell(file);
4759  fseek(file, 0, SEEK_SET);
4760  #endif
4761 
4762  // check for I/O errors
4763  if (length < 0) return status_io_error;
4764 
4765  // check for overflow
4766  size_t result = static_cast<size_t>(length);
4767 
4768  if (static_cast<length_type>(result) != length) return status_out_of_memory;
4769 
4770  // finalize
4771  out_result = result;
4772 
4773  return status_ok;
4774  }
4775 
4776  // This function assumes that buffer has extra sizeof(char_t) writable bytes after size
4777  PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding)
4778  {
4779  // We only need to zero-terminate if encoding conversion does not do it for us
4780  #ifdef PUGIXML_WCHAR_MODE
4781  xml_encoding wchar_encoding = get_wchar_encoding();
4782 
4783  if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding))
4784  {
4785  size_t length = size / sizeof(char_t);
4786 
4787  static_cast<char_t*>(buffer)[length] = 0;
4788  return (length + 1) * sizeof(char_t);
4789  }
4790  #else
4791  if (encoding == encoding_utf8)
4792  {
4793  static_cast<char*>(buffer)[size] = 0;
4794  return size + 1;
4795  }
4796  #endif
4797 
4798  return size;
4799  }
4800 
4801  PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer)
4802  {
4803  if (!file) return make_parse_result(status_file_not_found);
4804 
4805  // get file size (can result in I/O errors)
4806  size_t size = 0;
4807  xml_parse_status size_status = get_file_size(file, size);
4808  if (size_status != status_ok) return make_parse_result(size_status);
4809 
4810  size_t max_suffix_size = sizeof(char_t);
4811 
4812  // allocate buffer for the whole file
4813  char* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size));
4814  if (!contents) return make_parse_result(status_out_of_memory);
4815 
4816  // read file in memory
4817  size_t read_size = fread(contents, 1, size, file);
4818 
4819  if (read_size != size)
4820  {
4821  xml_memory::deallocate(contents);
4823  }
4824 
4825  xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
4826 
4827  return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer);
4828  }
4829 
4830  PUGI__FN void close_file(FILE* file)
4831  {
4832  fclose(file);
4833  }
4834 
4835 #ifndef PUGIXML_NO_STL
4836  template <typename T> struct xml_stream_chunk
4837  {
4839  {
4840  void* memory = xml_memory::allocate(sizeof(xml_stream_chunk));
4841  if (!memory) return 0;
4842 
4843  return new (memory) xml_stream_chunk();
4844  }
4845 
4846  static void destroy(xml_stream_chunk* chunk)
4847  {
4848  // free chunk chain
4849  while (chunk)
4850  {
4851  xml_stream_chunk* next_ = chunk->next;
4852 
4853  xml_memory::deallocate(chunk);
4854 
4855  chunk = next_;
4856  }
4857  }
4858 
4859  xml_stream_chunk(): next(0), size(0)
4860  {
4861  }
4862 
4864  size_t size;
4865 
4866  T data[xml_memory_page_size / sizeof(T)];
4867  };
4868 
4869  template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
4870  {
4872 
4873  // read file to a chunk list
4874  size_t total = 0;
4876 
4877  while (!stream.eof())
4878  {
4879  // allocate new chunk
4881  if (!chunk) return status_out_of_memory;
4882 
4883  // append chunk to list
4884  if (last) last = last->next = chunk;
4885  else chunks.data = last = chunk;
4886 
4887  // read data to chunk
4888  stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));
4889  chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);
4890 
4891  // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors
4892  if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
4893 
4894  // guard against huge files (chunk size is small enough to make this overflow check work)
4895  if (total + chunk->size < total) return status_out_of_memory;
4896  total += chunk->size;
4897  }
4898 
4899  size_t max_suffix_size = sizeof(char_t);
4900 
4901  // copy chunk list to a contiguous buffer
4902  char* buffer = static_cast<char*>(xml_memory::allocate(total + max_suffix_size));
4903  if (!buffer) return status_out_of_memory;
4904 
4905  char* write = buffer;
4906 
4907  for (xml_stream_chunk<T>* chunk = chunks.data; chunk; chunk = chunk->next)
4908  {
4909  assert(write + chunk->size <= buffer + total);
4910  memcpy(write, chunk->data, chunk->size);
4911  write += chunk->size;
4912  }
4913 
4914  assert(write == buffer + total);
4915 
4916  // return buffer
4917  *out_buffer = buffer;
4918  *out_size = total;
4919 
4920  return status_ok;
4921  }
4922 
4923  template <typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
4924  {
4925  // get length of remaining data in stream
4926  typename std::basic_istream<T>::pos_type pos = stream.tellg();
4927  stream.seekg(0, std::ios::end);
4928  std::streamoff length = stream.tellg() - pos;
4929  stream.seekg(pos);
4930 
4931  if (stream.fail() || pos < 0) return status_io_error;
4932 
4933  // guard against huge files
4934  size_t read_length = static_cast<size_t>(length);
4935 
4936  if (static_cast<std::streamsize>(read_length) != length || length < 0) return status_out_of_memory;
4937 
4938  size_t max_suffix_size = sizeof(char_t);
4939 
4940  // read stream data into memory (guard against stream exceptions with buffer holder)
4941  auto_deleter<void> buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);
4942  if (!buffer.data) return status_out_of_memory;
4943 
4944  stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
4945 
4946  // 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
4947  if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
4948 
4949  // return buffer
4950  size_t actual_length = static_cast<size_t>(stream.gcount());
4951  assert(actual_length <= read_length);
4952 
4953  *out_buffer = buffer.release();
4954  *out_size = actual_length * sizeof(T);
4955 
4956  return status_ok;
4957  }
4958 
4959  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)
4960  {
4961  void* buffer = 0;
4962  size_t size = 0;
4963  xml_parse_status status = status_ok;
4964 
4965  // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits)
4966  if (stream.fail()) return make_parse_result(status_io_error);
4967 
4968  // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)
4969  if (stream.tellg() < 0)
4970  {
4971  stream.clear(); // clear error flags that could be set by a failing tellg
4972  status = load_stream_data_noseek(stream, &buffer, &size);
4973  }
4974  else
4975  status = load_stream_data_seek(stream, &buffer, &size);
4976 
4977  if (status != status_ok) return make_parse_result(status);
4978 
4979  xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
4980 
4981  return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer);
4982  }
4983 #endif
4984 
4985 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))
4986  PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
4987  {
4988 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
4989  FILE* file = 0;
4990  return _wfopen_s(&file, path, mode) == 0 ? file : 0;
4991 #else
4992  return _wfopen(path, mode);
4993 #endif
4994  }
4995 #else
4996  PUGI__FN char* convert_path_heap(const wchar_t* str)
4997  {
4998  assert(str);
4999 
5000  // first pass: get length in utf8 characters
5001  size_t length = strlength_wide(str);
5002  size_t size = as_utf8_begin(str, length);
5003 
5004  // allocate resulting string
5005  char* result = static_cast<char*>(xml_memory::allocate(size + 1));
5006  if (!result) return 0;
5007 
5008  // second pass: convert to utf8
5009  as_utf8_end(result, size, str, length);
5010 
5011  // zero-terminate
5012  result[size] = 0;
5013 
5014  return result;
5015  }
5016 
5017  PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
5018  {
5019  // there is no standard function to open wide paths, so our best bet is to try utf8 path
5020  char* path_utf8 = convert_path_heap(path);
5021  if (!path_utf8) return 0;
5022 
5023  // convert mode to ASCII (we mirror _wfopen interface)
5024  char mode_ascii[4] = {0};
5025  for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);
5026 
5027  // try to open the utf8 path
5028  FILE* result = fopen(path_utf8, mode_ascii);
5029 
5030  // free dummy buffer
5031  xml_memory::deallocate(path_utf8);
5032 
5033  return result;
5034  }
5035 #endif
5036 
5037  PUGI__FN FILE* open_file(const char* path, const char* mode)
5038  {
5039 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
5040  FILE* file = 0;
5041  return fopen_s(&file, path, mode) == 0 ? file : 0;
5042 #else
5043  return fopen(path, mode);
5044 #endif
5045  }
5046 
5047  PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)
5048  {
5049  if (!file) return false;
5050 
5051  xml_writer_file writer(file);
5052  doc.save(writer, indent, flags, encoding);
5053 
5054  return ferror(file) == 0;
5055  }
5056 
5058  {
5059  xml_node_struct* node;
5060  char_t* name;
5061 
5062  name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name)
5063  {
5064  node->name = 0;
5065  }
5066 
5068  {
5069  node->name = name;
5070  }
5071  };
5073 
5074 OIIO_NAMESPACE_BEGIN namespace pugi
5075 {
5076  PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_)
5077  {
5078  }
5079 
5080  PUGI__FN void xml_writer_file::write(const void* data, size_t size)
5081  {
5082  size_t result = fwrite(data, 1, size, static_cast<FILE*>(file));
5083  (void)!result; // unfortunately we can't do proper error handling here
5084  }
5085 
5086 #ifndef PUGIXML_NO_STL
5087  PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
5088  {
5089  }
5090 
5091  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)
5092  {
5093  }
5094 
5095  PUGI__FN void xml_writer_stream::write(const void* data, size_t size)
5096  {
5097  if (narrow_stream)
5098  {
5099  assert(!wide_stream);
5100  narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
5101  }
5102  else
5103  {
5104  assert(wide_stream);
5105  assert(size % sizeof(wchar_t) == 0);
5106 
5107  wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size / sizeof(wchar_t)));
5108  }
5109  }
5110 #endif
5111 
5113  {
5114  }
5115 
5117  {
5118  }
5119 
5121  {
5122  return _depth;
5123  }
5124 
5126  {
5127  return true;
5128  }
5129 
5131  {
5132  return true;
5133  }
5134 
5136  {
5137  }
5138 
5140  {
5141  }
5142 
5143  PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***)
5144  {
5145  }
5146 
5147  PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
5148  {
5149  return _attr ? unspecified_bool_xml_attribute : 0;
5150  }
5151 
5153  {
5154  return !_attr;
5155  }
5156 
5158  {
5159  return (_attr == r._attr);
5160  }
5161 
5163  {
5164  return (_attr != r._attr);
5165  }
5166 
5168  {
5169  return (_attr < r._attr);
5170  }
5171 
5173  {
5174  return (_attr > r._attr);
5175  }
5176 
5178  {
5179  return (_attr <= r._attr);
5180  }
5181 
5183  {
5184  return (_attr >= r._attr);
5185  }
5186 
5188  {
5189  return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
5190  }
5191 
5193  {
5194  return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
5195  }
5196 
5197  PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const
5198  {
5199  return (_attr && _attr->value) ? _attr->value + 0 : def;
5200  }
5201 
5202  PUGI__FN int xml_attribute::as_int(int def) const
5203  {
5204  return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def;
5205  }
5206 
5207  PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
5208  {
5209  return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def;
5210  }
5211 
5212  PUGI__FN double xml_attribute::as_double(double def) const
5213  {
5214  return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def;
5215  }
5216 
5217  PUGI__FN float xml_attribute::as_float(float def) const
5218  {
5219  return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def;
5220  }
5221 
5222  PUGI__FN bool xml_attribute::as_bool(bool def) const
5223  {
5224  return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def;
5225  }
5226 
5227 #ifdef PUGIXML_HAS_LONG_LONG
5228  PUGI__FN long long xml_attribute::as_llong(long long def) const
5229  {
5230  return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def;
5231  }
5232 
5233  PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
5234  {
5235  return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def;
5236  }
5237 #endif
5238 
5240  {
5241  return !_attr;
5242  }
5243 
5244  PUGI__FN const char_t* xml_attribute::name() const
5245  {
5246  return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT("");
5247  }
5248 
5249  PUGI__FN const char_t* xml_attribute::value() const
5250  {
5251  return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT("");
5252  }
5253 
5255  {
5256  return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
5257  }
5258 
5260  {
5261  return _attr;
5262  }
5263 
5265  {
5266  set_value(rhs);
5267  return *this;
5268  }
5269 
5271  {
5272  set_value(rhs);
5273  return *this;
5274  }
5275 
5277  {
5278  set_value(rhs);
5279  return *this;
5280  }
5281 
5283  {
5284  set_value(rhs);
5285  return *this;
5286  }
5287 
5289  {
5290  set_value(rhs);
5291  return *this;
5292  }
5293 
5295  {
5296  set_value(rhs);
5297  return *this;
5298  }
5299 
5301  {
5302  set_value(rhs);
5303  return *this;
5304  }
5305 
5307  {
5308  set_value(rhs);
5309  return *this;
5310  }
5311 
5312 #ifdef PUGIXML_HAS_LONG_LONG
5314  {
5315  set_value(rhs);
5316  return *this;
5317  }
5318 
5319  PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs)
5320  {
5321  set_value(rhs);
5322  return *this;
5323  }
5324 #endif
5325 
5326  PUGI__FN bool xml_attribute::set_name(const char_t* rhs)
5327  {
5328  if (!_attr) return false;
5329 
5330  return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
5331  }
5332 
5333  PUGI__FN bool xml_attribute::set_value(const char_t* rhs)
5334  {
5335  if (!_attr) return false;
5336 
5337  return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
5338  }
5339 
5341  {
5342  if (!_attr) return false;
5343 
5344  return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5345  }
5346 
5347  PUGI__FN bool xml_attribute::set_value(unsigned int rhs)
5348  {
5349  if (!_attr) return false;
5350 
5351  return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
5352  }
5353 
5355  {
5356  if (!_attr) return false;
5357 
5358  return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5359  }
5360 
5361  PUGI__FN bool xml_attribute::set_value(unsigned long rhs)
5362  {
5363  if (!_attr) return false;
5364 
5365  return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
5366  }
5367 
5369  {
5370  if (!_attr) return false;
5371 
5372  return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision);
5373  }
5374 
5376  {
5377  if (!_attr) return false;
5378 
5379  return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision);
5380  }
5381 
5383  {
5384  if (!_attr) return false;
5385 
5386  return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision);
5387  }
5388 
5390  {
5391  if (!_attr) return false;
5392 
5393  return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision);
5394  }
5395 
5397  {
5398  if (!_attr) return false;
5399 
5400  return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
5401  }
5402 
5403 #ifdef PUGIXML_HAS_LONG_LONG
5404  PUGI__FN bool xml_attribute::set_value(long long rhs)
5405  {
5406  if (!_attr) return false;
5407 
5408  return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5409  }
5410 
5411  PUGI__FN bool xml_attribute::set_value(unsigned long long rhs)
5412  {
5413  if (!_attr) return false;
5414 
5415  return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
5416  }
5417 #endif
5418 
5419 #ifdef __BORLANDC__
5420  PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs)
5421  {
5422  return (bool)lhs && rhs;
5423  }
5424 
5425  PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs)
5426  {
5427  return (bool)lhs || rhs;
5428  }
5429 #endif
5430 
5432  {
5433  }
5434 
5436  {
5437  }
5438 
5439  PUGI__FN static void unspecified_bool_xml_node(xml_node***)
5440  {
5441  }
5442 
5443  PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const
5444  {
5445  return _root ? unspecified_bool_xml_node : 0;
5446  }
5447 
5449  {
5450  return !_root;
5451  }
5452 
5454  {
5455  return iterator(_root ? _root->first_child + 0 : 0, _root);
5456  }
5457 
5459  {
5460  return iterator(0, _root);
5461  }
5462 
5464  {
5465  return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root);
5466  }
5467 
5469  {
5470  return attribute_iterator(0, _root);
5471  }
5472 
5474  {
5476  }
5477 
5479  {
5481  }
5482 
5484  {
5486  }
5487 
5489  {
5490  return (_root == r._root);
5491  }
5492 
5494  {
5495  return (_root != r._root);
5496  }
5497 
5499  {
5500  return (_root < r._root);
5501  }
5502 
5504  {
5505  return (_root > r._root);
5506  }
5507 
5509  {
5510  return (_root <= r._root);
5511  }
5512 
5514  {
5515  return (_root >= r._root);
5516  }
5517 
5519  {
5520  return !_root;
5521  }
5522 
5523  PUGI__FN const char_t* xml_node::name() const
5524  {
5525  return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT("");
5526  }
5527 
5529  {
5530  return _root ? PUGI__NODETYPE(_root) : node_null;
5531  }
5532 
5533  PUGI__FN const char_t* xml_node::value() const
5534  {
5535  return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT("");
5536  }
5537 
5538  PUGI__FN xml_node xml_node::child(const char_t* name_) const
5539  {
5540  if (!_root) return xml_node();
5541 
5542  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5543  if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
5544 
5545  return xml_node();
5546  }
5547 
5548  PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const
5549  {
5550  if (!_root) return xml_attribute();
5551 
5553  if (i->name && impl::strequal(name_, i->name))
5554  return xml_attribute(i);
5555 
5556  return xml_attribute();
5557  }
5558 
5559  PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const
5560  {
5561  if (!_root) return xml_node();
5562 
5563  for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
5564  if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
5565 
5566  return xml_node();
5567  }
5568 
5570  {
5571  return _root ? xml_node(_root->next_sibling) : xml_node();
5572  }
5573 
5574  PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const
5575  {
5576  if (!_root) return xml_node();
5577 
5579  if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
5580 
5581  return xml_node();
5582  }
5583 
5584  PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const
5585  {
5586  xml_attribute_struct* hint = hint_._attr;
5587 
5588  // if hint is not an attribute of node, behavior is not defined
5589  assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
5590 
5591  if (!_root) return xml_attribute();
5592 
5593  // optimistically search from hint up until the end
5594  for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
5595  if (i->name && impl::strequal(name_, i->name))
5596  {
5597  // update hint to maximize efficiency of searching for consecutive attributes
5598  hint_._attr = i->next_attribute;
5599 
5600  return xml_attribute(i);
5601  }
5602 
5603  // wrap around and search from the first attribute until the hint
5604  // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails
5605  for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)
5606  if (j->name && impl::strequal(name_, j->name))
5607  {
5608  // update hint to maximize efficiency of searching for consecutive attributes
5609  hint_._attr = j->next_attribute;
5610 
5611  return xml_attribute(j);
5612  }
5613 
5614  return xml_attribute();
5615  }
5616 
5618  {
5619  if (!_root) return xml_node();
5620 
5622  else return xml_node();
5623  }
5624 
5626  {
5627  return _root ? xml_node(_root->parent) : xml_node();
5628  }
5629 
5631  {
5633  }
5634 
5636  {
5637  return xml_text(_root);
5638  }
5639 
5640  PUGI__FN const char_t* xml_node::child_value() const
5641  {
5642  if (!_root) return PUGIXML_TEXT("");
5643 
5644  // element nodes can have value if parse_embed_pcdata was used
5646  return _root->value;
5647 
5648  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5649  if (impl::is_text_node(i) && i->value)
5650  return i->value;
5651 
5652  return PUGIXML_TEXT("");
5653  }
5654 
5655  PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const
5656  {
5657  return child(name_).child_value();
5658  }
5659 
5661  {
5662  return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
5663  }
5664 
5666  {
5668  }
5669 
5671  {
5672  return _root ? xml_node(_root->first_child) : xml_node();
5673  }
5674 
5676  {
5678  }
5679 
5680  PUGI__FN bool xml_node::set_name(const char_t* rhs)
5681  {
5683 
5684  if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
5685  return false;
5686 
5687  return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
5688  }
5689 
5690  PUGI__FN bool xml_node::set_value(const char_t* rhs)
5691  {
5693 
5694  if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
5695  return false;
5696 
5697  return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
5698  }
5699 
5701  {
5703 
5704  impl::xml_allocator& alloc = impl::get_allocator(_root);
5705  if (!alloc.reserve()) return xml_attribute();
5706 
5708  if (!a) return xml_attribute();
5709 
5710  impl::append_attribute(a._attr, _root);
5711 
5712  a.set_name(name_);
5713 
5714  return a;
5715  }
5716 
5718  {
5720 
5721  impl::xml_allocator& alloc = impl::get_allocator(_root);
5722  if (!alloc.reserve()) return xml_attribute();
5723 
5725  if (!a) return xml_attribute();
5726 
5727  impl::prepend_attribute(a._attr, _root);
5728 
5729  a.set_name(name_);
5730 
5731  return a;
5732  }
5733 
5735  {
5737  if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
5738 
5739  impl::xml_allocator& alloc = impl::get_allocator(_root);
5740  if (!alloc.reserve()) return xml_attribute();
5741 
5743  if (!a) return xml_attribute();
5744 
5745  impl::insert_attribute_after(a._attr, attr._attr, _root);
5746 
5747  a.set_name(name_);
5748 
5749  return a;
5750  }
5751 
5753  {
5755  if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
5756 
5757  impl::xml_allocator& alloc = impl::get_allocator(_root);
5758  if (!alloc.reserve()) return xml_attribute();
5759 
5761  if (!a) return xml_attribute();
5762 
5763  impl::insert_attribute_before(a._attr, attr._attr, _root);
5764 
5765  a.set_name(name_);
5766 
5767  return a;
5768  }
5769 
5771  {
5772  if (!proto) return xml_attribute();
5774 
5775  impl::xml_allocator& alloc = impl::get_allocator(_root);
5776  if (!alloc.reserve()) return xml_attribute();
5777 
5779  if (!a) return xml_attribute();
5780 
5781  impl::append_attribute(a._attr, _root);
5782  impl::node_copy_attribute(a._attr, proto._attr);
5783 
5784  return a;
5785  }
5786 
5788  {
5789  if (!proto) return xml_attribute();
5791 
5792  impl::xml_allocator& alloc = impl::get_allocator(_root);
5793  if (!alloc.reserve()) return xml_attribute();
5794 
5796  if (!a) return xml_attribute();
5797 
5798  impl::prepend_attribute(a._attr, _root);
5799  impl::node_copy_attribute(a._attr, proto._attr);
5800 
5801  return a;
5802  }
5803 
5805  {
5806  if (!proto) return xml_attribute();
5808  if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
5809 
5810  impl::xml_allocator& alloc = impl::get_allocator(_root);
5811  if (!alloc.reserve()) return xml_attribute();
5812 
5814  if (!a) return xml_attribute();
5815 
5816  impl::insert_attribute_after(a._attr, attr._attr, _root);
5817  impl::node_copy_attribute(a._attr, proto._attr);
5818 
5819  return a;
5820  }
5821 
5823  {
5824  if (!proto) return xml_attribute();
5826  if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
5827 
5828  impl::xml_allocator& alloc = impl::get_allocator(_root);
5829  if (!alloc.reserve()) return xml_attribute();
5830 
5832  if (!a) return xml_attribute();
5833 
5834  impl::insert_attribute_before(a._attr, attr._attr, _root);
5835  impl::node_copy_attribute(a._attr, proto._attr);
5836 
5837  return a;
5838  }
5839 
5841  {
5842  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5843 
5844  impl::xml_allocator& alloc = impl::get_allocator(_root);
5845  if (!alloc.reserve()) return xml_node();
5846 
5847  xml_node n(impl::allocate_node(alloc, type_));
5848  if (!n) return xml_node();
5849 
5851 
5852  if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
5853 
5854  return n;
5855  }
5856 
5858  {
5859  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5860 
5861  impl::xml_allocator& alloc = impl::get_allocator(_root);
5862  if (!alloc.reserve()) return xml_node();
5863 
5864  xml_node n(impl::allocate_node(alloc, type_));
5865  if (!n) return xml_node();
5866 
5868 
5869  if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
5870 
5871  return n;
5872  }
5873 
5875  {
5876  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5877  if (!node._root || node._root->parent != _root) return xml_node();
5878 
5879  impl::xml_allocator& alloc = impl::get_allocator(_root);
5880  if (!alloc.reserve()) return xml_node();
5881 
5882  xml_node n(impl::allocate_node(alloc, type_));
5883  if (!n) return xml_node();
5884 
5886 
5887  if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
5888 
5889  return n;
5890  }
5891 
5893  {
5894  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5895  if (!node._root || node._root->parent != _root) return xml_node();
5896 
5897  impl::xml_allocator& alloc = impl::get_allocator(_root);
5898  if (!alloc.reserve()) return xml_node();
5899 
5900  xml_node n(impl::allocate_node(alloc, type_));
5901  if (!n) return xml_node();
5902 
5904 
5905  if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
5906 
5907  return n;
5908  }
5909 
5911  {
5913 
5914  result.set_name(name_);
5915 
5916  return result;
5917  }
5918 
5920  {
5922 
5923  result.set_name(name_);
5924 
5925  return result;
5926  }
5927 
5928  PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node)
5929  {
5930  xml_node result = insert_child_after(node_element, node);
5931 
5932  result.set_name(name_);
5933 
5934  return result;
5935  }
5936 
5937  PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node)
5938  {
5939  xml_node result = insert_child_before(node_element, node);
5940 
5941  result.set_name(name_);
5942 
5943  return result;
5944  }
5945 
5947  {
5948  xml_node_type type_ = proto.type();
5949  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5950 
5951  impl::xml_allocator& alloc = impl::get_allocator(_root);
5952  if (!alloc.reserve()) return xml_node();
5953 
5954  xml_node n(impl::allocate_node(alloc, type_));
5955  if (!n) return xml_node();
5956 
5958  impl::node_copy_tree(n._root, proto._root);
5959 
5960  return n;
5961  }
5962 
5964  {
5965  xml_node_type type_ = proto.type();
5966  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5967 
5968  impl::xml_allocator& alloc = impl::get_allocator(_root);
5969  if (!alloc.reserve()) return xml_node();
5970 
5971  xml_node n(impl::allocate_node(alloc, type_));
5972  if (!n) return xml_node();
5973 
5975  impl::node_copy_tree(n._root, proto._root);
5976 
5977  return n;
5978  }
5979 
5981  {
5982  xml_node_type type_ = proto.type();
5983  if (!impl::allow_insert_child(type(), type_)) return xml_node();
5984  if (!node._root || node._root->parent != _root) return xml_node();
5985 
5986  impl::xml_allocator& alloc = impl::get_allocator(_root);
5987  if (!alloc.reserve()) return xml_node();
5988 
5989  xml_node n(impl::allocate_node(alloc, type_));
5990  if (!n) return xml_node();
5991 
5993  impl::node_copy_tree(n._root, proto._root);
5994 
5995  return n;
5996  }
5997 
5999  {
6000  xml_node_type type_ = proto.type();
6001  if (!impl::allow_insert_child(type(), type_)) return xml_node();
6002  if (!node._root || node._root->parent != _root) return xml_node();
6003 
6004  impl::xml_allocator& alloc = impl::get_allocator(_root);
6005  if (!alloc.reserve()) return xml_node();
6006 
6007  xml_node n(impl::allocate_node(alloc, type_));
6008  if (!n) return xml_node();
6009 
6011  impl::node_copy_tree(n._root, proto._root);
6012 
6013  return n;
6014  }
6015 
6017  {
6018  if (!impl::allow_move(*this, moved)) return xml_node();
6019 
6020  impl::xml_allocator& alloc = impl::get_allocator(_root);
6021  if (!alloc.reserve()) return xml_node();
6022 
6023  // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
6024  impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
6025 
6026  impl::remove_node(moved._root);
6027  impl::append_node(moved._root, _root);
6028 
6029  return moved;
6030  }
6031 
6033  {
6034  if (!impl::allow_move(*this, moved)) return xml_node();
6035 
6036  impl::xml_allocator& alloc = impl::get_allocator(_root);
6037  if (!alloc.reserve()) return xml_node();
6038 
6039  // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
6040  impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
6041 
6042  impl::remove_node(moved._root);
6043  impl::prepend_node(moved._root, _root);
6044 
6045  return moved;
6046  }
6047 
6049  {
6050  if (!impl::allow_move(*this, moved)) return xml_node();
6051  if (!node._root || node._root->parent != _root) return xml_node();
6052  if (moved._root == node._root) return xml_node();
6053 
6054  impl::xml_allocator& alloc = impl::get_allocator(_root);
6055  if (!alloc.reserve()) return xml_node();
6056 
6057  // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
6058  impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
6059 
6060  impl::remove_node(moved._root);
6061  impl::insert_node_after(moved._root, node._root);
6062 
6063  return moved;
6064  }
6065 
6067  {
6068  if (!impl::allow_move(*this, moved)) return xml_node();
6069  if (!node._root || node._root->parent != _root) return xml_node();
6070  if (moved._root == node._root) return xml_node();
6071 
6072  impl::xml_allocator& alloc = impl::get_allocator(_root);
6073  if (!alloc.reserve()) return xml_node();
6074 
6075  // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
6076  impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
6077 
6078  impl::remove_node(moved._root);
6079  impl::insert_node_before(moved._root, node._root);
6080 
6081  return moved;
6082  }
6083 
6084  PUGI__FN bool xml_node::remove_attribute(const char_t* name_)
6085  {
6086  return remove_attribute(attribute(name_));
6087  }
6088 
6090  {
6091  if (!_root || !a._attr) return false;
6092  if (!impl::is_attribute_of(a._attr, _root)) return false;
6093 
6094  impl::xml_allocator& alloc = impl::get_allocator(_root);
6095  if (!alloc.reserve()) return false;
6096 
6097  impl::remove_attribute(a._attr, _root);
6098  impl::destroy_attribute(a._attr, alloc);
6099 
6100  return true;
6101  }
6102 
6104  {
6105  if (!_root) return false;
6106 
6107  impl::xml_allocator& alloc = impl::get_allocator(_root);
6108  if (!alloc.reserve()) return false;
6109 
6110  for (xml_attribute_struct* attr = _root->first_attribute; attr; )
6111  {
6112  xml_attribute_struct* next = attr->next_attribute;
6113 
6114  impl::destroy_attribute(attr, alloc);
6115 
6116  attr = next;
6117  }
6118 
6119  _root->first_attribute = 0;
6120 
6121  return true;
6122  }
6123 
6124  PUGI__FN bool xml_node::remove_child(const char_t* name_)
6125  {
6126  return remove_child(child(name_));
6127  }
6128 
6130  {
6131  if (!_root || !n._root || n._root->parent != _root) return false;
6132 
6133  impl::xml_allocator& alloc = impl::get_allocator(_root);
6134  if (!alloc.reserve()) return false;
6135 
6137  impl::destroy_node(n._root, alloc);
6138 
6139  return true;
6140  }
6141 
6143  {
6144  if (!_root) return false;
6145 
6146  impl::xml_allocator& alloc = impl::get_allocator(_root);
6147  if (!alloc.reserve()) return false;
6148 
6149  for (xml_node_struct* cur = _root->first_child; cur; )
6150  {
6151  xml_node_struct* next = cur->next_sibling;
6152 
6153  impl::destroy_node(cur, alloc);
6154 
6155  cur = next;
6156  }
6157 
6158  _root->first_child = 0;
6159 
6160  return true;
6161  }
6162 
6163  PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
6164  {
6165  // append_buffer is only valid for elements/documents
6167 
6168  // get document node
6169  impl::xml_document_struct* doc = &impl::get_document(_root);
6170 
6171  // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense
6172  doc->header |= impl::xml_memory_page_contents_shared_mask;
6173 
6174  // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later)
6175  impl::xml_memory_page* page = 0;
6176  impl::xml_extra_buffer* extra = static_cast<impl::xml_extra_buffer*>(doc->allocate_memory(sizeof(impl::xml_extra_buffer) + sizeof(void*), page));
6177  (void)page;
6178 
6179  if (!extra) return impl::make_parse_result(status_out_of_memory);
6180 
6181  #ifdef PUGIXML_COMPACT
6182  // align the memory block to a pointer boundary; this is required for compact mode where memory allocations are only 4b aligned
6183  // note that this requires up to sizeof(void*)-1 additional memory, which the allocation above takes into account
6184  extra = reinterpret_cast<impl::xml_extra_buffer*>((reinterpret_cast<uintptr_t>(extra) + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1));
6185  #endif
6186 
6187  // add extra buffer to the list
6188  extra->buffer = 0;
6189  extra->next = doc->extra_buffers;
6190  doc->extra_buffers = extra;
6191 
6192  // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level
6193  impl::name_null_sentry sentry(_root);
6194 
6195  return impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &extra->buffer);
6196  }
6197 
6198  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
6199  {
6200  if (!_root) return xml_node();
6201 
6202  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
6203  if (i->name && impl::strequal(name_, i->name))
6204  {
6205  for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
6206  if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
6207  return xml_node(i);
6208  }
6209 
6210  return xml_node();
6211  }
6212 
6213  PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
6214  {
6215  if (!_root) return xml_node();
6216 
6217  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
6218  for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
6219  if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
6220  return xml_node(i);
6221 
6222  return xml_node();
6223  }
6224 
6225 #ifndef PUGIXML_NO_STL
6226  PUGI__FN string_t xml_node::path(char_t delimiter) const
6227  {
6228  if (!_root) return string_t();
6229 
6230  size_t offset = 0;
6231 
6232  for (xml_node_struct* i = _root; i; i = i->parent)
6233  {
6234  offset += (i != _root);
6235  offset += i->name ? impl::strlength(i->name) : 0;
6236  }
6237 
6238  string_t result;
6239  result.resize(offset);
6240 
6241  for (xml_node_struct* j = _root; j; j = j->parent)
6242  {
6243  if (j != _root)
6244  result[--offset] = delimiter;
6245 
6246  if (j->name)
6247  {
6248  size_t length = impl::strlength(j->name);
6249 
6250  offset -= length;
6251  memcpy(&result[offset], j->name, length * sizeof(char_t));
6252  }
6253  }
6254 
6255  assert(offset == 0);
6256 
6257  return result;
6258  }
6259 #endif
6260 
6261  PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const
6262  {
6263  xml_node context = path_[0] == delimiter ? root() : *this;
6264 
6265  if (!context._root) return xml_node();
6266 
6267  const char_t* path_segment = path_;
6268 
6269  while (*path_segment == delimiter) ++path_segment;
6270 
6271  const char_t* path_segment_end = path_segment;
6272 
6273  while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;
6274 
6275  if (path_segment == path_segment_end) return context;
6276 
6277  const char_t* next_segment = path_segment_end;
6278 
6279  while (*next_segment == delimiter) ++next_segment;
6280 
6281  if (*path_segment == '.' && path_segment + 1 == path_segment_end)
6282  return context.first_element_by_path(next_segment, delimiter);
6283  else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end)
6284  return context.parent().first_element_by_path(next_segment, delimiter);
6285  else
6286  {
6287  for (xml_node_struct* j = context._root->first_child; j; j = j->next_sibling)
6288  {
6289  if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
6290  {
6291  xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
6292 
6293  if (subsearch) return subsearch;
6294  }
6295  }
6296 
6297  return xml_node();
6298  }
6299  }
6300 
6302  {
6303  walker._depth = -1;
6304 
6305  xml_node arg_begin(_root);
6306  if (!walker.begin(arg_begin)) return false;
6307 
6308  xml_node_struct* cur = _root ? _root->first_child + 0 : 0;
6309 
6310  if (cur)
6311  {
6312  ++walker._depth;
6313 
6314  do
6315  {
6316  xml_node arg_for_each(cur);
6317  if (!walker.for_each(arg_for_each))
6318  return false;
6319 
6320  if (cur->first_child)
6321  {
6322  ++walker._depth;
6323  cur = cur->first_child;
6324  }
6325  else if (cur->next_sibling)
6326  cur = cur->next_sibling;
6327  else
6328  {
6329  while (!cur->next_sibling && cur != _root && cur->parent)
6330  {
6331  --walker._depth;
6332  cur = cur->parent;
6333  }
6334 
6335  if (cur != _root)
6336  cur = cur->next_sibling;
6337  }
6338  }
6339  while (cur && cur != _root);
6340  }
6341 
6342  assert(walker._depth == -1);
6343 
6344  xml_node arg_end(_root);
6345  return walker.end(arg_end);
6346  }
6347 
6349  {
6350  return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
6351  }
6352 
6354  {
6355  return _root;
6356  }
6357 
6358  PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
6359  {
6360  if (!_root) return;
6361 
6362  impl::xml_buffered_writer buffered_writer(writer, encoding);
6363 
6364  impl::node_output(buffered_writer, _root, indent, flags, depth);
6365 
6366  buffered_writer.flush();
6367  }
6368 
6369 #ifndef PUGIXML_NO_STL
6370  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
6371  {
6372  xml_writer_stream writer(stream);
6373 
6374  print(writer, indent, flags, encoding, depth);
6375  }
6376 
6377  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
6378  {
6379  xml_writer_stream writer(stream);
6380 
6381  print(writer, indent, flags, encoding_wchar, depth);
6382  }
6383 #endif
6384 
6386  {
6387  if (!_root) return -1;
6388 
6389  impl::xml_document_struct& doc = impl::get_document(_root);
6390 
6391  // we can determine the offset reliably only if there is exactly once parse buffer
6392  if (!doc.buffer || doc.extra_buffers) return -1;
6393 
6394  switch (type())
6395  {
6396  case node_document:
6397  return 0;
6398 
6399  case node_element:
6400  case node_declaration:
6401  case node_pi:
6402  return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1;
6403 
6404  case node_pcdata:
6405  case node_cdata:
6406  case node_comment:
6407  case node_doctype:
6408  return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1;
6409 
6410  default:
6411  assert(false && "Invalid node type"); // unreachable
6412  return -1;
6413  }
6414  }
6415 
6416 #ifdef __BORLANDC__
6417  PUGI__FN bool operator&&(const xml_node& lhs, bool rhs)
6418  {
6419  return (bool)lhs && rhs;
6420  }
6421 
6422  PUGI__FN bool operator||(const xml_node& lhs, bool rhs)
6423  {
6424  return (bool)lhs || rhs;
6425  }
6426 #endif
6427 
6428  PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root)
6429  {
6430  }
6431 
6432  PUGI__FN xml_node_struct* xml_text::_data() const
6433  {
6434  if (!_root || impl::is_text_node(_root)) return _root;
6435 
6436  // element nodes can have value if parse_embed_pcdata was used
6437  if (PUGI__NODETYPE(_root) == node_element && _root->value)
6438  return _root;
6439 
6440  for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
6441  if (impl::is_text_node(node))
6442  return node;
6443 
6444  return 0;
6445  }
6446 
6447  PUGI__FN xml_node_struct* xml_text::_data_new()
6448  {
6449  xml_node_struct* d = _data();
6450  if (d) return d;
6451 
6452  return xml_node(_root).append_child(node_pcdata).internal_object();
6453  }
6454 
6456  {
6457  }
6458 
6459  PUGI__FN static void unspecified_bool_xml_text(xml_text***)
6460  {
6461  }
6462 
6463  PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const
6464  {
6465  return _data() ? unspecified_bool_xml_text : 0;
6466  }
6467 
6469  {
6470  return !_data();
6471  }
6472 
6474  {
6475  return _data() == 0;
6476  }
6477 
6478  PUGI__FN const char_t* xml_text::get() const
6479  {
6480  xml_node_struct* d = _data();
6481 
6482  return (d && d->value) ? d->value + 0 : PUGIXML_TEXT("");
6483  }
6484 
6485  PUGI__FN const char_t* xml_text::as_string(const char_t* def) const
6486  {
6487  xml_node_struct* d = _data();
6488 
6489  return (d && d->value) ? d->value + 0 : def;
6490  }
6491 
6492  PUGI__FN int xml_text::as_int(int def) const
6493  {
6494  xml_node_struct* d = _data();
6495 
6496  return (d && d->value) ? impl::get_value_int(d->value) : def;
6497  }
6498 
6499  PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
6500  {
6501  xml_node_struct* d = _data();
6502 
6503  return (d && d->value) ? impl::get_value_uint(d->value) : def;
6504  }
6505 
6506  PUGI__FN double xml_text::as_double(double def) const
6507  {
6508  xml_node_struct* d = _data();
6509 
6510  return (d && d->value) ? impl::get_value_double(d->value) : def;
6511  }
6512 
6513  PUGI__FN float xml_text::as_float(float def) const
6514  {
6515  xml_node_struct* d = _data();
6516 
6517  return (d && d->value) ? impl::get_value_float(d->value) : def;
6518  }
6519 
6520  PUGI__FN bool xml_text::as_bool(bool def) const
6521  {
6522  xml_node_struct* d = _data();
6523 
6524  return (d && d->value) ? impl::get_value_bool(d->value) : def;
6525  }
6526 
6527 #ifdef PUGIXML_HAS_LONG_LONG
6528  PUGI__FN long long xml_text::as_llong(long long def) const
6529  {
6530  xml_node_struct* d = _data();
6531 
6532  return (d && d->value) ? impl::get_value_llong(d->value) : def;
6533  }
6534 
6535  PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const
6536  {
6537  xml_node_struct* d = _data();
6538 
6539  return (d && d->value) ? impl::get_value_ullong(d->value) : def;
6540  }
6541 #endif
6542 
6543  PUGI__FN bool xml_text::set(const char_t* rhs)
6544  {
6545  xml_node_struct* dn = _data_new();
6546 
6547  return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false;
6548  }
6549 
6550  PUGI__FN bool xml_text::set(int rhs)
6551  {
6552  xml_node_struct* dn = _data_new();
6553 
6554  return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6555  }
6556 
6557  PUGI__FN bool xml_text::set(unsigned int rhs)
6558  {
6559  xml_node_struct* dn = _data_new();
6560 
6561  return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
6562  }
6563 
6564  PUGI__FN bool xml_text::set(long rhs)
6565  {
6566  xml_node_struct* dn = _data_new();
6567 
6568  return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6569  }
6570 
6571  PUGI__FN bool xml_text::set(unsigned long rhs)
6572  {
6573  xml_node_struct* dn = _data_new();
6574 
6575  return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
6576  }
6577 
6578  PUGI__FN bool xml_text::set(float rhs)
6579  {
6580  xml_node_struct* dn = _data_new();
6581 
6582  return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false;
6583  }
6584 
6585  PUGI__FN bool xml_text::set(float rhs, int precision)
6586  {
6587  xml_node_struct* dn = _data_new();
6588 
6589  return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false;
6590  }
6591 
6592  PUGI__FN bool xml_text::set(double rhs)
6593  {
6594  xml_node_struct* dn = _data_new();
6595 
6596  return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false;
6597  }
6598 
6599  PUGI__FN bool xml_text::set(double rhs, int precision)
6600  {
6601  xml_node_struct* dn = _data_new();
6602 
6603  return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false;
6604  }
6605 
6606  PUGI__FN bool xml_text::set(bool rhs)
6607  {
6608  xml_node_struct* dn = _data_new();
6609 
6610  return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
6611  }
6612 
6613 #ifdef PUGIXML_HAS_LONG_LONG
6614  PUGI__FN bool xml_text::set(long long rhs)
6615  {
6616  xml_node_struct* dn = _data_new();
6617 
6618  return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6619  }
6620 
6621  PUGI__FN bool xml_text::set(unsigned long long rhs)
6622  {
6623  xml_node_struct* dn = _data_new();
6624 
6625  return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
6626  }
6627 #endif
6628 
6630  {
6631  set(rhs);
6632  return *this;
6633  }
6634 
6636  {
6637  set(rhs);
6638  return *this;
6639  }
6640 
6642  {
6643  set(rhs);
6644  return *this;
6645  }
6646 
6648  {
6649  set(rhs);
6650  return *this;
6651  }
6652 
6654  {
6655  set(rhs);
6656  return *this;
6657  }
6658 
6660  {
6661  set(rhs);
6662  return *this;
6663  }
6664 
6666  {
6667  set(rhs);
6668  return *this;
6669  }
6670 
6672  {
6673  set(rhs);
6674  return *this;
6675  }
6676 
6677 #ifdef PUGIXML_HAS_LONG_LONG
6678  PUGI__FN xml_text& xml_text::operator=(long long rhs)
6679  {
6680  set(rhs);
6681  return *this;
6682  }
6683 
6684  PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs)
6685  {
6686  set(rhs);
6687  return *this;
6688  }
6689 #endif
6690 
6692  {
6693  return xml_node(_data());
6694  }
6695 
6696 #ifdef __BORLANDC__
6697  PUGI__FN bool operator&&(const xml_text& lhs, bool rhs)
6698  {
6699  return (bool)lhs && rhs;
6700  }
6701 
6702  PUGI__FN bool operator||(const xml_text& lhs, bool rhs)
6703  {
6704  return (bool)lhs || rhs;
6705  }
6706 #endif
6707 
6709  {
6710  }
6711 
6712  PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
6713  {
6714  }
6715 
6716  PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
6717  {
6718  }
6719 
6721  {
6722  return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
6723  }
6724 
6726  {
6727  return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
6728  }
6729 
6731  {
6732  assert(_wrap._root);
6733  return _wrap;
6734  }
6735 
6737  {
6738  assert(_wrap._root);
6739  return const_cast<xml_node*>(&_wrap); // BCC5 workaround
6740  }
6741 
6743  {
6744  assert(_wrap._root);
6745  _wrap._root = _wrap._root->next_sibling;
6746  return *this;
6747  }
6748 
6750  {
6751  xml_node_iterator temp = *this;
6752  ++*this;
6753  return temp;
6754  }
6755 
6757  {
6758  _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
6759  return *this;
6760  }
6761 
6763  {
6764  xml_node_iterator temp = *this;
6765  --*this;
6766  return temp;
6767  }
6768 
6770  {
6771  }
6772 
6773  PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
6774  {
6775  }
6776 
6778  {
6779  }
6780 
6782  {
6783  return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
6784  }
6785 
6787  {
6788  return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
6789  }
6790 
6792  {
6793  assert(_wrap._attr);
6794  return _wrap;
6795  }
6796 
6798  {
6799  assert(_wrap._attr);
6800  return const_cast<xml_attribute*>(&_wrap); // BCC5 workaround
6801  }
6802 
6804  {
6805  assert(_wrap._attr);
6806  _wrap._attr = _wrap._attr->next_attribute;
6807  return *this;
6808  }
6809 
6811  {
6812  xml_attribute_iterator temp = *this;
6813  ++*this;
6814  return temp;
6815  }
6816 
6818  {
6819  _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
6820  return *this;
6821  }
6822 
6824  {
6825  xml_attribute_iterator temp = *this;
6826  --*this;
6827  return temp;
6828  }
6829 
6831  {
6832  }
6833 
6834  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)
6835  {
6836  }
6837 
6838  PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name)
6839  {
6840  }
6841 
6843  {
6844  return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
6845  }
6846 
6848  {
6849  return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
6850  }
6851 
6853  {
6854  assert(_wrap._root);
6855  return _wrap;
6856  }
6857 
6859  {
6860  assert(_wrap._root);
6861  return const_cast<xml_node*>(&_wrap); // BCC5 workaround
6862  }
6863 
6865  {
6866  assert(_wrap._root);
6867  _wrap = _wrap.next_sibling(_name);
6868  return *this;
6869  }
6870 
6872  {
6873  xml_named_node_iterator temp = *this;
6874  ++*this;
6875  return temp;
6876  }
6877 
6879  {
6880  if (_wrap._root)
6881  _wrap = _wrap.previous_sibling(_name);
6882  else
6883  {
6884  _wrap = _parent.last_child();
6885 
6886  if (!impl::strequal(_wrap.name(), _name))
6887  _wrap = _wrap.previous_sibling(_name);
6888  }
6889 
6890  return *this;
6891  }
6892 
6894  {
6895  xml_named_node_iterator temp = *this;
6896  --*this;
6897  return temp;
6898  }
6899 
6901  {
6902  }
6903 
6904  PUGI__FN xml_parse_result::operator bool() const
6905  {
6906  return status == status_ok;
6907  }
6908 
6910  {
6911  switch (status)
6912  {
6913  case status_ok: return "No error";
6914 
6915  case status_file_not_found: return "File was not found";
6916  case status_io_error: return "Error reading from file/stream";
6917  case status_out_of_memory: return "Could not allocate memory";
6918  case status_internal_error: return "Internal error occurred";
6919 
6920  case status_unrecognized_tag: return "Could not determine tag type";
6921 
6922  case status_bad_pi: return "Error parsing document declaration/processing instruction";
6923  case status_bad_comment: return "Error parsing comment";
6924  case status_bad_cdata: return "Error parsing CDATA section";
6925  case status_bad_doctype: return "Error parsing document type declaration";
6926  case status_bad_pcdata: return "Error parsing PCDATA section";
6927  case status_bad_start_element: return "Error parsing start element tag";
6928  case status_bad_attribute: return "Error parsing element attribute";
6929  case status_bad_end_element: return "Error parsing end element tag";
6930  case status_end_element_mismatch: return "Start-end tags mismatch";
6931 
6932  case status_append_invalid_root: return "Unable to append nodes: root is not an element or document";
6933 
6934  case status_no_document_element: return "No document element found";
6935 
6936  default: return "Unknown error";
6937  }
6938  }
6939 
6941  {
6942  _create();
6943  }
6944 
6946  {
6947  _destroy();
6948  }
6949 
6950 #ifdef PUGIXML_HAS_MOVE
6952  {
6953  _create();
6954  _move(rhs);
6955  }
6956 
6957  PUGI__FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
6958  {
6959  if (this == &rhs) return *this;
6960 
6961  _destroy();
6962  _create();
6963  _move(rhs);
6964 
6965  return *this;
6966  }
6967 #endif
6968 
6970  {
6971  _destroy();
6972  _create();
6973  }
6974 
6976  {
6977  reset();
6978 
6980  }
6981 
6982  PUGI__FN void xml_document::_create()
6983  {
6984  assert(!_root);
6985 
6986  #ifdef PUGIXML_COMPACT
6987  // space for page marker for the first page (uint32_t), rounded up to pointer size; assumes pointers are at least 32-bit
6988  const size_t page_offset = sizeof(void*);
6989  #else
6990  const size_t page_offset = 0;
6991  #endif
6992 
6993  // initialize sentinel page
6994  PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory));
6995 
6996  // prepare page structure
6997  impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory);
6998  assert(page);
6999 
7000  page->busy_size = impl::xml_memory_page_size;
7001 
7002  // setup first page marker
7003  #ifdef PUGIXML_COMPACT
7004  // round-trip through void* to avoid 'cast increases required alignment of target type' warning
7005  page->compact_page_marker = reinterpret_cast<uint32_t*>(static_cast<void*>(reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page)));
7006  *page->compact_page_marker = sizeof(impl::xml_memory_page);
7007  #endif
7008 
7009  // allocate new root
7010  _root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page);
7012 
7013  // setup sentinel page
7014  page->allocator = static_cast<impl::xml_document_struct*>(_root);
7015 
7016  // setup hash table pointer in allocator
7017  #ifdef PUGIXML_COMPACT
7018  page->allocator->_hash = &static_cast<impl::xml_document_struct*>(_root)->hash;
7019  #endif
7020 
7021  // verify the document allocation
7022  assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory));
7023  }
7024 
7025  PUGI__FN void xml_document::_destroy()
7026  {
7027  assert(_root);
7028 
7029  // destroy static storage
7030  if (_buffer)
7031  {
7032  impl::xml_memory::deallocate(_buffer);
7033  _buffer = 0;
7034  }
7035 
7036  // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator)
7037  for (impl::xml_extra_buffer* extra = static_cast<impl::xml_document_struct*>(_root)->extra_buffers; extra; extra = extra->next)
7038  {
7039  if (extra->buffer) impl::xml_memory::deallocate(extra->buffer);
7040  }
7041 
7042  // destroy dynamic storage, leave sentinel page (it's in static memory)
7043  impl::xml_memory_page* root_page = PUGI__GETPAGE(_root);
7044  assert(root_page && !root_page->prev);
7045  assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));
7046 
7047  for (impl::xml_memory_page* page = root_page->next; page; )
7048  {
7049  impl::xml_memory_page* next = page->next;
7050 
7051  impl::xml_allocator::deallocate_page(page);
7052 
7053  page = next;
7054  }
7055 
7056  #ifdef PUGIXML_COMPACT
7057  // destroy hash table
7058  static_cast<impl::xml_document_struct*>(_root)->hash.clear();
7059  #endif
7060 
7061  _root = 0;
7062  }
7063 
7064 #ifdef PUGIXML_HAS_MOVE
7065  PUGI__FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
7066  {
7067  impl::xml_document_struct* doc = static_cast<impl::xml_document_struct*>(_root);
7068  impl::xml_document_struct* other = static_cast<impl::xml_document_struct*>(rhs._root);
7069 
7070  // save first child pointer for later; this needs hash access
7071  xml_node_struct* other_first_child = other->first_child;
7072 
7073  #ifdef PUGIXML_COMPACT
7074  // reserve space for the hash table up front; this is the only operation that can fail
7075  // if it does, we have no choice but to throw (if we have exceptions)
7076  if (other_first_child)
7077  {
7078  size_t other_children = 0;
7079  for (xml_node_struct* node = other_first_child; node; node = node->next_sibling)
7080  other_children++;
7081 
7082  // in compact mode, each pointer assignment could result in a hash table request
7083  // during move, we have to relocate document first_child and parents of all children
7084  // normally there's just one child and its parent has a pointerless encoding but
7085  // we assume the worst here
7086  if (!other->_hash->reserve(other_children + 1))
7087  {
7088  #ifdef PUGIXML_NO_EXCEPTIONS
7089  return;
7090  #else
7091  throw std::bad_alloc();
7092  #endif
7093  }
7094  }
7095  #endif
7096 
7097  // move allocation state
7098  // note that other->_root may point to the embedded document page, in which case we should keep original (empty) state
7099  if (other->_root != PUGI__GETPAGE(other))
7100  {
7101  doc->_root = other->_root;
7102  doc->_busy_size = other->_busy_size;
7103  }
7104 
7105  // move buffer state
7106  doc->buffer = other->buffer;
7107  doc->extra_buffers = other->extra_buffers;
7108  _buffer = rhs._buffer;
7109 
7110  #ifdef PUGIXML_COMPACT
7111  // 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
7112  doc->hash = other->hash;
7113  doc->_hash = &doc->hash;
7114 
7115  // make sure we don't access other hash up until the end when we reinitialize other document
7116  other->_hash = 0;
7117  #endif
7118 
7119  // move page structure
7120  impl::xml_memory_page* doc_page = PUGI__GETPAGE(doc);
7121  assert(doc_page && !doc_page->prev && !doc_page->next);
7122 
7123  impl::xml_memory_page* other_page = PUGI__GETPAGE(other);
7124  assert(other_page && !other_page->prev);
7125 
7126  // relink pages since root page is embedded into xml_document
7127  if (impl::xml_memory_page* page = other_page->next)
7128  {
7129  assert(page->prev == other_page);
7130 
7131  page->prev = doc_page;
7132 
7133  doc_page->next = page;
7134  other_page->next = 0;
7135  }
7136 
7137  // make sure pages point to the correct document state
7138  for (impl::xml_memory_page* page = doc_page->next; page; page = page->next)
7139  {
7140  assert(page->allocator == other);
7141 
7142  page->allocator = doc;
7143 
7144  #ifdef PUGIXML_COMPACT
7145  // this automatically migrates most children between documents and prevents ->parent assignment from allocating
7146  if (page->compact_shared_parent == other)
7147  page->compact_shared_parent = doc;
7148  #endif
7149  }
7150 
7151  // move tree structure
7152  assert(!doc->first_child);
7153 
7154  doc->first_child = other_first_child;
7155 
7156  for (xml_node_struct* node = other_first_child; node; node = node->next_sibling)
7157  {
7158  #ifdef PUGIXML_COMPACT
7159  // most children will have migrated when we reassigned compact_shared_parent
7160  assert(node->parent == other || node->parent == doc);
7161 
7162  node->parent = doc;
7163  #else
7164  assert(node->parent == other);
7165  node->parent = doc;
7166  #endif
7167  }
7168 
7169  // reset other document
7170  new (other) impl::xml_document_struct(PUGI__GETPAGE(other));
7171  rhs._buffer = 0;
7172  }
7173 #endif
7174 
7175 #ifndef PUGIXML_NO_STL
7176  PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
7177  {
7178  reset();
7179 
7180  return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding, &_buffer);
7181  }
7182 
7183  PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
7184  {
7185  reset();
7186 
7187  return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding_wchar, &_buffer);
7188  }
7189 #endif
7190 
7191  PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options)
7192  {
7193  // Force native encoding (skip autodetection)
7194  #ifdef PUGIXML_WCHAR_MODE
7195  xml_encoding encoding = encoding_wchar;
7196  #else
7197  xml_encoding encoding = encoding_utf8;
7198  #endif
7199 
7200  return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
7201  }
7202 
7203  PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
7204  {
7205  return load_string(contents, options);
7206  }
7207 
7208  PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
7209  {
7210  reset();
7211 
7212  using impl::auto_deleter; // MSVC7 workaround
7214 
7215  return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
7216  }
7217 
7218  PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)
7219  {
7220  reset();
7221 
7222  using impl::auto_deleter; // MSVC7 workaround
7224 
7225  return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
7226  }
7227 
7228  PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
7229  {
7230  reset();
7231 
7232  return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, const_cast<void*>(contents), size, options, encoding, false, false, &_buffer);
7233  }
7234 
7235  PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
7236  {
7237  reset();
7238 
7239  return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, false, &_buffer);
7240  }
7241 
7242  PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
7243  {
7244  reset();
7245 
7246  return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, true, &_buffer);
7247  }
7248 
7249  PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
7250  {
7251  impl::xml_buffered_writer buffered_writer(writer, encoding);
7252 
7253  if ((flags & format_write_bom) && encoding != encoding_latin1)
7254  {
7255  // BOM always represents the codepoint U+FEFF, so just write it in native encoding
7256  #ifdef PUGIXML_WCHAR_MODE
7257  unsigned int bom = 0xfeff;
7258  buffered_writer.write(static_cast<wchar_t>(bom));
7259  #else
7260  buffered_writer.write('\xef', '\xbb', '\xbf');
7261  #endif
7262  }
7263 
7265  {
7266  buffered_writer.write_string(PUGIXML_TEXT("<?xml version=\"1.0\""));
7267  if (encoding == encoding_latin1) buffered_writer.write_string(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
7268  buffered_writer.write('?', '>');
7269  if (!(flags & format_raw)) buffered_writer.write('\n');
7270  }
7271 
7272  impl::node_output(buffered_writer, _root, indent, flags, 0);
7273 
7274  buffered_writer.flush();
7275  }
7276 
7277 #ifndef PUGIXML_NO_STL
7278  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
7279  {
7280  xml_writer_stream writer(stream);
7281 
7282  save(writer, indent, flags, encoding);
7283  }
7284 
7285  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
7286  {
7287  xml_writer_stream writer(stream);
7288 
7289  save(writer, indent, flags, encoding_wchar);
7290  }
7291 #endif
7292 
7293  PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
7294  {
7295  using impl::auto_deleter; // MSVC7 workaround
7296  auto_deleter<FILE> file(impl::open_file(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file);
7297 
7298  return impl::save_file_impl(*this, file.data, indent, flags, encoding);
7299  }
7300 
7301  PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
7302  {
7303  using impl::auto_deleter; // MSVC7 workaround
7304  auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file);
7305 
7306  return impl::save_file_impl(*this, file.data, indent, flags, encoding);
7307  }
7308 
7310  {
7311  assert(_root);
7312 
7313  for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
7314  if (PUGI__NODETYPE(i) == node_element)
7315  return xml_node(i);
7316 
7317  return xml_node();
7318  }
7319 
7320 #ifndef PUGIXML_NO_STL
7321  PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
7322  {
7323  assert(str);
7324 
7325  return impl::as_utf8_impl(str, impl::strlength_wide(str));
7326  }
7327 
7329  {
7330  return impl::as_utf8_impl(str.c_str(), str.size());
7331  }
7332 
7334  {
7335  assert(str);
7336 
7337  return impl::as_wide_impl(str, strlen(str));
7338  }
7339 
7341  {
7342  return impl::as_wide_impl(str.c_str(), str.size());
7343  }
7344 #endif
7345 
7347  {
7348  impl::xml_memory::allocate = allocate;
7349  impl::xml_memory::deallocate = deallocate;
7350  }
7351 
7353  {
7354  return impl::xml_memory::allocate;
7355  }
7356 
7358  {
7359  return impl::xml_memory::deallocate;
7360  }
7362 
7363 #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
7364 namespace std
7365 {
7366  // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
7367  PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
7368  {
7369  return std::bidirectional_iterator_tag();
7370  }
7371 
7372  PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
7373  {
7374  return std::bidirectional_iterator_tag();
7375  }
7376 
7377  PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)
7378  {
7379  return std::bidirectional_iterator_tag();
7380  }
7381 }
7382 #endif
7383 
7384 #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
7385 namespace std
7386 {
7387  // Workarounds for (non-standard) iterator category detection
7388  PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)
7389  {
7390  return std::bidirectional_iterator_tag();
7391  }
7392 
7393  PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)
7394  {
7395  return std::bidirectional_iterator_tag();
7396  }
7397 
7398  PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)
7399  {
7400  return std::bidirectional_iterator_tag();
7401  }
7402 }
7403 #endif
7404 
7405 #ifndef PUGIXML_NO_XPATH
7406 // STL replacements
7408  struct equal_to
7409  {
7410  template <typename T> bool operator()(const T& lhs, const T& rhs) const
7411  {
7412  return lhs == rhs;
7413  }
7414  };
7415 
7417  {
7418  template <typename T> bool operator()(const T& lhs, const T& rhs) const
7419  {
7420  return lhs != rhs;
7421  }
7422  };
7423 
7424  struct less
7425  {
7426  template <typename T> bool operator()(const T& lhs, const T& rhs) const
7427  {
7428  return lhs < rhs;
7429  }
7430  };
7431 
7432  struct less_equal
7433  {
7434  template <typename T> bool operator()(const T& lhs, const T& rhs) const
7435  {
7436  return lhs <= rhs;
7437  }
7438  };
7439 
7440  template <typename T> inline void swap(T& lhs, T& rhs)
7441  {
7442  T temp = lhs;
7443  lhs = rhs;
7444  rhs = temp;
7445  }
7446 
7447  template <typename I, typename Pred> PUGI__FN I min_element(I begin, I end, const Pred& pred)
7448  {
7449  I result = begin;
7450 
7451  for (I it = begin + 1; it != end; ++it)
7452  if (pred(*it, *result))
7453  result = it;
7454 
7455  return result;
7456  }
7457 
7458  template <typename I> PUGI__FN void reverse(I begin, I end)
7459  {
7460  while (end - begin > 1)
7461  swap(*begin++, *--end);
7462  }
7463 
7464  template <typename I> PUGI__FN I unique(I begin, I end)
7465  {
7466  // fast skip head
7467  while (end - begin > 1 && *begin != *(begin + 1))
7468  begin++;
7469 
7470  if (begin == end)
7471  return begin;
7472 
7473  // last written element
7474  I write = begin++;
7475 
7476  // merge unique elements
7477  while (begin != end)
7478  {
7479  if (*begin != *write)
7480  *++write = *begin++;
7481  else
7482  begin++;
7483  }
7484 
7485  // past-the-end (write points to live element)
7486  return write + 1;
7487  }
7488 
7489  template <typename T, typename Pred> PUGI__FN void insertion_sort(T* begin, T* end, const Pred& pred)
7490  {
7491  if (begin == end)
7492  return;
7493 
7494  for (T* it = begin + 1; it != end; ++it)
7495  {
7496  T val = *it;
7497  T* hole = it;
7498 
7499  // move hole backwards
7500  while (hole > begin && pred(val, *(hole - 1)))
7501  {
7502  *hole = *(hole - 1);
7503  hole--;
7504  }
7505 
7506  // fill hole with element
7507  *hole = val;
7508  }
7509  }
7510 
7511  template <typename I, typename Pred> inline I median3(I first, I middle, I last, const Pred& pred)
7512  {
7513  if (pred(*middle, *first))
7514  swap(middle, first);
7515  if (pred(*last, *middle))
7516  swap(last, middle);
7517  if (pred(*middle, *first))
7518  swap(middle, first);
7519 
7520  return middle;
7521  }
7522 
7523  template <typename T, typename Pred> PUGI__FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend)
7524  {
7525  // invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups)
7526  T* eq = begin;
7527  T* lt = begin;
7528  T* gt = end;
7529 
7530  while (lt < gt)
7531  {
7532  if (pred(*lt, pivot))
7533  lt++;
7534  else if (*lt == pivot)
7535  swap(*eq++, *lt++);
7536  else
7537  swap(*lt, *--gt);
7538  }
7539 
7540  // we now have just 4 groups: = < >; move equal elements to the middle
7541  T* eqbeg = gt;
7542 
7543  for (T* it = begin; it != eq; ++it)
7544  swap(*it, *--eqbeg);
7545 
7546  *out_eqbeg = eqbeg;
7547  *out_eqend = gt;
7548  }
7549 
7550  template <typename I, typename Pred> PUGI__FN void sort(I begin, I end, const Pred& pred)
7551  {
7552  // sort large chunks
7553  while (end - begin > 16)
7554  {
7555  // find median element
7556  I middle = begin + (end - begin) / 2;
7557  I median = median3(begin, middle, end - 1, pred);
7558 
7559  // partition in three chunks (< = >)
7560  I eqbeg, eqend;
7561  partition3(begin, end, *median, pred, &eqbeg, &eqend);
7562 
7563  // loop on larger half
7564  if (eqbeg - begin > end - eqend)
7565  {
7566  sort(eqend, end, pred);
7567  end = eqbeg;
7568  }
7569  else
7570  {
7571  sort(begin, eqbeg, pred);
7572  begin = eqend;
7573  }
7574  }
7575 
7576  // insertion sort small chunk
7577  insertion_sort(begin, end, pred);
7578  }
7579 
7580  PUGI__FN bool hash_insert(const void** table, size_t size, const void* key)
7581  {
7582  assert(key);
7583 
7584  unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key));
7585 
7586  // MurmurHash3 32-bit finalizer
7587  h ^= h >> 16;
7588  h *= 0x85ebca6bu;
7589  h ^= h >> 13;
7590  h *= 0xc2b2ae35u;
7591  h ^= h >> 16;
7592 
7593  size_t hashmod = size - 1;
7594  size_t bucket = h & hashmod;
7595 
7596  for (size_t probe = 0; probe <= hashmod; ++probe)
7597  {
7598  if (table[bucket] == 0)
7599  {
7600  table[bucket] = key;
7601  return true;
7602  }
7603 
7604  if (table[bucket] == key)
7605  return false;
7606 
7607  // hash collision, quadratic probing
7608  bucket = (bucket + probe + 1) & hashmod;
7609  }
7610 
7611  assert(false && "Hash table is full"); // unreachable
7612  return false;
7613  }
7615 
7616 // Allocator used for AST and evaluation stacks
7618  static const size_t xpath_memory_page_size =
7619  #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
7620  PUGIXML_MEMORY_XPATH_PAGE_SIZE
7621  #else
7622  4096
7623  #endif
7624  ;
7625 
7626  static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*);
7627 
7629  {
7631  size_t capacity;
7632 
7633  union
7634  {
7635  char data[xpath_memory_page_size];
7636  double alignment;
7637  };
7638  };
7639 
7641  {
7643  size_t _root_size;
7644  bool* _error;
7645 
7647  {
7648  }
7649 
7650  void* allocate(size_t size)
7651  {
7652  // round size up to block alignment boundary
7653  size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7654 
7655  if (_root_size + size <= _root->capacity)
7656  {
7657  void* buf = &_root->data[0] + _root_size;
7658  _root_size += size;
7659  return buf;
7660  }
7661  else
7662  {
7663  // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests
7664  size_t block_capacity_base = sizeof(_root->data);
7665  size_t block_capacity_req = size + block_capacity_base / 4;
7666  size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req;
7667 
7668  size_t block_size = block_capacity + offsetof(xpath_memory_block, data);
7669 
7670  xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));
7671  if (!block)
7672  {
7673  if (_error) *_error = true;
7674  return 0;
7675  }
7676 
7677  block->next = _root;
7678  block->capacity = block_capacity;
7679 
7680  _root = block;
7681  _root_size = size;
7682 
7683  return block->data;
7684  }
7685  }
7686 
7687  void* reallocate(void* ptr, size_t old_size, size_t new_size)
7688  {
7689  // round size up to block alignment boundary
7690  old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7691  new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7692 
7693  // we can only reallocate the last object
7694  assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);
7695 
7696  // try to reallocate the object inplace
7697  if (ptr && _root_size - old_size + new_size <= _root->capacity)
7698  {
7699  _root_size = _root_size - old_size + new_size;
7700  return ptr;
7701  }
7702 
7703  // allocate a new block
7704  void* result = allocate(new_size);
7705  if (!result) return 0;
7706 
7707  // we have a new block
7708  if (ptr)
7709  {
7710  // copy old data (we only support growing)
7711  assert(new_size >= old_size);
7712  memcpy(result, ptr, old_size);
7713 
7714  // free the previous page if it had no other objects
7715  assert(_root->data == result);
7716  assert(_root->next);
7717 
7718  if (_root->next->data == ptr)
7719  {
7720  // deallocate the whole page, unless it was the first one
7721  xpath_memory_block* next = _root->next->next;
7722 
7723  if (next)
7724  {
7726  _root->next = next;
7727  }
7728  }
7729  }
7730 
7731  return result;
7732  }
7733 
7735  {
7736  // free all new pages
7737  xpath_memory_block* cur = _root;
7738 
7739  while (cur != state._root)
7740  {
7741  xpath_memory_block* next = cur->next;
7742 
7744 
7745  cur = next;
7746  }
7747 
7748  // restore state
7749  _root = state._root;
7750  _root_size = state._root_size;
7751  }
7752 
7753  void release()
7754  {
7755  xpath_memory_block* cur = _root;
7756  assert(cur);
7757 
7758  while (cur->next)
7759  {
7760  xpath_memory_block* next = cur->next;
7761 
7763 
7764  cur = next;
7765  }
7766  }
7767  };
7768 
7770  {
7772  {
7773  }
7774 
7776  {
7777  _target->revert(_state);
7778  }
7779 
7782  };
7783 
7785  {
7788  };
7789 
7791  {
7796  bool oom;
7797 
7798  xpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false)
7799  {
7800  blocks[0].next = blocks[1].next = 0;
7801  blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data);
7802 
7803  stack.result = &result;
7804  stack.temp = &temp;
7805  }
7806 
7808  {
7809  result.release();
7810  temp.release();
7811  }
7812  };
7814 
7815 // String class
7818  {
7819  const char_t* _buffer;
7820  bool _uses_heap;
7821  size_t _length_heap;
7822 
7823  static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc)
7824  {
7825  char_t* result = static_cast<char_t*>(alloc->allocate((length + 1) * sizeof(char_t)));
7826  if (!result) return 0;
7827 
7828  memcpy(result, string, length * sizeof(char_t));
7829  result[length] = 0;
7830 
7831  return result;
7832  }
7833 
7834  xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap)
7835  {
7836  }
7837 
7838  public:
7839  static xpath_string from_const(const char_t* str)
7840  {
7841  return xpath_string(str, false, 0);
7842  }
7843 
7844  static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end)
7845  {
7846  assert(begin <= end && *end == 0);
7847 
7848  return xpath_string(begin, true, static_cast<size_t>(end - begin));
7849  }
7850 
7851  static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc)
7852  {
7853  assert(begin <= end);
7854 
7855  if (begin == end)
7856  return xpath_string();
7857 
7858  size_t length = static_cast<size_t>(end - begin);
7859  const char_t* data = duplicate_string(begin, length, alloc);
7860 
7861  return data ? xpath_string(data, true, length) : xpath_string();
7862  }
7863 
7864  xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0)
7865  {
7866  }
7867 
7868  void append(const xpath_string& o, xpath_allocator* alloc)
7869  {
7870  // skip empty sources
7871  if (!*o._buffer) return;
7872 
7873  // fast append for constant empty target and constant source
7874  if (!*_buffer && !_uses_heap && !o._uses_heap)
7875  {
7876  _buffer = o._buffer;
7877  }
7878  else
7879  {
7880  // need to make heap copy
7881  size_t target_length = length();
7882  size_t source_length = o.length();
7883  size_t result_length = target_length + source_length;
7884 
7885  // allocate new buffer
7886  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)));
7887  if (!result) return;
7888 
7889  // append first string to the new buffer in case there was no reallocation
7890  if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t));
7891 
7892  // append second string to the new buffer
7893  memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
7894  result[result_length] = 0;
7895 
7896  // finalize
7897  _buffer = result;
7898  _uses_heap = true;
7899  _length_heap = result_length;
7900  }
7901  }
7902 
7903  const char_t* c_str() const
7904  {
7905  return _buffer;
7906  }
7907 
7908  size_t length() const
7909  {
7910  return _uses_heap ? _length_heap : strlength(_buffer);
7911  }
7912 
7913  char_t* data(xpath_allocator* alloc)
7914  {
7915  // make private heap copy
7916  if (!_uses_heap)
7917  {
7918  size_t length_ = strlength(_buffer);
7919  const char_t* data_ = duplicate_string(_buffer, length_, alloc);
7920 
7921  if (!data_) return 0;
7922 
7923  _buffer = data_;
7924  _uses_heap = true;
7925  _length_heap = length_;
7926  }
7927 
7928  return const_cast<char_t*>(_buffer);
7929  }
7930 
7931  bool empty() const
7932  {
7933  return *_buffer == 0;
7934  }
7935 
7936  bool operator==(const xpath_string& o) const
7937  {
7938  return strequal(_buffer, o._buffer);
7939  }
7940 
7941  bool operator!=(const xpath_string& o) const
7942  {
7943  return !strequal(_buffer, o._buffer);
7944  }
7945 
7946  bool uses_heap() const
7947  {
7948  return _uses_heap;
7949  }
7950  };
7952 
7954  PUGI__FN bool starts_with(const char_t* string, const char_t* pattern)
7955  {
7956  while (*pattern && *string == *pattern)
7957  {
7958  string++;
7959  pattern++;
7960  }
7961 
7962  return *pattern == 0;
7963  }
7964 
7965  PUGI__FN const char_t* find_char(const char_t* s, char_t c)
7966  {
7967  #ifdef PUGIXML_WCHAR_MODE
7968  return wcschr(s, c);
7969  #else
7970  return strchr(s, c);
7971  #endif
7972  }
7973 
7974  PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p)
7975  {
7976  #ifdef PUGIXML_WCHAR_MODE
7977  // MSVC6 wcsstr bug workaround (if s is empty it always returns 0)
7978  return (*p == 0) ? s : wcsstr(s, p);
7979  #else
7980  return strstr(s, p);
7981  #endif
7982  }
7983 
7984  // Converts symbol to lower case, if it is an ASCII one
7985  PUGI__FN char_t tolower_ascii(char_t ch)
7986  {
7987  return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
7988  }
7989 
7990  PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
7991  {
7992  if (na.attribute())
7993  return xpath_string::from_const(na.attribute().value());
7994  else
7995  {
7996  xml_node n = na.node();
7997 
7998  switch (n.type())
7999  {
8000  case node_pcdata:
8001  case node_cdata:
8002  case node_comment:
8003  case node_pi:
8004  return xpath_string::from_const(n.value());
8005 
8006  case node_document:
8007  case node_element:
8008  {
8010 
8011  // element nodes can have value if parse_embed_pcdata was used
8012  if (n.value()[0])
8013  result.append(xpath_string::from_const(n.value()), alloc);
8014 
8015  xml_node cur = n.first_child();
8016 
8017  while (cur && cur != n)
8018  {
8019  if (cur.type() == node_pcdata || cur.type() == node_cdata)
8020  result.append(xpath_string::from_const(cur.value()), alloc);
8021 
8022  if (cur.first_child())
8023  cur = cur.first_child();
8024  else if (cur.next_sibling())
8025  cur = cur.next_sibling();
8026  else
8027  {
8028  while (!cur.next_sibling() && cur != n)
8029  cur = cur.parent();
8030 
8031  if (cur != n) cur = cur.next_sibling();
8032  }
8033  }
8034 
8035  return result;
8036  }
8037 
8038  default:
8039  return xpath_string();
8040  }
8041  }
8042  }
8043 
8044  PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)
8045  {
8046  assert(ln->parent == rn->parent);
8047 
8048  // there is no common ancestor (the shared parent is null), nodes are from different documents
8049  if (!ln->parent) return ln < rn;
8050 
8051  // determine sibling order
8052  xml_node_struct* ls = ln;
8053  xml_node_struct* rs = rn;
8054 
8055  while (ls && rs)
8056  {
8057  if (ls == rn) return true;
8058  if (rs == ln) return false;
8059 
8060  ls = ls->next_sibling;
8061  rs = rs->next_sibling;
8062  }
8063 
8064  // if rn sibling chain ended ln must be before rn
8065  return !rs;
8066  }
8067 
8068  PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
8069  {
8070  // find common ancestor at the same depth, if any
8071  xml_node_struct* lp = ln;
8072  xml_node_struct* rp = rn;
8073 
8074  while (lp && rp && lp->parent != rp->parent)
8075  {
8076  lp = lp->parent;
8077  rp = rp->parent;
8078  }
8079 
8080  // parents are the same!
8081  if (lp && rp) return node_is_before_sibling(lp, rp);
8082 
8083  // nodes are at different depths, need to normalize heights
8084  bool left_higher = !lp;
8085 
8086  while (lp)
8087  {
8088  lp = lp->parent;
8089  ln = ln->parent;
8090  }
8091 
8092  while (rp)
8093  {
8094  rp = rp->parent;
8095  rn = rn->parent;
8096  }
8097 
8098  // one node is the ancestor of the other
8099  if (ln == rn) return left_higher;
8100 
8101  // find common ancestor... again
8102  while (ln->parent != rn->parent)
8103  {
8104  ln = ln->parent;
8105  rn = rn->parent;
8106  }
8107 
8108  return node_is_before_sibling(ln, rn);
8109  }
8110 
8111  PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)
8112  {
8113  while (node && node != parent) node = node->parent;
8114 
8115  return parent && node == parent;
8116  }
8117 
8118  PUGI__FN const void* document_buffer_order(const xpath_node& xnode)
8119  {
8120  xml_node_struct* node = xnode.node().internal_object();
8121 
8122  if (node)
8123  {
8124  if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0)
8125  {
8126  if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name;
8127  if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value;
8128  }
8129 
8130  return 0;
8131  }
8132 
8133  xml_attribute_struct* attr = xnode.attribute().internal_object();
8134 
8135  if (attr)
8136  {
8137  if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0)
8138  {
8139  if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name;
8140  if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value;
8141  }
8142 
8143  return 0;
8144  }
8145 
8146  return 0;
8147  }
8148 
8150  {
8151  bool operator()(const xpath_node& lhs, const xpath_node& rhs) const
8152  {
8153  // optimized document order based check
8154  const void* lo = document_buffer_order(lhs);
8155  const void* ro = document_buffer_order(rhs);
8156 
8157  if (lo && ro) return lo < ro;
8158 
8159  // slow comparison
8160  xml_node ln = lhs.node(), rn = rhs.node();
8161 
8162  // compare attributes
8163  if (lhs.attribute() && rhs.attribute())
8164  {
8165  // shared parent
8166  if (lhs.parent() == rhs.parent())
8167  {
8168  // determine sibling order
8169  for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
8170  if (a == rhs.attribute())
8171  return true;
8172 
8173  return false;
8174  }
8175 
8176  // compare attribute parents
8177  ln = lhs.parent();
8178  rn = rhs.parent();
8179  }
8180  else if (lhs.attribute())
8181  {
8182  // attributes go after the parent element
8183  if (lhs.parent() == rhs.node()) return false;
8184 
8185  ln = lhs.parent();
8186  }
8187  else if (rhs.attribute())
8188  {
8189  // attributes go after the parent element
8190  if (rhs.parent() == lhs.node()) return true;
8191 
8192  rn = rhs.parent();
8193  }
8194 
8195  if (ln == rn) return false;
8196 
8197  if (!ln || !rn) return ln < rn;
8198 
8199  return node_is_before(ln.internal_object(), rn.internal_object());
8200  }
8201  };
8202 
8204  {
8205  #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
8206  PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t));
8207  typedef uint32_t UI; // BCC5 workaround
8208  union { float f; UI i; } u;
8209  u.i = 0x7fc00000;
8210  return double(u.f);
8211  #else
8212  // fallback
8213  const volatile double zero = 0.0;
8214  return zero / zero;
8215  #endif
8216  }
8217 
8218  PUGI__FN bool is_nan(double value)
8219  {
8220  #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
8221  return !!_isnan(value);
8222  #elif defined(fpclassify) && defined(FP_NAN)
8223  return fpclassify(value) == FP_NAN;
8224  #else
8225  // fallback
8226  const volatile double v = value;
8227  return v != v;
8228  #endif
8229  }
8230 
8231  PUGI__FN const char_t* convert_number_to_string_special(double value)
8232  {
8233  #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
8234  if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0;
8235  if (_isnan(value)) return PUGIXML_TEXT("NaN");
8236  return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
8237  #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
8238  switch (fpclassify(value))
8239  {
8240  case FP_NAN:
8241  return PUGIXML_TEXT("NaN");
8242 
8243  case FP_INFINITE:
8244  return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
8245 
8246  case FP_ZERO:
8247  return PUGIXML_TEXT("0");
8248 
8249  default:
8250  return 0;
8251  }
8252  #else
8253  // fallback
8254  const volatile double v = value;
8255 
8256  if (v == 0) return PUGIXML_TEXT("0");
8257  if (v != v) return PUGIXML_TEXT("NaN");
8258  if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
8259  return 0;
8260  #endif
8261  }
8262 
8264  {
8265  return (value != 0 && !is_nan(value));
8266  }
8267 
8268  PUGI__FN void truncate_zeros(char* begin, char* end)
8269  {
8270  while (begin != end && end[-1] == '0') end--;
8271 
8272  *end = 0;
8273  }
8274 
8275  // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
8276 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
8277  PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
8278  {
8279  // get base values
8280  int sign, exponent;
8281  _ecvt_s(buffer, sizeof(buffer), value, DBL_DIG + 1, &exponent, &sign);
8282 
8283  // truncate redundant zeros
8284  truncate_zeros(buffer, buffer + strlen(buffer));
8285 
8286  // fill results
8287  *out_mantissa = buffer;
8288  *out_exponent = exponent;
8289  }
8290 #else
8291  PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
8292  {
8293  // get a scientific notation value with IEEE DBL_DIG decimals
8294  PUGI__SNPRINTF(buffer, "%.*e", DBL_DIG, value);
8295 
8296  // get the exponent (possibly negative)
8297  char* exponent_string = strchr(buffer, 'e');
8298  assert(exponent_string);
8299 
8300  int exponent = atoi(exponent_string + 1);
8301 
8302  // extract mantissa string: skip sign
8303  char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
8304  assert(mantissa[0] != '0' && mantissa[1] == '.');
8305 
8306  // divide mantissa by 10 to eliminate integer part
8307  mantissa[1] = mantissa[0];
8308  mantissa++;
8309  exponent++;
8310 
8311  // remove extra mantissa digits and zero-terminate mantissa
8312  truncate_zeros(mantissa, exponent_string);
8313 
8314  // fill results
8315  *out_mantissa = mantissa;
8316  *out_exponent = exponent;
8317  }
8318 #endif
8319 
8321  {
8322  // try special number conversion
8323  const char_t* special = convert_number_to_string_special(value);
8324  if (special) return xpath_string::from_const(special);
8325 
8326  // get mantissa + exponent form
8327  char mantissa_buffer[32];
8328 
8329  char* mantissa;
8330  int exponent;
8331  convert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent);
8332 
8333  // allocate a buffer of suitable length for the number
8334  size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
8335  char_t* result = static_cast<char_t*>(alloc->allocate(sizeof(char_t) * result_size));
8336  if (!result) return xpath_string();
8337 
8338  // make the number!
8339  char_t* s = result;
8340 
8341  // sign
8342  if (value < 0) *s++ = '-';
8343 
8344  // integer part
8345  if (exponent <= 0)
8346  {
8347  *s++ = '0';
8348  }
8349  else
8350  {
8351  while (exponent > 0)
8352  {
8353  assert(*mantissa == 0 || static_cast<unsigned int>(*mantissa - '0') <= 9);
8354  *s++ = *mantissa ? *mantissa++ : '0';
8355  exponent--;
8356  }
8357  }
8358 
8359  // fractional part
8360  if (*mantissa)
8361  {
8362  // decimal point
8363  *s++ = '.';
8364 
8365  // extra zeroes from negative exponent
8366  while (exponent < 0)
8367  {
8368  *s++ = '0';
8369  exponent++;
8370  }
8371 
8372  // extra mantissa digits
8373  while (*mantissa)
8374  {
8375  assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
8376  *s++ = *mantissa++;
8377  }
8378  }
8379 
8380  // zero-terminate
8381  assert(s < result + result_size);
8382  *s = 0;
8383 
8384  return xpath_string::from_heap_preallocated(result, s);
8385  }
8386 
8387  PUGI__FN bool check_string_to_number_format(const char_t* string)
8388  {
8389  // parse leading whitespace
8390  while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
8391 
8392  // parse sign
8393  if (*string == '-') ++string;
8394 
8395  if (!*string) return false;
8396 
8397  // if there is no integer part, there should be a decimal part with at least one digit
8398  if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false;
8399 
8400  // parse integer part
8401  while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
8402 
8403  // parse decimal part
8404  if (*string == '.')
8405  {
8406  ++string;
8407 
8408  while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
8409  }
8410 
8411  // parse trailing whitespace
8412  while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
8413 
8414  return *string == 0;
8415  }
8416 
8417  PUGI__FN double convert_string_to_number(const char_t* string)
8418  {
8419  // check string format
8420  if (!check_string_to_number_format(string)) return gen_nan();
8421 
8422  // parse string
8423  #ifdef PUGIXML_WCHAR_MODE
8424  return wcstod(string, 0);
8425  #else
8426  return strtod(string, 0);
8427  #endif
8428  }
8429 
8430  PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result)
8431  {
8432  size_t length = static_cast<size_t>(end - begin);
8433  char_t* scratch = buffer;
8434 
8435  if (length >= sizeof(buffer) / sizeof(buffer[0]))
8436  {
8437  // need to make dummy on-heap copy
8438  scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
8439  if (!scratch) return false;
8440  }
8441 
8442  // copy string to zero-terminated buffer and perform conversion
8443  memcpy(scratch, begin, length * sizeof(char_t));
8444  scratch[length] = 0;
8445 
8446  *out_result = convert_string_to_number(scratch);
8447 
8448  // free dummy buffer
8449  if (scratch != buffer) xml_memory::deallocate(scratch);
8450 
8451  return true;
8452  }
8453 
8454  PUGI__FN double round_nearest(double value)
8455  {
8456  return floor(value + 0.5);
8457  }
8458 
8459  PUGI__FN double round_nearest_nzero(double value)
8460  {
8461  // same as round_nearest, but returns -0 for [-0.5, -0]
8462  // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)
8463  return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
8464  }
8465 
8466  PUGI__FN const char_t* qualified_name(const xpath_node& node)
8467  {
8468  return node.attribute() ? node.attribute().name() : node.node().name();
8469  }
8470 
8471  PUGI__FN const char_t* local_name(const xpath_node& node)
8472  {
8473  const char_t* name = qualified_name(node);
8474  const char_t* p = find_char(name, ':');
8475 
8476  return p ? p + 1 : name;
8477  }
8478 
8480  {
8481  const char_t* prefix;
8483 
8485  {
8486  const char_t* pos = find_char(name, ':');
8487 
8488  prefix = pos ? name : 0;
8489  prefix_length = pos ? static_cast<size_t>(pos - name) : 0;
8490  }
8491 
8492  bool operator()(xml_attribute a) const
8493  {
8494  const char_t* name = a.name();
8495 
8496  if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false;
8497 
8498  return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
8499  }
8500  };
8501 
8502  PUGI__FN const char_t* namespace_uri(xml_node node)
8503  {
8504  namespace_uri_predicate pred = node.name();
8505 
8506  xml_node p = node;
8507 
8508  while (p)
8509  {
8510  xml_attribute a = p.find_attribute(pred);
8511 
8512  if (a) return a.value();
8513 
8514  p = p.parent();
8515  }
8516 
8517  return PUGIXML_TEXT("");
8518  }
8519 
8520  PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent)
8521  {
8522  namespace_uri_predicate pred = attr.name();
8523 
8524  // Default namespace does not apply to attributes
8525  if (!pred.prefix) return PUGIXML_TEXT("");
8526 
8527  xml_node p = parent;
8528 
8529  while (p)
8530  {
8531  xml_attribute a = p.find_attribute(pred);
8532 
8533  if (a) return a.value();
8534 
8535  p = p.parent();
8536  }
8537 
8538  return PUGIXML_TEXT("");
8539  }
8540 
8541  PUGI__FN const char_t* namespace_uri(const xpath_node& node)
8542  {
8543  return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
8544  }
8545 
8546  PUGI__FN char_t* normalize_space(char_t* buffer)
8547  {
8548  char_t* write = buffer;
8549 
8550  for (char_t* it = buffer; *it; )
8551  {
8552  char_t ch = *it++;
8553 
8554  if (PUGI__IS_CHARTYPE(ch, ct_space))
8555  {
8556  // replace whitespace sequence with single space
8557  while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
8558 
8559  // avoid leading spaces
8560  if (write != buffer) *write++ = ' ';
8561  }
8562  else *write++ = ch;
8563  }
8564 
8565  // remove trailing space
8566  if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
8567 
8568  // zero-terminate
8569  *write = 0;
8570 
8571  return write;
8572  }
8573 
8574  PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)
8575  {
8576  char_t* write = buffer;
8577 
8578  while (*buffer)
8579  {
8580  PUGI__DMC_VOLATILE char_t ch = *buffer++;
8581 
8582  const char_t* pos = find_char(from, ch);
8583 
8584  if (!pos)
8585  *write++ = ch; // do not process
8586  else if (static_cast<size_t>(pos - from) < to_length)
8587  *write++ = to[pos - from]; // replace
8588  }
8589 
8590  // zero-terminate
8591  *write = 0;
8592 
8593  return write;
8594  }
8595 
8596  PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to)
8597  {
8598  unsigned char table[128] = {0};
8599 
8600  while (*from)
8601  {
8602  unsigned int fc = static_cast<unsigned int>(*from);
8603  unsigned int tc = static_cast<unsigned int>(*to);
8604 
8605  if (fc >= 128 || tc >= 128)
8606  return 0;
8607 
8608  // code=128 means "skip character"
8609  if (!table[fc])
8610  table[fc] = static_cast<unsigned char>(tc ? tc : 128);
8611 
8612  from++;
8613  if (tc) to++;
8614  }
8615 
8616  for (int i = 0; i < 128; ++i)
8617  if (!table[i])
8618  table[i] = static_cast<unsigned char>(i);
8619 
8620  void* result = alloc->allocate(sizeof(table));
8621  if (!result) return 0;
8622 
8623  memcpy(result, table, sizeof(table));
8624 
8625  return static_cast<unsigned char*>(result);
8626  }
8627 
8628  PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table)
8629  {
8630  char_t* write = buffer;
8631 
8632  while (*buffer)
8633  {
8634  char_t ch = *buffer++;
8635  unsigned int index = static_cast<unsigned int>(ch);
8636 
8637  if (index < 128)
8638  {
8639  unsigned char code = table[index];
8640 
8641  // code=128 means "skip character" (table size is 128 so 128 can be a special value)
8642  // this code skips these characters without extra branches
8643  *write = static_cast<char_t>(code);
8644  write += 1 - (code >> 7);
8645  }
8646  else
8647  {
8648  *write++ = ch;
8649  }
8650  }
8651 
8652  // zero-terminate
8653  *write = 0;
8654 
8655  return write;
8656  }
8657 
8658  inline bool is_xpath_attribute(const char_t* name)
8659  {
8660  return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':'));
8661  }
8662 
8663  struct xpath_variable_boolean: xpath_variable
8664  {
8665  xpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false)
8666  {
8667  }
8668 
8669  bool value;
8670  char_t name[1];
8671  };
8672 
8673  struct xpath_variable_number: xpath_variable
8674  {
8675  xpath_variable_number(): xpath_variable(xpath_type_number), value(0)
8676  {
8677  }
8678 
8679  double value;
8680  char_t name[1];
8681  };
8682 
8683  struct xpath_variable_string: xpath_variable
8684  {
8685  xpath_variable_string(): xpath_variable(xpath_type_string), value(0)
8686  {
8687  }
8688 
8690  {
8691  if (value) xml_memory::deallocate(value);
8692  }
8693 
8694  char_t* value;
8695  char_t name[1];
8696  };
8697 
8698  struct xpath_variable_node_set: xpath_variable
8699  {
8701  {
8702  }
8703 
8704  xpath_node_set value;
8705  char_t name[1];
8706  };
8707 
8708  static const xpath_node_set dummy_node_set;
8709 
8710  PUGI__FN PUGI__UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str)
8711  {
8712  // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
8713  unsigned int result = 0;
8714 
8715  while (*str)
8716  {
8717  result += static_cast<unsigned int>(*str++);
8718  result += result << 10;
8719  result ^= result >> 6;
8720  }
8721 
8722  result += result << 3;
8723  result ^= result >> 11;
8724  result += result << 15;
8725 
8726  return result;
8727  }
8728 
8729  template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name)
8730  {
8731  size_t length = strlength(name);
8732  if (length == 0) return 0; // empty variable names are invalid
8733 
8734  // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
8735  void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));
8736  if (!memory) return 0;
8737 
8738  T* result = new (memory) T();
8739 
8740  memcpy(result->name, name, (length + 1) * sizeof(char_t));
8741 
8742  return result;
8743  }
8744 
8745  PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
8746  {
8747  switch (type)
8748  {
8749  case xpath_type_node_set:
8750  return new_xpath_variable<xpath_variable_node_set>(name);
8751 
8752  case xpath_type_number:
8753  return new_xpath_variable<xpath_variable_number>(name);
8754 
8755  case xpath_type_string:
8756  return new_xpath_variable<xpath_variable_string>(name);
8757 
8758  case xpath_type_boolean:
8759  return new_xpath_variable<xpath_variable_boolean>(name);
8760 
8761  default:
8762  return 0;
8763  }
8764  }
8765 
8766  template <typename T> PUGI__FN void delete_xpath_variable(T* var)
8767  {
8768  var->~T();
8770  }
8771 
8773  {
8774  switch (type)
8775  {
8776  case xpath_type_node_set:
8777  delete_xpath_variable(static_cast<xpath_variable_node_set*>(var));
8778  break;
8779 
8780  case xpath_type_number:
8781  delete_xpath_variable(static_cast<xpath_variable_number*>(var));
8782  break;
8783 
8784  case xpath_type_string:
8785  delete_xpath_variable(static_cast<xpath_variable_string*>(var));
8786  break;
8787 
8788  case xpath_type_boolean:
8789  delete_xpath_variable(static_cast<xpath_variable_boolean*>(var));
8790  break;
8791 
8792  default:
8793  assert(false && "Invalid variable type"); // unreachable
8794  }
8795  }
8796 
8797  PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs)
8798  {
8799  switch (rhs->type())
8800  {
8801  case xpath_type_node_set:
8802  return lhs->set(static_cast<const xpath_variable_node_set*>(rhs)->value);
8803 
8804  case xpath_type_number:
8805  return lhs->set(static_cast<const xpath_variable_number*>(rhs)->value);
8806 
8807  case xpath_type_string:
8808  return lhs->set(static_cast<const xpath_variable_string*>(rhs)->value);
8809 
8810  case xpath_type_boolean:
8811  return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value);
8812 
8813  default:
8814  assert(false && "Invalid variable type"); // unreachable
8815  return false;
8816  }
8817  }
8818 
8819  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)
8820  {
8821  size_t length = static_cast<size_t>(end - begin);
8822  char_t* scratch = buffer;
8823 
8824  if (length >= sizeof(buffer) / sizeof(buffer[0]))
8825  {
8826  // need to make dummy on-heap copy
8827  scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
8828  if (!scratch) return false;
8829  }
8830 
8831  // copy string to zero-terminated buffer and perform lookup
8832  memcpy(scratch, begin, length * sizeof(char_t));
8833  scratch[length] = 0;
8834 
8835  *out_result = set->get(scratch);
8836 
8837  // free dummy buffer
8838  if (scratch != buffer) xml_memory::deallocate(scratch);
8839 
8840  return true;
8841  }
8843 
8844 // Internal node set class
8846  PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end)
8847  {
8848  if (end - begin < 2)
8849  return xpath_node_set::type_sorted;
8850 
8852 
8853  bool first = cmp(begin[0], begin[1]);
8854 
8855  for (const xpath_node* it = begin + 1; it + 1 < end; ++it)
8856  if (cmp(it[0], it[1]) != first)
8857  return xpath_node_set::type_unsorted;
8858 
8859  return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse;
8860  }
8861 
8862  PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
8863  {
8864  xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
8865 
8866  if (type == xpath_node_set::type_unsorted)
8867  {
8868  xpath_node_set::type_t sorted = xpath_get_order(begin, end);
8869 
8870  if (sorted == xpath_node_set::type_unsorted)
8871  {
8872  sort(begin, end, document_order_comparator());
8873 
8874  type = xpath_node_set::type_sorted;
8875  }
8876  else
8877  type = sorted;
8878  }
8879 
8880  if (type != order) reverse(begin, end);
8881 
8882  return order;
8883  }
8884 
8885  PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
8886  {
8887  if (begin == end) return xpath_node();
8888 
8889  switch (type)
8890  {
8891  case xpath_node_set::type_sorted:
8892  return *begin;
8893 
8894  case xpath_node_set::type_sorted_reverse:
8895  return *(end - 1);
8896 
8897  case xpath_node_set::type_unsorted:
8898  return *min_element(begin, end, document_order_comparator());
8899 
8900  default:
8901  assert(false && "Invalid node set type"); // unreachable
8902  return xpath_node();
8903  }
8904  }
8905 
8907  {
8908  xpath_node_set::type_t _type;
8909 
8910  xpath_node* _begin;
8911  xpath_node* _end;
8912  xpath_node* _eos;
8913 
8914  public:
8915  xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0)
8916  {
8917  }
8918 
8919  xpath_node* begin() const
8920  {
8921  return _begin;
8922  }
8923 
8924  xpath_node* end() const
8925  {
8926  return _end;
8927  }
8928 
8929  bool empty() const
8930  {
8931  return _begin == _end;
8932  }
8933 
8934  size_t size() const
8935  {
8936  return static_cast<size_t>(_end - _begin);
8937  }
8938 
8939  xpath_node first() const
8940  {
8941  return xpath_first(_begin, _end, _type);
8942  }
8943 
8944  void push_back_grow(const xpath_node& node, xpath_allocator* alloc);
8945 
8946  void push_back(const xpath_node& node, xpath_allocator* alloc)
8947  {
8948  if (_end != _eos)
8949  *_end++ = node;
8950  else
8951  push_back_grow(node, alloc);
8952  }
8953 
8954  void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)
8955  {
8956  if (begin_ == end_) return;
8957 
8958  size_t size_ = static_cast<size_t>(_end - _begin);
8959  size_t capacity = static_cast<size_t>(_eos - _begin);
8960  size_t count = static_cast<size_t>(end_ - begin_);
8961 
8962  if (size_ + count > capacity)
8963  {
8964  // reallocate the old array or allocate a new one
8965  xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
8966  if (!data) return;
8967 
8968  // finalize
8969  _begin = data;
8970  _end = data + size_;
8971  _eos = data + size_ + count;
8972  }
8973 
8974  memcpy(_end, begin_, count * sizeof(xpath_node));
8975  _end += count;
8976  }
8977 
8978  void sort_do()
8979  {
8980  _type = xpath_sort(_begin, _end, _type, false);
8981  }
8982 
8983  void truncate(xpath_node* pos)
8984  {
8985  assert(_begin <= pos && pos <= _end);
8986 
8987  _end = pos;
8988  }
8989 
8991  {
8992  if (_type == xpath_node_set::type_unsorted && _end - _begin > 2)
8993  {
8994  xpath_allocator_capture cr(alloc);
8995 
8996  size_t size_ = static_cast<size_t>(_end - _begin);
8997 
8998  size_t hash_size = 1;
8999  while (hash_size < size_ + size_ / 2) hash_size *= 2;
9000 
9001  const void** hash_data = static_cast<const void**>(alloc->allocate(hash_size * sizeof(void**)));
9002  if (!hash_data) return;
9003 
9004  memset(hash_data, 0, hash_size * sizeof(const void**));
9005 
9006  xpath_node* write = _begin;
9007 
9008  for (xpath_node* it = _begin; it != _end; ++it)
9009  {
9010  const void* attr = it->attribute().internal_object();
9011  const void* node = it->node().internal_object();
9012  const void* key = attr ? attr : node;
9013 
9014  if (key && hash_insert(hash_data, hash_size, key))
9015  {
9016  *write++ = *it;
9017  }
9018  }
9019 
9020  _end = write;
9021  }
9022  else
9023  {
9024  _end = unique(_begin, _end);
9025  }
9026  }
9027 
9028  xpath_node_set::type_t type() const
9029  {
9030  return _type;
9031  }
9032 
9033  void set_type(xpath_node_set::type_t value)
9034  {
9035  _type = value;
9036  }
9037  };
9038 
9040  {
9041  size_t capacity = static_cast<size_t>(_eos - _begin);
9042 
9043  // get new capacity (1.5x rule)
9044  size_t new_capacity = capacity + capacity / 2 + 1;
9045 
9046  // reallocate the old array or allocate a new one
9047  xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
9048  if (!data) return;
9049 
9050  // finalize
9051  _begin = data;
9052  _end = data + capacity;
9053  _eos = data + new_capacity;
9054 
9055  // push
9056  *_end++ = node;
9057  }
9059 
9062  {
9063  xpath_node n;
9064  size_t position, size;
9065 
9066  xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_)
9067  {
9068  }
9069  };
9070 
9072  {
9100  };
9101 
9103  {
9104  const char_t* begin;
9105  const char_t* end;
9106 
9108  {
9109  }
9110 
9111  bool operator==(const char_t* other) const
9112  {
9113  size_t length = static_cast<size_t>(end - begin);
9114 
9115  return strequalrange(other, begin, length);
9116  }
9117  };
9118 
9120  {
9121  const char_t* _cur;
9122  const char_t* _cur_lexeme_pos;
9123  xpath_lexer_string _cur_lexeme_contents;
9124 
9125  lexeme_t _cur_lexeme;
9126 
9127  public:
9128  explicit xpath_lexer(const char_t* query): _cur(query)
9129  {
9130  next();
9131  }
9132 
9133  const char_t* state() const
9134  {
9135  return _cur;
9136  }
9137 
9138  void next()
9139  {
9140  const char_t* cur = _cur;
9141 
9142  while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
9143 
9144  // save lexeme position for error reporting
9145  _cur_lexeme_pos = cur;
9146 
9147  switch (*cur)
9148  {
9149  case 0:
9150  _cur_lexeme = lex_eof;
9151  break;
9152 
9153  case '>':
9154  if (*(cur+1) == '=')
9155  {
9156  cur += 2;
9157  _cur_lexeme = lex_greater_or_equal;
9158  }
9159  else
9160  {
9161  cur += 1;
9162  _cur_lexeme = lex_greater;
9163  }
9164  break;
9165 
9166  case '<':
9167  if (*(cur+1) == '=')
9168  {
9169  cur += 2;
9170  _cur_lexeme = lex_less_or_equal;
9171  }
9172  else
9173  {
9174  cur += 1;
9175  _cur_lexeme = lex_less;
9176  }
9177  break;
9178 
9179  case '!':
9180  if (*(cur+1) == '=')
9181  {
9182  cur += 2;
9183  _cur_lexeme = lex_not_equal;
9184  }
9185  else
9186  {
9187  _cur_lexeme = lex_none;
9188  }
9189  break;
9190 
9191  case '=':
9192  cur += 1;
9193  _cur_lexeme = lex_equal;
9194 
9195  break;
9196 
9197  case '+':
9198  cur += 1;
9199  _cur_lexeme = lex_plus;
9200 
9201  break;
9202 
9203  case '-':
9204  cur += 1;
9205  _cur_lexeme = lex_minus;
9206 
9207  break;
9208 
9209  case '*':
9210  cur += 1;
9211  _cur_lexeme = lex_multiply;
9212 
9213  break;
9214 
9215  case '|':
9216  cur += 1;
9217  _cur_lexeme = lex_union;
9218 
9219  break;
9220 
9221  case '$':
9222  cur += 1;
9223 
9225  {
9226  _cur_lexeme_contents.begin = cur;
9227 
9228  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9229 
9230  if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
9231  {
9232  cur++; // :
9233 
9234  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9235  }
9236 
9237  _cur_lexeme_contents.end = cur;
9238 
9239  _cur_lexeme = lex_var_ref;
9240  }
9241  else
9242  {
9243  _cur_lexeme = lex_none;
9244  }
9245 
9246  break;
9247 
9248  case '(':
9249  cur += 1;
9250  _cur_lexeme = lex_open_brace;
9251 
9252  break;
9253 
9254  case ')':
9255  cur += 1;
9256  _cur_lexeme = lex_close_brace;
9257 
9258  break;
9259 
9260  case '[':
9261  cur += 1;
9262  _cur_lexeme = lex_open_square_brace;
9263 
9264  break;
9265 
9266  case ']':
9267  cur += 1;
9268  _cur_lexeme = lex_close_square_brace;
9269 
9270  break;
9271 
9272  case ',':
9273  cur += 1;
9274  _cur_lexeme = lex_comma;
9275 
9276  break;
9277 
9278  case '/':
9279  if (*(cur+1) == '/')
9280  {
9281  cur += 2;
9282  _cur_lexeme = lex_double_slash;
9283  }
9284  else
9285  {
9286  cur += 1;
9287  _cur_lexeme = lex_slash;
9288  }
9289  break;
9290 
9291  case '.':
9292  if (*(cur+1) == '.')
9293  {
9294  cur += 2;
9295  _cur_lexeme = lex_double_dot;
9296  }
9297  else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
9298  {
9299  _cur_lexeme_contents.begin = cur; // .
9300 
9301  ++cur;
9302 
9303  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9304 
9305  _cur_lexeme_contents.end = cur;
9306 
9307  _cur_lexeme = lex_number;
9308  }
9309  else
9310  {
9311  cur += 1;
9312  _cur_lexeme = lex_dot;
9313  }
9314  break;
9315 
9316  case '@':
9317  cur += 1;
9318  _cur_lexeme = lex_axis_attribute;
9319 
9320  break;
9321 
9322  case '"':
9323  case '\'':
9324  {
9325  char_t terminator = *cur;
9326 
9327  ++cur;
9328 
9329  _cur_lexeme_contents.begin = cur;
9330  while (*cur && *cur != terminator) cur++;
9331  _cur_lexeme_contents.end = cur;
9332 
9333  if (!*cur)
9334  _cur_lexeme = lex_none;
9335  else
9336  {
9337  cur += 1;
9338  _cur_lexeme = lex_quoted_string;
9339  }
9340 
9341  break;
9342  }
9343 
9344  case ':':
9345  if (*(cur+1) == ':')
9346  {
9347  cur += 2;
9348  _cur_lexeme = lex_double_colon;
9349  }
9350  else
9351  {
9352  _cur_lexeme = lex_none;
9353  }
9354  break;
9355 
9356  default:
9357  if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
9358  {
9359  _cur_lexeme_contents.begin = cur;
9360 
9361  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9362 
9363  if (*cur == '.')
9364  {
9365  cur++;
9366 
9367  while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9368  }
9369 
9370  _cur_lexeme_contents.end = cur;
9371 
9372  _cur_lexeme = lex_number;
9373  }
9374  else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
9375  {
9376  _cur_lexeme_contents.begin = cur;
9377 
9378  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9379 
9380  if (cur[0] == ':')
9381  {
9382  if (cur[1] == '*') // namespace test ncname:*
9383  {
9384  cur += 2; // :*
9385  }
9386  else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
9387  {
9388  cur++; // :
9389 
9390  while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9391  }
9392  }
9393 
9394  _cur_lexeme_contents.end = cur;
9395 
9396  _cur_lexeme = lex_string;
9397  }
9398  else
9399  {
9400  _cur_lexeme = lex_none;
9401  }
9402  }
9403 
9404  _cur = cur;
9405  }
9406 
9408  {
9409  return _cur_lexeme;
9410  }
9411 
9412  const char_t* current_pos() const
9413  {
9414  return _cur_lexeme_pos;
9415  }
9416 
9418  {
9419  assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
9420 
9421  return _cur_lexeme_contents;
9422  }
9423  };
9424 
9426  {
9428  ast_op_or, // left or right
9429  ast_op_and, // left and right
9430  ast_op_equal, // left = right
9431  ast_op_not_equal, // left != right
9432  ast_op_less, // left < right
9433  ast_op_greater, // left > right
9434  ast_op_less_or_equal, // left <= right
9435  ast_op_greater_or_equal, // left >= right
9436  ast_op_add, // left + right
9437  ast_op_subtract, // left - right
9438  ast_op_multiply, // left * right
9439  ast_op_divide, // left / right
9440  ast_op_mod, // left % right
9441  ast_op_negate, // left - right
9442  ast_op_union, // left | right
9443  ast_predicate, // apply predicate to set; next points to next predicate
9444  ast_filter, // select * from left where right
9445  ast_string_constant, // string constant
9446  ast_number_constant, // number constant
9447  ast_variable, // variable
9448  ast_func_last, // last()
9449  ast_func_position, // position()
9450  ast_func_count, // count(left)
9451  ast_func_id, // id(left)
9452  ast_func_local_name_0, // local-name()
9453  ast_func_local_name_1, // local-name(left)
9454  ast_func_namespace_uri_0, // namespace-uri()
9455  ast_func_namespace_uri_1, // namespace-uri(left)
9456  ast_func_name_0, // name()
9457  ast_func_name_1, // name(left)
9458  ast_func_string_0, // string()
9459  ast_func_string_1, // string(left)
9460  ast_func_concat, // concat(left, right, siblings)
9461  ast_func_starts_with, // starts_with(left, right)
9462  ast_func_contains, // contains(left, right)
9463  ast_func_substring_before, // substring-before(left, right)
9464  ast_func_substring_after, // substring-after(left, right)
9465  ast_func_substring_2, // substring(left, right)
9466  ast_func_substring_3, // substring(left, right, third)
9467  ast_func_string_length_0, // string-length()
9468  ast_func_string_length_1, // string-length(left)
9469  ast_func_normalize_space_0, // normalize-space()
9470  ast_func_normalize_space_1, // normalize-space(left)
9471  ast_func_translate, // translate(left, right, third)
9472  ast_func_boolean, // boolean(left)
9473  ast_func_not, // not(left)
9474  ast_func_true, // true()
9475  ast_func_false, // false()
9476  ast_func_lang, // lang(left)
9477  ast_func_number_0, // number()
9478  ast_func_number_1, // number(left)
9479  ast_func_sum, // sum(left)
9480  ast_func_floor, // floor(left)
9481  ast_func_ceiling, // ceiling(left)
9482  ast_func_round, // round(left)
9483  ast_step, // process set left with step
9484  ast_step_root, // select root node
9485 
9486  ast_opt_translate_table, // translate(left, right, third) where right/third are constants
9487  ast_opt_compare_attribute // @name = 'string'
9488  };
9489 
9490  enum axis_t
9491  {
9505  };
9506 
9508  {
9518  };
9519 
9521  {
9526  };
9527 
9529  {
9533  };
9534 
9535  template <axis_t N> struct axis_to_type
9536  {
9537  static const axis_t axis;
9538  };
9539 
9540  template <axis_t N> const axis_t axis_to_type<N>::axis = N;
9541 
9543  {
9544  private:
9545  // node type
9546  char _type;
9547  char _rettype;
9548 
9549  // for ast_step
9550  char _axis;
9551 
9552  // for ast_step/ast_predicate/ast_filter
9553  char _test;
9554 
9555  // tree node structure
9556  xpath_ast_node* _left;
9557  xpath_ast_node* _right;
9558  xpath_ast_node* _next;
9559 
9560  union
9561  {
9562  // value for ast_string_constant
9563  const char_t* string;
9564  // value for ast_number_constant
9565  double number;
9566  // variable for ast_variable
9567  xpath_variable* variable;
9568  // node test for ast_step (node name/namespace/node type/pi target)
9569  const char_t* nodetest;
9570  // table for ast_opt_translate_table
9571  const unsigned char* table;
9572  } _data;
9573 
9575  xpath_ast_node& operator=(const xpath_ast_node&);
9576 
9577  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)
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  {
9583  if (lt == xpath_type_boolean || rt == xpath_type_boolean)
9584  return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
9585  else if (lt == xpath_type_number || rt == xpath_type_number)
9586  return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
9587  else if (lt == xpath_type_string || rt == xpath_type_string)
9588  {
9589  xpath_allocator_capture cr(stack.result);
9590 
9591  xpath_string ls = lhs->eval_string(c, stack);
9592  xpath_string rs = rhs->eval_string(c, stack);
9593 
9594  return comp(ls, rs);
9595  }
9596  }
9597  else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
9598  {
9599  xpath_allocator_capture cr(stack.result);
9600 
9601  xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
9602  xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9603 
9604  for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9605  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9606  {
9607  xpath_allocator_capture cri(stack.result);
9608 
9609  if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
9610  return true;
9611  }
9612 
9613  return false;
9614  }
9615  else
9616  {
9617  if (lt == xpath_type_node_set)
9618  {
9619  swap(lhs, rhs);
9620  swap(lt, rt);
9621  }
9622 
9623  if (lt == xpath_type_boolean)
9624  return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
9625  else if (lt == xpath_type_number)
9626  {
9627  xpath_allocator_capture cr(stack.result);
9628 
9629  double l = lhs->eval_number(c, stack);
9630  xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9631 
9632  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9633  {
9634  xpath_allocator_capture cri(stack.result);
9635 
9636  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9637  return true;
9638  }
9639 
9640  return false;
9641  }
9642  else if (lt == xpath_type_string)
9643  {
9644  xpath_allocator_capture cr(stack.result);
9645 
9646  xpath_string l = lhs->eval_string(c, stack);
9647  xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9648 
9649  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9650  {
9651  xpath_allocator_capture cri(stack.result);
9652 
9653  if (comp(l, string_value(*ri, stack.result)))
9654  return true;
9655  }
9656 
9657  return false;
9658  }
9659  }
9660 
9661  assert(false && "Wrong types"); // unreachable
9662  return false;
9663  }
9664 
9665  static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval)
9666  {
9667  return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any;
9668  }
9669 
9670  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)
9671  {
9672  xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
9673 
9674  if (lt != xpath_type_node_set && rt != xpath_type_node_set)
9675  return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
9676  else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
9677  {
9678  xpath_allocator_capture cr(stack.result);
9679 
9680  xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
9681  xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9682 
9683  for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9684  {
9685  xpath_allocator_capture cri(stack.result);
9686 
9687  double l = convert_string_to_number(string_value(*li, stack.result).c_str());
9688 
9689  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9690  {
9691  xpath_allocator_capture crii(stack.result);
9692 
9693  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9694  return true;
9695  }
9696  }
9697 
9698  return false;
9699  }
9700  else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
9701  {
9702  xpath_allocator_capture cr(stack.result);
9703 
9704  double l = lhs->eval_number(c, stack);
9705  xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9706 
9707  for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9708  {
9709  xpath_allocator_capture cri(stack.result);
9710 
9711  if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9712  return true;
9713  }
9714 
9715  return false;
9716  }
9717  else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
9718  {
9719  xpath_allocator_capture cr(stack.result);
9720 
9721  xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
9722  double r = rhs->eval_number(c, stack);
9723 
9724  for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9725  {
9726  xpath_allocator_capture cri(stack.result);
9727 
9728  if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
9729  return true;
9730  }
9731 
9732  return false;
9733  }
9734  else
9735  {
9736  assert(false && "Wrong types"); // unreachable
9737  return false;
9738  }
9739  }
9740 
9741  static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)
9742  {
9743  assert(ns.size() >= first);
9744  assert(expr->rettype() != xpath_type_number);
9745 
9746  size_t i = 1;
9747  size_t size = ns.size() - first;
9748 
9749  xpath_node* last = ns.begin() + first;
9750 
9751  // remove_if... or well, sort of
9752  for (xpath_node* it = last; it != ns.end(); ++it, ++i)
9753  {
9754  xpath_context c(*it, i, size);
9755 
9756  if (expr->eval_boolean(c, stack))
9757  {
9758  *last++ = *it;
9759 
9760  if (once) break;
9761  }
9762  }
9763 
9764  ns.truncate(last);
9765  }
9766 
9767  static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)
9768  {
9769  assert(ns.size() >= first);
9770  assert(expr->rettype() == xpath_type_number);
9771 
9772  size_t i = 1;
9773  size_t size = ns.size() - first;
9774 
9775  xpath_node* last = ns.begin() + first;
9776 
9777  // remove_if... or well, sort of
9778  for (xpath_node* it = last; it != ns.end(); ++it, ++i)
9779  {
9780  xpath_context c(*it, i, size);
9781 
9782  if (expr->eval_number(c, stack) == static_cast<double>(i))
9783  {
9784  *last++ = *it;
9785 
9786  if (once) break;
9787  }
9788  }
9789 
9790  ns.truncate(last);
9791  }
9792 
9793  static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)
9794  {
9795  assert(ns.size() >= first);
9796  assert(expr->rettype() == xpath_type_number);
9797 
9798  size_t size = ns.size() - first;
9799 
9800  xpath_node* last = ns.begin() + first;
9801 
9802  xpath_context c(xpath_node(), 1, size);
9803 
9804  double er = expr->eval_number(c, stack);
9805 
9806  if (er >= 1.0 && er <= static_cast<double>(size))
9807  {
9808  size_t eri = static_cast<size_t>(er);
9809 
9810  if (er == static_cast<double>(eri))
9811  {
9812  xpath_node r = last[eri - 1];
9813 
9814  *last++ = r;
9815  }
9816  }
9817 
9818  ns.truncate(last);
9819  }
9820 
9821  void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once)
9822  {
9823  if (ns.size() == first) return;
9824 
9825  assert(_type == ast_filter || _type == ast_predicate);
9826 
9827  if (_test == predicate_constant || _test == predicate_constant_one)
9828  apply_predicate_number_const(ns, first, _right, stack);
9829  else if (_right->rettype() == xpath_type_number)
9830  apply_predicate_number(ns, first, _right, stack, once);
9831  else
9832  apply_predicate_boolean(ns, first, _right, stack, once);
9833  }
9834 
9835  void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval)
9836  {
9837  if (ns.size() == first) return;
9838 
9839  bool last_once = eval_once(ns.type(), eval);
9840 
9841  for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
9842  pred->apply_predicate(ns, first, stack, !pred->_next && last_once);
9843  }
9844 
9845  bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc)
9846  {
9847  assert(a);
9848 
9849  const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT("");
9850 
9851  switch (_test)
9852  {
9853  case nodetest_name:
9854  if (strequal(name, _data.nodetest) && is_xpath_attribute(name))
9855  {
9856  ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9857  return true;
9858  }
9859  break;
9860 
9861  case nodetest_type_node:
9862  case nodetest_all:
9863  if (is_xpath_attribute(name))
9864  {
9865  ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9866  return true;
9867  }
9868  break;
9869 
9871  if (starts_with(name, _data.nodetest) && is_xpath_attribute(name))
9872  {
9873  ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9874  return true;
9875  }
9876  break;
9877 
9878  default:
9879  ;
9880  }
9881 
9882  return false;
9883  }
9884 
9885  bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc)
9886  {
9887  assert(n);
9888 
9890 
9891  switch (_test)
9892  {
9893  case nodetest_name:
9894  if (type == node_element && n->name && strequal(n->name, _data.nodetest))
9895  {
9896  ns.push_back(xml_node(n), alloc);
9897  return true;
9898  }
9899  break;
9900 
9901  case nodetest_type_node:
9902  ns.push_back(xml_node(n), alloc);
9903  return true;
9904 
9905  case nodetest_type_comment:
9906  if (type == node_comment)
9907  {
9908  ns.push_back(xml_node(n), alloc);
9909  return true;
9910  }
9911  break;
9912 
9913  case nodetest_type_text:
9914  if (type == node_pcdata || type == node_cdata)
9915  {
9916  ns.push_back(xml_node(n), alloc);
9917  return true;
9918  }
9919  break;
9920 
9921  case nodetest_type_pi:
9922  if (type == node_pi)
9923  {
9924  ns.push_back(xml_node(n), alloc);
9925  return true;
9926  }
9927  break;
9928 
9929  case nodetest_pi:
9930  if (type == node_pi && n->name && strequal(n->name, _data.nodetest))
9931  {
9932  ns.push_back(xml_node(n), alloc);
9933  return true;
9934  }
9935  break;
9936 
9937  case nodetest_all:
9938  if (type == node_element)
9939  {
9940  ns.push_back(xml_node(n), alloc);
9941  return true;
9942  }
9943  break;
9944 
9946  if (type == node_element && n->name && starts_with(n->name, _data.nodetest))
9947  {
9948  ns.push_back(xml_node(n), alloc);
9949  return true;
9950  }
9951  break;
9952 
9953  default:
9954  assert(false && "Unknown axis"); // unreachable
9955  }
9956 
9957  return false;
9958  }
9959 
9960  template <class T> void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T)
9961  {
9962  const axis_t axis = T::axis;
9963 
9964  switch (axis)
9965  {
9966  case axis_attribute:
9967  {
9968  for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute)
9969  if (step_push(ns, a, n, alloc) & once)
9970  return;
9971 
9972  break;
9973  }
9974 
9975  case axis_child:
9976  {
9977  for (xml_node_struct* c = n->first_child; c; c = c->next_sibling)
9978  if (step_push(ns, c, alloc) & once)
9979  return;
9980 
9981  break;
9982  }
9983 
9984  case axis_descendant:
9986  {
9987  if (axis == axis_descendant_or_self)
9988  if (step_push(ns, n, alloc) & once)
9989  return;
9990 
9991  xml_node_struct* cur = n->first_child;
9992 
9993  while (cur)
9994  {
9995  if (step_push(ns, cur, alloc) & once)
9996  return;
9997 
9998  if (cur->first_child)
9999  cur = cur->first_child;
10000  else
10001  {
10002  while (!cur->next_sibling)
10003  {
10004  cur = cur->parent;
10005 
10006  if (cur == n) return;
10007  }
10008 
10009  cur = cur->next_sibling;
10010  }
10011  }
10012 
10013  break;
10014  }
10015 
10017  {
10018  for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling)
10019  if (step_push(ns, c, alloc) & once)
10020  return;
10021 
10022  break;
10023  }
10024 
10026  {
10027  for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c)
10028  if (step_push(ns, c, alloc) & once)
10029  return;
10030 
10031  break;
10032  }
10033 
10034  case axis_following:
10035  {
10036  xml_node_struct* cur = n;
10037 
10038  // exit from this node so that we don't include descendants
10039  while (!cur->next_sibling)
10040  {
10041  cur = cur->parent;
10042 
10043  if (!cur) return;
10044  }
10045 
10046  cur = cur->next_sibling;
10047 
10048  while (cur)
10049  {
10050  if (step_push(ns, cur, alloc) & once)
10051  return;
10052 
10053  if (cur->first_child)
10054  cur = cur->first_child;
10055  else
10056  {
10057  while (!cur->next_sibling)
10058  {
10059  cur = cur->parent;
10060 
10061  if (!cur) return;
10062  }
10063 
10064  cur = cur->next_sibling;
10065  }
10066  }
10067 
10068  break;
10069  }
10070 
10071  case axis_preceding:
10072  {
10073  xml_node_struct* cur = n;
10074 
10075  // exit from this node so that we don't include descendants
10076  while (!cur->prev_sibling_c->next_sibling)
10077  {
10078  cur = cur->parent;
10079 
10080  if (!cur) return;
10081  }
10082 
10083  cur = cur->prev_sibling_c;
10084 
10085  while (cur)
10086  {
10087  if (cur->first_child)
10088  cur = cur->first_child->prev_sibling_c;
10089  else
10090  {
10091  // leaf node, can't be ancestor
10092  if (step_push(ns, cur, alloc) & once)
10093  return;
10094 
10095  while (!cur->prev_sibling_c->next_sibling)
10096  {
10097  cur = cur->parent;
10098 
10099  if (!cur) return;
10100 
10101  if (!node_is_ancestor(cur, n))
10102  if (step_push(ns, cur, alloc) & once)
10103  return;
10104  }
10105 
10106  cur = cur->prev_sibling_c;
10107  }
10108  }
10109 
10110  break;
10111  }
10112 
10113  case axis_ancestor:
10114  case axis_ancestor_or_self:
10115  {
10116  if (axis == axis_ancestor_or_self)
10117  if (step_push(ns, n, alloc) & once)
10118  return;
10119 
10120  xml_node_struct* cur = n->parent;
10121 
10122  while (cur)
10123  {
10124  if (step_push(ns, cur, alloc) & once)
10125  return;
10126 
10127  cur = cur->parent;
10128  }
10129 
10130  break;
10131  }
10132 
10133  case axis_self:
10134  {
10135  step_push(ns, n, alloc);
10136 
10137  break;
10138  }
10139 
10140  case axis_parent:
10141  {
10142  if (n->parent)
10143  step_push(ns, n->parent, alloc);
10144 
10145  break;
10146  }
10147 
10148  default:
10149  assert(false && "Unimplemented axis"); // unreachable
10150  }
10151  }
10152 
10153  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)
10154  {
10155  const axis_t axis = T::axis;
10156 
10157  switch (axis)
10158  {
10159  case axis_ancestor:
10160  case axis_ancestor_or_self:
10161  {
10162  if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test
10163  if (step_push(ns, a, p, alloc) & once)
10164  return;
10165 
10166  xml_node_struct* cur = p;
10167 
10168  while (cur)
10169  {
10170  if (step_push(ns, cur, alloc) & once)
10171  return;
10172 
10173  cur = cur->parent;
10174  }
10175 
10176  break;
10177  }
10178 
10180  case axis_self:
10181  {
10182  if (_test == nodetest_type_node) // reject attributes based on principal node type test
10183  step_push(ns, a, p, alloc);
10184 
10185  break;
10186  }
10187 
10188  case axis_following:
10189  {
10190  xml_node_struct* cur = p;
10191 
10192  while (cur)
10193  {
10194  if (cur->first_child)
10195  cur = cur->first_child;
10196  else
10197  {
10198  while (!cur->next_sibling)
10199  {
10200  cur = cur->parent;
10201 
10202  if (!cur) return;
10203  }
10204 
10205  cur = cur->next_sibling;
10206  }
10207 
10208  if (step_push(ns, cur, alloc) & once)
10209  return;
10210  }
10211 
10212  break;
10213  }
10214 
10215  case axis_parent:
10216  {
10217  step_push(ns, p, alloc);
10218 
10219  break;
10220  }
10221 
10222  case axis_preceding:
10223  {
10224  // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding
10225  step_fill(ns, p, alloc, once, v);
10226  break;
10227  }
10228 
10229  default:
10230  assert(false && "Unimplemented axis"); // unreachable
10231  }
10232  }
10233 
10234  template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v)
10235  {
10236  const axis_t axis = T::axis;
10237  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);
10238 
10239  if (xn.node())
10240  step_fill(ns, xn.node().internal_object(), alloc, once, v);
10241  else if (axis_has_attributes && xn.attribute() && xn.parent())
10242  step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v);
10243  }
10244 
10245  template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v)
10246  {
10247  const axis_t axis = T::axis;
10248  const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);
10249  const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
10250 
10251  bool once =
10252  (axis == axis_attribute && _test == nodetest_name) ||
10253  (!_right && eval_once(axis_type, eval)) ||
10254  // coverity[mixed_enums]
10255  (_right && !_right->_next && _right->_test == predicate_constant_one);
10256 
10257  xpath_node_set_raw ns;
10258  ns.set_type(axis_type);
10259 
10260  if (_left)
10261  {
10262  xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all);
10263 
10264  // self axis preserves the original order
10265  if (axis == axis_self) ns.set_type(s.type());
10266 
10267  for (const xpath_node* it = s.begin(); it != s.end(); ++it)
10268  {
10269  size_t size = ns.size();
10270 
10271  // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes
10272  if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
10273 
10274  step_fill(ns, *it, stack.result, once, v);
10275  if (_right) apply_predicates(ns, size, stack, eval);
10276  }
10277  }
10278  else
10279  {
10280  step_fill(ns, c.n, stack.result, once, v);
10281  if (_right) apply_predicates(ns, 0, stack, eval);
10282  }
10283 
10284  // child, attribute and self axes always generate unique set of nodes
10285  // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice
10286  if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)
10287  ns.remove_duplicates(stack.temp);
10288 
10289  return ns;
10290  }
10291 
10292  public:
10293  xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value):
10294  _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10295  {
10296  assert(type == ast_string_constant);
10297  _data.string = value;
10298  }
10299 
10300  xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value):
10301  _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10302  {
10303  assert(type == ast_number_constant);
10304  _data.number = value;
10305  }
10306 
10307  xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):
10308  _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10309  {
10310  assert(type == ast_variable);
10311  _data.variable = value;
10312  }
10313 
10315  _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
10316  {
10317  }
10318 
10319  xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents):
10320  _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)
10321  {
10322  assert(type == ast_step);
10323  _data.nodetest = contents;
10324  }
10325 
10327  _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast<char>(test)), _left(left), _right(right), _next(0)
10328  {
10329  assert(type == ast_filter || type == ast_predicate);
10330  }
10331 
10333  {
10334  _next = value;
10335  }
10336 
10338  {
10339  _right = value;
10340  }
10341 
10342  bool eval_boolean(const xpath_context& c, const xpath_stack& stack)
10343  {
10344  switch (_type)
10345  {
10346  case ast_op_or:
10347  return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
10348 
10349  case ast_op_and:
10350  return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
10351 
10352  case ast_op_equal:
10353  return compare_eq(_left, _right, c, stack, equal_to());
10354 
10355  case ast_op_not_equal:
10356  return compare_eq(_left, _right, c, stack, not_equal_to());
10357 
10358  case ast_op_less:
10359  return compare_rel(_left, _right, c, stack, less());
10360 
10361  case ast_op_greater:
10362  return compare_rel(_right, _left, c, stack, less());
10363 
10364  case ast_op_less_or_equal:
10365  return compare_rel(_left, _right, c, stack, less_equal());
10366 
10368  return compare_rel(_right, _left, c, stack, less_equal());
10369 
10370  case ast_func_starts_with:
10371  {
10372  xpath_allocator_capture cr(stack.result);
10373 
10374  xpath_string lr = _left->eval_string(c, stack);
10375  xpath_string rr = _right->eval_string(c, stack);
10376 
10377  return starts_with(lr.c_str(), rr.c_str());
10378  }
10379 
10380  case ast_func_contains:
10381  {
10382  xpath_allocator_capture cr(stack.result);
10383 
10384  xpath_string lr = _left->eval_string(c, stack);
10385  xpath_string rr = _right->eval_string(c, stack);
10386 
10387  return find_substring(lr.c_str(), rr.c_str()) != 0;
10388  }
10389 
10390  case ast_func_boolean:
10391  return _left->eval_boolean(c, stack);
10392 
10393  case ast_func_not:
10394  return !_left->eval_boolean(c, stack);
10395 
10396  case ast_func_true:
10397  return true;
10398 
10399  case ast_func_false:
10400  return false;
10401 
10402  case ast_func_lang:
10403  {
10404  if (c.n.attribute()) return false;
10405 
10406  xpath_allocator_capture cr(stack.result);
10407 
10408  xpath_string lang = _left->eval_string(c, stack);
10409 
10410  for (xml_node n = c.n.node(); n; n = n.parent())
10411  {
10412  xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
10413 
10414  if (a)
10415  {
10416  const char_t* value = a.value();
10417 
10418  // strnicmp / strncasecmp is not portable
10419  for (const char_t* lit = lang.c_str(); *lit; ++lit)
10420  {
10421  if (tolower_ascii(*lit) != tolower_ascii(*value)) return false;
10422  ++value;
10423  }
10424 
10425  return *value == 0 || *value == '-';
10426  }
10427  }
10428 
10429  return false;
10430  }
10431 
10433  {
10434  const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string();
10435 
10436  xml_attribute attr = c.n.node().attribute(_left->_data.nodetest);
10437 
10438  return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name());
10439  }
10440 
10441  case ast_variable:
10442  {
10443  assert(_rettype == _data.variable->type());
10444 
10445  if (_rettype == xpath_type_boolean)
10446  return _data.variable->get_boolean();
10447 
10448  // variable needs to be converted to the correct type, this is handled by the fallthrough block below
10449  break;
10450  }
10451 
10452  default:
10453  ;
10454  }
10455 
10456  // none of the ast types that return the value directly matched, we need to perform type conversion
10457  switch (_rettype)
10458  {
10459  case xpath_type_number:
10460  return convert_number_to_boolean(eval_number(c, stack));
10461 
10462  case xpath_type_string:
10463  {
10464  xpath_allocator_capture cr(stack.result);
10465 
10466  return !eval_string(c, stack).empty();
10467  }
10468 
10469  case xpath_type_node_set:
10470  {
10471  xpath_allocator_capture cr(stack.result);
10472 
10473  return !eval_node_set(c, stack, nodeset_eval_any).empty();
10474  }
10475 
10476  default:
10477  assert(false && "Wrong expression for return type boolean"); // unreachable
10478  return false;
10479  }
10480  }
10481 
10482  double eval_number(const xpath_context& c, const xpath_stack& stack)
10483  {
10484  switch (_type)
10485  {
10486  case ast_op_add:
10487  return _left->eval_number(c, stack) + _right->eval_number(c, stack);
10488 
10489  case ast_op_subtract:
10490  return _left->eval_number(c, stack) - _right->eval_number(c, stack);
10491 
10492  case ast_op_multiply:
10493  return _left->eval_number(c, stack) * _right->eval_number(c, stack);
10494 
10495  case ast_op_divide:
10496  return _left->eval_number(c, stack) / _right->eval_number(c, stack);
10497 
10498  case ast_op_mod:
10499  return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
10500 
10501  case ast_op_negate:
10502  return -_left->eval_number(c, stack);
10503 
10504  case ast_number_constant:
10505  return _data.number;
10506 
10507  case ast_func_last:
10508  return static_cast<double>(c.size);
10509 
10510  case ast_func_position:
10511  return static_cast<double>(c.position);
10512 
10513  case ast_func_count:
10514  {
10515  xpath_allocator_capture cr(stack.result);
10516 
10517  return static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size());
10518  }
10519 
10521  {
10522  xpath_allocator_capture cr(stack.result);
10523 
10524  return static_cast<double>(string_value(c.n, stack.result).length());
10525  }
10526 
10528  {
10529  xpath_allocator_capture cr(stack.result);
10530 
10531  return static_cast<double>(_left->eval_string(c, stack).length());
10532  }
10533 
10534  case ast_func_number_0:
10535  {
10536  xpath_allocator_capture cr(stack.result);
10537 
10538  return convert_string_to_number(string_value(c.n, stack.result).c_str());
10539  }
10540 
10541  case ast_func_number_1:
10542  return _left->eval_number(c, stack);
10543 
10544  case ast_func_sum:
10545  {
10546  xpath_allocator_capture cr(stack.result);
10547 
10548  double r = 0;
10549 
10550  xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all);
10551 
10552  for (const xpath_node* it = ns.begin(); it != ns.end(); ++it)
10553  {
10554  xpath_allocator_capture cri(stack.result);
10555 
10556  r += convert_string_to_number(string_value(*it, stack.result).c_str());
10557  }
10558 
10559  return r;
10560  }
10561 
10562  case ast_func_floor:
10563  {
10564  double r = _left->eval_number(c, stack);
10565 
10566  return r == r ? floor(r) : r;
10567  }
10568 
10569  case ast_func_ceiling:
10570  {
10571  double r = _left->eval_number(c, stack);
10572 
10573  return r == r ? ceil(r) : r;
10574  }
10575 
10576  case ast_func_round:
10577  return round_nearest_nzero(_left->eval_number(c, stack));
10578 
10579  case ast_variable:
10580  {
10581  assert(_rettype == _data.variable->type());
10582 
10583  if (_rettype == xpath_type_number)
10584  return _data.variable->get_number();
10585 
10586  // variable needs to be converted to the correct type, this is handled by the fallthrough block below
10587  break;
10588  }
10589 
10590  default:
10591  ;
10592  }
10593 
10594  // none of the ast types that return the value directly matched, we need to perform type conversion
10595  switch (_rettype)
10596  {
10597  case xpath_type_boolean:
10598  return eval_boolean(c, stack) ? 1 : 0;
10599 
10600  case xpath_type_string:
10601  {
10602  xpath_allocator_capture cr(stack.result);
10603 
10604  return convert_string_to_number(eval_string(c, stack).c_str());
10605  }
10606 
10607  case xpath_type_node_set:
10608  {
10609  xpath_allocator_capture cr(stack.result);
10610 
10611  return convert_string_to_number(eval_string(c, stack).c_str());
10612  }
10613 
10614  default:
10615  assert(false && "Wrong expression for return type number"); // unreachable
10616  return 0;
10617  }
10618  }
10619 
10621  {
10622  assert(_type == ast_func_concat);
10623 
10624  xpath_allocator_capture ct(stack.temp);
10625 
10626  // count the string number
10627  size_t count = 1;
10628  for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
10629 
10630  // allocate a buffer for temporary string objects
10631  xpath_string* buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string)));
10632  if (!buffer) return xpath_string();
10633 
10634  // evaluate all strings to temporary stack
10635  xpath_stack swapped_stack = {stack.temp, stack.result};
10636 
10637  buffer[0] = _left->eval_string(c, swapped_stack);
10638 
10639  size_t pos = 1;
10640  for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
10641  assert(pos == count);
10642 
10643  // get total length
10644  size_t length = 0;
10645  for (size_t i = 0; i < count; ++i) length += buffer[i].length();
10646 
10647  // create final string
10648  char_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t)));
10649  if (!result) return xpath_string();
10650 
10651  char_t* ri = result;
10652 
10653  for (size_t j = 0; j < count; ++j)
10654  for (const char_t* bi = buffer[j].c_str(); *bi; ++bi)
10655  *ri++ = *bi;
10656 
10657  *ri = 0;
10658 
10659  return xpath_string::from_heap_preallocated(result, ri);
10660  }
10661 
10663  {
10664  switch (_type)
10665  {
10666  case ast_string_constant:
10667  return xpath_string::from_const(_data.string);
10668 
10669  case ast_func_local_name_0:
10670  {
10671  xpath_node na = c.n;
10672 
10674  }
10675 
10676  case ast_func_local_name_1:
10677  {
10678  xpath_allocator_capture cr(stack.result);
10679 
10680  xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10681  xpath_node na = ns.first();
10682 
10684  }
10685 
10686  case ast_func_name_0:
10687  {
10688  xpath_node na = c.n;
10689 
10691  }
10692 
10693  case ast_func_name_1:
10694  {
10695  xpath_allocator_capture cr(stack.result);
10696 
10697  xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10698  xpath_node na = ns.first();
10699 
10701  }
10702 
10704  {
10705  xpath_node na = c.n;
10706 
10708  }
10709 
10711  {
10712  xpath_allocator_capture cr(stack.result);
10713 
10714  xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10715  xpath_node na = ns.first();
10716 
10718  }
10719 
10720  case ast_func_string_0:
10721  return string_value(c.n, stack.result);
10722 
10723  case ast_func_string_1:
10724  return _left->eval_string(c, stack);
10725 
10726  case ast_func_concat:
10727  return eval_string_concat(c, stack);
10728 
10730  {
10731  xpath_allocator_capture cr(stack.temp);
10732 
10733  xpath_stack swapped_stack = {stack.temp, stack.result};
10734 
10735  xpath_string s = _left->eval_string(c, swapped_stack);
10736  xpath_string p = _right->eval_string(c, swapped_stack);
10737 
10738  const char_t* pos = find_substring(s.c_str(), p.c_str());
10739 
10740  return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string();
10741  }
10742 
10744  {
10745  xpath_allocator_capture cr(stack.temp);
10746 
10747  xpath_stack swapped_stack = {stack.temp, stack.result};
10748 
10749  xpath_string s = _left->eval_string(c, swapped_stack);
10750  xpath_string p = _right->eval_string(c, swapped_stack);
10751 
10752  const char_t* pos = find_substring(s.c_str(), p.c_str());
10753  if (!pos) return xpath_string();
10754 
10755  const char_t* rbegin = pos + p.length();
10756  const char_t* rend = s.c_str() + s.length();
10757 
10758  return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
10759  }
10760 
10761  case ast_func_substring_2:
10762  {
10763  xpath_allocator_capture cr(stack.temp);
10764 
10765  xpath_stack swapped_stack = {stack.temp, stack.result};
10766 
10767  xpath_string s = _left->eval_string(c, swapped_stack);
10768  size_t s_length = s.length();
10769 
10770  double first = round_nearest(_right->eval_number(c, stack));
10771 
10772  if (is_nan(first)) return xpath_string(); // NaN
10773  else if (first >= static_cast<double>(s_length + 1)) return xpath_string();
10774 
10776  assert(1 <= pos && pos <= s_length + 1);
10777 
10778  const char_t* rbegin = s.c_str() + (pos - 1);
10779  const char_t* rend = s.c_str() + s.length();
10780 
10781  return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
10782  }
10783 
10784  case ast_func_substring_3:
10785  {
10786  xpath_allocator_capture cr(stack.temp);
10787 
10788  xpath_stack swapped_stack = {stack.temp, stack.result};
10789 
10790  xpath_string s = _left->eval_string(c, swapped_stack);
10791  size_t s_length = s.length();
10792 
10793  double first = round_nearest(_right->eval_number(c, stack));
10794  double last = first + round_nearest(_right->_next->eval_number(c, stack));
10795 
10796  if (is_nan(first) || is_nan(last)) return xpath_string();
10797  else if (first >= static_cast<double>(s_length + 1)) return xpath_string();
10798  else if (first >= last) return xpath_string();
10799  else if (last < 1) return xpath_string();
10800 
10802  size_t end = last >= static_cast<double>(s_length + 1) ? s_length + 1 : static_cast<size_t>(last);
10803 
10804  assert(1 <= pos && pos <= end && end <= s_length + 1);
10805  const char_t* rbegin = s.c_str() + (pos - 1);
10806  const char_t* rend = s.c_str() + (end - 1);
10807 
10808  return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result);
10809  }
10810 
10812  {
10813  xpath_string s = string_value(c.n, stack.result);
10814 
10815  char_t* begin = s.data(stack.result);
10816  if (!begin) return xpath_string();
10817 
10818  char_t* end = normalize_space(begin);
10819 
10820  return xpath_string::from_heap_preallocated(begin, end);
10821  }
10822 
10824  {
10825  xpath_string s = _left->eval_string(c, stack);
10826 
10827  char_t* begin = s.data(stack.result);
10828  if (!begin) return xpath_string();
10829 
10830  char_t* end = normalize_space(begin);
10831 
10832  return xpath_string::from_heap_preallocated(begin, end);
10833  }
10834 
10835  case ast_func_translate:
10836  {
10837  xpath_allocator_capture cr(stack.temp);
10838 
10839  xpath_stack swapped_stack = {stack.temp, stack.result};
10840 
10841  xpath_string s = _left->eval_string(c, stack);
10842  xpath_string from = _right->eval_string(c, swapped_stack);
10843  xpath_string to = _right->_next->eval_string(c, swapped_stack);
10844 
10845  char_t* begin = s.data(stack.result);
10846  if (!begin) return xpath_string();
10847 
10848  char_t* end = translate(begin, from.c_str(), to.c_str(), to.length());
10849 
10850  return xpath_string::from_heap_preallocated(begin, end);
10851  }
10852 
10854  {
10855  xpath_string s = _left->eval_string(c, stack);
10856 
10857  char_t* begin = s.data(stack.result);
10858  if (!begin) return xpath_string();
10859 
10860  char_t* end = translate_table(begin, _data.table);
10861 
10862  return xpath_string::from_heap_preallocated(begin, end);
10863  }
10864 
10865  case ast_variable:
10866  {
10867  assert(_rettype == _data.variable->type());
10868 
10869  if (_rettype == xpath_type_string)
10870  return xpath_string::from_const(_data.variable->get_string());
10871 
10872  // variable needs to be converted to the correct type, this is handled by the fallthrough block below
10873  break;
10874  }
10875 
10876  default:
10877  ;
10878  }
10879 
10880  // none of the ast types that return the value directly matched, we need to perform type conversion
10881  switch (_rettype)
10882  {
10883  case xpath_type_boolean:
10884  return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
10885 
10886  case xpath_type_number:
10887  return convert_number_to_string(eval_number(c, stack), stack.result);
10888 
10889  case xpath_type_node_set:
10890  {
10891  xpath_allocator_capture cr(stack.temp);
10892 
10893  xpath_stack swapped_stack = {stack.temp, stack.result};
10894 
10895  xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first);
10896  return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
10897  }
10898 
10899  default:
10900  assert(false && "Wrong expression for return type string"); // unreachable
10901  return xpath_string();
10902  }
10903  }
10904 
10906  {
10907  switch (_type)
10908  {
10909  case ast_op_union:
10910  {
10911  xpath_allocator_capture cr(stack.temp);
10912 
10913  xpath_stack swapped_stack = {stack.temp, stack.result};
10914 
10915  xpath_node_set_raw ls = _left->eval_node_set(c, stack, eval);
10916  xpath_node_set_raw rs = _right->eval_node_set(c, swapped_stack, eval);
10917 
10918  // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
10919  ls.set_type(xpath_node_set::type_unsorted);
10920 
10921  ls.append(rs.begin(), rs.end(), stack.result);
10922  ls.remove_duplicates(stack.temp);
10923 
10924  return ls;
10925  }
10926 
10927  case ast_filter:
10928  {
10930 
10931  // either expression is a number or it contains position() call; sort by document order
10932  if (_test != predicate_posinv) set.sort_do();
10933 
10934  bool once = eval_once(set.type(), eval);
10935 
10936  apply_predicate(set, 0, stack, once);
10937 
10938  return set;
10939  }
10940 
10941  case ast_func_id:
10942  return xpath_node_set_raw();
10943 
10944  case ast_step:
10945  {
10946  switch (_axis)
10947  {
10948  case axis_ancestor:
10949  return step_do(c, stack, eval, axis_to_type<axis_ancestor>());
10950 
10951  case axis_ancestor_or_self:
10952  return step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>());
10953 
10954  case axis_attribute:
10955  return step_do(c, stack, eval, axis_to_type<axis_attribute>());
10956 
10957  case axis_child:
10958  return step_do(c, stack, eval, axis_to_type<axis_child>());
10959 
10960  case axis_descendant:
10961  return step_do(c, stack, eval, axis_to_type<axis_descendant>());
10962 
10964  return step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>());
10965 
10966  case axis_following:
10967  return step_do(c, stack, eval, axis_to_type<axis_following>());
10968 
10970  return step_do(c, stack, eval, axis_to_type<axis_following_sibling>());
10971 
10972  case axis_namespace:
10973  // namespaced axis is not supported
10974  return xpath_node_set_raw();
10975 
10976  case axis_parent:
10977  return step_do(c, stack, eval, axis_to_type<axis_parent>());
10978 
10979  case axis_preceding:
10980  return step_do(c, stack, eval, axis_to_type<axis_preceding>());
10981 
10983  return step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>());
10984 
10985  case axis_self:
10986  return step_do(c, stack, eval, axis_to_type<axis_self>());
10987 
10988  default:
10989  assert(false && "Unknown axis"); // unreachable
10990  return xpath_node_set_raw();
10991  }
10992  }
10993 
10994  case ast_step_root:
10995  {
10996  assert(!_right); // root step can't have any predicates
10997 
10998  xpath_node_set_raw ns;
10999 
11000  ns.set_type(xpath_node_set::type_sorted);
11001 
11002  if (c.n.node()) ns.push_back(c.n.node().root(), stack.result);
11003  else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);
11004 
11005  return ns;
11006  }
11007 
11008  case ast_variable:
11009  {
11010  assert(_rettype == _data.variable->type());
11011 
11012  if (_rettype == xpath_type_node_set)
11013  {
11014  const xpath_node_set& s = _data.variable->get_node_set();
11015 
11016  xpath_node_set_raw ns;
11017 
11018  ns.set_type(s.type());
11019  ns.append(s.begin(), s.end(), stack.result);
11020 
11021  return ns;
11022  }
11023 
11024  // variable needs to be converted to the correct type, this is handled by the fallthrough block below
11025  break;
11026  }
11027 
11028  default:
11029  ;
11030  }
11031 
11032  // none of the ast types that return the value directly matched, but conversions to node set are invalid
11033  assert(false && "Wrong expression for return type node set"); // unreachable
11034  return xpath_node_set_raw();
11035  }
11036 
11038  {
11039  if (_left)
11040  _left->optimize(alloc);
11041 
11042  if (_right)
11043  _right->optimize(alloc);
11044 
11045  if (_next)
11046  _next->optimize(alloc);
11047 
11048  // coverity[var_deref_model]
11049  optimize_self(alloc);
11050  }
11051 
11053  {
11054  // Rewrite [position()=expr] with [expr]
11055  // Note that this step has to go before classification to recognize [position()=1]
11056  if ((_type == ast_filter || _type == ast_predicate) &&
11057  _right && // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate)
11058  _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number)
11059  {
11060  _right = _right->_right;
11061  }
11062 
11063  // Classify filter/predicate ops to perform various optimizations during evaluation
11064  if ((_type == ast_filter || _type == ast_predicate) && _right) // workaround for clang static analyzer (_right is never null for ast_filter/ast_predicate)
11065  {
11066  assert(_test == predicate_default);
11067 
11068  if (_right->_type == ast_number_constant && _right->_data.number == 1.0)
11069  _test = predicate_constant_one;
11070  else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last))
11071  _test = predicate_constant;
11072  else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr())
11073  _test = predicate_posinv;
11074  }
11075 
11076  // Rewrite descendant-or-self::node()/child::foo with descendant::foo
11077  // The former is a full form of //foo, the latter is much faster since it executes the node test immediately
11078  // Do a similar kind of rewrite for self/descendant/descendant-or-self axes
11079  // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1])
11080  if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) &&
11081  _left && _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right &&
11082  is_posinv_step())
11083  {
11084  if (_axis == axis_child || _axis == axis_descendant)
11085  _axis = axis_descendant;
11086  else
11087  _axis = axis_descendant_or_self;
11088 
11089  _left = _left->_left;
11090  }
11091 
11092  // Use optimized lookup table implementation for translate() with constant arguments
11093  if (_type == ast_func_translate &&
11094  _right && // workaround for clang static analyzer (_right is never null for ast_func_translate)
11095  _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant)
11096  {
11097  unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string);
11098 
11099  if (table)
11100  {
11101  _type = ast_opt_translate_table;
11102  _data.table = table;
11103  }
11104  }
11105 
11106  // Use optimized path for @attr = 'value' or @attr = $value
11107  if (_type == ast_op_equal &&
11108  _left && _right && // workaround for clang static analyzer and Coverity (_left and _right are never null for ast_op_equal)
11109  // coverity[mixed_enums]
11110  _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right &&
11111  (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string)))
11112  {
11113  _type = ast_opt_compare_attribute;
11114  }
11115  }
11116 
11117  bool is_posinv_expr() const
11118  {
11119  switch (_type)
11120  {
11121  case ast_func_position:
11122  case ast_func_last:
11123  return false;
11124 
11125  case ast_string_constant:
11126  case ast_number_constant:
11127  case ast_variable:
11128  return true;
11129 
11130  case ast_step:
11131  case ast_step_root:
11132  return true;
11133 
11134  case ast_predicate:
11135  case ast_filter:
11136  return true;
11137 
11138  default:
11139  if (_left && !_left->is_posinv_expr()) return false;
11140 
11141  for (xpath_ast_node* n = _right; n; n = n->_next)
11142  if (!n->is_posinv_expr()) return false;
11143 
11144  return true;
11145  }
11146  }
11147 
11148  bool is_posinv_step() const
11149  {
11150  assert(_type == ast_step);
11151 
11152  for (xpath_ast_node* n = _right; n; n = n->_next)
11153  {
11154  assert(n->_type == ast_predicate);
11155 
11156  if (n->_test != predicate_posinv)
11157  return false;
11158  }
11159 
11160  return true;
11161  }
11162 
11164  {
11165  return static_cast<xpath_value_type>(_rettype);
11166  }
11167  };
11168 
11169  static const size_t xpath_ast_depth_limit =
11170  #ifdef PUGIXML_XPATH_DEPTH_LIMIT
11171  PUGIXML_XPATH_DEPTH_LIMIT
11172  #else
11173  1024
11174  #endif
11175  ;
11176 
11178  {
11181 
11182  const char_t* _query;
11183  xpath_variable_set* _variables;
11184 
11185  xpath_parse_result* _result;
11186 
11187  char_t _scratch[32];
11188 
11189  size_t _depth;
11190 
11192  {
11193  _result->error = message;
11194  _result->offset = _lexer.current_pos() - _query;
11195 
11196  return 0;
11197  }
11198 
11200  {
11201  assert(_alloc->_error);
11202  *_alloc->_error = true;
11203 
11204  return 0;
11205  }
11206 
11208  {
11209  return error("Exceeded maximum allowed query depth");
11210  }
11211 
11212  void* alloc_node()
11213  {
11214  return _alloc->allocate(sizeof(xpath_ast_node));
11215  }
11216 
11217  xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, const char_t* value)
11218  {
11219  void* memory = alloc_node();
11220  return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
11221  }
11222 
11224  {
11225  void* memory = alloc_node();
11226  return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
11227  }
11228 
11229  xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value)
11230  {
11231  void* memory = alloc_node();
11232  return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
11233  }
11234 
11236  {
11237  void* memory = alloc_node();
11238  return memory ? new (memory) xpath_ast_node(type, rettype, left, right) : 0;
11239  }
11240 
11242  {
11243  void* memory = alloc_node();
11244  return memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : 0;
11245  }
11246 
11248  {
11249  void* memory = alloc_node();
11250  return memory ? new (memory) xpath_ast_node(type, left, right, test) : 0;
11251  }
11252 
11253  const char_t* alloc_string(const xpath_lexer_string& value)
11254  {
11255  if (!value.begin)
11256  return PUGIXML_TEXT("");
11257 
11258  size_t length = static_cast<size_t>(value.end - value.begin);
11259 
11260  char_t* c = static_cast<char_t*>(_alloc->allocate((length + 1) * sizeof(char_t)));
11261  if (!c) return 0;
11262 
11263  memcpy(c, value.begin, length * sizeof(char_t));
11264  c[length] = 0;
11265 
11266  return c;
11267  }
11268 
11270  {
11271  switch (name.begin[0])
11272  {
11273  case 'b':
11274  if (name == PUGIXML_TEXT("boolean") && argc == 1)
11276 
11277  break;
11278 
11279  case 'c':
11280  if (name == PUGIXML_TEXT("count") && argc == 1)
11281  {
11282  if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11283  return alloc_node(ast_func_count, xpath_type_number, args[0]);
11284  }
11285  else if (name == PUGIXML_TEXT("contains") && argc == 2)
11286  return alloc_node(ast_func_contains, xpath_type_boolean, args[0], args[1]);
11287  else if (name == PUGIXML_TEXT("concat") && argc >= 2)
11288  return alloc_node(ast_func_concat, xpath_type_string, args[0], args[1]);
11289  else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
11290  return alloc_node(ast_func_ceiling, xpath_type_number, args[0]);
11291 
11292  break;
11293 
11294  case 'f':
11295  if (name == PUGIXML_TEXT("false") && argc == 0)
11297  else if (name == PUGIXML_TEXT("floor") && argc == 1)
11298  return alloc_node(ast_func_floor, xpath_type_number, args[0]);
11299 
11300  break;
11301 
11302  case 'i':
11303  if (name == PUGIXML_TEXT("id") && argc == 1)
11304  return alloc_node(ast_func_id, xpath_type_node_set, args[0]);
11305 
11306  break;
11307 
11308  case 'l':
11309  if (name == PUGIXML_TEXT("last") && argc == 0)
11311  else if (name == PUGIXML_TEXT("lang") && argc == 1)
11312  return alloc_node(ast_func_lang, xpath_type_boolean, args[0]);
11313  else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
11314  {
11315  if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11317  }
11318 
11319  break;
11320 
11321  case 'n':
11322  if (name == PUGIXML_TEXT("name") && argc <= 1)
11323  {
11324  if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11325  return alloc_node(argc == 0 ? ast_func_name_0 : ast_func_name_1, xpath_type_string, args[0]);
11326  }
11327  else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1)
11328  {
11329  if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11331  }
11332  else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
11333  return alloc_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);
11334  else if (name == PUGIXML_TEXT("not") && argc == 1)
11335  return alloc_node(ast_func_not, xpath_type_boolean, args[0]);
11336  else if (name == PUGIXML_TEXT("number") && argc <= 1)
11337  return alloc_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
11338 
11339  break;
11340 
11341  case 'p':
11342  if (name == PUGIXML_TEXT("position") && argc == 0)
11344 
11345  break;
11346 
11347  case 'r':
11348  if (name == PUGIXML_TEXT("round") && argc == 1)
11349  return alloc_node(ast_func_round, xpath_type_number, args[0]);
11350 
11351  break;
11352 
11353  case 's':
11354  if (name == PUGIXML_TEXT("string") && argc <= 1)
11355  return alloc_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
11356  else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
11358  else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
11359  return alloc_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
11360  else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
11361  return alloc_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
11362  else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
11363  return alloc_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
11364  else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
11365  return alloc_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
11366  else if (name == PUGIXML_TEXT("sum") && argc == 1)
11367  {
11368  if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
11369  return alloc_node(ast_func_sum, xpath_type_number, args[0]);
11370  }
11371 
11372  break;
11373 
11374  case 't':
11375  if (name == PUGIXML_TEXT("translate") && argc == 3)
11376  return alloc_node(ast_func_translate, xpath_type_string, args[0], args[1]);
11377  else if (name == PUGIXML_TEXT("true") && argc == 0)
11379 
11380  break;
11381 
11382  default:
11383  break;
11384  }
11385 
11386  return error("Unrecognized function or wrong parameter count");
11387  }
11388 
11389  axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified)
11390  {
11391  specified = true;
11392 
11393  switch (name.begin[0])
11394  {
11395  case 'a':
11396  if (name == PUGIXML_TEXT("ancestor"))
11397  return axis_ancestor;
11398  else if (name == PUGIXML_TEXT("ancestor-or-self"))
11399  return axis_ancestor_or_self;
11400  else if (name == PUGIXML_TEXT("attribute"))
11401  return axis_attribute;
11402 
11403  break;
11404 
11405  case 'c':
11406  if (name == PUGIXML_TEXT("child"))
11407  return axis_child;
11408 
11409  break;
11410 
11411  case 'd':
11412  if (name == PUGIXML_TEXT("descendant"))
11413  return axis_descendant;
11414  else if (name == PUGIXML_TEXT("descendant-or-self"))
11415  return axis_descendant_or_self;
11416 
11417  break;
11418 
11419  case 'f':
11420  if (name == PUGIXML_TEXT("following"))
11421  return axis_following;
11422  else if (name == PUGIXML_TEXT("following-sibling"))
11423  return axis_following_sibling;
11424 
11425  break;
11426 
11427  case 'n':
11428  if (name == PUGIXML_TEXT("namespace"))
11429  return axis_namespace;
11430 
11431  break;
11432 
11433  case 'p':
11434  if (name == PUGIXML_TEXT("parent"))
11435  return axis_parent;
11436  else if (name == PUGIXML_TEXT("preceding"))
11437  return axis_preceding;
11438  else if (name == PUGIXML_TEXT("preceding-sibling"))
11439  return axis_preceding_sibling;
11440 
11441  break;
11442 
11443  case 's':
11444  if (name == PUGIXML_TEXT("self"))
11445  return axis_self;
11446 
11447  break;
11448 
11449  default:
11450  break;
11451  }
11452 
11453  specified = false;
11454  return axis_child;
11455  }
11456 
11458  {
11459  switch (name.begin[0])
11460  {
11461  case 'c':
11462  if (name == PUGIXML_TEXT("comment"))
11463  return nodetest_type_comment;
11464 
11465  break;
11466 
11467  case 'n':
11468  if (name == PUGIXML_TEXT("node"))
11469  return nodetest_type_node;
11470 
11471  break;
11472 
11473  case 'p':
11474  if (name == PUGIXML_TEXT("processing-instruction"))
11475  return nodetest_type_pi;
11476 
11477  break;
11478 
11479  case 't':
11480  if (name == PUGIXML_TEXT("text"))
11481  return nodetest_type_text;
11482 
11483  break;
11484 
11485  default:
11486  break;
11487  }
11488 
11489  return nodetest_none;
11490  }
11491 
11492  // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
11494  {
11495  switch (_lexer.current())
11496  {
11497  case lex_var_ref:
11498  {
11500 
11501  if (!_variables)
11502  return error("Unknown variable: variable set is not provided");
11503 
11504  xpath_variable* var = 0;
11505  if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var))
11506  return error_oom();
11507 
11508  if (!var)
11509  return error("Unknown variable: variable set does not contain the given name");
11510 
11511  _lexer.next();
11512 
11513  return alloc_node(ast_variable, var->type(), var);
11514  }
11515 
11516  case lex_open_brace:
11517  {
11518  _lexer.next();
11519 
11521  if (!n) return 0;
11522 
11523  if (_lexer.current() != lex_close_brace)
11524  return error("Expected ')' to match an opening '('");
11525 
11526  _lexer.next();
11527 
11528  return n;
11529  }
11530 
11531  case lex_quoted_string:
11532  {
11533  const char_t* value = alloc_string(_lexer.contents());
11534  if (!value) return 0;
11535 
11536  _lexer.next();
11537 
11539  }
11540 
11541  case lex_number:
11542  {
11543  double value = 0;
11544 
11546  return error_oom();
11547 
11548  _lexer.next();
11549 
11551  }
11552 
11553  case lex_string:
11554  {
11555  xpath_ast_node* args[2] = {0};
11556  size_t argc = 0;
11557 
11558  xpath_lexer_string function = _lexer.contents();
11559  _lexer.next();
11560 
11561  xpath_ast_node* last_arg = 0;
11562 
11563  if (_lexer.current() != lex_open_brace)
11564  return error("Unrecognized function call");
11565  _lexer.next();
11566 
11567  size_t old_depth = _depth;
11568 
11569  while (_lexer.current() != lex_close_brace)
11570  {
11571  if (argc > 0)
11572  {
11573  if (_lexer.current() != lex_comma)
11574  return error("No comma between function arguments");
11575  _lexer.next();
11576  }
11577 
11578  if (++_depth > xpath_ast_depth_limit)
11579  return error_rec();
11580 
11582  if (!n) return 0;
11583 
11584  if (argc < 2) args[argc] = n;
11585  else last_arg->set_next(n);
11586 
11587  argc++;
11588  last_arg = n;
11589  }
11590 
11591  _lexer.next();
11592 
11593  _depth = old_depth;
11594 
11595  return parse_function(function, argc, args);
11596  }
11597 
11598  default:
11599  return error("Unrecognizable primary expression");
11600  }
11601  }
11602 
11603  // FilterExpr ::= PrimaryExpr | FilterExpr Predicate
11604  // Predicate ::= '[' PredicateExpr ']'
11605  // PredicateExpr ::= Expr
11607  {
11609  if (!n) return 0;
11610 
11611  size_t old_depth = _depth;
11612 
11613  while (_lexer.current() == lex_open_square_brace)
11614  {
11615  _lexer.next();
11616 
11617  if (++_depth > xpath_ast_depth_limit)
11618  return error_rec();
11619 
11620  if (n->rettype() != xpath_type_node_set)
11621  return error("Predicate has to be applied to node set");
11622 
11623  xpath_ast_node* expr = parse_expression();
11624  if (!expr) return 0;
11625 
11626  n = alloc_node(ast_filter, n, expr, predicate_default);
11627  if (!n) return 0;
11628 
11630  return error("Expected ']' to match an opening '['");
11631 
11632  _lexer.next();
11633  }
11634 
11635  _depth = old_depth;
11636 
11637  return n;
11638  }
11639 
11640  // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
11641  // AxisSpecifier ::= AxisName '::' | '@'?
11642  // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
11643  // NameTest ::= '*' | NCName ':' '*' | QName
11644  // AbbreviatedStep ::= '.' | '..'
11646  {
11647  if (set && set->rettype() != xpath_type_node_set)
11648  return error("Step has to be applied to node set");
11649 
11650  bool axis_specified = false;
11651  axis_t axis = axis_child; // implied child axis
11652 
11654  {
11655  axis = axis_attribute;
11656  axis_specified = true;
11657 
11658  _lexer.next();
11659  }
11660  else if (_lexer.current() == lex_dot)
11661  {
11662  _lexer.next();
11663 
11665  return error("Predicates are not allowed after an abbreviated step");
11666 
11667  return alloc_node(ast_step, set, axis_self, nodetest_type_node, 0);
11668  }
11669  else if (_lexer.current() == lex_double_dot)
11670  {
11671  _lexer.next();
11672 
11674  return error("Predicates are not allowed after an abbreviated step");
11675 
11677  }
11678 
11679  nodetest_t nt_type = nodetest_none;
11680  xpath_lexer_string nt_name;
11681 
11682  if (_lexer.current() == lex_string)
11683  {
11684  // node name test
11685  nt_name = _lexer.contents();
11686  _lexer.next();
11687 
11688  // was it an axis name?
11689  if (_lexer.current() == lex_double_colon)
11690  {
11691  // parse axis name
11692  if (axis_specified)
11693  return error("Two axis specifiers in one step");
11694 
11695  axis = parse_axis_name(nt_name, axis_specified);
11696 
11697  if (!axis_specified)
11698  return error("Unknown axis");
11699 
11700  // read actual node test
11701  _lexer.next();
11702 
11703  if (_lexer.current() == lex_multiply)
11704  {
11705  nt_type = nodetest_all;
11706  nt_name = xpath_lexer_string();
11707  _lexer.next();
11708  }
11709  else if (_lexer.current() == lex_string)
11710  {
11711  nt_name = _lexer.contents();
11712  _lexer.next();
11713  }
11714  else
11715  {
11716  return error("Unrecognized node test");
11717  }
11718  }
11719 
11720  if (nt_type == nodetest_none)
11721  {
11722  // node type test or processing-instruction
11723  if (_lexer.current() == lex_open_brace)
11724  {
11725  _lexer.next();
11726 
11727  if (_lexer.current() == lex_close_brace)
11728  {
11729  _lexer.next();
11730 
11731  nt_type = parse_node_test_type(nt_name);
11732 
11733  if (nt_type == nodetest_none)
11734  return error("Unrecognized node type");
11735 
11736  nt_name = xpath_lexer_string();
11737  }
11738  else if (nt_name == PUGIXML_TEXT("processing-instruction"))
11739  {
11740  if (_lexer.current() != lex_quoted_string)
11741  return error("Only literals are allowed as arguments to processing-instruction()");
11742 
11743  nt_type = nodetest_pi;
11744  nt_name = _lexer.contents();
11745  _lexer.next();
11746 
11747  if (_lexer.current() != lex_close_brace)
11748  return error("Unmatched brace near processing-instruction()");
11749  _lexer.next();
11750  }
11751  else
11752  {
11753  return error("Unmatched brace near node type test");
11754  }
11755  }
11756  // QName or NCName:*
11757  else
11758  {
11759  if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:*
11760  {
11761  nt_name.end--; // erase *
11762 
11763  nt_type = nodetest_all_in_namespace;
11764  }
11765  else
11766  {
11767  nt_type = nodetest_name;
11768  }
11769  }
11770  }
11771  }
11772  else if (_lexer.current() == lex_multiply)
11773  {
11774  nt_type = nodetest_all;
11775  _lexer.next();
11776  }
11777  else
11778  {
11779  return error("Unrecognized node test");
11780  }
11781 
11782  const char_t* nt_name_copy = alloc_string(nt_name);
11783  if (!nt_name_copy) return 0;
11784 
11785  xpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy);
11786  if (!n) return 0;
11787 
11788  size_t old_depth = _depth;
11789 
11790  xpath_ast_node* last = 0;
11791 
11792  while (_lexer.current() == lex_open_square_brace)
11793  {
11794  _lexer.next();
11795 
11796  if (++_depth > xpath_ast_depth_limit)
11797  return error_rec();
11798 
11799  xpath_ast_node* expr = parse_expression();
11800  if (!expr) return 0;
11801 
11803  if (!pred) return 0;
11804 
11806  return error("Expected ']' to match an opening '['");
11807  _lexer.next();
11808 
11809  if (last) last->set_next(pred);
11810  else n->set_right(pred);
11811 
11812  last = pred;
11813  }
11814 
11815  _depth = old_depth;
11816 
11817  return n;
11818  }
11819 
11820  // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
11822  {
11823  xpath_ast_node* n = parse_step(set);
11824  if (!n) return 0;
11825 
11826  size_t old_depth = _depth;
11827 
11828  while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
11829  {
11830  lexeme_t l = _lexer.current();
11831  _lexer.next();
11832 
11833  if (l == lex_double_slash)
11834  {
11836  if (!n) return 0;
11837 
11838  ++_depth;
11839  }
11840 
11841  if (++_depth > xpath_ast_depth_limit)
11842  return error_rec();
11843 
11844  n = parse_step(n);
11845  if (!n) return 0;
11846  }
11847 
11848  _depth = old_depth;
11849 
11850  return n;
11851  }
11852 
11853  // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
11854  // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
11856  {
11857  if (_lexer.current() == lex_slash)
11858  {
11859  _lexer.next();
11860 
11862  if (!n) return 0;
11863 
11864  // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path
11865  lexeme_t l = _lexer.current();
11866 
11867  if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
11868  return parse_relative_location_path(n);
11869  else
11870  return n;
11871  }
11872  else if (_lexer.current() == lex_double_slash)
11873  {
11874  _lexer.next();
11875 
11877  if (!n) return 0;
11878 
11880  if (!n) return 0;
11881 
11882  return parse_relative_location_path(n);
11883  }
11884 
11885  // 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
11886  return parse_relative_location_path(0);
11887  }
11888 
11889  // PathExpr ::= LocationPath
11890  // | FilterExpr
11891  // | FilterExpr '/' RelativeLocationPath
11892  // | FilterExpr '//' RelativeLocationPath
11893  // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
11894  // UnaryExpr ::= UnionExpr | '-' UnaryExpr
11896  {
11897  // Clarification.
11898  // PathExpr begins with either LocationPath or FilterExpr.
11899  // FilterExpr begins with PrimaryExpr
11900  // PrimaryExpr begins with '$' in case of it being a variable reference,
11901  // '(' in case of it being an expression, string literal, number constant or
11902  // function call.
11905  _lexer.current() == lex_string)
11906  {
11907  if (_lexer.current() == lex_string)
11908  {
11909  // This is either a function call, or not - if not, we shall proceed with location path
11910  const char_t* state = _lexer.state();
11911 
11912  while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
11913 
11914  if (*state != '(')
11915  return parse_location_path();
11916 
11917  // This looks like a function call; however this still can be a node-test. Check it.
11919  return parse_location_path();
11920  }
11921 
11923  if (!n) return 0;
11924 
11926  {
11927  lexeme_t l = _lexer.current();
11928  _lexer.next();
11929 
11930  if (l == lex_double_slash)
11931  {
11932  if (n->rettype() != xpath_type_node_set)
11933  return error("Step has to be applied to node set");
11934 
11936  if (!n) return 0;
11937  }
11938 
11939  // select from location path
11940  return parse_relative_location_path(n);
11941  }
11942 
11943  return n;
11944  }
11945  else if (_lexer.current() == lex_minus)
11946  {
11947  _lexer.next();
11948 
11949  // precedence 7+ - only parses union expressions
11951  if (!n) return 0;
11952 
11954  }
11955  else
11956  {
11957  return parse_location_path();
11958  }
11959  }
11960 
11962  {
11966 
11968  {
11969  }
11970 
11971  binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_)
11972  {
11973  }
11974 
11976  {
11977  switch (lexer.current())
11978  {
11979  case lex_string:
11980  if (lexer.contents() == PUGIXML_TEXT("or"))
11982  else if (lexer.contents() == PUGIXML_TEXT("and"))
11984  else if (lexer.contents() == PUGIXML_TEXT("div"))
11986  else if (lexer.contents() == PUGIXML_TEXT("mod"))
11988  else
11989  return binary_op_t();
11990 
11991  case lex_equal:
11993 
11994  case lex_not_equal:
11996 
11997  case lex_less:
11999 
12000  case lex_greater:
12002 
12003  case lex_less_or_equal:
12005 
12006  case lex_greater_or_equal:
12008 
12009  case lex_plus:
12011 
12012  case lex_minus:
12014 
12015  case lex_multiply:
12017 
12018  case lex_union:
12020 
12021  default:
12022  return binary_op_t();
12023  }
12024  }
12025  };
12026 
12028  {
12030 
12031  while (op.asttype != ast_unknown && op.precedence >= limit)
12032  {
12033  _lexer.next();
12034 
12035  if (++_depth > xpath_ast_depth_limit)
12036  return error_rec();
12037 
12039  if (!rhs) return 0;
12040 
12042 
12043  while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)
12044  {
12045  rhs = parse_expression_rec(rhs, nextop.precedence);
12046  if (!rhs) return 0;
12047 
12048  nextop = binary_op_t::parse(_lexer);
12049  }
12050 
12051  if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))
12052  return error("Union operator has to be applied to node sets");
12053 
12054  lhs = alloc_node(op.asttype, op.rettype, lhs, rhs);
12055  if (!lhs) return 0;
12056 
12057  op = binary_op_t::parse(_lexer);
12058  }
12059 
12060  return lhs;
12061  }
12062 
12063  // Expr ::= OrExpr
12064  // OrExpr ::= AndExpr | OrExpr 'or' AndExpr
12065  // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
12066  // EqualityExpr ::= RelationalExpr
12067  // | EqualityExpr '=' RelationalExpr
12068  // | EqualityExpr '!=' RelationalExpr
12069  // RelationalExpr ::= AdditiveExpr
12070  // | RelationalExpr '<' AdditiveExpr
12071  // | RelationalExpr '>' AdditiveExpr
12072  // | RelationalExpr '<=' AdditiveExpr
12073  // | RelationalExpr '>=' AdditiveExpr
12074  // AdditiveExpr ::= MultiplicativeExpr
12075  // | AdditiveExpr '+' MultiplicativeExpr
12076  // | AdditiveExpr '-' MultiplicativeExpr
12077  // MultiplicativeExpr ::= UnaryExpr
12078  // | MultiplicativeExpr '*' UnaryExpr
12079  // | MultiplicativeExpr 'div' UnaryExpr
12080  // | MultiplicativeExpr 'mod' UnaryExpr
12082  {
12083  size_t old_depth = _depth;
12084 
12085  if (++_depth > xpath_ast_depth_limit)
12086  return error_rec();
12087 
12089  if (!n) return 0;
12090 
12091  n = parse_expression_rec(n, limit);
12092 
12093  _depth = old_depth;
12094 
12095  return n;
12096  }
12097 
12098  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), _depth(0)
12099  {
12100  }
12101 
12103  {
12105  if (!n) return 0;
12106 
12107  assert(_depth == 0);
12108 
12109  // check if there are unparsed tokens left
12110  if (_lexer.current() != lex_eof)
12111  return error("Incorrect query");
12112 
12113  return n;
12114  }
12115 
12116  static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)
12117  {
12118  xpath_parser parser(query, variables, alloc, result);
12119 
12120  return parser.parse();
12121  }
12122  };
12123 
12125  {
12127  {
12128  void* memory = xml_memory::allocate(sizeof(xpath_query_impl));
12129  if (!memory) return 0;
12130 
12131  return new (memory) xpath_query_impl();
12132  }
12133 
12134  static void destroy(xpath_query_impl* impl)
12135  {
12136  // free all allocated pages
12137  impl->alloc.release();
12138 
12139  // free allocator memory (with the first page)
12140  xml_memory::deallocate(impl);
12141  }
12142 
12143  xpath_query_impl(): root(0), alloc(&block, &oom), oom(false)
12144  {
12145  block.next = 0;
12146  block.capacity = sizeof(block.data);
12147  }
12148 
12152  bool oom;
12153  };
12154 
12156  {
12157  if (!impl) return 0;
12158 
12159  if (impl->root->rettype() != xpath_type_node_set)
12160  {
12161  #ifdef PUGIXML_NO_EXCEPTIONS
12162  return 0;
12163  #else
12164  xpath_parse_result res;
12165  res.error = "Expression does not evaluate to node set";
12166 
12167  throw xpath_exception(res);
12168  #endif
12169  }
12170 
12171  return impl->root;
12172  }
12174 
12175 OIIO_NAMESPACE_BEGIN namespace pugi
12176 {
12177 #ifndef PUGIXML_NO_EXCEPTIONS
12179  {
12180  assert(_result.error);
12181  }
12182 
12183  PUGI__FN const char* xpath_exception::what() const throw()
12184  {
12185  return _result.error;
12186  }
12187 
12189  {
12190  return _result;
12191  }
12192 #endif
12193 
12195  {
12196  }
12197 
12198  PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_)
12199  {
12200  }
12201 
12202  PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
12203  {
12204  }
12205 
12207  {
12208  return _attribute ? xml_node() : _node;
12209  }
12210 
12212  {
12213  return _attribute;
12214  }
12215 
12217  {
12218  return _attribute ? _node : _node.parent();
12219  }
12220 
12221  PUGI__FN static void unspecified_bool_xpath_node(xpath_node***)
12222  {
12223  }
12224 
12225  PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const
12226  {
12227  return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
12228  }
12229 
12231  {
12232  return !(_node || _attribute);
12233  }
12234 
12236  {
12237  return _node == n._node && _attribute == n._attribute;
12238  }
12239 
12241  {
12242  return _node != n._node || _attribute != n._attribute;
12243  }
12244 
12245 #ifdef __BORLANDC__
12246  PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs)
12247  {
12248  return (bool)lhs && rhs;
12249  }
12250 
12251  PUGI__FN bool operator||(const xpath_node& lhs, bool rhs)
12252  {
12253  return (bool)lhs || rhs;
12254  }
12255 #endif
12256 
12257  PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)
12258  {
12259  assert(begin_ <= end_);
12260 
12261  size_t size_ = static_cast<size_t>(end_ - begin_);
12262 
12263  // use internal buffer for 0 or 1 elements, heap buffer otherwise
12264  xpath_node* storage = (size_ <= 1) ? _storage : static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
12265 
12266  if (!storage)
12267  {
12268  #ifdef PUGIXML_NO_EXCEPTIONS
12269  return;
12270  #else
12271  throw std::bad_alloc();
12272  #endif
12273  }
12274 
12275  // deallocate old buffer
12276  if (_begin != _storage)
12277  impl::xml_memory::deallocate(_begin);
12278 
12279  // size check is necessary because for begin_ = end_ = nullptr, memcpy is UB
12280  if (size_)
12281  memcpy(storage, begin_, size_ * sizeof(xpath_node));
12282 
12283  _begin = storage;
12284  _end = storage + size_;
12285  _type = type_;
12286  }
12287 
12288 #ifdef PUGIXML_HAS_MOVE
12289  PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT
12290  {
12291  _type = rhs._type;
12292  _storage[0] = rhs._storage[0];
12293  _begin = (rhs._begin == rhs._storage) ? _storage : rhs._begin;
12294  _end = _begin + (rhs._end - rhs._begin);
12295 
12296  rhs._type = type_unsorted;
12297  rhs._begin = rhs._storage;
12298  rhs._end = rhs._storage;
12299  }
12300 #endif
12301 
12302  PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage)
12303  {
12304  }
12305 
12306  PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage)
12307  {
12308  _assign(begin_, end_, type_);
12309  }
12310 
12312  {
12313  if (_begin != _storage)
12314  impl::xml_memory::deallocate(_begin);
12315  }
12316 
12317  PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage)
12318  {
12319  _assign(ns._begin, ns._end, ns._type);
12320  }
12321 
12323  {
12324  if (this == &ns) return *this;
12325 
12326  _assign(ns._begin, ns._end, ns._type);
12327 
12328  return *this;
12329  }
12330 
12331 #ifdef PUGIXML_HAS_MOVE
12332  PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage)
12333  {
12334  _move(rhs);
12335  }
12336 
12337  PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT
12338  {
12339  if (this == &rhs) return *this;
12340 
12341  if (_begin != _storage)
12342  impl::xml_memory::deallocate(_begin);
12343 
12344  _move(rhs);
12345 
12346  return *this;
12347  }
12348 #endif
12349 
12351  {
12352  return _type;
12353  }
12354 
12356  {
12357  return _end - _begin;
12358  }
12359 
12361  {
12362  return _begin == _end;
12363  }
12364 
12366  {
12367  assert(index < size());
12368  return _begin[index];
12369  }
12370 
12372  {
12373  return _begin;
12374  }
12375 
12377  {
12378  return _end;
12379  }
12380 
12382  {
12383  _type = impl::xpath_sort(_begin, _end, _type, reverse);
12384  }
12385 
12387  {
12388  return impl::xpath_first(_begin, _end, _type);
12389  }
12390 
12392  {
12393  }
12394 
12395  PUGI__FN xpath_parse_result::operator bool() const
12396  {
12397  return error == 0;
12398  }
12399 
12401  {
12402  return error ? error : "No error";
12403  }
12404 
12406  {
12407  }
12408 
12409  PUGI__FN const char_t* xpath_variable::name() const
12410  {
12411  switch (_type)
12412  {
12413  case xpath_type_node_set:
12414  return static_cast<const impl::xpath_variable_node_set*>(this)->name;
12415 
12416  case xpath_type_number:
12417  return static_cast<const impl::xpath_variable_number*>(this)->name;
12418 
12419  case xpath_type_string:
12420  return static_cast<const impl::xpath_variable_string*>(this)->name;
12421 
12422  case xpath_type_boolean:
12423  return static_cast<const impl::xpath_variable_boolean*>(this)->name;
12424 
12425  default:
12426  assert(false && "Invalid variable type"); // unreachable
12427  return 0;
12428  }
12429  }
12430 
12432  {
12433  return _type;
12434  }
12435 
12437  {
12438  return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
12439  }
12440 
12442  {
12443  return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();
12444  }
12445 
12446  PUGI__FN const char_t* xpath_variable::get_string() const
12447  {
12448  const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0;
12449  return value ? value : PUGIXML_TEXT("");
12450  }
12451 
12453  {
12454  return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
12455  }
12456 
12458  {
12459  if (_type != xpath_type_boolean) return false;
12460 
12461  static_cast<impl::xpath_variable_boolean*>(this)->value = value;
12462  return true;
12463  }
12464 
12465  PUGI__FN bool xpath_variable::set(double value)
12466  {
12467  if (_type != xpath_type_number) return false;
12468 
12469  static_cast<impl::xpath_variable_number*>(this)->value = value;
12470  return true;
12471  }
12472 
12473  PUGI__FN bool xpath_variable::set(const char_t* value)
12474  {
12475  if (_type != xpath_type_string) return false;
12476 
12477  impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);
12478 
12479  // duplicate string
12480  size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
12481 
12482  char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));
12483  if (!copy) return false;
12484 
12485  memcpy(copy, value, size);
12486 
12487  // replace old string
12488  if (var->value) impl::xml_memory::deallocate(var->value);
12489  var->value = copy;
12490 
12491  return true;
12492  }
12493 
12495  {
12496  if (_type != xpath_type_node_set) return false;
12497 
12498  static_cast<impl::xpath_variable_node_set*>(this)->value = value;
12499  return true;
12500  }
12501 
12503  {
12504  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12505  _data[i] = 0;
12506  }
12507 
12509  {
12510  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12511  _destroy(_data[i]);
12512  }
12513 
12515  {
12516  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12517  _data[i] = 0;
12518 
12519  _assign(rhs);
12520  }
12521 
12523  {
12524  if (this == &rhs) return *this;
12525 
12526  _assign(rhs);
12527 
12528  return *this;
12529  }
12530 
12531 #ifdef PUGIXML_HAS_MOVE
12533  {
12534  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12535  {
12536  _data[i] = rhs._data[i];
12537  rhs._data[i] = 0;
12538  }
12539  }
12540 
12541  PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT
12542  {
12543  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12544  {
12545  _destroy(_data[i]);
12546 
12547  _data[i] = rhs._data[i];
12548  rhs._data[i] = 0;
12549  }
12550 
12551  return *this;
12552  }
12553 #endif
12554 
12555  PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs)
12556  {
12557  xpath_variable_set temp;
12558 
12559  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12560  if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))
12561  return;
12562 
12563  _swap(temp);
12564  }
12565 
12566  PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs)
12567  {
12568  for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12569  {
12570  xpath_variable* chain = _data[i];
12571 
12572  _data[i] = rhs._data[i];
12573  rhs._data[i] = chain;
12574  }
12575  }
12576 
12577  PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const
12578  {
12579  const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
12580  size_t hash = impl::hash_string(name) % hash_size;
12581 
12582  // look for existing variable
12583  for (xpath_variable* var = _data[hash]; var; var = var->_next)
12584  if (impl::strequal(var->name(), name))
12585  return var;
12586 
12587  return 0;
12588  }
12589 
12590  PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)
12591  {
12592  xpath_variable* last = 0;
12593 
12594  while (var)
12595  {
12596  // allocate storage for new variable
12597  xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
12598  if (!nvar) return false;
12599 
12600  // link the variable to the result immediately to handle failures gracefully
12601  if (last)
12602  last->_next = nvar;
12603  else
12604  *out_result = nvar;
12605 
12606  last = nvar;
12607 
12608  // copy the value; this can fail due to out-of-memory conditions
12609  if (!impl::copy_xpath_variable(nvar, var)) return false;
12610 
12611  var = var->_next;
12612  }
12613 
12614  return true;
12615  }
12616 
12617  PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var)
12618  {
12619  while (var)
12620  {
12621  xpath_variable* next = var->_next;
12622 
12623  impl::delete_xpath_variable(var->_type, var);
12624 
12625  var = next;
12626  }
12627  }
12628 
12630  {
12631  const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
12632  size_t hash = impl::hash_string(name) % hash_size;
12633 
12634  // look for existing variable
12635  for (xpath_variable* var = _data[hash]; var; var = var->_next)
12636  if (impl::strequal(var->name(), name))
12637  return var->type() == type ? var : 0;
12638 
12639  // add new variable
12640  xpath_variable* result = impl::new_xpath_variable(type, name);
12641 
12642  if (result)
12643  {
12644  result->_next = _data[hash];
12645 
12646  _data[hash] = result;
12647  }
12648 
12649  return result;
12650  }
12651 
12652  PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value)
12653  {
12654  xpath_variable* var = add(name, xpath_type_boolean);
12655  return var ? var->set(value) : false;
12656  }
12657 
12658  PUGI__FN bool xpath_variable_set::set(const char_t* name, double value)
12659  {
12660  xpath_variable* var = add(name, xpath_type_number);
12661  return var ? var->set(value) : false;
12662  }
12663 
12664  PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value)
12665  {
12666  xpath_variable* var = add(name, xpath_type_string);
12667  return var ? var->set(value) : false;
12668  }
12669 
12670  PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
12671  {
12672  xpath_variable* var = add(name, xpath_type_node_set);
12673  return var ? var->set(value) : false;
12674  }
12675 
12677  {
12678  return _find(name);
12679  }
12680 
12681  PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
12682  {
12683  return _find(name);
12684  }
12685 
12686  PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
12687  {
12688  impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
12689 
12690  if (!qimpl)
12691  {
12692  #ifdef PUGIXML_NO_EXCEPTIONS
12693  _result.error = "Out of memory";
12694  #else
12695  throw std::bad_alloc();
12696  #endif
12697  }
12698  else
12699  {
12700  using impl::auto_deleter; // MSVC7 workaround
12701  auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);
12702 
12703  qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
12704 
12705  if (qimpl->root)
12706  {
12707  qimpl->root->optimize(&qimpl->alloc);
12708 
12709  _impl = impl.release();
12710  _result.error = 0;
12711  }
12712  else
12713  {
12714  #ifdef PUGIXML_NO_EXCEPTIONS
12715  if (qimpl->oom) _result.error = "Out of memory";
12716  #else
12717  if (qimpl->oom) throw std::bad_alloc();
12718  throw xpath_exception(_result);
12719  #endif
12720  }
12721  }
12722  }
12723 
12725  {
12726  }
12727 
12729  {
12730  if (_impl)
12731  impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
12732  }
12733 
12734 #ifdef PUGIXML_HAS_MOVE
12735  PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT
12736  {
12737  _impl = rhs._impl;
12738  _result = rhs._result;
12739  rhs._impl = 0;
12740  rhs._result = xpath_parse_result();
12741  }
12742 
12743  PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT
12744  {
12745  if (this == &rhs) return *this;
12746 
12747  if (_impl)
12748  impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
12749 
12750  _impl = rhs._impl;
12751  _result = rhs._result;
12752  rhs._impl = 0;
12753  rhs._result = xpath_parse_result();
12754 
12755  return *this;
12756  }
12757 #endif
12758 
12760  {
12761  if (!_impl) return xpath_type_none;
12762 
12763  return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();
12764  }
12765 
12767  {
12768  if (!_impl) return false;
12769 
12770  impl::xpath_context c(n, 1, 1);
12771  impl::xpath_stack_data sd;
12772 
12773  bool r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
12774 
12775  if (sd.oom)
12776  {
12777  #ifdef PUGIXML_NO_EXCEPTIONS
12778  return false;
12779  #else
12780  throw std::bad_alloc();
12781  #endif
12782  }
12783 
12784  return r;
12785  }
12786 
12788  {
12789  if (!_impl) return impl::gen_nan();
12790 
12791  impl::xpath_context c(n, 1, 1);
12792  impl::xpath_stack_data sd;
12793 
12794  double r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
12795 
12796  if (sd.oom)
12797  {
12798  #ifdef PUGIXML_NO_EXCEPTIONS
12799  return impl::gen_nan();
12800  #else
12801  throw std::bad_alloc();
12802  #endif
12803  }
12804 
12805  return r;
12806  }
12807 
12808 #ifndef PUGIXML_NO_STL
12810  {
12811  if (!_impl) return string_t();
12812 
12813  impl::xpath_context c(n, 1, 1);
12814  impl::xpath_stack_data sd;
12815 
12816  impl::xpath_string r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_string(c, sd.stack);
12817 
12818  if (sd.oom)
12819  {
12820  #ifdef PUGIXML_NO_EXCEPTIONS
12821  return string_t();
12822  #else
12823  throw std::bad_alloc();
12824  #endif
12825  }
12826 
12827  return string_t(r.c_str(), r.length());
12828  }
12829 #endif
12830 
12831  PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
12832  {
12833  impl::xpath_context c(n, 1, 1);
12834  impl::xpath_stack_data sd;
12835 
12836  impl::xpath_string r = _impl ? static_cast<impl::xpath_query_impl*>(_impl)->root->eval_string(c, sd.stack) : impl::xpath_string();
12837 
12838  if (sd.oom)
12839  {
12840  #ifdef PUGIXML_NO_EXCEPTIONS
12841  r = impl::xpath_string();
12842  #else
12843  throw std::bad_alloc();
12844  #endif
12845  }
12846 
12847  size_t full_size = r.length() + 1;
12848 
12849  if (capacity > 0)
12850  {
12851  size_t size = (full_size < capacity) ? full_size : capacity;
12852  assert(size > 0);
12853 
12854  memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
12855  buffer[size - 1] = 0;
12856  }
12857 
12858  return full_size;
12859  }
12860 
12862  {
12863  impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
12864  if (!root) return xpath_node_set();
12865 
12866  impl::xpath_context c(n, 1, 1);
12867  impl::xpath_stack_data sd;
12868 
12869  impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
12870 
12871  if (sd.oom)
12872  {
12873  #ifdef PUGIXML_NO_EXCEPTIONS
12874  return xpath_node_set();
12875  #else
12876  throw std::bad_alloc();
12877  #endif
12878  }
12879 
12880  return xpath_node_set(r.begin(), r.end(), r.type());
12881  }
12882 
12884  {
12885  impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
12886  if (!root) return xpath_node();
12887 
12888  impl::xpath_context c(n, 1, 1);
12889  impl::xpath_stack_data sd;
12890 
12891  impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);
12892 
12893  if (sd.oom)
12894  {
12895  #ifdef PUGIXML_NO_EXCEPTIONS
12896  return xpath_node();
12897  #else
12898  throw std::bad_alloc();
12899  #endif
12900  }
12901 
12902  return r.first();
12903  }
12904 
12906  {
12907  return _result;
12908  }
12909 
12910  PUGI__FN static void unspecified_bool_xpath_query(xpath_query***)
12911  {
12912  }
12913 
12914  PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
12915  {
12916  return _impl ? unspecified_bool_xpath_query : 0;
12917  }
12918 
12920  {
12921  return !_impl;
12922  }
12923 
12925  {
12926  xpath_query q(query, variables);
12927  return q.evaluate_node(*this);
12928  }
12929 
12931  {
12932  return query.evaluate_node(*this);
12933  }
12934 
12936  {
12937  xpath_query q(query, variables);
12938  return q.evaluate_node_set(*this);
12939  }
12940 
12942  {
12943  return query.evaluate_node_set(*this);
12944  }
12945 
12947  {
12948  xpath_query q(query, variables);
12949  return q.evaluate_node(*this);
12950  }
12951 
12953  {
12954  return query.evaluate_node(*this);
12955  }
12957 
12958 #endif
12959 
12960 #ifdef __BORLANDC__
12961 # pragma option pop
12962 #endif
12963 
12964 // Intel C++ does not properly keep warning state for function templates,
12965 // so popping warning state at the end of translation unit leads to warnings in the middle.
12966 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
12967 # pragma warning(pop)
12968 #endif
12969 
12970 #if defined(_MSC_VER) && defined(__c2__)
12971 # pragma clang diagnostic pop
12972 #endif
12973 
12974 // Undefine all local macros (makes sure we're not leaking macros in header-only mode)
12975 #undef PUGI__NO_INLINE
12976 #undef PUGI__UNLIKELY
12977 #undef PUGI__STATIC_ASSERT
12978 #undef PUGI__DMC_VOLATILE
12979 #undef PUGI__UNSIGNED_OVERFLOW
12980 #undef PUGI__MSVC_CRT_VERSION
12981 #undef PUGI__SNPRINTF
12982 #undef PUGI__NS_BEGIN
12983 #undef PUGI__NS_END
12984 #undef PUGI__FN
12985 #undef PUGI__FN_NO_INLINE
12986 #undef PUGI__GETHEADER_IMPL
12987 #undef PUGI__GETPAGE_IMPL
12988 #undef PUGI__GETPAGE
12989 #undef PUGI__NODETYPE
12990 #undef PUGI__IS_CHARTYPE_IMPL
12991 #undef PUGI__IS_CHARTYPE
12992 #undef PUGI__IS_CHARTYPEX
12993 #undef PUGI__ENDSWITH
12994 #undef PUGI__SKIPWS
12995 #undef PUGI__OPTSET
12996 #undef PUGI__PUSHNODE
12997 #undef PUGI__POPNODE
12998 #undef PUGI__SCANFOR
12999 #undef PUGI__SCANWHILE
13000 #undef PUGI__SCANWHILE_UNROLL
13001 #undef PUGI__ENDSEG
13002 #undef PUGI__THROW_ERROR
13003 #undef PUGI__CHECK_ERROR
13004 
13005 #endif
13006 
13007 /**
13008  * Copyright (c) 2006-2022 Arseny Kapoulkine
13009  *
13010  * Permission is hereby granted, free of charge, to any person
13011  * obtaining a copy of this software and associated documentation
13012  * files (the "Software"), to deal in the Software without
13013  * restriction, including without limitation the rights to use,
13014  * copy, modify, merge, publish, distribute, sublicense, and/or sell
13015  * copies of the Software, and to permit persons to whom the
13016  * Software is furnished to do so, subject to the following
13017  * conditions:
13018  *
13019  * The above copyright notice and this permission notice shall be
13020  * included in all copies or substantial portions of the Software.
13021  *
13022  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13023  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
13024  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13025  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
13026  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
13027  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
13028  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
13029  * OTHER DEALINGS IN THE SOFTWARE.
13030  */
GLsizei GLenum GLsizei GLsizei GLuint memory
Definition: RE_OGL.h:202
xpath_ast_node * alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable *value)
Definition: pugixml.cpp:11229
const unsigned int parse_ws_pcdata
Definition: pugixml.hpp:189
GLuint GLuint stream
Definition: glcorearb.h:1832
virtual bool for_each(xml_node &node)=0
xml_text text() const
Definition: pugixml.cpp:5635
void swap(ArAssetInfo &lhs, ArAssetInfo &rhs)
Definition: assetInfo.h:57
utf16_writer writer
Definition: pugixml.cpp:1795
virtual bool begin(xml_node &node)
Definition: pugixml.cpp:5125
bool operator>=(const xml_node &r) const
Definition: pugixml.cpp:5513
const unsigned int format_indent_attributes
Definition: pugixml.hpp:272
#define PUGI__NODETYPE(n)
Definition: pugixml.cpp:457
type
Definition: core.h:556
xml_attribute prepend_attribute(const char_t *name)
Definition: pugixml.cpp:5717
int as_int(int def=0) const
Definition: pugixml.cpp:6492
xpath_variable * get(const char_t *name)
Definition: pugixml.cpp:12676
GLenum query
Definition: glad.h:2772
PUGI__FN bool strcpy_insitu(String &dest, Header &header, uintptr_t header_mask, const char_t *source, size_t source_length)
Definition: pugixml.cpp:2360
GLint first
Definition: glcorearb.h:405
#define PUGI__GETHEADER_IMPL(object, page, flags)
Definition: pugixml.cpp:451
char data[xpath_memory_page_size]
Definition: pugixml.cpp:7635
#define PUGI__SCANFOR(X)
Definition: pugixml.cpp:2596
xml_memory_page * allocate_page(size_t data_size)
Definition: pugixml.cpp:520
GLuint GLsizei const GLchar * message
Definition: glcorearb.h:2543
void next()
Definition: pugixml.cpp:9138
PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
Definition: pugixml.cpp:2712
float as_float(float def=0) const
Definition: pugixml.cpp:6513
xpath_allocator_capture(xpath_allocator *alloc)
Definition: pugixml.cpp:7771
int depth() const
Definition: pugixml.cpp:5120
typedef int(APIENTRYP RE_PFNGLXSWAPINTERVALSGIPROC)(int)
PUGI__FN void text_output_cdata(xml_buffered_writer &writer, const char_t *s)
Definition: pugixml.cpp:3970
bool empty() const
Definition: pugixml.cpp:12360
xpath_node_set_raw eval_node_set(const xpath_context &c, const xpath_stack &stack, nodeset_eval_t eval)
Definition: pugixml.cpp:10905
xml_node_iterator iterator
Definition: pugixml.hpp:710
xml_extra_buffer * next
Definition: pugixml.cpp:1142
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:1570
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glcorearb.h:2540
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:7418
GLbitfield flags
Definition: glcorearb.h:1596
#define PUGI__UNSIGNED_OVERFLOW
Definition: pugixml.cpp:118
xpath_string eval_string(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:10662
SYS_API double fmod(double x, double y)
PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void *contents, size_t size)
Definition: pugixml.cpp:2024
#define PUGI__FN_NO_INLINE
Definition: pugixml.cpp:156
cvex test(vector P=0;int unbound=3;export float s=0;export vector Cf=0;)
Definition: test.vfl:11
const char_t * _query
Definition: pugixml.cpp:11182
xml_attribute append_attribute(const char_t *name)
Definition: pugixml.cpp:5700
xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset=0)
Definition: pugixml.cpp:2907
wchar_selector< sizeof(wchar_t)>::writer wchar_writer
Definition: pugixml.cpp:1808
xml_node last_child() const
Definition: pugixml.cpp:5675
xpath_allocator * temp
Definition: pugixml.cpp:7787
static void destroy(xml_stream_chunk *chunk)
Definition: pugixml.cpp:4846
GLenum GLuint GLsizei bufsize
Definition: glcorearb.h:1818
bool operator==(const xml_attribute &r) const
Definition: pugixml.cpp:5157
void append(const xpath_string &o, xpath_allocator *alloc)
Definition: pugixml.cpp:7868
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:4394
#define PUGI__SCANCHAR(ch)
OCIOEXPORT ConstColorSpaceSetRcPtr operator&&(const ConstColorSpaceSetRcPtr &lcss, const ConstColorSpaceSetRcPtr &rcss)
Perform the intersection of two sets.
xml_node prepend_child(xml_node_type type=node_element)
Definition: pugixml.cpp:5857
static xpath_string from_heap_preallocated(const char_t *begin, const char_t *end)
Definition: pugixml.cpp:7844
xpath_variable * _next
Definition: pugixml.hpp:1151
PUGI__FN const char_t * namespace_uri(xml_node node)
Definition: pugixml.cpp:8502
size_t _root_size
Definition: pugixml.cpp:7643
void write_string(const char_t *data)
Definition: pugixml.cpp:3786
void insert_node_after(xml_node_struct *child, xml_node_struct *node)
Definition: pugixml.cpp:1274
typename detail::char_t_impl< S >::type char_t
Definition: core.h:643
char_t data_char[bufcapacity]
Definition: pugixml.cpp:3902
const unsigned int parse_wconv_attribute
Definition: pugixml.hpp:198
PUGI__FN size_t get_valid_length(const char_t *data, size_t length)
Definition: pugixml.cpp:3656
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1580
uint16_t type
Definition: pugixml.cpp:1692
PUGI__FN int get_value_int(const char_t *value)
Definition: pugixml.cpp:4583
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:5047
bool set_name(const char_t *rhs)
Definition: pugixml.cpp:5326
PUGI__FN bool is_nan(double value)
Definition: pugixml.cpp:8218
static xml_memory_page * construct(void *memory)
Definition: pugixml.cpp:463
T mod(T x, int y)
Definition: chrono.h:1648
size_t busy_size
Definition: pugixml.cpp:487
static binary_op_t parse(xpath_lexer &lexer)
Definition: pugixml.cpp:11975
bool is_text_node(xml_node_struct *node)
Definition: pugixml.cpp:4493
void write_direct(const char_t *data, size_t length)
Definition: pugixml.cpp:3732
char_t * data(xpath_allocator *alloc)
Definition: pugixml.cpp:7913
void deallocate_memory(void *ptr, size_t size, xml_memory_page *page)
Definition: pugixml.cpp:597
const char_t * begin
Definition: pugixml.cpp:9104
xpath_node_set::type_t type() const
Definition: pugixml.cpp:9028
PUGI__FN char_t * normalize_space(char_t *buffer)
Definition: pugixml.cpp:8546
void append_attribute(xml_attribute_struct *attr, xml_node_struct *node)
Definition: pugixml.cpp:1327
char_t * parse_doctype_group(char_t *s, char_t endch)
Definition: pugixml.cpp:2997
bool operator!() const
Definition: pugixml.cpp:5448
PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
Definition: pugixml.cpp:7352
utf16_decoder< opt_false > decoder
Definition: pugixml.cpp:1796
xpath_value_type type() const
Definition: pugixml.cpp:12431
size_t size() const
Definition: pugixml.cpp:8934
PUGI__FN const char_t * local_name(const xpath_node &node)
Definition: pugixml.cpp:8471
xml_memory_page * prev
Definition: pugixml.cpp:484
void deallocate_string(char_t *string)
Definition: pugixml.cpp:675
bool operator==(const xml_node_iterator &rhs) const
Definition: pugixml.cpp:6720
xpath_variable_set & operator=(const xpath_variable_set &rhs)
Definition: pugixml.cpp:12522
utf32_writer writer
Definition: pugixml.cpp:1803
void remove_attribute(xml_attribute_struct *attr, xml_node_struct *node)
Definition: pugixml.cpp:1386
void * allocate_memory_oob(size_t size, xml_memory_page *&out_page)
Definition: pugixml.cpp:711
void
Definition: png.h:1083
#define PUGI__NS_END
Definition: pugixml.cpp:154
PUGI__FN void node_output_pi_value(xml_buffered_writer &writer, const char_t *s)
Definition: pugixml.cpp:4057
uint32_t data_u32[bufcapacity]
Definition: pugixml.cpp:3901
bool operator==(const xpath_string &o) const
Definition: pugixml.cpp:7936
IMATH_HOSTDEVICE constexpr int floor(T x) IMATH_NOEXCEPT
Definition: ImathFun.h:112
GLint left
Definition: glcorearb.h:2005
T negative(const T &val)
Return the unary negation of the given value.
Definition: Math.h:128
getFileOption("OpenEXR:storage") storage
Definition: HDK_Image.dox:276
const unsigned int format_no_empty_element_tags
Definition: pugixml.hpp:275
GLboolean * data
Definition: glcorearb.h:131
OIIO_UTIL_API bool copy(string_view from, string_view to, std::string &err)
const GLdouble * v
Definition: glcorearb.h:837
PUGI__NS_END PUGI__NS_BEGIN uint16_t endian_swap(uint16_t value)
Definition: pugixml.cpp:1442
#define PUGI__ENDSWITH(c, e)
Definition: pugixml.cpp:2591
virtual const char * what() const PUGIXML_OVERRIDE
Definition: pugixml.cpp:12183
uint128_t uintptr_t
Definition: format.h:479
bool set_value(const char_t *rhs)
Definition: pugixml.cpp:5333
xml_node append_move(const xml_node &moved)
Definition: pugixml.cpp:6016
float as_float(float def=0) const
Definition: pugixml.cpp:5217
static char_t * parse_wconv(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2786
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:11241
bool set(const char_t *rhs)
Definition: pugixml.cpp:6543
GLuint start
Definition: glcorearb.h:475
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
bool is_posinv_step() const
Definition: pugixml.cpp:11148
GLsizei const GLfloat * value
Definition: glcorearb.h:824
static void deallocate_page(xml_memory_page *page)
Definition: pugixml.cpp:538
xpath_parse_result * _result
Definition: pugixml.cpp:11185
const xpath_node & operator[](size_t index) const
Definition: pugixml.cpp:12365
const unsigned int parse_eol
Definition: pugixml.hpp:195
const unsigned int format_no_declaration
Definition: pugixml.hpp:263
size_t hash_value() const
Definition: pugixml.cpp:5254
PUGI__FN xml_parse_status get_file_size(FILE *file, size_t &out_result)
Definition: pugixml.cpp:4737
double get_number() const
Definition: pugixml.cpp:12441
PUGI__FN bool has_declaration(xml_node_struct *node)
Definition: pugixml.cpp:4333
xpath_memory_block * next
Definition: pugixml.cpp:7630
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
xpath_ast_node(ast_type_t type, xpath_ast_node *left, xpath_ast_node *right, predicate_t test)
Definition: pugixml.cpp:10326
uint8_t type
Definition: pugixml.cpp:1625
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition: pugixml.cpp:5197
char_t * end
Definition: pugixml.cpp:2410
xml_attribute_struct(impl::xml_memory_page *page)
Definition: pugixml.cpp:1100
I median3(I first, I middle, I last, const Pred &pred)
Definition: pugixml.cpp:7511
size_t _busy_size
Definition: pugixml.cpp:704
GLdouble right
Definition: glad.h:2817
GLboolean GLboolean g
Definition: glcorearb.h:1222
xpath_value_type rettype() const
Definition: pugixml.cpp:11163
bool operator==(const xml_named_node_iterator &rhs) const
Definition: pugixml.cpp:6842
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:1587
bool traverse(xml_tree_walker &walker)
Definition: pugixml.cpp:6301
#define SEEK_END
Definition: zconf.h:185
xml_node root() const
Definition: pugixml.cpp:5630
nodeset_eval_t
Definition: pugixml.cpp:9528
xml_parse_result load_file(const char *path, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7208
const char_t * child_value() const
Definition: pugixml.cpp:5640
void(* D)(T *)
Definition: pugixml.cpp:267
namespace_uri_predicate(const char_t *name)
Definition: pugixml.cpp:8484
PUGI__FN char_t * strconv_comment(char_t *s, char_t endch)
Definition: pugixml.cpp:2603
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:7410
PUGI__FN void text_output_indent(xml_buffered_writer &writer, const char_t *indent, size_t indent_length, unsigned int depth)
Definition: pugixml.cpp:3992
xml_node * operator->() const
Definition: pugixml.cpp:6736
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
xml_node first_child() const
Definition: pugixml.cpp:5670
size_t value_type
Definition: pugixml.cpp:1454
xml_node parent() const
Definition: pugixml.cpp:5625
const unsigned int format_no_escapes
Definition: pugixml.hpp:266
GLdouble s
Definition: glad.h:3009
void swap(T &lhs, T &rhs)
Definition: pugixml.cpp:7440
PUGI__FN void reverse(I begin, I end)
Definition: pugixml.cpp:7458
const_iterator end() const
Definition: pugixml.cpp:12376
chartypex_t
Definition: pugixml.cpp:1865
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
PUGI__FN std::string as_utf8_impl(const wchar_t *str, size_t length)
Definition: pugixml.cpp:2302
static xpath_string from_const(const char_t *str)
Definition: pugixml.cpp:7839
PUGI__FN const void * document_buffer_order(const xpath_node &xnode)
Definition: pugixml.cpp:8118
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:1512
xml_attribute prepend_copy(const xml_attribute &proto)
Definition: pugixml.cpp:5787
PUGI__FN PUGI__UNSIGNED_OVERFLOW unsigned int hash_string(const char_t *str)
Definition: pugixml.cpp:8710
PUGI__FN bool node_is_ancestor(xml_node_struct *parent, xml_node_struct *node)
Definition: pugixml.cpp:8111
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:8819
xml_attribute last_attribute() const
Definition: pugixml.cpp:5665
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:2249
PUGI__FN bool check_string_to_number_format(const char_t *string)
Definition: pugixml.cpp:8387
virtual ~xml_tree_walker()
Definition: pugixml.cpp:5116
xml_document_struct(xml_memory_page *page)
Definition: pugixml.cpp:1147
PUGI__FN void sort(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7550
char_t *(* strconv_attribute_t)(char_t *, char_t)
Definition: pugixml.cpp:2730
void insert_attribute_before(xml_attribute_struct *attr, xml_attribute_struct *place, xml_node_struct *node)
Definition: pugixml.cpp:1374
xml_attribute next_attribute() const
Definition: pugixml.cpp:5187
const char_t * prefix
Definition: pugixml.cpp:8481
bool evaluate_boolean(const xpath_node &n) const
Definition: pugixml.cpp:12766
const char_t * value() const
Definition: pugixml.cpp:5533
bool operator!=(const xml_attribute &r) const
Definition: pugixml.cpp:5162
xml_node_type type() const
Definition: pugixml.cpp:5528
xpath_context(const xpath_node &n_, size_t position_, size_t size_)
Definition: pugixml.cpp:9066
xml_node data() const
Definition: pugixml.cpp:6691
xml_encoding encoding
Definition: pugixml.cpp:3907
**But if you need a result
Definition: thread.h:622
xpath_variable_set * _variables
Definition: pugixml.cpp:11183
bool operator==(const xml_node &r) const
Definition: pugixml.cpp:5488
PUGI__FN size_t strlength_wide(const wchar_t *s)
Definition: pugixml.cpp:249
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2138
bool uses_heap() const
Definition: pugixml.cpp:7946
xml_memory_management_function_storage< int > xml_memory
Definition: pugixml.cpp:209
size_t size
Definition: pugixml.cpp:2411
GLdouble GLdouble GLdouble q
Definition: glad.h:2445
xml_parse_result append_buffer(const void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:6163
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:8846
char_t * error_offset
Definition: pugixml.cpp:2919
std::enable_if< UT_EnableBitMask< T >::enable, T & >::type operator&=(T &lhs, T rhs)
Definition: UT_EnumHelper.h:57
#define PUGI__STATIC_ASSERT(cond)
Definition: pugixml.cpp:101
OIIO_FORCEINLINE vbool4 insert(const vbool4 &a, bool val)
Helper: substitute val for a[i].
Definition: simd.h:3556
bool operator<=(const xml_attribute &r) const
Definition: pugixml.cpp:5177
#define PUGI__SCANWHILE(X)
Definition: pugixml.cpp:2597
double evaluate_number(const xpath_node &n) const
Definition: pugixml.cpp:12787
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable *value)
Definition: pugixml.cpp:10307
bool set_value(const char_t *rhs)
Definition: pugixml.cpp:5690
bool remove_children()
Definition: pugixml.cpp:6142
xpath_ast_node(ast_type_t type, xpath_ast_node *left, axis_t axis, nodetest_t test, const char_t *contents)
Definition: pugixml.cpp:10319
xpath_allocator * _alloc
Definition: pugixml.cpp:11179
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:1466
xml_attribute_struct * first_attribute
Definition: pugixml.cpp:1133
char_t * allocate_string(size_t length)
Definition: pugixml.cpp:641
char_t * flush(char_t *s)
Definition: pugixml.cpp:2436
bool empty() const
Definition: pugixml.cpp:6473
xml_node previous_sibling() const
Definition: pugixml.cpp:5617
const int default_float_precision
Definition: pugixml.hpp:288
PUGI__FN bool is_little_endian()
Definition: pugixml.cpp:1905
bool remove_attributes()
Definition: pugixml.cpp:6103
GLuint buffer
Definition: glcorearb.h:660
type_t type() const
Definition: pugixml.cpp:12350
xpath_lexer(const char_t *query)
Definition: pugixml.cpp:9128
uint64 value_type
Definition: GA_PrimCompat.h:29
xml_attribute & operator=(const char_t *rhs)
Definition: pugixml.cpp:5264
bool operator>(const xml_node &r) const
Definition: pugixml.cpp:5503
xml_writer & writer
Definition: pugixml.cpp:3905
friend class xml_named_node_iterator
Definition: pugixml.hpp:486
bool empty() const
Definition: pugixml.cpp:5518
static char_t * parse_skip_bom(char_t *s)
Definition: pugixml.cpp:3491
wchar_t type
Definition: pugixml.cpp:1812
PUGI__FN double round_nearest_nzero(double value)
Definition: pugixml.cpp:8459
void flush(const char_t *data, size_t size)
Definition: pugixml.cpp:3714
PUGI__FN char * convert_path_heap(const wchar_t *str)
Definition: pugixml.cpp:4996
bool as_bool(bool def=false) const
Definition: pugixml.cpp:6520
PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(const char_t *value, U minv, U maxv)
Definition: pugixml.cpp:4501
void truncate(xpath_node *pos)
Definition: pugixml.cpp:8983
OutGridT const XformOp bool bool
const char_t * alloc_string(const xpath_lexer_string &value)
Definition: pugixml.cpp:11253
PUGI__FN xpath_string string_value(const xpath_node &na, xpath_allocator *alloc)
Definition: pugixml.cpp:7990
const unsigned int format_write_bom
Definition: pugixml.hpp:257
void destroy_attribute(xml_attribute_struct *a, xml_allocator &alloc)
Definition: pugixml.cpp:1195
axis_t
Definition: pugixml.cpp:9490
const char_t * buffer
Definition: pugixml.cpp:1151
uint32_t * value_type
Definition: pugixml.cpp:1578
xpath_node select_node(const char_t *query, xpath_variable_set *variables=PUGIXML_NULL) const
Definition: pugixml.cpp:12924
bool as_bool(bool def=false) const
Definition: pugixml.cpp:5222
xpath_ast_node * alloc_node(ast_type_t type, xpath_value_type rettype, const char_t *value)
Definition: pugixml.cpp:11217
bool operator!() const
Definition: pugixml.cpp:12919
const unsigned int parse_fragment
Definition: pugixml.hpp:219
bool remove_attribute(const xml_attribute &a)
Definition: pugixml.cpp:6089
bool operator<=(const xml_node &r) const
Definition: pugixml.cpp:5508
xpath_allocator _state
Definition: pugixml.cpp:7781
xml_attribute insert_copy_before(const xml_attribute &proto, const xml_attribute &attr)
Definition: pugixml.cpp:5822
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:8862
IMATH_HOSTDEVICE constexpr int cmp(T a, T b) IMATH_NOEXCEPT
Definition: ImathFun.h:84
xpath_ast_node * parse_step(xpath_ast_node *set)
Definition: pugixml.cpp:11645
void push(char_t *&s, size_t count)
Definition: pugixml.cpp:2419
xml_node insert_move_before(const xml_node &moved, const xml_node &node)
Definition: pugixml.cpp:6066
axis_t parse_axis_name(const xpath_lexer_string &name, bool &specified)
Definition: pugixml.cpp:11389
void append_node(xml_node_struct *child, xml_node_struct *node)
Definition: pugixml.cpp:1235
< returns > If no error
Definition: snippets.dox:2
PUGI__FN bool node_is_before(xml_node_struct *ln, xml_node_struct *rn)
Definition: pugixml.cpp:8068
static Traits::value_type process(const wchar_t *data, size_t size, typename Traits::value_type result, Traits traits)
Definition: pugixml.cpp:1814
void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
Definition: pugixml.cpp:3853
xpath_ast_node * root
Definition: pugixml.cpp:12149
#define PUGI__ENDSEG()
Definition: pugixml.cpp:2599
PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t *data, size_t size)
Definition: pugixml.cpp:1976
#define PUGIXML_NOEXCEPT_IF_NOT_COMPACT
Definition: pugixml.hpp:104
PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
Definition: pugixml.cpp:7357
static value_type high(value_type result, uint32_t)
Definition: pugixml.cpp:1527
xpath_ast_node * parse_filter_expression()
Definition: pugixml.cpp:11606
T data[xml_memory_page_size/sizeof(T)]
Definition: pugixml.cpp:4866
const char_t * nodetest
Definition: pugixml.cpp:9569
const unsigned int parse_escapes
Definition: pugixml.hpp:192
uint8_t data_u8[4 *bufcapacity]
Definition: pugixml.cpp:3899
virtual bool end(xml_node &node)
Definition: pugixml.cpp:5130
bool operator!=(const xml_named_node_iterator &rhs) const
Definition: pugixml.cpp:6847
xml_node find_child_by_attribute(const char_t *name, const char_t *attr_name, const char_t *attr_value) const
Definition: pugixml.cpp:6198
utf32_decoder< opt_false > decoder
Definition: pugixml.cpp:1804
bool empty() const
Definition: pugixml.cpp:7931
xml_parse_status error_status
Definition: pugixml.cpp:2920
char_t * parse_exclamation(char_t *s, xml_node_struct *cursor, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:3043
PUGI__FN bool set_value_ascii(String &dest, Header &header, uintptr_t header_mask, char *buf)
Definition: pugixml.cpp:4654
#define PUGIXML_NOEXCEPT
Definition: pugixml.hpp:96
xml_attribute append_copy(const xml_attribute &proto)
Definition: pugixml.cpp:5770
GLdouble n
Definition: glcorearb.h:2008
void set_next(xpath_ast_node *value)
Definition: pugixml.cpp:10332
#define PUGI__OPTSET(OPT)
Definition: pugixml.cpp:2593
bool operator!=(const xml_node_iterator &rhs) const
Definition: pugixml.cpp:6725
nodetest_t parse_node_test_type(const xpath_lexer_string &name)
Definition: pugixml.cpp:11457
xml_node_struct * _root
Definition: pugixml.hpp:489
GLfloat f
Definition: glcorearb.h:1926
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
xpath_ast_node * parse_expression(int limit=0)
Definition: pugixml.cpp:12081
xpath_ast_node * parse_location_path()
Definition: pugixml.cpp:11855
PUGIXML_DEPRECATED xpath_node select_single_node(const char_t *query, xpath_variable_set *variables=PUGIXML_NULL) const
Definition: pugixml.cpp:12946
xml_attribute_struct * prev_attribute_c
Definition: pugixml.cpp:1110
OCIOEXPORT ConstColorSpaceSetRcPtr operator||(const ConstColorSpaceSetRcPtr &lcss, const ConstColorSpaceSetRcPtr &rcss)
Perform the union of two sets.
size_t freed_size
Definition: pugixml.cpp:488
bool is_xpath_attribute(const char_t *name)
Definition: pugixml.cpp:8658
indent_flags_t
Definition: pugixml.cpp:4234
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:1922
GLintptr offset
Definition: glcorearb.h:665
PUGI__NS_END PUGI__NS_BEGIN xml_attribute_struct * allocate_attribute(xml_allocator &alloc)
Definition: pugixml.cpp:1177
char_t * buffer
Definition: pugixml.cpp:1141
xml_node insert_move_after(const xml_node &moved, const xml_node &node)
Definition: pugixml.cpp:6048
xpath_node_set select_nodes(const char_t *query, xpath_variable_set *variables=PUGIXML_NULL) const
Definition: pugixml.cpp:12935
xml_parse_result load_buffer(const void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7228
xpath_ast_node * error(const char *message)
Definition: pugixml.cpp:11191
bool is_posinv_expr() const
Definition: pugixml.cpp:11117
PUGI__FN char_t * strconv_escape(char_t *s, gap &g)
Definition: pugixml.cpp:2450
bool any(const vbool4 &v)
Definition: simd.h:3600
PUGI__FN char_t tolower_ascii(char_t ch)
Definition: pugixml.cpp:7985
#define PUGI__NS_BEGIN
Definition: pugixml.cpp:153
const char_t * end
Definition: pugixml.cpp:9105
xml_node_struct * next_sibling
Definition: pugixml.cpp:1131
#define PUGI__POPNODE()
Definition: pugixml.cpp:2595
void write(char_t d0, char_t d1, char_t d2)
Definition: pugixml.cpp:3830
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:4801
xml_attribute attribute(const char_t *name) const
Definition: pugixml.cpp:5548
xml_document_struct & get_document(const Object *object)
Definition: pugixml.cpp:1167
const unsigned int parse_pi
Definition: pugixml.hpp:179
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:1555
PUGI__FN void insertion_sort(T *begin, T *end, const Pred &pred)
Definition: pugixml.cpp:7489
const unsigned int parse_embed_pcdata
Definition: pugixml.hpp:224
xpath_allocator temp
Definition: pugixml.cpp:7794
bool strcpy_insitu_allow(size_t length, const Header &header, uintptr_t header_mask, char_t *target)
Definition: pugixml.cpp:2343
const unsigned int parse_ws_pcdata_single
Definition: pugixml.hpp:212
const unsigned int parse_declaration
Definition: pugixml.hpp:204
GLint ref
Definition: glcorearb.h:124
static Traits::value_type process(const uint32_t *data, size_t size, typename Traits::value_type result, Traits)
Definition: pugixml.cpp:1746
xml_attribute & operator*() const
Definition: pugixml.cpp:6791
PUGI__FN FILE * open_file_wide(const wchar_t *path, const wchar_t *mode)
Definition: pugixml.cpp:5017
PUGI__FN void as_utf8_end(char *buffer, size_t size, const wchar_t *str, size_t length)
Definition: pugixml.cpp:2290
xml_node & operator*() const
Definition: pugixml.cpp:6730
xml_node append_child(xml_node_type type=node_element)
Definition: pugixml.cpp:5840
xml_attribute first_attribute() const
Definition: pugixml.cpp:5660
OIIO_UTIL_API FILE * fopen(string_view path, string_view mode)
Version of fopen that can handle UTF-8 paths even on Windows.
PUGI__FN FILE * open_file(const char *path, const char *mode)
Definition: pugixml.cpp:5037
xpath_node * end() const
Definition: pugixml.cpp:8924
wchar_selector< sizeof(wchar_t)>::counter wchar_counter
Definition: pugixml.cpp:1807
xpath_stack stack
Definition: pugixml.cpp:7795
bool operator!=(const xpath_string &o) const
Definition: pugixml.cpp:7941
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value)
Definition: pugixml.cpp:10300
static char_t * parse_simple(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2854
PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator *alloc)
Definition: pugixml.cpp:8320
size_t _depth
Definition: pugixml.cpp:11189
constexpr auto set(type rhs) -> int
Definition: core.h:610
#define PUGI__PUSHNODE(TYPE)
Definition: pugixml.cpp:2594
const char_t * get_string() const
Definition: pugixml.cpp:12446
#define PUGI__THROW_ERROR(err, m)
Definition: pugixml.cpp:2600
#define PUGI__SKIPWS()
Definition: pugixml.cpp:2592
#define PUGI__UNLIKELY(cond)
Definition: pugixml.cpp:97
#define PUGIXML_FUNCTION
Definition: pugixml.hpp:68
iterator end() const
Definition: pugixml.cpp:5458
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:8430
const unsigned int format_skip_control_chars
Definition: pugixml.hpp:278
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:7176
static Traits::value_type process(const uint16_t *data, size_t size, typename Traits::value_type result, Traits)
Definition: pugixml.cpp:1694
xml_node_struct(impl::xml_memory_page *page, xml_node_type type)
Definition: pugixml.cpp:1116
const char_t * string
Definition: pugixml.cpp:9563
PUGI__FN void convert_number_to_mantissa_exponent(double value, char(&buffer)[32], char **out_mantissa, int *out_exponent)
Definition: pugixml.cpp:8291
xml_object_range< xml_node_iterator > children() const
Definition: pugixml.cpp:5473
xpath_variable * add(const char_t *name, xpath_value_type type)
Definition: pugixml.cpp:12629
GLuint GLuint end
Definition: glcorearb.h:475
PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t * integer_to_string(char_t *begin, char_t *end, U value, bool negative)
Definition: pugixml.cpp:4632
PUGI__FN bool convert_buffer_generic(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, D)
Definition: pugixml.cpp:2178
xpath_allocator * result
Definition: pugixml.cpp:7786
xpath_ast_node * error_oom()
Definition: pugixml.cpp:11199
const unsigned int format_indent
Definition: pugixml.hpp:254
void(* deallocation_function)(void *ptr)
Definition: pugixml.hpp:1451
PUGI__FN unsigned char * translate_table_generate(xpath_allocator *alloc, const char_t *from, const char_t *to)
Definition: pugixml.cpp:8596
void * reallocate(void *ptr, size_t old_size, size_t new_size)
Definition: pugixml.cpp:7687
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:803
void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
Definition: pugixml.cpp:3866
void write(char_t d0)
Definition: pugixml.cpp:3811
PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t *str)
Definition: pugixml.cpp:7321
uint8_t * value_type
Definition: pugixml.cpp:1475
PUGI__FN bool hash_insert(const void **table, size_t size, const void *key)
Definition: pugixml.cpp:7580
xml_attribute insert_attribute_after(const char_t *name, const xml_attribute &attr)
Definition: pugixml.cpp:5734
PUGI__FN const char_t * find_char(const char_t *s, char_t c)
Definition: pugixml.cpp:7965
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition: pugixml.cpp:6485
lexeme_t
Definition: pugixml.cpp:9071
const xpath_parse_result & result() const
Definition: pugixml.cpp:12188
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1537
std::basic_string< PUGIXML_CHAR, std::char_traits< PUGIXML_CHAR >, std::allocator< PUGIXML_CHAR > > string_t
Definition: pugixml.hpp:151
xml_extra_buffer * extra_buffers
Definition: pugixml.cpp:1153
void sort(bool reverse=false)
Definition: pugixml.cpp:12381
xml_node next_sibling() const
Definition: pugixml.cpp:5569
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:4106
PUGI__FN bool set_value_convert(String &dest, Header &header, uintptr_t header_mask, float value, int precision)
Definition: pugixml.cpp:4680
xpath_node_set evaluate_node_set(const xpath_node &n) const
Definition: pugixml.cpp:12861
static xpath_string from_heap(const char_t *begin, const char_t *end, xpath_allocator *alloc)
Definition: pugixml.cpp:7851
bool operator>=(const xml_attribute &r) const
Definition: pugixml.cpp:5182
xpath_value_type
Definition: pugixml.hpp:1116
double as_double(double def=0) const
Definition: pugixml.cpp:6506
xml_node_struct * prev_sibling_c
Definition: pugixml.cpp:1130
void set_right(xpath_ast_node *value)
Definition: pugixml.cpp:10337
xpath_variable * variable
Definition: pugixml.cpp:9567
xpath_node_set & operator=(const xpath_node_set &ns)
Definition: pugixml.cpp:12322
GLdouble GLdouble GLint GLint order
Definition: glad.h:2676
#define PUGI__SCANWHILE_UNROLL(X)
Definition: pugixml.cpp:2598
PUGI__FN bool is_attribute_of(xml_attribute_struct *attr, xml_node_struct *node)
Definition: pugixml.cpp:4346
static value_type any(value_type result, uint32_t ch)
Definition: pugixml.cpp:1594
static value_type low(value_type result, uint32_t)
Definition: pugixml.cpp:1565
xml_node * operator->() const
Definition: pugixml.cpp:6858
xml_parse_status status
Definition: pugixml.hpp:1017
GLenum target
Definition: glcorearb.h:1667
PUGI__FN std::basic_string< wchar_t > PUGIXML_FUNCTION as_wide(const char *str)
Definition: pugixml.cpp:7333
bool operator!=(const xml_attribute_iterator &rhs) const
Definition: pugixml.cpp:6786
xpath_ast_node * parse()
Definition: pugixml.cpp:12102
PUGI__FN void delete_xpath_variable(T *var)
Definition: pugixml.cpp:8766
xml_node & operator*() const
Definition: pugixml.cpp:6852
void destroy_node(xml_node_struct *n, xml_allocator &alloc)
Definition: pugixml.cpp:1206
void remove_node(xml_node_struct *node)
Definition: pugixml.cpp:1308
xpath_ast_node * error_rec()
Definition: pugixml.cpp:11207
xml_parse_result load_buffer_inplace(void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition: pugixml.cpp:7235
PUGI__FN xpath_node xpath_first(const xpath_node *begin, const xpath_node *end, xpath_node_set::type_t type)
Definition: pugixml.cpp:8885
xml_parse_status
Definition: pugixml.hpp:987
nodetest_t
Definition: pugixml.cpp:9507
HUSD_API bool eval(VtValue &val, T &ret_val)
xml_node_struct * first_child
Definition: pugixml.cpp:1128
const unsigned int parse_wnorm_attribute
Definition: pugixml.hpp:201
xml_attribute insert_attribute_before(const char_t *name, const xml_attribute &attr)
Definition: pugixml.cpp:5752
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN bool starts_with(const char_t *string, const char_t *pattern)
Definition: pugixml.cpp:7954
xml_attribute_struct * internal_object() const
Definition: pugixml.cpp:5259
void push_back_grow(const xpath_node &node, xpath_allocator *alloc)
Definition: pugixml.cpp:9039
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:1402
void remove_duplicates(xpath_allocator *alloc)
Definition: pugixml.cpp:8990
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:3672
void *(* allocation_function)(size_t size)
Definition: pugixml.hpp:1448
xml_node document_element() const
Definition: pugixml.cpp:7309
GLuint const GLchar * name
Definition: glcorearb.h:786
IMATH_HOSTDEVICE constexpr int sign(T a) IMATH_NOEXCEPT
Definition: ImathFun.h:33
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:1502
friend class xml_node
Definition: pugixml.hpp:745
string_t path(char_t delimiter= '/') const
Definition: pugixml.cpp:6226
PUGI__FN void close_file(FILE *file)
Definition: pugixml.cpp:4830
const char_t * state() const
Definition: pugixml.cpp:9133
uint16_t data_u16[2 *bufcapacity]
Definition: pugixml.cpp:3900
static const axis_t axis
Definition: pugixml.cpp:9537
GLushort pattern
Definition: glad.h:2583
PUGI__FN const char_t * convert_number_to_string_special(double value)
Definition: pugixml.cpp:8231
const unsigned int parse_doctype
Definition: pugixml.hpp:207
xpath_string eval_string_concat(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:10620
bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
Definition: pugixml.cpp:8151
void insert_attribute_after(xml_attribute_struct *attr, xml_attribute_struct *place, xml_node_struct *node)
Definition: pugixml.cpp:1362
xml_allocator(xml_memory_page *root)
Definition: pugixml.cpp:513
string_t evaluate_string(const xpath_node &n) const
Definition: pugixml.cpp:12809
const unsigned int parse_trim_pcdata
Definition: pugixml.hpp:215
GLenum GLenum GLsizei void * table
Definition: glad.h:5129
PUGI__FN xml_encoding get_wchar_encoding()
Definition: pugixml.cpp:1912
xpath_ast_node * alloc_node(ast_type_t type, xpath_ast_node *left, xpath_ast_node *right, predicate_t test)
Definition: pugixml.cpp:11247
xpath_allocator(xpath_memory_block *root, bool *error=0)
Definition: pugixml.cpp:7646
unsigned int as_uint(unsigned int def=0) const
Definition: pugixml.cpp:5207
size_t position
Definition: pugixml.cpp:9064
const char_t * name() const
Definition: pugixml.cpp:5244
auto_deleter(T *data_, D deleter_)
Definition: pugixml.cpp:272
PUGI__FN I min_element(I begin, I end, const Pred &pred)
Definition: pugixml.cpp:7447
xpath_node evaluate_node(const xpath_node &n) const
Definition: pugixml.cpp:12883
const TypeMask operator&(const TypeMask &m1, const TypeMask &m2)
Definition: GA_PrimCompat.h:84
xml_node prepend_move(const xml_node &moved)
Definition: pugixml.cpp:6032
void * allocate_object(size_t size, xml_memory_page *&out_page)
Definition: pugixml.cpp:591
PUGI__FN void truncate_zeros(char *begin, char *end)
Definition: pugixml.cpp:8268
xpath_node n
Definition: pugixml.cpp:9063
char_t *(* strconv_pcdata_t)(char_t *)
Definition: pugixml.cpp:2659
PUGI__FN void text_output(xml_buffered_writer &writer, const char_t *s, chartypex_t type, unsigned int flags)
Definition: pugixml.cpp:3962
xml_node insert_child_before(xml_node_type type, const xml_node &node)
Definition: pugixml.cpp:5874
T * release()
Definition: pugixml.cpp:281
xml_allocator * alloc
Definition: pugixml.cpp:2918
char_t * parse_doctype_ignore(char_t *s)
Definition: pugixml.cpp:2966
gap()
Definition: pugixml.cpp:2413
GLenum mode
Definition: glcorearb.h:99
GLint GLint GLsizei GLsizei GLsizei depth
Definition: glcorearb.h:476
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:4240
bool empty() const
Definition: pugixml.cpp:8929
static void destroy(xpath_query_impl *impl)
Definition: pugixml.cpp:12134
xml_parse_result load_string(const char_t *contents, unsigned int options=parse_default)
Definition: pugixml.cpp:7191
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:3509
xml_node_type
Definition: pugixml.hpp:159
char_t _scratch[32]
Definition: pugixml.cpp:11187
GLenum GLint GLint * precision
Definition: glcorearb.h:1925
auto reserve(std::back_insert_iterator< Container > it, size_t n) -> checked_ptr< typename Container::value_type >
Definition: format.h:578
const char_t * c_str() const
Definition: pugixml.cpp:7903
xpath_ast_node * alloc_node(ast_type_t type, xpath_value_type rettype, double value)
Definition: pugixml.cpp:11223
bool operator!=(const xml_node &r) const
Definition: pugixml.cpp:5493
void prepend_node(xml_node_struct *child, xml_node_struct *node)
Definition: pugixml.cpp:1256
PUGI__FN T * new_xpath_variable(const char_t *name)
Definition: pugixml.cpp:8729
const unsigned int parse_cdata
Definition: pugixml.hpp:185
PUGI__FN void node_output_comment(xml_buffered_writer &writer, const char_t *s)
Definition: pugixml.cpp:4032
const xpath_node_set & get_node_set() const
Definition: pugixml.cpp:12452
#define PUGI__SNPRINTF
Definition: pugixml.cpp:148
xml_attribute_iterator & operator++()
Definition: pugixml.cpp:6803
void(* unspecified_bool_type)(xml_node ***)
Definition: pugixml.hpp:491
GLint j
Definition: glad.h:2733
__hostdev__ uint64_t last(uint32_t i) const
Definition: NanoVDB.h:5976
union xml_buffered_writer::@203 scratch
#define PUGI__SCANCHARTYPE(ct)
bool get_boolean() const
Definition: pugixml.cpp:12436
static Traits::value_type process(const uint8_t *data, size_t size, typename Traits::value_type result, Traits)
Definition: pugixml.cpp:1627
const char_t * get() const
Definition: pugixml.cpp:6478
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:4703
GLsizeiptr size
Definition: glcorearb.h:664
#define SEEK_SET
Definition: zconf.h:183
void write(char_t d0, char_t d1)
Definition: pugixml.cpp:3820
PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t *data, size_t size)
Definition: pugixml.cpp:2203
GLfloat GLfloat GLfloat GLfloat h
Definition: glcorearb.h:2002
GLenum GLenum dst
Definition: glcorearb.h:1793
xpath_ast_node * parse_function(const xpath_lexer_string &name, size_t argc, xpath_ast_node *args[2])
Definition: pugixml.cpp:11269
IMATH_HOSTDEVICE constexpr int ceil(T x) IMATH_NOEXCEPT
Definition: ImathFun.h:119
OIIO_UTIL_API int fseek(FILE *file, int64_t offset, int whence)
PUGI__FN bool convert_number_to_boolean(double value)
Definition: pugixml.cpp:8263
attribute_iterator attributes_begin() const
Definition: pugixml.cpp:5463
int as_int(int def=0) const
Definition: pugixml.cpp:5202
unsigned int as_uint(unsigned int def=0) const
Definition: pugixml.cpp:6499
static allocation_function allocate
Definition: pugixml.cpp:200
PUGI__FN bool get_value_bool(const char_t *value)
Definition: pugixml.cpp:4611
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN size_t strlength(const char_t *s)
Definition: pugixml.cpp:215
bool operator>(const xml_attribute &r) const
Definition: pugixml.cpp:5172
#define PUGIXML_TEXT(t)
Definition: pugixml.hpp:132
binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_)
Definition: pugixml.cpp:11971
bool operator!=(const xpath_node &n) const
Definition: pugixml.cpp:12240
xpath_value_type _type
Definition: pugixml.hpp:1150
bool operator==(const xpath_node &n) const
Definition: pugixml.cpp:12235
const xpath_lexer_string & contents() const
Definition: pugixml.cpp:9417
static char_t * parse_eol(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2822
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:6358
xml_attribute_iterator attribute_iterator
Definition: pugixml.hpp:716
PUGI__FN double convert_string_to_number(const char_t *string)
Definition: pugixml.cpp:8417
xml_node_iterator & operator--()
Definition: pugixml.cpp:6756
const unsigned int format_raw
Definition: pugixml.hpp:260
PUGI__FN size_t as_utf8_begin(const wchar_t *str, size_t length)
Definition: pugixml.cpp:2284
PUGI__FN bool node_is_before_sibling(xml_node_struct *ln, xml_node_struct *rn)
Definition: pugixml.cpp:8044
const_iterator begin() const
Definition: pugixml.cpp:12371
xpath_ast_node * parse_path_or_unary_expression()
Definition: pugixml.cpp:11895
void set_type(xpath_node_set::type_t value)
Definition: pugixml.cpp:9033
xml_node child(const char_t *name) const
Definition: pugixml.cpp:5538
#define PUGI__IS_CHARTYPEX(c, ct)
Definition: pugixml.cpp:1903
static value_type low(value_type result, uint32_t)
Definition: pugixml.cpp:1522
xml_attribute * operator->() const
Definition: pugixml.cpp:6797
attribute_iterator attributes_end() const
Definition: pugixml.cpp:5468
bool operator<(const xml_attribute &r) const
Definition: pugixml.cpp:5167
xml_node_struct * parent
Definition: pugixml.cpp:1126
PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
Definition: pugixml.cpp:7346
bool operator()(xml_attribute a) const
Definition: pugixml.cpp:8492
bool operator<(const xml_node &r) const
Definition: pugixml.cpp:5498
void optimize(xpath_allocator *alloc)
Definition: pugixml.cpp:11037
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:4078
PUGI__FN char_t * translate_table(char_t *buffer, const unsigned char *table)
Definition: pugixml.cpp:8628
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:7434
xpath_variable(xpath_value_type type)
Definition: pugixml.cpp:12405
bool set(bool value)
Definition: pugixml.cpp:12457
virtual void write(const void *data, size_t size) PUGIXML_OVERRIDE
Definition: pugixml.cpp:5095
PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream< T > &stream, void **out_buffer, size_t *out_size)
Definition: pugixml.cpp:4923
xml_node insert_child_after(xml_node_type type, const xml_node &node)
Definition: pugixml.cpp:5892
PUGI__FN std::basic_string< wchar_t > as_wide_impl(const char *str, size_t size)
Definition: pugixml.cpp:2317
xpath_node_set value
Definition: pugixml.cpp:8704
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:2044
PUGI__FN size_t zero_terminate_buffer(void *buffer, size_t size, xml_encoding encoding)
Definition: pugixml.cpp:4777
size_t value_type
Definition: pugixml.cpp:1520
xpath_lexer _lexer
Definition: pugixml.cpp:11180
PUGI__FN bool set_value_integer(String &dest, Header &header, uintptr_t header_mask, U value, bool negative)
Definition: pugixml.cpp:4670
xml_stream_chunk * next
Definition: pugixml.cpp:4863
LeafData & operator=(const LeafData &)=delete
PUGI__FN const char_t * qualified_name(const xpath_node &node)
Definition: pugixml.cpp:8466
static deallocation_function deallocate
Definition: pugixml.cpp:201
bool operator!() const
Definition: pugixml.cpp:5152
GLuint index
Definition: glcorearb.h:786
PUGI__FN bool allow_move(xml_node parent, xml_node child)
Definition: pugixml.cpp:4369
const unsigned int format_save_file_text
Definition: pugixml.hpp:269
xpath_node first() const
Definition: pugixml.cpp:8939
void * allocate_memory(size_t size, xml_memory_page *&out_page)
Definition: pugixml.cpp:545
static bool has_element_node_siblings(xml_node_struct *node)
Definition: pugixml.cpp:3497
void append(const xpath_node *begin_, const xpath_node *end_, xpath_allocator *alloc)
Definition: pugixml.cpp:8954
PUGI__NS_BEGIN PUGI__FN void * default_allocate(size_t size)
Definition: pugixml.cpp:187
xml_object_range< xml_attribute_iterator > attributes() const
Definition: pugixml.cpp:5483
PUGI__FN float get_value_float(const char_t *value)
Definition: pugixml.cpp:4602
xml_writer_file(void *file)
Definition: pugixml.cpp:5076
xml_attribute insert_copy_after(const xml_attribute &proto, const xml_attribute &attr)
Definition: pugixml.cpp:5804
xpath_ast_node * parse_expression_rec(xpath_ast_node *lhs, int limit)
Definition: pugixml.cpp:12027
xpath_ast_node * parse_relative_location_path(xpath_ast_node *set)
Definition: pugixml.cpp:11821
auto ptr(T p) -> const void *
Definition: format.h:4331
GLuint GLfloat * val
Definition: glcorearb.h:1608
void write_buffer(const char_t *data, size_t length)
Definition: pugixml.cpp:3771
void optimize_self(xpath_allocator *alloc)
Definition: pugixml.cpp:11052
OIIO_UTIL_API int64_t ftell(FILE *file)
Version of ftell that works with 64 bit offsets on all systems.
PUGI__FN unsigned int get_value_uint(const char_t *value)
Definition: pugixml.cpp:4588
const char_t * name() const
Definition: pugixml.cpp:12409
char_t * parse_tree(char_t *s, xml_node_struct *root, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:3246
xpath_value_type return_type() const
Definition: pugixml.cpp:12759
iterator begin() const
Definition: pugixml.cpp:5453
xpath_memory_block blocks[2]
Definition: pugixml.cpp:7792
#define PUGI__CHECK_ERROR(err, m)
Definition: pugixml.cpp:2601
char_t * parse_doctype_primitive(char_t *s)
Definition: pugixml.cpp:2933
GA_API const UT_StringHolder N
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node *left=0, xpath_ast_node *right=0)
Definition: pugixml.cpp:10314
const char_t * current_pos() const
Definition: pugixml.cpp:9412
GA_API const UT_StringHolder pivot
utf32_counter counter
Definition: pugixml.cpp:1802
xml_node_struct * internal_object() const
Definition: pugixml.cpp:6353
xml_buffered_writer(xml_writer &writer_, xml_encoding user_encoding)
Definition: pugixml.cpp:3702
PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream< T > &stream, void **out_buffer, size_t *out_size)
Definition: pugixml.cpp:4869
size_t length() const
Definition: pugixml.cpp:7908
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:2212
const char_t * value() const
Definition: pugixml.cpp:5249
bool process(T &func, UT_WorkBuffer &fullpath, exint fullpath_len, const UT_StringArray &paths, const UT_Array< FS_Stat > &stats)
Utility function to process the contents of the traverse() function.
Definition: FS_Traverse.h:24
**If you just want to fire and args
Definition: thread.h:618
xpath_allocator alloc
Definition: pugixml.cpp:12150
#define PUGI__DMC_VOLATILE
Definition: pugixml.cpp:107
#define PUGI__FN
Definition: pugixml.cpp:155
xml_encoding
Definition: pugixml.hpp:237
PUGI__FN bool allow_insert_attribute(xml_node_type parent)
Definition: pugixml.cpp:4355
PUGI__FN void partition3(T *begin, T *end, T pivot, const Pred &pred, T **out_eqbeg, T **out_eqend)
Definition: pugixml.cpp:7523
PUGI__FN void node_copy_attribute(xml_attribute_struct *da, xml_attribute_struct *sa)
Definition: pugixml.cpp:4484
#define PUGI__IS_CHARTYPE(c, ct)
Definition: pugixml.cpp:1902
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:7242
xpath_allocator * _target
Definition: pugixml.cpp:7780
static xpath_ast_node * parse(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
Definition: pugixml.cpp:12116
PUGI__FN const char_t * find_substring(const char_t *s, const char_t *p)
Definition: pugixml.cpp:7974
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:1544
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:3585
PUGI__FN bool copy_xpath_variable(xpath_variable *lhs, const xpath_variable *rhs)
Definition: pugixml.cpp:8797
bool reserve()
Definition: pugixml.cpp:694
OIIO_UTIL_API const char * c_str(string_view str)
bool empty() const
Definition: pugixml.cpp:5239
xml_allocator * allocator
Definition: pugixml.cpp:482
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1606
PUGI__FN void node_output_simple(xml_buffered_writer &writer, xml_node_struct *node, unsigned int flags)
Definition: pugixml.cpp:4178
double eval_number(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:10482
PUGI__FN char_t * strconv_cdata(char_t *s, char_t endch)
Definition: pugixml.cpp:2631
xml_node first_element_by_path(const char_t *path, char_t delimiter= '/') const
Definition: pugixml.cpp:6261
xml_attribute attribute() const
Definition: pugixml.cpp:12211
name_null_sentry(xml_node_struct *node_)
Definition: pugixml.cpp:5062
void insert_node_before(xml_node_struct *child, xml_node_struct *node)
Definition: pugixml.cpp:1291
PUGI__FN void node_output_end(xml_buffered_writer &writer, xml_node_struct *node)
Definition: pugixml.cpp:4168
ast_type_t
Definition: pugixml.cpp:9425
PUGI__FN impl::xpath_ast_node * evaluate_node_set_prepare(xpath_query_impl *impl)
Definition: pugixml.cpp:12155
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:7293
PUGI__FN bool strequal(const char_t *src, const char_t *dst)
Definition: pugixml.cpp:227
static char_t * parse(char_t *s)
Definition: pugixml.cpp:2663
bool operator==(const char_t *other) const
Definition: pugixml.cpp:9111
const unsigned char * table
Definition: pugixml.cpp:9571
static xpath_query_impl * create()
Definition: pugixml.cpp:12126
chartype_t
Definition: pugixml.cpp:1832
static value_type high(value_type result, uint32_t ch)
Definition: pugixml.cpp:1613
size_t size() const
Definition: pugixml.cpp:12355
xml_node node() const
Definition: pugixml.cpp:12206
size_t hash_value() const
Definition: pugixml.cpp:6348
PUGI__FN double gen_nan()
Definition: pugixml.cpp:8203
bool operator!() const
Definition: pugixml.cpp:12230
PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child)
Definition: pugixml.cpp:4360
xpath_ast_node * parse_primary_expression()
Definition: pugixml.cpp:11493
PUGI__FN bool strequalrange(const char_t *lhs, const char_t *rhs, size_t count)
Definition: pugixml.cpp:239
char_t * parse_question(char_t *s, xml_node_struct *&ref_cursor, unsigned int optmsk, char_t endch)
Definition: pugixml.cpp:3152
GLboolean r
Definition: glcorearb.h:1222
bool operator!() const
Definition: pugixml.cpp:6468
PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
Definition: pugixml.cpp:2881
void write(char_t d0, char_t d1, char_t d2, char_t d3)
Definition: pugixml.cpp:3841
#define OIIO_NAMESPACE_END
Definition: oiioversion.h:127
PUGI__FN char_t * translate(char_t *buffer, const char_t *from, const char_t *to, size_t to_length)
Definition: pugixml.cpp:8574
xpath_value_type rettype
Definition: pugixml.cpp:11964
xml_node_iterator & operator++()
Definition: pugixml.cpp:6742
void prepend_attribute(xml_attribute_struct *attr, xml_node_struct *node)
Definition: pugixml.cpp:1346
PUGI__FN I unique(I begin, I end)
Definition: pugixml.cpp:7464
xml_text & operator=(const char_t *rhs)
Definition: pugixml.cpp:6629
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1456
predicate_t
Definition: pugixml.cpp:9520
PUGI__FN xml_encoding get_write_native_encoding()
Definition: pugixml.cpp:3558
PUGI__FN void text_output_escaped(xml_buffered_writer &writer, const char_t *s, chartypex_t type, unsigned int flags)
Definition: pugixml.cpp:3910
xml_named_node_iterator & operator--()
Definition: pugixml.cpp:6878
xpath_node * begin() const
Definition: pugixml.cpp:8919
xml_attribute_struct * next_attribute
Definition: pugixml.cpp:1111
bool set(const char_t *name, bool value)
Definition: pugixml.cpp:12652
uint16_t * value_type
Definition: pugixml.cpp:1535
ptrdiff_t offset_debug() const
Definition: pugixml.cpp:6385
bool operator()(const T &lhs, const T &rhs) const
Definition: pugixml.cpp:7426
PUGI__FN bool set_value_bool(String &dest, Header &header, uintptr_t header_mask, bool value)
Definition: pugixml.cpp:4698
static xml_stream_chunk * create()
Definition: pugixml.cpp:4838
xml_allocator & get_allocator(const Object *object)
Definition: pugixml.cpp:1160
bool operator==(const xml_attribute_iterator &rhs) const
Definition: pugixml.cpp:6781
static Traits::value_type process(const uint8_t *data, size_t size, typename Traits::value_type result, Traits)
Definition: pugixml.cpp:1776
GA_API const UT_StringHolder rest
bool remove_child(const xml_node &n)
Definition: pugixml.cpp:6129
PUGI__FN double round_nearest(double value)
Definition: pugixml.cpp:8454
void * allocate(size_t size)
Definition: pugixml.cpp:7650
xml_memory_page * next
Definition: pugixml.cpp:485
static char_t * parse_wnorm(char_t *s, char_t end_quote)
Definition: pugixml.cpp:2734
xml_node_struct * allocate_node(xml_allocator &alloc, xml_node_type type)
Definition: pugixml.cpp:1186
xml_node_struct * node
Definition: pugixml.cpp:5059
xml_node parent() const
Definition: pugixml.cpp:12216
PUGI__FN void node_copy_tree(xml_node_struct *dn, xml_node_struct *sn)
Definition: pugixml.cpp:4430
xpath_allocator result
Definition: pugixml.cpp:7793
utf16_counter counter
Definition: pugixml.cpp:1794
xpath_node first() const
Definition: pugixml.cpp:12386
state
Definition: core.h:2289
xml_parser(xml_allocator *alloc_)
Definition: pugixml.cpp:2922
xml_attribute_iterator & operator--()
Definition: pugixml.cpp:6817
void revert(const xpath_allocator &state)
Definition: pugixml.cpp:7734
PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
Definition: pugixml.cpp:3567
double as_double(double def=0) const
Definition: pugixml.cpp:5212
const int default_double_precision
Definition: pugixml.hpp:287
xpath_parser(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
Definition: pugixml.cpp:12098
void push_back(const xpath_node &node, xpath_allocator *alloc)
Definition: pugixml.cpp:8946
uint8_t * value_type
Definition: pugixml.cpp:1604
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:11235
const unsigned int parse_comments
Definition: pugixml.hpp:182
xml_named_node_iterator & operator++()
Definition: pugixml.cpp:6864
uint32_t type
Definition: pugixml.cpp:1744
bool set_name(const char_t *rhs)
Definition: pugixml.cpp:5680
const unsigned int format_attribute_single_quote
Definition: pugixml.hpp:281
void * alloc_node()
Definition: pugixml.cpp:11212
const char * description() const
Definition: pugixml.cpp:12400
static value_type low(value_type result, uint32_t ch)
Definition: pugixml.cpp:1477
GLint GLsizei count
Definition: glcorearb.h:405
Definition: format.h:1821
xpath_memory_block * _root
Definition: pugixml.cpp:7642
const char_t * name() const
Definition: pugixml.cpp:5523
size_t value_type
Definition: pugixml.cpp:1563
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:7249
xml_memory_page * _root
Definition: pugixml.cpp:703
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:4959
xpath_memory_block block
Definition: pugixml.cpp:12151
lexeme_t current() const
Definition: pugixml.cpp:9407
std::enable_if< UT_EnableBitMask< T >::enable, T & >::type operator|=(T &lhs, T rhs)
Definition: UT_EnumHelper.h:37
const char * description() const
Definition: pugixml.cpp:6909
xml_attribute previous_attribute() const
Definition: pugixml.cpp:5192
const xpath_parse_result & result() const
Definition: pugixml.cpp:12905
PUGI__FN double get_value_double(const char_t *value)
Definition: pugixml.cpp:4593
bool eval_boolean(const xpath_context &c, const xpath_stack &stack)
Definition: pugixml.cpp:10342
#define OIIO_NAMESPACE_BEGIN
Definition: oiioversion.h:126
PUGI__FN void node_copy_contents(xml_node_struct *dn, xml_node_struct *sn, xml_allocator *shared_alloc)
Definition: pugixml.cpp:4413
xpath_exception(const xpath_parse_result &result)
Definition: pugixml.cpp:12178
GLenum src
Definition: glcorearb.h:1793
virtual void write(const void *data, size_t size) PUGIXML_OVERRIDE
Definition: pugixml.cpp:5080
PUGI__FN_NO_INLINE xml_attribute_struct * append_new_attribute(xml_node_struct *node, xml_allocator &alloc)
Definition: pugixml.cpp:1414
uint8_t type
Definition: pugixml.cpp:1774
xml_writer_stream(std::basic_ostream< char, std::char_traits< char > > &stream)
Definition: pugixml.cpp:5087
PUGI__FN void default_deallocate(void *ptr)
Definition: pugixml.cpp:192
#define PUGI__GETPAGE(n)
Definition: pugixml.cpp:456
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t *value)
Definition: pugixml.cpp:10293
#define PUGI__GETPAGE_IMPL(header)
Definition: pugixml.cpp:453
double OIIO_UTIL_API strtod(const char *nptr, char **endptr=nullptr) noexcept
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:566