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