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