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