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