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