ETISS 0.8.0
Extendable Translating Instruction Set Simulator (version 0.8.0)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
pugixml.cpp
Go to the documentation of this file.
1
14#ifndef SOURCE_PUGIXML_CPP
15#define SOURCE_PUGIXML_CPP
16
17#ifndef NO_ETISS
19#else
20#include "fault/xml/pugixml.hpp"
21#endif
22#include <assert.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#ifdef PUGIXML_WCHAR_MODE
28#include <wchar.h>
29#endif
30
31#ifndef PUGIXML_NO_XPATH
32#include <math.h>
33#include <float.h>
34#ifdef PUGIXML_NO_EXCEPTIONS
35#include <setjmp.h>
36#endif
37#endif
38
39#ifndef PUGIXML_NO_STL
40#include <istream>
41#include <ostream>
42#include <string>
43#endif
44
45// For placement new
46#include <new>
47
48#ifdef _MSC_VER
49#pragma warning(push)
50#pragma warning(disable : 4127) // conditional expression is constant
51#pragma warning(disable : 4324) // structure was padded due to __declspec(align())
52#pragma warning(disable : 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
53#pragma warning(disable : 4702) // unreachable code
54#pragma warning(disable : 4996) // this function or variable may be unsafe
55#pragma warning(disable : 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
56#endif
57
58#ifdef __INTEL_COMPILER
59#pragma warning(disable : 177) // function was declared but never referenced
60#pragma warning(disable : 279) // controlling expression is constant
61#pragma warning(disable : 1478 1786) // function was declared "deprecated"
62#pragma warning(disable : 1684) // conversion from pointer to same-sized integral type
63#endif
64
65#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
66#pragma warn - 8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the
67 // warning go away
68#endif
69
70#ifdef __BORLANDC__
71#pragma option push
72#pragma warn - 8008 // condition is always false
73#pragma warn - 8066 // unreachable code
74#endif
75
76#ifdef __SNC__
77// Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug
78#pragma diag_suppress = 178 // function was declared but never referenced
79#pragma diag_suppress = 237 // controlling expression is constant
80#endif
81
82// Inlining controls
83#if defined(_MSC_VER) && _MSC_VER >= 1300
84#define PUGI__NO_INLINE __declspec(noinline)
85#elif defined(__GNUC__)
86#define PUGI__NO_INLINE __attribute__((noinline))
87#else
88#define PUGI__NO_INLINE
89#endif
90
91// Simple static assertion
92#define PUGI__STATIC_ASSERT(cond) \
93 { \
94 static const char condition_failed[(cond) ? 1 : -1] = { 0 }; \
95 (void)condition_failed[0]; \
96 }
97
98// Digital Mars C++ bug workaround for passing char loaded from memory via stack
99#ifdef __DMC__
100#define PUGI__DMC_VOLATILE volatile
101#else
102#define PUGI__DMC_VOLATILE
103#endif
104
105// Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy
106// because some compilers don't have it at all)
107#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
108using std::memcpy;
109using std::memmove;
110#endif
111
112// In some environments MSVC is a compiler but the CRT lacks certain
113// MSVC-specific features
114#if defined(_MSC_VER) && !defined(__S3E__)
115#define PUGI__MSVC_CRT_VERSION _MSC_VER
116#endif
117
118#ifdef PUGIXML_HEADER_ONLY
119#define PUGI__NS_BEGIN \
120 namespace pugi \
121 { \
122 namespace impl \
123 {
124#define PUGI__NS_END \
125 } \
126 }
127#define PUGI__FN inline
128#define PUGI__FN_NO_INLINE inline
129#else
130#if defined(_MSC_VER) && \
131 _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
132#define PUGI__NS_BEGIN \
133 namespace pugi \
134 { \
135 namespace impl \
136 {
137#define PUGI__NS_END \
138 } \
139 }
140#else
141#define PUGI__NS_BEGIN \
142 namespace pugi \
143 { \
144 namespace impl \
145 { \
146 namespace \
147 {
148#define PUGI__NS_END \
149 } \
150 } \
151 }
152#endif
153#define PUGI__FN
154#define PUGI__FN_NO_INLINE PUGI__NO_INLINE
155#endif
156
157// uintptr_t
158#if !defined(_MSC_VER) || _MSC_VER >= 1600
159#include <stdint.h>
160#else
161#ifndef _UINTPTR_T_DEFINED
162// No native uintptr_t in MSVC6 and in some WinCE versions
163typedef size_t uintptr_t;
164#define _UINTPTR_T_DEFINED
165#endif
167typedef unsigned __int8 uint8_t;
168typedef unsigned __int16 uint16_t;
169typedef unsigned __int32 uint32_t;
171#endif
172
173// Memory allocation
175PUGI__FN void *default_allocate(size_t size)
176{
177 return malloc(size);
178}
179
181{
182 free(ptr);
183}
184
185template <typename T>
187{
188 static allocation_function allocate;
189 static deallocation_function deallocate;
190};
191
192template <typename T>
194template <typename T>
196
199
200// String utilities
202// Get string length
203PUGI__FN size_t strlength(const char_t *s)
204{
205 assert(s);
206
207#ifdef PUGIXML_WCHAR_MODE
208 return wcslen(s);
209#else
210 return strlen(s);
211#endif
212}
213
214// Compare two strings
215PUGI__FN bool strequal(const char_t *src, const char_t *dst)
216{
217 assert(src && dst);
218
219#ifdef PUGIXML_WCHAR_MODE
220 return wcscmp(src, dst) == 0;
221#else
222 return strcmp(src, dst) == 0;
223#endif
224}
225
226// Compare lhs with [rhs_begin, rhs_end)
227PUGI__FN bool strequalrange(const char_t *lhs, const char_t *rhs, size_t count)
228{
229 for (size_t i = 0; i < count; ++i)
230 if (lhs[i] != rhs[i])
231 return false;
232
233 return lhs[count] == 0;
234}
235
236// Get length of wide string, even if CRT lacks wide character support
237PUGI__FN size_t strlength_wide(const wchar_t *s)
238{
239 assert(s);
240
241#ifdef PUGIXML_WCHAR_MODE
242 return wcslen(s);
243#else
244 const wchar_t *end = s;
245 while (*end)
246 end++;
247 return static_cast<size_t>(end - s);
248#endif
249}
250
251#ifdef PUGIXML_WCHAR_MODE
252// Convert string to wide string, assuming all symbols are ASCII
253PUGI__FN void widen_ascii(wchar_t *dest, const char *source)
254{
255 for (const char *i = source; *i; ++i)
256 *dest++ = *i;
257 *dest = 0;
258}
259#endif
261
262#if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH)
263// auto_ptr-like buffer holder for exception recovery
266{
267 void *data;
268 void (*deleter)(void *);
269
270 buffer_holder(void *data_, void (*deleter_)(void *)) : data(data_), deleter(deleter_) {}
271
273 {
274 if (data)
275 deleter(data);
276 }
277
278 void *release()
279 {
280 void *result = data;
281 data = 0;
282 return result;
283 }
284};
286#endif
287
289static const size_t xml_memory_page_size =
290#ifdef PUGIXML_MEMORY_PAGE_SIZE
291 PUGIXML_MEMORY_PAGE_SIZE
292#else
293 32768
294#endif
295 ;
296
302
303struct xml_allocator;
304
306{
308 {
309 if (!memory)
310 return 0; //$ redundant, left for performance
311
312 xml_memory_page *result = static_cast<xml_memory_page *>(memory);
313
314 result->allocator = 0;
315 result->memory = 0;
316 result->prev = 0;
317 result->next = 0;
318 result->busy_size = 0;
319 result->freed_size = 0;
320
321 return result;
322 }
323
325
326 void *memory;
327
330
331 size_t busy_size;
333
334 char data[1];
335};
336
338{
339 uint16_t page_offset; // offset from page->data
340 uint16_t full_size; // 0 if string occupies whole page
341};
342
344{
345 xml_allocator(xml_memory_page *root) : _root(root), _busy_size(root->busy_size) {}
346
348 {
349 size_t size = offsetof(xml_memory_page, data) + data_size;
350
351 // allocate block with some alignment, leaving memory for worst-case padding
352 void *memory = xml_memory::allocate(size + xml_memory_page_alignment);
353 if (!memory)
354 return 0;
355
356 // align upwards to page boundary
357 void *page_memory = reinterpret_cast<void *>(
358 (reinterpret_cast<uintptr_t>(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1));
359
360 // prepare page structure
361 xml_memory_page *page = xml_memory_page::construct(page_memory);
362 assert(page);
363
364 page->memory = memory;
365 page->allocator = _root->allocator;
366
367 return page;
368 }
369
371
372 void *allocate_memory_oob(size_t size, xml_memory_page *&out_page);
373
374 void *allocate_memory(size_t size, xml_memory_page *&out_page)
375 {
376 if (_busy_size + size > xml_memory_page_size)
377 return allocate_memory_oob(size, out_page);
378
379 void *buf = _root->data + _busy_size;
380
381 _busy_size += size;
382
383 out_page = _root;
384
385 return buf;
386 }
387
388 void deallocate_memory(void *ptr, size_t size, xml_memory_page *page)
389 {
390 if (page == _root)
391 page->busy_size = _busy_size;
392
393 assert(ptr >= page->data && ptr < page->data + page->busy_size);
394 (void)!ptr;
395
396 page->freed_size += size;
397 assert(page->freed_size <= page->busy_size);
398
399 if (page->freed_size == page->busy_size)
400 {
401 if (page->next == 0)
402 {
403 assert(_root == page);
404
405 // top page freed, just reset sizes
406 page->busy_size = page->freed_size = 0;
407 _busy_size = 0;
408 }
409 else
410 {
411 assert(_root != page);
412 assert(page->prev);
413
414 // remove from the list
415 page->prev->next = page->next;
416 page->next->prev = page->prev;
417
418 // deallocate
419 deallocate_page(page);
420 }
421 }
422 }
423
424 char_t *allocate_string(size_t length)
425 {
426 // allocate memory for string and header block
427 size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
428
429 // round size up to pointer alignment boundary
430 size_t full_size = (size + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1);
431
432 xml_memory_page *page;
433 xml_memory_string_header *header = static_cast<xml_memory_string_header *>(allocate_memory(full_size, page));
434
435 if (!header)
436 return 0;
437
438 // setup header
439 ptrdiff_t page_offset = reinterpret_cast<char *>(header) - page->data;
440
441 assert(page_offset >= 0 && page_offset < (1 << 16));
442 header->page_offset = static_cast<uint16_t>(page_offset);
443
444 // full_size == 0 for large strings that occupy the whole page
445 assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0));
446 header->full_size = static_cast<uint16_t>(full_size < (1 << 16) ? full_size : 0);
447
448 // round-trip through void* to avoid 'cast increases required alignment of target type' warning
449 // header is guaranteed a pointer-sized alignment, which should be enough for char_t
450 return static_cast<char_t *>(static_cast<void *>(header + 1));
451 }
452
453 void deallocate_string(char_t *string)
454 {
455 // this function casts pointers through void* to avoid 'cast increases required alignment of target type'
456 // warnings we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via
457 // allocate_string
458
459 // get header
460 xml_memory_string_header *header = static_cast<xml_memory_string_header *>(static_cast<void *>(string)) - 1;
461
462 // deallocate
463 size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset;
464 xml_memory_page *page =
465 reinterpret_cast<xml_memory_page *>(static_cast<void *>(reinterpret_cast<char *>(header) - page_offset));
466
467 // if full_size == 0 then this string occupies the whole page
468 size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size;
469
470 deallocate_memory(header, full_size, page);
471 }
472
475};
476
478{
479 const size_t large_allocation_threshold = xml_memory_page_size / 4;
480
481 xml_memory_page *page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
482 out_page = page;
483
484 if (!page)
485 return 0;
486
487 if (size <= large_allocation_threshold)
488 {
490
491 // insert page at the end of linked list
492 page->prev = _root;
493 _root->next = page;
494 _root = page;
495
496 _busy_size = size;
497 }
498 else
499 {
500 // insert page before the end of linked list, so that it is deleted as soon as possible
501 // the last page is not deleted even if it's empty (see deallocate_memory)
502 assert(_root->prev);
503
504 page->prev = _root->prev;
505 page->next = _root;
506
507 _root->prev->next = page;
508 _root->prev = page;
509 }
510
511 // allocate inside page
512 page->busy_size = size;
513
514 return page->data;
515}
517
518namespace pugi
519{
522{
524 xml_attribute_struct(impl::xml_memory_page *page)
525 : header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0)
526 {
527 }
528
530
533
536};
537
540{
543 xml_node_struct(impl::xml_memory_page *page, xml_node_type type)
544 : header(reinterpret_cast<uintptr_t>(page) | (type - 1))
545 , parent(0)
546 , name(0)
547 , value(0)
548 , first_child(0)
549 , prev_sibling_c(0)
550 , next_sibling(0)
551 , first_attribute(0)
552 {
553 }
554
556
558
561
563
566
568};
569} // namespace pugi
570
577
589
591{
592 assert(node);
593
594 return *reinterpret_cast<xml_memory_page *>(node->header & xml_memory_page_pointer_mask)->allocator;
595}
597
598// Low-level DOM operations
600inline xml_attribute_struct *allocate_attribute(xml_allocator &alloc)
601{
602 xml_memory_page *page;
603 void *memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page);
604
605 return new (memory) xml_attribute_struct(page);
606}
607
608inline xml_node_struct *allocate_node(xml_allocator &alloc, xml_node_type type)
609{
610 xml_memory_page *page;
611 void *memory = alloc.allocate_memory(sizeof(xml_node_struct), page);
612
613 return new (memory) xml_node_struct(page, type);
614}
615
616inline void destroy_attribute(xml_attribute_struct *a, xml_allocator &alloc)
617{
618 uintptr_t header = a->header;
619
620 if (header & impl::xml_memory_page_name_allocated_mask)
621 alloc.deallocate_string(a->name);
622 if (header & impl::xml_memory_page_value_allocated_mask)
623 alloc.deallocate_string(a->value);
624
625 alloc.deallocate_memory(a, sizeof(xml_attribute_struct),
626 reinterpret_cast<xml_memory_page *>(header & xml_memory_page_pointer_mask));
627}
628
630{
631 uintptr_t header = n->header;
632
633 if (header & impl::xml_memory_page_name_allocated_mask)
634 alloc.deallocate_string(n->name);
635 if (header & impl::xml_memory_page_value_allocated_mask)
636 alloc.deallocate_string(n->value);
637
638 for (xml_attribute_struct *attr = n->first_attribute; attr;)
639 {
640 xml_attribute_struct *next = attr->next_attribute;
641
642 destroy_attribute(attr, alloc);
643
644 attr = next;
645 }
646
647 for (xml_node_struct *child = n->first_child; child;)
648 {
649 xml_node_struct *next = child->next_sibling;
650
651 destroy_node(child, alloc);
652
653 child = next;
654 }
655
656 alloc.deallocate_memory(n, sizeof(xml_node_struct),
657 reinterpret_cast<xml_memory_page *>(header & xml_memory_page_pointer_mask));
658}
659
661 xml_node_type type = node_element)
662{
663 xml_node_struct *child = allocate_node(alloc, type);
664 if (!child)
665 return 0;
666
667 child->parent = node;
668
669 xml_node_struct *first_child = node->first_child;
670
671 if (first_child)
672 {
673 xml_node_struct *last_child = first_child->prev_sibling_c;
674
675 last_child->next_sibling = child;
676 child->prev_sibling_c = last_child;
677 first_child->prev_sibling_c = child;
678 }
679 else
680 {
681 node->first_child = child;
682 child->prev_sibling_c = child;
683 }
684
685 return child;
686}
687
689{
690 xml_attribute_struct *a = allocate_attribute(alloc);
691 if (!a)
692 return 0;
693
694 xml_attribute_struct *first_attribute = node->first_attribute;
695
696 if (first_attribute)
697 {
698 xml_attribute_struct *last_attribute = first_attribute->prev_attribute_c;
699
700 last_attribute->next_attribute = a;
701 a->prev_attribute_c = last_attribute;
702 first_attribute->prev_attribute_c = a;
703 }
704 else
705 {
706 node->first_attribute = a;
707 a->prev_attribute_c = a;
708 }
709
710 return a;
711}
713
714// Helper classes for code generation
717{
718 enum
719 {
720 value = 0
721 };
722};
723
725{
726 enum
727 {
728 value = 1
729 };
730};
732
733// Unicode utilities
736{
737 return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
738}
739
741{
742 return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
743}
744
746{
747 typedef size_t value_type;
748
750 {
751 // U+0000..U+007F
752 if (ch < 0x80)
753 return result + 1;
754 // U+0080..U+07FF
755 else if (ch < 0x800)
756 return result + 2;
757 // U+0800..U+FFFF
758 else
759 return result + 3;
760 }
761
763 {
764 // U+10000..U+10FFFF
765 return result + 4;
766 }
767};
768
770{
772
774 {
775 // U+0000..U+007F
776 if (ch < 0x80)
777 {
778 *result = static_cast<uint8_t>(ch);
779 return result + 1;
780 }
781 // U+0080..U+07FF
782 else if (ch < 0x800)
783 {
784 result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));
785 result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
786 return result + 2;
787 }
788 // U+0800..U+FFFF
789 else
790 {
791 result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));
792 result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
793 result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
794 return result + 3;
795 }
796 }
797
799 {
800 // U+10000..U+10FFFF
801 result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));
802 result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));
803 result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
804 result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
805 return result + 4;
806 }
807
809 {
810 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
811 }
812};
813
815{
816 typedef size_t value_type;
817
818 static value_type low(value_type result, uint32_t) { return result + 1; }
819
820 static value_type high(value_type result, uint32_t) { return result + 2; }
821};
822
824{
826
828 {
829 *result = static_cast<uint16_t>(ch);
830
831 return result + 1;
832 }
833
835 {
836 uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10;
837 uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff;
838
839 result[0] = static_cast<uint16_t>(0xD800 + msh);
840 result[1] = static_cast<uint16_t>(0xDC00 + lsh);
841
842 return result + 2;
843 }
844
846 {
847 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
848 }
849};
850
852{
853 typedef size_t value_type;
854
855 static value_type low(value_type result, uint32_t) { return result + 1; }
856
857 static value_type high(value_type result, uint32_t) { return result + 1; }
858};
859
861{
863
865 {
866 *result = ch;
867
868 return result + 1;
869 }
870
872 {
873 *result = ch;
874
875 return result + 1;
876 }
877
879 {
880 *result = ch;
881
882 return result + 1;
883 }
884};
885
887{
889
891 {
892 *result = static_cast<uint8_t>(ch > 255 ? '?' : ch);
893
894 return result + 1;
895 }
896
898 {
899 (void)ch;
900
901 *result = '?';
902
903 return result + 1;
904 }
905};
906
907template <size_t size>
909
910template <>
912{
913 typedef uint16_t type;
916};
917
918template <>
920{
921 typedef uint32_t type;
924};
925
926typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
927typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
928
929template <typename Traits, typename opt_swap = opt_false>
931{
932 static inline typename Traits::value_type decode_utf8_block(const uint8_t *data, size_t size,
933 typename Traits::value_type result)
934 {
935 const uint8_t utf8_byte_mask = 0x3f;
936
937 while (size)
938 {
939 uint8_t lead = *data;
940
941 // 0xxxxxxx -> U+0000..U+007F
942 if (lead < 0x80)
943 {
944 result = Traits::low(result, lead);
945 data += 1;
946 size -= 1;
947
948 // process aligned single-byte (ascii) blocks
949 if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
950 {
951 // round-trip through void* to silence 'cast increases required alignment of target type' warnings
952 while (size >= 4 &&
953 (*static_cast<const uint32_t *>(static_cast<const void *>(data)) & 0x80808080) == 0)
954 {
955 result = Traits::low(result, data[0]);
956 result = Traits::low(result, data[1]);
957 result = Traits::low(result, data[2]);
958 result = Traits::low(result, data[3]);
959 data += 4;
960 size -= 4;
961 }
962 }
963 }
964 // 110xxxxx -> U+0080..U+07FF
965 else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
966 {
967 result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
968 data += 2;
969 size -= 2;
970 }
971 // 1110xxxx -> U+0800-U+FFFF
972 else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 &&
973 (data[2] & 0xc0) == 0x80)
974 {
975 result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) |
976 (data[2] & utf8_byte_mask));
977 data += 3;
978 size -= 3;
979 }
980 // 11110xxx -> U+10000..U+10FFFF
981 else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 &&
982 (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
983 {
984 result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) |
985 ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
986 data += 4;
987 size -= 4;
988 }
989 // 10xxxxxx or 11111xxx -> invalid
990 else
991 {
992 data += 1;
993 size -= 1;
994 }
995 }
996
997 return result;
998 }
999
1000 static inline typename Traits::value_type decode_utf16_block(const uint16_t *data, size_t size,
1001 typename Traits::value_type result)
1002 {
1003 const uint16_t *end = data + size;
1004
1005 while (data < end)
1006 {
1007 unsigned int lead = opt_swap::value ? endian_swap(*data) : *data;
1008
1009 // U+0000..U+D7FF
1010 if (lead < 0xD800)
1011 {
1012 result = Traits::low(result, lead);
1013 data += 1;
1014 }
1015 // U+E000..U+FFFF
1016 else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
1017 {
1018 result = Traits::low(result, lead);
1019 data += 1;
1020 }
1021 // surrogate pair lead
1022 else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && data + 1 < end)
1023 {
1024 uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
1025
1026 if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
1027 {
1028 result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
1029 data += 2;
1030 }
1031 else
1032 {
1033 data += 1;
1034 }
1035 }
1036 else
1037 {
1038 data += 1;
1039 }
1040 }
1041
1042 return result;
1043 }
1044
1045 static inline typename Traits::value_type decode_utf32_block(const uint32_t *data, size_t size,
1046 typename Traits::value_type result)
1047 {
1048 const uint32_t *end = data + size;
1049
1050 while (data < end)
1051 {
1052 uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
1053
1054 // U+0000..U+FFFF
1055 if (lead < 0x10000)
1056 {
1057 result = Traits::low(result, lead);
1058 data += 1;
1059 }
1060 // U+10000..U+10FFFF
1061 else
1062 {
1063 result = Traits::high(result, lead);
1064 data += 1;
1065 }
1066 }
1067
1068 return result;
1069 }
1070
1071 static inline typename Traits::value_type decode_latin1_block(const uint8_t *data, size_t size,
1072 typename Traits::value_type result)
1073 {
1074 for (size_t i = 0; i < size; ++i)
1075 {
1076 result = Traits::low(result, data[i]);
1077 }
1078
1079 return result;
1080 }
1081
1082 static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t *data, size_t size,
1083 typename Traits::value_type result)
1084 {
1085 return decode_utf16_block(data, size, result);
1086 }
1087
1088 static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t *data, size_t size,
1089 typename Traits::value_type result)
1090 {
1091 return decode_utf32_block(data, size, result);
1092 }
1093
1094 static inline typename Traits::value_type decode_wchar_block(const wchar_t *data, size_t size,
1095 typename Traits::value_type result)
1096 {
1097 return decode_wchar_block_impl(reinterpret_cast<const wchar_selector<sizeof(wchar_t)>::type *>(data), size,
1098 result);
1099 }
1100};
1101
1102template <typename T>
1103PUGI__FN void convert_utf_endian_swap(T *result, const T *data, size_t length)
1104{
1105 for (size_t i = 0; i < length; ++i)
1106 result[i] = endian_swap(data[i]);
1107}
1108
1109#ifdef PUGIXML_WCHAR_MODE
1110PUGI__FN void convert_wchar_endian_swap(wchar_t *result, const wchar_t *data, size_t length)
1111{
1112 for (size_t i = 0; i < length; ++i)
1113 result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
1114}
1115#endif
1117
1120{
1121 ct_parse_pcdata = 1, // \0, &, \r, <
1122 ct_parse_attr = 2, // \0, &, \r, ', "
1123 ct_parse_attr_ws = 4, // \0, &, \r, ', ", \n, tab
1124 ct_space = 8, // \r, \n, space, tab
1125 ct_parse_cdata = 16, // \0, ], >, \r
1126 ct_parse_comment = 32, // \0, -, >, \r
1127 ct_symbol = 64, // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .
1128 ct_start_symbol = 128 // Any symbol > 127, a-z, A-Z, _, :
1130
1131static const unsigned char chartype_table[256] = {
1132 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0, // 0-15
1133 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
1134 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0, // 32-47
1135 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0, // 48-63
1136 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 64-79
1137 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192, // 80-95
1138 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 96-111
1139 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0, // 112-127
1140
1141 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, // 128+
1142 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1143 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1144 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1145 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1146 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
1147};
1148
1150{
1151 ctx_special_pcdata = 1, // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
1152 ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, "
1153 ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _
1154 ctx_digit = 8, // 0-9
1155 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
1157
1158static const unsigned char chartypex_table[256] = {
1159 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15
1160 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31
1161 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47
1162 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0, // 48-63
1163
1164 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 64-79
1165 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20, // 80-95
1166 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 96-111
1167 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0, // 112-127
1168
1169 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 128+
1170 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1171 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1172 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1173 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
1174};
1175
1176#ifdef PUGIXML_WCHAR_MODE
1177#define PUGI__IS_CHARTYPE_IMPL(c, ct, table) \
1178 ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
1179#else
1180#define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
1181#endif
1182
1183#define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
1184#define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
1185
1187{
1188 unsigned int ui = 1;
1189
1190 return *reinterpret_cast<unsigned char *>(&ui) == 1;
1191}
1192
1194{
1195 PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
1196
1197 if (sizeof(wchar_t) == 2)
1198 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1199 else
1200 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1201}
1202
1204{
1205 // look for BOM in first few bytes
1206 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff)
1207 return encoding_utf32_be;
1208 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0)
1209 return encoding_utf32_le;
1210 if (d0 == 0xfe && d1 == 0xff)
1211 return encoding_utf16_be;
1212 if (d0 == 0xff && d1 == 0xfe)
1213 return encoding_utf16_le;
1214 if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf)
1215 return encoding_utf8;
1216
1217 // look for <, <? or <?xm in various encodings
1218 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c)
1219 return encoding_utf32_be;
1220 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0)
1221 return encoding_utf32_le;
1222 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f)
1223 return encoding_utf16_be;
1224 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0)
1225 return encoding_utf16_le;
1226 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d)
1227 return encoding_utf8;
1228
1229 // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so
1230 // early)
1231 if (d0 == 0 && d1 == 0x3c)
1232 return encoding_utf16_be;
1233 if (d0 == 0x3c && d1 == 0)
1234 return encoding_utf16_le;
1235
1236 // no known BOM detected, assume utf8
1237 return encoding_utf8;
1238}
1239
1240PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void *contents, size_t size)
1241{
1242 // replace wchar encoding with utf implementation
1243 if (encoding == encoding_wchar)
1244 return get_wchar_encoding();
1245
1246 // replace utf16 encoding with utf16 with specific endianness
1247 if (encoding == encoding_utf16)
1248 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1249
1250 // replace utf32 encoding with utf32 with specific endianness
1251 if (encoding == encoding_utf32)
1252 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1253
1254 // only do autodetection if no explicit encoding is requested
1255 if (encoding != encoding_auto)
1256 return encoding;
1257
1258 // skip encoding autodetection if input buffer is too small
1259 if (size < 4)
1260 return encoding_utf8;
1261
1262 // try to guess encoding (based on XML specification, Appendix F.1)
1263 const uint8_t *data = static_cast<const uint8_t *>(contents);
1264
1265 PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1266
1267 return guess_buffer_encoding(d0, d1, d2, d3);
1268}
1269
1270PUGI__FN bool get_mutable_buffer(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size,
1271 bool is_mutable)
1272{
1273 size_t length = size / sizeof(char_t);
1274
1275 if (is_mutable)
1276 {
1277 out_buffer = static_cast<char_t *>(const_cast<void *>(contents));
1278 out_length = length;
1279 }
1280 else
1281 {
1282 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1283 if (!buffer)
1284 return false;
1285
1286 memcpy(buffer, contents, length * sizeof(char_t));
1287 buffer[length] = 0;
1288
1289 out_buffer = buffer;
1290 out_length = length + 1;
1291 }
1292
1293 return true;
1294}
1295
1296#ifdef PUGIXML_WCHAR_MODE
1297PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
1298{
1299 return (le == encoding_utf16_be && re == encoding_utf16_le) ||
1300 (le == encoding_utf16_le && re == encoding_utf16_be) ||
1301 (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
1302}
1303
1304PUGI__FN bool convert_buffer_endian_swap(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size,
1305 bool is_mutable)
1306{
1307 const char_t *data = static_cast<const char_t *>(contents);
1308 size_t length = size / sizeof(char_t);
1309
1310 if (is_mutable)
1311 {
1312 char_t *buffer = const_cast<char_t *>(data);
1313
1314 convert_wchar_endian_swap(buffer, data, length);
1315
1316 out_buffer = buffer;
1317 out_length = length;
1318 }
1319 else
1320 {
1321 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1322 if (!buffer)
1323 return false;
1324
1325 convert_wchar_endian_swap(buffer, data, length);
1326 buffer[length] = 0;
1327
1328 out_buffer = buffer;
1329 out_length = length + 1;
1330 }
1331
1332 return true;
1333}
1334
1335PUGI__FN bool convert_buffer_utf8(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size)
1336{
1337 const uint8_t *data = static_cast<const uint8_t *>(contents);
1338 size_t data_length = size;
1339
1340 // first pass: get length in wchar_t units
1341 size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, data_length, 0);
1342
1343 // allocate buffer of suitable length
1344 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1345 if (!buffer)
1346 return false;
1347
1348 // second pass: convert utf8 input to wchar_t
1349 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
1350 wchar_writer::value_type oend = utf_decoder<wchar_writer>::decode_utf8_block(data, data_length, obegin);
1351
1352 assert(oend == obegin + length);
1353 *oend = 0;
1354
1355 out_buffer = buffer;
1356 out_length = length + 1;
1357
1358 return true;
1359}
1360
1361template <typename opt_swap>
1362PUGI__FN bool convert_buffer_utf16(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
1363{
1364 const uint16_t *data = static_cast<const uint16_t *>(contents);
1365 size_t data_length = size / sizeof(uint16_t);
1366
1367 // first pass: get length in wchar_t units
1369
1370 // allocate buffer of suitable length
1371 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1372 if (!buffer)
1373 return false;
1374
1375 // second pass: convert utf16 input to wchar_t
1376 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
1377 wchar_writer::value_type oend = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, data_length, obegin);
1378
1379 assert(oend == obegin + length);
1380 *oend = 0;
1381
1382 out_buffer = buffer;
1383 out_length = length + 1;
1384
1385 return true;
1386}
1387
1388template <typename opt_swap>
1389PUGI__FN bool convert_buffer_utf32(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
1390{
1391 const uint32_t *data = static_cast<const uint32_t *>(contents);
1392 size_t data_length = size / sizeof(uint32_t);
1393
1394 // first pass: get length in wchar_t units
1396
1397 // allocate buffer of suitable length
1398 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1399 if (!buffer)
1400 return false;
1401
1402 // second pass: convert utf32 input to wchar_t
1403 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
1404 wchar_writer::value_type oend = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, data_length, obegin);
1405
1406 assert(oend == obegin + length);
1407 *oend = 0;
1408
1409 out_buffer = buffer;
1410 out_length = length + 1;
1411
1412 return true;
1413}
1414
1415PUGI__FN bool convert_buffer_latin1(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size)
1416{
1417 const uint8_t *data = static_cast<const uint8_t *>(contents);
1418 size_t data_length = size;
1419
1420 // get length in wchar_t units
1421 size_t length = data_length;
1422
1423 // allocate buffer of suitable length
1424 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1425 if (!buffer)
1426 return false;
1427
1428 // convert latin1 input to wchar_t
1429 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
1430 wchar_writer::value_type oend = utf_decoder<wchar_writer>::decode_latin1_block(data, data_length, obegin);
1431
1432 assert(oend == obegin + length);
1433 *oend = 0;
1434
1435 out_buffer = buffer;
1436 out_length = length + 1;
1437
1438 return true;
1439}
1440
1441PUGI__FN bool convert_buffer(char_t *&out_buffer, size_t &out_length, xml_encoding encoding, const void *contents,
1442 size_t size, bool is_mutable)
1443{
1444 // get native encoding
1445 xml_encoding wchar_encoding = get_wchar_encoding();
1446
1447 // fast path: no conversion required
1448 if (encoding == wchar_encoding)
1449 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1450
1451 // only endian-swapping is required
1452 if (need_endian_swap_utf(encoding, wchar_encoding))
1453 return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
1454
1455 // source encoding is utf8
1456 if (encoding == encoding_utf8)
1457 return convert_buffer_utf8(out_buffer, out_length, contents, size);
1458
1459 // source encoding is utf16
1460 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
1461 {
1463
1464 return (native_encoding == encoding) ? convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false())
1465 : convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1466 }
1467
1468 // source encoding is utf32
1469 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
1470 {
1472
1473 return (native_encoding == encoding) ? convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false())
1474 : convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1475 }
1476
1477 // source encoding is latin1
1478 if (encoding == encoding_latin1)
1479 return convert_buffer_latin1(out_buffer, out_length, contents, size);
1480
1481 assert(!"Invalid encoding");
1482 return false;
1483}
1484#else
1485template <typename opt_swap>
1486PUGI__FN bool convert_buffer_utf16(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
1487{
1488 const uint16_t *data = static_cast<const uint16_t *>(contents);
1489 size_t data_length = size / sizeof(uint16_t);
1490
1491 // first pass: get length in utf8 units
1493
1494 // allocate buffer of suitable length
1495 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1496 if (!buffer)
1497 return false;
1498
1499 // second pass: convert utf16 input to utf8
1500 uint8_t *obegin = reinterpret_cast<uint8_t *>(buffer);
1501 uint8_t *oend = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, data_length, obegin);
1502
1503 assert(oend == obegin + length);
1504 *oend = 0;
1505
1506 out_buffer = buffer;
1507 out_length = length + 1;
1508
1509 return true;
1510}
1511
1512template <typename opt_swap>
1513PUGI__FN bool convert_buffer_utf32(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
1514{
1515 const uint32_t *data = static_cast<const uint32_t *>(contents);
1516 size_t data_length = size / sizeof(uint32_t);
1517
1518 // first pass: get length in utf8 units
1520
1521 // allocate buffer of suitable length
1522 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1523 if (!buffer)
1524 return false;
1525
1526 // second pass: convert utf32 input to utf8
1527 uint8_t *obegin = reinterpret_cast<uint8_t *>(buffer);
1528 uint8_t *oend = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, data_length, obegin);
1529
1530 assert(oend == obegin + length);
1531 *oend = 0;
1532
1533 out_buffer = buffer;
1534 out_length = length + 1;
1535
1536 return true;
1537}
1538
1539PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t *data, size_t size)
1540{
1541 for (size_t i = 0; i < size; ++i)
1542 if (data[i] > 127)
1543 return i;
1544
1545 return size;
1546}
1547
1548PUGI__FN bool convert_buffer_latin1(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size,
1549 bool is_mutable)
1550{
1551 const uint8_t *data = static_cast<const uint8_t *>(contents);
1552 size_t data_length = size;
1553
1554 // get size of prefix that does not need utf8 conversion
1555 size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
1556 assert(prefix_length <= data_length);
1557
1558 const uint8_t *postfix = data + prefix_length;
1559 size_t postfix_length = data_length - prefix_length;
1560
1561 // if no conversion is needed, just return the original buffer
1562 if (postfix_length == 0)
1563 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1564
1565 // first pass: get length in utf8 units
1566 size_t length = prefix_length + utf_decoder<utf8_counter>::decode_latin1_block(postfix, postfix_length, 0);
1567
1568 // allocate buffer of suitable length
1569 char_t *buffer = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
1570 if (!buffer)
1571 return false;
1572
1573 // second pass: convert latin1 input to utf8
1574 memcpy(buffer, data, prefix_length);
1575
1576 uint8_t *obegin = reinterpret_cast<uint8_t *>(buffer);
1577 uint8_t *oend = utf_decoder<utf8_writer>::decode_latin1_block(postfix, postfix_length, obegin + prefix_length);
1578
1579 assert(oend == obegin + length);
1580 *oend = 0;
1581
1582 out_buffer = buffer;
1583 out_length = length + 1;
1584
1585 return true;
1586}
1587
1588PUGI__FN bool convert_buffer(char_t *&out_buffer, size_t &out_length, xml_encoding encoding, const void *contents,
1589 size_t size, bool is_mutable)
1590{
1591 // fast path: no conversion required
1592 if (encoding == encoding_utf8)
1593 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1594
1595 // source encoding is utf16
1596 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
1597 {
1598 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1599
1600 return (native_encoding == encoding) ? convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false())
1601 : convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1602 }
1603
1604 // source encoding is utf32
1605 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
1606 {
1607 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1608
1609 return (native_encoding == encoding) ? convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false())
1610 : convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1611 }
1612
1613 // source encoding is latin1
1614 if (encoding == encoding_latin1)
1615 return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
1616
1617 assert(!"Invalid encoding");
1618 return false;
1619}
1620#endif
1621
1622PUGI__FN size_t as_utf8_begin(const wchar_t *str, size_t length)
1623{
1624 // get length in utf8 characters
1626}
1627
1628PUGI__FN void as_utf8_end(char *buffer, size_t size, const wchar_t *str, size_t length)
1629{
1630 // convert to utf8
1631 uint8_t *begin = reinterpret_cast<uint8_t *>(buffer);
1633
1634 assert(begin + size == end);
1635 (void)!end;
1636
1637 // zero-terminate
1638 buffer[size] = 0;
1639}
1640
1641#ifndef PUGIXML_NO_STL
1642PUGI__FN std::string as_utf8_impl(const wchar_t *str, size_t length)
1643{
1644 // first pass: get length in utf8 characters
1645 size_t size = as_utf8_begin(str, length);
1646
1647 // allocate resulting string
1648 std::string result;
1649 result.resize(size);
1650
1651 // second pass: convert to utf8
1652 if (size > 0)
1653 as_utf8_end(&result[0], size, str, length);
1654
1655 return result;
1656}
1657
1658PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char *str, size_t size)
1659{
1660 const uint8_t *data = reinterpret_cast<const uint8_t *>(str);
1661
1662 // first pass: get length in wchar_t units
1664
1665 // allocate resulting string
1666 std::basic_string<wchar_t> result;
1667 result.resize(length);
1668
1669 // second pass: convert to wchar_t
1670 if (length > 0)
1671 {
1672 wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
1673 wchar_writer::value_type end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, begin);
1674
1675 assert(begin + length == end);
1676 (void)!end;
1677 }
1678
1679 return result;
1680}
1681#endif
1682
1683inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t *target)
1684{
1685 assert(target);
1686 size_t target_length = strlength(target);
1687
1688 // always reuse document buffer memory if possible
1689 if (!allocated)
1690 return target_length >= length;
1691
1692 // reuse heap memory if waste is not too great
1693 const size_t reuse_threshold = 32;
1694
1695 return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
1696}
1697
1698PUGI__FN bool strcpy_insitu(char_t *&dest, uintptr_t &header, uintptr_t header_mask, const char_t *source)
1699{
1700 assert(header);
1701
1702 size_t source_length = strlength(source);
1703
1704 if (source_length == 0)
1705 {
1706 // empty string and null pointer are equivalent, so just deallocate old memory
1707 xml_allocator *alloc = reinterpret_cast<xml_memory_page *>(header & xml_memory_page_pointer_mask)->allocator;
1708
1709 if (header & header_mask)
1710 alloc->deallocate_string(dest);
1711
1712 // mark the string as not allocated
1713 dest = 0;
1714 header &= ~header_mask;
1715
1716 return true;
1717 }
1718 else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest))
1719 {
1720 // we can reuse old buffer, so just copy the new data (including zero terminator)
1721 memcpy(dest, source, (source_length + 1) * sizeof(char_t));
1722
1723 return true;
1724 }
1725 else
1726 {
1727 xml_allocator *alloc = reinterpret_cast<xml_memory_page *>(header & xml_memory_page_pointer_mask)->allocator;
1728
1729 // allocate new buffer
1730 char_t *buf = alloc->allocate_string(source_length + 1);
1731 if (!buf)
1732 return false;
1733
1734 // copy the string (including zero terminator)
1735 memcpy(buf, source, (source_length + 1) * sizeof(char_t));
1736
1737 // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
1738 if (header & header_mask)
1739 alloc->deallocate_string(dest);
1740
1741 // the string is now allocated, so set the flag
1742 dest = buf;
1743 header |= header_mask;
1744
1745 return true;
1746 }
1747}
1748
1749struct gap
1750{
1751 char_t *end;
1752 size_t size;
1753
1754 gap() : end(0), size(0) {}
1755
1756 // Push new gap, move s count bytes further (skipping the gap).
1757 // Collapse previous gap.
1758 void push(char_t *&s, size_t count)
1759 {
1760 if (end) // there was a gap already; collapse it
1761 {
1762 // Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
1763 assert(s >= end);
1764 memmove(end - size, end, reinterpret_cast<char *>(s) - reinterpret_cast<char *>(end));
1765 }
1766
1767 s += count; // end of current gap
1768
1769 // "merge" two gaps
1770 end = s;
1771 size += count;
1772 }
1773
1774 // Collapse all gaps, return past-the-end pointer
1775 char_t *flush(char_t *s)
1776 {
1777 if (end)
1778 {
1779 // Move [old_gap_end, current_pos) to [old_gap_start, ...)
1780 assert(s >= end);
1781 memmove(end - size, end, reinterpret_cast<char *>(s) - reinterpret_cast<char *>(end));
1782
1783 return s - size;
1784 }
1785 else
1786 return s;
1787 }
1788};
1789
1790PUGI__FN char_t *strconv_escape(char_t *s, gap &g)
1791{
1792 char_t *stre = s + 1;
1793
1794 switch (*stre)
1795 {
1796 case '#': // &#...
1797 {
1798 unsigned int ucsc = 0;
1799
1800 if (stre[1] == 'x') // &#x... (hex code)
1801 {
1802 stre += 2;
1803
1804 char_t ch = *stre;
1805
1806 if (ch == ';')
1807 return stre;
1808
1809 for (;;)
1810 {
1811 if (static_cast<unsigned int>(ch - '0') <= 9)
1812 ucsc = 16 * ucsc + (ch - '0');
1813 else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)
1814 ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);
1815 else if (ch == ';')
1816 break;
1817 else // cancel
1818 return stre;
1819
1820 ch = *++stre;
1821 }
1822
1823 ++stre;
1824 }
1825 else // &#... (dec code)
1826 {
1827 char_t ch = *++stre;
1828
1829 if (ch == ';')
1830 return stre;
1831
1832 for (;;)
1833 {
1834 if (static_cast<unsigned int>(static_cast<unsigned int>(ch) - '0') <= 9)
1835 ucsc = 10 * ucsc + (ch - '0');
1836 else if (ch == ';')
1837 break;
1838 else // cancel
1839 return stre;
1840
1841 ch = *++stre;
1842 }
1843
1844 ++stre;
1845 }
1846
1847#ifdef PUGIXML_WCHAR_MODE
1848 s = reinterpret_cast<char_t *>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
1849#else
1850 s = reinterpret_cast<char_t *>(utf8_writer::any(reinterpret_cast<uint8_t *>(s), ucsc));
1851#endif
1852
1853 g.push(s, stre - s);
1854 return stre;
1855 }
1856
1857 case 'a': // &a
1858 {
1859 ++stre;
1860
1861 if (*stre == 'm') // &am
1862 {
1863 if (*++stre == 'p' && *++stre == ';') // &amp;
1864 {
1865 *s++ = '&';
1866 ++stre;
1867
1868 g.push(s, stre - s);
1869 return stre;
1870 }
1871 }
1872 else if (*stre == 'p') // &ap
1873 {
1874 if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // &apos;
1875 {
1876 *s++ = '\'';
1877 ++stre;
1878
1879 g.push(s, stre - s);
1880 return stre;
1881 }
1882 }
1883 break;
1884 }
1885
1886 case 'g': // &g
1887 {
1888 if (*++stre == 't' && *++stre == ';') // &gt;
1889 {
1890 *s++ = '>';
1891 ++stre;
1892
1893 g.push(s, stre - s);
1894 return stre;
1895 }
1896 break;
1897 }
1898
1899 case 'l': // &l
1900 {
1901 if (*++stre == 't' && *++stre == ';') // &lt;
1902 {
1903 *s++ = '<';
1904 ++stre;
1905
1906 g.push(s, stre - s);
1907 return stre;
1908 }
1909 break;
1910 }
1911
1912 case 'q': // &q
1913 {
1914 if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // &quot;
1915 {
1916 *s++ = '"';
1917 ++stre;
1918
1919 g.push(s, stre - s);
1920 return stre;
1921 }
1922 break;
1923 }
1924
1925 default:
1926 break;
1927 }
1928
1929 return stre;
1930}
1931
1932// Utility macro for last character handling
1933#define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
1934
1935PUGI__FN char_t *strconv_comment(char_t *s, char_t endch)
1936{
1937 gap g;
1938
1939 while (true)
1940 {
1942 ++s;
1943
1944 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
1945 {
1946 *s++ = '\n'; // replace first one with 0x0a
1947
1948 if (*s == '\n')
1949 g.push(s, 1);
1950 }
1951 else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here
1952 {
1953 *g.flush(s) = 0;
1954
1955 return s + (s[2] == '>' ? 3 : 2);
1956 }
1957 else if (*s == 0)
1958 {
1959 return 0;
1960 }
1961 else
1962 ++s;
1963 }
1964}
1965
1966PUGI__FN char_t *strconv_cdata(char_t *s, char_t endch)
1967{
1968 gap g;
1969
1970 while (true)
1971 {
1973 ++s;
1974
1975 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
1976 {
1977 *s++ = '\n'; // replace first one with 0x0a
1978
1979 if (*s == '\n')
1980 g.push(s, 1);
1981 }
1982 else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here
1983 {
1984 *g.flush(s) = 0;
1985
1986 return s + 1;
1987 }
1988 else if (*s == 0)
1989 {
1990 return 0;
1991 }
1992 else
1993 ++s;
1994 }
1995}
1996
1997typedef char_t *(*strconv_pcdata_t)(char_t *);
1998
1999template <typename opt_trim, typename opt_eol, typename opt_escape>
2001{
2002 static char_t *parse(char_t *s)
2003 {
2004 gap g;
2005
2006 char_t *begin = s;
2007
2008 while (true)
2009 {
2011 ++s;
2012
2013 if (*s == '<') // PCDATA ends here
2014 {
2015 char_t *end = g.flush(s);
2016
2017 if (opt_trim::value)
2018 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2019 --end;
2020
2021 *end = 0;
2022
2023 return s + 1;
2024 }
2025 else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
2026 {
2027 *s++ = '\n'; // replace first one with 0x0a
2028
2029 if (*s == '\n')
2030 g.push(s, 1);
2031 }
2032 else if (opt_escape::value && *s == '&')
2033 {
2034 s = strconv_escape(s, g);
2035 }
2036 else if (*s == 0)
2037 {
2038 char_t *end = g.flush(s);
2039
2040 if (opt_trim::value)
2041 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2042 --end;
2043
2044 *end = 0;
2045
2046 return s;
2047 }
2048 else
2049 ++s;
2050 }
2051 }
2052};
2053
2055{
2056 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
2057
2058 switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (eol escapes trim)
2059 {
2060 case 0:
2062 case 1:
2064 case 2:
2066 case 3:
2068 case 4:
2070 case 5:
2072 case 6:
2074 case 7:
2076 default:
2077 assert(false);
2078 return 0; // should not get here
2079 }
2080}
2081
2082typedef char_t *(*strconv_attribute_t)(char_t *, char_t);
2083
2084template <typename opt_escape>
2086{
2087 static char_t *parse_wnorm(char_t *s, char_t end_quote)
2088 {
2089 gap g;
2090
2091 // trim leading whitespaces
2093 {
2094 char_t *str = s;
2095
2096 do
2097 ++str;
2098 while (PUGI__IS_CHARTYPE(*str, ct_space));
2099
2100 g.push(s, str - s);
2101 }
2102
2103 while (true)
2104 {
2106 ++s;
2107
2108 if (*s == end_quote)
2109 {
2110 char_t *str = g.flush(s);
2111
2112 do
2113 *str-- = 0;
2114 while (PUGI__IS_CHARTYPE(*str, ct_space));
2115
2116 return s + 1;
2117 }
2118 else if (PUGI__IS_CHARTYPE(*s, ct_space))
2119 {
2120 *s++ = ' ';
2121
2123 {
2124 char_t *str = s + 1;
2125 while (PUGI__IS_CHARTYPE(*str, ct_space))
2126 ++str;
2127
2128 g.push(s, str - s);
2129 }
2130 }
2131 else if (opt_escape::value && *s == '&')
2132 {
2133 s = strconv_escape(s, g);
2134 }
2135 else if (!*s)
2136 {
2137 return 0;
2138 }
2139 else
2140 ++s;
2141 }
2142 }
2143
2144 static char_t *parse_wconv(char_t *s, char_t end_quote)
2145 {
2146 gap g;
2147
2148 while (true)
2149 {
2151 ++s;
2152
2153 if (*s == end_quote)
2154 {
2155 *g.flush(s) = 0;
2156
2157 return s + 1;
2158 }
2159 else if (PUGI__IS_CHARTYPE(*s, ct_space))
2160 {
2161 if (*s == '\r')
2162 {
2163 *s++ = ' ';
2164
2165 if (*s == '\n')
2166 g.push(s, 1);
2167 }
2168 else
2169 *s++ = ' ';
2170 }
2171 else if (opt_escape::value && *s == '&')
2172 {
2173 s = strconv_escape(s, g);
2174 }
2175 else if (!*s)
2176 {
2177 return 0;
2178 }
2179 else
2180 ++s;
2181 }
2182 }
2183
2184 static char_t *parse_eol(char_t *s, char_t end_quote)
2185 {
2186 gap g;
2187
2188 while (true)
2189 {
2191 ++s;
2192
2193 if (*s == end_quote)
2194 {
2195 *g.flush(s) = 0;
2196
2197 return s + 1;
2198 }
2199 else if (*s == '\r')
2200 {
2201 *s++ = '\n';
2202
2203 if (*s == '\n')
2204 g.push(s, 1);
2205 }
2206 else if (opt_escape::value && *s == '&')
2207 {
2208 s = strconv_escape(s, g);
2209 }
2210 else if (!*s)
2211 {
2212 return 0;
2213 }
2214 else
2215 ++s;
2216 }
2217 }
2218
2219 static char_t *parse_simple(char_t *s, char_t end_quote)
2220 {
2221 gap g;
2222
2223 while (true)
2224 {
2226 ++s;
2227
2228 if (*s == end_quote)
2229 {
2230 *g.flush(s) = 0;
2231
2232 return s + 1;
2233 }
2234 else if (opt_escape::value && *s == '&')
2235 {
2236 s = strconv_escape(s, g);
2237 }
2238 else if (!*s)
2239 {
2240 return 0;
2241 }
2242 else
2243 ++s;
2244 }
2245 }
2246};
2247
2249{
2250 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 &&
2251 parse_wnorm_attribute == 0x80);
2252
2253 switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes)
2254 {
2255 case 0:
2257 case 1:
2259 case 2:
2261 case 3:
2263 case 4:
2265 case 5:
2267 case 6:
2269 case 7:
2271 case 8:
2273 case 9:
2275 case 10:
2277 case 11:
2279 case 12:
2281 case 13:
2283 case 14:
2285 case 15:
2287 default:
2288 assert(false);
2289 return 0; // should not get here
2290 }
2291}
2292
2293inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
2294{
2295 xml_parse_result result;
2296 result.status = status;
2297 result.offset = offset;
2298
2299 return result;
2300}
2301
2303{
2306 xml_parse_status error_status;
2307
2308// Parser utilities.
2309#define PUGI__SKIPWS() \
2310 { \
2311 while (PUGI__IS_CHARTYPE(*s, ct_space)) \
2312 ++s; \
2313 }
2314#define PUGI__OPTSET(OPT) (optmsk & (OPT))
2315#define PUGI__PUSHNODE(TYPE) \
2316 { \
2317 cursor = append_node(cursor, alloc, TYPE); \
2318 if (!cursor) \
2319 PUGI__THROW_ERROR(status_out_of_memory, s); \
2320 }
2321#define PUGI__POPNODE() \
2322 { \
2323 cursor = cursor->parent; \
2324 }
2325#define PUGI__SCANFOR(X) \
2326 { \
2327 while (*s != 0 && !(X)) \
2328 ++s; \
2329 }
2330#define PUGI__SCANWHILE(X) \
2331 { \
2332 while ((X)) \
2333 ++s; \
2334 }
2335#define PUGI__ENDSEG() \
2336 { \
2337 ch = *s; \
2338 *s = 0; \
2339 ++s; \
2340 }
2341#define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t *>(0)
2342#define PUGI__CHECK_ERROR(err, m) \
2343 { \
2344 if (*s == 0) \
2345 PUGI__THROW_ERROR(err, m); \
2346 }
2347
2348 xml_parser(const xml_allocator &alloc_) : alloc(alloc_), error_offset(0), error_status(status_ok) {}
2349
2350 // DOCTYPE consists of nested sections of the following possible types:
2351 // <!-- ... -->, <? ... ?>, "...", '...'
2352 // <![...]]>
2353 // <!...>
2354 // First group can not contain nested groups
2355 // Second group can contain nested groups of the same type
2356 // Third group can contain all other groups
2358 {
2359 if (*s == '"' || *s == '\'')
2360 {
2361 // quoted string
2362 char_t ch = *s++;
2363 PUGI__SCANFOR(*s == ch);
2364 if (!*s)
2365 PUGI__THROW_ERROR(status_bad_doctype, s);
2366
2367 s++;
2368 }
2369 else if (s[0] == '<' && s[1] == '?')
2370 {
2371 // <? ... ?>
2372 s += 2;
2373 PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
2374 if (!*s)
2375 PUGI__THROW_ERROR(status_bad_doctype, s);
2376
2377 s += 2;
2378 }
2379 else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')
2380 {
2381 s += 4;
2382 PUGI__SCANFOR(s[0] == '-' && s[1] == '-' &&
2383 s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
2384 if (!*s)
2385 PUGI__THROW_ERROR(status_bad_doctype, s);
2386
2387 s += 4;
2388 }
2389 else
2390 PUGI__THROW_ERROR(status_bad_doctype, s);
2391
2392 return s;
2393 }
2394
2395 char_t *parse_doctype_ignore(char_t *s)
2396 {
2397 assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
2398 s++;
2399
2400 while (*s)
2401 {
2402 if (s[0] == '<' && s[1] == '!' && s[2] == '[')
2403 {
2404 // nested ignore section
2406 if (!s)
2407 return s;
2408 }
2409 else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
2410 {
2411 // ignore section end
2412 s += 3;
2413
2414 return s;
2415 }
2416 else
2417 s++;
2418 }
2419
2420 PUGI__THROW_ERROR(status_bad_doctype, s);
2421 }
2422
2423 char_t *parse_doctype_group(char_t *s, char_t endch, bool toplevel)
2424 {
2425 assert((s[0] == '<' || s[0] == 0) && s[1] == '!');
2426 s++;
2427
2428 while (*s)
2429 {
2430 if (s[0] == '<' && s[1] == '!' && s[2] != '-')
2431 {
2432 if (s[2] == '[')
2433 {
2434 // ignore
2436 if (!s)
2437 return s;
2438 }
2439 else
2440 {
2441 // some control group
2442 s = parse_doctype_group(s, endch, false);
2443 if (!s)
2444 return s;
2445
2446 // skip >
2447 assert(*s == '>');
2448 s++;
2449 }
2450 }
2451 else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
2452 {
2453 // unknown tag (forbidden), or some primitive group
2455 if (!s)
2456 return s;
2457 }
2458 else if (*s == '>')
2459 {
2460 return s;
2461 }
2462 else
2463 s++;
2464 }
2465
2466 if (!toplevel || endch != '>')
2467 PUGI__THROW_ERROR(status_bad_doctype, s);
2468
2469 return s;
2470 }
2471
2472 char_t *parse_exclamation(char_t *s, xml_node_struct *cursor, unsigned int optmsk, char_t endch)
2473 {
2474 // parse node contents, starting with exclamation mark
2475 ++s;
2476
2477 if (*s == '-') // '<!-...'
2478 {
2479 ++s;
2480
2481 if (*s == '-') // '<!--...'
2482 {
2483 ++s;
2484
2485 if (PUGI__OPTSET(parse_comments))
2486 {
2487 PUGI__PUSHNODE(node_comment); // Append a new node on the tree.
2488 cursor->value = s; // Save the offset.
2489 }
2490
2491 if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments))
2492 {
2493 s = strconv_comment(s, endch);
2494
2495 if (!s)
2496 PUGI__THROW_ERROR(status_bad_comment, cursor->value);
2497 }
2498 else
2499 {
2500 // Scan for terminating '-->'.
2501 PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>'));
2502 PUGI__CHECK_ERROR(status_bad_comment, s);
2503
2504 if (PUGI__OPTSET(parse_comments))
2505 *s = 0; // Zero-terminate this segment at the first terminating '-'.
2506
2507 s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
2508 }
2509 }
2510 else
2511 PUGI__THROW_ERROR(status_bad_comment, s);
2512 }
2513 else if (*s == '[')
2514 {
2515 // '<![CDATA[...'
2516 if (*++s == 'C' && *++s == 'D' && *++s == 'A' && *++s == 'T' && *++s == 'A' && *++s == '[')
2517 {
2518 ++s;
2519
2520 if (PUGI__OPTSET(parse_cdata))
2521 {
2522 PUGI__PUSHNODE(node_cdata); // Append a new node on the tree.
2523 cursor->value = s; // Save the offset.
2524
2525 if (PUGI__OPTSET(parse_eol))
2526 {
2527 s = strconv_cdata(s, endch);
2528
2529 if (!s)
2530 PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
2531 }
2532 else
2533 {
2534 // Scan for terminating ']]>'.
2535 PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
2536 PUGI__CHECK_ERROR(status_bad_cdata, s);
2537
2538 *s++ = 0; // Zero-terminate this segment.
2539 }
2540 }
2541 else // Flagged for discard, but we still have to scan for the terminator.
2542 {
2543 // Scan for terminating ']]>'.
2544 PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
2545 PUGI__CHECK_ERROR(status_bad_cdata, s);
2546
2547 ++s;
2548 }
2549
2550 s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
2551 }
2552 else
2553 PUGI__THROW_ERROR(status_bad_cdata, s);
2554 }
2555 else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' &&
2556 ENDSWITH(s[6], 'E'))
2557 {
2558 s -= 2;
2559
2560 if (cursor->parent)
2561 PUGI__THROW_ERROR(status_bad_doctype, s);
2562
2563 char_t *mark = s + 9;
2564
2565 s = parse_doctype_group(s, endch, true);
2566 if (!s)
2567 return s;
2568
2569 assert((*s == 0 && endch == '>') || *s == '>');
2570 if (*s)
2571 *s++ = 0;
2572
2573 if (PUGI__OPTSET(parse_doctype))
2574 {
2575 while (PUGI__IS_CHARTYPE(*mark, ct_space))
2576 ++mark;
2577
2578 PUGI__PUSHNODE(node_doctype);
2579
2580 cursor->value = mark;
2581
2582 PUGI__POPNODE();
2583 }
2584 }
2585 else if (*s == 0 && endch == '-')
2586 PUGI__THROW_ERROR(status_bad_comment, s);
2587 else if (*s == 0 && endch == '[')
2588 PUGI__THROW_ERROR(status_bad_cdata, s);
2589 else
2590 PUGI__THROW_ERROR(status_unrecognized_tag, s);
2591
2592 return s;
2593 }
2594
2595 char_t *parse_question(char_t *s, xml_node_struct *&ref_cursor, unsigned int optmsk, char_t endch)
2596 {
2597 // load into registers
2598 xml_node_struct *cursor = ref_cursor;
2599 char_t ch = 0;
2600
2601 // parse node contents, starting with question mark
2602 ++s;
2603
2604 // read PI target
2605 char_t *target = s;
2606
2608 PUGI__THROW_ERROR(status_bad_pi, s);
2609
2611 PUGI__CHECK_ERROR(status_bad_pi, s);
2612
2613 // determine node type; stricmp / strcasecmp is not portable
2614 bool declaration =
2615 (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
2616
2617 if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
2618 {
2619 if (declaration)
2620 {
2621 // disallow non top-level declarations
2622 if (cursor->parent)
2623 PUGI__THROW_ERROR(status_bad_pi, s);
2624
2625 PUGI__PUSHNODE(node_declaration);
2626 }
2627 else
2628 {
2629 PUGI__PUSHNODE(node_pi);
2630 }
2631
2632 cursor->name = target;
2633
2634 PUGI__ENDSEG();
2635
2636 // parse value/attributes
2637 if (ch == '?')
2638 {
2639 // empty node
2640 if (!ENDSWITH(*s, '>'))
2641 PUGI__THROW_ERROR(status_bad_pi, s);
2642 s += (*s == '>');
2643
2644 PUGI__POPNODE();
2645 }
2646 else if (PUGI__IS_CHARTYPE(ch, ct_space))
2647 {
2648 PUGI__SKIPWS();
2649
2650 // scan for tag end
2651 char_t *value = s;
2652
2653 PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
2654 PUGI__CHECK_ERROR(status_bad_pi, s);
2655
2656 if (declaration)
2657 {
2658 // replace ending ? with / so that 'element' terminates properly
2659 *s = '/';
2660
2661 // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to
2662 // LOC_ATTRIBUTES
2663 s = value;
2664 }
2665 else
2666 {
2667 // store value and step over >
2668 cursor->value = value;
2669 PUGI__POPNODE();
2670
2671 PUGI__ENDSEG();
2672
2673 s += (*s == '>');
2674 }
2675 }
2676 else
2677 PUGI__THROW_ERROR(status_bad_pi, s);
2678 }
2679 else
2680 {
2681 // scan for tag end
2682 PUGI__SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
2683 PUGI__CHECK_ERROR(status_bad_pi, s);
2684
2685 s += (s[1] == '>' ? 2 : 1);
2686 }
2687
2688 // store from registers
2689 ref_cursor = cursor;
2690
2691 return s;
2692 }
2693
2694 char_t *parse_tree(char_t *s, xml_node_struct *root, unsigned int optmsk, char_t endch)
2695 {
2696 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
2697 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
2698
2699 char_t ch = 0;
2700 xml_node_struct *cursor = root;
2701 char_t *mark = s;
2702
2703 while (*s != 0)
2704 {
2705 if (*s == '<')
2706 {
2707 ++s;
2708
2709 LOC_TAG:
2710 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
2711 {
2712 PUGI__PUSHNODE(node_element); // Append a new node to the tree.
2713
2714 cursor->name = s;
2715
2716 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
2717 PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
2718
2719 if (ch == '>')
2720 {
2721 // end of tag
2722 }
2723 else if (PUGI__IS_CHARTYPE(ch, ct_space))
2724 {
2725 LOC_ATTRIBUTES:
2726 while (true)
2727 {
2728 PUGI__SKIPWS(); // Eat any whitespace.
2729
2730 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
2731 {
2732 xml_attribute_struct *a =
2733 append_attribute_ll(cursor, alloc); // Make space for this attribute.
2734 if (!a)
2735 PUGI__THROW_ERROR(status_out_of_memory, s);
2736
2737 a->name = s; // Save the offset.
2738
2739 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
2740 PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2741
2742 PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
2743 PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2744
2745 if (PUGI__IS_CHARTYPE(ch, ct_space))
2746 {
2747 PUGI__SKIPWS(); // Eat any whitespace.
2748 PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
2749
2750 ch = *s;
2751 ++s;
2752 }
2753
2754 if (ch == '=') // '<... #=...'
2755 {
2756 PUGI__SKIPWS(); // Eat any whitespace.
2757
2758 if (*s == '"' || *s == '\'') // '<... #="...'
2759 {
2760 ch = *s; // Save quote char to avoid breaking on "''" -or- '""'.
2761 ++s; // Step over the quote.
2762 a->value = s; // Save the offset.
2763
2764 s = strconv_attribute(s, ch);
2765
2766 if (!s)
2767 PUGI__THROW_ERROR(status_bad_attribute, a->value);
2768
2769 // After this line the loop continues from the start;
2770 // Whitespaces, / and > are ok, symbols and EOF are wrong,
2771 // everything else will be detected
2773 PUGI__THROW_ERROR(status_bad_attribute, s);
2774 }
2775 else
2776 PUGI__THROW_ERROR(status_bad_attribute, s);
2777 }
2778 else
2779 PUGI__THROW_ERROR(status_bad_attribute, s);
2780 }
2781 else if (*s == '/')
2782 {
2783 ++s;
2784
2785 if (*s == '>')
2786 {
2787 PUGI__POPNODE();
2788 s++;
2789 break;
2790 }
2791 else if (*s == 0 && endch == '>')
2792 {
2793 PUGI__POPNODE();
2794 break;
2795 }
2796 else
2797 PUGI__THROW_ERROR(status_bad_start_element, s);
2798 }
2799 else if (*s == '>')
2800 {
2801 ++s;
2802
2803 break;
2804 }
2805 else if (*s == 0 && endch == '>')
2806 {
2807 break;
2808 }
2809 else
2810 PUGI__THROW_ERROR(status_bad_start_element, s);
2811 }
2812
2813 // !!!
2814 }
2815 else if (ch == '/') // '<#.../'
2816 {
2817 if (!ENDSWITH(*s, '>'))
2818 PUGI__THROW_ERROR(status_bad_start_element, s);
2819
2820 PUGI__POPNODE(); // Pop.
2821
2822 s += (*s == '>');
2823 }
2824 else if (ch == 0)
2825 {
2826 // we stepped over null terminator, backtrack & handle closing tag
2827 --s;
2828
2829 if (endch != '>')
2830 PUGI__THROW_ERROR(status_bad_start_element, s);
2831 }
2832 else
2833 PUGI__THROW_ERROR(status_bad_start_element, s);
2834 }
2835 else if (*s == '/')
2836 {
2837 ++s;
2838
2839 char_t *name = cursor->name;
2840 if (!name)
2841 PUGI__THROW_ERROR(status_end_element_mismatch, s);
2842
2843 while (PUGI__IS_CHARTYPE(*s, ct_symbol))
2844 {
2845 if (*s++ != *name++)
2846 PUGI__THROW_ERROR(status_end_element_mismatch, s);
2847 }
2848
2849 if (*name)
2850 {
2851 if (*s == 0 && name[0] == endch && name[1] == 0)
2852 PUGI__THROW_ERROR(status_bad_end_element, s);
2853 else
2854 PUGI__THROW_ERROR(status_end_element_mismatch, s);
2855 }
2856
2857 PUGI__POPNODE(); // Pop.
2858
2859 PUGI__SKIPWS();
2860
2861 if (*s == 0)
2862 {
2863 if (endch != '>')
2864 PUGI__THROW_ERROR(status_bad_end_element, s);
2865 }
2866 else
2867 {
2868 if (*s != '>')
2869 PUGI__THROW_ERROR(status_bad_end_element, s);
2870 ++s;
2871 }
2872 }
2873 else if (*s == '?') // '<?...'
2874 {
2875 s = parse_question(s, cursor, optmsk, endch);
2876 if (!s)
2877 return s;
2878
2879 assert(cursor);
2880 if ((cursor->header & xml_memory_page_type_mask) + 1 == node_declaration)
2881 goto LOC_ATTRIBUTES;
2882 }
2883 else if (*s == '!') // '<!...'
2884 {
2885 s = parse_exclamation(s, cursor, optmsk, endch);
2886 if (!s)
2887 return s;
2888 }
2889 else if (*s == 0 && endch == '?')
2890 PUGI__THROW_ERROR(status_bad_pi, s);
2891 else
2892 PUGI__THROW_ERROR(status_unrecognized_tag, s);
2893 }
2894 else
2895 {
2896 mark = s; // Save this offset while searching for a terminator.
2897
2898 PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
2899
2900 if (*s == '<' || !*s)
2901 {
2902 // We skipped some whitespace characters because otherwise we would take the tag branch instead of
2903 // PCDATA one
2904 assert(mark != s);
2905
2906 if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI__OPTSET(parse_trim_pcdata))
2907 {
2908 continue;
2909 }
2910 else if (PUGI__OPTSET(parse_ws_pcdata_single))
2911 {
2912 if (s[0] != '<' || s[1] != '/' || cursor->first_child)
2913 continue;
2914 }
2915 }
2916
2917 if (!PUGI__OPTSET(parse_trim_pcdata))
2918 s = mark;
2919
2920 if (cursor->parent || PUGI__OPTSET(parse_fragment))
2921 {
2922 PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree.
2923 cursor->value = s; // Save the offset.
2924
2925 s = strconv_pcdata(s);
2926
2927 PUGI__POPNODE(); // Pop since this is a standalone.
2928
2929 if (!*s)
2930 break;
2931 }
2932 else
2933 {
2934 PUGI__SCANFOR(*s == '<'); // '...<'
2935 if (!*s)
2936 break;
2937
2938 ++s;
2939 }
2940
2941 // We're after '<'
2942 goto LOC_TAG;
2943 }
2944 }
2945
2946 // check that last tag is closed
2947 if (cursor != root)
2948 PUGI__THROW_ERROR(status_end_element_mismatch, s);
2949
2950 return s;
2951 }
2952
2953#ifdef PUGIXML_WCHAR_MODE
2954 static char_t *parse_skip_bom(char_t *s)
2955 {
2956 unsigned int bom = 0xfeff;
2957 return (s[0] == static_cast<wchar_t>(bom)) ? s + 1 : s;
2958 }
2959#else
2960 static char_t *parse_skip_bom(char_t *s)
2961 {
2962 return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s;
2963 }
2964#endif
2965
2967 {
2968 while (node)
2969 {
2970 xml_node_type type = static_cast<xml_node_type>((node->header & impl::xml_memory_page_type_mask) + 1);
2971 if (type == node_element)
2972 return true;
2973
2974 node = node->next_sibling;
2975 }
2976
2977 return false;
2978 }
2979
2980 static xml_parse_result parse(char_t *buffer, size_t length, xml_document_struct *xmldoc, xml_node_struct *root,
2981 unsigned int optmsk)
2982 {
2983 // allocator object is a part of document object
2984 xml_allocator &alloc = *static_cast<xml_allocator *>(xmldoc);
2985
2986 // early-out for empty documents
2987 if (length == 0)
2988 return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element);
2989
2990 // get last child of the root before parsing
2991 xml_node_struct *last_root_child = root->first_child ? root->first_child->prev_sibling_c : 0;
2992
2993 // create parser on stack
2994 xml_parser parser(alloc);
2995
2996 // save last character and make buffer zero-terminated (speeds up parsing)
2997 char_t endch = buffer[length - 1];
2998 buffer[length - 1] = 0;
2999
3000 // skip BOM to make sure it does not end up as part of parse output
3001 char_t *buffer_data = parse_skip_bom(buffer);
3002
3003 // perform actual parsing
3004 parser.parse_tree(buffer_data, root, optmsk, endch);
3005
3006 // update allocator state
3007 alloc = parser.alloc;
3008
3009 xml_parse_result result =
3010 make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
3011 assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
3012
3013 if (result)
3014 {
3015 // since we removed last character, we have to handle the only possible false positive (stray <)
3016 if (endch == '<')
3017 return make_parse_result(status_unrecognized_tag, length - 1);
3018
3019 // check if there are any element nodes parsed
3020 xml_node_struct *first_root_child_parsed =
3021 last_root_child ? last_root_child->next_sibling : root->first_child;
3022
3023 if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
3024 return make_parse_result(status_no_document_element, length - 1);
3025 }
3026 else
3027 {
3028 // roll back offset if it occurs on a null terminator in the source buffer
3029 if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0)
3030 result.offset--;
3031 }
3032
3033 return result;
3034 }
3035};
3036
3037// Output facilities
3039{
3040#ifdef PUGIXML_WCHAR_MODE
3041 return get_wchar_encoding();
3042#else
3043 return encoding_utf8;
3044#endif
3045}
3046
3047PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
3048{
3049 // replace wchar encoding with utf implementation
3050 if (encoding == encoding_wchar)
3051 return get_wchar_encoding();
3052
3053 // replace utf16 encoding with utf16 with specific endianness
3054 if (encoding == encoding_utf16)
3055 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
3056
3057 // replace utf32 encoding with utf32 with specific endianness
3058 if (encoding == encoding_utf32)
3059 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
3060
3061 // only do autodetection if no explicit encoding is requested
3062 if (encoding != encoding_auto)
3063 return encoding;
3064
3065 // assume utf8 encoding
3066 return encoding_utf8;
3067}
3068
3069#ifdef PUGIXML_WCHAR_MODE
3070PUGI__FN size_t get_valid_length(const char_t *data, size_t length)
3071{
3072 assert(length > 0);
3073
3074 // discard last character if it's the lead of a surrogate pair
3075 return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400)
3076 ? length - 1
3077 : length;
3078}
3079
3080PUGI__FN size_t convert_buffer_output(char_t *r_char, uint8_t *r_u8, uint16_t *r_u16, uint32_t *r_u32,
3081 const char_t *data, size_t length, xml_encoding encoding)
3082{
3083 // only endian-swapping is required
3084 if (need_endian_swap_utf(encoding, get_wchar_encoding()))
3085 {
3086 convert_wchar_endian_swap(r_char, data, length);
3087
3088 return length * sizeof(char_t);
3089 }
3090
3091 // convert to utf8
3092 if (encoding == encoding_utf8)
3093 {
3094 uint8_t *dest = r_u8;
3096
3097 return static_cast<size_t>(end - dest);
3098 }
3099
3100 // convert to utf16
3101 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3102 {
3103 uint16_t *dest = r_u16;
3104
3105 // convert to native utf16
3107
3108 // swap if necessary
3110
3111 if (native_encoding != encoding)
3112 convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
3113
3114 return static_cast<size_t>(end - dest) * sizeof(uint16_t);
3115 }
3116
3117 // convert to utf32
3118 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3119 {
3120 uint32_t *dest = r_u32;
3121
3122 // convert to native utf32
3124
3125 // swap if necessary
3127
3128 if (native_encoding != encoding)
3129 convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
3130
3131 return static_cast<size_t>(end - dest) * sizeof(uint32_t);
3132 }
3133
3134 // convert to latin1
3135 if (encoding == encoding_latin1)
3136 {
3137 uint8_t *dest = r_u8;
3139
3140 return static_cast<size_t>(end - dest);
3141 }
3142
3143 assert(!"Invalid encoding");
3144 return 0;
3145}
3146#else
3147PUGI__FN size_t get_valid_length(const char_t *data, size_t length)
3148{
3149 assert(length > 4);
3150
3151 for (size_t i = 1; i <= 4; ++i)
3152 {
3153 uint8_t ch = static_cast<uint8_t>(data[length - i]);
3154
3155 // either a standalone character or a leading one
3156 if ((ch & 0xc0) != 0x80)
3157 return length - i;
3158 }
3159
3160 // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole
3161 // chunk
3162 return length;
3163}
3164
3165PUGI__FN size_t convert_buffer_output(char_t * /* r_char */, uint8_t *r_u8, uint16_t *r_u16, uint32_t *r_u32,
3166 const char_t *data, size_t length, xml_encoding encoding)
3167{
3168 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3169 {
3170 uint16_t *dest = r_u16;
3171
3172 // convert to native utf16
3173 uint16_t *end =
3174 utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t *>(data), length, dest);
3175
3176 // swap if necessary
3177 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
3178
3179 if (native_encoding != encoding)
3180 convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
3181
3182 return static_cast<size_t>(end - dest) * sizeof(uint16_t);
3183 }
3184
3185 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3186 {
3187 uint32_t *dest = r_u32;
3188
3189 // convert to native utf32
3190 uint32_t *end =
3191 utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t *>(data), length, dest);
3192
3193 // swap if necessary
3194 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
3195
3196 if (native_encoding != encoding)
3197 convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
3198
3199 return static_cast<size_t>(end - dest) * sizeof(uint32_t);
3200 }
3201
3202 if (encoding == encoding_latin1)
3203 {
3204 uint8_t *dest = r_u8;
3205 uint8_t *end =
3206 utf_decoder<latin1_writer>::decode_utf8_block(reinterpret_cast<const uint8_t *>(data), length, dest);
3207
3208 return static_cast<size_t>(end - dest);
3209 }
3210
3211 assert(!"Invalid encoding");
3212 return 0;
3213}
3214#endif
3215
3217{
3220
3221 public:
3222 xml_buffered_writer(xml_writer &writer_, xml_encoding user_encoding)
3223 : writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
3224 {
3226 }
3227
3229
3230 void flush()
3231 {
3233 bufsize = 0;
3234 }
3235
3236 void flush(const char_t *data, size_t size)
3237 {
3238 if (size == 0)
3239 return;
3240
3241 // fast path, just write data
3243 writer.write(data, size * sizeof(char_t));
3244 else
3245 {
3246 // convert chunk
3247 size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16,
3248 scratch.data_u32, data, size, encoding);
3249 assert(result <= sizeof(scratch));
3250
3251 // write data
3252 writer.write(scratch.data_u8, result);
3253 }
3254 }
3255
3256 void write(const char_t *data, size_t length)
3257 {
3258 if (bufsize + length > bufcapacity)
3259 {
3260 // flush the remaining buffer contents
3261 flush();
3262
3263 // handle large chunks
3264 if (length > bufcapacity)
3265 {
3267 {
3268 // fast path, can just write data chunk
3269 writer.write(data, length * sizeof(char_t));
3270 return;
3271 }
3272
3273 // need to convert in suitable chunks
3274 while (length > bufcapacity)
3275 {
3276 // get chunk size by selecting such number of characters that are guaranteed to fit into scratch
3277 // buffer and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
3278 size_t chunk_size = get_valid_length(data, bufcapacity);
3279
3280 // convert chunk and write
3281 flush(data, chunk_size);
3282
3283 // iterate
3284 data += chunk_size;
3285 length -= chunk_size;
3286 }
3287
3288 // small tail is copied below
3289 bufsize = 0;
3290 }
3291 }
3292
3293 memcpy(buffer + bufsize, data, length * sizeof(char_t));
3294 bufsize += length;
3295 }
3296
3297 void write(const char_t *data) { write(data, strlength(data)); }
3298
3299 void write(char_t d0)
3300 {
3301 if (bufsize + 1 > bufcapacity)
3302 flush();
3303
3304 buffer[bufsize + 0] = d0;
3305 bufsize += 1;
3306 }
3307
3308 void write(char_t d0, char_t d1)
3309 {
3310 if (bufsize + 2 > bufcapacity)
3311 flush();
3312
3313 buffer[bufsize + 0] = d0;
3314 buffer[bufsize + 1] = d1;
3315 bufsize += 2;
3316 }
3317
3318 void write(char_t d0, char_t d1, char_t d2)
3319 {
3320 if (bufsize + 3 > bufcapacity)
3321 flush();
3322
3323 buffer[bufsize + 0] = d0;
3324 buffer[bufsize + 1] = d1;
3325 buffer[bufsize + 2] = d2;
3326 bufsize += 3;
3327 }
3328
3329 void write(char_t d0, char_t d1, char_t d2, char_t d3)
3330 {
3331 if (bufsize + 4 > bufcapacity)
3332 flush();
3333
3334 buffer[bufsize + 0] = d0;
3335 buffer[bufsize + 1] = d1;
3336 buffer[bufsize + 2] = d2;
3337 buffer[bufsize + 3] = d3;
3338 bufsize += 4;
3339 }
3340
3341 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
3342 {
3343 if (bufsize + 5 > bufcapacity)
3344 flush();
3345
3346 buffer[bufsize + 0] = d0;
3347 buffer[bufsize + 1] = d1;
3348 buffer[bufsize + 2] = d2;
3349 buffer[bufsize + 3] = d3;
3350 buffer[bufsize + 4] = d4;
3351 bufsize += 5;
3352 }
3353
3354 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
3355 {
3356 if (bufsize + 6 > bufcapacity)
3357 flush();
3358
3359 buffer[bufsize + 0] = d0;
3360 buffer[bufsize + 1] = d1;
3361 buffer[bufsize + 2] = d2;
3362 buffer[bufsize + 3] = d3;
3363 buffer[bufsize + 4] = d4;
3364 buffer[bufsize + 5] = d5;
3365 bufsize += 6;
3366 }
3367
3368 // utf8 maximum expansion: x4 (-> utf32)
3369 // utf16 maximum expansion: x2 (-> utf32)
3370 // utf32 maximum expansion: x1
3371 enum
3372 {
3374#ifdef PUGIXML_MEMORY_OUTPUT_STACK
3375 PUGIXML_MEMORY_OUTPUT_STACK
3376#else
3377 10240
3378#endif
3380 bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4)
3382
3384
3385 union {
3391
3392 xml_writer &writer;
3393 size_t bufsize;
3394 xml_encoding encoding;
3395};
3396
3398{
3399 while (*s)
3400 {
3401 const char_t *prev = s;
3402
3403 // While *s is a usual symbol
3404 while (!PUGI__IS_CHARTYPEX(*s, type))
3405 ++s;
3406
3407 writer.write(prev, static_cast<size_t>(s - prev));
3408
3409 switch (*s)
3410 {
3411 case 0:
3412 break;
3413 case '&':
3414 writer.write('&', 'a', 'm', 'p', ';');
3415 ++s;
3416 break;
3417 case '<':
3418 writer.write('&', 'l', 't', ';');
3419 ++s;
3420 break;
3421 case '>':
3422 writer.write('&', 'g', 't', ';');
3423 ++s;
3424 break;
3425 case '"':
3426 writer.write('&', 'q', 'u', 'o', 't', ';');
3427 ++s;
3428 break;
3429 default: // s is not a usual symbol
3430 {
3431 unsigned int ch = static_cast<unsigned int>(*s++);
3432 assert(ch < 32);
3433
3434 writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');
3435 }
3436 }
3437 }
3438}
3439
3440PUGI__FN void text_output(xml_buffered_writer &writer, const char_t *s, chartypex_t type, unsigned int flags)
3441{
3442 if (flags & format_no_escapes)
3443 writer.write(s);
3444 else
3445 text_output_escaped(writer, s, type);
3446}
3447
3449{
3450 do
3451 {
3452 writer.write('<', '!', '[', 'C', 'D');
3453 writer.write('A', 'T', 'A', '[');
3454
3455 const char_t *prev = s;
3456
3457 // look for ]]> sequence - we can't output it as is since it terminates CDATA
3458 while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>'))
3459 ++s;
3460
3461 // skip ]] if we stopped at ]]>, > will go to the next CDATA section
3462 if (*s)
3463 s += 2;
3464
3465 writer.write(prev, static_cast<size_t>(s - prev));
3466
3467 writer.write(']', ']', '>');
3468 } while (*s);
3469}
3470
3471PUGI__FN void node_output_attributes(xml_buffered_writer &writer, const xml_node &node, unsigned int flags)
3472{
3473 const char_t *default_name = PUGIXML_TEXT(":anonymous");
3474
3475 for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute())
3476 {
3477 writer.write(' ');
3478 writer.write(a.name()[0] ? a.name() : default_name);
3479 writer.write('=', '"');
3480
3481 text_output(writer, a.value(), ctx_special_attr, flags);
3482
3483 writer.write('"');
3484 }
3485}
3486
3487PUGI__FN void node_output(xml_buffered_writer &writer, const xml_node &node, const char_t *indent, unsigned int flags,
3488 unsigned int depth)
3489{
3490 const char_t *default_name = PUGIXML_TEXT(":anonymous");
3491
3492 if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
3493 for (unsigned int i = 0; i < depth; ++i)
3494 writer.write(indent);
3495
3496 switch (node.type())
3497 {
3498 case node_document:
3499 {
3500 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3501 node_output(writer, n, indent, flags, depth);
3502 break;
3503 }
3504
3505 case node_element:
3506 {
3507 const char_t *name = node.name()[0] ? node.name() : default_name;
3508
3509 writer.write('<');
3510 writer.write(name);
3511
3512 node_output_attributes(writer, node, flags);
3513
3514 if (flags & format_raw)
3515 {
3516 if (!node.first_child())
3517 writer.write(' ', '/', '>');
3518 else
3519 {
3520 writer.write('>');
3521
3522 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3523 node_output(writer, n, indent, flags, depth + 1);
3524
3525 writer.write('<', '/');
3526 writer.write(name);
3527 writer.write('>');
3528 }
3529 }
3530 else if (!node.first_child())
3531 writer.write(' ', '/', '>', '\n');
3532 else if (node.first_child() == node.last_child() &&
3533 (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata))
3534 {
3535 writer.write('>');
3536
3537 if (node.first_child().type() == node_pcdata)
3538 text_output(writer, node.first_child().value(), ctx_special_pcdata, flags);
3539 else
3540 text_output_cdata(writer, node.first_child().value());
3541
3542 writer.write('<', '/');
3543 writer.write(name);
3544 writer.write('>', '\n');
3545 }
3546 else
3547 {
3548 writer.write('>', '\n');
3549
3550 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3551 node_output(writer, n, indent, flags, depth + 1);
3552
3553 if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
3554 for (unsigned int i = 0; i < depth; ++i)
3555 writer.write(indent);
3556
3557 writer.write('<', '/');
3558 writer.write(name);
3559 writer.write('>', '\n');
3560 }
3561
3562 break;
3563 }
3564
3565 case node_pcdata:
3566 text_output(writer, node.value(), ctx_special_pcdata, flags);
3567 if ((flags & format_raw) == 0)
3568 writer.write('\n');
3569 break;
3570
3571 case node_cdata:
3572 text_output_cdata(writer, node.value());
3573 if ((flags & format_raw) == 0)
3574 writer.write('\n');
3575 break;
3576
3577 case node_comment:
3578 writer.write('<', '!', '-', '-');
3579 writer.write(node.value());
3580 writer.write('-', '-', '>');
3581 if ((flags & format_raw) == 0)
3582 writer.write('\n');
3583 break;
3584
3585 case node_pi:
3586 case node_declaration:
3587 writer.write('<', '?');
3588 writer.write(node.name()[0] ? node.name() : default_name);
3589
3590 if (node.type() == node_declaration)
3591 {
3592 node_output_attributes(writer, node, flags);
3593 }
3594 else if (node.value()[0])
3595 {
3596 writer.write(' ');
3597 writer.write(node.value());
3598 }
3599
3600 writer.write('?', '>');
3601 if ((flags & format_raw) == 0)
3602 writer.write('\n');
3603 break;
3604
3605 case node_doctype:
3606 writer.write('<', '!', 'D', 'O', 'C');
3607 writer.write('T', 'Y', 'P', 'E');
3608
3609 if (node.value()[0])
3610 {
3611 writer.write(' ');
3612 writer.write(node.value());
3613 }
3614
3615 writer.write('>');
3616 if ((flags & format_raw) == 0)
3617 writer.write('\n');
3618 break;
3619
3620 default:
3621 assert(!"Invalid node type");
3622 }
3623}
3624
3625inline bool has_declaration(const xml_node &node)
3626{
3627 for (xml_node child = node.first_child(); child; child = child.next_sibling())
3628 {
3629 xml_node_type type = child.type();
3630
3631 if (type == node_declaration)
3632 return true;
3633 if (type == node_element)
3634 return false;
3635 }
3636
3637 return false;
3638}
3639
3640inline bool allow_insert_child(xml_node_type parent, xml_node_type child)
3641{
3642 if (parent != node_document && parent != node_element)
3643 return false;
3644 if (child == node_document || child == node_null)
3645 return false;
3646 if (parent != node_document && (child == node_declaration || child == node_doctype))
3647 return false;
3648
3649 return true;
3650}
3651
3652PUGI__FN void recursive_copy_skip(xml_node &dest, const xml_node &source, const xml_node &skip)
3653{
3654 assert(dest.type() == source.type());
3655
3656 switch (source.type())
3657 {
3658 case node_element:
3659 {
3660 dest.set_name(source.name());
3661
3662 for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
3663 dest.append_attribute(a.name()).set_value(a.value());
3664
3665 for (xml_node c = source.first_child(); c; c = c.next_sibling())
3666 {
3667 if (c == skip)
3668 continue;
3669
3670 xml_node cc = dest.append_child(c.type());
3671 assert(cc);
3672
3673 recursive_copy_skip(cc, c, skip);
3674 }
3675
3676 break;
3677 }
3678
3679 case node_pcdata:
3680 case node_cdata:
3681 case node_comment:
3682 case node_doctype:
3683 dest.set_value(source.value());
3684 break;
3685
3686 case node_pi:
3687 dest.set_name(source.name());
3688 dest.set_value(source.value());
3689 break;
3690
3691 case node_declaration:
3692 {
3693 dest.set_name(source.name());
3694
3695 for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
3696 dest.append_attribute(a.name()).set_value(a.value());
3697
3698 break;
3699 }
3700
3701 default:
3702 assert(!"Invalid node type");
3703 }
3704}
3705
3707{
3708 xml_node_type type = static_cast<xml_node_type>((node->header & impl::xml_memory_page_type_mask) + 1);
3709
3710 return type == node_pcdata || type == node_cdata;
3711}
3712
3713// get value with conversion functions
3714PUGI__FN int get_integer_base(const char_t *value)
3715{
3716 const char_t *s = value;
3717
3718 while (PUGI__IS_CHARTYPE(*s, ct_space))
3719 s++;
3720
3721 if (*s == '-')
3722 s++;
3723
3724 return (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
3725}
3726
3727PUGI__FN int get_value_int(const char_t *value, int def)
3728{
3729 if (!value)
3730 return def;
3731
3732 int base = get_integer_base(value);
3733
3734#ifdef PUGIXML_WCHAR_MODE
3735 return static_cast<int>(wcstol(value, 0, base));
3736#else
3737 return static_cast<int>(strtol(value, 0, base));
3738#endif
3739}
3740
3741PUGI__FN unsigned int get_value_uint(const char_t *value, unsigned int def)
3742{
3743 if (!value)
3744 return def;
3745
3746 int base = get_integer_base(value);
3747
3748#ifdef PUGIXML_WCHAR_MODE
3749 return static_cast<unsigned int>(wcstoul(value, 0, base));
3750#else
3751 return static_cast<unsigned int>(strtoul(value, 0, base));
3752#endif
3753}
3754
3755PUGI__FN double get_value_double(const char_t *value, double def)
3756{
3757 if (!value)
3758 return def;
3759
3760#ifdef PUGIXML_WCHAR_MODE
3761 return wcstod(value, 0);
3762#else
3763 return strtod(value, 0);
3764#endif
3765}
3766
3767PUGI__FN float get_value_float(const char_t *value, float def)
3768{
3769 if (!value)
3770 return def;
3771
3772#ifdef PUGIXML_WCHAR_MODE
3773 return static_cast<float>(wcstod(value, 0));
3774#else
3775 return static_cast<float>(strtod(value, 0));
3776#endif
3777}
3778
3779PUGI__FN bool get_value_bool(const char_t *value, bool def)
3780{
3781 if (!value)
3782 return def;
3783
3784 // only look at first char
3785 char_t first = *value;
3786
3787 // 1*, t* (true), T* (True), y* (yes), Y* (YES)
3788 return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
3789}
3790
3791#ifdef PUGIXML_HAS_LONG_LONG
3792PUGI__FN long long get_value_llong(const char_t *value, long long def)
3793{
3794 if (!value)
3795 return def;
3796
3797 int base = get_integer_base(value);
3798
3799#ifdef PUGIXML_WCHAR_MODE
3800#ifdef PUGI__MSVC_CRT_VERSION
3801 return _wcstoi64(value, 0, base);
3802#else
3803 return wcstoll(value, 0, base);
3804#endif
3805#else
3806#ifdef PUGI__MSVC_CRT_VERSION
3807 return _strtoi64(value, 0, base);
3808#else
3809 return strtoll(value, 0, base);
3810#endif
3811#endif
3812}
3813
3814PUGI__FN unsigned long long get_value_ullong(const char_t *value, unsigned long long def)
3815{
3816 if (!value)
3817 return def;
3818
3819 int base = get_integer_base(value);
3820
3821#ifdef PUGIXML_WCHAR_MODE
3822#ifdef PUGI__MSVC_CRT_VERSION
3823 return _wcstoui64(value, 0, base);
3824#else
3825 return wcstoull(value, 0, base);
3826#endif
3827#else
3828#ifdef PUGI__MSVC_CRT_VERSION
3829 return _strtoui64(value, 0, base);
3830#else
3831 return strtoull(value, 0, base);
3832#endif
3833#endif
3834}
3835#endif
3836
3837// set value with conversion functions
3838PUGI__FN bool set_value_buffer(char_t *&dest, uintptr_t &header, uintptr_t header_mask, char (&buf)[128])
3839{
3840#ifdef PUGIXML_WCHAR_MODE
3841 char_t wbuf[128];
3842 impl::widen_ascii(wbuf, buf);
3843
3844 return strcpy_insitu(dest, header, header_mask, wbuf);
3845#else
3846 return strcpy_insitu(dest, header, header_mask, buf);
3847#endif
3848}
3849
3850PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, int value)
3851{
3852 char buf[128];
3853 sprintf(buf, "%d", value);
3854
3855 return set_value_buffer(dest, header, header_mask, buf);
3856}
3857
3858PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, unsigned int value)
3859{
3860 char buf[128];
3861 sprintf(buf, "%u", value);
3862
3863 return set_value_buffer(dest, header, header_mask, buf);
3864}
3865
3866PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, double value)
3867{
3868 char buf[128];
3869 sprintf(buf, "%g", value);
3870
3871 return set_value_buffer(dest, header, header_mask, buf);
3872}
3873
3874PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, bool value)
3875{
3876 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
3877}
3878
3879#ifdef PUGIXML_HAS_LONG_LONG
3880PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, long long value)
3881{
3882 char buf[128];
3883 sprintf(buf, "%lld", value);
3884
3885 return set_value_buffer(dest, header, header_mask, buf);
3886}
3887
3888PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, unsigned long long value)
3889{
3890 char buf[128];
3891 sprintf(buf, "%llu", value);
3892
3893 return set_value_buffer(dest, header, header_mask, buf);
3894}
3895#endif
3896
3897// 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
3898// trick
3899PUGI__FN xml_parse_status get_file_size(FILE *file, size_t &out_result)
3900{
3901#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
3902 // there are 64-bit versions of fseek/ftell, let's use them
3903 typedef __int64 length_type;
3904
3905 _fseeki64(file, 0, SEEK_END);
3906 length_type length = _ftelli64(file);
3907 _fseeki64(file, 0, SEEK_SET);
3908#elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__)
3909 // there are 64-bit versions of fseek/ftell, let's use them
3910 typedef off64_t length_type;
3911
3912 fseeko64(file, 0, SEEK_END);
3913 length_type length = ftello64(file);
3914 fseeko64(file, 0, SEEK_SET);
3915#else
3916 // 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
3917 // can't do anything anyway.
3918 typedef long length_type;
3919
3920 fseek(file, 0, SEEK_END);
3921 length_type length = ftell(file);
3922 fseek(file, 0, SEEK_SET);
3923#endif
3924
3925 // check for I/O errors
3926 if (length < 0)
3927 return status_io_error;
3928
3929 // check for overflow
3930 size_t result = static_cast<size_t>(length);
3931
3932 if (static_cast<length_type>(result) != length)
3933 return status_out_of_memory;
3934
3935 // finalize
3936 out_result = result;
3937
3938 return status_ok;
3939}
3940
3941PUGI__FN size_t zero_terminate_buffer(void *buffer, size_t size, xml_encoding encoding)
3942{
3943 // We only need to zero-terminate if encoding conversion does not do it for us
3944#ifdef PUGIXML_WCHAR_MODE
3945 xml_encoding wchar_encoding = get_wchar_encoding();
3946
3947 if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding))
3948 {
3949 size_t length = size / sizeof(char_t);
3950
3951 static_cast<char_t *>(buffer)[length] = 0;
3952 return (length + 1) * sizeof(char_t);
3953 }
3954#else
3955 if (encoding == encoding_utf8)
3956 {
3957 static_cast<char *>(buffer)[size] = 0;
3958 return size + 1;
3959 }
3960#endif
3961
3962 return size;
3963}
3964
3965PUGI__FN xml_parse_result load_file_impl(xml_document &doc, FILE *file, unsigned int options, xml_encoding encoding)
3966{
3967 if (!file)
3968 return make_parse_result(status_file_not_found);
3969
3970 // get file size (can result in I/O errors)
3971 size_t size = 0;
3972 xml_parse_status size_status = get_file_size(file, size);
3973
3974 if (size_status != status_ok)
3975 {
3976 fclose(file);
3977 return make_parse_result(size_status);
3978 }
3979
3980 size_t max_suffix_size = sizeof(char_t);
3981
3982 // allocate buffer for the whole file
3983 char *contents = static_cast<char *>(xml_memory::allocate(size + max_suffix_size));
3984
3985 if (!contents)
3986 {
3987 fclose(file);
3988 return make_parse_result(status_out_of_memory);
3989 }
3990
3991 // read file in memory
3992 size_t read_size = fread(contents, 1, size, file);
3993 fclose(file);
3994
3995 if (read_size != size)
3996 {
3997 xml_memory::deallocate(contents);
3998 return make_parse_result(status_io_error);
3999 }
4000
4001 xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
4002
4003 return doc.load_buffer_inplace_own(contents, zero_terminate_buffer(contents, size, real_encoding), options,
4004 real_encoding);
4005}
4006
4007#ifndef PUGIXML_NO_STL
4008template <typename T>
4010{
4012 {
4013 void *memory = xml_memory::allocate(sizeof(xml_stream_chunk));
4014
4015 return new (memory) xml_stream_chunk();
4016 }
4017
4018 static void destroy(void *ptr)
4019 {
4020 xml_stream_chunk *chunk = static_cast<xml_stream_chunk *>(ptr);
4021
4022 // free chunk chain
4023 while (chunk)
4024 {
4025 xml_stream_chunk *next = chunk->next;
4027 chunk = next;
4028 }
4029 }
4030
4032
4034 size_t size;
4035
4037};
4038
4039template <typename T>
4040PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T> &stream, void **out_buffer, size_t *out_size)
4041{
4043
4044 // read file to a chunk list
4045 size_t total = 0;
4046 xml_stream_chunk<T> *last = 0;
4047
4048 while (!stream.eof())
4049 {
4050 // allocate new chunk
4052 if (!chunk)
4053 return status_out_of_memory;
4054
4055 // append chunk to list
4056 if (last)
4057 last = last->next = chunk;
4058 else
4059 chunks.data = last = chunk;
4060
4061 // read data to chunk
4062 stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));
4063 chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);
4064
4065 // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors
4066 if (stream.bad() || (!stream.eof() && stream.fail()))
4067 return status_io_error;
4068
4069 // guard against huge files (chunk size is small enough to make this overflow check work)
4070 if (total + chunk->size < total)
4071 return status_out_of_memory;
4072 total += chunk->size;
4073 }
4074
4075 size_t max_suffix_size = sizeof(char_t);
4076
4077 // copy chunk list to a contiguous buffer
4078 char *buffer = static_cast<char *>(xml_memory::allocate(total + max_suffix_size));
4079 if (!buffer)
4080 return status_out_of_memory;
4081
4082 char *write = buffer;
4083
4084 for (xml_stream_chunk<T> *chunk = static_cast<xml_stream_chunk<T> *>(chunks.data); chunk; chunk = chunk->next)
4085 {
4086 assert(write + chunk->size <= buffer + total);
4087 memcpy(write, chunk->data, chunk->size);
4088 write += chunk->size;
4089 }
4090
4091 assert(write == buffer + total);
4092
4093 // return buffer
4094 *out_buffer = buffer;
4095 *out_size = total;
4096
4097 return status_ok;
4098}
4099
4100template <typename T>
4101PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T> &stream, void **out_buffer, size_t *out_size)
4102{
4103 // get length of remaining data in stream
4104 typename std::basic_istream<T>::pos_type pos = stream.tellg();
4105 stream.seekg(0, std::ios::end);
4106 std::streamoff length = stream.tellg() - pos;
4107 stream.seekg(pos);
4108
4109 if (stream.fail() || pos < 0)
4110 return status_io_error;
4111
4112 // guard against huge files
4113 size_t read_length = static_cast<size_t>(length);
4114
4115 if (static_cast<std::streamsize>(read_length) != length || length < 0)
4116 return status_out_of_memory;
4117
4118 size_t max_suffix_size = sizeof(char_t);
4119
4120 // read stream data into memory (guard against stream exceptions with buffer holder)
4121 buffer_holder buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);
4122 if (!buffer.data)
4123 return status_out_of_memory;
4124
4125 stream.read(static_cast<T *>(buffer.data), static_cast<std::streamsize>(read_length));
4126
4127 // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check
4128 // for other I/O errors
4129 if (stream.bad() || (!stream.eof() && stream.fail()))
4130 return status_io_error;
4131
4132 // return buffer
4133 size_t actual_length = static_cast<size_t>(stream.gcount());
4134 assert(actual_length <= read_length);
4135
4136 *out_buffer = buffer.release();
4137 *out_size = actual_length * sizeof(T);
4138
4139 return status_ok;
4140}
4141
4142template <typename T>
4143PUGI__FN xml_parse_result load_stream_impl(xml_document &doc, std::basic_istream<T> &stream, unsigned int options,
4144 xml_encoding encoding)
4145{
4146 void *buffer = 0;
4147 size_t size = 0;
4148 xml_parse_status status = status_ok;
4149
4150 // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits)
4151 if (stream.fail())
4152 return make_parse_result(status_io_error);
4153
4154 // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)
4155 if (stream.tellg() < 0)
4156 {
4157 stream.clear(); // clear error flags that could be set by a failing tellg
4158 status = load_stream_data_noseek(stream, &buffer, &size);
4159 }
4160 else
4161 status = load_stream_data_seek(stream, &buffer, &size);
4162
4163 if (status != status_ok)
4164 return make_parse_result(status);
4165
4166 xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
4167
4168 return doc.load_buffer_inplace_own(buffer, zero_terminate_buffer(buffer, size, real_encoding), options,
4169 real_encoding);
4170}
4171#endif
4172
4173#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__))
4174PUGI__FN FILE *open_file_wide(const wchar_t *path, const wchar_t *mode)
4175{
4176 return _wfopen(path, mode);
4177}
4178#else
4179PUGI__FN char *convert_path_heap(const wchar_t *str)
4180{
4181 assert(str);
4182
4183 // first pass: get length in utf8 characters
4184 size_t length = strlength_wide(str);
4185 size_t size = as_utf8_begin(str, length);
4186
4187 // allocate resulting string
4188 char *result = static_cast<char *>(xml_memory::allocate(size + 1));
4189 if (!result)
4190 return 0;
4191
4192 // second pass: convert to utf8
4193 as_utf8_end(result, size, str, length);
4194
4195 return result;
4196}
4197
4198PUGI__FN FILE *open_file_wide(const wchar_t *path, const wchar_t *mode)
4199{
4200 // there is no standard function to open wide paths, so our best bet is to try utf8 path
4201 char *path_utf8 = convert_path_heap(path);
4202 if (!path_utf8)
4203 return 0;
4204
4205 // convert mode to ASCII (we mirror _wfopen interface)
4206 char mode_ascii[4] = { 0 };
4207 for (size_t i = 0; mode[i]; ++i)
4208 mode_ascii[i] = static_cast<char>(mode[i]);
4209
4210 // try to open the utf8 path
4211 FILE *result = fopen(path_utf8, mode_ascii);
4212
4213 // free dummy buffer
4214 xml_memory::deallocate(path_utf8);
4215
4216 return result;
4217}
4218#endif
4219
4220PUGI__FN bool save_file_impl(const xml_document &doc, FILE *file, const char_t *indent, unsigned int flags,
4221 xml_encoding encoding)
4222{
4223 if (!file)
4224 return false;
4225
4226 xml_writer_file writer(file);
4227 doc.save(writer, indent, flags, encoding);
4228
4229 int result = ferror(file);
4230
4231 fclose(file);
4232
4233 return result == 0;
4234}
4235
4236PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct *doc, xml_node_struct *root, void *contents, size_t size,
4237 unsigned int options, xml_encoding encoding, bool is_mutable, bool own,
4238 char_t **out_buffer)
4239{
4240 // check input buffer
4241 assert(contents || size == 0);
4242
4243 // get actual encoding
4244 xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
4245
4246 // get private buffer
4247 char_t *buffer = 0;
4248 size_t length = 0;
4249
4250 if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable))
4251 return impl::make_parse_result(status_out_of_memory);
4252
4253 // delete original buffer if we performed a conversion
4254 if (own && buffer != contents && contents)
4255 impl::xml_memory::deallocate(contents);
4256
4257 // store buffer for offset_debug
4258 doc->buffer = buffer;
4259
4260 // parse
4261 xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
4262
4263 // remember encoding
4264 res.encoding = buffer_encoding;
4265
4266 // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
4267 if (own || buffer != contents)
4268 *out_buffer = buffer;
4269
4270 return res;
4271}
4273
4274namespace pugi
4275{
4276PUGI__FN xml_writer_file::xml_writer_file(void *file_) : file(file_) {}
4277
4278PUGI__FN void xml_writer_file::write(const void *data, size_t size)
4279{
4280 size_t result = fwrite(data, 1, size, static_cast<FILE *>(file));
4281 (void)!result; // unfortunately we can't do proper error handling here
4282}
4283
4284#ifndef PUGIXML_NO_STL
4285PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char>> &stream)
4286 : narrow_stream(&stream), wide_stream(0)
4287{
4288}
4289
4290PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t>> &stream)
4291 : narrow_stream(0), wide_stream(&stream)
4292{
4293}
4294
4295PUGI__FN void xml_writer_stream::write(const void *data, size_t size)
4296{
4297 if (narrow_stream)
4298 {
4299 assert(!wide_stream);
4300 narrow_stream->write(reinterpret_cast<const char *>(data), static_cast<std::streamsize>(size));
4301 }
4302 else
4303 {
4304 assert(wide_stream);
4305 assert(size % sizeof(wchar_t) == 0);
4306
4307 wide_stream->write(reinterpret_cast<const wchar_t *>(data),
4308 static_cast<std::streamsize>(size / sizeof(wchar_t)));
4309 }
4310}
4311#endif
4312
4314
4316
4318{
4319 return _depth;
4320}
4321
4323{
4324 return true;
4325}
4326
4328{
4329 return true;
4330}
4331
4333
4335
4337
4338PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
4339{
4341}
4342
4344{
4345 return !_attr;
4346}
4347
4349{
4350 return (_attr == r._attr);
4351}
4352
4354{
4355 return (_attr != r._attr);
4356}
4357
4359{
4360 return (_attr < r._attr);
4361}
4362
4364{
4365 return (_attr > r._attr);
4366}
4367
4369{
4370 return (_attr <= r._attr);
4371}
4372
4374{
4375 return (_attr >= r._attr);
4376}
4377
4382
4387
4389{
4390 return (_attr && _attr->value) ? _attr->value : def;
4391}
4392
4394{
4395 return impl::get_value_int(_attr ? _attr->value : 0, def);
4396}
4397
4398PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
4399{
4400 return impl::get_value_uint(_attr ? _attr->value : 0, def);
4401}
4402
4403PUGI__FN double xml_attribute::as_double(double def) const
4404{
4405 return impl::get_value_double(_attr ? _attr->value : 0, def);
4406}
4407
4408PUGI__FN float xml_attribute::as_float(float def) const
4409{
4410 return impl::get_value_float(_attr ? _attr->value : 0, def);
4411}
4412
4414{
4415 return impl::get_value_bool(_attr ? _attr->value : 0, def);
4416}
4417
4418#ifdef PUGIXML_HAS_LONG_LONG
4419PUGI__FN long long xml_attribute::as_llong(long long def) const
4420{
4421 return impl::get_value_llong(_attr ? _attr->value : 0, def);
4422}
4423
4424PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
4425{
4426 return impl::get_value_ullong(_attr ? _attr->value : 0, def);
4427}
4428#endif
4429
4431{
4432 return !_attr;
4433}
4434
4436{
4437 return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT("");
4438}
4439
4441{
4442 return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");
4443}
4444
4446{
4447 return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
4448}
4449
4454
4456{
4457 set_value(rhs);
4458 return *this;
4459}
4460
4462{
4463 set_value(rhs);
4464 return *this;
4465}
4466
4468{
4469 set_value(rhs);
4470 return *this;
4471}
4472
4474{
4475 set_value(rhs);
4476 return *this;
4477}
4478
4480{
4481 set_value(rhs);
4482 return *this;
4483}
4484
4485#ifdef PUGIXML_HAS_LONG_LONG
4487{
4488 set_value(rhs);
4489 return *this;
4490}
4491
4492PUGI__FN xml_attribute &xml_attribute::operator=(unsigned long long rhs)
4493{
4494 set_value(rhs);
4495 return *this;
4496}
4497#endif
4498
4500{
4501 if (!_attr)
4502 return false;
4503
4504 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs);
4505}
4506
4508{
4509 if (!_attr)
4510 return false;
4511
4512 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
4513}
4514
4516{
4517 if (!_attr)
4518 return false;
4519
4520 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
4521}
4522
4524{
4525 if (!_attr)
4526 return false;
4527
4528 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
4529}
4530
4532{
4533 if (!_attr)
4534 return false;
4535
4536 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
4537}
4538
4540{
4541 if (!_attr)
4542 return false;
4543
4544 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
4545}
4546
4547#ifdef PUGIXML_HAS_LONG_LONG
4548PUGI__FN bool xml_attribute::set_value(long long rhs)
4549{
4550 if (!_attr)
4551 return false;
4552
4553 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
4554}
4555
4556PUGI__FN bool xml_attribute::set_value(unsigned long long rhs)
4557{
4558 if (!_attr)
4559 return false;
4560
4561 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
4562}
4563#endif
4564
4565#ifdef __BORLANDC__
4566PUGI__FN bool operator&&(const xml_attribute &lhs, bool rhs)
4567{
4568 return (bool)lhs && rhs;
4569}
4570
4571PUGI__FN bool operator||(const xml_attribute &lhs, bool rhs)
4572{
4573 return (bool)lhs || rhs;
4574}
4575#endif
4576
4578
4580
4582
4584{
4585 return _root ? unspecified_bool_xml_node : 0;
4586}
4587
4589{
4590 return !_root;
4591}
4592
4597
4599{
4600 return iterator(0, _root);
4601}
4602
4607
4612
4617
4623
4628
4630{
4631 return (_root == r._root);
4632}
4633
4635{
4636 return (_root != r._root);
4637}
4638
4640{
4641 return (_root < r._root);
4642}
4643
4645{
4646 return (_root > r._root);
4647}
4648
4650{
4651 return (_root <= r._root);
4652}
4653
4655{
4656 return (_root >= r._root);
4657}
4658
4660{
4661 return !_root;
4662}
4663
4665{
4666 return (_root && _root->name) ? _root->name : PUGIXML_TEXT("");
4667}
4668
4670{
4671 return _root ? static_cast<xml_node_type>((_root->header & impl::xml_memory_page_type_mask) + 1) : node_null;
4672}
4673
4675{
4676 return (_root && _root->value) ? _root->value : PUGIXML_TEXT("");
4677}
4678
4680{
4681 if (!_root)
4682 return xml_node();
4683
4684 for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
4685 if (i->name && impl::strequal(name_, i->name))
4686 return xml_node(i);
4687
4688 return xml_node();
4689}
4690
4692{
4693 if (!_root)
4694 return xml_attribute();
4695
4696 for (xml_attribute_struct *i = _root->first_attribute; i; i = i->next_attribute)
4697 if (i->name && impl::strequal(name_, i->name))
4698 return xml_attribute(i);
4699
4700 return xml_attribute();
4701}
4702
4704{
4705 if (!_root)
4706 return xml_node();
4707
4708 for (xml_node_struct *i = _root->next_sibling; i; i = i->next_sibling)
4709 if (i->name && impl::strequal(name_, i->name))
4710 return xml_node(i);
4711
4712 return xml_node();
4713}
4714
4716{
4717 if (!_root)
4718 return xml_node();
4719
4720 if (_root->next_sibling)
4721 return xml_node(_root->next_sibling);
4722 else
4723 return xml_node();
4724}
4725
4727{
4728 if (!_root)
4729 return xml_node();
4730
4731 for (xml_node_struct *i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
4732 if (i->name && impl::strequal(name_, i->name))
4733 return xml_node(i);
4734
4735 return xml_node();
4736}
4737
4739{
4740 if (!_root)
4741 return xml_node();
4742
4744 return xml_node(_root->prev_sibling_c);
4745 else
4746 return xml_node();
4747}
4748
4750{
4751 return _root ? xml_node(_root->parent) : xml_node();
4752}
4753
4755{
4756 if (!_root)
4757 return xml_node();
4758
4759 impl::xml_memory_page *page =
4760 reinterpret_cast<impl::xml_memory_page *>(_root->header & impl::xml_memory_page_pointer_mask);
4761
4762 return xml_node(static_cast<impl::xml_document_struct *>(page->allocator));
4763}
4764
4766{
4767 return xml_text(_root);
4768}
4769
4771{
4772 if (!_root)
4773 return PUGIXML_TEXT("");
4774
4775 for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
4776 if (i->value && impl::is_text_node(i))
4777 return i->value;
4778
4779 return PUGIXML_TEXT("");
4780}
4781
4783{
4784 return child(name_).child_value();
4785}
4786
4791
4796
4801
4806
4808{
4809 switch (type())
4810 {
4811 case node_pi:
4812 case node_declaration:
4813 case node_element:
4814 return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs);
4815
4816 default:
4817 return false;
4818 }
4819}
4820
4822{
4823 switch (type())
4824 {
4825 case node_pi:
4826 case node_cdata:
4827 case node_pcdata:
4828 case node_comment:
4829 case node_doctype:
4830 return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs);
4831
4832 default:
4833 return false;
4834 }
4835}
4836
4838{
4839 if (type() != node_element && type() != node_declaration)
4840 return xml_attribute();
4841
4842 xml_attribute a(impl::append_attribute_ll(_root, impl::get_allocator(_root)));
4843 a.set_name(name_);
4844
4845 return a;
4846}
4847
4849{
4850 if (type() != node_element && type() != node_declaration)
4851 return xml_attribute();
4852
4853 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4854 if (!a)
4855 return xml_attribute();
4856
4857 a.set_name(name_);
4858
4860
4861 if (head)
4862 {
4864 head->prev_attribute_c = a._attr;
4865 }
4866 else
4868
4869 a._attr->next_attribute = head;
4871
4872 return a;
4873}
4874
4876{
4877 if ((type() != node_element && type() != node_declaration) || attr.empty())
4878 return xml_attribute();
4879
4880 // check that attribute belongs to *this
4881 xml_attribute_struct *cur = attr._attr;
4882
4883 while (cur->prev_attribute_c->next_attribute)
4884 cur = cur->prev_attribute_c;
4885
4886 if (cur != _root->first_attribute)
4887 return xml_attribute();
4888
4889 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4890 if (!a)
4891 return xml_attribute();
4892
4893 a.set_name(name_);
4894
4897 else
4899
4901 a._attr->next_attribute = attr._attr;
4902 attr._attr->prev_attribute_c = a._attr;
4903
4904 return a;
4905}
4906
4908{
4909 if ((type() != node_element && type() != node_declaration) || attr.empty())
4910 return xml_attribute();
4911
4912 // check that attribute belongs to *this
4913 xml_attribute_struct *cur = attr._attr;
4914
4915 while (cur->prev_attribute_c->next_attribute)
4916 cur = cur->prev_attribute_c;
4917
4918 if (cur != _root->first_attribute)
4919 return xml_attribute();
4920
4921 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4922 if (!a)
4923 return xml_attribute();
4924
4925 a.set_name(name_);
4926
4927 if (attr._attr->next_attribute)
4929 else
4931
4933 a._attr->prev_attribute_c = attr._attr;
4934 attr._attr->next_attribute = a._attr;
4935
4936 return a;
4937}
4938
4940{
4941 if (!proto)
4942 return xml_attribute();
4943
4944 xml_attribute result = append_attribute(proto.name());
4945 result.set_value(proto.value());
4946
4947 return result;
4948}
4949
4951{
4952 if (!proto)
4953 return xml_attribute();
4954
4955 xml_attribute result = prepend_attribute(proto.name());
4956 result.set_value(proto.value());
4957
4958 return result;
4959}
4960
4962{
4963 if (!proto)
4964 return xml_attribute();
4965
4966 xml_attribute result = insert_attribute_after(proto.name(), attr);
4967 result.set_value(proto.value());
4968
4969 return result;
4970}
4971
4973{
4974 if (!proto)
4975 return xml_attribute();
4976
4977 xml_attribute result = insert_attribute_before(proto.name(), attr);
4978 result.set_value(proto.value());
4979
4980 return result;
4981}
4982
4984{
4985 if (!impl::allow_insert_child(this->type(), type_))
4986 return xml_node();
4987
4988 xml_node n(impl::append_node(_root, impl::get_allocator(_root), type_));
4989
4990 if (type_ == node_declaration)
4991 n.set_name(PUGIXML_TEXT("xml"));
4992
4993 return n;
4994}
4995
4997{
4998 if (!impl::allow_insert_child(this->type(), type_))
4999 return xml_node();
5000
5001 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
5002 if (!n)
5003 return xml_node();
5004
5005 n._root->parent = _root;
5006
5008
5009 if (head)
5010 {
5012 head->prev_sibling_c = n._root;
5013 }
5014 else
5015 n._root->prev_sibling_c = n._root;
5016
5017 n._root->next_sibling = head;
5018 _root->first_child = n._root;
5019
5020 if (type_ == node_declaration)
5021 n.set_name(PUGIXML_TEXT("xml"));
5022
5023 return n;
5024}
5025
5027{
5028 if (!impl::allow_insert_child(this->type(), type_))
5029 return xml_node();
5030 if (!node._root || node._root->parent != _root)
5031 return xml_node();
5032
5033 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
5034 if (!n)
5035 return xml_node();
5036
5037 n._root->parent = _root;
5038
5041 else
5042 _root->first_child = n._root;
5043
5045 n._root->next_sibling = node._root;
5046 node._root->prev_sibling_c = n._root;
5047
5048 if (type_ == node_declaration)
5049 n.set_name(PUGIXML_TEXT("xml"));
5050
5051 return n;
5052}
5053
5055{
5056 if (!impl::allow_insert_child(this->type(), type_))
5057 return xml_node();
5058 if (!node._root || node._root->parent != _root)
5059 return xml_node();
5060
5061 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
5062 if (!n)
5063 return xml_node();
5064
5065 n._root->parent = _root;
5066
5067 if (node._root->next_sibling)
5069 else
5071
5073 n._root->prev_sibling_c = node._root;
5074 node._root->next_sibling = n._root;
5075
5076 if (type_ == node_declaration)
5077 n.set_name(PUGIXML_TEXT("xml"));
5078
5079 return n;
5080}
5081
5083{
5085
5086 result.set_name(name_);
5087
5088 return result;
5089}
5090
5092{
5094
5095 result.set_name(name_);
5096
5097 return result;
5098}
5099
5101{
5103
5104 result.set_name(name_);
5105
5106 return result;
5107}
5108
5110{
5112
5113 result.set_name(name_);
5114
5115 return result;
5116}
5117
5119{
5120 xml_node result = append_child(proto.type());
5121
5122 if (result)
5123 impl::recursive_copy_skip(result, proto, result);
5124
5125 return result;
5126}
5127
5129{
5130 xml_node result = prepend_child(proto.type());
5131
5132 if (result)
5133 impl::recursive_copy_skip(result, proto, result);
5134
5135 return result;
5136}
5137
5139{
5140 xml_node result = insert_child_after(proto.type(), node);
5141
5142 if (result)
5143 impl::recursive_copy_skip(result, proto, result);
5144
5145 return result;
5146}
5147
5149{
5150 xml_node result = insert_child_before(proto.type(), node);
5151
5152 if (result)
5153 impl::recursive_copy_skip(result, proto, result);
5154
5155 return result;
5156}
5157
5159{
5160 return remove_attribute(attribute(name_));
5161}
5162
5164{
5165 if (!_root || !a._attr)
5166 return false;
5167
5168 // check that attribute belongs to *this
5169 xml_attribute_struct *attr = a._attr;
5170
5171 while (attr->prev_attribute_c->next_attribute)
5172 attr = attr->prev_attribute_c;
5173
5174 if (attr != _root->first_attribute)
5175 return false;
5176
5177 if (a._attr->next_attribute)
5179 else if (_root->first_attribute)
5181
5184 else
5186
5187 impl::destroy_attribute(a._attr, impl::get_allocator(_root));
5188
5189 return true;
5190}
5191
5193{
5194 return remove_child(child(name_));
5195}
5196
5198{
5199 if (!_root || !n._root || n._root->parent != _root)
5200 return false;
5201
5202 if (n._root->next_sibling)
5204 else if (_root->first_child)
5206
5209 else
5211
5212 impl::destroy_node(n._root, impl::get_allocator(_root));
5213
5214 return true;
5215}
5216
5217PUGI__FN xml_parse_result xml_node::append_buffer(const void *contents, size_t size, unsigned int options,
5218 xml_encoding encoding)
5219{
5220 // append_buffer is only valid for elements/documents
5221 if (!impl::allow_insert_child(type(), node_element))
5222 return impl::make_parse_result(status_append_invalid_root);
5223
5224 // get document node
5225 impl::xml_document_struct *doc = static_cast<impl::xml_document_struct *>(root()._root);
5226 assert(doc);
5227
5228 // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later)
5229 impl::xml_memory_page *page = 0;
5230 impl::xml_extra_buffer *extra =
5231 static_cast<impl::xml_extra_buffer *>(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page));
5232 (void)page;
5233
5234 if (!extra)
5235 return impl::make_parse_result(status_out_of_memory);
5236
5237 // save name; name of the root has to be NULL before parsing - otherwise closing node mismatches will not be
5238 // detected at the top level
5239 char_t *rootname = _root->name;
5240 _root->name = 0;
5241
5242 // parse
5243 char_t *buffer = 0;
5244 xml_parse_result res = impl::load_buffer_impl(doc, _root, const_cast<void *>(contents), size, options, encoding,
5245 false, false, &buffer);
5246
5247 // restore name
5248 _root->name = rootname;
5249
5250 // add extra buffer to the list
5251 extra->buffer = buffer;
5252 extra->next = doc->extra_buffers;
5253 doc->extra_buffers = extra;
5254
5255 return res;
5256}
5257
5259 const char_t *attr_value) const
5260{
5261 if (!_root)
5262 return xml_node();
5263
5264 for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
5265 if (i->name && impl::strequal(name_, i->name))
5266 {
5267 for (xml_attribute_struct *a = i->first_attribute; a; a = a->next_attribute)
5268 if (a->name && impl::strequal(attr_name, a->name) &&
5269 impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT("")))
5270 return xml_node(i);
5271 }
5272
5273 return xml_node();
5274}
5275
5276PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t *attr_name, const char_t *attr_value) const
5277{
5278 if (!_root)
5279 return xml_node();
5280
5281 for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
5282 for (xml_attribute_struct *a = i->first_attribute; a; a = a->next_attribute)
5283 if (a->name && impl::strequal(attr_name, a->name) &&
5284 impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT("")))
5285 return xml_node(i);
5286
5287 return xml_node();
5288}
5289
5290#ifndef PUGIXML_NO_STL
5292{
5293 xml_node cursor = *this; // Make a copy.
5294
5295 string_t result = cursor.name();
5296
5297 while (cursor.parent())
5298 {
5299 cursor = cursor.parent();
5300
5301 string_t temp = cursor.name();
5302 temp += delimiter;
5303 temp += result;
5304 result.swap(temp);
5305 }
5306
5307 return result;
5308}
5309#endif
5310
5312{
5313 xml_node found = *this; // Current search context.
5314
5315 if (!_root || !path_ || !path_[0])
5316 return found;
5317
5318 if (path_[0] == delimiter)
5319 {
5320 // Absolute path; e.g. '/foo/bar'
5321 found = found.root();
5322 ++path_;
5323 }
5324
5325 const char_t *path_segment = path_;
5326
5327 while (*path_segment == delimiter)
5328 ++path_segment;
5329
5330 const char_t *path_segment_end = path_segment;
5331
5332 while (*path_segment_end && *path_segment_end != delimiter)
5333 ++path_segment_end;
5334
5335 if (path_segment == path_segment_end)
5336 return found;
5337
5338 const char_t *next_segment = path_segment_end;
5339
5340 while (*next_segment == delimiter)
5341 ++next_segment;
5342
5343 if (*path_segment == '.' && path_segment + 1 == path_segment_end)
5344 return found.first_element_by_path(next_segment, delimiter);
5345 else if (*path_segment == '.' && *(path_segment + 1) == '.' && path_segment + 2 == path_segment_end)
5346 return found.parent().first_element_by_path(next_segment, delimiter);
5347 else
5348 {
5349 for (xml_node_struct *j = found._root->first_child; j; j = j->next_sibling)
5350 {
5351 if (j->name &&
5352 impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
5353 {
5354 xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
5355
5356 if (subsearch)
5357 return subsearch;
5358 }
5359 }
5360
5361 return xml_node();
5362 }
5363}
5364
5366{
5367 walker._depth = -1;
5368
5369 xml_node arg_begin = *this;
5370 if (!walker.begin(arg_begin))
5371 return false;
5372
5373 xml_node cur = first_child();
5374
5375 if (cur)
5376 {
5377 ++walker._depth;
5378
5379 do
5380 {
5381 xml_node arg_for_each = cur;
5382 if (!walker.for_each(arg_for_each))
5383 return false;
5384
5385 if (cur.first_child())
5386 {
5387 ++walker._depth;
5388 cur = cur.first_child();
5389 }
5390 else if (cur.next_sibling())
5391 cur = cur.next_sibling();
5392 else
5393 {
5394 // Borland C++ workaround
5395 while (!cur.next_sibling() && cur != *this && !cur.parent().empty())
5396 {
5397 --walker._depth;
5398 cur = cur.parent();
5399 }
5400
5401 if (cur != *this)
5402 cur = cur.next_sibling();
5403 }
5404 } while (cur && cur != *this);
5405 }
5406
5407 assert(walker._depth == -1);
5408
5409 xml_node arg_end = *this;
5410 return walker.end(arg_end);
5411}
5412
5414{
5415 return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
5416}
5417
5422
5423PUGI__FN void xml_node::print(xml_writer &writer, const char_t *indent, unsigned int flags, xml_encoding encoding,
5424 unsigned int depth) const
5425{
5426 if (!_root)
5427 return;
5428
5429 impl::xml_buffered_writer buffered_writer(writer, encoding);
5430
5431 impl::node_output(buffered_writer, *this, indent, flags, depth);
5432}
5433
5434#ifndef PUGIXML_NO_STL
5435PUGI__FN void xml_node::print(std::basic_ostream<char, std::char_traits<char>> &stream, const char_t *indent,
5436 unsigned int flags, xml_encoding encoding, unsigned int depth) const
5437{
5438 xml_writer_stream writer(stream);
5439
5440 print(writer, indent, flags, encoding, depth);
5441}
5442
5443PUGI__FN void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t>> &stream, const char_t *indent,
5444 unsigned int flags, unsigned int depth) const
5445{
5446 xml_writer_stream writer(stream);
5447
5448 print(writer, indent, flags, encoding_wchar, depth);
5449}
5450#endif
5451
5453{
5454 xml_node_struct *r = root()._root;
5455
5456 if (!r)
5457 return -1;
5458
5459 const char_t *buffer = static_cast<impl::xml_document_struct *>(r)->buffer;
5460
5461 if (!buffer)
5462 return -1;
5463
5464 switch (type())
5465 {
5466 case node_document:
5467 return 0;
5468
5469 case node_element:
5470 case node_declaration:
5471 case node_pi:
5472 return (_root->header & impl::xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer;
5473
5474 case node_pcdata:
5475 case node_cdata:
5476 case node_comment:
5477 case node_doctype:
5478 return (_root->header & impl::xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer;
5479
5480 default:
5481 return -1;
5482 }
5483}
5484
5485#ifdef __BORLANDC__
5486PUGI__FN bool operator&&(const xml_node &lhs, bool rhs)
5487{
5488 return (bool)lhs && rhs;
5489}
5490
5491PUGI__FN bool operator||(const xml_node &lhs, bool rhs)
5492{
5493 return (bool)lhs || rhs;
5494}
5495#endif
5496
5498
5500{
5501 if (!_root || impl::is_text_node(_root))
5502 return _root;
5503
5504 for (xml_node_struct *node = _root->first_child; node; node = node->next_sibling)
5505 if (impl::is_text_node(node))
5506 return node;
5507
5508 return 0;
5509}
5510
5512{
5513 xml_node_struct *d = _data();
5514 if (d)
5515 return d;
5516
5517 return xml_node(_root).append_child(node_pcdata).internal_object();
5518}
5519
5521
5523
5525{
5526 return _data() ? unspecified_bool_xml_text : 0;
5527}
5528
5530{
5531 return !_data();
5532}
5533
5535{
5536 return _data() == 0;
5537}
5538
5540{
5541 xml_node_struct *d = _data();
5542
5543 return (d && d->value) ? d->value : PUGIXML_TEXT("");
5544}
5545
5547{
5548 xml_node_struct *d = _data();
5549
5550 return (d && d->value) ? d->value : def;
5551}
5552
5553PUGI__FN int xml_text::as_int(int def) const
5554{
5555 xml_node_struct *d = _data();
5556
5557 return impl::get_value_int(d ? d->value : 0, def);
5558}
5559
5560PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
5561{
5562 xml_node_struct *d = _data();
5563
5564 return impl::get_value_uint(d ? d->value : 0, def);
5565}
5566
5567PUGI__FN double xml_text::as_double(double def) const
5568{
5569 xml_node_struct *d = _data();
5570
5571 return impl::get_value_double(d ? d->value : 0, def);
5572}
5573
5574PUGI__FN float xml_text::as_float(float def) const
5575{
5576 xml_node_struct *d = _data();
5577
5578 return impl::get_value_float(d ? d->value : 0, def);
5579}
5580
5581PUGI__FN bool xml_text::as_bool(bool def) const
5582{
5583 xml_node_struct *d = _data();
5584
5585 return impl::get_value_bool(d ? d->value : 0, def);
5586}
5587
5588#ifdef PUGIXML_HAS_LONG_LONG
5589PUGI__FN long long xml_text::as_llong(long long def) const
5590{
5591 xml_node_struct *d = _data();
5592
5593 return impl::get_value_llong(d ? d->value : 0, def);
5594}
5595
5596PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const
5597{
5598 xml_node_struct *d = _data();
5599
5600 return impl::get_value_ullong(d ? d->value : 0, def);
5601}
5602#endif
5603
5605{
5606 xml_node_struct *dn = _data_new();
5607
5608 return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5609}
5610
5612{
5613 xml_node_struct *dn = _data_new();
5614
5615 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5616}
5617
5618PUGI__FN bool xml_text::set(unsigned int rhs)
5619{
5620 xml_node_struct *dn = _data_new();
5621
5622 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5623}
5624
5625PUGI__FN bool xml_text::set(double rhs)
5626{
5627 xml_node_struct *dn = _data_new();
5628
5629 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5630}
5631
5633{
5634 xml_node_struct *dn = _data_new();
5635
5636 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5637}
5638
5639#ifdef PUGIXML_HAS_LONG_LONG
5640PUGI__FN bool xml_text::set(long long rhs)
5641{
5642 xml_node_struct *dn = _data_new();
5643
5644 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5645}
5646
5647PUGI__FN bool xml_text::set(unsigned long long rhs)
5648{
5649 xml_node_struct *dn = _data_new();
5650
5651 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
5652}
5653#endif
5654
5656{
5657 set(rhs);
5658 return *this;
5659}
5660
5662{
5663 set(rhs);
5664 return *this;
5665}
5666
5668{
5669 set(rhs);
5670 return *this;
5671}
5672
5674{
5675 set(rhs);
5676 return *this;
5677}
5678
5680{
5681 set(rhs);
5682 return *this;
5683}
5684
5685#ifdef PUGIXML_HAS_LONG_LONG
5687{
5688 set(rhs);
5689 return *this;
5690}
5691
5692PUGI__FN xml_text &xml_text::operator=(unsigned long long rhs)
5693{
5694 set(rhs);
5695 return *this;
5696}
5697#endif
5698
5700{
5701 return xml_node(_data());
5702}
5703
5704#ifdef __BORLANDC__
5705PUGI__FN bool operator&&(const xml_text &lhs, bool rhs)
5706{
5707 return (bool)lhs && rhs;
5708}
5709
5710PUGI__FN bool operator||(const xml_text &lhs, bool rhs)
5711{
5712 return (bool)lhs || rhs;
5713}
5714#endif
5715
5717
5718PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node &node) : _wrap(node), _parent(node.parent()) {}
5719
5721 : _wrap(ref), _parent(parent)
5722{
5723}
5724
5726{
5727 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
5728}
5729
5731{
5732 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
5733}
5734
5736{
5737 assert(_wrap._root);
5738 return _wrap;
5739}
5740
5742{
5743 assert(_wrap._root);
5744 return const_cast<xml_node *>(&_wrap); // BCC32 workaround
5745}
5746
5748{
5749 assert(_wrap._root);
5751 return *this;
5752}
5753
5755{
5756 xml_node_iterator temp = *this;
5757 ++*this;
5758 return temp;
5759}
5760
5766
5768{
5769 xml_node_iterator temp = *this;
5770 --*this;
5771 return temp;
5772}
5773
5775
5777 : _wrap(attr), _parent(parent)
5778{
5779}
5780
5782 : _wrap(ref), _parent(parent)
5783{
5784}
5785
5787{
5788 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
5789}
5790
5792{
5793 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
5794}
5795
5797{
5798 assert(_wrap._attr);
5799 return _wrap;
5800}
5801
5803{
5804 assert(_wrap._attr);
5805 return const_cast<xml_attribute *>(&_wrap); // BCC32 workaround
5806}
5807
5814
5816{
5817 xml_attribute_iterator temp = *this;
5818 ++*this;
5819 return temp;
5820}
5821
5827
5829{
5830 xml_attribute_iterator temp = *this;
5831 --*this;
5832 return temp;
5833}
5834
5836
5838 : _wrap(node), _parent(node.parent()), _name(name)
5839{
5840}
5841
5843 const char_t *name)
5844 : _wrap(ref), _parent(parent), _name(name)
5845{
5846}
5847
5852
5857
5859{
5860 assert(_wrap._root);
5861 return _wrap;
5862}
5863
5865{
5866 assert(_wrap._root);
5867 return const_cast<xml_node *>(&_wrap); // BCC32 workaround
5868}
5869
5871{
5872 assert(_wrap._root);
5874 return *this;
5875}
5876
5878{
5879 xml_named_node_iterator temp = *this;
5880 ++*this;
5881 return temp;
5882}
5883
5885{
5886 if (_wrap._root)
5888 else
5889 {
5891
5892 if (!impl::strequal(_wrap.name(), _name))
5894 }
5895
5896 return *this;
5897}
5898
5900{
5901 xml_named_node_iterator temp = *this;
5902 --*this;
5903 return temp;
5904}
5905
5907
5908PUGI__FN xml_parse_result::operator bool() const
5909{
5910 return status == status_ok;
5911}
5912
5914{
5915 switch (status)
5916 {
5917 case status_ok:
5918 return "No error";
5919
5921 return "File was not found";
5922 case status_io_error:
5923 return "Error reading from file/stream";
5925 return "Could not allocate memory";
5927 return "Internal error occurred";
5928
5930 return "Could not determine tag type";
5931
5932 case status_bad_pi:
5933 return "Error parsing document declaration/processing instruction";
5934 case status_bad_comment:
5935 return "Error parsing comment";
5936 case status_bad_cdata:
5937 return "Error parsing CDATA section";
5938 case status_bad_doctype:
5939 return "Error parsing document type declaration";
5940 case status_bad_pcdata:
5941 return "Error parsing PCDATA section";
5943 return "Error parsing start element tag";
5945 return "Error parsing element attribute";
5947 return "Error parsing end element tag";
5949 return "Start-end tags mismatch";
5950
5952 return "Unable to append nodes: root is not an element or document";
5953
5955 return "No document element found";
5956
5957 default:
5958 return "Unknown error";
5959 }
5960}
5961
5963{
5964 create();
5965}
5966
5971
5973{
5974 destroy();
5975 create();
5976}
5977
5979{
5980 reset();
5981
5982 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
5983 append_copy(cur);
5984}
5985
5987{
5988 assert(!_root);
5989
5990 // initialize sentinel page
5991 PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) +
5992 impl::xml_memory_page_alignment <=
5993 sizeof(_memory));
5994
5995 // align upwards to page boundary
5996 void *page_memory =
5997 reinterpret_cast<void *>((reinterpret_cast<uintptr_t>(_memory) + (impl::xml_memory_page_alignment - 1)) &
5998 ~(impl::xml_memory_page_alignment - 1));
5999
6000 // prepare page structure
6001 impl::xml_memory_page *page = impl::xml_memory_page::construct(page_memory);
6002 assert(page);
6003
6004 page->busy_size = impl::xml_memory_page_size;
6005
6006 // allocate new root
6007 _root = new (page->data) impl::xml_document_struct(page);
6009
6010 // setup sentinel page
6011 page->allocator = static_cast<impl::xml_document_struct *>(_root);
6012}
6013
6015{
6016 assert(_root);
6017
6018 // destroy static storage
6019 if (_buffer)
6020 {
6021 impl::xml_memory::deallocate(_buffer);
6022 _buffer = 0;
6023 }
6024
6025 // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator)
6026 for (impl::xml_extra_buffer *extra = static_cast<impl::xml_document_struct *>(_root)->extra_buffers; extra;
6027 extra = extra->next)
6028 {
6029 if (extra->buffer)
6030 impl::xml_memory::deallocate(extra->buffer);
6031 }
6032
6033 // destroy dynamic storage, leave sentinel page (it's in static memory)
6034 impl::xml_memory_page *root_page =
6035 reinterpret_cast<impl::xml_memory_page *>(_root->header & impl::xml_memory_page_pointer_mask);
6036 assert(root_page && !root_page->prev && !root_page->memory);
6037
6038 for (impl::xml_memory_page *page = root_page->next; page;)
6039 {
6040 impl::xml_memory_page *next = page->next;
6041
6042 impl::xml_allocator::deallocate_page(page);
6043
6044 page = next;
6045 }
6046
6047 _root = 0;
6048}
6049
6050#ifndef PUGIXML_NO_STL
6051PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char>> &stream,
6052 unsigned int options, xml_encoding encoding)
6053{
6054 reset();
6055
6056 return impl::load_stream_impl(*this, stream, options, encoding);
6057}
6058
6059PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t>> &stream,
6060 unsigned int options)
6061{
6062 reset();
6063
6064 return impl::load_stream_impl(*this, stream, options, encoding_wchar);
6065}
6066#endif
6067
6069{
6070 // Force native encoding (skip autodetection)
6071#ifdef PUGIXML_WCHAR_MODE
6072 xml_encoding encoding = encoding_wchar;
6073#else
6074 xml_encoding encoding = encoding_utf8;
6075#endif
6076
6077 return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
6078}
6079
6081{
6082 reset();
6083
6084 FILE *file = fopen(path_, "rb");
6085
6086 return impl::load_file_impl(*this, file, options, encoding);
6087}
6088
6089PUGI__FN xml_parse_result xml_document::load_file(const wchar_t *path_, unsigned int options, xml_encoding encoding)
6090{
6091 reset();
6092
6093 FILE *file = impl::open_file_wide(path_, L"rb");
6094
6095 return impl::load_file_impl(*this, file, options, encoding);
6096}
6097
6098PUGI__FN xml_parse_result xml_document::load_buffer(const void *contents, size_t size, unsigned int options,
6099 xml_encoding encoding)
6100{
6101 reset();
6102
6103 return impl::load_buffer_impl(static_cast<impl::xml_document_struct *>(_root), _root, const_cast<void *>(contents),
6104 size, options, encoding, false, false, &_buffer);
6105}
6106
6107PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void *contents, size_t size, unsigned int options,
6108 xml_encoding encoding)
6109{
6110 reset();
6111
6112 return impl::load_buffer_impl(static_cast<impl::xml_document_struct *>(_root), _root, contents, size, options,
6113 encoding, true, false, &_buffer);
6114}
6115
6117 xml_encoding encoding)
6118{
6119 reset();
6120
6121 return impl::load_buffer_impl(static_cast<impl::xml_document_struct *>(_root), _root, contents, size, options,
6122 encoding, true, true, &_buffer);
6123}
6124
6125PUGI__FN void xml_document::save(xml_writer &writer, const char_t *indent, unsigned int flags,
6126 xml_encoding encoding) const
6127{
6128 impl::xml_buffered_writer buffered_writer(writer, encoding);
6129
6130 if ((flags & format_write_bom) && encoding != encoding_latin1)
6131 {
6132 // BOM always represents the codepoint U+FEFF, so just write it in native encoding
6133#ifdef PUGIXML_WCHAR_MODE
6134 unsigned int bom = 0xfeff;
6135 buffered_writer.write(static_cast<wchar_t>(bom));
6136#else
6137 buffered_writer.write('\xef', '\xbb', '\xbf');
6138#endif
6139 }
6140
6141 if (!(flags & format_no_declaration) && !impl::has_declaration(*this))
6142 {
6143 buffered_writer.write(PUGIXML_TEXT("<?xml version=\"1.0\""));
6144 if (encoding == encoding_latin1)
6145 buffered_writer.write(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
6146 buffered_writer.write('?', '>');
6147 if (!(flags & format_raw))
6148 buffered_writer.write('\n');
6149 }
6150
6151 impl::node_output(buffered_writer, *this, indent, flags, 0);
6152}
6153
6154#ifndef PUGIXML_NO_STL
6155PUGI__FN void xml_document::save(std::basic_ostream<char, std::char_traits<char>> &stream, const char_t *indent,
6156 unsigned int flags, xml_encoding encoding) const
6157{
6158 xml_writer_stream writer(stream);
6159
6160 save(writer, indent, flags, encoding);
6161}
6162
6163PUGI__FN void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t>> &stream, const char_t *indent,
6164 unsigned int flags) const
6165{
6166 xml_writer_stream writer(stream);
6167
6168 save(writer, indent, flags, encoding_wchar);
6169}
6170#endif
6171
6172PUGI__FN bool xml_document::save_file(const char *path_, const char_t *indent, unsigned int flags,
6173 xml_encoding encoding) const
6174{
6175 FILE *file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb");
6176 return impl::save_file_impl(*this, file, indent, flags, encoding);
6177}
6178
6179PUGI__FN bool xml_document::save_file(const wchar_t *path_, const char_t *indent, unsigned int flags,
6180 xml_encoding encoding) const
6181{
6182 FILE *file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb");
6183 return impl::save_file_impl(*this, file, indent, flags, encoding);
6184}
6185
6187{
6188 assert(_root);
6189
6190 for (xml_node_struct *i = _root->first_child; i; i = i->next_sibling)
6191 if ((i->header & impl::xml_memory_page_type_mask) + 1 == node_element)
6192 return xml_node(i);
6193
6194 return xml_node();
6195}
6196
6197#ifndef PUGIXML_NO_STL
6198PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t *str)
6199{
6200 assert(str);
6201
6202 return impl::as_utf8_impl(str, impl::strlength_wide(str));
6203}
6204
6205PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t> &str)
6206{
6207 return impl::as_utf8_impl(str.c_str(), str.size());
6208}
6209
6210PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char *str)
6211{
6212 assert(str);
6213
6214 return impl::as_wide_impl(str, strlen(str));
6215}
6216
6217PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string &str)
6218{
6219 return impl::as_wide_impl(str.c_str(), str.size());
6220}
6221#endif
6222
6224 deallocation_function deallocate)
6225{
6226 impl::xml_memory::allocate = allocate;
6227 impl::xml_memory::deallocate = deallocate;
6228}
6229
6231{
6232 return impl::xml_memory::allocate;
6233}
6234
6236{
6237 return impl::xml_memory::deallocate;
6238}
6239} // namespace pugi
6240
6241#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
6242namespace std
6243{
6244// Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
6245PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator &)
6246{
6247 return std::bidirectional_iterator_tag();
6248}
6249
6250PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator &)
6251{
6252 return std::bidirectional_iterator_tag();
6253}
6254
6255PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator &)
6256{
6257 return std::bidirectional_iterator_tag();
6258}
6259} // namespace std
6260#endif
6261
6262#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
6263namespace std
6264{
6265// Workarounds for (non-standard) iterator category detection
6266PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator &)
6267{
6268 return std::bidirectional_iterator_tag();
6269}
6270
6271PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator &)
6272{
6273 return std::bidirectional_iterator_tag();
6274}
6275
6276PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator &)
6277{
6278 return std::bidirectional_iterator_tag();
6279}
6280} // namespace std
6281#endif
6282
6283#ifndef PUGIXML_NO_XPATH
6284
6285// STL replacements
6288{
6289 template <typename T>
6290 bool operator()(const T &lhs, const T &rhs) const
6291 {
6292 return lhs == rhs;
6293 }
6294};
6295
6297{
6298 template <typename T>
6299 bool operator()(const T &lhs, const T &rhs) const
6300 {
6301 return lhs != rhs;
6302 }
6303};
6304
6305struct less
6306{
6307 template <typename T>
6308 bool operator()(const T &lhs, const T &rhs) const
6309 {
6310 return lhs < rhs;
6311 }
6312};
6313
6315{
6316 template <typename T>
6317 bool operator()(const T &lhs, const T &rhs) const
6318 {
6319 return lhs <= rhs;
6320 }
6321};
6322
6323template <typename T>
6324void swap(T &lhs, T &rhs)
6325{
6326 T temp = lhs;
6327 lhs = rhs;
6328 rhs = temp;
6329}
6330
6331template <typename I, typename Pred>
6332I min_element(I begin, I end, const Pred &pred)
6333{
6334 I result = begin;
6335
6336 for (I it = begin + 1; it != end; ++it)
6337 if (pred(*it, *result))
6338 result = it;
6339
6340 return result;
6341}
6342
6343template <typename I>
6344void reverse(I begin, I end)
6345{
6346 while (end - begin > 1)
6347 swap(*begin++, *--end);
6348}
6349
6350template <typename I>
6351I unique(I begin, I end)
6352{
6353 // fast skip head
6354 while (end - begin > 1 && *begin != *(begin + 1))
6355 begin++;
6356
6357 if (begin == end)
6358 return begin;
6359
6360 // last written element
6361 I write = begin++;
6362
6363 // merge unique elements
6364 while (begin != end)
6365 {
6366 if (*begin != *write)
6367 *++write = *begin++;
6368 else
6369 begin++;
6370 }
6371
6372 // past-the-end (write points to live element)
6373 return write + 1;
6374}
6375
6376template <typename I>
6377void copy_backwards(I begin, I end, I target)
6378{
6379 while (begin != end)
6380 *--target = *--end;
6381}
6382
6383template <typename I, typename Pred, typename T>
6384void insertion_sort(I begin, I end, const Pred &pred, T *)
6385{
6386 assert(begin != end);
6387
6388 for (I it = begin + 1; it != end; ++it)
6389 {
6390 T val = *it;
6391
6392 if (pred(val, *begin))
6393 {
6394 // move to front
6395 copy_backwards(begin, it, it + 1);
6396 *begin = val;
6397 }
6398 else
6399 {
6400 I hole = it;
6401
6402 // move hole backwards
6403 while (pred(val, *(hole - 1)))
6404 {
6405 *hole = *(hole - 1);
6406 hole--;
6407 }
6408
6409 // fill hole with element
6410 *hole = val;
6411 }
6412 }
6413}
6414
6415// std variant for elements with ==
6416template <typename I, typename Pred>
6417void partition(I begin, I middle, I end, const Pred &pred, I *out_eqbeg, I *out_eqend)
6418{
6419 I eqbeg = middle, eqend = middle + 1;
6420
6421 // expand equal range
6422 while (eqbeg != begin && *(eqbeg - 1) == *eqbeg)
6423 --eqbeg;
6424 while (eqend != end && *eqend == *eqbeg)
6425 ++eqend;
6426
6427 // process outer elements
6428 I ltend = eqbeg, gtbeg = eqend;
6429
6430 for (;;)
6431 {
6432 // find the element from the right side that belongs to the left one
6433 for (; gtbeg != end; ++gtbeg)
6434 if (!pred(*eqbeg, *gtbeg))
6435 {
6436 if (*gtbeg == *eqbeg)
6437 swap(*gtbeg, *eqend++);
6438 else
6439 break;
6440 }
6441
6442 // find the element from the left side that belongs to the right one
6443 for (; ltend != begin; --ltend)
6444 if (!pred(*(ltend - 1), *eqbeg))
6445 {
6446 if (*eqbeg == *(ltend - 1))
6447 swap(*(ltend - 1), *--eqbeg);
6448 else
6449 break;
6450 }
6451
6452 // scanned all elements
6453 if (gtbeg == end && ltend == begin)
6454 {
6455 *out_eqbeg = eqbeg;
6456 *out_eqend = eqend;
6457 return;
6458 }
6459
6460 // make room for elements by moving equal area
6461 if (gtbeg == end)
6462 {
6463 if (--ltend != --eqbeg)
6464 swap(*ltend, *eqbeg);
6465 swap(*eqbeg, *--eqend);
6466 }
6467 else if (ltend == begin)
6468 {
6469 if (eqend != gtbeg)
6470 swap(*eqbeg, *eqend);
6471 ++eqend;
6472 swap(*gtbeg++, *eqbeg++);
6473 }
6474 else
6475 swap(*gtbeg++, *--ltend);
6476 }
6477}
6478
6479template <typename I, typename Pred>
6480void median3(I first, I middle, I last, const Pred &pred)
6481{
6482 if (pred(*middle, *first))
6483 swap(*middle, *first);
6484 if (pred(*last, *middle))
6485 swap(*last, *middle);
6486 if (pred(*middle, *first))
6487 swap(*middle, *first);
6488}
6489
6490template <typename I, typename Pred>
6491void median(I first, I middle, I last, const Pred &pred)
6492{
6493 if (last - first <= 40)
6494 {
6495 // median of three for small chunks
6496 median3(first, middle, last, pred);
6497 }
6498 else
6499 {
6500 // median of nine
6501 size_t step = (last - first + 1) / 8;
6502
6503 median3(first, first + step, first + 2 * step, pred);
6504 median3(middle - step, middle, middle + step, pred);
6505 median3(last - 2 * step, last - step, last, pred);
6506 median3(first + step, middle, last - step, pred);
6507 }
6508}
6509
6510template <typename I, typename Pred>
6511void sort(I begin, I end, const Pred &pred)
6512{
6513 // sort large chunks
6514 while (end - begin > 32)
6515 {
6516 // find median element
6517 I middle = begin + (end - begin) / 2;
6518 median(begin, middle, end - 1, pred);
6519
6520 // partition in three chunks (< = >)
6521 I eqbeg, eqend;
6522 partition(begin, middle, end, pred, &eqbeg, &eqend);
6523
6524 // loop on larger half
6525 if (eqbeg - begin > end - eqend)
6526 {
6527 sort(eqend, end, pred);
6528 end = eqbeg;
6529 }
6530 else
6531 {
6532 sort(begin, eqbeg, pred);
6533 begin = eqend;
6534 }
6535 }
6536
6537 // insertion sort small chunk
6538 if (begin != end)
6539 insertion_sort(begin, end, pred, &*begin);
6540}
6542
6543// Allocator used for AST and evaluation stacks
6546{
6548
6549 char data[
6550#ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
6551 PUGIXML_MEMORY_XPATH_PAGE_SIZE
6552#else
6553 4096
6554#endif
6555 ];
6556};
6557
6559{
6562
6563 public:
6564#ifdef PUGIXML_NO_EXCEPTIONS
6565 jmp_buf *error_handler;
6566#endif
6567
6568 xpath_allocator(xpath_memory_block *root, size_t root_size = 0) : _root(root), _root_size(root_size)
6569 {
6570#ifdef PUGIXML_NO_EXCEPTIONS
6571 error_handler = 0;
6572#endif
6573 }
6574
6575 void *allocate_nothrow(size_t size)
6576 {
6577 const size_t block_capacity = sizeof(_root->data);
6578
6579 // align size so that we're able to store pointers in subsequent blocks
6580 size = (size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
6581
6582 if (_root_size + size <= block_capacity)
6583 {
6584 void *buf = _root->data + _root_size;
6585 _root_size += size;
6586 return buf;
6587 }
6588 else
6589 {
6590 size_t block_data_size = (size > block_capacity) ? size : block_capacity;
6591 size_t block_size = block_data_size + offsetof(xpath_memory_block, data);
6592
6593 xpath_memory_block *block = static_cast<xpath_memory_block *>(xml_memory::allocate(block_size));
6594 if (!block)
6595 return 0;
6596
6597 block->next = _root;
6598
6599 _root = block;
6600 _root_size = size;
6601
6602 return block->data;
6603 }
6604 }
6605
6606 void *allocate(size_t size)
6607 {
6608 void *result = allocate_nothrow(size);
6609
6610 if (!result)
6611 {
6612#ifdef PUGIXML_NO_EXCEPTIONS
6613 assert(error_handler);
6614 longjmp(*error_handler, 1);
6615#else
6616 throw std::bad_alloc();
6617#endif
6618 }
6619
6620 return result;
6621 }
6622
6623 void *reallocate(void *ptr, size_t old_size, size_t new_size)
6624 {
6625 // align size so that we're able to store pointers in subsequent blocks
6626 old_size = (old_size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
6627 new_size = (new_size + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
6628
6629 // we can only reallocate the last object
6630 assert(ptr == 0 || static_cast<char *>(ptr) + old_size == _root->data + _root_size);
6631
6632 // adjust root size so that we have not allocated the object at all
6633 bool only_object = (_root_size == old_size);
6634
6635 if (ptr)
6636 _root_size -= old_size;
6637
6638 // allocate a new version (this will obviously reuse the memory if possible)
6639 void *result = allocate(new_size);
6640 assert(result);
6641
6642 // we have a new block
6643 if (result != ptr && ptr)
6644 {
6645 // copy old data
6646 assert(new_size >= old_size);
6647 memcpy(result, ptr, old_size);
6648
6649 // free the previous page if it had no other objects
6650 if (only_object)
6651 {
6652 assert(_root->data == result);
6653 assert(_root->next);
6654
6656
6657 if (next)
6658 {
6659 // deallocate the whole page, unless it was the first one
6661 _root->next = next;
6662 }
6663 }
6664 }
6665
6666 return result;
6667 }
6668
6669 void revert(const xpath_allocator &state)
6670 {
6671 // free all new pages
6673
6674 while (cur != state._root)
6675 {
6676 xpath_memory_block *next = cur->next;
6677
6679
6680 cur = next;
6681 }
6682
6683 // restore state
6684 _root = state._root;
6685 _root_size = state._root_size;
6686 }
6687
6688 void release()
6689 {
6691 assert(cur);
6692
6693 while (cur->next)
6694 {
6695 xpath_memory_block *next = cur->next;
6696
6698
6699 cur = next;
6700 }
6701 }
6702};
6703
6713
6719
6721{
6726
6727#ifdef PUGIXML_NO_EXCEPTIONS
6728 jmp_buf error_handler;
6729#endif
6730
6732 {
6733 blocks[0].next = blocks[1].next = 0;
6734
6735 stack.result = &result;
6736 stack.temp = &temp;
6737
6738#ifdef PUGIXML_NO_EXCEPTIONS
6739 result.error_handler = temp.error_handler = &error_handler;
6740#endif
6741 }
6742
6744 {
6745 result.release();
6746 temp.release();
6747 }
6748};
6750
6751// String class
6754{
6755 const char_t *_buffer;
6757
6758 static char_t *duplicate_string(const char_t *string, size_t length, xpath_allocator *alloc)
6759 {
6760 char_t *result = static_cast<char_t *>(alloc->allocate((length + 1) * sizeof(char_t)));
6761 assert(result);
6762
6763 memcpy(result, string, length * sizeof(char_t));
6764 result[length] = 0;
6765
6766 return result;
6767 }
6768
6769 static char_t *duplicate_string(const char_t *string, xpath_allocator *alloc)
6770 {
6771 return duplicate_string(string, strlength(string), alloc);
6772 }
6773
6774 public:
6776
6777 explicit xpath_string(const char_t *str, xpath_allocator *alloc)
6778 {
6779 bool empty_ = (*str == 0);
6780
6781 _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(str, alloc);
6782 _uses_heap = !empty_;
6783 }
6784
6785 explicit xpath_string(const char_t *str, bool use_heap) : _buffer(str), _uses_heap(use_heap) {}
6786
6787 xpath_string(const char_t *begin, const char_t *end, xpath_allocator *alloc)
6788 {
6789 assert(begin <= end);
6790
6791 bool empty_ = (begin == end);
6792
6793 _buffer = empty_ ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast<size_t>(end - begin), alloc);
6794 _uses_heap = !empty_;
6795 }
6796
6797 void append(const xpath_string &o, xpath_allocator *alloc)
6798 {
6799 // skip empty sources
6800 if (!*o._buffer)
6801 return;
6802
6803 // fast append for constant empty target and constant source
6804 if (!*_buffer && !_uses_heap && !o._uses_heap)
6805 {
6806 _buffer = o._buffer;
6807 }
6808 else
6809 {
6810 // need to make heap copy
6811 size_t target_length = strlength(_buffer);
6812 size_t source_length = strlength(o._buffer);
6813 size_t result_length = target_length + source_length;
6814
6815 // allocate new buffer
6816 char_t *result = static_cast<char_t *>(alloc->reallocate(_uses_heap ? const_cast<char_t *>(_buffer) : 0,
6817 (target_length + 1) * sizeof(char_t),
6818 (result_length + 1) * sizeof(char_t)));
6819 assert(result);
6820
6821 // append first string to the new buffer in case there was no reallocation
6822 if (!_uses_heap)
6823 memcpy(result, _buffer, target_length * sizeof(char_t));
6824
6825 // append second string to the new buffer
6826 memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
6827 result[result_length] = 0;
6828
6829 // finalize
6830 _buffer = result;
6831 _uses_heap = true;
6832 }
6833 }
6834
6835 const char_t *c_str() const { return _buffer; }
6836
6837 size_t length() const { return strlength(_buffer); }
6838
6839 char_t *data(xpath_allocator *alloc)
6840 {
6841 // make private heap copy
6842 if (!_uses_heap)
6843 {
6845 _uses_heap = true;
6846 }
6847
6848 return const_cast<char_t *>(_buffer);
6849 }
6850
6851 bool empty() const { return *_buffer == 0; }
6852
6853 bool operator==(const xpath_string &o) const { return strequal(_buffer, o._buffer); }
6854
6855 bool operator!=(const xpath_string &o) const { return !strequal(_buffer, o._buffer); }
6856
6857 bool uses_heap() const { return _uses_heap; }
6858};
6859
6861{
6862 return xpath_string(str, false);
6863}
6865
6867PUGI__FN bool starts_with(const char_t *string, const char_t *pattern)
6868{
6869 while (*pattern && *string == *pattern)
6870 {
6871 string++;
6872 pattern++;
6873 }
6874
6875 return *pattern == 0;
6876}
6877
6878PUGI__FN const char_t *find_char(const char_t *s, char_t c)
6879{
6880#ifdef PUGIXML_WCHAR_MODE
6881 return wcschr(s, c);
6882#else
6883 return strchr(s, c);
6884#endif
6885}
6886
6887PUGI__FN const char_t *find_substring(const char_t *s, const char_t *p)
6888{
6889#ifdef PUGIXML_WCHAR_MODE
6890 // MSVC6 wcsstr bug workaround (if s is empty it always returns 0)
6891 return (*p == 0) ? s : wcsstr(s, p);
6892#else
6893 return strstr(s, p);
6894#endif
6895}
6896
6897// Converts symbol to lower case, if it is an ASCII one
6898PUGI__FN char_t tolower_ascii(char_t ch)
6899{
6900 return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
6901}
6902
6904{
6905 if (na.attribute())
6906 return xpath_string_const(na.attribute().value());
6907 else
6908 {
6909 const xml_node &n = na.node();
6910
6911 switch (n.type())
6912 {
6913 case node_pcdata:
6914 case node_cdata:
6915 case node_comment:
6916 case node_pi:
6917 return xpath_string_const(n.value());
6918
6919 case node_document:
6920 case node_element:
6921 {
6922 xpath_string result;
6923
6924 xml_node cur = n.first_child();
6925
6926 while (cur && cur != n)
6927 {
6928 if (cur.type() == node_pcdata || cur.type() == node_cdata)
6929 result.append(xpath_string_const(cur.value()), alloc);
6930
6931 if (cur.first_child())
6932 cur = cur.first_child();
6933 else if (cur.next_sibling())
6934 cur = cur.next_sibling();
6935 else
6936 {
6937 while (!cur.next_sibling() && cur != n)
6938 cur = cur.parent();
6939
6940 if (cur != n)
6941 cur = cur.next_sibling();
6942 }
6943 }
6944
6945 return result;
6946 }
6947
6948 default:
6949 return xpath_string();
6950 }
6951 }
6952}
6953
6954PUGI__FN unsigned int node_height(xml_node n)
6955{
6956 unsigned int result = 0;
6957
6958 while (n)
6959 {
6960 ++result;
6961 n = n.parent();
6962 }
6963
6964 return result;
6965}
6966
6967PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh)
6968{
6969 // normalize heights
6970 for (unsigned int i = rh; i < lh; i++)
6971 ln = ln.parent();
6972 for (unsigned int j = lh; j < rh; j++)
6973 rn = rn.parent();
6974
6975 // one node is the ancestor of the other
6976 if (ln == rn)
6977 return lh < rh;
6978
6979 // find common ancestor
6980 while (ln.parent() != rn.parent())
6981 {
6982 ln = ln.parent();
6983 rn = rn.parent();
6984 }
6985
6986 // there is no common ancestor (the shared parent is null), nodes are from different documents
6987 if (!ln.parent())
6988 return ln < rn;
6989
6990 // determine sibling order
6991 for (; ln; ln = ln.next_sibling())
6992 if (ln == rn)
6993 return true;
6994
6995 return false;
6996}
6997
6998PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node)
6999{
7000 while (node && node != parent)
7001 node = node.parent();
7002
7003 return parent && node == parent;
7004}
7005
7006PUGI__FN const void *document_order(const xpath_node &xnode)
7007{
7008 xml_node_struct *node = xnode.node().internal_object();
7009
7010 if (node)
7011 {
7012 if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0)
7013 return node->name;
7014 if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0)
7015 return node->value;
7016 return 0;
7017 }
7018
7019 xml_attribute_struct *attr = xnode.attribute().internal_object();
7020
7021 if (attr)
7022 {
7023 if ((attr->header & xml_memory_page_name_allocated_mask) == 0)
7024 return attr->name;
7025 if ((attr->header & xml_memory_page_value_allocated_mask) == 0)
7026 return attr->value;
7027 return 0;
7028 }
7029
7030 return 0;
7031}
7032
7034{
7035 bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
7036 {
7037 // optimized document order based check
7038 const void *lo = document_order(lhs);
7039 const void *ro = document_order(rhs);
7040
7041 if (lo && ro)
7042 return lo < ro;
7043
7044 // slow comparison
7045 xml_node ln = lhs.node(), rn = rhs.node();
7046
7047 // compare attributes
7048 if (lhs.attribute() && rhs.attribute())
7049 {
7050 // shared parent
7051 if (lhs.parent() == rhs.parent())
7052 {
7053 // determine sibling order
7054 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
7055 if (a == rhs.attribute())
7056 return true;
7057
7058 return false;
7059 }
7060
7061 // compare attribute parents
7062 ln = lhs.parent();
7063 rn = rhs.parent();
7064 }
7065 else if (lhs.attribute())
7066 {
7067 // attributes go after the parent element
7068 if (lhs.parent() == rhs.node())
7069 return false;
7070
7071 ln = lhs.parent();
7072 }
7073 else if (rhs.attribute())
7074 {
7075 // attributes go after the parent element
7076 if (rhs.parent() == lhs.node())
7077 return true;
7078
7079 rn = rhs.parent();
7080 }
7081
7082 if (ln == rn)
7083 return false;
7084
7085 unsigned int lh = node_height(ln);
7086 unsigned int rh = node_height(rn);
7087
7088 return node_is_before(ln, lh, rn, rh);
7089 }
7090};
7091
7093{
7094 bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
7095 {
7096 if (lhs.attribute())
7097 return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true;
7098 else
7099 return rhs.attribute() ? false : lhs.node() < rhs.node();
7100 }
7101};
7102
7104{
7105#if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
7106 union {
7107 float f;
7108 uint32_t i;
7109 } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1];
7110 u[0].i = 0x7fc00000;
7111 return u[0].f;
7112#else
7113 // fallback
7114 const volatile double zero = 0.0;
7115 return zero / zero;
7116#endif
7117}
7118
7119PUGI__FN bool is_nan(double value)
7120{
7121#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
7122 return !!_isnan(value);
7123#elif defined(fpclassify) && defined(FP_NAN)
7124 return fpclassify(value) == FP_NAN;
7125#else
7126 // fallback
7127 const volatile double v = value;
7128 return v != v;
7129#endif
7130}
7131
7133{
7134#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
7135 if (_finite(value))
7136 return (value == 0) ? PUGIXML_TEXT("0") : 0;
7137 if (_isnan(value))
7138 return PUGIXML_TEXT("NaN");
7139 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
7140#elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
7141 switch (fpclassify(value))
7142 {
7143 case FP_NAN:
7144 return PUGIXML_TEXT("NaN");
7145
7146 case FP_INFINITE:
7147 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
7148
7149 case FP_ZERO:
7150 return PUGIXML_TEXT("0");
7151
7152 default:
7153 return 0;
7154 }
7155#else
7156 // fallback
7157 const volatile double v = value;
7158
7159 if (v == 0)
7160 return PUGIXML_TEXT("0");
7161 if (v != v)
7162 return PUGIXML_TEXT("NaN");
7163 if (v * 2 == v)
7164 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
7165 return 0;
7166#endif
7167}
7168
7170{
7171 return (value != 0 && !is_nan(value));
7172}
7173
7174PUGI__FN void truncate_zeros(char *begin, char *end)
7175{
7176 while (begin != end && end[-1] == '0')
7177 end--;
7178
7179 *end = 0;
7180}
7181
7182// gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
7183#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
7184PUGI__FN void convert_number_to_mantissa_exponent(double value, char *buffer, size_t buffer_size, char **out_mantissa,
7185 int *out_exponent)
7186{
7187 // get base values
7188 int sign, exponent;
7189 _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign);
7190
7191 // truncate redundant zeros
7192 truncate_zeros(buffer, buffer + strlen(buffer));
7193
7194 // fill results
7195 *out_mantissa = buffer;
7196 *out_exponent = exponent;
7197}
7198#else
7199PUGI__FN void convert_number_to_mantissa_exponent(double value, char *buffer, size_t buffer_size, char **out_mantissa,
7200 int *out_exponent)
7201{
7202 // get a scientific notation value with IEEE DBL_DIG decimals
7203 sprintf(buffer, "%.*e", DBL_DIG, value);
7204 assert(strlen(buffer) < buffer_size);
7205 (void)!buffer_size;
7206
7207 // get the exponent (possibly negative)
7208 char *exponent_string = strchr(buffer, 'e');
7209 assert(exponent_string);
7210
7211 int exponent = atoi(exponent_string + 1);
7212
7213 // extract mantissa string: skip sign
7214 char *mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
7215 assert(mantissa[0] != '0' && mantissa[1] == '.');
7216
7217 // divide mantissa by 10 to eliminate integer part
7218 mantissa[1] = mantissa[0];
7219 mantissa++;
7220 exponent++;
7221
7222 // remove extra mantissa digits and zero-terminate mantissa
7223 truncate_zeros(mantissa, exponent_string);
7224
7225 // fill results
7226 *out_mantissa = mantissa;
7227 *out_exponent = exponent;
7228}
7229#endif
7230
7232{
7233 // try special number conversion
7234 const char_t *special = convert_number_to_string_special(value);
7235 if (special)
7236 return xpath_string_const(special);
7237
7238 // get mantissa + exponent form
7239 char mantissa_buffer[32];
7240
7241 char *mantissa;
7242 int exponent;
7243 convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent);
7244
7245 // allocate a buffer of suitable length for the number
7246 size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
7247 char_t *result = static_cast<char_t *>(alloc->allocate(sizeof(char_t) * result_size));
7248 assert(result);
7249
7250 // make the number!
7251 char_t *s = result;
7252
7253 // sign
7254 if (value < 0)
7255 *s++ = '-';
7256
7257 // integer part
7258 if (exponent <= 0)
7259 {
7260 *s++ = '0';
7261 }
7262 else
7263 {
7264 while (exponent > 0)
7265 {
7266 assert(*mantissa == 0 || static_cast<unsigned int>(static_cast<unsigned int>(*mantissa) - '0') <= 9);
7267 *s++ = *mantissa ? *mantissa++ : '0';
7268 exponent--;
7269 }
7270 }
7271
7272 // fractional part
7273 if (*mantissa)
7274 {
7275 // decimal point
7276 *s++ = '.';
7277
7278 // extra zeroes from negative exponent
7279 while (exponent < 0)
7280 {
7281 *s++ = '0';
7282 exponent++;
7283 }
7284
7285 // extra mantissa digits
7286 while (*mantissa)
7287 {
7288 assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
7289 *s++ = *mantissa++;
7290 }
7291 }
7292
7293 // zero-terminate
7294 assert(s < result + result_size);
7295 *s = 0;
7296
7297 return xpath_string(result, true);
7298}
7299
7300PUGI__FN bool check_string_to_number_format(const char_t *string)
7301{
7302 // parse leading whitespace
7303 while (PUGI__IS_CHARTYPE(*string, ct_space))
7304 ++string;
7305
7306 // parse sign
7307 if (*string == '-')
7308 ++string;
7309
7310 if (!*string)
7311 return false;
7312
7313 // if there is no integer part, there should be a decimal part with at least one digit
7314 if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit)))
7315 return false;
7316
7317 // parse integer part
7318 while (PUGI__IS_CHARTYPEX(*string, ctx_digit))
7319 ++string;
7320
7321 // parse decimal part
7322 if (*string == '.')
7323 {
7324 ++string;
7325
7326 while (PUGI__IS_CHARTYPEX(*string, ctx_digit))
7327 ++string;
7328 }
7329
7330 // parse trailing whitespace
7331 while (PUGI__IS_CHARTYPE(*string, ct_space))
7332 ++string;
7333
7334 return *string == 0;
7335}
7336
7337PUGI__FN double convert_string_to_number(const char_t *string)
7338{
7339 // check string format
7340 if (!check_string_to_number_format(string))
7341 return gen_nan();
7342
7343 // parse string
7344#ifdef PUGIXML_WCHAR_MODE
7345 return wcstod(string, 0);
7346#else
7347 return atof(string);
7348#endif
7349}
7350
7351PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t *begin, const char_t *end,
7352 double *out_result)
7353{
7354 size_t length = static_cast<size_t>(end - begin);
7355 char_t *scratch = buffer;
7356
7357 if (length >= sizeof(buffer) / sizeof(buffer[0]))
7358 {
7359 // need to make dummy on-heap copy
7360 scratch = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
7361 if (!scratch)
7362 return false;
7363 }
7364
7365 // copy string to zero-terminated buffer and perform conversion
7366 memcpy(scratch, begin, length * sizeof(char_t));
7367 scratch[length] = 0;
7368
7369 *out_result = convert_string_to_number(scratch);
7370
7371 // free dummy buffer
7372 if (scratch != buffer)
7373 xml_memory::deallocate(scratch);
7374
7375 return true;
7376}
7377
7378PUGI__FN double round_nearest(double value)
7379{
7380 return floor(value + 0.5);
7381}
7382
7383PUGI__FN double round_nearest_nzero(double value)
7384{
7385 // same as round_nearest, but returns -0 for [-0.5, -0]
7386 // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)
7387 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
7388}
7389
7390PUGI__FN const char_t *qualified_name(const xpath_node &node)
7391{
7392 return node.attribute() ? node.attribute().name() : node.node().name();
7393}
7394
7395PUGI__FN const char_t *local_name(const xpath_node &node)
7396{
7397 const char_t *name = qualified_name(node);
7398 const char_t *p = find_char(name, ':');
7399
7400 return p ? p + 1 : name;
7401}
7402
7404{
7405 const char_t *prefix;
7407
7408 namespace_uri_predicate(const char_t *name)
7409 {
7410 const char_t *pos = find_char(name, ':');
7411
7412 prefix = pos ? name : 0;
7413 prefix_length = pos ? static_cast<size_t>(pos - name) : 0;
7414 }
7415
7416 bool operator()(const xml_attribute &a) const
7417 {
7418 const char_t *name = a.name();
7419
7420 if (!starts_with(name, PUGIXML_TEXT("xmlns")))
7421 return false;
7422
7423 return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
7424 }
7425};
7426
7427PUGI__FN const char_t *namespace_uri(const xml_node &node)
7428{
7429 namespace_uri_predicate pred = node.name();
7430
7431 xml_node p = node;
7432
7433 while (p)
7434 {
7435 xml_attribute a = p.find_attribute(pred);
7436
7437 if (a)
7438 return a.value();
7439
7440 p = p.parent();
7441 }
7442
7443 return PUGIXML_TEXT("");
7444}
7445
7446PUGI__FN const char_t *namespace_uri(const xml_attribute &attr, const xml_node &parent)
7447{
7448 namespace_uri_predicate pred = attr.name();
7449
7450 // Default namespace does not apply to attributes
7451 if (!pred.prefix)
7452 return PUGIXML_TEXT("");
7453
7454 xml_node p = parent;
7455
7456 while (p)
7457 {
7458 xml_attribute a = p.find_attribute(pred);
7459
7460 if (a)
7461 return a.value();
7462
7463 p = p.parent();
7464 }
7465
7466 return PUGIXML_TEXT("");
7467}
7468
7469PUGI__FN const char_t *namespace_uri(const xpath_node &node)
7470{
7471 return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
7472}
7473
7474PUGI__FN void normalize_space(char_t *buffer)
7475{
7476 char_t *write = buffer;
7477
7478 for (char_t *it = buffer; *it;)
7479 {
7480 char_t ch = *it++;
7481
7482 if (PUGI__IS_CHARTYPE(ch, ct_space))
7483 {
7484 // replace whitespace sequence with single space
7485 while (PUGI__IS_CHARTYPE(*it, ct_space))
7486 it++;
7487
7488 // avoid leading spaces
7489 if (write != buffer)
7490 *write++ = ' ';
7491 }
7492 else
7493 *write++ = ch;
7494 }
7495
7496 // remove trailing space
7497 if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space))
7498 write--;
7499
7500 // zero-terminate
7501 *write = 0;
7502}
7503
7504PUGI__FN void translate(char_t *buffer, const char_t *from, const char_t *to)
7505{
7506 size_t to_length = strlength(to);
7507
7508 char_t *write = buffer;
7509
7510 while (*buffer)
7511 {
7512 PUGI__DMC_VOLATILE char_t ch = *buffer++;
7513
7514 const char_t *pos = find_char(from, ch);
7515
7516 if (!pos)
7517 *write++ = ch; // do not process
7518 else if (static_cast<size_t>(pos - from) < to_length)
7519 *write++ = to[pos - from]; // replace
7520 }
7521
7522 // zero-terminate
7523 *write = 0;
7524}
7525
7533
7535{
7537
7538 double value;
7539 char_t name[1];
7540};
7541
7555
7557{
7558 xpath_node_set value;
7559 char_t name[1];
7560};
7561
7562static const xpath_node_set dummy_node_set;
7563
7564PUGI__FN unsigned int hash_string(const char_t *str)
7565{
7566 // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
7567 unsigned int result = 0;
7568
7569 while (*str)
7570 {
7571 result += static_cast<unsigned int>(*str++);
7572 result += result << 10;
7573 result ^= result >> 6;
7574 }
7575
7576 result += result << 3;
7577 result ^= result >> 11;
7578 result += result << 15;
7579
7580 return result;
7581}
7582
7583template <typename T>
7584PUGI__FN T *new_xpath_variable(const char_t *name)
7585{
7586 size_t length = strlength(name);
7587 if (length == 0)
7588 return 0; // empty variable names are invalid
7589
7590 // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
7591 void *memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));
7592 if (!memory)
7593 return 0;
7594
7595 T *result = new (memory) T();
7596
7597 memcpy(result->name, name, (length + 1) * sizeof(char_t));
7598
7599 return result;
7600}
7601
7602PUGI__FN xpath_variable *new_xpath_variable(xpath_value_type type, const char_t *name)
7603{
7604 switch (type)
7605 {
7606 case xpath_type_node_set:
7607 return new_xpath_variable<xpath_variable_node_set>(name);
7608
7609 case xpath_type_number:
7610 return new_xpath_variable<xpath_variable_number>(name);
7611
7612 case xpath_type_string:
7613 return new_xpath_variable<xpath_variable_string>(name);
7614
7615 case xpath_type_boolean:
7616 return new_xpath_variable<xpath_variable_boolean>(name);
7617
7618 default:
7619 return 0;
7620 }
7621}
7622
7623template <typename T>
7625{
7626 var->~T();
7628}
7629
7630PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable *var)
7631{
7632 switch (type)
7633 {
7634 case xpath_type_node_set:
7636 break;
7637
7638 case xpath_type_number:
7639 delete_xpath_variable(static_cast<xpath_variable_number *>(var));
7640 break;
7641
7642 case xpath_type_string:
7643 delete_xpath_variable(static_cast<xpath_variable_string *>(var));
7644 break;
7645
7646 case xpath_type_boolean:
7647 delete_xpath_variable(static_cast<xpath_variable_boolean *>(var));
7648 break;
7649
7650 default:
7651 assert(!"Invalid variable type");
7652 }
7653}
7654
7655PUGI__FN xpath_variable *get_variable_scratch(char_t (&buffer)[32], xpath_variable_set *set, const char_t *begin,
7656 const char_t *end)
7657{
7658 size_t length = static_cast<size_t>(end - begin);
7659 char_t *scratch = buffer;
7660
7661 if (length >= sizeof(buffer) / sizeof(buffer[0]))
7662 {
7663 // need to make dummy on-heap copy
7664 scratch = static_cast<char_t *>(xml_memory::allocate((length + 1) * sizeof(char_t)));
7665 if (!scratch)
7666 return 0;
7667 }
7668
7669 // copy string to zero-terminated buffer and perform lookup
7670 memcpy(scratch, begin, length * sizeof(char_t));
7671 scratch[length] = 0;
7672
7673 xpath_variable *result = set->get(scratch);
7674
7675 // free dummy buffer
7676 if (scratch != buffer)
7677 xml_memory::deallocate(scratch);
7678
7679 return result;
7680}
7682
7683// Internal node set class
7685PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node *begin, xpath_node *end, xpath_node_set::type_t type, bool rev)
7686{
7687 xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
7688
7689 if (type == xpath_node_set::type_unsorted)
7690 {
7691 sort(begin, end, document_order_comparator());
7692
7693 type = xpath_node_set::type_sorted;
7694 }
7695
7696 if (type != order)
7697 reverse(begin, end);
7698
7699 return order;
7700}
7701
7702PUGI__FN xpath_node xpath_first(const xpath_node *begin, const xpath_node *end, xpath_node_set::type_t type)
7703{
7704 if (begin == end)
7705 return xpath_node();
7706
7707 switch (type)
7708 {
7709 case xpath_node_set::type_sorted:
7710 return *begin;
7711
7712 case xpath_node_set::type_sorted_reverse:
7713 return *(end - 1);
7714
7715 case xpath_node_set::type_unsorted:
7716 return *min_element(begin, end, document_order_comparator());
7717
7718 default:
7719 assert(!"Invalid node set type");
7720 return xpath_node();
7721 }
7722}
7723
7725{
7726 xpath_node_set::type_t _type;
7727
7728 xpath_node *_begin;
7729 xpath_node *_end;
7730 xpath_node *_eos;
7731
7732 public:
7733 xpath_node_set_raw() : _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) {}
7734
7735 xpath_node *begin() const { return _begin; }
7736
7737 xpath_node *end() const { return _end; }
7738
7739 bool empty() const { return _begin == _end; }
7740
7741 size_t size() const { return static_cast<size_t>(_end - _begin); }
7742
7743 xpath_node first() const { return xpath_first(_begin, _end, _type); }
7744
7745 void push_back(const xpath_node &node, xpath_allocator *alloc)
7746 {
7747 if (_end == _eos)
7748 {
7749 size_t capacity = static_cast<size_t>(_eos - _begin);
7750
7751 // get new capacity (1.5x rule)
7752 size_t new_capacity = capacity + capacity / 2 + 1;
7753
7754 // reallocate the old array or allocate a new one
7755 xpath_node *data = static_cast<xpath_node *>(
7756 alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
7757 assert(data);
7758
7759 // finalize
7760 _begin = data;
7761 _end = data + capacity;
7762 _eos = data + new_capacity;
7763 }
7764
7765 *_end++ = node;
7766 }
7767
7768 void append(const xpath_node *begin_, const xpath_node *end_, xpath_allocator *alloc)
7769 {
7770 size_t size_ = static_cast<size_t>(_end - _begin);
7771 size_t capacity = static_cast<size_t>(_eos - _begin);
7772 size_t count = static_cast<size_t>(end_ - begin_);
7773
7774 if (size_ + count > capacity)
7775 {
7776 // reallocate the old array or allocate a new one
7777 xpath_node *data = static_cast<xpath_node *>(
7778 alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
7779 assert(data);
7780
7781 // finalize
7782 _begin = data;
7783 _end = data + size_;
7784 _eos = data + size_ + count;
7785 }
7786
7787 memcpy(_end, begin_, count * sizeof(xpath_node));
7788 _end += count;
7789 }
7790
7791 void sort_do() { _type = xpath_sort(_begin, _end, _type, false); }
7792
7793 void truncate(xpath_node *pos)
7794 {
7795 assert(_begin <= pos && pos <= _end);
7796
7797 _end = pos;
7798 }
7799
7801 {
7802 if (_type == xpath_node_set::type_unsorted)
7804
7805 _end = unique(_begin, _end);
7806 }
7807
7808 xpath_node_set::type_t type() const { return _type; }
7809
7810 void set_type(xpath_node_set::type_t value) { _type = value; }
7811};
7813
7816{
7817 xpath_node n;
7819
7820 xpath_context(const xpath_node &n_, size_t position_, size_t size_) : n(n_), position(position_), size(size_) {}
7821};
7822
7853
7855{
7856 const char_t *begin;
7857 const char_t *end;
7858
7860
7861 bool operator==(const char_t *other) const
7862 {
7863 size_t length = static_cast<size_t>(end - begin);
7864
7865 return strequalrange(other, begin, length);
7866 }
7867};
7868
7870{
7871 const char_t *_cur;
7872 const char_t *_cur_lexeme_pos;
7874
7876
7877 public:
7878 explicit xpath_lexer(const char_t *query) : _cur(query) { next(); }
7879
7880 const char_t *state() const { return _cur; }
7881
7882 void next()
7883 {
7884 const char_t *cur = _cur;
7885
7886 while (PUGI__IS_CHARTYPE(*cur, ct_space))
7887 ++cur;
7888
7889 // save lexeme position for error reporting
7890 _cur_lexeme_pos = cur;
7891
7892 switch (*cur)
7893 {
7894 case 0:
7896 break;
7897
7898 case '>':
7899 if (*(cur + 1) == '=')
7900 {
7901 cur += 2;
7903 }
7904 else
7905 {
7906 cur += 1;
7908 }
7909 break;
7910
7911 case '<':
7912 if (*(cur + 1) == '=')
7913 {
7914 cur += 2;
7916 }
7917 else
7918 {
7919 cur += 1;
7921 }
7922 break;
7923
7924 case '!':
7925 if (*(cur + 1) == '=')
7926 {
7927 cur += 2;
7929 }
7930 else
7931 {
7933 }
7934 break;
7935
7936 case '=':
7937 cur += 1;
7939
7940 break;
7941
7942 case '+':
7943 cur += 1;
7945
7946 break;
7947
7948 case '-':
7949 cur += 1;
7951
7952 break;
7953
7954 case '*':
7955 cur += 1;
7957
7958 break;
7959
7960 case '|':
7961 cur += 1;
7963
7964 break;
7965
7966 case '$':
7967 cur += 1;
7968
7970 {
7972
7973 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol))
7974 cur++;
7975
7976 if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
7977 {
7978 cur++; // :
7979
7980 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol))
7981 cur++;
7982 }
7983
7985
7987 }
7988 else
7989 {
7991 }
7992
7993 break;
7994
7995 case '(':
7996 cur += 1;
7998
7999 break;
8000
8001 case ')':
8002 cur += 1;
8004
8005 break;
8006
8007 case '[':
8008 cur += 1;
8010
8011 break;
8012
8013 case ']':
8014 cur += 1;
8016
8017 break;
8018
8019 case ',':
8020 cur += 1;
8022
8023 break;
8024
8025 case '/':
8026 if (*(cur + 1) == '/')
8027 {
8028 cur += 2;
8030 }
8031 else
8032 {
8033 cur += 1;
8035 }
8036 break;
8037
8038 case '.':
8039 if (*(cur + 1) == '.')
8040 {
8041 cur += 2;
8043 }
8044 else if (PUGI__IS_CHARTYPEX(*(cur + 1), ctx_digit))
8045 {
8046 _cur_lexeme_contents.begin = cur; // .
8047
8048 ++cur;
8049
8050 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
8051 cur++;
8052
8054
8056 }
8057 else
8058 {
8059 cur += 1;
8061 }
8062 break;
8063
8064 case '@':
8065 cur += 1;
8067
8068 break;
8069
8070 case '"':
8071 case '\'':
8072 {
8073 char_t terminator = *cur;
8074
8075 ++cur;
8076
8078 while (*cur && *cur != terminator)
8079 cur++;
8081
8082 if (!*cur)
8084 else
8085 {
8086 cur += 1;
8088 }
8089
8090 break;
8091 }
8092
8093 case ':':
8094 if (*(cur + 1) == ':')
8095 {
8096 cur += 2;
8098 }
8099 else
8100 {
8102 }
8103 break;
8104
8105 default:
8106 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
8107 {
8109
8110 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
8111 cur++;
8112
8113 if (*cur == '.')
8114 {
8115 cur++;
8116
8117 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
8118 cur++;
8119 }
8120
8122
8124 }
8125 else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
8126 {
8128
8129 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol))
8130 cur++;
8131
8132 if (cur[0] == ':')
8133 {
8134 if (cur[1] == '*') // namespace test ncname:*
8135 {
8136 cur += 2; // :*
8137 }
8138 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
8139 {
8140 cur++; // :
8141
8142 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol))
8143 cur++;
8144 }
8145 }
8146
8148
8150 }
8151 else
8152 {
8154 }
8155 }
8156
8157 _cur = cur;
8158 }
8159
8160 lexeme_t current() const { return _cur_lexeme; }
8161
8162 const char_t *current_pos() const { return _cur_lexeme_pos; }
8163
8165 {
8168
8169 return _cur_lexeme_contents;
8170 }
8171};
8172
8174{
8176 ast_op_or, // left or right
8177 ast_op_and, // left and right
8178 ast_op_equal, // left = right
8179 ast_op_not_equal, // left != right
8180 ast_op_less, // left < right
8181 ast_op_greater, // left > right
8182 ast_op_less_or_equal, // left <= right
8183 ast_op_greater_or_equal, // left >= right
8184 ast_op_add, // left + right
8185 ast_op_subtract, // left - right
8186 ast_op_multiply, // left * right
8187 ast_op_divide, // left / right
8188 ast_op_mod, // left % right
8189 ast_op_negate, // left - right
8190 ast_op_union, // left | right
8191 ast_predicate, // apply predicate to set; next points to next predicate
8192 ast_filter, // select * from left where right
8193 ast_filter_posinv, // select * from left where right; proximity position invariant
8194 ast_string_constant, // string constant
8195 ast_number_constant, // number constant
8196 ast_variable, // variable
8197 ast_func_last, // last()
8198 ast_func_position, // position()
8199 ast_func_count, // count(left)
8200 ast_func_id, // id(left)
8201 ast_func_local_name_0, // local-name()
8202 ast_func_local_name_1, // local-name(left)
8203 ast_func_namespace_uri_0, // namespace-uri()
8204 ast_func_namespace_uri_1, // namespace-uri(left)
8206 ast_func_name_1, // name(left)
8208 ast_func_string_1, // string(left)
8209 ast_func_concat, // concat(left, right, siblings)
8210 ast_func_starts_with, // starts_with(left, right)
8211 ast_func_contains, // contains(left, right)
8212 ast_func_substring_before, // substring-before(left, right)
8213 ast_func_substring_after, // substring-after(left, right)
8214 ast_func_substring_2, // substring(left, right)
8215 ast_func_substring_3, // substring(left, right, third)
8216 ast_func_string_length_0, // string-length()
8217 ast_func_string_length_1, // string-length(left)
8218 ast_func_normalize_space_0, // normalize-space()
8219 ast_func_normalize_space_1, // normalize-space(left)
8220 ast_func_translate, // translate(left, right, third)
8221 ast_func_boolean, // boolean(left)
8222 ast_func_not, // not(left)
8223 ast_func_true, // true()
8224 ast_func_false, // false()
8225 ast_func_lang, // lang(left)
8227 ast_func_number_1, // number(left)
8228 ast_func_sum, // sum(left)
8229 ast_func_floor, // floor(left)
8230 ast_func_ceiling, // ceiling(left)
8231 ast_func_round, // round(left)
8232 ast_step, // process set left with step
8233 ast_step_root // select root node
8235
8252
8265
8266template <axis_t N>
8268{
8269 static const axis_t axis;
8270};
8271
8272template <axis_t N>
8274
8276{
8277 private:
8278 // node type
8279 char _type;
8281
8282 // for ast_step / ast_predicate
8283 char _axis;
8284 char _test;
8285
8286 // tree node structure
8290
8291 union {
8292 // value for ast_string_constant
8293 const char_t *string;
8294 // value for ast_number_constant
8295 double number;
8296 // variable for ast_variable
8298 // node test for ast_step (node name/namespace/node type/pi target)
8299 const char_t *nodetest;
8301
8304
8305 template <class Comp>
8306 static bool compare_eq(xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack,
8307 const Comp &comp)
8308 {
8309 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
8310
8311 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
8312 {
8313 if (lt == xpath_type_boolean || rt == xpath_type_boolean)
8314 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
8315 else if (lt == xpath_type_number || rt == xpath_type_number)
8316 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
8317 else if (lt == xpath_type_string || rt == xpath_type_string)
8318 {
8320
8321 xpath_string ls = lhs->eval_string(c, stack);
8322 xpath_string rs = rhs->eval_string(c, stack);
8323
8324 return comp(ls, rs);
8325 }
8326 }
8327 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
8328 {
8330
8331 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
8332 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8333
8334 for (const xpath_node *li = ls.begin(); li != ls.end(); ++li)
8335 for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8336 {
8338
8339 if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
8340 return true;
8341 }
8342
8343 return false;
8344 }
8345 else
8346 {
8347 if (lt == xpath_type_node_set)
8348 {
8349 swap(lhs, rhs);
8350 swap(lt, rt);
8351 }
8352
8353 if (lt == xpath_type_boolean)
8354 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
8355 else if (lt == xpath_type_number)
8356 {
8358
8359 double l = lhs->eval_number(c, stack);
8360 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8361
8362 for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8363 {
8365
8366 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8367 return true;
8368 }
8369
8370 return false;
8371 }
8372 else if (lt == xpath_type_string)
8373 {
8375
8376 xpath_string l = lhs->eval_string(c, stack);
8377 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8378
8379 for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8380 {
8382
8383 if (comp(l, string_value(*ri, stack.result)))
8384 return true;
8385 }
8386
8387 return false;
8388 }
8389 }
8390
8391 assert(!"Wrong types");
8392 return false;
8393 }
8394
8395 template <class Comp>
8396 static bool compare_rel(xpath_ast_node *lhs, xpath_ast_node *rhs, const xpath_context &c, const xpath_stack &stack,
8397 const Comp &comp)
8398 {
8399 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
8400
8401 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
8402 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
8403 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
8404 {
8406
8407 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
8408 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8409
8410 for (const xpath_node *li = ls.begin(); li != ls.end(); ++li)
8411 {
8413
8414 double l = convert_string_to_number(string_value(*li, stack.result).c_str());
8415
8416 for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8417 {
8418 xpath_allocator_capture crii(stack.result);
8419
8420 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8421 return true;
8422 }
8423 }
8424
8425 return false;
8426 }
8427 else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
8428 {
8430
8431 double l = lhs->eval_number(c, stack);
8432 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
8433
8434 for (const xpath_node *ri = rs.begin(); ri != rs.end(); ++ri)
8435 {
8437
8438 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
8439 return true;
8440 }
8441
8442 return false;
8443 }
8444 else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
8445 {
8447
8448 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
8449 double r = rhs->eval_number(c, stack);
8450
8451 for (const xpath_node *li = ls.begin(); li != ls.end(); ++li)
8452 {
8454
8455 if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
8456 return true;
8457 }
8458
8459 return false;
8460 }
8461 else
8462 {
8463 assert(!"Wrong types");
8464 return false;
8465 }
8466 }
8467
8468 void apply_predicate(xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack)
8469 {
8470 assert(ns.size() >= first);
8471
8472 size_t i = 1;
8473 size_t size = ns.size() - first;
8474
8475 xpath_node *last = ns.begin() + first;
8476
8477 // remove_if... or well, sort of
8478 for (xpath_node *it = last; it != ns.end(); ++it, ++i)
8479 {
8480 xpath_context c(*it, i, size);
8481
8482 if (expr->rettype() == xpath_type_number)
8483 {
8484 if (expr->eval_number(c, stack) == i)
8485 *last++ = *it;
8486 }
8487 else if (expr->eval_boolean(c, stack))
8488 *last++ = *it;
8489 }
8490
8491 ns.truncate(last);
8492 }
8493
8494 void apply_predicates(xpath_node_set_raw &ns, size_t first, const xpath_stack &stack)
8495 {
8496 if (ns.size() == first)
8497 return;
8498
8499 for (xpath_ast_node *pred = _right; pred; pred = pred->_next)
8500 {
8501 apply_predicate(ns, first, pred->_left, stack);
8502 }
8503 }
8504
8505 void step_push(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &parent, xpath_allocator *alloc)
8506 {
8507 if (!a)
8508 return;
8509
8510 const char_t *name = a.name();
8511
8512 // There are no attribute nodes corresponding to attributes that declare namespaces
8513 // That is, "xmlns:..." or "xmlns"
8514 if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':'))
8515 return;
8516
8517 switch (_test)
8518 {
8519 case nodetest_name:
8520 if (strequal(name, _data.nodetest))
8521 ns.push_back(xpath_node(a, parent), alloc);
8522 break;
8523
8524 case nodetest_type_node:
8525 case nodetest_all:
8526 ns.push_back(xpath_node(a, parent), alloc);
8527 break;
8528
8530 if (starts_with(name, _data.nodetest))
8531 ns.push_back(xpath_node(a, parent), alloc);
8532 break;
8533
8534 default:;
8535 }
8536 }
8537
8538 void step_push(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc)
8539 {
8540 if (!n)
8541 return;
8542
8543 switch (_test)
8544 {
8545 case nodetest_name:
8546 if (n.type() == node_element && strequal(n.name(), _data.nodetest))
8547 ns.push_back(n, alloc);
8548 break;
8549
8550 case nodetest_type_node:
8551 ns.push_back(n, alloc);
8552 break;
8553
8555 if (n.type() == node_comment)
8556 ns.push_back(n, alloc);
8557 break;
8558
8559 case nodetest_type_text:
8560 if (n.type() == node_pcdata || n.type() == node_cdata)
8561 ns.push_back(n, alloc);
8562 break;
8563
8564 case nodetest_type_pi:
8565 if (n.type() == node_pi)
8566 ns.push_back(n, alloc);
8567 break;
8568
8569 case nodetest_pi:
8570 if (n.type() == node_pi && strequal(n.name(), _data.nodetest))
8571 ns.push_back(n, alloc);
8572 break;
8573
8574 case nodetest_all:
8575 if (n.type() == node_element)
8576 ns.push_back(n, alloc);
8577 break;
8578
8580 if (n.type() == node_element && starts_with(n.name(), _data.nodetest))
8581 ns.push_back(n, alloc);
8582 break;
8583
8584 default:
8585 assert(!"Unknown axis");
8586 }
8587 }
8588
8589 template <class T>
8590 void step_fill(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc, T)
8591 {
8592 const axis_t axis = T::axis;
8593
8594 switch (axis)
8595 {
8596 case axis_attribute:
8597 {
8598 for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute())
8599 step_push(ns, a, n, alloc);
8600
8601 break;
8602 }
8603
8604 case axis_child:
8605 {
8606 for (xml_node c = n.first_child(); c; c = c.next_sibling())
8607 step_push(ns, c, alloc);
8608
8609 break;
8610 }
8611
8612 case axis_descendant:
8614 {
8615 if (axis == axis_descendant_or_self)
8616 step_push(ns, n, alloc);
8617
8618 xml_node cur = n.first_child();
8619
8620 while (cur && cur != n)
8621 {
8622 step_push(ns, cur, alloc);
8623
8624 if (cur.first_child())
8625 cur = cur.first_child();
8626 else if (cur.next_sibling())
8627 cur = cur.next_sibling();
8628 else
8629 {
8630 while (!cur.next_sibling() && cur != n)
8631 cur = cur.parent();
8632
8633 if (cur != n)
8634 cur = cur.next_sibling();
8635 }
8636 }
8637
8638 break;
8639 }
8640
8642 {
8643 for (xml_node c = n.next_sibling(); c; c = c.next_sibling())
8644 step_push(ns, c, alloc);
8645
8646 break;
8647 }
8648
8650 {
8651 for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling())
8652 step_push(ns, c, alloc);
8653
8654 break;
8655 }
8656
8657 case axis_following:
8658 {
8659 xml_node cur = n;
8660
8661 // exit from this node so that we don't include descendants
8662 while (cur && !cur.next_sibling())
8663 cur = cur.parent();
8664 cur = cur.next_sibling();
8665
8666 for (;;)
8667 {
8668 step_push(ns, cur, alloc);
8669
8670 if (cur.first_child())
8671 cur = cur.first_child();
8672 else if (cur.next_sibling())
8673 cur = cur.next_sibling();
8674 else
8675 {
8676 while (cur && !cur.next_sibling())
8677 cur = cur.parent();
8678 cur = cur.next_sibling();
8679
8680 if (!cur)
8681 break;
8682 }
8683 }
8684
8685 break;
8686 }
8687
8688 case axis_preceding:
8689 {
8690 xml_node cur = n;
8691
8692 while (cur && !cur.previous_sibling())
8693 cur = cur.parent();
8694 cur = cur.previous_sibling();
8695
8696 for (;;)
8697 {
8698 if (cur.last_child())
8699 cur = cur.last_child();
8700 else
8701 {
8702 // leaf node, can't be ancestor
8703 step_push(ns, cur, alloc);
8704
8705 if (cur.previous_sibling())
8706 cur = cur.previous_sibling();
8707 else
8708 {
8709 do
8710 {
8711 cur = cur.parent();
8712 if (!cur)
8713 break;
8714
8715 if (!node_is_ancestor(cur, n))
8716 step_push(ns, cur, alloc);
8717 } while (!cur.previous_sibling());
8718
8719 cur = cur.previous_sibling();
8720
8721 if (!cur)
8722 break;
8723 }
8724 }
8725 }
8726
8727 break;
8728 }
8729
8730 case axis_ancestor:
8732 {
8733 if (axis == axis_ancestor_or_self)
8734 step_push(ns, n, alloc);
8735
8736 xml_node cur = n.parent();
8737
8738 while (cur)
8739 {
8740 step_push(ns, cur, alloc);
8741
8742 cur = cur.parent();
8743 }
8744
8745 break;
8746 }
8747
8748 case axis_self:
8749 {
8750 step_push(ns, n, alloc);
8751
8752 break;
8753 }
8754
8755 case axis_parent:
8756 {
8757 if (n.parent())
8758 step_push(ns, n.parent(), alloc);
8759
8760 break;
8761 }
8762
8763 default:
8764 assert(!"Unimplemented axis");
8765 }
8766 }
8767
8768 template <class T>
8769 void step_fill(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &p, xpath_allocator *alloc, T v)
8770 {
8771 const axis_t axis = T::axis;
8772
8773 switch (axis)
8774 {
8775 case axis_ancestor:
8777 {
8778 if (axis == axis_ancestor_or_self &&
8779 _test == nodetest_type_node) // reject attributes based on principal node type test
8780 step_push(ns, a, p, alloc);
8781
8782 xml_node cur = p;
8783
8784 while (cur)
8785 {
8786 step_push(ns, cur, alloc);
8787
8788 cur = cur.parent();
8789 }
8790
8791 break;
8792 }
8793
8795 case axis_self:
8796 {
8797 if (_test == nodetest_type_node) // reject attributes based on principal node type test
8798 step_push(ns, a, p, alloc);
8799
8800 break;
8801 }
8802
8803 case axis_following:
8804 {
8805 xml_node cur = p;
8806
8807 for (;;)
8808 {
8809 if (cur.first_child())
8810 cur = cur.first_child();
8811 else if (cur.next_sibling())
8812 cur = cur.next_sibling();
8813 else
8814 {
8815 while (cur && !cur.next_sibling())
8816 cur = cur.parent();
8817 cur = cur.next_sibling();
8818
8819 if (!cur)
8820 break;
8821 }
8822
8823 step_push(ns, cur, alloc);
8824 }
8825
8826 break;
8827 }
8828
8829 case axis_parent:
8830 {
8831 step_push(ns, p, alloc);
8832
8833 break;
8834 }
8835
8836 case axis_preceding:
8837 {
8838 // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's
8839 // ancestors), so we can reuse node preceding
8840 step_fill(ns, p, alloc, v);
8841 break;
8842 }
8843
8844 default:
8845 assert(!"Unimplemented axis");
8846 }
8847 }
8848
8849 template <class T>
8851 {
8852 const axis_t axis = T::axis;
8853 bool attributes =
8854 (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self ||
8855 axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
8856
8858 ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding ||
8859 axis == axis_preceding_sibling)
8860 ? xpath_node_set::type_sorted_reverse
8861 : xpath_node_set::type_sorted);
8862
8863 if (_left)
8864 {
8866
8867 // self axis preserves the original order
8868 if (axis == axis_self)
8869 ns.set_type(s.type());
8870
8871 for (const xpath_node *it = s.begin(); it != s.end(); ++it)
8872 {
8873 size_t size = ns.size();
8874
8875 // in general, all axes generate elements in a particular order, but there is no order guarantee if axis
8876 // is applied to two nodes
8877 if (axis != axis_self && size != 0)
8878 ns.set_type(xpath_node_set::type_unsorted);
8879
8880 if (it->node())
8881 step_fill(ns, it->node(), stack.result, v);
8882 else if (attributes)
8883 step_fill(ns, it->attribute(), it->parent(), stack.result, v);
8884
8885 apply_predicates(ns, size, stack);
8886 }
8887 }
8888 else
8889 {
8890 if (c.n.node())
8891 step_fill(ns, c.n.node(), stack.result, v);
8892 else if (attributes)
8893 step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v);
8894
8895 apply_predicates(ns, 0, stack);
8896 }
8897
8898 // child, attribute and self axes always generate unique set of nodes
8899 // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the
8900 // same node twice
8901 if (axis != axis_child && axis != axis_attribute && axis != axis_self &&
8902 ns.type() == xpath_node_set::type_unsorted)
8903 ns.remove_duplicates();
8904
8905 return ns;
8906 }
8907
8908 public:
8909 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t *value)
8910 : _type(static_cast<char>(type))
8911 , _rettype(static_cast<char>(rettype_))
8912 , _axis(0)
8913 , _test(0)
8914 , _left(0)
8915 , _right(0)
8916 , _next(0)
8917 {
8918 assert(type == ast_string_constant);
8919 _data.string = value;
8920 }
8921
8922 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value)
8923 : _type(static_cast<char>(type))
8924 , _rettype(static_cast<char>(rettype_))
8925 , _axis(0)
8926 , _test(0)
8927 , _left(0)
8928 , _right(0)
8929 , _next(0)
8930 {
8931 assert(type == ast_number_constant);
8932 _data.number = value;
8933 }
8934
8935 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable *value)
8936 : _type(static_cast<char>(type))
8937 , _rettype(static_cast<char>(rettype_))
8938 , _axis(0)
8939 , _test(0)
8940 , _left(0)
8941 , _right(0)
8942 , _next(0)
8943 {
8944 assert(type == ast_variable);
8945 _data.variable = value;
8946 }
8947
8948 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node *left = 0, xpath_ast_node *right = 0)
8949 : _type(static_cast<char>(type))
8950 , _rettype(static_cast<char>(rettype_))
8951 , _axis(0)
8952 , _test(0)
8953 , _left(left)
8954 , _right(right)
8955 , _next(0)
8956 {
8957 }
8958
8959 xpath_ast_node(ast_type_t type, xpath_ast_node *left, axis_t axis, nodetest_t test, const char_t *contents)
8960 : _type(static_cast<char>(type))
8961 , _rettype(xpath_type_node_set)
8962 , _axis(static_cast<char>(axis))
8963 , _test(static_cast<char>(test))
8964 , _left(left)
8965 , _right(0)
8966 , _next(0)
8967 {
8968 _data.nodetest = contents;
8969 }
8970
8971 void set_next(xpath_ast_node *value) { _next = value; }
8972
8973 void set_right(xpath_ast_node *value) { _right = value; }
8974
8975 bool eval_boolean(const xpath_context &c, const xpath_stack &stack)
8976 {
8977 switch (_type)
8978 {
8979 case ast_op_or:
8980 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
8981
8982 case ast_op_and:
8983 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
8984
8985 case ast_op_equal:
8986 return compare_eq(_left, _right, c, stack, equal_to());
8987
8988 case ast_op_not_equal:
8989 return compare_eq(_left, _right, c, stack, not_equal_to());
8990
8991 case ast_op_less:
8992 return compare_rel(_left, _right, c, stack, less());
8993
8994 case ast_op_greater:
8995 return compare_rel(_right, _left, c, stack, less());
8996
8998 return compare_rel(_left, _right, c, stack, less_equal());
8999
9001 return compare_rel(_right, _left, c, stack, less_equal());
9002
9004 {
9006
9007 xpath_string lr = _left->eval_string(c, stack);
9008 xpath_string rr = _right->eval_string(c, stack);
9009
9010 return starts_with(lr.c_str(), rr.c_str());
9011 }
9012
9013 case ast_func_contains:
9014 {
9016
9017 xpath_string lr = _left->eval_string(c, stack);
9018 xpath_string rr = _right->eval_string(c, stack);
9019
9020 return find_substring(lr.c_str(), rr.c_str()) != 0;
9021 }
9022
9023 case ast_func_boolean:
9024 return _left->eval_boolean(c, stack);
9025
9026 case ast_func_not:
9027 return !_left->eval_boolean(c, stack);
9028
9029 case ast_func_true:
9030 return true;
9031
9032 case ast_func_false:
9033 return false;
9034
9035 case ast_func_lang:
9036 {
9037 if (c.n.attribute())
9038 return false;
9039
9041
9042 xpath_string lang = _left->eval_string(c, stack);
9043
9044 for (xml_node n = c.n.node(); n; n = n.parent())
9045 {
9046 xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
9047
9048 if (a)
9049 {
9050 const char_t *value = a.value();
9051
9052 // strnicmp / strncasecmp is not portable
9053 for (const char_t *lit = lang.c_str(); *lit; ++lit)
9054 {
9055 if (tolower_ascii(*lit) != tolower_ascii(*value))
9056 return false;
9057 ++value;
9058 }
9059
9060 return *value == 0 || *value == '-';
9061 }
9062 }
9063
9064 return false;
9065 }
9066
9067 case ast_variable:
9068 {
9069 assert(_rettype == _data.variable->type());
9070
9071 if (_rettype == xpath_type_boolean)
9072 return _data.variable->get_boolean();
9073
9074 // fallthrough to type conversion
9075 }
9076
9077 default:
9078 {
9079 switch (_rettype)
9080 {
9081 case xpath_type_number:
9082 return convert_number_to_boolean(eval_number(c, stack));
9083
9084 case xpath_type_string:
9085 {
9087
9088 return !eval_string(c, stack).empty();
9089 }
9090
9091 case xpath_type_node_set:
9092 {
9094
9095 return !eval_node_set(c, stack).empty();
9096 }
9097
9098 default:
9099 assert(!"Wrong expression for return type boolean");
9100 return false;
9101 }
9102 }
9103 }
9104 }
9105
9106 double eval_number(const xpath_context &c, const xpath_stack &stack)
9107 {
9108 switch (_type)
9109 {
9110 case ast_op_add:
9111 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
9112
9113 case ast_op_subtract:
9114 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
9115
9116 case ast_op_multiply:
9117 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
9118
9119 case ast_op_divide:
9120 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
9121
9122 case ast_op_mod:
9123 return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
9124
9125 case ast_op_negate:
9126 return -_left->eval_number(c, stack);
9127
9129 return _data.number;
9130
9131 case ast_func_last:
9132 return static_cast<double>(c.size);
9133
9134 case ast_func_position:
9135 return static_cast<double>(c.position);
9136
9137 case ast_func_count:
9138 {
9140
9141 return static_cast<double>(_left->eval_node_set(c, stack).size());
9142 }
9143
9145 {
9147
9148 return static_cast<double>(string_value(c.n, stack.result).length());
9149 }
9150
9152 {
9154
9155 return static_cast<double>(_left->eval_string(c, stack).length());
9156 }
9157
9158 case ast_func_number_0:
9159 {
9161
9163 }
9164
9165 case ast_func_number_1:
9166 return _left->eval_number(c, stack);
9167
9168 case ast_func_sum:
9169 {
9171
9172 double r = 0;
9173
9175
9176 for (const xpath_node *it = ns.begin(); it != ns.end(); ++it)
9177 {
9179
9181 }
9182
9183 return r;
9184 }
9185
9186 case ast_func_floor:
9187 {
9188 double r = _left->eval_number(c, stack);
9189
9190 return r == r ? floor(r) : r;
9191 }
9192
9193 case ast_func_ceiling:
9194 {
9195 double r = _left->eval_number(c, stack);
9196
9197 return r == r ? ceil(r) : r;
9198 }
9199
9200 case ast_func_round:
9201 return round_nearest_nzero(_left->eval_number(c, stack));
9202
9203 case ast_variable:
9204 {
9205 assert(_rettype == _data.variable->type());
9206
9207 if (_rettype == xpath_type_number)
9208 return _data.variable->get_number();
9209
9210 // fallthrough to type conversion
9211 }
9212
9213 default:
9214 {
9215 switch (_rettype)
9216 {
9217 case xpath_type_boolean:
9218 return eval_boolean(c, stack) ? 1 : 0;
9219
9220 case xpath_type_string:
9221 {
9223
9224 return convert_string_to_number(eval_string(c, stack).c_str());
9225 }
9226
9227 case xpath_type_node_set:
9228 {
9230
9231 return convert_string_to_number(eval_string(c, stack).c_str());
9232 }
9233
9234 default:
9235 assert(!"Wrong expression for return type number");
9236 return 0;
9237 }
9238 }
9239 }
9240 }
9241
9243 {
9244 assert(_type == ast_func_concat);
9245
9246 xpath_allocator_capture ct(stack.temp);
9247
9248 // count the string number
9249 size_t count = 1;
9250 for (xpath_ast_node *nc = _right; nc; nc = nc->_next)
9251 count++;
9252
9253 // gather all strings
9254 xpath_string static_buffer[4];
9255 xpath_string *buffer = static_buffer;
9256
9257 // allocate on-heap for large concats
9258 if (count > sizeof(static_buffer) / sizeof(static_buffer[0]))
9259 {
9260 buffer = static_cast<xpath_string *>(stack.temp->allocate(count * sizeof(xpath_string)));
9261 assert(buffer);
9262 }
9263
9264 // evaluate all strings to temporary stack
9265 xpath_stack swapped_stack = { stack.temp, stack.result };
9266
9267 buffer[0] = _left->eval_string(c, swapped_stack);
9268
9269 size_t pos = 1;
9270 for (xpath_ast_node *n = _right; n; n = n->_next, ++pos)
9271 buffer[pos] = n->eval_string(c, swapped_stack);
9272 assert(pos == count);
9273
9274 // get total length
9275 size_t length = 0;
9276 for (size_t i = 0; i < count; ++i)
9277 length += buffer[i].length();
9278
9279 // create final string
9280 char_t *result = static_cast<char_t *>(stack.result->allocate((length + 1) * sizeof(char_t)));
9281 assert(result);
9282
9283 char_t *ri = result;
9284
9285 for (size_t j = 0; j < count; ++j)
9286 for (const char_t *bi = buffer[j].c_str(); *bi; ++bi)
9287 *ri++ = *bi;
9288
9289 *ri = 0;
9290
9291 return xpath_string(result, true);
9292 }
9293
9295 {
9296 switch (_type)
9297 {
9299 return xpath_string_const(_data.string);
9300
9302 {
9303 xpath_node na = c.n;
9304
9305 return xpath_string_const(local_name(na));
9306 }
9307
9309 {
9311
9313 xpath_node na = ns.first();
9314
9315 return xpath_string_const(local_name(na));
9316 }
9317
9318 case ast_func_name_0:
9319 {
9320 xpath_node na = c.n;
9321
9323 }
9324
9325 case ast_func_name_1:
9326 {
9328
9330 xpath_node na = ns.first();
9331
9333 }
9334
9336 {
9337 xpath_node na = c.n;
9338
9340 }
9341
9343 {
9345
9347 xpath_node na = ns.first();
9348
9350 }
9351
9352 case ast_func_string_0:
9353 return string_value(c.n, stack.result);
9354
9355 case ast_func_string_1:
9356 return _left->eval_string(c, stack);
9357
9358 case ast_func_concat:
9359 return eval_string_concat(c, stack);
9360
9362 {
9363 xpath_allocator_capture cr(stack.temp);
9364
9365 xpath_stack swapped_stack = { stack.temp, stack.result };
9366
9367 xpath_string s = _left->eval_string(c, swapped_stack);
9368 xpath_string p = _right->eval_string(c, swapped_stack);
9369
9370 const char_t *pos = find_substring(s.c_str(), p.c_str());
9371
9372 return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string();
9373 }
9374
9376 {
9377 xpath_allocator_capture cr(stack.temp);
9378
9379 xpath_stack swapped_stack = { stack.temp, stack.result };
9380
9381 xpath_string s = _left->eval_string(c, swapped_stack);
9382 xpath_string p = _right->eval_string(c, swapped_stack);
9383
9384 const char_t *pos = find_substring(s.c_str(), p.c_str());
9385 if (!pos)
9386 return xpath_string();
9387
9388 const char_t *result = pos + p.length();
9389
9390 return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result);
9391 }
9392
9394 {
9395 xpath_allocator_capture cr(stack.temp);
9396
9397 xpath_stack swapped_stack = { stack.temp, stack.result };
9398
9399 xpath_string s = _left->eval_string(c, swapped_stack);
9400 size_t s_length = s.length();
9401
9402 double first = round_nearest(_right->eval_number(c, stack));
9403
9404 if (is_nan(first))
9405 return xpath_string(); // NaN
9406 else if (first >= s_length + 1)
9407 return xpath_string();
9408
9409 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
9410 assert(1 <= pos && pos <= s_length + 1);
9411
9412 const char_t *rbegin = s.c_str() + (pos - 1);
9413
9414 return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin);
9415 }
9416
9418 {
9419 xpath_allocator_capture cr(stack.temp);
9420
9421 xpath_stack swapped_stack = { stack.temp, stack.result };
9422
9423 xpath_string s = _left->eval_string(c, swapped_stack);
9424 size_t s_length = s.length();
9425
9426 double first = round_nearest(_right->eval_number(c, stack));
9427 double last = first + round_nearest(_right->_next->eval_number(c, stack));
9428
9429 if (is_nan(first) || is_nan(last))
9430 return xpath_string();
9431 else if (first >= s_length + 1)
9432 return xpath_string();
9433 else if (first >= last)
9434 return xpath_string();
9435 else if (last < 1)
9436 return xpath_string();
9437
9438 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
9439 size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last);
9440
9441 assert(1 <= pos && pos <= end && end <= s_length + 1);
9442 const char_t *rbegin = s.c_str() + (pos - 1);
9443 const char_t *rend = s.c_str() + (end - 1);
9444
9445 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin)
9446 : xpath_string(rbegin, rend, stack.result);
9447 }
9448
9450 {
9451 xpath_string s = string_value(c.n, stack.result);
9452
9453 normalize_space(s.data(stack.result));
9454
9455 return s;
9456 }
9457
9459 {
9460 xpath_string s = _left->eval_string(c, stack);
9461
9462 normalize_space(s.data(stack.result));
9463
9464 return s;
9465 }
9466
9467 case ast_func_translate:
9468 {
9469 xpath_allocator_capture cr(stack.temp);
9470
9471 xpath_stack swapped_stack = { stack.temp, stack.result };
9472
9473 xpath_string s = _left->eval_string(c, stack);
9474 xpath_string from = _right->eval_string(c, swapped_stack);
9475 xpath_string to = _right->_next->eval_string(c, swapped_stack);
9476
9477 translate(s.data(stack.result), from.c_str(), to.c_str());
9478
9479 return s;
9480 }
9481
9482 case ast_variable:
9483 {
9484 assert(_rettype == _data.variable->type());
9485
9486 if (_rettype == xpath_type_string)
9487 return xpath_string_const(_data.variable->get_string());
9488
9489 // fallthrough to type conversion
9490 }
9491
9492 default:
9493 {
9494 switch (_rettype)
9495 {
9496 case xpath_type_boolean:
9497 return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
9498
9499 case xpath_type_number:
9500 return convert_number_to_string(eval_number(c, stack), stack.result);
9501
9502 case xpath_type_node_set:
9503 {
9504 xpath_allocator_capture cr(stack.temp);
9505
9506 xpath_stack swapped_stack = { stack.temp, stack.result };
9507
9508 xpath_node_set_raw ns = eval_node_set(c, swapped_stack);
9509 return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
9510 }
9511
9512 default:
9513 assert(!"Wrong expression for return type string");
9514 return xpath_string();
9515 }
9516 }
9517 }
9518 }
9519
9521 {
9522 switch (_type)
9523 {
9524 case ast_op_union:
9525 {
9526 xpath_allocator_capture cr(stack.temp);
9527
9528 xpath_stack swapped_stack = { stack.temp, stack.result };
9529
9530 xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack);
9532
9533 // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
9534 rs.set_type(xpath_node_set::type_unsorted);
9535
9536 rs.append(ls.begin(), ls.end(), stack.result);
9537 rs.remove_duplicates();
9538
9539 return rs;
9540 }
9541
9542 case ast_filter:
9543 case ast_filter_posinv:
9544 {
9545 xpath_node_set_raw set = _left->eval_node_set(c, stack);
9546
9547 // either expression is a number or it contains position() call; sort by document order
9548 if (_type == ast_filter)
9549 set.sort_do();
9550
9551 apply_predicate(set, 0, _right, stack);
9552
9553 return set;
9554 }
9555
9556 case ast_func_id:
9557 return xpath_node_set_raw();
9558
9559 case ast_step:
9560 {
9561 switch (_axis)
9562 {
9563 case axis_ancestor:
9564 return step_do(c, stack, axis_to_type<axis_ancestor>());
9565
9568
9569 case axis_attribute:
9570 return step_do(c, stack, axis_to_type<axis_attribute>());
9571
9572 case axis_child:
9573 return step_do(c, stack, axis_to_type<axis_child>());
9574
9575 case axis_descendant:
9576 return step_do(c, stack, axis_to_type<axis_descendant>());
9577
9580
9581 case axis_following:
9582 return step_do(c, stack, axis_to_type<axis_following>());
9583
9586
9587 case axis_namespace:
9588 // namespaced axis is not supported
9589 return xpath_node_set_raw();
9590
9591 case axis_parent:
9592 return step_do(c, stack, axis_to_type<axis_parent>());
9593
9594 case axis_preceding:
9595 return step_do(c, stack, axis_to_type<axis_preceding>());
9596
9599
9600 case axis_self:
9601 return step_do(c, stack, axis_to_type<axis_self>());
9602
9603 default:
9604 assert(!"Unknown axis");
9605 return xpath_node_set_raw();
9606 }
9607 }
9608
9609 case ast_step_root:
9610 {
9611 assert(!_right); // root step can't have any predicates
9612
9614
9615 ns.set_type(xpath_node_set::type_sorted);
9616
9617 if (c.n.node())
9618 ns.push_back(c.n.node().root(), stack.result);
9619 else if (c.n.attribute())
9620 ns.push_back(c.n.parent().root(), stack.result);
9621
9622 return ns;
9623 }
9624
9625 case ast_variable:
9626 {
9627 assert(_rettype == _data.variable->type());
9628
9629 if (_rettype == xpath_type_node_set)
9630 {
9631 const xpath_node_set &s = _data.variable->get_node_set();
9632
9634
9635 ns.set_type(s.type());
9636 ns.append(s.begin(), s.end(), stack.result);
9637
9638 return ns;
9639 }
9640
9641 // fallthrough to type conversion
9642 }
9643
9644 default:
9645 assert(!"Wrong expression for return type node set");
9646 return xpath_node_set_raw();
9647 }
9648 }
9649
9651 {
9652 switch (_type)
9653 {
9654 case ast_func_position:
9655 return false;
9656
9659 case ast_variable:
9660 return true;
9661
9662 case ast_step:
9663 case ast_step_root:
9664 return true;
9665
9666 case ast_predicate:
9667 case ast_filter:
9668 case ast_filter_posinv:
9669 return true;
9670
9671 default:
9672 if (_left && !_left->is_posinv())
9673 return false;
9674
9675 for (xpath_ast_node *n = _right; n; n = n->_next)
9676 if (!n->is_posinv())
9677 return false;
9678
9679 return true;
9680 }
9681 }
9682
9683 xpath_value_type rettype() const { return static_cast<xpath_value_type>(_rettype); }
9684};
9685
9687{
9690
9691 const char_t *_query;
9692 xpath_variable_set *_variables;
9693
9694 xpath_parse_result *_result;
9695
9696 char_t _scratch[32];
9697
9698#ifdef PUGIXML_NO_EXCEPTIONS
9699 jmp_buf _error_handler;
9700#endif
9701
9702 void throw_error(const char *message)
9703 {
9704 _result->error = message;
9705 _result->offset = _lexer.current_pos() - _query;
9706
9707#ifdef PUGIXML_NO_EXCEPTIONS
9708 longjmp(_error_handler, 1);
9709#else
9710 throw xpath_exception(*_result);
9711#endif
9712 }
9713
9715 {
9716#ifdef PUGIXML_NO_EXCEPTIONS
9717 throw_error("Out of memory");
9718#else
9719 throw std::bad_alloc();
9720#endif
9721 }
9722
9724 {
9725 void *result = _alloc->allocate_nothrow(sizeof(xpath_ast_node));
9726
9727 if (!result)
9729
9730 return result;
9731 }
9732
9733 const char_t *alloc_string(const xpath_lexer_string &value)
9734 {
9735 if (value.begin)
9736 {
9737 size_t length = static_cast<size_t>(value.end - value.begin);
9738
9739 char_t *c = static_cast<char_t *>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t)));
9740 if (!c)
9742 assert(c); // workaround for clang static analysis
9743
9744 memcpy(c, value.begin, length * sizeof(char_t));
9745 c[length] = 0;
9746
9747 return c;
9748 }
9749 else
9750 return 0;
9751 }
9752
9754 {
9755 assert(argc <= 1);
9756
9757 if (argc == 1 && args[0]->rettype() != xpath_type_node_set)
9758 throw_error("Function has to be applied to node set");
9759
9760 return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
9761 }
9762
9764 {
9765 switch (name.begin[0])
9766 {
9767 case 'b':
9768 if (name == PUGIXML_TEXT("boolean") && argc == 1)
9769 return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]);
9770
9771 break;
9772
9773 case 'c':
9774 if (name == PUGIXML_TEXT("count") && argc == 1)
9775 {
9776 if (args[0]->rettype() != xpath_type_node_set)
9777 throw_error("Function has to be applied to node set");
9778 return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]);
9779 }
9780 else if (name == PUGIXML_TEXT("contains") && argc == 2)
9781 return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]);
9782 else if (name == PUGIXML_TEXT("concat") && argc >= 2)
9783 return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]);
9784 else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
9785 return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]);
9786
9787 break;
9788
9789 case 'f':
9790 if (name == PUGIXML_TEXT("false") && argc == 0)
9791 return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean);
9792 else if (name == PUGIXML_TEXT("floor") && argc == 1)
9793 return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]);
9794
9795 break;
9796
9797 case 'i':
9798 if (name == PUGIXML_TEXT("id") && argc == 1)
9799 return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]);
9800
9801 break;
9802
9803 case 'l':
9804 if (name == PUGIXML_TEXT("last") && argc == 0)
9805 return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number);
9806 else if (name == PUGIXML_TEXT("lang") && argc == 1)
9807 return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]);
9808 else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
9810
9811 break;
9812
9813 case 'n':
9814 if (name == PUGIXML_TEXT("name") && argc <= 1)
9816 else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1)
9818 else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
9819 return new (alloc_node())
9821 xpath_type_string, args[0], args[1]);
9822 else if (name == PUGIXML_TEXT("not") && argc == 1)
9823 return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]);
9824 else if (name == PUGIXML_TEXT("number") && argc <= 1)
9825 return new (alloc_node())
9826 xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
9827
9828 break;
9829
9830 case 'p':
9831 if (name == PUGIXML_TEXT("position") && argc == 0)
9832 return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number);
9833
9834 break;
9835
9836 case 'r':
9837 if (name == PUGIXML_TEXT("round") && argc == 1)
9838 return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]);
9839
9840 break;
9841
9842 case 's':
9843 if (name == PUGIXML_TEXT("string") && argc <= 1)
9844 return new (alloc_node())
9845 xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
9846 else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
9847 return new (alloc_node()) xpath_ast_node(
9848 argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]);
9849 else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
9850 return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
9851 else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
9852 return new (alloc_node())
9853 xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
9854 else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
9855 return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
9856 else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
9858 xpath_type_string, args[0], args[1]);
9859 else if (name == PUGIXML_TEXT("sum") && argc == 1)
9860 {
9861 if (args[0]->rettype() != xpath_type_node_set)
9862 throw_error("Function has to be applied to node set");
9863 return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]);
9864 }
9865
9866 break;
9867
9868 case 't':
9869 if (name == PUGIXML_TEXT("translate") && argc == 3)
9870 return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]);
9871 else if (name == PUGIXML_TEXT("true") && argc == 0)
9872 return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean);
9873
9874 break;
9875
9876 default:
9877 break;
9878 }
9879
9880 throw_error("Unrecognized function or wrong parameter count");
9881
9882 return 0;
9883 }
9884
9885 axis_t parse_axis_name(const xpath_lexer_string &name, bool &specified)
9886 {
9887 specified = true;
9888
9889 switch (name.begin[0])
9890 {
9891 case 'a':
9892 if (name == PUGIXML_TEXT("ancestor"))
9893 return axis_ancestor;
9894 else if (name == PUGIXML_TEXT("ancestor-or-self"))
9895 return axis_ancestor_or_self;
9896 else if (name == PUGIXML_TEXT("attribute"))
9897 return axis_attribute;
9898
9899 break;
9900
9901 case 'c':
9902 if (name == PUGIXML_TEXT("child"))
9903 return axis_child;
9904
9905 break;
9906
9907 case 'd':
9908 if (name == PUGIXML_TEXT("descendant"))
9909 return axis_descendant;
9910 else if (name == PUGIXML_TEXT("descendant-or-self"))
9912
9913 break;
9914
9915 case 'f':
9916 if (name == PUGIXML_TEXT("following"))
9917 return axis_following;
9918 else if (name == PUGIXML_TEXT("following-sibling"))
9920
9921 break;
9922
9923 case 'n':
9924 if (name == PUGIXML_TEXT("namespace"))
9925 return axis_namespace;
9926
9927 break;
9928
9929 case 'p':
9930 if (name == PUGIXML_TEXT("parent"))
9931 return axis_parent;
9932 else if (name == PUGIXML_TEXT("preceding"))
9933 return axis_preceding;
9934 else if (name == PUGIXML_TEXT("preceding-sibling"))
9936
9937 break;
9938
9939 case 's':
9940 if (name == PUGIXML_TEXT("self"))
9941 return axis_self;
9942
9943 break;
9944
9945 default:
9946 break;
9947 }
9948
9949 specified = false;
9950 return axis_child;
9951 }
9952
9954 {
9955 switch (name.begin[0])
9956 {
9957 case 'c':
9958 if (name == PUGIXML_TEXT("comment"))
9959 return nodetest_type_comment;
9960
9961 break;
9962
9963 case 'n':
9964 if (name == PUGIXML_TEXT("node"))
9965 return nodetest_type_node;
9966
9967 break;
9968
9969 case 'p':
9970 if (name == PUGIXML_TEXT("processing-instruction"))
9971 return nodetest_type_pi;
9972
9973 break;
9974
9975 case 't':
9976 if (name == PUGIXML_TEXT("text"))
9977 return nodetest_type_text;
9978
9979 break;
9980
9981 default:
9982 break;
9983 }
9984
9985 return nodetest_none;
9986 }
9987
9988 // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
9990 {
9991 switch (_lexer.current())
9992 {
9993 case lex_var_ref:
9994 {
9996
9997 if (!_variables)
9998 throw_error("Unknown variable: variable set is not provided");
9999
10001
10002 if (!var)
10003 throw_error("Unknown variable: variable set does not contain the given name");
10004
10005 _lexer.next();
10006
10007 return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
10008 }
10009
10010 case lex_open_brace:
10011 {
10012 _lexer.next();
10013
10015
10017 throw_error("Unmatched braces");
10018
10019 _lexer.next();
10020
10021 return n;
10022 }
10023
10024 case lex_quoted_string:
10025 {
10026 const char_t *value = alloc_string(_lexer.contents());
10027
10028 xpath_ast_node *n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value);
10029 _lexer.next();
10030
10031 return n;
10032 }
10033
10034 case lex_number:
10035 {
10036 double value = 0;
10037
10040
10041 xpath_ast_node *n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value);
10042 _lexer.next();
10043
10044 return n;
10045 }
10046
10047 case lex_string:
10048 {
10049 xpath_ast_node *args[2] = { 0 };
10050 size_t argc = 0;
10051
10052 xpath_lexer_string function = _lexer.contents();
10053 _lexer.next();
10054
10055 xpath_ast_node *last_arg = 0;
10056
10057 if (_lexer.current() != lex_open_brace)
10058 throw_error("Unrecognized function call");
10059 _lexer.next();
10060
10062 args[argc++] = parse_expression();
10063
10064 while (_lexer.current() != lex_close_brace)
10065 {
10066 if (_lexer.current() != lex_comma)
10067 throw_error("No comma between function arguments");
10068 _lexer.next();
10069
10071
10072 if (argc < 2)
10073 args[argc] = n;
10074 else
10075 last_arg->set_next(n);
10076
10077 argc++;
10078 last_arg = n;
10079 }
10080
10081 _lexer.next();
10082
10083 return parse_function(function, argc, args);
10084 }
10085
10086 default:
10087 throw_error("Unrecognizable primary expression");
10088
10089 return 0;
10090 }
10091 }
10092
10093 // FilterExpr ::= PrimaryExpr | FilterExpr Predicate
10094 // Predicate ::= '[' PredicateExpr ']'
10095 // PredicateExpr ::= Expr
10097 {
10099
10101 {
10102 _lexer.next();
10103
10105
10106 if (n->rettype() != xpath_type_node_set)
10107 throw_error("Predicate has to be applied to node set");
10108
10109 bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv();
10110
10111 n = new (alloc_node())
10112 xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr);
10113
10115 throw_error("Unmatched square brace");
10116
10117 _lexer.next();
10118 }
10119
10120 return n;
10121 }
10122
10123 // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
10124 // AxisSpecifier ::= AxisName '::' | '@'?
10125 // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
10126 // NameTest ::= '*' | NCName ':' '*' | QName
10127 // AbbreviatedStep ::= '.' | '..'
10129 {
10130 if (set && set->rettype() != xpath_type_node_set)
10131 throw_error("Step has to be applied to node set");
10132
10133 bool axis_specified = false;
10134 axis_t axis = axis_child; // implied child axis
10135
10137 {
10138 axis = axis_attribute;
10139 axis_specified = true;
10140
10141 _lexer.next();
10142 }
10143 else if (_lexer.current() == lex_dot)
10144 {
10145 _lexer.next();
10146
10148 }
10149 else if (_lexer.current() == lex_double_dot)
10150 {
10151 _lexer.next();
10152
10154 }
10155
10156 nodetest_t nt_type = nodetest_none;
10157 xpath_lexer_string nt_name;
10158
10159 if (_lexer.current() == lex_string)
10160 {
10161 // node name test
10162 nt_name = _lexer.contents();
10163 _lexer.next();
10164
10165 // was it an axis name?
10167 {
10168 // parse axis name
10169 if (axis_specified)
10170 throw_error("Two axis specifiers in one step");
10171
10172 axis = parse_axis_name(nt_name, axis_specified);
10173
10174 if (!axis_specified)
10175 throw_error("Unknown axis");
10176
10177 // read actual node test
10178 _lexer.next();
10179
10180 if (_lexer.current() == lex_multiply)
10181 {
10182 nt_type = nodetest_all;
10183 nt_name = xpath_lexer_string();
10184 _lexer.next();
10185 }
10186 else if (_lexer.current() == lex_string)
10187 {
10188 nt_name = _lexer.contents();
10189 _lexer.next();
10190 }
10191 else
10192 throw_error("Unrecognized node test");
10193 }
10194
10195 if (nt_type == nodetest_none)
10196 {
10197 // node type test or processing-instruction
10198 if (_lexer.current() == lex_open_brace)
10199 {
10200 _lexer.next();
10201
10203 {
10204 _lexer.next();
10205
10206 nt_type = parse_node_test_type(nt_name);
10207
10208 if (nt_type == nodetest_none)
10209 throw_error("Unrecognized node type");
10210
10211 nt_name = xpath_lexer_string();
10212 }
10213 else if (nt_name == PUGIXML_TEXT("processing-instruction"))
10214 {
10216 throw_error("Only literals are allowed as arguments to processing-instruction()");
10217
10218 nt_type = nodetest_pi;
10219 nt_name = _lexer.contents();
10220 _lexer.next();
10221
10223 throw_error("Unmatched brace near processing-instruction()");
10224 _lexer.next();
10225 }
10226 else
10227 throw_error("Unmatched brace near node type test");
10228 }
10229 // QName or NCName:*
10230 else
10231 {
10232 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:*
10233 {
10234 nt_name.end--; // erase *
10235
10236 nt_type = nodetest_all_in_namespace;
10237 }
10238 else
10239 nt_type = nodetest_name;
10240 }
10241 }
10242 }
10243 else if (_lexer.current() == lex_multiply)
10244 {
10245 nt_type = nodetest_all;
10246 _lexer.next();
10247 }
10248 else
10249 throw_error("Unrecognized node test");
10250
10251 xpath_ast_node *n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name));
10252
10253 xpath_ast_node *last = 0;
10254
10256 {
10257 _lexer.next();
10258
10260
10261 xpath_ast_node *pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr);
10262
10264 throw_error("Unmatched square brace");
10265 _lexer.next();
10266
10267 if (last)
10268 last->set_next(pred);
10269 else
10270 n->set_right(pred);
10271
10272 last = pred;
10273 }
10274
10275 return n;
10276 }
10277
10278 // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
10280 {
10281 xpath_ast_node *n = parse_step(set);
10282
10284 {
10285 lexeme_t l = _lexer.current();
10286 _lexer.next();
10287
10288 if (l == lex_double_slash)
10290
10291 n = parse_step(n);
10292 }
10293
10294 return n;
10295 }
10296
10297 // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
10298 // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
10300 {
10301 if (_lexer.current() == lex_slash)
10302 {
10303 _lexer.next();
10304
10305 xpath_ast_node *n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
10306
10307 // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any
10308 // other lexeme means standalone root path
10309 lexeme_t l = _lexer.current();
10310
10311 if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
10313 else
10314 return n;
10315 }
10316 else if (_lexer.current() == lex_double_slash)
10317 {
10318 _lexer.next();
10319
10320 xpath_ast_node *n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
10322
10324 }
10325
10326 // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being
10327 // inlined' in gcc 4.0.1
10329 }
10330
10331 // PathExpr ::= LocationPath
10332 // | FilterExpr
10333 // | FilterExpr '/' RelativeLocationPath
10334 // | FilterExpr '//' RelativeLocationPath
10335 // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
10336 // UnaryExpr ::= UnionExpr | '-' UnaryExpr
10338 {
10339 // Clarification.
10340 // PathExpr begins with either LocationPath or FilterExpr.
10341 // FilterExpr begins with PrimaryExpr
10342 // PrimaryExpr begins with '$' in case of it being a variable reference,
10343 // '(' in case of it being an expression, string literal, number constant or
10344 // function call.
10345
10348 {
10349 if (_lexer.current() == lex_string)
10350 {
10351 // This is either a function call, or not - if not, we shall proceed with location path
10352 const char_t *state = _lexer.state();
10353
10354 while (PUGI__IS_CHARTYPE(*state, ct_space))
10355 ++state;
10356
10357 if (*state != '(')
10358 return parse_location_path();
10359
10360 // This looks like a function call; however this still can be a node-test. Check it.
10362 return parse_location_path();
10363 }
10364
10366
10368 {
10369 lexeme_t l = _lexer.current();
10370 _lexer.next();
10371
10372 if (l == lex_double_slash)
10373 {
10374 if (n->rettype() != xpath_type_node_set)
10375 throw_error("Step has to be applied to node set");
10376
10378 }
10379
10380 // select from location path
10382 }
10383
10384 return n;
10385 }
10386 else if (_lexer.current() == lex_minus)
10387 {
10388 _lexer.next();
10389
10390 // precedence 7+ - only parses union expressions
10392
10393 return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr);
10394 }
10395 else
10396 return parse_location_path();
10397 }
10398
10400 {
10402 xpath_value_type rettype;
10404
10405 binary_op_t() : asttype(ast_unknown), rettype(xpath_type_none), precedence(0) {}
10406
10407 binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_)
10408 : asttype(asttype_), rettype(rettype_), precedence(precedence_)
10409 {
10410 }
10411
10413 {
10414 switch (lexer.current())
10415 {
10416 case lex_string:
10417 if (lexer.contents() == PUGIXML_TEXT("or"))
10418 return binary_op_t(ast_op_or, xpath_type_boolean, 1);
10419 else if (lexer.contents() == PUGIXML_TEXT("and"))
10420 return binary_op_t(ast_op_and, xpath_type_boolean, 2);
10421 else if (lexer.contents() == PUGIXML_TEXT("div"))
10422 return binary_op_t(ast_op_divide, xpath_type_number, 6);
10423 else if (lexer.contents() == PUGIXML_TEXT("mod"))
10424 return binary_op_t(ast_op_mod, xpath_type_number, 6);
10425 else
10426 return binary_op_t();
10427
10428 case lex_equal:
10429 return binary_op_t(ast_op_equal, xpath_type_boolean, 3);
10430
10431 case lex_not_equal:
10432 return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3);
10433
10434 case lex_less:
10435 return binary_op_t(ast_op_less, xpath_type_boolean, 4);
10436
10437 case lex_greater:
10438 return binary_op_t(ast_op_greater, xpath_type_boolean, 4);
10439
10440 case lex_less_or_equal:
10441 return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4);
10442
10444 return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4);
10445
10446 case lex_plus:
10447 return binary_op_t(ast_op_add, xpath_type_number, 5);
10448
10449 case lex_minus:
10450 return binary_op_t(ast_op_subtract, xpath_type_number, 5);
10451
10452 case lex_multiply:
10453 return binary_op_t(ast_op_multiply, xpath_type_number, 6);
10454
10455 case lex_union:
10456 return binary_op_t(ast_op_union, xpath_type_node_set, 7);
10457
10458 default:
10459 return binary_op_t();
10460 }
10461 }
10462 };
10463
10465 {
10467
10468 while (op.asttype != ast_unknown && op.precedence >= limit)
10469 {
10470 _lexer.next();
10471
10473
10475
10476 while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)
10477 {
10478 rhs = parse_expression_rec(rhs, nextop.precedence);
10479
10480 nextop = binary_op_t::parse(_lexer);
10481 }
10482
10483 if (op.asttype == ast_op_union &&
10484 (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))
10485 throw_error("Union operator has to be applied to node sets");
10486
10487 lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs);
10488
10490 }
10491
10492 return lhs;
10493 }
10494
10495 // Expr ::= OrExpr
10496 // OrExpr ::= AndExpr | OrExpr 'or' AndExpr
10497 // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
10498 // EqualityExpr ::= RelationalExpr
10499 // | EqualityExpr '=' RelationalExpr
10500 // | EqualityExpr '!=' RelationalExpr
10501 // RelationalExpr ::= AdditiveExpr
10502 // | RelationalExpr '<' AdditiveExpr
10503 // | RelationalExpr '>' AdditiveExpr
10504 // | RelationalExpr '<=' AdditiveExpr
10505 // | RelationalExpr '>=' AdditiveExpr
10506 // AdditiveExpr ::= MultiplicativeExpr
10507 // | AdditiveExpr '+' MultiplicativeExpr
10508 // | AdditiveExpr '-' MultiplicativeExpr
10509 // MultiplicativeExpr ::= UnaryExpr
10510 // | MultiplicativeExpr '*' UnaryExpr
10511 // | MultiplicativeExpr 'div' UnaryExpr
10512 // | MultiplicativeExpr 'mod' UnaryExpr
10514
10515 xpath_parser(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
10516 : _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result)
10517 {
10518 }
10519
10521 {
10522 xpath_ast_node *result = parse_expression();
10523
10524 if (_lexer.current() != lex_eof)
10525 {
10526 // there are still unparsed tokens left, error
10527 throw_error("Incorrect query");
10528 }
10529
10530 return result;
10531 }
10532
10533 static xpath_ast_node *parse(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc,
10534 xpath_parse_result *result)
10535 {
10536 xpath_parser parser(query, variables, alloc, result);
10537
10538#ifdef PUGIXML_NO_EXCEPTIONS
10539 int error = setjmp(parser._error_handler);
10540
10541 return (error == 0) ? parser.parse() : 0;
10542#else
10543 return parser.parse();
10544#endif
10545 }
10546};
10547
10549{
10551 {
10552 void *memory = xml_memory::allocate(sizeof(xpath_query_impl));
10553
10554 return new (memory) xpath_query_impl();
10555 }
10556
10557 static void destroy(void *ptr)
10558 {
10559 if (!ptr)
10560 return;
10561
10562 // free all allocated pages
10563 static_cast<xpath_query_impl *>(ptr)->alloc.release();
10564
10565 // free allocator memory (with the first page)
10567 }
10568
10570
10574};
10575
10577{
10578 if (!impl)
10579 return xpath_string();
10580
10581#ifdef PUGIXML_NO_EXCEPTIONS
10582 if (setjmp(sd.error_handler))
10583 return xpath_string();
10584#endif
10585
10586 xpath_context c(n, 1, 1);
10587
10588 return impl->root->eval_string(c, sd.stack);
10589}
10591
10592namespace pugi
10593{
10594#ifndef PUGIXML_NO_EXCEPTIONS
10596{
10597 assert(_result.error);
10598}
10599
10600PUGI__FN const char *xpath_exception::what() const throw()
10601{
10602 return _result.error;
10603}
10604
10606{
10607 return _result;
10608}
10609#endif
10610
10612
10613PUGI__FN xpath_node::xpath_node(const xml_node &node_) : _node(node_) {}
10614
10615PUGI__FN xpath_node::xpath_node(const xml_attribute &attribute_, const xml_node &parent_)
10616 : _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
10617{
10618}
10619
10621{
10622 return _attribute ? xml_node() : _node;
10623}
10624
10626{
10627 return _attribute;
10628}
10629
10631{
10632 return _attribute ? _node : _node.parent();
10633}
10634
10636
10638{
10640}
10641
10643{
10644 return !(_node || _attribute);
10645}
10646
10648{
10649 return _node == n._node && _attribute == n._attribute;
10650}
10651
10653{
10654 return _node != n._node || _attribute != n._attribute;
10655}
10656
10657#ifdef __BORLANDC__
10658PUGI__FN bool operator&&(const xpath_node &lhs, bool rhs)
10659{
10660 return (bool)lhs && rhs;
10661}
10662
10663PUGI__FN bool operator||(const xpath_node &lhs, bool rhs)
10664{
10665 return (bool)lhs || rhs;
10666}
10667#endif
10668
10670{
10671 assert(begin_ <= end_);
10672
10673 size_t size_ = static_cast<size_t>(end_ - begin_);
10674
10675 if (size_ <= 1)
10676 {
10677 // deallocate old buffer
10678 if (_begin != &_storage)
10679 impl::xml_memory::deallocate(_begin);
10680
10681 // use internal buffer
10682 if (begin_ != end_)
10683 _storage = *begin_;
10684
10685 _begin = &_storage;
10686 _end = &_storage + size_;
10687 }
10688 else
10689 {
10690 // make heap copy
10691 xpath_node *storage = static_cast<xpath_node *>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
10692
10693 if (!storage)
10694 {
10695#ifdef PUGIXML_NO_EXCEPTIONS
10696 return;
10697#else
10698 throw std::bad_alloc();
10699#endif
10700 }
10701
10702 memcpy(storage, begin_, size_ * sizeof(xpath_node));
10703
10704 // deallocate old buffer
10705 if (_begin != &_storage)
10706 impl::xml_memory::deallocate(_begin);
10707
10708 // finalize
10709 _begin = storage;
10710 _end = storage + size_;
10711 }
10712}
10713
10714PUGI__FN xpath_node_set::xpath_node_set() : _type(type_unsorted), _begin(&_storage), _end(&_storage) {}
10715
10717 : _type(type_), _begin(&_storage), _end(&_storage)
10718{
10719 _assign(begin_, end_);
10720}
10721
10723{
10724 if (_begin != &_storage)
10725 impl::xml_memory::deallocate(_begin);
10726}
10727
10728PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set &ns) : _type(ns._type), _begin(&_storage), _end(&_storage)
10729{
10730 _assign(ns._begin, ns._end);
10731}
10732
10734{
10735 if (this == &ns)
10736 return *this;
10737
10738 _type = ns._type;
10739 _assign(ns._begin, ns._end);
10740
10741 return *this;
10742}
10743
10745{
10746 return _type;
10747}
10748
10750{
10751 return _end - _begin;
10752}
10753
10755{
10756 return _begin == _end;
10757}
10758
10760{
10761 assert(index < size());
10762 return _begin[index];
10763}
10764
10769
10774
10776{
10777 _type = impl::xpath_sort(_begin, _end, _type, reverse);
10778}
10779
10781{
10782 return impl::xpath_first(_begin, _end, _type);
10783}
10784
10785PUGI__FN xpath_parse_result::xpath_parse_result() : error("Internal error"), offset(0) {}
10786
10787PUGI__FN xpath_parse_result::operator bool() const
10788{
10789 return error == 0;
10790}
10791
10793{
10794 return error ? error : "No error";
10795}
10796
10798
10800{
10801 switch (_type)
10802 {
10804 return static_cast<const impl::xpath_variable_node_set *>(this)->name;
10805
10806 case xpath_type_number:
10807 return static_cast<const impl::xpath_variable_number *>(this)->name;
10808
10809 case xpath_type_string:
10810 return static_cast<const impl::xpath_variable_string *>(this)->name;
10811
10812 case xpath_type_boolean:
10813 return static_cast<const impl::xpath_variable_boolean *>(this)->name;
10814
10815 default:
10816 assert(!"Invalid variable type");
10817 return 0;
10818 }
10819}
10820
10822{
10823 return _type;
10824}
10825
10827{
10828 return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean *>(this)->value : false;
10829}
10830
10832{
10833 return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number *>(this)->value
10834 : impl::gen_nan();
10835}
10836
10838{
10839 const char_t *value =
10840 (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string *>(this)->value : 0;
10841 return value ? value : PUGIXML_TEXT("");
10842}
10843
10845{
10846 return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set *>(this)->value
10847 : impl::dummy_node_set;
10848}
10849
10851{
10853 return false;
10854
10855 static_cast<impl::xpath_variable_boolean *>(this)->value = value;
10856 return true;
10857}
10858
10860{
10861 if (_type != xpath_type_number)
10862 return false;
10863
10864 static_cast<impl::xpath_variable_number *>(this)->value = value;
10865 return true;
10866}
10867
10869{
10870 if (_type != xpath_type_string)
10871 return false;
10872
10873 impl::xpath_variable_string *var = static_cast<impl::xpath_variable_string *>(this);
10874
10875 // duplicate string
10876 size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
10877
10878 char_t *copy = static_cast<char_t *>(impl::xml_memory::allocate(size));
10879 if (!copy)
10880 return false;
10881
10882 memcpy(copy, value, size);
10883
10884 // replace old string
10885 if (var->value)
10886 impl::xml_memory::deallocate(var->value);
10887 var->value = copy;
10888
10889 return true;
10890}
10891
10893{
10895 return false;
10896
10897 static_cast<impl::xpath_variable_node_set *>(this)->value = value;
10898 return true;
10899}
10900
10902{
10903 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
10904 _data[i] = 0;
10905}
10906
10908{
10909 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
10910 {
10911 xpath_variable *var = _data[i];
10912
10913 while (var)
10914 {
10915 xpath_variable *next = var->_next;
10916
10917 impl::delete_xpath_variable(var->_type, var);
10918
10919 var = next;
10920 }
10921 }
10922}
10923
10925{
10926 const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
10927 size_t hash = impl::hash_string(name) % hash_size;
10928
10929 // look for existing variable
10930 for (xpath_variable *var = _data[hash]; var; var = var->_next)
10931 if (impl::strequal(var->name(), name))
10932 return var;
10933
10934 return 0;
10935}
10936
10938{
10939 const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
10940 size_t hash = impl::hash_string(name) % hash_size;
10941
10942 // look for existing variable
10943 for (xpath_variable *var = _data[hash]; var; var = var->_next)
10944 if (impl::strequal(var->name(), name))
10945 return var->type() == type ? var : 0;
10946
10947 // add new variable
10948 xpath_variable *result = impl::new_xpath_variable(type, name);
10949
10950 if (result)
10951 {
10952 result->_type = type;
10953 result->_next = _data[hash];
10954
10955 _data[hash] = result;
10956 }
10957
10958 return result;
10959}
10960
10961PUGI__FN bool xpath_variable_set::set(const char_t *name, bool value)
10962{
10964 return var ? var->set(value) : false;
10965}
10966
10967PUGI__FN bool xpath_variable_set::set(const char_t *name, double value)
10968{
10969 xpath_variable *var = add(name, xpath_type_number);
10970 return var ? var->set(value) : false;
10971}
10972
10973PUGI__FN bool xpath_variable_set::set(const char_t *name, const char_t *value)
10974{
10975 xpath_variable *var = add(name, xpath_type_string);
10976 return var ? var->set(value) : false;
10977}
10978
10980{
10982 return var ? var->set(value) : false;
10983}
10984
10986{
10987 return find(name);
10988}
10989
10991{
10992 return find(name);
10993}
10994
10996{
10997 impl::xpath_query_impl *qimpl = impl::xpath_query_impl::create();
10998
10999 if (!qimpl)
11000 {
11001#ifdef PUGIXML_NO_EXCEPTIONS
11002 _result.error = "Out of memory";
11003#else
11004 throw std::bad_alloc();
11005#endif
11006 }
11007 else
11008 {
11009 impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy);
11010
11011 qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
11012
11013 if (qimpl->root)
11014 {
11015 _impl = static_cast<impl::xpath_query_impl *>(impl_holder.release());
11016 _result.error = 0;
11017 }
11018 }
11019}
11020
11022{
11023 impl::xpath_query_impl::destroy(_impl);
11024}
11025
11027{
11028 if (!_impl)
11029 return xpath_type_none;
11030
11031 return static_cast<impl::xpath_query_impl *>(_impl)->root->rettype();
11032}
11033
11035{
11036 if (!_impl)
11037 return false;
11038
11039 impl::xpath_context c(n, 1, 1);
11040 impl::xpath_stack_data sd;
11041
11042#ifdef PUGIXML_NO_EXCEPTIONS
11043 if (setjmp(sd.error_handler))
11044 return false;
11045#endif
11046
11047 return static_cast<impl::xpath_query_impl *>(_impl)->root->eval_boolean(c, sd.stack);
11048}
11049
11051{
11052 if (!_impl)
11053 return impl::gen_nan();
11054
11055 impl::xpath_context c(n, 1, 1);
11056 impl::xpath_stack_data sd;
11057
11058#ifdef PUGIXML_NO_EXCEPTIONS
11059 if (setjmp(sd.error_handler))
11060 return impl::gen_nan();
11061#endif
11062
11063 return static_cast<impl::xpath_query_impl *>(_impl)->root->eval_number(c, sd.stack);
11064}
11065
11066#ifndef PUGIXML_NO_STL
11068{
11069 impl::xpath_stack_data sd;
11070
11071 return impl::evaluate_string_impl(static_cast<impl::xpath_query_impl *>(_impl), n, sd).c_str();
11072}
11073#endif
11074
11075PUGI__FN size_t xpath_query::evaluate_string(char_t *buffer, size_t capacity, const xpath_node &n) const
11076{
11077 impl::xpath_stack_data sd;
11078
11079 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl *>(_impl), n, sd);
11080
11081 size_t full_size = r.length() + 1;
11082
11083 if (capacity > 0)
11084 {
11085 size_t size = (full_size < capacity) ? full_size : capacity;
11086 assert(size > 0);
11087
11088 memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
11089 buffer[size - 1] = 0;
11090 }
11091
11092 return full_size;
11093}
11094
11096{
11097 if (!_impl)
11098 return xpath_node_set();
11099
11100 impl::xpath_ast_node *root = static_cast<impl::xpath_query_impl *>(_impl)->root;
11101
11102 if (root->rettype() != xpath_type_node_set)
11103 {
11104#ifdef PUGIXML_NO_EXCEPTIONS
11105 return xpath_node_set();
11106#else
11108 res.error = "Expression does not evaluate to node set";
11109
11110 throw xpath_exception(res);
11111#endif
11112 }
11113
11114 impl::xpath_context c(n, 1, 1);
11115 impl::xpath_stack_data sd;
11116
11117#ifdef PUGIXML_NO_EXCEPTIONS
11118 if (setjmp(sd.error_handler))
11119 return xpath_node_set();
11120#endif
11121
11122 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack);
11123
11124 return xpath_node_set(r.begin(), r.end(), r.type());
11125}
11126
11128{
11129 return _result;
11130}
11131
11133
11135{
11137}
11138
11140{
11141 return !_impl;
11142}
11143
11145{
11146 xpath_query q(query, variables);
11147 return select_single_node(q);
11148}
11149
11151{
11152 xpath_node_set s = query.evaluate_node_set(*this);
11153 return s.empty() ? xpath_node() : s.first();
11154}
11155
11157{
11158 xpath_query q(query, variables);
11159 return select_nodes(q);
11160}
11161
11163{
11164 return query.evaluate_node_set(*this);
11165}
11166} // namespace pugi
11167
11168#endif
11169
11170#ifdef __BORLANDC__
11171#pragma option pop
11172#endif
11173
11174// Intel C++ does not properly keep warning state for function templates,
11175// so popping warning state at the end of translation unit leads to warnings in
11176// the middle.
11177#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
11178#pragma warning(pop)
11179#endif
11180
11181// Undefine all local macros (makes sure we're not leaking macros in header-only
11182// mode)
11183#undef PUGI__NO_INLINE
11184#undef PUGI__STATIC_ASSERT
11185#undef PUGI__DMC_VOLATILE
11186#undef PUGI__MSVC_CRT_VERSION
11187#undef PUGI__NS_BEGIN
11188#undef PUGI__NS_END
11189#undef PUGI__FN
11190#undef PUGI__FN_NO_INLINE
11191#undef PUGI__IS_CHARTYPE_IMPL
11192#undef PUGI__IS_CHARTYPE
11193#undef PUGI__IS_CHARTYPEX
11194#undef PUGI__SKIPWS
11195#undef PUGI__OPTSET
11196#undef PUGI__PUSHNODE
11197#undef PUGI__POPNODE
11198#undef PUGI__SCANFOR
11199#undef PUGI__SCANWHILE
11200#undef PUGI__ENDSEG
11201#undef PUGI__THROW_ERROR
11202#undef PUGI__CHECK_ERROR
11203
11204#endif
11205
ETISS_PLUGIN_EXPORT etiss::CPUArch std::map< std::string, std::string > options
create new instance of the CPUArch type at index
__DEVICE__ int fpclassify(float __x)
__DEVICE__ void * memcpy(void *__a, const void *__b, size_t __c)
__device__ __2f16 float c
__device__ float
__device__ __2f16 float bool s
do v
Definition arm_acle.h:76
static __inline__ uint32_t
Definition arm_cde.h:25
static __inline__ uint8_t
Definition arm_mve.h:323
static __inline__ uint16_t
Definition arm_mve.h:315
bool operator!=(const xml_attribute_iterator &rhs) const
Definition pugixml.cpp:5791
const xml_attribute_iterator & operator--()
Definition pugixml.cpp:5822
xml_attribute * operator->() const
Definition pugixml.cpp:5802
xml_attribute & operator*() const
Definition pugixml.cpp:5796
bool operator==(const xml_attribute_iterator &rhs) const
Definition pugixml.cpp:5786
const xml_attribute_iterator & operator++()
Definition pugixml.cpp:5808
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition pugixml.cpp:4388
bool operator>=(const xml_attribute &r) const
Definition pugixml.cpp:4373
bool as_bool(bool def=false) const
Definition pugixml.cpp:4413
bool operator!=(const xml_attribute &r) const
Definition pugixml.cpp:4353
bool operator<(const xml_attribute &r) const
Definition pugixml.cpp:4358
int as_int(int def=0) const
Definition pugixml.cpp:4393
float as_float(float def=0) const
Definition pugixml.cpp:4408
bool operator==(const xml_attribute &r) const
Definition pugixml.cpp:4348
bool empty() const
Definition pugixml.cpp:4430
size_t hash_value() const
Definition pugixml.cpp:4445
const char_t * name() const
Definition pugixml.cpp:4435
xml_attribute & operator=(const char_t *rhs)
Definition pugixml.cpp:4455
xml_attribute previous_attribute() const
Definition pugixml.cpp:4383
xml_attribute_struct * _attr
Definition pugixml.hpp:302
xml_attribute next_attribute() const
Definition pugixml.cpp:4378
bool operator!() const
Definition pugixml.cpp:4343
bool operator<=(const xml_attribute &r) const
Definition pugixml.cpp:4368
double as_double(double def=0) const
Definition pugixml.cpp:4403
void(* unspecified_bool_type)(xml_attribute ***)
Definition pugixml.hpp:304
bool set_name(const char_t *rhs)
Definition pugixml.cpp:4499
bool set_value(const char_t *rhs)
Definition pugixml.cpp:4507
unsigned int as_uint(unsigned int def=0) const
Definition pugixml.cpp:4398
xml_attribute_struct * internal_object() const
Definition pugixml.cpp:4450
bool operator>(const xml_attribute &r) const
Definition pugixml.cpp:4363
const char_t * value() const
Definition pugixml.cpp:4440
xml_parse_result load_buffer_inplace(void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition pugixml.cpp:6107
char _memory[192]
Definition pugixml.hpp:927
xml_node document_element() const
Definition pugixml.cpp:6186
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:6172
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:6116
xml_parse_result load_file(const char *path, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition pugixml.cpp:6080
xml_parse_result load_buffer(const void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition pugixml.cpp:6098
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:6051
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:6125
bool operator!=(const xml_named_node_iterator &rhs) const
Definition pugixml.cpp:5853
xml_node * operator->() const
Definition pugixml.cpp:5864
const xml_named_node_iterator & operator--()
Definition pugixml.cpp:5884
bool operator==(const xml_named_node_iterator &rhs) const
Definition pugixml.cpp:5848
xml_node & operator*() const
Definition pugixml.cpp:5858
const xml_named_node_iterator & operator++()
Definition pugixml.cpp:5870
bool operator==(const xml_node_iterator &rhs) const
Definition pugixml.cpp:5725
const xml_node_iterator & operator--()
Definition pugixml.cpp:5761
xml_node * operator->() const
Definition pugixml.cpp:5741
bool operator!=(const xml_node_iterator &rhs) const
Definition pugixml.cpp:5730
const xml_node_iterator & operator++()
Definition pugixml.cpp:5747
xml_node & operator*() const
Definition pugixml.cpp:5735
string_t path(char_t delimiter='/') const
Definition pugixml.cpp:5291
size_t hash_value() const
Definition pugixml.cpp:5413
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:4821
xml_node_type type() const
Definition pugixml.cpp:4669
xml_node append_child(xml_node_type type=node_element)
Definition pugixml.cpp:4983
xml_node child(const char_t *name) const
Definition pugixml.cpp:4679
friend class xml_named_node_iterator
Definition pugixml.hpp:400
xml_node last_child() const
Definition pugixml.cpp:4802
xml_node first_child() const
Definition pugixml.cpp:4797
bool operator>(const xml_node &r) const
Definition pugixml.cpp:4644
xml_object_range< xml_node_iterator > children() const
Definition pugixml.cpp:4613
xml_attribute append_attribute(const char_t *name)
Definition pugixml.cpp:4837
xml_node next_sibling() const
Definition pugixml.cpp:4715
xml_node_struct * internal_object() const
Definition pugixml.cpp:5418
xml_node_struct * _root
Definition pugixml.hpp:403
xml_object_range< xml_attribute_iterator > attributes() const
Definition pugixml.cpp:4624
xml_node parent() const
Definition pugixml.cpp:4749
bool remove_child(const xml_node &n)
Definition pugixml.cpp:5197
xml_attribute append_copy(const xml_attribute &proto)
Definition pugixml.cpp:4939
xml_node insert_child_after(xml_node_type type, const xml_node &node)
Definition pugixml.cpp:5054
xml_attribute last_attribute() const
Definition pugixml.cpp:4792
attribute_iterator attributes_end() const
Definition pugixml.cpp:4608
xml_node previous_sibling() const
Definition pugixml.cpp:4738
ptrdiff_t offset_debug() const
Definition pugixml.cpp:5452
iterator end() const
Definition pugixml.cpp:4598
xml_text text() const
Definition pugixml.cpp:4765
xml_attribute insert_attribute_before(const char_t *name, const xml_attribute &attr)
Definition pugixml.cpp:4875
xml_attribute insert_attribute_after(const char_t *name, const xml_attribute &attr)
Definition pugixml.cpp:4907
bool operator!=(const xml_node &r) const
Definition pugixml.cpp:4634
bool operator<(const xml_node &r) const
Definition pugixml.cpp:4639
xml_attribute prepend_attribute(const char_t *name)
Definition pugixml.cpp:4848
xml_parse_result append_buffer(const void *contents, size_t size, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition pugixml.cpp:5217
const char_t * value() const
Definition pugixml.cpp:4674
void(* unspecified_bool_type)(xml_node ***)
Definition pugixml.hpp:405
xml_attribute_iterator attribute_iterator
Definition pugixml.hpp:610
bool traverse(xml_tree_walker &walker)
Definition pugixml.cpp:5365
xml_node find_child_by_attribute(const char_t *name, const char_t *attr_name, const char_t *attr_value) const
Definition pugixml.cpp:5258
const char_t * child_value() const
Definition pugixml.cpp:4770
bool set_name(const char_t *rhs)
Definition pugixml.cpp:4807
xml_node prepend_child(xml_node_type type=node_element)
Definition pugixml.cpp:4996
xml_attribute first_attribute() const
Definition pugixml.cpp:4787
bool operator!() const
Definition pugixml.cpp:4588
bool operator>=(const xml_node &r) const
Definition pugixml.cpp:4654
xml_attribute insert_copy_after(const xml_attribute &proto, const xml_attribute &attr)
Definition pugixml.cpp:4961
xml_attribute prepend_copy(const xml_attribute &proto)
Definition pugixml.cpp:4950
xml_node first_element_by_path(const char_t *path, char_t delimiter='/') const
Definition pugixml.cpp:5311
xml_attribute attribute(const char_t *name) const
Definition pugixml.cpp:4691
const char_t * name() const
Definition pugixml.cpp:4664
xml_attribute insert_copy_before(const xml_attribute &proto, const xml_attribute &attr)
Definition pugixml.cpp:4972
attribute_iterator attributes_begin() const
Definition pugixml.cpp:4603
xpath_node_set select_nodes(const char_t *query, xpath_variable_set *variables=0) const
xml_node_iterator iterator
Definition pugixml.hpp:604
bool operator<=(const xml_node &r) const
Definition pugixml.cpp:4649
iterator begin() const
Definition pugixml.cpp:4593
bool remove_attribute(const xml_attribute &a)
Definition pugixml.cpp:5163
xml_node root() const
Definition pugixml.cpp:4754
bool empty() const
Definition pugixml.cpp:4659
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:5423
xml_node insert_child_before(xml_node_type type, const xml_node &node)
Definition pugixml.cpp:5026
bool operator==(const xml_node &r) const
Definition pugixml.cpp:4629
const char_t * as_string(const char_t *def=PUGIXML_TEXT("")) const
Definition pugixml.cpp:5546
double as_double(double def=0) const
Definition pugixml.cpp:5567
xml_text & operator=(const char_t *rhs)
Definition pugixml.cpp:5655
bool operator!() const
Definition pugixml.cpp:5529
friend class xml_node
Definition pugixml.hpp:639
float as_float(float def=0) const
Definition pugixml.cpp:5574
xml_node_struct * _data_new()
Definition pugixml.cpp:5511
xml_node_struct * _root
Definition pugixml.hpp:641
bool as_bool(bool def=false) const
Definition pugixml.cpp:5581
xml_node data() const
Definition pugixml.cpp:5699
bool empty() const
Definition pugixml.cpp:5534
bool set(const char_t *rhs)
Definition pugixml.cpp:5604
int as_int(int def=0) const
Definition pugixml.cpp:5553
unsigned int as_uint(unsigned int def=0) const
Definition pugixml.cpp:5560
void(* unspecified_bool_type)(xml_text ***)
Definition pugixml.hpp:643
const char_t * get() const
Definition pugixml.cpp:5539
xml_node_struct * _data() const
Definition pugixml.cpp:5499
virtual bool end(xml_node &node)
Definition pugixml.cpp:4327
virtual bool for_each(xml_node &node)=0
virtual bool begin(xml_node &node)
Definition pugixml.cpp:4322
virtual ~xml_tree_walker()
Definition pugixml.cpp:4315
virtual void write(const void *data, size_t size)
Definition pugixml.cpp:4278
xml_writer_file(void *file)
Definition pugixml.cpp:4276
xml_writer_stream(std::basic_ostream< char, std::char_traits< char > > &stream)
Definition pugixml.cpp:4285
std::basic_ostream< wchar_t, std::char_traits< wchar_t > > * wide_stream
Definition pugixml.hpp:291
virtual void write(const void *data, size_t size)
Definition pugixml.cpp:4295
std::basic_ostream< char, std::char_traits< char > > * narrow_stream
Definition pugixml.hpp:290
virtual const char * what() const
const xpath_parse_result & result() const
xpath_exception(const xpath_parse_result &result)
xpath_parse_result _result
Definition pugixml.hpp:1150
type_t type() const
xpath_node_set & operator=(const xpath_node_set &ns)
void _assign(const_iterator begin, const_iterator end)
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:1260
xpath_node * _end
Definition pugixml.hpp:1261
void(* unspecified_bool_type)(xpath_node ***)
Definition pugixml.hpp:1171
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:1169
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:1093
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:1091
xpath_query(const xpath_query &)
const xpath_parse_result & result() const
bool evaluate_boolean(const xpath_node &n) const
xpath_variable * add(const char_t *name, xpath_value_type type)
xpath_variable * find(const char_t *name) const
bool set(const char_t *name, bool value)
xpath_variable * get(const char_t *name)
xpath_variable * _data[64]
Definition pugixml.hpp:1059
xpath_variable * _next
Definition pugixml.hpp:1027
bool set(bool value)
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:1026
void write(char_t d0)
Definition pugixml.cpp:3299
xml_writer & writer
Definition pugixml.cpp:3392
xml_buffered_writer(xml_writer &writer_, xml_encoding user_encoding)
Definition pugixml.cpp:3222
void write(char_t d0, char_t d1)
Definition pugixml.cpp:3308
xml_buffered_writer(const xml_buffered_writer &)
char_t data_char[bufcapacity]
Definition pugixml.cpp:3389
xml_buffered_writer & operator=(const xml_buffered_writer &)
char_t buffer[bufcapacity]
Definition pugixml.cpp:3383
void flush(const char_t *data, size_t size)
Definition pugixml.cpp:3236
uint16_t data_u16[2 *bufcapacity]
Definition pugixml.cpp:3387
union xml_buffered_writer::@9 scratch
void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
Definition pugixml.cpp:3341
xml_encoding encoding
Definition pugixml.cpp:3394
uint8_t data_u8[4 *bufcapacity]
Definition pugixml.cpp:3386
void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
Definition pugixml.cpp:3354
void write(const char_t *data)
Definition pugixml.cpp:3297
void write(char_t d0, char_t d1, char_t d2, char_t d3)
Definition pugixml.cpp:3329
void write(char_t d0, char_t d1, char_t d2)
Definition pugixml.cpp:3318
void write(const char_t *data, size_t length)
Definition pugixml.cpp:3256
uint32_t data_u32[bufcapacity]
Definition pugixml.cpp:3388
xpath_allocator(xpath_memory_block *root, size_t root_size=0)
Definition pugixml.cpp:6568
void * reallocate(void *ptr, size_t old_size, size_t new_size)
Definition pugixml.cpp:6623
void * allocate(size_t size)
Definition pugixml.cpp:6606
void * allocate_nothrow(size_t size)
Definition pugixml.cpp:6575
xpath_memory_block * _root
Definition pugixml.cpp:6560
void revert(const xpath_allocator &state)
Definition pugixml.cpp:6669
xpath_variable * variable
Definition pugixml.cpp:8297
xpath_ast_node * _next
Definition pugixml.cpp:8289
const char_t * string
Definition pugixml.cpp:8293
void set_next(xpath_ast_node *value)
Definition pugixml.cpp:8971
xpath_value_type rettype() const
Definition pugixml.cpp:9683
xpath_node_set_raw eval_node_set(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:9520
const char_t * nodetest
Definition pugixml.cpp:8299
xpath_string eval_string(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:9294
void step_push(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc)
Definition pugixml.cpp:8538
void step_fill(xpath_node_set_raw &ns, const xml_node &n, xpath_allocator *alloc, T)
Definition pugixml.cpp:8590
xpath_ast_node(ast_type_t type, xpath_ast_node *left, axis_t axis, nodetest_t test, const char_t *contents)
Definition pugixml.cpp:8959
xpath_node_set_raw step_do(const xpath_context &c, const xpath_stack &stack, T v)
Definition pugixml.cpp:8850
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable *value)
Definition pugixml.cpp:8935
double eval_number(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:9106
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:8306
void step_push(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &parent, xpath_allocator *alloc)
Definition pugixml.cpp:8505
void step_fill(xpath_node_set_raw &ns, const xml_attribute &a, const xml_node &p, xpath_allocator *alloc, T v)
Definition pugixml.cpp:8769
xpath_string eval_string_concat(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:9242
xpath_ast_node * _right
Definition pugixml.cpp:8288
bool eval_boolean(const xpath_context &c, const xpath_stack &stack)
Definition pugixml.cpp:8975
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:8396
xpath_ast_node & operator=(const xpath_ast_node &)
xpath_ast_node * _left
Definition pugixml.cpp:8287
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value)
Definition pugixml.cpp:8922
union xpath_ast_node::@10 _data
xpath_ast_node(const xpath_ast_node &)
void apply_predicates(xpath_node_set_raw &ns, size_t first, const xpath_stack &stack)
Definition pugixml.cpp:8494
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t *value)
Definition pugixml.cpp:8909
xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node *left=0, xpath_ast_node *right=0)
Definition pugixml.cpp:8948
void apply_predicate(xpath_node_set_raw &ns, size_t first, xpath_ast_node *expr, const xpath_stack &stack)
Definition pugixml.cpp:8468
void set_right(xpath_ast_node *value)
Definition pugixml.cpp:8973
const char_t * _cur_lexeme_pos
Definition pugixml.cpp:7872
const char_t * current_pos() const
Definition pugixml.cpp:8162
lexeme_t _cur_lexeme
Definition pugixml.cpp:7875
void next()
Definition pugixml.cpp:7882
lexeme_t current() const
Definition pugixml.cpp:8160
xpath_lexer_string _cur_lexeme_contents
Definition pugixml.cpp:7873
const xpath_lexer_string & contents() const
Definition pugixml.cpp:8164
xpath_lexer(const char_t *query)
Definition pugixml.cpp:7878
const char_t * state() const
Definition pugixml.cpp:7880
const char_t * _cur
Definition pugixml.cpp:7871
xpath_node_set::type_t _type
Definition pugixml.cpp:7726
void append(const xpath_node *begin_, const xpath_node *end_, xpath_allocator *alloc)
Definition pugixml.cpp:7768
size_t size() const
Definition pugixml.cpp:7741
xpath_node_set::type_t type() const
Definition pugixml.cpp:7808
xpath_node * end() const
Definition pugixml.cpp:7737
void push_back(const xpath_node &node, xpath_allocator *alloc)
Definition pugixml.cpp:7745
xpath_node * _eos
Definition pugixml.cpp:7730
xpath_node first() const
Definition pugixml.cpp:7743
xpath_node * _begin
Definition pugixml.cpp:7728
bool empty() const
Definition pugixml.cpp:7739
xpath_node * begin() const
Definition pugixml.cpp:7735
void truncate(xpath_node *pos)
Definition pugixml.cpp:7793
void set_type(xpath_node_set::type_t value)
Definition pugixml.cpp:7810
xpath_node * _end
Definition pugixml.cpp:7729
bool empty() const
Definition pugixml.cpp:6851
bool uses_heap() const
Definition pugixml.cpp:6857
static char_t * duplicate_string(const char_t *string, xpath_allocator *alloc)
Definition pugixml.cpp:6769
size_t length() const
Definition pugixml.cpp:6837
bool operator!=(const xpath_string &o) const
Definition pugixml.cpp:6855
void append(const xpath_string &o, xpath_allocator *alloc)
Definition pugixml.cpp:6797
xpath_string(const char_t *str, xpath_allocator *alloc)
Definition pugixml.cpp:6777
char_t * data(xpath_allocator *alloc)
Definition pugixml.cpp:6839
bool operator==(const xpath_string &o) const
Definition pugixml.cpp:6853
xpath_string(const char_t *begin, const char_t *end, xpath_allocator *alloc)
Definition pugixml.cpp:6787
const char_t * _buffer
Definition pugixml.cpp:6755
xpath_string(const char_t *str, bool use_heap)
Definition pugixml.cpp:6785
static char_t * duplicate_string(const char_t *string, size_t length, xpath_allocator *alloc)
Definition pugixml.cpp:6758
const char_t * c_str() const
Definition pugixml.cpp:6835
#define DBL_DIG
Definition float.h:95
xml_encoding
Definition pugixml.hpp:177
@ encoding_utf16_le
Definition pugixml.hpp:180
@ encoding_utf32_be
Definition pugixml.hpp:184
@ encoding_utf16_be
Definition pugixml.hpp:181
@ encoding_utf8
Definition pugixml.hpp:179
@ encoding_latin1
Definition pugixml.hpp:187
@ encoding_utf32_le
Definition pugixml.hpp:183
@ encoding_auto
Definition pugixml.hpp:178
@ encoding_wchar
Definition pugixml.hpp:186
std::basic_string< PUGIXML_CHAR, std::char_traits< PUGIXML_CHAR >, std::allocator< PUGIXML_CHAR > > string_t
Definition pugixml.hpp:95
const unsigned int format_no_declaration
Definition pugixml.hpp:202
xml_node_type
Definition pugixml.hpp:104
@ node_comment
Definition pugixml.hpp:110
@ node_pcdata
Definition pugixml.hpp:108
@ node_element
Definition pugixml.hpp:107
@ node_doctype
Definition pugixml.hpp:113
@ node_document
Definition pugixml.hpp:106
@ node_declaration
Definition pugixml.hpp:112
@ node_pi
Definition pugixml.hpp:111
@ node_null
Definition pugixml.hpp:105
@ node_cdata
Definition pugixml.hpp:109
const unsigned int format_raw
Definition pugixml.hpp:199
void(* deallocation_function)(void *ptr)
Definition pugixml.hpp:1281
std::basic_string< char, std::char_traits< char >, std::allocator< char > > PUGIXML_FUNCTION as_utf8(const wchar_t *str)
Definition pugixml.cpp:6198
static PUGI__FN void unspecified_bool_xpath_query(xpath_query ***)
static PUGI__FN void unspecified_bool_xml_node(xml_node ***)
Definition pugixml.cpp:4581
void *(* allocation_function)(size_t size)
Definition pugixml.hpp:1278
static PUGI__FN void unspecified_bool_xml_attribute(xml_attribute ***)
Definition pugixml.cpp:4336
@ status_append_invalid_root
Definition pugixml.hpp:894
@ status_end_element_mismatch
Definition pugixml.hpp:892
@ status_bad_end_element
Definition pugixml.hpp:891
@ status_io_error
Definition pugixml.hpp:878
@ status_bad_attribute
Definition pugixml.hpp:890
@ status_file_not_found
Definition pugixml.hpp:877
@ status_internal_error
Definition pugixml.hpp:880
@ status_bad_start_element
Definition pugixml.hpp:889
@ status_ok
Definition pugixml.hpp:875
@ status_bad_comment
Definition pugixml.hpp:885
@ status_bad_doctype
Definition pugixml.hpp:887
@ status_out_of_memory
Definition pugixml.hpp:879
@ status_unrecognized_tag
Definition pugixml.hpp:882
@ status_bad_cdata
Definition pugixml.hpp:886
@ status_bad_pcdata
Definition pugixml.hpp:888
@ status_bad_pi
Definition pugixml.hpp:884
@ status_no_document_element
Definition pugixml.hpp:896
void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
Definition pugixml.cpp:6223
deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
Definition pugixml.cpp:6235
std::basic_string< wchar_t, std::char_traits< wchar_t >, std::allocator< wchar_t > > PUGIXML_FUNCTION as_wide(const char *str)
Definition pugixml.cpp:6210
const unsigned int format_save_file_text
Definition pugixml.hpp:208
allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
Definition pugixml.cpp:6230
const unsigned int format_write_bom
Definition pugixml.hpp:196
static PUGI__FN void unspecified_bool_xpath_node(xpath_node ***)
static PUGI__FN void unspecified_bool_xml_text(xml_text ***)
Definition pugixml.cpp:5522
xpath_value_type
Definition pugixml.hpp:993
@ xpath_type_number
Definition pugixml.hpp:996
@ xpath_type_boolean
Definition pugixml.hpp:998
@ xpath_type_none
Definition pugixml.hpp:994
@ xpath_type_string
Definition pugixml.hpp:997
@ xpath_type_node_set
Definition pugixml.hpp:995
PUGIXML_CHAR char_t
Definition pugixml.hpp:91
STL namespace.
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...
__PTRDIFF_TYPE__ ptrdiff_t
A signed integer type that is the result of subtracting two pointers.
float __ovld __cnfn sign(float x)
Returns 1.0 if x > 0, -0.0 if x = -0.0, +0.0 if x = +0.0, or -1.0 if x < 0.
float __ovld __cnfn length(float p)
Return the length of vector p, i.e., sqrt(p.x2 + p.y 2 + ...)
float __ovld __cnfn step(float edge, float x)
Returns 0.0 if x < edge, otherwise it returns 1.0.
void destroy_node(xml_node_struct *n, xml_allocator &alloc)
Definition pugixml.cpp:629
#define PUGI__CHECK_ERROR(err, m)
Definition pugixml.cpp:2342
PUGI__FN void default_deallocate(void *ptr)
Definition pugixml.cpp:180
PUGI__FN size_t strlength_wide(const wchar_t *s)
Definition pugixml.cpp:237
#define PUGI__OPTSET(OPT)
Definition pugixml.cpp:2314
PUGI__FN double round_nearest_nzero(double value)
Definition pugixml.cpp:7383
PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t *data, size_t size)
Definition pugixml.cpp:1539
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:4236
PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl *impl, const xpath_node &n, xpath_stack_data &sd)
ast_type_t
Definition pugixml.cpp:8174
@ ast_op_and
Definition pugixml.cpp:8177
@ ast_number_constant
Definition pugixml.cpp:8195
@ ast_filter
Definition pugixml.cpp:8192
@ ast_func_substring_3
Definition pugixml.cpp:8215
@ ast_func_sum
Definition pugixml.cpp:8228
@ ast_func_name_1
Definition pugixml.cpp:8206
@ ast_func_floor
Definition pugixml.cpp:8229
@ ast_op_divide
Definition pugixml.cpp:8187
@ ast_func_concat
Definition pugixml.cpp:8209
@ ast_op_equal
Definition pugixml.cpp:8178
@ ast_unknown
Definition pugixml.cpp:8175
@ ast_func_name_0
Definition pugixml.cpp:8205
@ ast_predicate
Definition pugixml.cpp:8191
@ ast_filter_posinv
Definition pugixml.cpp:8193
@ ast_func_not
Definition pugixml.cpp:8222
@ ast_variable
Definition pugixml.cpp:8196
@ ast_func_string_1
Definition pugixml.cpp:8208
@ ast_func_string_0
Definition pugixml.cpp:8207
@ ast_func_number_0
Definition pugixml.cpp:8226
@ ast_op_union
Definition pugixml.cpp:8190
@ ast_func_substring_before
Definition pugixml.cpp:8212
@ ast_func_string_length_0
Definition pugixml.cpp:8216
@ ast_func_local_name_1
Definition pugixml.cpp:8202
@ ast_func_namespace_uri_0
Definition pugixml.cpp:8203
@ ast_func_lang
Definition pugixml.cpp:8225
@ ast_func_true
Definition pugixml.cpp:8223
@ ast_func_normalize_space_1
Definition pugixml.cpp:8219
@ ast_op_not_equal
Definition pugixml.cpp:8179
@ ast_func_contains
Definition pugixml.cpp:8211
@ ast_op_greater
Definition pugixml.cpp:8181
@ ast_op_negate
Definition pugixml.cpp:8189
@ ast_func_substring_2
Definition pugixml.cpp:8214
@ ast_func_position
Definition pugixml.cpp:8198
@ ast_string_constant
Definition pugixml.cpp:8194
@ ast_func_ceiling
Definition pugixml.cpp:8230
@ ast_op_subtract
Definition pugixml.cpp:8185
@ ast_func_last
Definition pugixml.cpp:8197
@ ast_func_normalize_space_0
Definition pugixml.cpp:8218
@ ast_func_boolean
Definition pugixml.cpp:8221
@ ast_op_less_or_equal
Definition pugixml.cpp:8182
@ ast_step
Definition pugixml.cpp:8232
@ ast_op_multiply
Definition pugixml.cpp:8186
@ ast_func_count
Definition pugixml.cpp:8199
@ ast_func_substring_after
Definition pugixml.cpp:8213
@ ast_func_namespace_uri_1
Definition pugixml.cpp:8204
@ ast_step_root
Definition pugixml.cpp:8233
@ ast_func_translate
Definition pugixml.cpp:8220
@ ast_func_round
Definition pugixml.cpp:8231
@ ast_func_number_1
Definition pugixml.cpp:8227
@ ast_func_string_length_1
Definition pugixml.cpp:8217
@ ast_func_starts_with
Definition pugixml.cpp:8210
@ ast_op_add
Definition pugixml.cpp:8184
@ ast_op_or
Definition pugixml.cpp:8176
@ ast_op_greater_or_equal
Definition pugixml.cpp:8183
@ ast_func_false
Definition pugixml.cpp:8224
@ ast_func_local_name_0
Definition pugixml.cpp:8201
@ ast_op_mod
Definition pugixml.cpp:8188
@ ast_func_id
Definition pugixml.cpp:8200
@ ast_op_less
Definition pugixml.cpp:8180
PUGI__FN xml_encoding get_write_native_encoding()
Definition pugixml.cpp:3038
PUGI__FN const char_t * qualified_name(const xpath_node &node)
Definition pugixml.cpp:7390
PUGI__FN bool convert_number_to_boolean(double value)
Definition pugixml.cpp:7169
char_t *(* strconv_attribute_t)(char_t *, char_t)
Definition pugixml.cpp:2082
PUGI__FN void as_utf8_end(char *buffer, size_t size, const wchar_t *str, size_t length)
Definition pugixml.cpp:1628
wchar_selector< sizeof(wchar_t)>::writer wchar_writer
Definition pugixml.cpp:927
PUGI__FN xml_encoding get_wchar_encoding()
Definition pugixml.cpp:1193
lexeme_t
Definition pugixml.cpp:7824
@ lex_multiply
Definition pugixml.cpp:7834
@ lex_double_slash
Definition pugixml.cpp:7842
@ lex_quoted_string
Definition pugixml.cpp:7839
@ lex_not_equal
Definition pugixml.cpp:7827
@ lex_axis_attribute
Definition pugixml.cpp:7847
@ lex_less
Definition pugixml.cpp:7828
@ lex_equal
Definition pugixml.cpp:7826
@ lex_greater_or_equal
Definition pugixml.cpp:7831
@ lex_none
Definition pugixml.cpp:7825
@ lex_union
Definition pugixml.cpp:7835
@ lex_comma
Definition pugixml.cpp:7846
@ lex_close_brace
Definition pugixml.cpp:7838
@ lex_slash
Definition pugixml.cpp:7841
@ lex_var_ref
Definition pugixml.cpp:7836
@ lex_dot
Definition pugixml.cpp:7848
@ lex_minus
Definition pugixml.cpp:7833
@ lex_string
Definition pugixml.cpp:7845
@ lex_eof
Definition pugixml.cpp:7851
@ lex_plus
Definition pugixml.cpp:7832
@ lex_number
Definition pugixml.cpp:7840
@ lex_greater
Definition pugixml.cpp:7829
@ lex_double_dot
Definition pugixml.cpp:7849
@ lex_less_or_equal
Definition pugixml.cpp:7830
@ lex_close_square_brace
Definition pugixml.cpp:7844
@ lex_open_square_brace
Definition pugixml.cpp:7843
@ lex_open_brace
Definition pugixml.cpp:7837
@ lex_double_colon
Definition pugixml.cpp:7850
PUGI__FN FILE * open_file_wide(const wchar_t *path, const wchar_t *mode)
Definition pugixml.cpp:4198
PUGI__FN void text_output_cdata(xml_buffered_writer &writer, const char_t *s)
Definition pugixml.cpp:3448
bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t *target)
Definition pugixml.cpp:1683
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:1270
static const uintptr_t xml_memory_page_type_mask
Definition pugixml.cpp:301
PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator *alloc)
Definition pugixml.cpp:7231
PUGI__FN bool is_little_endian()
Definition pugixml.cpp:1186
PUGI__FN unsigned int hash_string(const char_t *str)
Definition pugixml.cpp:7564
PUGI__FN size_t zero_terminate_buffer(void *buffer, size_t size, xml_encoding encoding)
Definition pugixml.cpp:3941
PUGI__FN char_t * strconv_comment(char_t *s, char_t endch)
Definition pugixml.cpp:1935
#define PUGI__IS_CHARTYPE(c, ct)
Definition pugixml.cpp:1183
PUGI__FN double gen_nan()
Definition pugixml.cpp:7103
PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
Definition pugixml.cpp:2248
PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
Definition pugixml.cpp:2054
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:1588
PUGI__FN void convert_utf_endian_swap(T *result, const T *data, size_t length)
Definition pugixml.cpp:1103
PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream< T > &stream, void **out_buffer, size_t *out_size)
Definition pugixml.cpp:4101
PUGI__FN xml_parse_result load_stream_impl(xml_document &doc, std::basic_istream< T > &stream, unsigned int options, xml_encoding encoding)
Definition pugixml.cpp:4143
PUGI__FN bool set_value_convert(char_t *&dest, uintptr_t &header, uintptr_t header_mask, int value)
Definition pugixml.cpp:3850
I min_element(I begin, I end, const Pred &pred)
Definition pugixml.cpp:6332
#define PUGI__ENDSEG()
Definition pugixml.cpp:2335
#define ENDSWITH(c, e)
Definition pugixml.cpp:1933
static const uintptr_t xml_memory_page_pointer_mask
Definition pugixml.cpp:298
PUGI__FN char_t * strconv_escape(char_t *s, gap &g)
Definition pugixml.cpp:1790
void sort(I begin, I end, const Pred &pred)
Definition pugixml.cpp:6511
void destroy_attribute(xml_attribute_struct *a, xml_allocator &alloc)
Definition pugixml.cpp:616
PUGI__FN bool convert_buffer_utf32(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
Definition pugixml.cpp:1513
wchar_selector< sizeof(wchar_t)>::counter wchar_counter
Definition pugixml.cpp:926
void median(I first, I middle, I last, const Pred &pred)
Definition pugixml.cpp:6491
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN bool starts_with(const char_t *string, const char_t *pattern)
Definition pugixml.cpp:6867
#define PUGI__IS_CHARTYPEX(c, ct)
Definition pugixml.cpp:1184
PUGI__FN_NO_INLINE xml_attribute_struct * append_attribute_ll(xml_node_struct *node, xml_allocator &alloc)
Definition pugixml.cpp:688
I unique(I begin, I end)
Definition pugixml.cpp:6351
bool has_declaration(const xml_node &node)
Definition pugixml.cpp:3625
void insertion_sort(I begin, I end, const Pred &pred, T *)
Definition pugixml.cpp:6384
static const unsigned char chartypex_table[256]
Definition pugixml.cpp:1158
PUGI__FN bool check_string_to_number_format(const char_t *string)
Definition pugixml.cpp:7300
PUGI__FN T * new_xpath_variable(const char_t *name)
Definition pugixml.cpp:7584
PUGI__FN const char_t * find_char(const char_t *s, char_t c)
Definition pugixml.cpp:6878
PUGI__FN size_t get_valid_length(const char_t *data, size_t length)
Definition pugixml.cpp:3147
PUGI__FN std::string as_utf8_impl(const wchar_t *str, size_t length)
Definition pugixml.cpp:1642
xml_allocator & get_allocator(const xml_node_struct *node)
Definition pugixml.cpp:590
xml_memory_management_function_storage< int > xml_memory
Definition pugixml.cpp:197
PUGI__FN xml_parse_status get_file_size(FILE *file, size_t &out_result)
Definition pugixml.cpp:3899
PUGI__FN bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh)
Definition pugixml.cpp:6967
char_t *(* strconv_pcdata_t)(char_t *)
Definition pugixml.cpp:1997
PUGI__FN_NO_INLINE xml_node_struct * append_node(xml_node_struct *node, xml_allocator &alloc, xml_node_type type=node_element)
Definition pugixml.cpp:660
static const unsigned char chartype_table[256]
Definition pugixml.cpp:1131
PUGI__NS_END PUGI__NS_BEGIN uint16_t endian_swap(uint16_t value)
Definition pugixml.cpp:735
void copy_backwards(I begin, I end, I target)
Definition pugixml.cpp:6377
PUGI__FN unsigned int node_height(xml_node n)
Definition pugixml.cpp:6954
bool is_text_node(xml_node_struct *node)
Definition pugixml.cpp:3706
PUGI__FN xpath_string string_value(const xpath_node &na, xpath_allocator *alloc)
Definition pugixml.cpp:6903
PUGI__FN xml_parse_result load_file_impl(xml_document &doc, FILE *file, unsigned int options, xml_encoding encoding)
Definition pugixml.cpp:3965
void reverse(I begin, I end)
Definition pugixml.cpp:6344
#define PUGI__FN_NO_INLINE
Definition pugixml.cpp:154
#define PUGI__STATIC_ASSERT(cond)
Definition pugixml.cpp:92
#define PUGI__NS_BEGIN
Definition pugixml.cpp:141
PUGI__FN void node_output(xml_buffered_writer &writer, const xml_node &node, const char_t *indent, unsigned int flags, unsigned int depth)
Definition pugixml.cpp:3487
PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream< T > &stream, void **out_buffer, size_t *out_size)
Definition pugixml.cpp:4040
#define PUGI__FN
Definition pugixml.cpp:153
PUGI__FN bool get_value_bool(const char_t *value, bool def)
Definition pugixml.cpp:3779
#define PUGI__SKIPWS()
Definition pugixml.cpp:2309
#define PUGI__DMC_VOLATILE
Definition pugixml.cpp:102
PUGI__NS_END PUGI__NS_BEGIN xml_attribute_struct * allocate_attribute(xml_allocator &alloc)
Definition pugixml.cpp:600
PUGI__FN double get_value_double(const char_t *value, double def)
Definition pugixml.cpp:3755
#define PUGI__THROW_ERROR(err, m)
Definition pugixml.cpp:2341
PUGI__NS_END PUGI__NS_BEGIN 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:7685
xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset=0)
Definition pugixml.cpp:2293
PUGI__FN const char_t * namespace_uri(const xml_node &node)
Definition pugixml.cpp:7427
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:3165
#define PUGI__SCANFOR(X)
Definition pugixml.cpp:2325
PUGI__FN const char_t * convert_number_to_string_special(double value)
Definition pugixml.cpp:7132
bool allow_insert_child(xml_node_type parent, xml_node_type child)
Definition pugixml.cpp:3640
static const uintptr_t xml_memory_page_name_allocated_mask
Definition pugixml.cpp:299
PUGI__NS_END static PUGI__NS_BEGIN const size_t xml_memory_page_size
Definition pugixml.cpp:289
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:7351
#define PUGI__NS_END
Definition pugixml.cpp:148
PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
Definition pugixml.cpp:3047
PUGI__FN void convert_number_to_mantissa_exponent(double value, char *buffer, size_t buffer_size, char **out_mantissa, int *out_exponent)
Definition pugixml.cpp:7199
PUGI__FN void delete_xpath_variable(T *var)
Definition pugixml.cpp:7624
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:1548
void swap(T &lhs, T &rhs)
Definition pugixml.cpp:6324
PUGI__NS_END PUGI__NS_BEGIN PUGI__FN size_t strlength(const char_t *s)
Definition pugixml.cpp:203
PUGI__FN char * convert_path_heap(const wchar_t *str)
Definition pugixml.cpp:4179
PUGI__FN void recursive_copy_skip(xml_node &dest, const xml_node &source, const xml_node &skip)
Definition pugixml.cpp:3652
PUGI__FN double round_nearest(double value)
Definition pugixml.cpp:7378
PUGI__FN void node_output_attributes(xml_buffered_writer &writer, const xml_node &node, unsigned int flags)
Definition pugixml.cpp:3471
nodetest_t
Definition pugixml.cpp:8254
@ nodetest_all
Definition pugixml.cpp:8262
@ nodetest_name
Definition pugixml.cpp:8256
@ nodetest_none
Definition pugixml.cpp:8255
@ nodetest_type_text
Definition pugixml.cpp:8260
@ nodetest_all_in_namespace
Definition pugixml.cpp:8263
@ nodetest_pi
Definition pugixml.cpp:8261
@ nodetest_type_comment
Definition pugixml.cpp:8258
@ nodetest_type_node
Definition pugixml.cpp:8257
@ nodetest_type_pi
Definition pugixml.cpp:8259
static const uintptr_t xml_memory_page_alignment
Definition pugixml.cpp:297
PUGI__FN bool set_value_buffer(char_t *&dest, uintptr_t &header, uintptr_t header_mask, char(&buf)[128])
Definition pugixml.cpp:3838
#define PUGI__POPNODE()
Definition pugixml.cpp:2321
PUGI__FN bool strcpy_insitu(char_t *&dest, uintptr_t &header, uintptr_t header_mask, const char_t *source)
Definition pugixml.cpp:1698
void partition(I begin, I middle, I end, const Pred &pred, I *out_eqbeg, I *out_eqend)
Definition pugixml.cpp:6417
PUGI__FN void normalize_space(char_t *buffer)
Definition pugixml.cpp:7474
PUGI__FN const char_t * find_substring(const char_t *s, const char_t *p)
Definition pugixml.cpp:6887
PUGI__FN bool strequalrange(const char_t *lhs, const char_t *rhs, size_t count)
Definition pugixml.cpp:227
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:4220
PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
Definition pugixml.cpp:1203
PUGI__FN double convert_string_to_number(const char_t *string)
Definition pugixml.cpp:7337
PUGI__FN bool is_nan(double value)
Definition pugixml.cpp:7119
static const uintptr_t xml_memory_page_value_allocated_mask
Definition pugixml.cpp:300
PUGI__FN xpath_node xpath_first(const xpath_node *begin, const xpath_node *end, xpath_node_set::type_t type)
Definition pugixml.cpp:7702
#define PUGI__PUSHNODE(TYPE)
Definition pugixml.cpp:2315
static const xpath_node_set dummy_node_set
Definition pugixml.cpp:7562
PUGI__FN size_t as_utf8_begin(const wchar_t *str, size_t length)
Definition pugixml.cpp:1622
PUGI__FN xpath_variable * get_variable_scratch(char_t(&buffer)[32], xpath_variable_set *set, const char_t *begin, const char_t *end)
Definition pugixml.cpp:7655
PUGI__FN void text_output(xml_buffered_writer &writer, const char_t *s, chartypex_t type, unsigned int flags)
Definition pugixml.cpp:3440
PUGI__FN void translate(char_t *buffer, const char_t *from, const char_t *to)
Definition pugixml.cpp:7504
xml_node_struct * allocate_node(xml_allocator &alloc, xml_node_type type)
Definition pugixml.cpp:608
#define PUGI__SCANWHILE(X)
Definition pugixml.cpp:2330
PUGI__FN void truncate_zeros(char *begin, char *end)
Definition pugixml.cpp:7174
PUGI__FN unsigned int get_value_uint(const char_t *value, unsigned int def)
Definition pugixml.cpp:3741
axis_t
Definition pugixml.cpp:8237
@ axis_preceding
Definition pugixml.cpp:8248
@ axis_ancestor_or_self
Definition pugixml.cpp:8239
@ axis_attribute
Definition pugixml.cpp:8240
@ axis_following_sibling
Definition pugixml.cpp:8245
@ axis_child
Definition pugixml.cpp:8241
@ axis_descendant
Definition pugixml.cpp:8242
@ axis_descendant_or_self
Definition pugixml.cpp:8243
@ axis_self
Definition pugixml.cpp:8250
@ axis_following
Definition pugixml.cpp:8244
@ axis_ancestor
Definition pugixml.cpp:8238
@ axis_preceding_sibling
Definition pugixml.cpp:8249
@ axis_namespace
Definition pugixml.cpp:8246
@ axis_parent
Definition pugixml.cpp:8247
chartype_t
Definition pugixml.cpp:1120
@ ct_parse_comment
Definition pugixml.cpp:1126
@ ct_start_symbol
Definition pugixml.cpp:1128
@ ct_parse_attr
Definition pugixml.cpp:1122
@ ct_parse_attr_ws
Definition pugixml.cpp:1123
@ ct_parse_cdata
Definition pugixml.cpp:1125
@ ct_parse_pcdata
Definition pugixml.cpp:1121
@ ct_space
Definition pugixml.cpp:1124
@ ct_symbol
Definition pugixml.cpp:1127
PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void *contents, size_t size)
Definition pugixml.cpp:1240
PUGI__FN float get_value_float(const char_t *value, float def)
Definition pugixml.cpp:3767
PUGI__FN const char_t * local_name(const xpath_node &node)
Definition pugixml.cpp:7395
void median3(I first, I middle, I last, const Pred &pred)
Definition pugixml.cpp:6480
PUGI__FN bool strequal(const char_t *src, const char_t *dst)
Definition pugixml.cpp:215
PUGI__FN bool convert_buffer_utf16(char_t *&out_buffer, size_t &out_length, const void *contents, size_t size, opt_swap)
Definition pugixml.cpp:1486
PUGI__FN std::basic_string< wchar_t > as_wide_impl(const char *str, size_t size)
Definition pugixml.cpp:1658
chartypex_t
Definition pugixml.cpp:1150
@ ctx_digit
Definition pugixml.cpp:1154
@ ctx_special_attr
Definition pugixml.cpp:1152
@ ctx_symbol
Definition pugixml.cpp:1155
@ ctx_start_symbol
Definition pugixml.cpp:1153
@ ctx_special_pcdata
Definition pugixml.cpp:1151
PUGI__FN const void * document_order(const xpath_node &xnode)
Definition pugixml.cpp:7006
PUGI__FN char_t * strconv_cdata(char_t *s, char_t endch)
Definition pugixml.cpp:1966
PUGI__FN xpath_string xpath_string_const(const char_t *str)
Definition pugixml.cpp:6860
PUGI__NS_BEGIN PUGI__FN void * default_allocate(size_t size)
Definition pugixml.cpp:175
PUGI__FN bool node_is_ancestor(xml_node parent, xml_node node)
Definition pugixml.cpp:6998
PUGI__FN int get_value_int(const char_t *value, int def)
Definition pugixml.cpp:3727
PUGI__FN char_t tolower_ascii(char_t ch)
Definition pugixml.cpp:6898
PUGI__FN int get_integer_base(const char_t *value)
Definition pugixml.cpp:3714
PUGI__FN void text_output_escaped(xml_buffered_writer &writer, const char_t *s, chartypex_t type)
Definition pugixml.cpp:3397
#define PUGIXML_FUNCTION
Definition pugixml.hpp:67
#define PUGIXML_TEXT(t)
Definition pugixml.hpp:84
#define false
Definition stdbool.h:17
#define bool
Definition stdbool.h:15
__WCHAR_TYPE__ wchar_t
Definition stddef.h:74
#define offsetof(t, d)
Definition stddef.h:104
static const axis_t axis
Definition pugixml.cpp:8269
void(* deleter)(void *)
Definition pugixml.cpp:268
void * release()
Definition pugixml.cpp:278
buffer_holder(void *data_, void(*deleter_)(void *))
Definition pugixml.cpp:270
bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
Definition pugixml.cpp:7035
bool operator()(const xpath_node &lhs, const xpath_node &rhs) const
Definition pugixml.cpp:7094
bool operator()(const T &lhs, const T &rhs) const
Definition pugixml.cpp:6290
char_t * end
Definition pugixml.cpp:1751
gap()
Definition pugixml.cpp:1754
char_t * flush(char_t *s)
Definition pugixml.cpp:1775
void push(char_t *&s, size_t count)
Definition pugixml.cpp:1758
size_t size
Definition pugixml.cpp:1752
static value_type high(value_type result, uint32_t ch)
Definition pugixml.cpp:897
static value_type low(value_type result, uint32_t ch)
Definition pugixml.cpp:890
uint8_t * value_type
Definition pugixml.cpp:888
bool operator()(const T &lhs, const T &rhs) const
Definition pugixml.cpp:6317
bool operator()(const T &lhs, const T &rhs) const
Definition pugixml.cpp:6308
namespace_uri_predicate(const char_t *name)
Definition pugixml.cpp:7408
const char_t * prefix
Definition pugixml.cpp:7405
bool operator()(const xml_attribute &a) const
Definition pugixml.cpp:7416
bool operator()(const T &lhs, const T &rhs) const
Definition pugixml.cpp:6299
A 'name=value' XML attribute structure.
Definition pugixml.cpp:522
xml_attribute_struct * prev_attribute_c
Previous attribute (cyclic list)
Definition pugixml.cpp:534
xml_attribute_struct(impl::xml_memory_page *page)
Default ctor.
Definition pugixml.cpp:524
xml_attribute_struct * next_attribute
Next attribute.
Definition pugixml.cpp:535
char_t * name
Pointer to attribute name.
Definition pugixml.cpp:531
char_t * value
Pointer to attribute value.
Definition pugixml.cpp:532
An XML document tree node.
Definition pugixml.cpp:540
char_t * value
Pointer to any associated string data.
Definition pugixml.cpp:560
xml_attribute_struct * first_attribute
First attribute.
Definition pugixml.cpp:567
xml_node_struct * prev_sibling_c
Left brother (cyclic list)
Definition pugixml.cpp:564
xml_node_struct * next_sibling
Right brother.
Definition pugixml.cpp:565
char_t * name
Pointer to element name.
Definition pugixml.cpp:559
xml_node_struct * parent
Pointer to parent.
Definition pugixml.cpp:557
xml_node_struct * first_child
First child.
Definition pugixml.cpp:562
xml_node_struct(impl::xml_memory_page *page, xml_node_type type)
Default ctor.
Definition pugixml.cpp:543
const char * description() const
Definition pugixml.cpp:5913
xml_parse_status status
Definition pugixml.hpp:903
const char * description() const
static char_t * parse_eol(char_t *s, char_t end_quote)
Definition pugixml.cpp:2184
static char_t * parse_simple(char_t *s, char_t end_quote)
Definition pugixml.cpp:2219
static char_t * parse_wnorm(char_t *s, char_t end_quote)
Definition pugixml.cpp:2087
static char_t * parse_wconv(char_t *s, char_t end_quote)
Definition pugixml.cpp:2144
static char_t * parse(char_t *s)
Definition pugixml.cpp:2002
size_t value_type
Definition pugixml.cpp:816
static value_type low(value_type result, uint32_t)
Definition pugixml.cpp:818
static value_type high(value_type result, uint32_t)
Definition pugixml.cpp:820
static value_type high(value_type result, uint32_t ch)
Definition pugixml.cpp:834
uint16_t * value_type
Definition pugixml.cpp:825
static value_type low(value_type result, uint32_t ch)
Definition pugixml.cpp:827
static value_type any(value_type result, uint32_t ch)
Definition pugixml.cpp:845
static value_type low(value_type result, uint32_t)
Definition pugixml.cpp:855
size_t value_type
Definition pugixml.cpp:853
static value_type high(value_type result, uint32_t)
Definition pugixml.cpp:857
static value_type low(value_type result, uint32_t ch)
Definition pugixml.cpp:864
uint32_t * value_type
Definition pugixml.cpp:862
static value_type high(value_type result, uint32_t ch)
Definition pugixml.cpp:871
static value_type any(value_type result, uint32_t ch)
Definition pugixml.cpp:878
static value_type low(value_type result, uint32_t ch)
Definition pugixml.cpp:749
static value_type high(value_type result, uint32_t)
Definition pugixml.cpp:762
size_t value_type
Definition pugixml.cpp:747
static value_type any(value_type result, uint32_t ch)
Definition pugixml.cpp:808
static value_type high(value_type result, uint32_t ch)
Definition pugixml.cpp:798
static value_type low(value_type result, uint32_t ch)
Definition pugixml.cpp:773
uint8_t * value_type
Definition pugixml.cpp:771
static Traits::value_type decode_wchar_block_impl(const uint32_t *data, size_t size, typename Traits::value_type result)
Definition pugixml.cpp:1088
static Traits::value_type decode_latin1_block(const uint8_t *data, size_t size, typename Traits::value_type result)
Definition pugixml.cpp:1071
static Traits::value_type decode_wchar_block_impl(const uint16_t *data, size_t size, typename Traits::value_type result)
Definition pugixml.cpp:1082
static Traits::value_type decode_wchar_block(const wchar_t *data, size_t size, typename Traits::value_type result)
Definition pugixml.cpp:1094
static Traits::value_type decode_utf8_block(const uint8_t *data, size_t size, typename Traits::value_type result)
Definition pugixml.cpp:932
static Traits::value_type decode_utf32_block(const uint32_t *data, size_t size, typename Traits::value_type result)
Definition pugixml.cpp:1045
static Traits::value_type decode_utf16_block(const uint16_t *data, size_t size, typename Traits::value_type result)
Definition pugixml.cpp:1000
utf16_counter counter
Definition pugixml.cpp:914
utf16_writer writer
Definition pugixml.cpp:915
utf32_writer writer
Definition pugixml.cpp:923
utf32_counter counter
Definition pugixml.cpp:922
void * allocate_memory(size_t size, xml_memory_page *&out_page)
Definition pugixml.cpp:374
char_t * allocate_string(size_t length)
Definition pugixml.cpp:424
static void deallocate_page(xml_memory_page *page)
Definition pugixml.cpp:370
void * allocate_memory_oob(size_t size, xml_memory_page *&out_page)
Definition pugixml.cpp:477
xml_memory_page * _root
Definition pugixml.cpp:473
size_t _busy_size
Definition pugixml.cpp:474
void deallocate_memory(void *ptr, size_t size, xml_memory_page *page)
Definition pugixml.cpp:388
xml_memory_page * allocate_page(size_t data_size)
Definition pugixml.cpp:347
xml_allocator(xml_memory_page *root)
Definition pugixml.cpp:345
void deallocate_string(char_t *string)
Definition pugixml.cpp:453
const char_t * buffer
Definition pugixml.cpp:585
xml_document_struct(xml_memory_page *page)
Definition pugixml.cpp:580
xml_extra_buffer * extra_buffers
Definition pugixml.cpp:587
xml_extra_buffer * next
Definition pugixml.cpp:575
char_t * buffer
Definition pugixml.cpp:574
static deallocation_function deallocate
Definition pugixml.cpp:189
static allocation_function allocate
Definition pugixml.cpp:188
xml_memory_page * prev
Definition pugixml.cpp:328
static xml_memory_page * construct(void *memory)
Definition pugixml.cpp:307
xml_memory_page * next
Definition pugixml.cpp:329
size_t freed_size
Definition pugixml.cpp:332
xml_allocator * allocator
Definition pugixml.cpp:324
static char_t * parse_skip_bom(char_t *s)
Definition pugixml.cpp:2960
xml_parse_status error_status
Definition pugixml.cpp:2306
char_t * parse_doctype_primitive(char_t *s)
Definition pugixml.cpp:2357
xml_allocator alloc
Definition pugixml.cpp:2304
char_t * error_offset
Definition pugixml.cpp:2305
char_t * parse_tree(char_t *s, xml_node_struct *root, unsigned int optmsk, char_t endch)
Definition pugixml.cpp:2694
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:2980
static bool has_element_node_siblings(xml_node_struct *node)
Definition pugixml.cpp:2966
char_t * parse_question(char_t *s, xml_node_struct *&ref_cursor, unsigned int optmsk, char_t endch)
Definition pugixml.cpp:2595
char_t * parse_doctype_ignore(char_t *s)
Definition pugixml.cpp:2395
xml_parser(const xml_allocator &alloc_)
Definition pugixml.cpp:2348
char_t * parse_doctype_group(char_t *s, char_t endch, bool toplevel)
Definition pugixml.cpp:2423
char_t * parse_exclamation(char_t *s, xml_node_struct *cursor, unsigned int optmsk, char_t endch)
Definition pugixml.cpp:2472
static xml_stream_chunk * create()
Definition pugixml.cpp:4011
T data[xml_memory_page_size/sizeof(T)]
Definition pugixml.cpp:4036
static void destroy(void *ptr)
Definition pugixml.cpp:4018
xml_stream_chunk * next
Definition pugixml.cpp:4033
xpath_allocator _state
Definition pugixml.cpp:6711
xpath_allocator * _target
Definition pugixml.cpp:6710
xpath_allocator_capture(xpath_allocator *alloc)
Definition pugixml.cpp:6706
xpath_context(const xpath_node &n_, size_t position_, size_t size_)
Definition pugixml.cpp:7820
xpath_node n
Definition pugixml.cpp:7817
size_t position
Definition pugixml.cpp:7818
const char_t * begin
Definition pugixml.cpp:7856
const char_t * end
Definition pugixml.cpp:7857
bool operator==(const char_t *other) const
Definition pugixml.cpp:7861
xpath_memory_block * next
Definition pugixml.cpp:6547
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)
void throw_error(const char *message)
Definition pugixml.cpp:9702
xpath_ast_node * parse_step(xpath_ast_node *set)
xpath_ast_node * parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node *args[2])
Definition pugixml.cpp:9753
xpath_variable_set * _variables
Definition pugixml.cpp:9692
xpath_parser(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
xpath_ast_node * parse_primary_expression()
Definition pugixml.cpp:9989
xpath_lexer _lexer
Definition pugixml.cpp:9689
xpath_ast_node * parse_filter_expression()
nodetest_t parse_node_test_type(const xpath_lexer_string &name)
Definition pugixml.cpp:9953
xpath_ast_node * parse_expression()
const char_t * alloc_string(const xpath_lexer_string &value)
Definition pugixml.cpp:9733
void * alloc_node()
Definition pugixml.cpp:9723
xpath_parse_result * _result
Definition pugixml.cpp:9694
xpath_ast_node * parse_function(const xpath_lexer_string &name, size_t argc, xpath_ast_node *args[2])
Definition pugixml.cpp:9763
xpath_ast_node * parse()
char_t _scratch[32]
Definition pugixml.cpp:9696
static xpath_ast_node * parse(const char_t *query, xpath_variable_set *variables, xpath_allocator *alloc, xpath_parse_result *result)
const char_t * _query
Definition pugixml.cpp:9691
xpath_ast_node * parse_path_or_unary_expression()
xpath_allocator * _alloc
Definition pugixml.cpp:9688
axis_t parse_axis_name(const xpath_lexer_string &name, bool &specified)
Definition pugixml.cpp:9885
xpath_ast_node * parse_expression_rec(xpath_ast_node *lhs, int limit)
void throw_error_oom()
Definition pugixml.cpp:9714
xpath_ast_node * parse_relative_location_path(xpath_ast_node *set)
xpath_ast_node * parse_location_path()
xpath_memory_block block
static void destroy(void *ptr)
xpath_ast_node * root
static xpath_query_impl * create()
xpath_allocator alloc
xpath_allocator temp
Definition pugixml.cpp:6724
xpath_memory_block blocks[2]
Definition pugixml.cpp:6722
xpath_allocator result
Definition pugixml.cpp:6723
xpath_stack stack
Definition pugixml.cpp:6725
xpath_allocator * temp
Definition pugixml.cpp:6717
xpath_allocator * result
Definition pugixml.cpp:6716
xpath_node_set value
Definition pugixml.cpp:7558
#define fmod(__x, __y)
Definition tgmath.h:798
#define floor(__x)
Definition tgmath.h:722
#define ceil(__x)
Definition tgmath.h:601