56 #ifndef SOURCE_XML_CPP
57 #define SOURCE_XML_CPP
62 #include "exception.h"
85 # pragma warning(push)
86 # pragma warning(disable: 4127) // conditional expression is constant
87 # pragma warning(disable: 4324) // structure was padded due to __declspec(align())
88 # pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
89 # pragma warning(disable: 4702) // unreachable code
90 # pragma warning(disable: 4996) // this function or variable may be unsafe
91 # pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
94 #ifdef __INTEL_COMPILER
95 # pragma warning(disable: 177) // function was declared but never referenced
96 # pragma warning(disable: 279) // controlling expression is constant
97 # pragma warning(disable: 1478 1786) // function was declared "deprecated"
98 # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type
103 # pragma diag_suppress=178 // function was declared but never referenced
104 # pragma diag_suppress=237 // controlling expression is constant
108 #if defined(_MSC_VER) && _MSC_VER >= 1300
109 # define PUGI__NO_INLINE __declspec(noinline)
110 #elif defined(__GNUC__)
111 # define PUGI__NO_INLINE __attribute__((noinline))
113 # define PUGI__NO_INLINE
117 #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
121 # define PUGI__DMC_VOLATILE volatile
123 # define PUGI__DMC_VOLATILE
127 #if defined(_MSC_VER) && !defined(__S3E__)
128 # define PUGI__MSVC_CRT_VERSION _MSC_VER
131 #ifdef XML_HEADER_ONLY
132 # define PUGI__NS_BEGIN namespace XML { namespace internal {
133 # define PUGI__NS_END } }
134 # define PUGI__FN inline
135 # define PUGI__FN_NO_INLINE inline
137 # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
138 # define PUGI__NS_BEGIN namespace XML { namespace internal {
139 # define PUGI__NS_END } }
141 # define PUGI__NS_BEGIN namespace XML { namespace internal { namespace {
142 # define PUGI__NS_END } } }
145 # define PUGI__FN_NO_INLINE PUGI__NO_INLINE
149 #if !defined(_MSC_VER) || _MSC_VER >= 1600
152 # ifndef _UINTPTR_T_DEFINED
154 typedef size_t uintptr_t;
155 #define _UINTPTR_T_DEFINED
158 typedef unsigned __int8 uint8_t;
159 typedef unsigned __int16 uint16_t;
160 typedef unsigned __int32 uint32_t;
164 namespace Mezzanine {
168 PUGI__FN
void* default_allocate(
size_t size)
173 PUGI__FN
void default_deallocate(
void* ptr)
178 template <
typename T>
179 struct MemoryManagement_function_storage
185 template <
typename T>
AllocationFunction MemoryManagement_function_storage<T>::allocate = default_allocate;
186 template <
typename T>
DeAllocationFunction MemoryManagement_function_storage<T>::deallocate = default_deallocate;
188 typedef MemoryManagement_function_storage<int> Memory;
194 PUGI__FN
size_t strlength(
const Char8* s)
202 PUGI__FN
bool strequal(
const Char8* src,
const Char8* dst)
206 return strcmp(src, dst) == 0;
211 PUGI__FN
bool strequalrange(
const Char8* lhs,
const Char8* rhs,
size_t count)
213 for (
size_t i = 0; i < count; ++i)
214 if (lhs[i] != rhs[i])
217 return lhs[count] == 0;
227 void (*deleter)(
void*);
229 buffer_holder(
void* data_,
void (*deleter_)(
void*)): data(data_), deleter(deleter_)
235 if (data) deleter(data);
249 static const size_t MemoryPage_size =
250 #ifdef XML_MEMORY_PAGE_SIZE
257 static const uintptr_t MemoryPage_alignment = 32;
258 static const uintptr_t MemoryPage_pointer_mask = ~(MemoryPage_alignment - 1);
259 static const uintptr_t MemoryPage_Name_allocated_mask = 16;
260 static const uintptr_t MemoryPage_Value_allocated_mask = 8;
261 static const uintptr_t MemoryPage_type_mask = 7;
267 static MemoryPage* construct(
void* memory)
269 if (!memory)
return 0;
271 MemoryPage* Result =
static_cast<MemoryPage*
>(memory);
273 Result->allocator = 0;
277 Result->busy_size = 0;
278 Result->freed_size = 0;
283 Allocator* allocator;
296 struct MemoryString_header
298 uint16_t page_Offset;
303 Allocator(MemoryPage* GetRoot): _GetRoot(GetRoot), _busy_size(GetRoot->busy_size)
307 MemoryPage* allocate_page(
size_t data_size)
309 size_t size = offsetof(MemoryPage, data) + data_size;
312 void* memory = Memory::allocate(size + MemoryPage_alignment);
313 if (!memory)
return 0;
316 void* page_memory =
reinterpret_cast<void*
>((
reinterpret_cast<uintptr_t
>(memory) + (MemoryPage_alignment - 1)) & ~(MemoryPage_alignment - 1));
319 MemoryPage* page = MemoryPage::construct(page_memory);
321 page->memory = memory;
322 page->allocator = _GetRoot->allocator;
327 static void deallocate_page(MemoryPage* page)
329 Memory::deallocate(page->memory);
332 void* allocate_memory_oob(
size_t size, MemoryPage*& out_page);
334 void* allocate_memory(
size_t size, MemoryPage*& out_page)
336 if (_busy_size + size > MemoryPage_size)
return allocate_memory_oob(size, out_page);
338 void* buf = _GetRoot->data + _busy_size;
347 void deallocate_memory(
void* ptr,
size_t size, MemoryPage* page)
349 if (page == _GetRoot) page->busy_size = _busy_size;
351 assert(ptr >= page->data && ptr < page->data + page->busy_size);
354 page->freed_size += size;
355 assert(page->freed_size <= page->busy_size);
357 if (page->freed_size == page->busy_size)
361 assert(_GetRoot == page);
364 page->busy_size = page->freed_size = 0;
369 assert(_GetRoot != page);
373 page->prev->next = page->next;
374 page->next->prev = page->prev;
377 deallocate_page(page);
382 Char8* allocate_string(
size_t length)
385 size_t size =
sizeof(MemoryString_header) + length *
sizeof(
Char8);
388 size_t full_size = (size + (
sizeof(
void*) - 1)) & ~(
sizeof(
void*) - 1);
391 MemoryString_header* header =
static_cast<MemoryString_header*
>(allocate_memory(full_size, page));
393 if (!header)
return 0;
396 ptrdiff_t page_Offset =
reinterpret_cast<char*
>(header) - page->data;
398 assert(page_Offset >= 0 && page_Offset < (1 << 16));
399 header->page_Offset =
static_cast<uint16_t
>(page_Offset);
402 assert(full_size < (1 << 16) || (page->busy_size == full_size && page_Offset == 0));
403 header->full_size =
static_cast<uint16_t
>(full_size < (1 << 16) ? full_size : 0);
407 return static_cast<Char8*
>(
static_cast<void*
>(header + 1));
410 void deallocate_string(
Char8*
string)
416 MemoryString_header* header =
static_cast<MemoryString_header*
>(
static_cast<void*
>(string)) - 1;
419 size_t page_Offset = offsetof(MemoryPage, data) + header->page_Offset;
420 MemoryPage* page =
reinterpret_cast<MemoryPage*
>(
static_cast<void*
>(
reinterpret_cast<char*
>(header) - page_Offset));
423 size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size;
425 deallocate_memory(header, full_size, page);
428 MemoryPage* _GetRoot;
432 PUGI__FN_NO_INLINE
void* Allocator::allocate_memory_oob(
size_t size, MemoryPage*& out_page)
434 const size_t large_allocation_threshold = MemoryPage_size / 4;
436 MemoryPage* page = allocate_page(size <= large_allocation_threshold ? MemoryPage_size : size);
441 if (size <= large_allocation_threshold)
443 _GetRoot->busy_size = _busy_size;
446 page->prev = _GetRoot;
447 _GetRoot->next = page;
456 assert(_GetRoot->prev);
458 page->prev = _GetRoot->prev;
459 page->next = _GetRoot;
461 _GetRoot->prev->next = page;
462 _GetRoot->prev = page;
466 page->busy_size = size;
475 struct AttributeStruct
478 AttributeStruct(internal::MemoryPage* page): header(reinterpret_cast<uintptr_t>(page)), Name(0), Value(0), prev_attribute_c(0), GetNextAttribute(0)
487 AttributeStruct* prev_attribute_c;
488 AttributeStruct* GetNextAttribute;
496 NodeStruct(internal::MemoryPage* page,
NodeType Type): header(reinterpret_cast<uintptr_t>(page) | (Type - 1)), GetParent(0), Name(0), Value(0), GetFirstChild(0), prev_sibling_c(0), GetNextSibling(0), GetFirstAttribute(0)
502 NodeStruct* GetParent;
507 NodeStruct* GetFirstChild;
509 NodeStruct* prev_sibling_c;
510 NodeStruct* GetNextSibling;
512 AttributeStruct* GetFirstAttribute;
517 struct DocumentStruct:
public NodeStruct,
public Allocator
519 DocumentStruct(MemoryPage* page): NodeStruct(page,
NodeDocument), Allocator(page), buffer(0)
526 inline Allocator& GetAllocator(
const NodeStruct* node)
530 return *
reinterpret_cast<MemoryPage*
>(node->header & MemoryPage_pointer_mask)->allocator;
536 inline AttributeStruct* allocate_attribute(Allocator& alloc)
539 void* memory = alloc.allocate_memory(
sizeof(AttributeStruct), page);
541 return new (memory) AttributeStruct(page);
544 inline NodeStruct* allocate_node(Allocator& alloc,
NodeType Type)
547 void* memory = alloc.allocate_memory(
sizeof(NodeStruct), page);
549 return new (memory) NodeStruct(page, Type);
552 inline void destroy_attribute(AttributeStruct* a, Allocator& alloc)
554 uintptr_t header = a->header;
556 if (header & internal::MemoryPage_Name_allocated_mask) alloc.deallocate_string(a->Name);
557 if (header & internal::MemoryPage_Value_allocated_mask) alloc.deallocate_string(a->Value);
559 alloc.deallocate_memory(a,
sizeof(AttributeStruct), reinterpret_cast<MemoryPage*>(header & MemoryPage_pointer_mask));
562 inline void destroy_node(NodeStruct* n, Allocator& alloc)
564 uintptr_t header = n->header;
566 if (header & internal::MemoryPage_Name_allocated_mask) alloc.deallocate_string(n->Name);
567 if (header & internal::MemoryPage_Value_allocated_mask) alloc.deallocate_string(n->Value);
569 for (AttributeStruct* attr = n->GetFirstAttribute; attr; )
571 AttributeStruct* next = attr->GetNextAttribute;
573 destroy_attribute(attr, alloc);
578 for (NodeStruct* GetChild = n->GetFirstChild; GetChild; )
580 NodeStruct* next = GetChild->GetNextSibling;
582 destroy_node(GetChild, alloc);
587 alloc.deallocate_memory(n,
sizeof(NodeStruct), reinterpret_cast<MemoryPage*>(header & MemoryPage_pointer_mask));
590 PUGI__FN_NO_INLINE NodeStruct* AppendNode(NodeStruct* node, Allocator& alloc,
NodeType Type =
NodeElement)
592 NodeStruct* GetChild = allocate_node(alloc, Type);
593 if (!GetChild)
return 0;
595 GetChild->GetParent = node;
597 NodeStruct* GetFirstChild = node->GetFirstChild;
601 NodeStruct* GetLastChild = GetFirstChild->prev_sibling_c;
603 GetLastChild->GetNextSibling = GetChild;
604 GetChild->prev_sibling_c = GetLastChild;
605 GetFirstChild->prev_sibling_c = GetChild;
609 node->GetFirstChild = GetChild;
610 GetChild->prev_sibling_c = GetChild;
616 PUGI__FN_NO_INLINE AttributeStruct* AppendAttribute_ll(NodeStruct* node, Allocator& alloc)
618 AttributeStruct* a = allocate_attribute(alloc);
621 AttributeStruct* GetFirstAttribute = node->GetFirstAttribute;
623 if (GetFirstAttribute)
625 AttributeStruct* GetLastAttribute = GetFirstAttribute->prev_attribute_c;
627 GetLastAttribute->GetNextAttribute = a;
628 a->prev_attribute_c = GetLastAttribute;
629 GetFirstAttribute->prev_attribute_c = a;
633 node->GetFirstAttribute = a;
634 a->prev_attribute_c = a;
656 inline uint16_t endian_swap(uint16_t Value)
658 return static_cast<uint16_t
>(((Value & 0xff) << 8) | (Value >> 8));
661 inline uint32_t endian_swap(uint32_t Value)
663 return ((Value & 0xff) << 24) | ((Value & 0xff00) << 8) | ((Value & 0xff0000) >> 8) | (Value >> 24);
668 typedef size_t value_type;
670 static value_type low(value_type Result, uint32_t ch)
673 if (ch < 0x80)
return Result + 1;
675 else if (ch < 0x800)
return Result + 2;
677 else return Result + 3;
680 static value_type high(value_type Result, uint32_t)
687 struct utf8_WriterInstance
689 typedef uint8_t* value_type;
691 static value_type low(value_type Result, uint32_t ch)
696 *Result =
static_cast<uint8_t
>(ch);
702 Result[0] =
static_cast<uint8_t
>(0xC0 | (ch >> 6));
703 Result[1] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
709 Result[0] =
static_cast<uint8_t
>(0xE0 | (ch >> 12));
710 Result[1] =
static_cast<uint8_t
>(0x80 | ((ch >> 6) & 0x3F));
711 Result[2] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
716 static value_type high(value_type Result, uint32_t ch)
719 Result[0] =
static_cast<uint8_t
>(0xF0 | (ch >> 18));
720 Result[1] =
static_cast<uint8_t
>(0x80 | ((ch >> 12) & 0x3F));
721 Result[2] =
static_cast<uint8_t
>(0x80 | ((ch >> 6) & 0x3F));
722 Result[3] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
726 static value_type any(value_type Result, uint32_t ch)
728 return (ch < 0x10000) ? low(Result, ch) : high(Result, ch);
734 typedef size_t value_type;
736 static value_type low(value_type Result, uint32_t)
741 static value_type high(value_type Result, uint32_t)
747 struct utf16_WriterInstance
749 typedef uint16_t* value_type;
751 static value_type low(value_type Result, uint32_t ch)
753 *Result =
static_cast<uint16_t
>(ch);
758 static value_type high(value_type Result, uint32_t ch)
760 uint32_t msh =
static_cast<uint32_t
>(ch - 0x10000) >> 10;
761 uint32_t lsh =
static_cast<uint32_t
>(ch - 0x10000) & 0x3ff;
763 Result[0] =
static_cast<uint16_t
>(0xD800 + msh);
764 Result[1] =
static_cast<uint16_t
>(0xDC00 + lsh);
769 static value_type any(value_type Result, uint32_t ch)
771 return (ch < 0x10000) ? low(Result, ch) : high(Result, ch);
777 typedef size_t value_type;
779 static value_type low(value_type Result, uint32_t)
784 static value_type high(value_type Result, uint32_t)
790 struct utf32_WriterInstance
792 typedef uint32_t* value_type;
794 static value_type low(value_type Result, uint32_t ch)
801 static value_type high(value_type Result, uint32_t ch)
808 static value_type any(value_type Result, uint32_t ch)
816 struct latin1_WriterInstance
818 typedef uint8_t* value_type;
820 static value_type low(value_type Result, uint32_t ch)
822 *Result =
static_cast<uint8_t
>(ch > 255 ?
'?' : ch);
827 static value_type high(value_type Result, uint32_t ch)
837 template <
size_t size>
struct wchar_selector;
839 template <>
struct wchar_selector<2>
841 typedef uint16_t Type;
842 typedef utf16_counter counter;
843 typedef utf16_WriterInstance WriterInstance;
846 template <>
struct wchar_selector<4>
848 typedef uint32_t Type;
849 typedef utf32_counter counter;
850 typedef utf32_WriterInstance WriterInstance;
853 typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
854 typedef wchar_selector<sizeof(wchar_t)>::WriterInstance wchar_WriterInstance;
856 template <
typename Traits,
typename opt_swap = opt_false>
struct utf_decoder
858 static inline typename Traits::value_type decode_utf8_block(
const uint8_t* data,
size_t size,
typename Traits::value_type Result)
860 const uint8_t utf8_byte_mask = 0x3f;
864 uint8_t lead = *data;
869 Result = Traits::low(Result, lead);
874 if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
877 while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)
879 Result = Traits::low(Result, data[0]);
880 Result = Traits::low(Result, data[1]);
881 Result = Traits::low(Result, data[2]);
882 Result = Traits::low(Result, data[3]);
889 else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
891 Result = Traits::low(Result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
896 else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
898 Result = Traits::low(Result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
903 else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
905 Result = Traits::high(Result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
920 static inline typename Traits::value_type decode_utf16_block(
const uint16_t* data,
size_t size,
typename Traits::value_type Result)
922 const uint16_t* end = data + size;
926 uint16_t lead = opt_swap::Value ? endian_swap(*data) : *data;
931 Result = Traits::low(Result, lead);
935 else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
937 Result = Traits::low(Result, lead);
941 else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && data + 1 < end)
943 uint16_t next = opt_swap::Value ? endian_swap(data[1]) : data[1];
945 if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
947 Result = Traits::high(Result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
964 static inline typename Traits::value_type decode_utf32_block(
const uint32_t* data,
size_t size,
typename Traits::value_type Result)
966 const uint32_t* end = data + size;
970 uint32_t lead = opt_swap::Value ? endian_swap(*data) : *data;
975 Result = Traits::low(Result, lead);
981 Result = Traits::high(Result, lead);
989 static inline typename Traits::value_type decode_latin1_block(
const uint8_t* data,
size_t size,
typename Traits::value_type Result)
991 for (
size_t i = 0; i < size; ++i)
993 Result = Traits::low(Result, data[i]);
999 static inline typename Traits::value_type decode_wchar_block_impl(
const uint16_t* data,
size_t size,
typename Traits::value_type Result)
1001 return decode_utf16_block(data, size, Result);
1004 static inline typename Traits::value_type decode_wchar_block_impl(
const uint32_t* data,
size_t size,
typename Traits::value_type Result)
1006 return decode_utf32_block(data, size, Result);
1009 static inline typename Traits::value_type decode_wchar_block(
const wchar_t* data,
size_t size,
typename Traits::value_type Result)
1011 return decode_wchar_block_impl(
reinterpret_cast<const wchar_selector<sizeof(wchar_t)>::Type*
>(data), size, Result);
1015 template <
typename T> PUGI__FN
void convert_utf_endian_swap(T* Result,
const T* data,
size_t length)
1017 for (
size_t i = 0; i < length; ++i) Result[i] = endian_swap(data[i]);
1023 enum charCollectionType
1030 ct_ParseComment = 32,
1032 ct_start_symbol = 128
1035 static const unsigned char charCollectionTypeable[256] =
1037 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0,
1038 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1039 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0,
1040 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0,
1041 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1042 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192,
1043 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1044 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0,
1046 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1047 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1048 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1049 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1050 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1051 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1052 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1053 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
1058 ctx_special_pcdata = 1,
1059 ctx_special_attr = 2,
1060 ctx_start_symbol = 4,
1065 static const unsigned char charTypex_table[256] =
1067 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3,
1068 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1069 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0,
1070 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0,
1072 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1073 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20,
1074 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1075 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0,
1077 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1078 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1079 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1080 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1081 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1082 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1083 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1084 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
1087 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
1089 #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, charCollectionTypeable)
1090 #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, charTypex_table)
1092 PUGI__FN
bool is_little_endian()
1094 unsigned int ui = 1;
1096 return *
reinterpret_cast<unsigned char*
>(&ui) == 1;
1099 PUGI__FN
Encoding GetWchar_DocumentEncoding()
1101 PUGI__STATIC_ASSERT(
sizeof(
wchar_t) == 2 ||
sizeof(
wchar_t) == 4);
1103 if (
sizeof(
wchar_t) == 2)
1109 PUGI__FN
Encoding guess_buffer_DocumentEncoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
1112 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff)
return EncodingUTF32BE;
1113 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0)
return EncodingUTF32LE;
1116 if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf)
return EncodingUTF8;
1119 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c)
return EncodingUTF32BE;
1120 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0)
return EncodingUTF32LE;
1121 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f)
return EncodingUTF16BE;
1122 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0)
return EncodingUTF16LE;
1123 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d)
return EncodingUTF8;
1133 PUGI__FN
Encoding GetBuffer_DocumentEncoding(
Encoding DocumentEncoding,
const void* contents,
size_t size)
1136 if (DocumentEncoding ==
Encodingwchar_t)
return GetWchar_DocumentEncoding();
1145 if (DocumentEncoding !=
EncodingAuto)
return DocumentEncoding;
1151 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
1153 PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1155 return guess_buffer_DocumentEncoding(d0, d1, d2, d3);
1158 PUGI__FN
bool GetMutable_buffer(
Char8*& out_buffer,
size_t& out_length,
const void* contents,
size_t size,
bool is_mutable)
1162 out_buffer =
static_cast<Char8*
>(
const_cast<void*
>(contents));
1166 void* buffer = Memory::allocate(size > 0 ? size : 1);
1167 if (!buffer)
return false;
1169 memcpy(buffer, contents, size);
1171 out_buffer =
static_cast<Char8*
>(buffer);
1174 out_length = size /
sizeof(
Char8);
1179 template <
typename opt_swap> PUGI__FN
bool convert_buffer_utf16(
Char8*& out_buffer,
size_t& out_length,
const void* contents,
size_t size, opt_swap)
1181 const uint16_t* data =
static_cast<const uint16_t*
>(contents);
1182 size_t length = size /
sizeof(uint16_t);
1185 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, length, 0);
1188 out_buffer =
static_cast<Char8*
>(Memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(
Char8)));
1189 if (!out_buffer)
return false;
1192 uint8_t* out_begin =
reinterpret_cast<uint8_t*
>(out_buffer);
1193 uint8_t* out_end = utf_decoder<utf8_WriterInstance, opt_swap>::decode_utf16_block(data, length, out_begin);
1195 assert(out_end == out_begin + out_length);
1201 template <
typename opt_swap> PUGI__FN
bool convert_buffer_utf32(
Char8*& out_buffer,
size_t& out_length,
const void* contents,
size_t size, opt_swap)
1203 const uint32_t* data =
static_cast<const uint32_t*
>(contents);
1204 size_t length = size /
sizeof(uint32_t);
1207 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, length, 0);
1210 out_buffer =
static_cast<Char8*
>(Memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(
Char8)));
1211 if (!out_buffer)
return false;
1214 uint8_t* out_begin =
reinterpret_cast<uint8_t*
>(out_buffer);
1215 uint8_t* out_end = utf_decoder<utf8_WriterInstance, opt_swap>::decode_utf32_block(data, length, out_begin);
1217 assert(out_end == out_begin + out_length);
1223 PUGI__FN
size_t GetLatin1_7bit_prefix_length(
const uint8_t* data,
size_t size)
1225 for (
size_t i = 0; i < size; ++i)
1232 PUGI__FN
bool convert_buffer_latin1(
Char8*& out_buffer,
size_t& out_length,
const void* contents,
size_t size,
bool is_mutable)
1234 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
1237 size_t prefix_length = GetLatin1_7bit_prefix_length(data, size);
1238 assert(prefix_length <= size);
1240 const uint8_t* postfix = data + prefix_length;
1241 size_t postfix_length = size - prefix_length;
1244 if (postfix_length == 0)
return GetMutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1247 out_length = prefix_length + utf_decoder<utf8_counter>::decode_latin1_block(postfix, postfix_length, 0);
1250 out_buffer =
static_cast<Char8*
>(Memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(
Char8)));
1251 if (!out_buffer)
return false;
1254 memcpy(out_buffer, data, prefix_length);
1256 uint8_t* out_begin =
reinterpret_cast<uint8_t*
>(out_buffer);
1257 uint8_t* out_end = utf_decoder<utf8_WriterInstance>::decode_latin1_block(postfix, postfix_length, out_begin + prefix_length);
1259 assert(out_end == out_begin + out_length);
1265 PUGI__FN
bool convert_buffer(
Char8*& out_buffer,
size_t& out_length,
Encoding DocumentEncoding,
const void* contents,
size_t size,
bool is_mutable)
1268 if (DocumentEncoding ==
EncodingUTF8)
return GetMutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1275 return (native_DocumentEncoding == DocumentEncoding) ?
1276 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
1277 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1285 return (native_DocumentEncoding == DocumentEncoding) ?
1286 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
1287 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1291 if (DocumentEncoding ==
EncodingLatin1)
return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
1293 assert(!
"Invalid DocumentEncoding");
1298 PUGI__FN
size_t AsUtf8_begin(
const wchar_t* str,
size_t length)
1301 return utf_decoder<utf8_counter>::decode_wchar_block(str, length, 0);
1304 PUGI__FN
void AsUtf8_end(
char* buffer,
size_t size,
const wchar_t* str,
size_t length)
1307 uint8_t* begin =
reinterpret_cast<uint8_t*
>(buffer);
1308 uint8_t* end = utf_decoder<utf8_WriterInstance>::decode_wchar_block(str, length, begin);
1310 assert(begin + size == end);
1318 PUGI__FN std::string AsUtf8_impl(
const wchar_t* str,
size_t length)
1321 size_t size = AsUtf8_begin(str, length);
1325 Result.resize(size);
1328 if (size > 0) AsUtf8_end(&Result[0], size, str, length);
1333 PUGI__FN std::basic_string<wchar_t> AsWide_impl(
const char* str,
size_t size)
1335 const uint8_t* data =
reinterpret_cast<const uint8_t*
>(str);
1338 size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
1341 std::basic_string<wchar_t> Result;
1342 Result.resize(length);
1347 wchar_WriterInstance::value_type begin =
reinterpret_cast<wchar_WriterInstance::value_type
>(&Result[0]);
1348 wchar_WriterInstance::value_type end = utf_decoder<wchar_WriterInstance>::decode_utf8_block(data, size, begin);
1350 assert(begin + length == end);
1358 inline bool strcpy_insitu_allow(
size_t length, uintptr_t allocated,
Char8* target)
1361 size_t tarGetLength = strlength(target);
1364 if (!allocated)
return tarGetLength >= length;
1367 const size_t reuse_threshold = 32;
1369 return tarGetLength >= length && (tarGetLength < reuse_threshold || tarGetLength - length < tarGetLength / 2);
1372 PUGI__FN
bool strcpy_insitu(
Char8*& dest, uintptr_t& header, uintptr_t header_mask,
const Char8* source)
1374 size_t source_length = strlength(source);
1376 if (source_length == 0)
1379 Allocator* alloc =
reinterpret_cast<MemoryPage*
>(header & MemoryPage_pointer_mask)->allocator;
1381 if (header & header_mask) alloc->deallocate_string(dest);
1385 header &= ~header_mask;
1389 else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest))
1392 memcpy(dest, source, (source_length + 1) *
sizeof(
Char8));
1398 Allocator* alloc =
reinterpret_cast<MemoryPage*
>(header & MemoryPage_pointer_mask)->allocator;
1401 Char8* buf = alloc->allocate_string(source_length + 1);
1402 if (!buf)
return false;
1405 memcpy(buf, source, (source_length + 1) *
sizeof(
Char8));
1408 if (header & header_mask) alloc->deallocate_string(dest);
1412 header |= header_mask;
1423 gap(): end(0), size(0)
1429 void push(
Char8*& s,
size_t count)
1435 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
1452 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
1460 PUGI__FN
Char8* strconv_escape(
Char8* s, gap& g)
1462 Char8* stre = s + 1;
1468 unsigned int ucsc = 0;
1476 if (ch ==
';')
return stre;
1480 if (static_cast<unsigned int>(ch -
'0') <= 9)
1481 ucsc = 16 * ucsc + (ch -
'0');
1482 else if (static_cast<unsigned int>((ch |
' ') -
'a') <= 5)
1483 ucsc = 16 * ucsc + ((ch |
' ') -
'a' + 10);
1498 if (ch ==
';')
return stre;
1502 if (static_cast<unsigned int>(ch -
'0') <= 9)
1503 ucsc = 10 * ucsc + (ch -
'0');
1516 s =
reinterpret_cast<Char8*
>(utf8_WriterInstance::any(reinterpret_cast<uint8_t*>(s), ucsc));
1519 g.push(s, stre - s);
1529 if (*++stre ==
'p' && *++stre ==
';')
1534 g.push(s, stre - s);
1538 else if (*stre ==
'p')
1540 if (*++stre ==
'o' && *++stre ==
's' && *++stre ==
';')
1545 g.push(s, stre - s);
1554 if (*++stre ==
't' && *++stre ==
';')
1559 g.push(s, stre - s);
1567 if (*++stre ==
't' && *++stre ==
';')
1572 g.push(s, stre - s);
1580 if (*++stre ==
'u' && *++stre ==
'o' && *++stre ==
't' && *++stre ==
';')
1585 g.push(s, stre - s);
1599 #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
1607 while (!PUGI__IS_CHARTYPE(*s, ct_ParseComment)) ++s;
1613 if (*s ==
'\n') g.push(s, 1);
1615 else if (s[0] ==
'-' && s[1] ==
'-' && ENDSWITH(s[2],
'>'))
1619 return s + (s[2] ==
'>' ? 3 : 2);
1635 while (!PUGI__IS_CHARTYPE(*s, ct_ParseCdata)) ++s;
1641 if (*s ==
'\n') g.push(s, 1);
1643 else if (s[0] ==
']' && s[1] ==
']' && ENDSWITH(s[2],
'>'))
1659 template <
typename opt_eol,
typename opt_escape>
struct strconv_pcdata_impl
1667 while (!PUGI__IS_CHARTYPE(*s, ct_ParsePcdata)) ++s;
1675 else if (opt_eol::Value && *s ==
'\r')
1679 if (*s ==
'\n') g.push(s, 1);
1681 else if (opt_escape::Value && *s ==
'&')
1683 s = strconv_escape(s, g);
1694 PUGI__FN strconv_pcdata_t GetStrconv_pcdata(
unsigned int optmask)
1698 switch ((optmask >> 4) & 3)
1700 case 0:
return strconv_pcdata_impl<opt_false, opt_false>::parse;
1701 case 1:
return strconv_pcdata_impl<opt_false, opt_true>::parse;
1702 case 2:
return strconv_pcdata_impl<opt_true, opt_false>::parse;
1703 case 3:
return strconv_pcdata_impl<opt_true, opt_true>::parse;
1710 template <
typename opt_escape>
struct strconv_attribute_impl
1717 if (PUGI__IS_CHARTYPE(*s, ct_space))
1722 while (PUGI__IS_CHARTYPE(*str, ct_space));
1729 while (!PUGI__IS_CHARTYPE(*s, ct_ParseAttrWs | ct_space)) ++s;
1731 if (*s == end_quote)
1733 Char8* str = g.flush(s);
1736 while (PUGI__IS_CHARTYPE(*str, ct_space));
1740 else if (PUGI__IS_CHARTYPE(*s, ct_space))
1744 if (PUGI__IS_CHARTYPE(*s, ct_space))
1747 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
1752 else if (opt_escape::Value && *s ==
'&')
1754 s = strconv_escape(s, g);
1770 while (!PUGI__IS_CHARTYPE(*s, ct_ParseAttrWs)) ++s;
1772 if (*s == end_quote)
1778 else if (PUGI__IS_CHARTYPE(*s, ct_space))
1784 if (*s ==
'\n') g.push(s, 1);
1788 else if (opt_escape::Value && *s ==
'&')
1790 s = strconv_escape(s, g);
1806 while (!PUGI__IS_CHARTYPE(*s, ct_ParseAttr)) ++s;
1808 if (*s == end_quote)
1814 else if (*s ==
'\r')
1818 if (*s ==
'\n') g.push(s, 1);
1820 else if (opt_escape::Value && *s ==
'&')
1822 s = strconv_escape(s, g);
1838 while (!PUGI__IS_CHARTYPE(*s, ct_ParseAttr)) ++s;
1840 if (*s == end_quote)
1846 else if (opt_escape::Value && *s ==
'&')
1848 s = strconv_escape(s, g);
1859 PUGI__FN strconv_attribute_t GetStrconv_attribute(
unsigned int optmask)
1863 switch ((optmask >> 4) & 15)
1865 case 0:
return strconv_attribute_impl<opt_false>::ParseSimple;
1866 case 1:
return strconv_attribute_impl<opt_true>::ParseSimple;
1869 case 4:
return strconv_attribute_impl<opt_false>::ParseWconv;
1870 case 5:
return strconv_attribute_impl<opt_true>::ParseWconv;
1871 case 6:
return strconv_attribute_impl<opt_false>::ParseWconv;
1872 case 7:
return strconv_attribute_impl<opt_true>::ParseWconv;
1873 case 8:
return strconv_attribute_impl<opt_false>::ParseWnorm;
1874 case 9:
return strconv_attribute_impl<opt_true>::ParseWnorm;
1875 case 10:
return strconv_attribute_impl<opt_false>::ParseWnorm;
1876 case 11:
return strconv_attribute_impl<opt_true>::ParseWnorm;
1877 case 12:
return strconv_attribute_impl<opt_false>::ParseWnorm;
1878 case 13:
return strconv_attribute_impl<opt_true>::ParseWnorm;
1879 case 14:
return strconv_attribute_impl<opt_false>::ParseWnorm;
1880 case 15:
return strconv_attribute_impl<opt_true>::ParseWnorm;
1885 inline ParseResult make_ParseResult(
ParseStatus Status, ptrdiff_t Offset = 0)
1888 Result.Status = Status;
1889 Result.Offset = Offset;
1897 Char8* error_Offset;
1901 #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
1902 #define PUGI__OPTSET(OPT) ( optmsk & (OPT) )
1903 #define PUGI__PUSHNODE(TYPE) { cursor = AppendNode(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(StatusOutOfMemory, s); }
1904 #define PUGI__POPNODE() { cursor = cursor->GetParent; }
1905 #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
1906 #define PUGI__SCANWHILE(X) { while ((X)) ++s; }
1907 #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; }
1908 #define PUGI__THROW_ERROR(err, m) return error_Offset = m, error_Status = err, static_cast<Char8*>(0)
1909 #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); }
1911 Parser(
const Allocator& alloc_): alloc(alloc_), error_Offset(0), error_Status(
StatusOk)
1924 if (*s ==
'"' || *s ==
'\'')
1928 PUGI__SCANFOR(*s == ch);
1933 else if (s[0] ==
'<' && s[1] ==
'?')
1937 PUGI__SCANFOR(s[0] ==
'?' && s[1] ==
'>');
1942 else if (s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'-' && s[3] ==
'-')
1945 PUGI__SCANFOR(s[0] ==
'-' && s[1] ==
'-' && s[2] ==
'>');
1957 assert(s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'[');
1962 if (s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'[')
1965 s = ParseDocTypeIgnore(s);
1968 else if (s[0] ==
']' && s[1] ==
']' && s[2] ==
'>')
1983 assert(s[0] ==
'<' && s[1] ==
'!');
1988 if (s[0] ==
'<' && s[1] ==
'!' && s[2] !=
'-')
1993 s = ParseDocTypeIgnore(s);
1999 s = ParseDocTypeGroup(s, endch,
false);
2003 else if (s[0] ==
'<' || s[0] ==
'"' || s[0] ==
'\'')
2006 s = ParseDocTypePrimitive(s);
2023 Char8* ParseExclamation(
Char8* s, NodeStruct* cursor,
unsigned int optmsk,
Char8 endch)
2044 s = strconv_comment(s, endch);
2051 PUGI__SCANFOR(s[0] ==
'-' && s[1] ==
'-' && ENDSWITH(s[2],
'>'));
2057 s += (s[2] ==
'>' ? 3 : 2);
2065 if (*++s==
'C' && *++s==
'D' && *++s==
'A' && *++s==
'T' && *++s==
'A' && *++s ==
'[')
2076 s = strconv_cdata(s, endch);
2083 PUGI__SCANFOR(s[0] ==
']' && s[1] ==
']' && ENDSWITH(s[2],
'>'));
2092 PUGI__SCANFOR(s[0] ==
']' && s[1] ==
']' && ENDSWITH(s[2],
'>'));
2098 s += (s[1] ==
'>' ? 2 : 1);
2102 else if (s[0] ==
'D' && s[1] ==
'O' && s[2] ==
'C' && s[3] ==
'T' && s[4] ==
'Y' && s[5] ==
'P' && ENDSWITH(s[6],
'E'))
2108 Char8* mark = s + 9;
2110 s = ParseDocTypeGroup(s, endch,
true);
2115 while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
2119 cursor->Value = mark;
2121 assert((s[0] == 0 && endch ==
'>') || s[-1] ==
'>');
2122 s[*s == 0 ? 0 : -1] = 0;
2128 else if (*s == 0 && endch ==
'[') PUGI__THROW_ERROR(
StatusBadCdata, s);
2134 Char8* ParseQuestion(
Char8* s, NodeStruct*& ref_cursor,
unsigned int optmsk,
Char8 endch)
2137 NodeStruct* cursor = ref_cursor;
2148 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
2152 bool declaration = (target[0] |
' ') ==
'x' && (target[1] |
' ') ==
'm' && (target[2] |
' ') ==
'l' && target + 3 == s;
2168 cursor->Name = target;
2181 else if (PUGI__IS_CHARTYPE(ch, ct_space))
2188 PUGI__SCANFOR(s[0] ==
'?' && ENDSWITH(s[1],
'>'));
2202 cursor->Value = Value;
2215 PUGI__SCANFOR(s[0] ==
'?' && ENDSWITH(s[1],
'>'));
2218 s += (s[1] ==
'>' ? 2 : 1);
2222 ref_cursor = cursor;
2227 Char8* parse(
Char8* s, NodeStruct* xmldoc,
unsigned int optmsk,
Char8 endch)
2229 strconv_attribute_t strconv_attribute = GetStrconv_attribute(optmsk);
2230 strconv_pcdata_t strconv_pcdata = GetStrconv_pcdata(optmsk);
2233 NodeStruct* cursor = xmldoc;
2243 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
2249 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
2256 else if (PUGI__IS_CHARTYPE(ch, ct_space))
2263 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
2265 AttributeStruct* a = AppendAttribute_ll(cursor, alloc);
2270 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
2276 if (PUGI__IS_CHARTYPE(ch, ct_space))
2289 if (*s ==
'"' || *s ==
'\'')
2295 s = strconv_attribute(s, ch);
2302 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(
StatusBadAttribute, s);
2318 else if (*s == 0 && endch ==
'>')
2331 else if (*s == 0 && endch ==
'>')
2361 Char8* Name = cursor->Name;
2364 while (PUGI__IS_CHARTYPE(*s, ct_symbol))
2371 if (*s == 0 && Name[0] == endch && Name[1] == 0) PUGI__THROW_ERROR(
StatusBadEndElement, s);
2391 s = ParseQuestion(s, cursor, optmsk, endch);
2395 if ((cursor->header & MemoryPage_type_mask) + 1 ==
NodeDeclaration)
goto LOC_ATTRIBUTES;
2399 s = ParseExclamation(s, cursor, optmsk, endch);
2422 if (s[1] !=
'/' || cursor->GetFirstChild)
continue;
2428 if (cursor->GetParent)
2433 s = strconv_pcdata(s);
2441 PUGI__SCANFOR(*s ==
'<');
2458 static ParseResult parse(
Char8* buffer,
size_t length, NodeStruct* GetRoot,
unsigned int optmsk)
2460 DocumentStruct* xmldoc =
static_cast<DocumentStruct*
>(GetRoot);
2463 xmldoc->buffer = buffer;
2466 if (length == 0)
return make_ParseResult(
StatusOk);
2469 Parser parser(*xmldoc);
2472 Char8 endch = buffer[length - 1];
2473 buffer[length - 1] = 0;
2476 parser.parse(buffer, xmldoc, optmsk, endch);
2478 ParseResult Result = make_ParseResult(parser.error_Status, parser.error_Offset ? parser.error_Offset - buffer : 0);
2479 assert(Result.Offset >= 0 && static_cast<size_t>(Result.Offset) <= length);
2482 *
static_cast<Allocator*
>(xmldoc) = parser.alloc;
2485 if (Result && endch ==
'<')
2496 PUGI__FN
Encoding GetWrite_native_DocumentEncoding()
2504 if (DocumentEncoding ==
Encodingwchar_t)
return GetWchar_DocumentEncoding();
2513 if (DocumentEncoding !=
EncodingAuto)
return DocumentEncoding;
2519 PUGI__FN
size_t GetValid_length(
const Char8* data,
size_t length)
2523 for (
size_t i = 1; i <= 4; ++i)
2525 uint8_t ch =
static_cast<uint8_t
>(data[length - i]);
2528 if ((ch & 0xc0) != 0x80)
return length - i;
2535 PUGI__FN
size_t convert_buffer(
Char8* , uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32,
const Char8* data,
size_t length,
Encoding DocumentEncoding)
2539 uint16_t* dest = r_u16;
2542 uint16_t* end = utf_decoder<utf16_WriterInstance>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2547 if (native_DocumentEncoding != DocumentEncoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2549 return static_cast<size_t>(end - dest) *
sizeof(uint16_t);
2554 uint32_t* dest = r_u32;
2557 uint32_t* end = utf_decoder<utf32_WriterInstance>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2562 if (native_DocumentEncoding != DocumentEncoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2564 return static_cast<size_t>(end - dest) *
sizeof(uint32_t);
2569 uint8_t* dest = r_u8;
2570 uint8_t* end = utf_decoder<latin1_WriterInstance>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2572 return static_cast<size_t>(end - dest);
2575 assert(!
"Invalid DocumentEncoding");
2580 class BufferedWriter
2582 BufferedWriter(
const BufferedWriter&);
2583 BufferedWriter& operator=(
const BufferedWriter&);
2586 BufferedWriter(Writer& WriterInstance_,
Encoding user_DocumentEncoding): WriterInstance(WriterInstance_), bufsize(0), DocumentEncoding(GetWrite_DocumentEncoding(user_DocumentEncoding))
2588 PUGI__STATIC_ASSERT(bufcapacity >= 8);
2598 flush(buffer, bufsize);
2602 void flush(
const Char8* data,
size_t size)
2604 if (size == 0)
return;
2607 if (DocumentEncoding == GetWrite_native_DocumentEncoding())
2608 WriterInstance.Write(data, size *
sizeof(
Char8));
2612 size_t Result = convert_buffer(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, DocumentEncoding);
2613 assert(Result <=
sizeof(scratch));
2616 WriterInstance.Write(scratch.data_u8, Result);
2620 void Write(
const Char8* data,
size_t length)
2622 if (bufsize + length > bufcapacity)
2628 if (length > bufcapacity)
2630 if (DocumentEncoding == GetWrite_native_DocumentEncoding())
2633 WriterInstance.Write(data, length *
sizeof(
Char8));
2638 while (length > bufcapacity)
2642 size_t chunk_size = GetValid_length(data, bufcapacity);
2645 flush(data, chunk_size);
2649 length -= chunk_size;
2657 memcpy(buffer + bufsize, data, length *
sizeof(
Char8));
2661 void Write(
const Char8* data)
2663 Write(data, strlength(data));
2666 void Write(
Char8 d0)
2668 if (bufsize + 1 > bufcapacity) flush();
2670 buffer[bufsize + 0] = d0;
2676 if (bufsize + 2 > bufcapacity) flush();
2678 buffer[bufsize + 0] = d0;
2679 buffer[bufsize + 1] = d1;
2685 if (bufsize + 3 > bufcapacity) flush();
2687 buffer[bufsize + 0] = d0;
2688 buffer[bufsize + 1] = d1;
2689 buffer[bufsize + 2] = d2;
2695 if (bufsize + 4 > bufcapacity) flush();
2697 buffer[bufsize + 0] = d0;
2698 buffer[bufsize + 1] = d1;
2699 buffer[bufsize + 2] = d2;
2700 buffer[bufsize + 3] = d3;
2706 if (bufsize + 5 > bufcapacity) flush();
2708 buffer[bufsize + 0] = d0;
2709 buffer[bufsize + 1] = d1;
2710 buffer[bufsize + 2] = d2;
2711 buffer[bufsize + 3] = d3;
2712 buffer[bufsize + 4] = d4;
2718 if (bufsize + 6 > bufcapacity) flush();
2720 buffer[bufsize + 0] = d0;
2721 buffer[bufsize + 1] = d1;
2722 buffer[bufsize + 2] = d2;
2723 buffer[bufsize + 3] = d3;
2724 buffer[bufsize + 4] = d4;
2725 buffer[bufsize + 5] = d5;
2735 #ifdef XML_MEMORY_OUTPUT_STACK
2736 XML_MEMORY_OUTPUT_STACK
2741 bufcapacity = bufcapacitybytes / (
sizeof(
Char8) + 4)
2744 Char8 buffer[bufcapacity];
2748 uint8_t data_u8[4 * bufcapacity];
2749 uint16_t data_u16[2 * bufcapacity];
2750 uint32_t data_u32[bufcapacity];
2751 Char8 data_char[bufcapacity];
2754 Writer& WriterInstance;
2759 PUGI__FN
void text_output_escaped(BufferedWriter& WriterInstance,
const Char8* s, charTypex_t Type)
2763 const Char8* prev = s;
2766 while (!PUGI__IS_CHARTYPEX(*s, Type)) ++s;
2768 WriterInstance.Write(prev, static_cast<size_t>(s - prev));
2774 WriterInstance.Write(
'&',
'a',
'm',
'p',
';');
2778 WriterInstance.Write(
'&',
'l',
't',
';');
2782 WriterInstance.Write(
'&',
'g',
't',
';');
2786 WriterInstance.Write(
'&',
'q',
'u',
'o',
't',
';');
2791 unsigned int ch =
static_cast<unsigned int>(*s++);
2794 WriterInstance.Write(
'&',
'#', static_cast<Char8>((ch / 10) +
'0'), static_cast<Char8>((ch % 10) +
'0'),
';');
2800 PUGI__FN
void text_output(BufferedWriter& WriterInstance,
const Char8* s, charTypex_t Type,
unsigned int flags)
2803 WriterInstance.Write(s);
2805 text_output_escaped(WriterInstance, s, Type);
2808 PUGI__FN
void text_output_cdata(BufferedWriter& WriterInstance,
const Char8* s)
2812 WriterInstance.Write(
'<',
'!',
'[',
'C',
'D');
2813 WriterInstance.Write(
'A',
'T',
'A',
'[');
2815 const Char8* prev = s;
2818 while (*s && !(s[0] ==
']' && s[1] ==
']' && s[2] ==
'>')) ++s;
2823 WriterInstance.Write(prev, static_cast<size_t>(s - prev));
2825 WriterInstance.Write(
']',
']',
'>');
2830 PUGI__FN
void NodeOutput_attributes(BufferedWriter& WriterInstance,
const Node& node,
unsigned int flags)
2832 const Char8* default_Name =
":anonymous";
2834 for (Attribute a = node.GetFirstAttribute(); a; a = a.GetNextAttribute())
2836 WriterInstance.Write(
' ');
2837 WriterInstance.Write(a.Name()[0] ? a.Name() : default_Name);
2838 WriterInstance.Write(
'=',
'"');
2840 text_output(WriterInstance, a.Value(), ctx_special_attr, flags);
2842 WriterInstance.Write(
'"');
2846 PUGI__FN
void NodeOutput(BufferedWriter& WriterInstance,
const Node& node,
const Char8* indent,
unsigned int flags,
unsigned int Depth)
2848 const Char8* default_Name =
":anonymous";
2851 for (
unsigned int i = 0; i < Depth; ++i) WriterInstance.Write(indent);
2853 switch (node.Type())
2857 for (Node n = node.GetFirstChild(); n; n = n.GetNextSibling())
2858 NodeOutput(WriterInstance, n, indent, flags, Depth);
2864 const Char8* Name = node.Name()[0] ? node.Name() : default_Name;
2866 WriterInstance.Write(
'<');
2867 WriterInstance.Write(Name);
2869 NodeOutput_attributes(WriterInstance, node, flags);
2871 if (flags & FormatRaw)
2873 if (!node.GetFirstChild())
2874 WriterInstance.Write(
' ',
'/',
'>');
2877 WriterInstance.Write(
'>');
2879 for (Node n = node.GetFirstChild(); n; n = n.GetNextSibling())
2880 NodeOutput(WriterInstance, n, indent, flags, Depth + 1);
2882 WriterInstance.Write(
'<',
'/');
2883 WriterInstance.Write(Name);
2884 WriterInstance.Write(
'>');
2887 else if (!node.GetFirstChild())
2888 WriterInstance.Write(
' ',
'/',
'>',
'\n');
2889 else if (node.GetFirstChild() == node.GetLastChild() && (node.GetFirstChild().Type() ==
NodePcdata || node.GetFirstChild().Type() ==
NodeCdata))
2891 WriterInstance.Write(
'>');
2893 if (node.GetFirstChild().Type() ==
NodePcdata)
2894 text_output(WriterInstance, node.GetFirstChild().Value(), ctx_special_pcdata, flags);
2896 text_output_cdata(WriterInstance, node.GetFirstChild().Value());
2898 WriterInstance.Write(
'<',
'/');
2899 WriterInstance.Write(Name);
2900 WriterInstance.Write(
'>',
'\n');
2904 WriterInstance.Write(
'>',
'\n');
2906 for (Node n = node.GetFirstChild(); n; n = n.GetNextSibling())
2907 NodeOutput(WriterInstance, n, indent, flags, Depth + 1);
2909 if ((flags & FormatIndent) != 0 && (flags &
FormatRaw) == 0)
2910 for (
unsigned int i = 0; i < Depth; ++i) WriterInstance.Write(indent);
2912 WriterInstance.Write(
'<',
'/');
2913 WriterInstance.Write(Name);
2914 WriterInstance.Write(
'>',
'\n');
2921 text_output(WriterInstance, node.Value(), ctx_special_pcdata, flags);
2922 if ((flags & FormatRaw) == 0) WriterInstance.Write(
'\n');
2926 text_output_cdata(WriterInstance, node.Value());
2927 if ((flags & FormatRaw) == 0) WriterInstance.Write(
'\n');
2931 WriterInstance.Write(
'<',
'!',
'-',
'-');
2932 WriterInstance.Write(node.Value());
2933 WriterInstance.Write(
'-',
'-',
'>');
2934 if ((flags & FormatRaw) == 0) WriterInstance.Write(
'\n');
2939 WriterInstance.Write(
'<',
'?');
2940 WriterInstance.Write(node.Name()[0] ? node.Name() : default_Name);
2944 NodeOutput_attributes(WriterInstance, node, flags);
2946 else if (node.Value()[0])
2948 WriterInstance.Write(
' ');
2949 WriterInstance.Write(node.Value());
2952 WriterInstance.Write(
'?',
'>');
2953 if ((flags & FormatRaw) == 0) WriterInstance.Write(
'\n');
2957 WriterInstance.Write(
'<',
'!',
'D',
'O',
'C');
2958 WriterInstance.Write(
'T',
'Y',
'P',
'E');
2960 if (node.Value()[0])
2962 WriterInstance.Write(
' ');
2963 WriterInstance.Write(node.Value());
2966 WriterInstance.Write(
'>');
2967 if ((flags & FormatRaw) == 0) WriterInstance.Write(
'\n');
2971 assert(!
"Invalid node Type");
2975 inline bool hAsDeclaration(
const Node& node)
2977 for (Node GetChild = node.GetFirstChild(); GetChild; GetChild = GetChild.GetNextSibling())
2997 PUGI__FN
void recursive_copy_skip(Node& dest,
const Node& source,
const Node& skip)
2999 assert(dest.Type() == source.Type());
3001 switch (source.Type())
3005 dest.SetName(source.Name());
3007 for (Attribute a = source.GetFirstAttribute(); a; a = a.GetNextAttribute())
3008 dest.AppendAttribute(a.Name()).SetValue(a.Value());
3010 for (Node c = source.GetFirstChild(); c; c = c.GetNextSibling())
3012 if (c == skip)
continue;
3014 Node cc = dest.AppendChild(c.Type());
3017 recursive_copy_skip(cc, c, skip);
3027 dest.SetValue(source.Value());
3031 dest.SetName(source.Name());
3032 dest.SetValue(source.Value());
3037 dest.SetName(source.Name());
3039 for (Attribute a = source.GetFirstAttribute(); a; a = a.GetNextAttribute())
3040 dest.AppendAttribute(a.Name()).SetValue(a.Value());
3046 assert(!
"Invalid node Type");
3050 inline bool is_text_node(NodeStruct* node)
3052 NodeType Type =
static_cast<NodeType>((node->header & internal::MemoryPage_type_mask) + 1);
3058 PUGI__FN
int GetValue_int(
const Char8* Value,
int def)
3060 if (!Value)
return def;
3062 return static_cast<int>(strtol(Value, 0, 10));
3065 PUGI__FN
unsigned int GetValue_uint(
const Char8* Value,
unsigned int def)
3067 if (!Value)
return def;
3069 return static_cast<unsigned int>(strtoul(Value, 0, 10));
3072 PUGI__FN
double GetValue_double(
const Char8* Value,
double def)
3074 if (!Value)
return def;
3076 return strtod(Value, 0);
3079 PUGI__FN
float GetValue_float(
const Char8* Value,
float def)
3081 if (!Value)
return def;
3083 return static_cast<float>(strtod(Value, 0));
3086 PUGI__FN
bool GetValue_bool(
const Char8* Value,
bool def)
3088 if (!Value)
return def;
3091 Char8 first = *Value;
3094 return (first ==
'1' || first ==
't' || first ==
'T' || first ==
'y' || first ==
'Y');
3098 PUGI__FN
bool SetValue_buffer(
Char8*& dest, uintptr_t& header, uintptr_t header_mask,
char (&buf)[128])
3100 return strcpy_insitu(dest, header, header_mask, buf);
3103 PUGI__FN
bool SetValue_convert(
Char8*& dest, uintptr_t& header, uintptr_t header_mask,
int Value)
3106 sprintf(buf,
"%d", Value);
3108 return SetValue_buffer(dest, header, header_mask, buf);
3111 PUGI__FN
bool SetValue_convert(
Char8*& dest, uintptr_t& header, uintptr_t header_mask,
unsigned int Value)
3114 sprintf(buf,
"%u", Value);
3116 return SetValue_buffer(dest, header, header_mask, buf);
3119 PUGI__FN
bool SetValue_convert(
Char8*& dest, uintptr_t& header, uintptr_t header_mask,
double Value)
3122 sprintf(buf,
"%g", Value);
3124 return SetValue_buffer(dest, header, header_mask, buf);
3127 PUGI__FN
bool SetValue_convert(
Char8*& dest, uintptr_t& header, uintptr_t header_mask,
bool Value)
3129 return strcpy_insitu(dest, header, header_mask, Value ?
"true" :
"false");
3133 PUGI__FN
ParseStatus GetFile_size(FILE* file,
size_t& out_Result)
3136 typedef long length_type;
3138 fseek(file, 0, SEEK_END);
3139 length_type length = ftell(file);
3140 fseek(file, 0, SEEK_SET);
3146 size_t Result =
static_cast<size_t>(length);
3151 out_Result = Result;
3161 size_t length = stream.
GetSize() - pos;
3165 buffer_holder buffer(Memory::allocate(stream.
GetSize() > 0 ? length : 1), Memory::deallocate);
3168 size_t actual_length = stream.
Read(buffer.data, length);
3169 assert(actual_length <= length);
3171 return doc.LoadBufferInplaceOwn(buffer.release(), actual_length, options, DocumentEncoding);
3174 PUGI__FN ParseResult LoadFileImpl(Document& doc, FILE* file,
unsigned int options,
Encoding DocumentEncoding)
3180 ParseStatus size_Status = GetFile_size(file, size);
3185 return make_ParseResult(size_Status);
3189 char* contents =
static_cast<char*
>(Memory::allocate(size > 0 ? size : 1));
3198 size_t read_size = fread(contents, 1, size, file);
3201 if (read_size != size)
3203 Memory::deallocate(contents);
3207 return doc.LoadBufferInplaceOwn(contents, size, options, DocumentEncoding);
3210 template <
typename T>
struct StreamChunk
3212 static StreamChunk* create()
3214 void* memory = Memory::allocate(
sizeof(StreamChunk));
3216 return new (memory) StreamChunk();
3219 static void destroy(
void* ptr)
3221 StreamChunk* chunk =
static_cast<StreamChunk*
>(ptr);
3226 StreamChunk* next = chunk->next;
3227 Memory::deallocate(chunk);
3232 StreamChunk(): next(0), size(0)
3239 T data[MemoryPage_size /
sizeof(T)];
3242 template <
typename T> PUGI__FN
ParseStatus LoadStreamDataNoseek(std::basic_istream<T>& stream,
void** out_buffer,
size_t* out_size)
3244 buffer_holder chunks(0, StreamChunk<T>::destroy);
3248 StreamChunk<T>* last = 0;
3250 while (!stream.eof())
3253 StreamChunk<T>* chunk = StreamChunk<T>::create();
3257 if (last) last = last->next = chunk;
3258 else chunks.data = last = chunk;
3261 stream.read(chunk->data, static_cast<std::streamsize>(
sizeof(chunk->data) /
sizeof(T)));
3262 chunk->size =
static_cast<size_t>(stream.gcount()) *
sizeof(T);
3265 if (stream.bad() || (!stream.eof() && stream.fail()))
return StatusIOError;
3269 total += chunk->size;
3273 char* buffer =
static_cast<char*
>(Memory::allocate(total));
3276 char* Write = buffer;
3278 for (StreamChunk<T>* chunk =
static_cast<StreamChunk<T>*
>(chunks.data); chunk; chunk = chunk->next)
3280 assert(Write + chunk->size <= buffer + total);
3281 memcpy(Write, chunk->data, chunk->size);
3282 Write += chunk->size;
3285 assert(Write == buffer + total);
3288 *out_buffer = buffer;
3294 template <
typename T> PUGI__FN
ParseStatus LoadStreamDataSeek(std::basic_istream<T>& stream,
void** out_buffer,
size_t* out_size)
3297 typename std::basic_istream<T>::pos_type pos = stream.tellg();
3298 stream.seekg(0, std::ios::end);
3299 std::streamoff length = stream.tellg() - pos;
3305 size_t read_length =
static_cast<size_t>(length);
3307 if (static_cast<std::streamsize>(read_length) != length || length < 0)
return StatusOutOfMemory;
3310 buffer_holder buffer(Memory::allocate((read_length > 0 ? read_length : 1) *
sizeof(T)), Memory::deallocate);
3313 stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
3316 if (stream.bad() || (!stream.eof() && stream.fail()))
return StatusIOError;
3319 size_t actual_length =
static_cast<size_t>(stream.gcount());
3320 assert(actual_length <= read_length);
3322 *out_buffer = buffer.release();
3323 *out_size = actual_length *
sizeof(T);
3328 template <
typename T> PUGI__FN ParseResult LoadStreamImpl(Document& doc, std::basic_istream<T>& stream,
unsigned int options,
Encoding DocumentEncoding)
3334 ParseStatus Status = (stream.tellg() < 0) ? LoadStreamDataNoseek(stream, &buffer, &size) : LoadStreamDataSeek(stream, &buffer, &size);
3335 if (Status !=
StatusOk)
return make_ParseResult(Status);
3337 return doc.LoadBufferInplaceOwn(buffer, size, options, DocumentEncoding);
3341 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__))
3342 PUGI__FN FILE* open_file_wide(
const wchar_t* Path,
const wchar_t* mode)
3344 return _wfopen(Path, mode);
3347 PUGI__FN
char* convert_Path_heap(
const wchar_t* str)
3352 size_t length = wcslen(str);
3353 size_t size = AsUtf8_begin(str, length);
3356 char* Result =
static_cast<char*
>(Memory::allocate(size + 1));
3357 if (!Result)
return 0;
3360 AsUtf8_end(Result, size, str, length);
3365 PUGI__FN FILE* open_file_wide(
const wchar_t* Path,
const wchar_t* mode)
3368 char* Path_utf8 = convert_Path_heap(Path);
3369 if (!Path_utf8)
return 0;
3372 char mode_ascii[4] = {0};
3373 for (
size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);
3376 FILE* Result = fopen(Path_utf8, mode_ascii);
3379 Memory::deallocate(Path_utf8);
3385 PUGI__FN
bool SaveFileImpl(
const Document& doc, FILE* file,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding)
3387 if (!file)
return false;
3389 WriterFile WriterInstance(file);
3390 doc.Save(WriterInstance, indent, flags, DocumentEncoding);
3392 int Result = ferror(file);
3409 size_t Result = fwrite(data, 1, size, static_cast<FILE*>(TargetFile));
3414 PUGI__FN
WriterStream::WriterStream(std::basic_ostream<
char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
3418 PUGI__FN
WriterStream::WriterStream(std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
3426 assert(!wide_stream);
3427 narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
3431 assert(wide_stream);
3432 assert(size %
sizeof(
wchar_t) == 0);
3434 wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size /
sizeof(
wchar_t)));
3449 return TraversalDepth;
3470 PUGI__FN
static void unspecified_bool_Attribute(Attribute***)
3474 PUGI__FN Attribute::operator Attribute::unspecified_bool_type()
const
3476 return AttributeData ? unspecified_bool_Attribute : 0;
3481 return !AttributeData;
3486 return (AttributeData == r.AttributeData);
3491 return (AttributeData != r.AttributeData);
3496 return (AttributeData < r.AttributeData);
3501 return (AttributeData > r.AttributeData);
3506 return (AttributeData <= r.AttributeData);
3511 return (AttributeData >= r.AttributeData);
3516 return AttributeData ?
Attribute(AttributeData->GetNextAttribute) : Attribute();
3521 return AttributeData && AttributeData->prev_attribute_c->GetNextAttribute ?
Attribute(AttributeData->prev_attribute_c) :
Attribute();
3526 return (AttributeData && AttributeData->Value) ? AttributeData->Value : def;
3531 return internal::GetValue_int(AttributeData ? AttributeData->Value : 0, def);
3536 return internal::GetValue_uint(AttributeData ? AttributeData->Value : 0, def);
3541 return internal::GetValue_double(AttributeData ? AttributeData->Value : 0, def);
3545 {
return (AttributeData ?
ToWhole(AttributeData->Value) : def); }
3548 {
return (AttributeData ?
ToInteger(AttributeData->Value) : def); }
3551 {
return (AttributeData ?
ToReal(AttributeData->Value) : def); }
3555 return internal::GetValue_float(AttributeData ? AttributeData->Value : 0, def);
3560 return internal::GetValue_bool(AttributeData ? AttributeData->Value : 0, def);
3565 return !AttributeData;
3570 return (AttributeData && AttributeData->Name) ? AttributeData->Name :
"";
3575 return (AttributeData && AttributeData->Value) ? AttributeData->Value :
"";
3580 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(AttributeData) /
sizeof(AttributeStruct));
3585 return AttributeData;
3620 if (!AttributeData)
return false;
3622 return internal::strcpy_insitu(AttributeData->Name, AttributeData->header, internal::MemoryPage_Name_allocated_mask, rhs);
3627 if (!AttributeData)
return false;
3629 return internal::strcpy_insitu(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3634 if (!AttributeData)
return false;
3636 return internal::SetValue_convert(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3641 if (!AttributeData)
return false;
3643 return internal::SetValue_convert(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3648 if (!AttributeData)
return false;
3650 return internal::SetValue_convert(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3655 if (!AttributeData)
return false;
3657 return internal::SetValue_convert(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3661 PUGI__FN
bool operator&&(
const Attribute& lhs,
bool rhs)
3663 return (
bool)lhs && rhs;
3666 PUGI__FN
bool operator||(
const Attribute& lhs,
bool rhs)
3668 return (
bool)lhs || rhs;
3680 PUGI__FN
Node::Node(NodeStruct* p): NodeData(p)
3684 PUGI__FN
static void unspecified_bool_Node(Node***)
3690 return NodeData ? unspecified_bool_Node : 0;
3720 return ObjectRange<NodeIterator>(
begin(),
end());
3725 return ObjectRange<NamedNodeIterator>(NamedNodeIterator(
GetChild(Name_), Name_), NamedNodeIterator());
3787 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
3788 if (i->Name && internal::strequal(Name_, i->Name))
return Node(i);
3797 for (AttributeStruct* i =
NodeData->GetFirstAttribute; i; i = i->GetNextAttribute)
3798 if (i->Name && internal::strequal(Name_, i->Name))
3799 return Attribute(i);
3808 for (NodeStruct* i =
NodeData->GetNextSibling; i; i = i->GetNextSibling)
3809 if (i->Name && internal::strequal(Name_, i->Name))
return Node(i);
3826 for (NodeStruct* i =
NodeData->prev_sibling_c; i->GetNextSibling; i = i->prev_sibling_c)
3827 if (i->Name && internal::strequal(Name_, i->Name))
return Node(i);
3849 internal::MemoryPage* page =
reinterpret_cast<internal::MemoryPage*
>(
NodeData->header & internal::MemoryPage_pointer_mask);
3851 return Node(static_cast<internal::DocumentStruct*>(page->allocator));
3863 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
3864 if (i->Value && internal::is_text_node(i))
3882 return NodeData &&
NodeData->GetFirstAttribute ? Attribute(
NodeData->GetFirstAttribute->prev_attribute_c) : Attribute();
3902 return internal::strcpy_insitu(
NodeData->Name,
NodeData->header, internal::MemoryPage_Name_allocated_mask, rhs);
3918 return internal::strcpy_insitu(
NodeData->Value,
NodeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3929 Attribute a(internal::AppendAttribute_ll(
NodeData, internal::GetAllocator(
NodeData)));
3939 Attribute a(internal::allocate_attribute(internal::GetAllocator(
NodeData)));
3940 if (!a)
return Attribute();
3944 AttributeStruct* head =
NodeData->GetFirstAttribute;
3948 a.AttributeData->prev_attribute_c = head->prev_attribute_c;
3949 head->prev_attribute_c = a.AttributeData;
3952 a.AttributeData->prev_attribute_c = a.AttributeData;
3954 a.AttributeData->GetNextAttribute = head;
3955 NodeData->GetFirstAttribute = a.AttributeData;
3965 AttributeStruct* cur = attr.AttributeData;
3967 while (cur->prev_attribute_c->GetNextAttribute) cur = cur->prev_attribute_c;
3969 if (cur !=
NodeData->GetFirstAttribute)
return Attribute();
3971 Attribute a(internal::allocate_attribute(internal::GetAllocator(
NodeData)));
3972 if (!a)
return Attribute();
3976 if (attr.AttributeData->prev_attribute_c->GetNextAttribute)
3977 attr.AttributeData->prev_attribute_c->GetNextAttribute = a.AttributeData;
3979 NodeData->GetFirstAttribute = a.AttributeData;
3981 a.AttributeData->prev_attribute_c = attr.AttributeData->prev_attribute_c;
3982 a.AttributeData->GetNextAttribute = attr.AttributeData;
3983 attr.AttributeData->prev_attribute_c = a.AttributeData;
3993 AttributeStruct* cur = attr.AttributeData;
3995 while (cur->prev_attribute_c->GetNextAttribute) cur = cur->prev_attribute_c;
3997 if (cur !=
NodeData->GetFirstAttribute)
return Attribute();
3999 Attribute a(internal::allocate_attribute(internal::GetAllocator(
NodeData)));
4000 if (!a)
return Attribute();
4004 if (attr.AttributeData->GetNextAttribute)
4005 attr.AttributeData->GetNextAttribute->prev_attribute_c = a.AttributeData;
4007 NodeData->GetFirstAttribute->prev_attribute_c = a.AttributeData;
4009 a.AttributeData->GetNextAttribute = attr.AttributeData->GetNextAttribute;
4010 a.AttributeData->prev_attribute_c = attr.AttributeData;
4011 attr.AttributeData->GetNextAttribute = a.AttributeData;
4018 if (!proto)
return Attribute();
4028 if (!proto)
return Attribute();
4038 if (!proto)
return Attribute();
4048 if (!proto)
return Attribute();
4058 if (!internal::allow_InsertChild(this->
Type(), Type_))
return Node();
4069 if (!internal::allow_InsertChild(this->
Type(), Type_))
return Node();
4071 Node n(internal::allocate_node(internal::GetAllocator(
NodeData), Type_));
4072 if (!n)
return Node();
4076 NodeStruct* head =
NodeData->GetFirstChild;
4080 n.NodeData->prev_sibling_c = head->prev_sibling_c;
4081 head->prev_sibling_c = n.NodeData;
4084 n.NodeData->prev_sibling_c = n.NodeData;
4086 n.NodeData->GetNextSibling = head;
4087 NodeData->GetFirstChild = n.NodeData;
4096 if (!internal::allow_InsertChild(this->
Type(), Type_))
return Node();
4097 if (!node.NodeData || node.NodeData->GetParent !=
NodeData)
return Node();
4099 Node n(internal::allocate_node(internal::GetAllocator(
NodeData), Type_));
4100 if (!n)
return Node();
4104 if (node.NodeData->prev_sibling_c->GetNextSibling)
4105 node.NodeData->prev_sibling_c->GetNextSibling = n.NodeData;
4107 NodeData->GetFirstChild = n.NodeData;
4109 n.NodeData->prev_sibling_c = node.NodeData->prev_sibling_c;
4110 n.NodeData->GetNextSibling = node.NodeData;
4111 node.NodeData->prev_sibling_c = n.NodeData;
4120 if (!internal::allow_InsertChild(this->
Type(), Type_))
return Node();
4121 if (!node.NodeData || node.NodeData->GetParent !=
NodeData)
return Node();
4123 Node n(internal::allocate_node(internal::GetAllocator(
NodeData), Type_));
4124 if (!n)
return Node();
4128 if (node.NodeData->GetNextSibling)
4129 node.NodeData->GetNextSibling->prev_sibling_c = n.NodeData;
4131 NodeData->GetFirstChild->prev_sibling_c = n.NodeData;
4133 n.NodeData->GetNextSibling = node.NodeData->GetNextSibling;
4134 n.NodeData->prev_sibling_c = node.NodeData;
4135 node.NodeData->GetNextSibling = n.NodeData;
4146 Result.SetName(Name_);
4155 Result.SetName(Name_);
4164 Result.SetName(Name_);
4173 Result.SetName(Name_);
4182 if (Result) internal::recursive_copy_skip(Result, proto, Result);
4191 if (Result) internal::recursive_copy_skip(Result, proto, Result);
4200 if (Result) internal::recursive_copy_skip(Result, proto, Result);
4209 if (Result) internal::recursive_copy_skip(Result, proto, Result);
4221 if (!
NodeData || !a.AttributeData)
return false;
4224 AttributeStruct* attr = a.AttributeData;
4226 while (attr->prev_attribute_c->GetNextAttribute) attr = attr->prev_attribute_c;
4228 if (attr !=
NodeData->GetFirstAttribute)
return false;
4230 if (a.AttributeData->GetNextAttribute) a.AttributeData->GetNextAttribute->prev_attribute_c = a.AttributeData->prev_attribute_c;
4231 else if (
NodeData->GetFirstAttribute)
NodeData->GetFirstAttribute->prev_attribute_c = a.AttributeData->prev_attribute_c;
4233 if (a.AttributeData->prev_attribute_c->GetNextAttribute) a.AttributeData->prev_attribute_c->GetNextAttribute = a.AttributeData->GetNextAttribute;
4234 else NodeData->GetFirstAttribute = a.AttributeData->GetNextAttribute;
4236 internal::destroy_attribute(a.AttributeData, internal::GetAllocator(
NodeData));
4248 if (!
NodeData || !n.NodeData || n.NodeData->GetParent !=
NodeData)
return false;
4250 if (n.NodeData->GetNextSibling) n.NodeData->GetNextSibling->prev_sibling_c = n.NodeData->prev_sibling_c;
4251 else if (
NodeData->GetFirstChild)
NodeData->GetFirstChild->prev_sibling_c = n.NodeData->prev_sibling_c;
4253 if (n.NodeData->prev_sibling_c->GetNextSibling) n.NodeData->prev_sibling_c->GetNextSibling = n.NodeData->GetNextSibling;
4254 else NodeData->GetFirstChild = n.NodeData->GetNextSibling;
4256 internal::destroy_node(n.NodeData, internal::GetAllocator(
NodeData));
4265 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
4266 if (i->Name && internal::strequal(Name_, i->Name))
4268 for (AttributeStruct* a = i->GetFirstAttribute; a; a = a->GetNextAttribute)
4269 if (internal::strequal(AttrName, a->Name) && internal::strequal(AttrValue, a->Value))
4280 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
4281 for (AttributeStruct* a = i->GetFirstAttribute; a; a = a->GetNextAttribute)
4282 if (internal::strequal(AttrName, a->Name) && internal::strequal(AttrValue, a->Value))
4290 Node cursor = *
this;
4292 String Result = cursor.Name();
4294 while (cursor.GetParent())
4296 cursor = cursor.GetParent();
4298 String temp = cursor.Name();
4311 if (!
NodeData || !Path_ || !Path_[0])
return found;
4313 if (Path_[0] == delimiter)
4316 found = found.GetRoot();
4320 const Char8* Path_segment = Path_;
4322 while (*Path_segment == delimiter) ++Path_segment;
4324 const Char8* Path_segment_end = Path_segment;
4326 while (*Path_segment_end && *Path_segment_end != delimiter) ++Path_segment_end;
4328 if (Path_segment == Path_segment_end)
return found;
4330 const Char8* NextSegment = Path_segment_end;
4332 while (*NextSegment == delimiter) ++NextSegment;
4334 if (*Path_segment ==
'.' && Path_segment + 1 == Path_segment_end)
4335 return found.FirstElementByPath(NextSegment, delimiter);
4336 else if (*Path_segment ==
'.' && *(Path_segment+1) ==
'.' && Path_segment + 2 == Path_segment_end)
4337 return found.GetParent().FirstElementByPath(NextSegment, delimiter);
4340 for (NodeStruct* j = found.NodeData->GetFirstChild; j; j = j->GetNextSibling)
4342 if (j->Name && internal::strequalrange(j->Name, Path_segment, static_cast<size_t>(Path_segment_end - Path_segment)))
4344 Node subsearch =
Node(j).FirstElementByPath(NextSegment, delimiter);
4346 if (subsearch)
return subsearch;
4356 walker.TraversalDepth = -1;
4358 Node arg_begin = *
this;
4359 if (!walker.OnTraversalBegin(arg_begin))
return false;
4365 ++walker.TraversalDepth;
4369 Node arg_for_each = cur;
4370 if (!walker.OnEachNode(arg_for_each))
4373 if (cur.GetFirstChild())
4375 ++walker.TraversalDepth;
4376 cur = cur.GetFirstChild();
4378 else if (cur.GetNextSibling())
4379 cur = cur.GetNextSibling();
4383 while (!cur.GetNextSibling() && cur != *
this && !cur.GetParent().Empty())
4385 --walker.TraversalDepth;
4386 cur = cur.GetParent();
4390 cur = cur.GetNextSibling();
4393 while (cur && cur != *
this);
4396 assert(walker.TraversalDepth == -1);
4398 Node arg_end = *
this;
4399 return walker.OnTraversalEnd(arg_end);
4404 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(
NodeData) /
sizeof(NodeStruct));
4412 PUGI__FN
void Node::Print(Writer& WriterInstance,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding,
unsigned int Depth)
const
4416 internal::BufferedWriter buffered_WriterInstance(WriterInstance, DocumentEncoding);
4418 internal::NodeOutput(buffered_WriterInstance, *
this, indent, flags, Depth);
4421 PUGI__FN
void Node::Print(std::basic_ostream<
char, std::char_traits<char> >& stream,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding,
unsigned int Depth)
const
4423 WriterStream WriterInstance(stream);
4425 Print(WriterInstance, indent, flags, DocumentEncoding, Depth);
4428 PUGI__FN
void Node::Print(std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream,
const Char8* indent,
unsigned int flags,
unsigned int Depth)
const
4430 WriterStream WriterInstance(stream);
4441 const Char8* buffer =
static_cast<internal::DocumentStruct*
>(r)->buffer;
4443 if (!buffer)
return -1;
4453 return (
NodeData->header & internal::MemoryPage_Name_allocated_mask) ? -1 :
NodeData->Name - buffer;
4459 return (
NodeData->header & internal::MemoryPage_Value_allocated_mask) ? -1 :
NodeData->Value - buffer;
4467 PUGI__FN
bool operator&&(
const Node& lhs,
bool rhs)
4469 return (
bool)lhs && rhs;
4472 PUGI__FN
bool operator||(
const Node& lhs,
bool rhs)
4474 return (
bool)lhs || rhs;
4482 PUGI__FN NodeStruct* NodeText::Data()
const
4484 if (!RootNode || internal::is_text_node(RootNode))
return RootNode;
4486 for (NodeStruct* node = RootNode->GetFirstChild; node; node = node->GetNextSibling)
4487 if (internal::is_text_node(node))
4493 PUGI__FN NodeStruct* NodeText::DataNew()
4495 NodeStruct* d = Data();
4498 return Node(RootNode).AppendChild(
NodePcdata).InternalObject();
4505 PUGI__FN
static void unspecified_bool_Text(NodeText***)
4509 PUGI__FN NodeText::operator NodeText::unspecified_bool_type()
const
4511 return Data() ? unspecified_bool_Text : 0;
4526 NodeStruct* d = Data();
4528 return (d && d->Value) ? d->Value :
"";
4533 NodeStruct* d = Data();
4535 return (d && d->Value) ? d->Value : def;
4540 NodeStruct* d = Data();
4542 return internal::GetValue_int(d ? d->Value : 0, def);
4547 NodeStruct* d = Data();
4549 return internal::GetValue_uint(d ? d->Value : 0, def);
4554 NodeStruct* d = Data();
4556 return internal::GetValue_double(d ? d->Value : 0, def);
4561 NodeStruct* d = Data();
4563 return internal::GetValue_float(d ? d->Value : 0, def);
4583 NodeStruct* d = Data();
4585 return internal::GetValue_bool(d ? d->Value : 0, def);
4590 NodeStruct* dn = DataNew();
4592 return dn ? internal::strcpy_insitu(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4597 NodeStruct* dn = DataNew();
4599 return dn ? internal::SetValue_convert(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4604 NodeStruct* dn = DataNew();
4606 return dn ? internal::SetValue_convert(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4611 NodeStruct* dn = DataNew();
4613 return dn ? internal::SetValue_convert(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4618 NodeStruct* dn = DataNew();
4620 return dn ? internal::SetValue_convert(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4655 return Node(Data());
4659 PUGI__FN
bool operator&&(
const Text& lhs,
bool rhs)
4661 return (
bool)lhs && rhs;
4664 PUGI__FN
bool operator||(
const Text& lhs,
bool rhs)
4666 return (
bool)lhs || rhs;
4684 return TargetNode.
NodeData == rhs.TargetNode.NodeData && ParentNode.
NodeData == rhs.ParentNode.NodeData;
4689 return TargetNode.
NodeData != rhs.TargetNode.NodeData || ParentNode.
NodeData != rhs.ParentNode.NodeData;
4701 return const_cast<Node*
>(&TargetNode);
4745 return TargetAttribute.AttributeData == rhs.TargetAttribute.AttributeData && ParentNode.
NodeData == rhs.ParentNode.NodeData;
4750 return TargetAttribute.AttributeData != rhs.TargetAttribute.AttributeData || ParentNode.
NodeData != rhs.ParentNode.NodeData;
4755 assert(TargetAttribute.AttributeData);
4756 return TargetAttribute;
4761 assert(TargetAttribute.AttributeData);
4762 return const_cast<Attribute*
>(&TargetAttribute);
4767 assert(TargetAttribute.AttributeData);
4768 TargetAttribute.AttributeData = TargetAttribute.AttributeData->GetNextAttribute;
4802 return TargetNode == rhs.TargetNode;
4807 return TargetNode != rhs.TargetNode;
4819 return const_cast<Node*
>(&TargetNode);
4840 PUGI__FN ParseResult::operator bool()
const
4852 case StatusIOError:
return "Error reading from file/stream";
4868 default:
return "Unknown error";
4892 for (
Node cur = proto.GetFirstChild(); cur; cur = cur.GetNextSibling())
4896 PUGI__FN
void Document::create()
4899 PUGI__STATIC_ASSERT(offsetof(internal::MemoryPage, data) +
sizeof(internal::DocumentStruct) + internal::MemoryPage_alignment <=
sizeof(_memory));
4902 void* page_memory =
reinterpret_cast<void*
>((
reinterpret_cast<uintptr_t
>(_memory) + (internal::MemoryPage_alignment - 1)) & ~(internal::MemoryPage_alignment - 1));
4905 internal::MemoryPage* page = internal::MemoryPage::construct(page_memory);
4907 page->busy_size = internal::MemoryPage_size;
4910 NodeData =
new (page->data) internal::DocumentStruct(page);
4914 page->allocator =
static_cast<internal::DocumentStruct*
>(
NodeData);
4917 PUGI__FN ParseResult
Document::Load(Resource::DataStream& stream,
unsigned int options,
Encoding DocumentEncoding)
4920 return internal::LoadDataStreamImpl(*
this, stream, options, DocumentEncoding);
4923 PUGI__FN
void Document::Save(Resource::DataStream& stream,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding)
const
4925 XMLStreamWrapper WriterInstance(&stream);
4926 Save(WriterInstance, indent, flags, DocumentEncoding);
4929 PUGI__FN
void Document::destroy()
4934 internal::Memory::deallocate(_buffer);
4941 internal::MemoryPage* GetRoot_page =
reinterpret_cast<internal::MemoryPage*
>(
NodeData->header & internal::MemoryPage_pointer_mask);
4942 assert(GetRoot_page && !GetRoot_page->prev && !GetRoot_page->memory);
4945 for (internal::MemoryPage* page = GetRoot_page->next; page; )
4947 internal::MemoryPage* next = page->next;
4949 internal::Allocator::deallocate_page(page);
4955 GetRoot_page->allocator = 0;
4956 GetRoot_page->next = 0;
4957 GetRoot_page->busy_size = GetRoot_page->freed_size = 0;
4963 PUGI__FN ParseResult
Document::Load(std::basic_istream<
char, std::char_traits<char> >& stream,
unsigned int options,
Encoding DocumentEncoding)
4967 return internal::LoadStreamImpl(*
this, stream, options, DocumentEncoding);
4970 PUGI__FN ParseResult
Document::Load(std::basic_istream<
wchar_t, std::char_traits<wchar_t> >& stream,
unsigned int options)
4974 return internal::LoadStreamImpl(*
this, stream, options,
Encodingwchar_t);
4982 return LoadBuffer(contents, internal::strlength(contents) *
sizeof(
Char8), options, DocumentEncoding);
4989 FILE* file = fopen(Path_,
"rb");
4991 return internal::LoadFileImpl(*
this, file, options, DocumentEncoding);
4998 FILE* file = internal::open_file_wide(Path_, L
"rb");
5000 return internal::LoadFileImpl(*
this, file, options, DocumentEncoding);
5003 PUGI__FN ParseResult Document::LoadBufferImpl(
void* contents,
size_t size,
unsigned int options,
Encoding DocumentEncoding,
bool is_mutable,
bool own)
5008 assert(contents || size == 0);
5011 Encoding buffer_DocumentEncoding = internal::GetBuffer_DocumentEncoding(DocumentEncoding, contents, size);
5017 if (!internal::convert_buffer(buffer, length, buffer_DocumentEncoding, contents, size, is_mutable))
return internal::make_ParseResult(
StatusOutOfMemory);
5020 if (own && buffer != contents && contents) internal::Memory::deallocate(contents);
5023 ParseResult res = internal::Parser::parse(buffer, length,
NodeData, options);
5026 res.DocumentEncoding = buffer_DocumentEncoding;
5029 if (own || buffer != contents) _buffer = buffer;
5036 return LoadBufferImpl(const_cast<void*>(contents), size, options, DocumentEncoding,
false,
false);
5041 return LoadBufferImpl(contents, size, options, DocumentEncoding,
true,
false);
5046 return LoadBufferImpl(contents, size, options, DocumentEncoding,
true,
true);
5051 internal::BufferedWriter buffered_WriterInstance(WriterInstance, DocumentEncoding);
5056 buffered_WriterInstance.Write(
'\xef',
'\xbb',
'\xbf');
5061 buffered_WriterInstance.Write(
"<?xml version=\"1.0\"");
5062 if (DocumentEncoding ==
EncodingLatin1) buffered_WriterInstance.Write(
" DocumentEncoding=\"ISO-8859-1\"");
5063 buffered_WriterInstance.Write(
'?',
'>');
5064 if (!(flags & FormatRaw)) buffered_WriterInstance.Write(
'\n');
5067 internal::NodeOutput(buffered_WriterInstance, *
this, indent, flags, 0);
5070 PUGI__FN
void Document::Save(std::basic_ostream<
char, std::char_traits<char> >& stream,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding)
const
5072 WriterStream WriterInstance(stream);
5074 Save(WriterInstance, indent, flags, DocumentEncoding);
5077 PUGI__FN
void Document::Save(std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream,
const Char8* indent,
unsigned int flags)
const
5079 WriterStream WriterInstance(stream);
5087 return internal::SaveFileImpl(*
this, file, indent, flags, DocumentEncoding);
5092 FILE* file = internal::open_file_wide(Path_, (flags &
FormatSaveFileText) ? L
"w" : L
"wb");
5093 return internal::SaveFileImpl(*
this, file, indent, flags, DocumentEncoding);
5098 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
5099 if ((i->header & internal::MemoryPage_type_mask) + 1 ==
NodeElement)
5109 return internal::AsUtf8_impl(str, wcslen(str));
5112 PUGI__FN std::string
MEZZ_LIB AsUtf8(
const std::basic_string<wchar_t>& str)
5114 return internal::AsUtf8_impl(str.c_str(), str.size());
5117 PUGI__FN std::basic_string<wchar_t>
MEZZ_LIB AsWide(
const char* str)
5121 return internal::AsWide_impl(str, strlen(str));
5124 PUGI__FN std::basic_string<wchar_t>
MEZZ_LIB AsWide(
const std::string& str)
5126 return internal::AsWide_impl(str.c_str(), str.size());
5132 internal::Memory::allocate = allocate;
5133 internal::Memory::deallocate = deallocate;
5138 return internal::Memory::allocate;
5143 return internal::Memory::deallocate;
5153 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5161 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5169 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5177 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5183 template <
typename T>
void swap(T& lhs, T& rhs)
5190 template <
typename I,
typename Pred> I min_element(I begin, I end,
const Pred& pred)
5194 for (I it = begin + 1; it != end; ++it)
5195 if (pred(*it, *Result))
5201 template <
typename I>
void reverse(I begin, I end)
5203 while (begin + 1 < end) swap(*begin++, *--end);
5206 template <
typename I> I unique(I begin, I end)
5209 while (begin + 1 < end && *begin != *(begin + 1)) begin++;
5211 if (begin == end)
return begin;
5217 while (begin != end)
5219 if (*begin != *Write)
5220 *++Write = *begin++;
5229 template <
typename I>
void copy_backwards(I begin, I end, I target)
5231 while (begin != end) *--target = *--end;
5234 template <
typename I,
typename Pred,
typename T>
void insertion_sort(I begin, I end,
const Pred& pred, T*)
5236 assert(begin != end);
5238 for (I it = begin + 1; it != end; ++it)
5242 if (pred(val, *begin))
5245 copy_backwards(begin, it, it + 1);
5253 while (pred(val, *(hole - 1)))
5255 *hole = *(hole - 1);
5266 template <
typename I,
typename Pred>
void partition(I begin, I middle, I end,
const Pred& pred, I* out_eqbeg, I* out_eqend)
5268 I eqbeg = middle, eqend = middle + 1;
5271 while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg;
5272 while (eqend != end && *eqend == *eqbeg) ++eqend;
5275 I ltend = eqbeg, gtbeg = eqend;
5280 for (; gtbeg != end; ++gtbeg)
5281 if (!pred(*eqbeg, *gtbeg))
5283 if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++);
5288 for (; ltend != begin; --ltend)
5289 if (!pred(*(ltend - 1), *eqbeg))
5291 if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg);
5296 if (gtbeg == end && ltend == begin)
5306 if (--ltend != --eqbeg) swap(*ltend, *eqbeg);
5307 swap(*eqbeg, *--eqend);
5309 else if (ltend == begin)
5311 if (eqend != gtbeg) swap(*eqbeg, *eqend);
5313 swap(*gtbeg++, *eqbeg++);
5315 else swap(*gtbeg++, *--ltend);
5319 template <
typename I,
typename Pred>
void median3(I first, I middle, I last,
const Pred& pred)
5321 if (pred(*middle, *first)) swap(*middle, *first);
5322 if (pred(*last, *middle)) swap(*last, *middle);
5323 if (pred(*middle, *first)) swap(*middle, *first);
5326 template <
typename I,
typename Pred>
void median(I first, I middle, I last,
const Pred& pred)
5328 if (last - first <= 40)
5331 median3(first, middle, last, pred);
5336 size_t step = (last - first + 1) / 8;
5338 median3(first, first + step, first + 2 * step, pred);
5339 median3(middle - step, middle, middle + step, pred);
5340 median3(last - 2 * step, last - step, last, pred);
5341 median3(first + step, middle, last - step, pred);
5345 template <
typename I,
typename Pred>
void sort(I begin, I end,
const Pred& pred)
5348 while (end - begin > 32)
5351 I middle = begin + (end - begin) / 2;
5352 median(begin, middle, end - 1, pred);
5356 partition(begin, middle, end, pred, &eqbeg, &eqend);
5359 if (eqbeg - begin > end - eqend)
5361 sort(eqend, end, pred);
5366 sort(begin, eqbeg, pred);
5372 if (begin != end) insertion_sort(begin, end, pred, &*begin);
5378 struct XPathMemoryBlock
5380 XPathMemoryBlock* next;
5383 #ifdef XML_MEMORY_XPATH_PAGE_SIZE
5384 XML_MEMORY_XPATH_PAGE_SIZE
5391 class XPathAllocator
5393 XPathMemoryBlock* _GetRoot;
5394 size_t _GetRoot_size;
5399 XPathAllocator(XPathMemoryBlock* GetRoot,
size_t GetRoot_size = 0): _GetRoot(GetRoot), _GetRoot_size(GetRoot_size)
5404 void* allocate_nothrow(
size_t size)
5406 const size_t block_capacity =
sizeof(_GetRoot->data);
5409 size = (size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5411 if (_GetRoot_size + size <= block_capacity)
5413 void* buf = _GetRoot->data + _GetRoot_size;
5414 _GetRoot_size += size;
5419 size_t block_data_size = (size > block_capacity) ? size : block_capacity;
5420 size_t block_size = block_data_size + offsetof(XPathMemoryBlock, data);
5422 XPathMemoryBlock* block =
static_cast<XPathMemoryBlock*
>(Memory::allocate(block_size));
5423 if (!block)
return 0;
5425 block->next = _GetRoot;
5428 _GetRoot_size = size;
5434 void* allocate(
size_t size)
5436 void* Result = allocate_nothrow(size);
5440 throw std::bad_alloc();
5446 void* reallocate(
void* ptr,
size_t old_size,
size_t new_size)
5449 old_size = (old_size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5450 new_size = (new_size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5453 assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _GetRoot->data + _GetRoot_size);
5456 bool only_object = (_GetRoot_size == old_size);
5458 if (ptr) _GetRoot_size -= old_size;
5461 void* Result = allocate(new_size);
5465 if (Result != ptr && ptr)
5468 assert(new_size > old_size);
5469 memcpy(Result, ptr, old_size);
5474 assert(_GetRoot->data == Result);
5475 assert(_GetRoot->next);
5477 XPathMemoryBlock* next = _GetRoot->next->next;
5482 Memory::deallocate(_GetRoot->next);
5483 _GetRoot->next = next;
5491 void revert(
const XPathAllocator& state)
5494 XPathMemoryBlock* cur = _GetRoot;
5496 while (cur != state._GetRoot)
5498 XPathMemoryBlock* next = cur->next;
5500 Memory::deallocate(cur);
5506 _GetRoot = state._GetRoot;
5507 _GetRoot_size = state._GetRoot_size;
5512 XPathMemoryBlock* cur = _GetRoot;
5517 XPathMemoryBlock* next = cur->next;
5519 Memory::deallocate(cur);
5526 struct XPathAllocatorCapture
5528 XPathAllocatorCapture(XPathAllocator* alloc): _target(alloc), _state(*alloc)
5532 ~XPathAllocatorCapture()
5534 _target->revert(_state);
5537 XPathAllocator* _target;
5538 XPathAllocator _state;
5543 XPathAllocator* Result;
5544 XPathAllocator* temp;
5547 struct XPathStackData
5549 XPathMemoryBlock blocks[2];
5550 XPathAllocator Result;
5551 XPathAllocator temp;
5554 XPathStackData(): Result(blocks + 0), temp(blocks + 1)
5556 blocks[0].next = blocks[1].next = 0;
5558 stack.Result = &Result;
5575 const Char8* _buffer;
5578 static Char8* duplicate_string(
const Char8*
string,
size_t length, XPathAllocator* alloc)
5580 Char8* Result =
static_cast<Char8*
>(alloc->allocate((length + 1) *
sizeof(
Char8)));
5583 memcpy(Result,
string, length *
sizeof(
Char8));
5589 static Char8* duplicate_string(
const Char8*
string, XPathAllocator* alloc)
5591 return duplicate_string(
string, strlength(
string), alloc);
5595 XPathString(): _buffer(
""), _uses_heap(false)
5599 explicit XPathString(
const Char8* str, XPathAllocator* alloc)
5601 bool empty_ = (*str == 0);
5603 _buffer = empty_ ?
"" : duplicate_string(str, alloc);
5604 _uses_heap = !empty_;
5607 explicit XPathString(
const Char8* str,
bool use_heap): _buffer(str), _uses_heap(use_heap)
5611 XPathString(
const Char8* begin,
const Char8* end, XPathAllocator* alloc)
5613 assert(begin <= end);
5615 bool empty_ = (begin == end);
5617 _buffer = empty_ ?
"" : duplicate_string(begin, static_cast<size_t>(end - begin), alloc);
5618 _uses_heap = !empty_;
5621 void append(
const XPathString& o, XPathAllocator* alloc)
5624 if (!*o._buffer)
return;
5627 if (!*_buffer && !_uses_heap && !o._uses_heap)
5629 _buffer = o._buffer;
5634 size_t tarGetLength = strlength(_buffer);
5635 size_t source_length = strlength(o._buffer);
5636 size_t Result_length = tarGetLength + source_length;
5639 Char8* Result =
static_cast<Char8*
>(alloc->reallocate(_uses_heap ? const_cast<Char8*>(_buffer) : 0, (tarGetLength + 1) *
sizeof(
Char8), (Result_length + 1) *
sizeof(
Char8)));
5643 if (!_uses_heap) memcpy(Result, _buffer, tarGetLength *
sizeof(
Char8));
5646 memcpy(Result + tarGetLength, o._buffer, source_length *
sizeof(
Char8));
5647 Result[Result_length] = 0;
5655 const Char8* c_str()
const
5660 size_t length()
const
5662 return strlength(_buffer);
5665 Char8* data(XPathAllocator* alloc)
5670 _buffer = duplicate_string(_buffer, alloc);
5674 return const_cast<Char8*
>(_buffer);
5679 return *_buffer == 0;
5682 bool operator==(
const XPathString& o)
const
5684 return strequal(_buffer, o._buffer);
5687 bool operator!=(
const XPathString& o)
const
5689 return !strequal(_buffer, o._buffer);
5692 bool uses_heap()
const
5698 PUGI__FN XPathString XPathStringConst(
const Char8* str)
5700 return XPathString(str,
false);
5705 PUGI__FN
bool starts_with(
const Char8*
string,
const Char8* pattern)
5707 while (*pattern && *
string == *pattern)
5713 return *pattern == 0;
5718 return strchr(s, c);
5723 return strstr(s, p);
5729 return static_cast<unsigned int>(ch -
'A') < 26 ? static_cast<Char8>(ch |
' ') : ch;
5732 PUGI__FN XPathString string_Value(
const XPathNode& na, XPathAllocator* alloc)
5734 if (na.GetAttribute())
5735 return XPathStringConst(na.GetAttribute().Value());
5738 const Node& n = na.GetNode();
5746 return XPathStringConst(n.Value());
5753 Node cur = n.GetFirstChild();
5755 while (cur && cur != n)
5758 Result.append(XPathStringConst(cur.Value()), alloc);
5760 if (cur.GetFirstChild())
5761 cur = cur.GetFirstChild();
5762 else if (cur.GetNextSibling())
5763 cur = cur.GetNextSibling();
5766 while (!cur.GetNextSibling() && cur != n)
5767 cur = cur.GetParent();
5769 if (cur != n) cur = cur.GetNextSibling();
5777 return XPathString();
5782 PUGI__FN
unsigned int NodeHeight(Node n)
5784 unsigned int Result = 0;
5795 PUGI__FN
bool NodeIs_before(Node ln,
unsigned int lh, Node rn,
unsigned int rh)
5798 for (
unsigned int i = rh; i < lh; i++) ln = ln.GetParent();
5799 for (
unsigned int j = lh; j < rh; j++) rn = rn.GetParent();
5802 if (ln == rn)
return lh < rh;
5805 while (ln.GetParent() != rn.GetParent())
5807 ln = ln.GetParent();
5808 rn = rn.GetParent();
5812 if (!ln.GetParent())
return ln < rn;
5815 for (; ln; ln = ln.GetNextSibling())
5822 PUGI__FN
bool NodeIs_ancestor(Node GetParent, Node node)
5824 while (node && node != GetParent) node = node.GetParent();
5826 return GetParent && node == GetParent;
5829 PUGI__FN
const void* document_order(
const XPathNode& xnode)
5831 NodeStruct* node = xnode.GetNode().InternalObject();
5835 if (node->Name && (node->header & MemoryPage_Name_allocated_mask) == 0)
return node->Name;
5836 if (node->Value && (node->header & MemoryPage_Value_allocated_mask) == 0)
return node->Value;
5840 AttributeStruct* attr = xnode.GetAttribute().InternalObject();
5844 if ((attr->header & MemoryPage_Name_allocated_mask) == 0)
return attr->Name;
5845 if ((attr->header & MemoryPage_Value_allocated_mask) == 0)
return attr->Value;
5852 struct document_order_comparator
5854 bool operator()(
const XPathNode& lhs,
const XPathNode& rhs)
const
5857 const void* lo = document_order(lhs);
5858 const void* ro = document_order(rhs);
5860 if (lo && ro)
return lo < ro;
5863 Node ln = lhs.GetNode(), rn = rhs.GetNode();
5866 if (lhs.GetAttribute() && rhs.GetAttribute())
5869 if (lhs.GetParent() == rhs.GetParent())
5872 for (Attribute a = lhs.GetAttribute(); a; a = a.GetNextAttribute())
5873 if (a == rhs.GetAttribute())
5880 ln = lhs.GetParent();
5881 rn = rhs.GetParent();
5883 else if (lhs.GetAttribute())
5886 if (lhs.GetParent() == rhs.GetNode())
return false;
5888 ln = lhs.GetParent();
5890 else if (rhs.GetAttribute())
5893 if (rhs.GetParent() == lhs.GetNode())
return true;
5895 rn = rhs.GetParent();
5898 if (ln == rn)
return false;
5900 unsigned int lh = NodeHeight(ln);
5901 unsigned int rh = NodeHeight(rn);
5903 return NodeIs_before(ln, lh, rn, rh);
5907 struct duplicate_comparator
5909 bool operator()(
const XPathNode& lhs,
const XPathNode& rhs)
const
5911 if (lhs.GetAttribute())
return rhs.GetAttribute() ? lhs.GetAttribute() < rhs.GetAttribute() :
true;
5912 else return rhs.GetAttribute() ?
false : lhs.GetNode() < rhs.GetNode();
5916 PUGI__FN
double gen_nan()
5918 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
5919 union {
float f; uint32_t i; } u[
sizeof(float) ==
sizeof(uint32_t) ? 1 : -1];
5920 u[0].i = 0x7fc00000;
5924 const volatile double zero = 0.0;
5929 PUGI__FN
bool is_nan(
double Value)
5931 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
5932 return !!_isnan(Value);
5933 #elif defined(fpclassify) && defined(FP_NAN)
5934 return fpclassify(Value) == FP_NAN;
5937 const volatile double v = Value;
5942 PUGI__FN
const Char8* convert_number_to_string_special(
double Value)
5944 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
5945 if (_finite(Value))
return (Value == 0) ?
"0" : 0;
5946 if (_isnan(Value))
return "NaN";
5947 return Value > 0 ?
"Infinity" :
"-Infinity";
5948 #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
5949 switch (fpclassify(Value))
5955 return Value > 0 ?
"Infinity" :
"-Infinity";
5965 const volatile double v = Value;
5967 if (v == 0)
return "0";
5968 if (v != v)
return "NaN";
5969 if (v * 2 == v)
return Value > 0 ?
"Infinity" :
"-Infinity";
5974 PUGI__FN
bool convert_number_to_boolean(
double Value)
5976 return (Value != 0 && !is_nan(Value));
5979 PUGI__FN
void truncate_zeros(
char* begin,
char* end)
5981 while (begin != end && end[-1] ==
'0') end--;
5987 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
5988 PUGI__FN
void convert_number_to_mantissa_exponent(
double Value,
char* buffer,
size_t buffer_size,
char** out_mantissa,
int* out_exponent)
5992 _ecvt_s(buffer, buffer_size, Value, DBL_DIG + 1, &exponent, &sign);
5995 truncate_zeros(buffer, buffer + strlen(buffer));
5998 *out_mantissa = buffer;
5999 *out_exponent = exponent;
6002 PUGI__FN
void convert_number_to_mantissa_exponent(
double Value,
char* buffer,
size_t buffer_size,
char** out_mantissa,
int* out_exponent)
6005 sprintf(buffer,
"%.*e", DBL_DIG, Value);
6006 assert(strlen(buffer) < buffer_size);
6010 char* exponent_string = strchr(buffer,
'e');
6011 assert(exponent_string);
6013 int exponent = atoi(exponent_string + 1);
6016 char* mantissa = buffer[0] ==
'-' ? buffer + 1 : buffer;
6017 assert(mantissa[0] !=
'0' && mantissa[1] ==
'.');
6020 mantissa[1] = mantissa[0];
6025 truncate_zeros(mantissa, exponent_string);
6028 *out_mantissa = mantissa;
6029 *out_exponent = exponent;
6033 PUGI__FN XPathString convert_number_to_string(
double Value, XPathAllocator* alloc)
6036 const Char8* special = convert_number_to_string_special(Value);
6037 if (special)
return XPathStringConst(special);
6040 char mantissa_buffer[64];
6044 convert_number_to_mantissa_exponent(Value, mantissa_buffer,
sizeof(mantissa_buffer), &mantissa, &exponent);
6051 if (Value < 0) *s++ =
'-';
6060 while (exponent > 0)
6062 assert(*mantissa == 0 || static_cast<unsigned int>(*mantissa -
'0') <= 9);
6063 *s++ = *mantissa ? *mantissa++ :
'0';
6075 while (exponent < 0)
6084 assert(static_cast<unsigned int>(*mantissa -
'0') <= 9);
6090 assert(s < Result +
sizeof(Result) /
sizeof(Result[0]));
6093 return XPathString(Result, alloc);
6096 PUGI__FN
bool check_Stringo_number_format(
const Char8*
string)
6099 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
6102 if (*
string ==
'-') ++string;
6104 if (!*
string)
return false;
6107 if (!PUGI__IS_CHARTYPEX(
string[0], ctx_digit) && (
string[0] !=
'.' || !PUGI__IS_CHARTYPEX(
string[1], ctx_digit)))
return false;
6110 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
6117 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
6121 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
6123 return *
string == 0;
6126 PUGI__FN
double convert_Stringo_number(
const Char8*
string)
6129 if (!check_Stringo_number_format(
string))
return gen_nan();
6132 return atof(
string);
6135 PUGI__FN
bool convert_Stringo_number(
const Char8* begin,
const Char8* end,
double* out_Result)
6139 size_t length =
static_cast<size_t>(end - begin);
6140 Char8* scratch = buffer;
6142 if (length >=
sizeof(buffer) /
sizeof(buffer[0]))
6145 scratch =
static_cast<Char8*
>(Memory::allocate((length + 1) *
sizeof(
Char8)));
6146 if (!scratch)
return false;
6150 memcpy(scratch, begin, length *
sizeof(
Char8));
6151 scratch[length] = 0;
6153 *out_Result = convert_Stringo_number(scratch);
6156 if (scratch != buffer) Memory::deallocate(scratch);
6161 PUGI__FN
double round_nearest(
double Value)
6163 return floor(Value + 0.5);
6166 PUGI__FN
double round_nearest_nzero(
double Value)
6170 return (Value >= -0.5 && Value <= 0) ? ceil(Value) : floor(Value + 0.5);
6173 PUGI__FN
const Char8* qualified_Name(
const XPathNode& node)
6175 return node.GetAttribute() ? node.GetAttribute().Name() : node.GetNode().Name();
6178 PUGI__FN
const Char8* local_Name(
const XPathNode& node)
6180 const Char8* Name = qualified_Name(node);
6181 const Char8* p = FindChar(Name,
':');
6183 return p ? p + 1 : Name;
6186 struct namespace_uri_predicate
6188 const Char8* prefix;
6189 size_t prefix_length;
6191 namespace_uri_predicate(
const Char8* Name)
6193 const Char8* pos = FindChar(Name,
':');
6195 prefix = pos ? Name : 0;
6196 prefix_length = pos ?
static_cast<size_t>(pos - Name) : 0;
6199 bool operator()(
const Attribute& a)
const
6201 const Char8* Name = a.Name();
6203 if (!starts_with(Name,
"xmlns"))
return false;
6205 return prefix ? Name[5] ==
':' && strequalrange(Name + 6, prefix, prefix_length) : Name[5] == 0;
6209 PUGI__FN
const Char8* namespace_uri(
const Node& node)
6211 namespace_uri_predicate pred = node.Name();
6217 Attribute a = p.FindAttribute(pred);
6219 if (a)
return a.Value();
6227 PUGI__FN
const Char8* namespace_uri(
const Attribute& attr,
const Node& GetParent)
6229 namespace_uri_predicate pred = attr.Name();
6232 if (!pred.prefix)
return "";
6238 Attribute a = p.FindAttribute(pred);
6240 if (a)
return a.Value();
6248 PUGI__FN
const Char8* namespace_uri(
const XPathNode& node)
6250 return node.GetAttribute() ? namespace_uri(node.GetAttribute(), node.GetParent()) : namespace_uri(node.GetNode());
6253 PUGI__FN
void normalize_space(
Char8* buffer)
6255 Char8* Write = buffer;
6257 for (
Char8* it = buffer; *it; )
6261 if (PUGI__IS_CHARTYPE(ch, ct_space))
6264 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
6267 if (Write != buffer) *Write++ =
' ';
6273 if (Write != buffer && PUGI__IS_CHARTYPE(Write[-1], ct_space)) Write--;
6279 PUGI__FN
void translate(
Char8* buffer,
const Char8* from,
const Char8* to)
6281 size_t to_length = strlength(to);
6283 Char8* Write = buffer;
6287 PUGI__DMC_VOLATILE
Char8 ch = *buffer++;
6289 const Char8* pos = FindChar(from, ch);
6293 else if (static_cast<size_t>(pos - from) < to_length)
6294 *Write++ = to[pos - from];
6301 struct XPathVariableBoolean: XPathVariable
6303 XPathVariableBoolean(): Value(false)
6311 struct XPathVariableNumber: XPathVariable
6313 XPathVariableNumber(): Value(0)
6321 struct XPathVariableString: XPathVariable
6323 XPathVariableString(): Value(0)
6327 ~XPathVariableString()
6329 if (Value) Memory::deallocate(Value);
6336 struct XPathVariableNodeSet: XPathVariable
6342 static const XPathNodeSet dummy_NodeSet;
6344 PUGI__FN
unsigned int hash_string(
const Char8* str)
6347 unsigned int Result = 0;
6351 Result +=
static_cast<unsigned int>(*str++);
6352 Result += Result << 10;
6353 Result ^= Result >> 6;
6356 Result += Result << 3;
6357 Result ^= Result >> 11;
6358 Result += Result << 15;
6363 template <
typename T> PUGI__FN T* new_XPathVariable(
const Char8* Name)
6365 size_t length = strlength(Name);
6366 if (length == 0)
return 0;
6369 void* memory = Memory::allocate(
sizeof(T) + length *
sizeof(
Char8));
6370 if (!memory)
return 0;
6372 T* Result =
new (memory) T();
6374 memcpy(Result->Name, Name, (length + 1) *
sizeof(
Char8));
6384 return new_XPathVariable<XPathVariableNodeSet>(Name);
6387 return new_XPathVariable<XPathVariableNumber>(Name);
6390 return new_XPathVariable<XPathVariableString>(Name);
6393 return new_XPathVariable<XPathVariableBoolean>(Name);
6400 template <
typename T> PUGI__FN
void delete_XPathVariable(T* var)
6403 Memory::deallocate(var);
6406 PUGI__FN
void delete_XPathVariable(
XPathValueType Type, XPathVariable* var)
6411 delete_XPathVariable(static_cast<XPathVariableNodeSet*>(var));
6415 delete_XPathVariable(static_cast<XPathVariableNumber*>(var));
6419 delete_XPathVariable(static_cast<XPathVariableString*>(var));
6423 delete_XPathVariable(static_cast<XPathVariableBoolean*>(var));
6427 assert(!
"Invalid variable Type");
6431 PUGI__FN XPathVariable* GetVariable(XPathVariableSet* set,
const Char8* begin,
const Char8* end)
6435 size_t length =
static_cast<size_t>(end - begin);
6436 Char8* scratch = buffer;
6438 if (length >=
sizeof(buffer) /
sizeof(buffer[0]))
6441 scratch =
static_cast<Char8*
>(Memory::allocate((length + 1) *
sizeof(
Char8)));
6442 if (!scratch)
return 0;
6446 memcpy(scratch, begin, length *
sizeof(
Char8));
6447 scratch[length] = 0;
6449 XPathVariable* Result = set->Get(scratch);
6452 if (scratch != buffer) Memory::deallocate(scratch);
6460 PUGI__FN XPathNodeSet::CollectionType XPathSort(XPathNode* begin, XPathNode* end, XPathNodeSet::CollectionType Type,
bool rev)
6462 XPathNodeSet::CollectionType order = rev ? XPathNodeSet::TypeSortedReverse : XPathNodeSet::TypeSorted;
6464 if (Type == XPathNodeSet::TypeUnsorted)
6466 sort(begin, end, document_order_comparator());
6468 Type = XPathNodeSet::TypeSorted;
6471 if (Type != order) reverse(begin, end);
6476 PUGI__FN XPathNode XPathFirst(
const XPathNode* begin,
const XPathNode* end, XPathNodeSet::CollectionType Type)
6478 if (begin == end)
return XPathNode();
6482 case XPathNodeSet::TypeSorted:
6485 case XPathNodeSet::TypeSortedReverse:
6488 case XPathNodeSet::TypeUnsorted:
6489 return *min_element(begin, end, document_order_comparator());
6492 assert(!
"Invalid node set Type");
6497 class XPathNodeSet_raw
6499 XPathNodeSet::CollectionType _type;
6506 XPathNodeSet_raw(): _type(XPathNodeSet::TypeUnsorted), _begin(0), _end(0), _eos(0)
6510 XPathNode* begin()
const
6515 XPathNode* end()
const
6522 return _begin == _end;
6527 return static_cast<size_t>(_end - _begin);
6530 XPathNode first()
const
6532 return XPathFirst(_begin, _end, _type);
6535 void push_back(
const XPathNode& node, XPathAllocator* alloc)
6539 size_t capacity =
static_cast<size_t>(_eos - _begin);
6542 size_t new_capacity = capacity + capacity / 2 + 1;
6545 XPathNode* data =
static_cast<XPathNode*
>(alloc->reallocate(_begin, capacity *
sizeof(XPathNode), new_capacity *
sizeof(XPathNode)));
6550 _end = data + capacity;
6551 _eos = data + new_capacity;
6557 void append(
const XPathNode* begin_,
const XPathNode* end_, XPathAllocator* alloc)
6559 size_t size_ =
static_cast<size_t>(_end - _begin);
6560 size_t capacity =
static_cast<size_t>(_eos - _begin);
6561 size_t count =
static_cast<size_t>(end_ - begin_);
6563 if (size_ + count > capacity)
6566 XPathNode* data =
static_cast<XPathNode*
>(alloc->reallocate(_begin, capacity *
sizeof(XPathNode), (size_ + count) *
sizeof(XPathNode)));
6571 _end = data + size_;
6572 _eos = data + size_ + count;
6575 memcpy(_end, begin_, count *
sizeof(XPathNode));
6581 _type = XPathSort(_begin, _end, _type,
false);
6584 void truncate(XPathNode* pos)
6586 assert(_begin <= pos && pos <= _end);
6591 void RemoveDuplicates()
6593 if (_type == XPathNodeSet::TypeUnsorted)
6594 sort(_begin, _end, duplicate_comparator());
6596 _end = unique(_begin, _end);
6599 XPathNodeSet::CollectionType Type()
const
6604 void SetType(XPathNodeSet::CollectionType Value)
6615 size_t position, size;
6617 XPathContext(
const XPathNode& n_,
size_t position_,
size_t size_): n(n_), position(position_), size(size_)
6630 lex_greater_or_equal,
6642 lex_open_square_brace,
6643 lex_close_square_brace,
6653 struct XPathLexerString
6658 XPathLexerString(): begin(0), end(0)
6662 bool operator==(
const Char8* other)
const
6664 size_t length =
static_cast<size_t>(end - begin);
6666 return strequalrange(other, begin, length);
6673 const Char8* _cur_lexeme_pos;
6674 XPathLexerString _cur_lexeme_contents;
6676 lexeme_t _cur_lexeme;
6679 explicit XPathLexer(
const Char8* query): _cur(query)
6684 const Char8* state()
const
6691 const Char8* cur = _cur;
6693 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
6696 _cur_lexeme_pos = cur;
6701 _cur_lexeme = lex_eof;
6705 if (*(cur+1) ==
'=')
6708 _cur_lexeme = lex_greater_or_equal;
6713 _cur_lexeme = lex_greater;
6718 if (*(cur+1) ==
'=')
6721 _cur_lexeme = lex_less_or_equal;
6726 _cur_lexeme = lex_less;
6731 if (*(cur+1) ==
'=')
6734 _cur_lexeme = lex_not_equal;
6738 _cur_lexeme = lex_none;
6744 _cur_lexeme = lex_equal;
6750 _cur_lexeme = lex_plus;
6756 _cur_lexeme = lex_minus;
6762 _cur_lexeme = lex_multiply;
6768 _cur_lexeme = lex_union;
6775 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
6777 _cur_lexeme_contents.begin = cur;
6779 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
6781 if (cur[0] ==
':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
6785 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
6788 _cur_lexeme_contents.end = cur;
6790 _cur_lexeme = lex_var_ref;
6794 _cur_lexeme = lex_none;
6801 _cur_lexeme = lex_open_brace;
6807 _cur_lexeme = lex_close_brace;
6813 _cur_lexeme = lex_open_square_brace;
6819 _cur_lexeme = lex_close_square_brace;
6825 _cur_lexeme = lex_comma;
6830 if (*(cur+1) ==
'/')
6833 _cur_lexeme = lex_double_slash;
6838 _cur_lexeme = lex_slash;
6843 if (*(cur+1) ==
'.')
6846 _cur_lexeme = lex_double_dot;
6848 else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
6850 _cur_lexeme_contents.begin = cur;
6854 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
6856 _cur_lexeme_contents.end = cur;
6858 _cur_lexeme = lex_number;
6863 _cur_lexeme = lex_dot;
6869 _cur_lexeme = lex_axis_attribute;
6876 Char8 terminator = *cur;
6880 _cur_lexeme_contents.begin = cur;
6881 while (*cur && *cur != terminator) cur++;
6882 _cur_lexeme_contents.end = cur;
6885 _cur_lexeme = lex_none;
6889 _cur_lexeme = lex_quoted_string;
6896 if (*(cur+1) ==
':')
6899 _cur_lexeme = lex_double_colon;
6903 _cur_lexeme = lex_none;
6908 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
6910 _cur_lexeme_contents.begin = cur;
6912 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
6918 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
6921 _cur_lexeme_contents.end = cur;
6923 _cur_lexeme = lex_number;
6925 else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
6927 _cur_lexeme_contents.begin = cur;
6929 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
6937 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
6941 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
6945 _cur_lexeme_contents.end = cur;
6947 _cur_lexeme = lex_string;
6951 _cur_lexeme = lex_none;
6958 lexeme_t current()
const
6963 const Char8* current_pos()
const
6965 return _cur_lexeme_pos;
6968 const XPathLexerString& contents()
const
6970 assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
6972 return _cur_lexeme_contents;
6984 ast_op_less_or_equal,
6985 ast_op_greater_or_equal,
6996 ast_string_constant,
6997 ast_number_constant,
7003 ast_func_local_Name_0,
7004 ast_func_local_Name_1,
7005 ast_func_namespace_uri_0,
7006 ast_func_namespace_uri_1,
7012 ast_func_starts_with,
7014 ast_func_substring_before,
7015 ast_func_substring_after,
7016 ast_func_substring_2,
7017 ast_func_substring_3,
7018 ast_func_string_length_0,
7019 ast_func_string_length_1,
7020 ast_func_normalize_space_0,
7021 ast_func_normalize_space_1,
7041 axis_ancestor_or_self,
7045 axis_descendant_or_self,
7047 axis_following_sibling,
7051 axis_preceding_sibling,
7060 nodetest_type_comment,
7065 nodetest_all_in_namespace
7068 template <axis_t N>
struct axis_to_type
7070 static const axis_t axis;
7073 template <axis_t N>
const axis_t axis_to_type<N>::axis = N;
7087 XPathAstNode* _left;
7088 XPathAstNode* _right;
7089 XPathAstNode* _next;
7094 const Char8* string;
7098 XPathVariable* variable;
7100 const Char8* nodetest;
7103 XPathAstNode(
const XPathAstNode&);
7104 XPathAstNode& operator=(
const XPathAstNode&);
7106 template <
class Comp>
static bool compare_eq(XPathAstNode* lhs, XPathAstNode* rhs,
const XPathContext& c,
const XPathStack& stack,
const Comp& comp)
7113 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7115 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7118 XPathAllocatorCapture cr(stack.Result);
7120 XPathString ls = lhs->eval_string(c, stack);
7121 XPathString rs = rhs->eval_string(c, stack);
7123 return comp(ls, rs);
7128 XPathAllocatorCapture cr(stack.Result);
7130 XPathNodeSet_raw ls = lhs->eval_NodeSet(c, stack);
7131 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7133 for (
const XPathNode* li = ls.begin(); li != ls.end(); ++li)
7134 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7136 XPathAllocatorCapture cri(stack.Result);
7138 if (comp(string_Value(*li, stack.Result), string_Value(*ri, stack.Result)))
7153 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7156 XPathAllocatorCapture cr(stack.Result);
7158 double l = lhs->eval_number(c, stack);
7159 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7161 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7163 XPathAllocatorCapture cri(stack.Result);
7165 if (comp(l, convert_Stringo_number(string_Value(*ri, stack.Result).c_str())))
7173 XPathAllocatorCapture cr(stack.Result);
7175 XPathString l = lhs->eval_string(c, stack);
7176 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7178 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7180 XPathAllocatorCapture cri(stack.Result);
7182 if (comp(l, string_Value(*ri, stack.Result)))
7190 assert(!
"Wrong Types");
7194 template <
class Comp>
static bool compare_rel(XPathAstNode* lhs, XPathAstNode* rhs,
const XPathContext& c,
const XPathStack& stack,
const Comp& comp)
7199 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7202 XPathAllocatorCapture cr(stack.Result);
7204 XPathNodeSet_raw ls = lhs->eval_NodeSet(c, stack);
7205 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7207 for (
const XPathNode* li = ls.begin(); li != ls.end(); ++li)
7209 XPathAllocatorCapture cri(stack.Result);
7211 double l = convert_Stringo_number(string_Value(*li, stack.Result).c_str());
7213 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7215 XPathAllocatorCapture crii(stack.Result);
7217 if (comp(l, convert_Stringo_number(string_Value(*ri, stack.Result).c_str())))
7226 XPathAllocatorCapture cr(stack.Result);
7228 double l = lhs->eval_number(c, stack);
7229 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7231 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7233 XPathAllocatorCapture cri(stack.Result);
7235 if (comp(l, convert_Stringo_number(string_Value(*ri, stack.Result).c_str())))
7243 XPathAllocatorCapture cr(stack.Result);
7245 XPathNodeSet_raw ls = lhs->eval_NodeSet(c, stack);
7246 double r = rhs->eval_number(c, stack);
7248 for (
const XPathNode* li = ls.begin(); li != ls.end(); ++li)
7250 XPathAllocatorCapture cri(stack.Result);
7252 if (comp(convert_Stringo_number(string_Value(*li, stack.Result).c_str()), r))
7260 assert(!
"Wrong Types");
7265 void apply_predicate(XPathNodeSet_raw& ns,
size_t first, XPathAstNode* expr,
const XPathStack& stack)
7267 assert(ns.size() >= first);
7270 size_t size = ns.size() - first;
7272 XPathNode* last = ns.begin() + first;
7275 for (XPathNode* it = last; it != ns.end(); ++it, ++i)
7277 XPathContext c(*it, i, size);
7281 if (expr->eval_number(c, stack) == i)
7284 else if (expr->eval_boolean(c, stack))
7291 void apply_predicates(XPathNodeSet_raw& ns,
size_t first,
const XPathStack& stack)
7293 if (ns.size() == first)
return;
7295 for (XPathAstNode* pred = _right; pred; pred = pred->_next)
7297 apply_predicate(ns, first, pred->_left, stack);
7301 void step_push(XPathNodeSet_raw& ns,
const Attribute& a,
const Node& GetParent, XPathAllocator* alloc)
7305 const Char8* Name = a.Name();
7309 if (starts_with(Name,
"xmlns") && (Name[5] == 0 || Name[5] ==
':'))
return;
7314 if (strequal(Name, _data.nodetest)) ns.push_back(XPathNode(a, GetParent), alloc);
7317 case nodetest_type_node:
7319 ns.push_back(XPathNode(a, GetParent), alloc);
7322 case nodetest_all_in_namespace:
7323 if (starts_with(Name, _data.nodetest))
7324 ns.push_back(XPathNode(a, GetParent), alloc);
7332 void step_push(XPathNodeSet_raw& ns,
const Node& n, XPathAllocator* alloc)
7339 if (n.Type() ==
NodeElement && strequal(n.Name(), _data.nodetest)) ns.push_back(n, alloc);
7342 case nodetest_type_node:
7343 ns.push_back(n, alloc);
7346 case nodetest_type_comment:
7348 ns.push_back(n, alloc);
7351 case nodetest_type_text:
7353 ns.push_back(n, alloc);
7356 case nodetest_type_pi:
7358 ns.push_back(n, alloc);
7362 if (n.Type() ==
NodePi && strequal(n.Name(), _data.nodetest))
7363 ns.push_back(n, alloc);
7368 ns.push_back(n, alloc);
7371 case nodetest_all_in_namespace:
7372 if (n.Type() ==
NodeElement && starts_with(n.Name(), _data.nodetest))
7373 ns.push_back(n, alloc);
7377 assert(!
"Unknown axis");
7381 template <
class T>
void step_fill(XPathNodeSet_raw& ns,
const Node& n, XPathAllocator* alloc, T)
7383 const axis_t axis = T::axis;
7387 case axis_attribute:
7389 for (Attribute a = n.GetFirstAttribute(); a; a = a.GetNextAttribute())
7390 step_push(ns, a, n, alloc);
7397 for (Node c = n.GetFirstChild(); c; c = c.GetNextSibling())
7398 step_push(ns, c, alloc);
7403 case axis_descendant:
7404 case axis_descendant_or_self:
7406 if (axis == axis_descendant_or_self)
7407 step_push(ns, n, alloc);
7409 Node cur = n.GetFirstChild();
7411 while (cur && cur != n)
7413 step_push(ns, cur, alloc);
7415 if (cur.GetFirstChild())
7416 cur = cur.GetFirstChild();
7417 else if (cur.GetNextSibling())
7418 cur = cur.GetNextSibling();
7421 while (!cur.GetNextSibling() && cur != n)
7422 cur = cur.GetParent();
7424 if (cur != n) cur = cur.GetNextSibling();
7431 case axis_following_sibling:
7433 for (Node c = n.GetNextSibling(); c; c = c.GetNextSibling())
7434 step_push(ns, c, alloc);
7439 case axis_preceding_sibling:
7441 for (Node c = n.GetPreviousSibling(); c; c = c.GetPreviousSibling())
7442 step_push(ns, c, alloc);
7447 case axis_following:
7452 while (cur && !cur.GetNextSibling()) cur = cur.GetParent();
7453 cur = cur.GetNextSibling();
7457 step_push(ns, cur, alloc);
7459 if (cur.GetFirstChild())
7460 cur = cur.GetFirstChild();
7461 else if (cur.GetNextSibling())
7462 cur = cur.GetNextSibling();
7465 while (cur && !cur.GetNextSibling()) cur = cur.GetParent();
7466 cur = cur.GetNextSibling();
7475 case axis_preceding:
7479 while (cur && !cur.GetPreviousSibling()) cur = cur.GetParent();
7480 cur = cur.GetPreviousSibling();
7484 if (cur.GetLastChild())
7485 cur = cur.GetLastChild();
7489 step_push(ns, cur, alloc);
7491 if (cur.GetPreviousSibling())
7492 cur = cur.GetPreviousSibling();
7497 cur = cur.GetParent();
7500 if (!NodeIs_ancestor(cur, n)) step_push(ns, cur, alloc);
7502 while (!cur.GetPreviousSibling());
7504 cur = cur.GetPreviousSibling();
7515 case axis_ancestor_or_self:
7517 if (axis == axis_ancestor_or_self)
7518 step_push(ns, n, alloc);
7520 Node cur = n.GetParent();
7524 step_push(ns, cur, alloc);
7526 cur = cur.GetParent();
7534 step_push(ns, n, alloc);
7539 case axis_GetParent:
7541 if (n.GetParent()) step_push(ns, n.GetParent(), alloc);
7547 assert(!
"Unimplemented axis");
7551 template <
class T>
void step_fill(XPathNodeSet_raw& ns,
const Attribute& a,
const Node& p, XPathAllocator* alloc, T v)
7553 const axis_t axis = T::axis;
7558 case axis_ancestor_or_self:
7560 if (axis == axis_ancestor_or_self && _test == nodetest_type_node)
7561 step_push(ns, a, p, alloc);
7567 step_push(ns, cur, alloc);
7569 cur = cur.GetParent();
7575 case axis_descendant_or_self:
7578 if (_test == nodetest_type_node)
7579 step_push(ns, a, p, alloc);
7584 case axis_following:
7590 if (cur.GetFirstChild())
7591 cur = cur.GetFirstChild();
7592 else if (cur.GetNextSibling())
7593 cur = cur.GetNextSibling();
7596 while (cur && !cur.GetNextSibling()) cur = cur.GetParent();
7597 cur = cur.GetNextSibling();
7602 step_push(ns, cur, alloc);
7608 case axis_GetParent:
7610 step_push(ns, p, alloc);
7615 case axis_preceding:
7618 step_fill(ns, p, alloc, v);
7623 assert(!
"Unimplemented axis");
7627 template <
class T> XPathNodeSet_raw step_do(
const XPathContext& c,
const XPathStack& stack, T v)
7629 const axis_t axis = T::axis;
7630 bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_GetParent || axis == axis_preceding || axis == axis_self);
7632 XPathNodeSet_raw ns;
7633 ns.SetType((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? XPathNodeSet::TypeSortedReverse : XPathNodeSet::TypeSorted);
7637 XPathNodeSet_raw s = _left->eval_NodeSet(c, stack);
7640 if (axis == axis_self) ns.SetType(s.Type());
7642 for (
const XPathNode* it = s.begin(); it != s.end(); ++it)
7644 size_t size = ns.size();
7647 if (axis != axis_self && size != 0) ns.SetType(XPathNodeSet::TypeUnsorted);
7650 step_fill(ns, it->GetNode(), stack.Result, v);
7651 else if (attributes)
7652 step_fill(ns, it->GetAttribute(), it->GetParent(), stack.Result, v);
7654 apply_predicates(ns, size, stack);
7660 step_fill(ns, c.n.GetNode(), stack.Result, v);
7661 else if (attributes)
7662 step_fill(ns, c.n.GetAttribute(), c.n.GetParent(), stack.Result, v);
7664 apply_predicates(ns, 0, stack);
7669 if (axis != axis_GetChild && axis != axis_attribute && axis != axis_self && ns.Type() == XPathNodeSet::TypeUnsorted)
7670 ns.RemoveDuplicates();
7677 _type(static_cast<char>(Type)), _retType(static_cast<char>(retType_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7679 assert(Type == ast_string_constant);
7680 _data.string = Value;
7683 XPathAstNode(ast_type_t Type,
XPathValueType retType_,
double Value):
7684 _type(static_cast<char>(Type)), _retType(static_cast<char>(retType_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7686 assert(Type == ast_number_constant);
7687 _data.number = Value;
7690 XPathAstNode(ast_type_t Type,
XPathValueType retType_, XPathVariable* Value):
7691 _type(static_cast<char>(Type)), _retType(static_cast<char>(retType_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7693 assert(Type == ast_variable);
7694 _data.variable = Value;
7697 XPathAstNode(ast_type_t Type,
XPathValueType retType_, XPathAstNode* left = 0, XPathAstNode* right = 0):
7698 _type(static_cast<char>(Type)), _retType(static_cast<char>(retType_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
7702 XPathAstNode(ast_type_t Type, XPathAstNode* left, axis_t axis, nodetest_t test,
const Char8* contents):
7703 _type(static_cast<char>(Type)), _retType(
XPathTypeNodeSet), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(0), _next(0)
7705 _data.nodetest = contents;
7708 void SetNext(XPathAstNode* Value)
7713 void SetRight(XPathAstNode* Value)
7718 bool eval_boolean(
const XPathContext& c,
const XPathStack& stack)
7723 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
7726 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
7729 return compare_eq(_left, _right, c, stack, equal_to());
7731 case ast_op_not_equal:
7732 return compare_eq(_left, _right, c, stack, not_equal_to());
7735 return compare_rel(_left, _right, c, stack, less());
7737 case ast_op_greater:
7738 return compare_rel(_right, _left, c, stack, less());
7740 case ast_op_less_or_equal:
7741 return compare_rel(_left, _right, c, stack, less_equal());
7743 case ast_op_greater_or_equal:
7744 return compare_rel(_right, _left, c, stack, less_equal());
7746 case ast_func_starts_with:
7748 XPathAllocatorCapture cr(stack.Result);
7750 XPathString lr = _left->eval_string(c, stack);
7751 XPathString rr = _right->eval_string(c, stack);
7753 return starts_with(lr.c_str(), rr.c_str());
7756 case ast_func_contains:
7758 XPathAllocatorCapture cr(stack.Result);
7760 XPathString lr = _left->eval_string(c, stack);
7761 XPathString rr = _right->eval_string(c, stack);
7763 return FindSubstring(lr.c_str(), rr.c_str()) != 0;
7766 case ast_func_boolean:
7767 return _left->eval_boolean(c, stack);
7770 return !_left->eval_boolean(c, stack);
7775 case ast_func_false:
7780 if (c.n.GetAttribute())
return false;
7782 XPathAllocatorCapture cr(stack.Result);
7784 XPathString lang = _left->eval_string(c, stack);
7786 for (Node n = c.n.GetNode(); n; n = n.GetParent())
7788 Attribute a = n.GetAttribute(
"xml:lang");
7792 const Char8* Value = a.Value();
7795 for (
const Char8* lit = lang.c_str(); *lit; ++lit)
7797 if (tolower_ascii(*lit) != tolower_ascii(*Value))
return false;
7801 return *Value == 0 || *Value ==
'-';
7810 assert(_retType == _data.variable->Type());
7813 return _data.variable->GetBoolean();
7823 return convert_number_to_boolean(eval_number(c, stack));
7827 XPathAllocatorCapture cr(stack.Result);
7829 return !eval_string(c, stack).Empty();
7834 XPathAllocatorCapture cr(stack.Result);
7836 return !eval_NodeSet(c, stack).Empty();
7840 assert(!
"Wrong expression for return Type boolean");
7847 double eval_number(
const XPathContext& c,
const XPathStack& stack)
7852 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
7854 case ast_op_subtract:
7855 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
7857 case ast_op_multiply:
7858 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
7861 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
7864 return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
7867 return -_left->eval_number(c, stack);
7869 case ast_number_constant:
7870 return _data.number;
7873 return static_cast<double>(c.size);
7875 case ast_func_position:
7876 return static_cast<double>(c.position);
7878 case ast_func_count:
7880 XPathAllocatorCapture cr(stack.Result);
7882 return static_cast<double>(_left->eval_NodeSet(c, stack).size());
7885 case ast_func_string_length_0:
7887 XPathAllocatorCapture cr(stack.Result);
7889 return static_cast<double>(string_Value(c.n, stack.Result).length());
7892 case ast_func_string_length_1:
7894 XPathAllocatorCapture cr(stack.Result);
7896 return static_cast<double>(_left->eval_string(c, stack).length());
7899 case ast_func_number_0:
7901 XPathAllocatorCapture cr(stack.Result);
7903 return convert_Stringo_number(string_Value(c.n, stack.Result).c_str());
7906 case ast_func_number_1:
7907 return _left->eval_number(c, stack);
7911 XPathAllocatorCapture cr(stack.Result);
7915 XPathNodeSet_raw ns = _left->eval_NodeSet(c, stack);
7917 for (
const XPathNode* it = ns.begin(); it != ns.end(); ++it)
7919 XPathAllocatorCapture cri(stack.Result);
7921 r += convert_Stringo_number(string_Value(*it, stack.Result).c_str());
7927 case ast_func_floor:
7929 double r = _left->eval_number(c, stack);
7931 return r == r ? floor(r) : r;
7934 case ast_func_ceiling:
7936 double r = _left->eval_number(c, stack);
7938 return r == r ? ceil(r) : r;
7941 case ast_func_round:
7942 return round_nearest_nzero(_left->eval_number(c, stack));
7946 assert(_retType == _data.variable->Type());
7949 return _data.variable->GetNumber();
7959 return eval_boolean(c, stack) ? 1 : 0;
7963 XPathAllocatorCapture cr(stack.Result);
7965 return convert_Stringo_number(eval_string(c, stack).c_str());
7970 XPathAllocatorCapture cr(stack.Result);
7972 return convert_Stringo_number(eval_string(c, stack).c_str());
7976 assert(!
"Wrong expression for return Type number");
7984 XPathString eval_string_concat(
const XPathContext& c,
const XPathStack& stack)
7986 assert(_type == ast_func_concat);
7988 XPathAllocatorCapture ct(stack.temp);
7992 for (XPathAstNode* nc = _right; nc; nc = nc->_next) count++;
7995 XPathString static_buffer[4];
7996 XPathString* buffer = static_buffer;
7999 if (count >
sizeof(static_buffer) /
sizeof(static_buffer[0]))
8001 buffer =
static_cast<XPathString*
>(stack.temp->allocate(count *
sizeof(XPathString)));
8006 XPathStack swapped_stack = {stack.temp, stack.Result};
8008 buffer[0] = _left->eval_string(c, swapped_stack);
8011 for (XPathAstNode* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
8012 assert(pos == count);
8016 for (
size_t i = 0; i < count; ++i) length += buffer[i].length();
8019 Char8* Result =
static_cast<Char8*
>(stack.Result->allocate((length + 1) *
sizeof(
Char8)));
8024 for (
size_t j = 0; j < count; ++j)
8025 for (
const Char8* bi = buffer[j].c_str(); *bi; ++bi)
8030 return XPathString(Result,
true);
8033 XPathString eval_string(
const XPathContext& c,
const XPathStack& stack)
8037 case ast_string_constant:
8038 return XPathStringConst(_data.string);
8040 case ast_func_local_Name_0:
8044 return XPathStringConst(local_Name(na));
8047 case ast_func_local_Name_1:
8049 XPathAllocatorCapture cr(stack.Result);
8051 XPathNodeSet_raw ns = _left->eval_NodeSet(c, stack);
8052 XPathNode na = ns.first();
8054 return XPathStringConst(local_Name(na));
8057 case ast_func_Name_0:
8061 return XPathStringConst(qualified_Name(na));
8064 case ast_func_Name_1:
8066 XPathAllocatorCapture cr(stack.Result);
8068 XPathNodeSet_raw ns = _left->eval_NodeSet(c, stack);
8069 XPathNode na = ns.first();
8071 return XPathStringConst(qualified_Name(na));
8074 case ast_func_namespace_uri_0:
8078 return XPathStringConst(namespace_uri(na));
8081 case ast_func_namespace_uri_1:
8083 XPathAllocatorCapture cr(stack.Result);
8085 XPathNodeSet_raw ns = _left->eval_NodeSet(c, stack);
8086 XPathNode na = ns.first();
8088 return XPathStringConst(namespace_uri(na));
8091 case ast_func_string_0:
8092 return string_Value(c.n, stack.Result);
8094 case ast_func_string_1:
8095 return _left->eval_string(c, stack);
8097 case ast_func_concat:
8098 return eval_string_concat(c, stack);
8100 case ast_func_substring_before:
8102 XPathAllocatorCapture cr(stack.temp);
8104 XPathStack swapped_stack = {stack.temp, stack.Result};
8106 XPathString s = _left->eval_string(c, swapped_stack);
8107 XPathString p = _right->eval_string(c, swapped_stack);
8109 const Char8* pos = FindSubstring(s.c_str(), p.c_str());
8111 return pos ? XPathString(s.c_str(), pos, stack.Result) : XPathString();
8114 case ast_func_substring_after:
8116 XPathAllocatorCapture cr(stack.temp);
8118 XPathStack swapped_stack = {stack.temp, stack.Result};
8120 XPathString s = _left->eval_string(c, swapped_stack);
8121 XPathString p = _right->eval_string(c, swapped_stack);
8123 const Char8* pos = FindSubstring(s.c_str(), p.c_str());
8124 if (!pos)
return XPathString();
8126 const Char8* Result = pos + p.length();
8128 return s.uses_heap() ? XPathString(Result, stack.Result) : XPathStringConst(Result);
8131 case ast_func_substring_2:
8133 XPathAllocatorCapture cr(stack.temp);
8135 XPathStack swapped_stack = {stack.temp, stack.Result};
8137 XPathString s = _left->eval_string(c, swapped_stack);
8138 size_t s_length = s.length();
8140 double first = round_nearest(_right->eval_number(c, stack));
8142 if (is_nan(first))
return XPathString();
8143 else if (first >= s_length + 1)
return XPathString();
8145 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8146 assert(1 <= pos && pos <= s_length + 1);
8148 const Char8* rbegin = s.c_str() + (pos - 1);
8150 return s.uses_heap() ? XPathString(rbegin, stack.Result) : XPathStringConst(rbegin);
8153 case ast_func_substring_3:
8155 XPathAllocatorCapture cr(stack.temp);
8157 XPathStack swapped_stack = {stack.temp, stack.Result};
8159 XPathString s = _left->eval_string(c, swapped_stack);
8160 size_t s_length = s.length();
8162 double first = round_nearest(_right->eval_number(c, stack));
8163 double last = first + round_nearest(_right->_next->eval_number(c, stack));
8165 if (is_nan(first) || is_nan(last))
return XPathString();
8166 else if (first >= s_length + 1)
return XPathString();
8167 else if (first >= last)
return XPathString();
8168 else if (last < 1)
return XPathString();
8170 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8171 size_t end = last >= s_length + 1 ? s_length + 1 :
static_cast<size_t>(last);
8173 assert(1 <= pos && pos <= end && end <= s_length + 1);
8174 const Char8* rbegin = s.c_str() + (pos - 1);
8175 const Char8* rend = s.c_str() + (end - 1);
8177 return (end == s_length + 1 && !s.uses_heap()) ? XPathStringConst(rbegin) : XPathString(rbegin, rend, stack.Result);
8180 case ast_func_normalize_space_0:
8182 XPathString s = string_Value(c.n, stack.Result);
8184 normalize_space(s.data(stack.Result));
8189 case ast_func_normalize_space_1:
8191 XPathString s = _left->eval_string(c, stack);
8193 normalize_space(s.data(stack.Result));
8198 case ast_func_translate:
8200 XPathAllocatorCapture cr(stack.temp);
8202 XPathStack swapped_stack = {stack.temp, stack.Result};
8204 XPathString s = _left->eval_string(c, stack);
8205 XPathString from = _right->eval_string(c, swapped_stack);
8206 XPathString to = _right->_next->eval_string(c, swapped_stack);
8208 translate(s.data(stack.Result), from.c_str(), to.c_str());
8215 assert(_retType == _data.variable->Type());
8218 return XPathStringConst(_data.variable->GetString());
8228 return XPathStringConst(eval_boolean(c, stack) ?
"true" :
"false");
8231 return convert_number_to_string(eval_number(c, stack), stack.Result);
8235 XPathAllocatorCapture cr(stack.temp);
8237 XPathStack swapped_stack = {stack.temp, stack.Result};
8239 XPathNodeSet_raw ns = eval_NodeSet(c, swapped_stack);
8240 return ns.Empty() ? XPathString() : string_Value(ns.first(), stack.Result);
8244 assert(!
"Wrong expression for return Type string");
8245 return XPathString();
8251 XPathNodeSet_raw eval_NodeSet(
const XPathContext& c,
const XPathStack& stack)
8257 XPathAllocatorCapture cr(stack.temp);
8259 XPathStack swapped_stack = {stack.temp, stack.Result};
8261 XPathNodeSet_raw ls = _left->eval_NodeSet(c, swapped_stack);
8262 XPathNodeSet_raw rs = _right->eval_NodeSet(c, stack);
8265 rs.SetType(XPathNodeSet::TypeUnsorted);
8267 rs.append(ls.begin(), ls.end(), stack.Result);
8268 rs.RemoveDuplicates();
8274 case ast_filter_posinv:
8276 XPathNodeSet_raw set = _left->eval_NodeSet(c, stack);
8279 if (_type == ast_filter) set.sort_do();
8281 apply_predicate(set, 0, _right, stack);
8287 return XPathNodeSet_raw();
8294 return step_do(c, stack, axis_to_type<axis_ancestor>());
8296 case axis_ancestor_or_self:
8297 return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());
8299 case axis_attribute:
8300 return step_do(c, stack, axis_to_type<axis_attribute>());
8303 return step_do(c, stack, axis_to_type<axis_GetChild>());
8305 case axis_descendant:
8306 return step_do(c, stack, axis_to_type<axis_descendant>());
8308 case axis_descendant_or_self:
8309 return step_do(c, stack, axis_to_type<axis_descendant_or_self>());
8311 case axis_following:
8312 return step_do(c, stack, axis_to_type<axis_following>());
8314 case axis_following_sibling:
8315 return step_do(c, stack, axis_to_type<axis_following_sibling>());
8317 case axis_namespace:
8319 return XPathNodeSet_raw();
8321 case axis_GetParent:
8322 return step_do(c, stack, axis_to_type<axis_GetParent>());
8324 case axis_preceding:
8325 return step_do(c, stack, axis_to_type<axis_preceding>());
8327 case axis_preceding_sibling:
8328 return step_do(c, stack, axis_to_type<axis_preceding_sibling>());
8331 return step_do(c, stack, axis_to_type<axis_self>());
8334 assert(!
"Unknown axis");
8335 return XPathNodeSet_raw();
8339 case ast_step_GetRoot:
8343 XPathNodeSet_raw ns;
8345 ns.SetType(XPathNodeSet::TypeSorted);
8347 if (c.n.GetNode()) ns.push_back(c.n.GetNode().GetRoot(), stack.Result);
8348 else if (c.n.GetAttribute()) ns.push_back(c.n.GetParent().GetRoot(), stack.Result);
8355 assert(_retType == _data.variable->Type());
8359 const XPathNodeSet& s = _data.variable->GetNodeSet();
8361 XPathNodeSet_raw ns;
8363 ns.SetType(s.Type());
8364 ns.append(s.begin(), s.end(), stack.Result);
8373 assert(!
"Wrong expression for return Type node set");
8374 return XPathNodeSet_raw();
8382 case ast_func_position:
8385 case ast_string_constant:
8386 case ast_number_constant:
8391 case ast_step_GetRoot:
8396 case ast_filter_posinv:
8400 if (_left && !_left->is_posinv())
return false;
8402 for (XPathAstNode* n = _right; n; n = n->_next)
8403 if (!n->is_posinv())
return false;
8417 XPathAllocator* _alloc;
8420 const Char8* _query;
8421 XPathVariableSet* _variables;
8423 XPathParseResult* _Result;
8425 void throw_error(
const char* message)
8427 _Result->error = message;
8428 _Result->Offset = _lexer.current_pos() - _query;
8433 void throw_error_oom()
8435 throw std::bad_alloc();
8440 void* Result = _alloc->allocate_nothrow(
sizeof(XPathAstNode));
8442 if (!Result) throw_error_oom();
8447 const Char8* alloc_string(
const XPathLexerString& Value)
8451 size_t length =
static_cast<size_t>(Value.end - Value.begin);
8453 Char8* c =
static_cast<Char8*
>(_alloc->allocate_nothrow((length + 1) *
sizeof(
Char8)));
8454 if (!c) throw_error_oom();
8456 memcpy(c, Value.begin, length *
sizeof(
Char8));
8464 XPathAstNode* ParseFunctionHelper(ast_type_t Type0, ast_type_t Type1,
size_t argc, XPathAstNode* args[2])
8468 if (argc == 1 && args[0]->retType() !=
XPathTypeNodeSet) throw_error(
"Function has to be applied to node set");
8470 return new (alloc_node()) XPathAstNode(argc == 0 ? Type0 : Type1,
XPathTypeString, args[0]);
8473 XPathAstNode* ParseFunction(
const XPathLexerString& Name,
size_t argc, XPathAstNode* args[2])
8475 switch (Name.begin[0])
8478 if (Name ==
"boolean" && argc == 1)
8479 return new (alloc_node()) XPathAstNode(ast_func_boolean,
XPathTypeBoolean, args[0]);
8484 if (Name ==
"count" && argc == 1)
8486 if (args[0]->retType() !=
XPathTypeNodeSet) throw_error(
"Function has to be applied to node set");
8487 return new (alloc_node()) XPathAstNode(ast_func_count,
XPathTypeNumber, args[0]);
8489 else if (Name ==
"contains" && argc == 2)
8490 return new (alloc_node()) XPathAstNode(ast_func_contains,
XPathTypeString, args[0], args[1]);
8491 else if (Name ==
"concat" && argc >= 2)
8492 return new (alloc_node()) XPathAstNode(ast_func_concat,
XPathTypeString, args[0], args[1]);
8493 else if (Name ==
"ceiling" && argc == 1)
8494 return new (alloc_node()) XPathAstNode(ast_func_ceiling,
XPathTypeNumber, args[0]);
8499 if (Name ==
"false" && argc == 0)
8501 else if (Name ==
"floor" && argc == 1)
8502 return new (alloc_node()) XPathAstNode(ast_func_floor,
XPathTypeNumber, args[0]);
8507 if (Name ==
"id" && argc == 1)
8508 return new (alloc_node()) XPathAstNode(ast_func_id,
XPathTypeNodeSet, args[0]);
8513 if (Name ==
"last" && argc == 0)
8514 return new (alloc_node()) XPathAstNode(ast_func_last,
XPathTypeNumber);
8515 else if (Name ==
"lang" && argc == 1)
8516 return new (alloc_node()) XPathAstNode(ast_func_lang,
XPathTypeBoolean, args[0]);
8517 else if (Name ==
"local-Name" && argc <= 1)
8518 return ParseFunctionHelper(ast_func_local_Name_0, ast_func_local_Name_1, argc, args);
8523 if (Name ==
"Name" && argc <= 1)
8524 return ParseFunctionHelper(ast_func_Name_0, ast_func_Name_1, argc, args);
8525 else if (Name ==
"namespace-uri" && argc <= 1)
8526 return ParseFunctionHelper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args);
8527 else if (Name ==
"normalize-space" && argc <= 1)
8528 return new (alloc_node()) XPathAstNode(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1,
XPathTypeString, args[0], args[1]);
8529 else if (Name ==
"not" && argc == 1)
8530 return new (alloc_node()) XPathAstNode(ast_func_not,
XPathTypeBoolean, args[0]);
8531 else if (Name ==
"number" && argc <= 1)
8532 return new (alloc_node()) XPathAstNode(argc == 0 ? ast_func_number_0 : ast_func_number_1,
XPathTypeNumber, args[0]);
8537 if (Name ==
"position" && argc == 0)
8538 return new (alloc_node()) XPathAstNode(ast_func_position,
XPathTypeNumber);
8543 if (Name ==
"round" && argc == 1)
8544 return new (alloc_node()) XPathAstNode(ast_func_round,
XPathTypeNumber, args[0]);
8549 if (Name ==
"string" && argc <= 1)
8550 return new (alloc_node()) XPathAstNode(argc == 0 ? ast_func_string_0 : ast_func_string_1,
XPathTypeString, args[0]);
8551 else if (Name ==
"string-length" && argc <= 1)
8552 return new (alloc_node()) XPathAstNode(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1,
XPathTypeString, args[0]);
8553 else if (Name ==
"starts-with" && argc == 2)
8554 return new (alloc_node()) XPathAstNode(ast_func_starts_with,
XPathTypeBoolean, args[0], args[1]);
8555 else if (Name ==
"substring-before" && argc == 2)
8556 return new (alloc_node()) XPathAstNode(ast_func_substring_before,
XPathTypeString, args[0], args[1]);
8557 else if (Name ==
"substring-after" && argc == 2)
8558 return new (alloc_node()) XPathAstNode(ast_func_substring_after,
XPathTypeString, args[0], args[1]);
8559 else if (Name ==
"substring" && (argc == 2 || argc == 3))
8560 return new (alloc_node()) XPathAstNode(argc == 2 ? ast_func_substring_2 : ast_func_substring_3,
XPathTypeString, args[0], args[1]);
8561 else if (Name ==
"sum" && argc == 1)
8563 if (args[0]->retType() !=
XPathTypeNodeSet) throw_error(
"Function has to be applied to node set");
8564 return new (alloc_node()) XPathAstNode(ast_func_sum,
XPathTypeNumber, args[0]);
8570 if (Name ==
"translate" && argc == 3)
8571 return new (alloc_node()) XPathAstNode(ast_func_translate,
XPathTypeString, args[0], args[1]);
8572 else if (Name ==
"true" && argc == 0)
8581 throw_error(
"Unrecognized function or wrong parameter count");
8586 axis_t ParseAxisName(
const XPathLexerString& Name,
bool& specified)
8590 switch (Name.begin[0])
8593 if (Name ==
"ancestor")
8594 return axis_ancestor;
8595 else if (Name ==
"ancestor-or-self")
8596 return axis_ancestor_or_self;
8597 else if (Name ==
"GetAttribute")
8598 return axis_attribute;
8603 if (Name ==
"GetChild")
8604 return axis_GetChild;
8609 if (Name ==
"descendant")
8610 return axis_descendant;
8611 else if (Name ==
"descendant-or-self")
8612 return axis_descendant_or_self;
8617 if (Name ==
"following")
8618 return axis_following;
8619 else if (Name ==
"following-sibling")
8620 return axis_following_sibling;
8625 if (Name ==
"namespace")
8626 return axis_namespace;
8631 if (Name ==
"GetParent")
8632 return axis_GetParent;
8633 else if (Name ==
"preceding")
8634 return axis_preceding;
8635 else if (Name ==
"preceding-sibling")
8636 return axis_preceding_sibling;
8651 return axis_GetChild;
8654 nodetest_t ParseNodeTest_type(
const XPathLexerString& Name)
8656 switch (Name.begin[0])
8659 if (Name ==
"comment")
8660 return nodetest_type_comment;
8666 return nodetest_type_node;
8671 if (Name ==
"processing-instruction")
8672 return nodetest_type_pi;
8678 return nodetest_type_text;
8686 return nodetest_none;
8690 XPathAstNode* ParsePrimaryExpression()
8692 switch (_lexer.current())
8696 XPathLexerString Name = _lexer.contents();
8699 throw_error(
"Unknown variable: variable set is not provided");
8701 XPathVariable* var = GetVariable(_variables, Name.begin, Name.end);
8704 throw_error(
"Unknown variable: variable set does not contain the given Name");
8708 return new (alloc_node()) XPathAstNode(ast_variable, var->Type(), var);
8711 case lex_open_brace:
8715 XPathAstNode* n = ParseExpression();
8717 if (_lexer.current() != lex_close_brace)
8718 throw_error(
"Unmatched braces");
8725 case lex_quoted_string:
8727 const Char8* Value = alloc_string(_lexer.contents());
8729 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_string_constant,
XPathTypeString, Value);
8739 if (!convert_Stringo_number(_lexer.contents().begin, _lexer.contents().end, &Value))
8742 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_number_constant,
XPathTypeNumber, Value);
8750 XPathAstNode* args[2] = {0};
8753 XPathLexerString
function = _lexer.contents();
8756 XPathAstNode* LastArg = 0;
8758 if (_lexer.current() != lex_open_brace)
8759 throw_error(
"Unrecognized function call");
8762 if (_lexer.current() != lex_close_brace)
8763 args[argc++] = ParseExpression();
8765 while (_lexer.current() != lex_close_brace)
8767 if (_lexer.current() != lex_comma)
8768 throw_error(
"No comma between function arguments");
8771 XPathAstNode* n = ParseExpression();
8773 if (argc < 2) args[argc] = n;
8774 else LastArg->SetNext(n);
8782 return ParseFunction(
function, argc, args);
8786 throw_error(
"Unrecognizable primary expression");
8795 XPathAstNode* ParseFilterExpression()
8797 XPathAstNode* n = ParsePrimaryExpression();
8799 while (_lexer.current() == lex_open_square_brace)
8803 XPathAstNode* expr = ParseExpression();
8805 if (n->retType() !=
XPathTypeNodeSet) throw_error(
"Predicate has to be applied to node set");
8807 bool posinv = expr->retType() !=
XPathTypeNumber && expr->is_posinv();
8809 n =
new (alloc_node()) XPathAstNode(posinv ? ast_filter_posinv : ast_filter,
XPathTypeNodeSet, n, expr);
8811 if (_lexer.current() != lex_close_square_brace)
8812 throw_error(
"Unmatched square brace");
8825 XPathAstNode* ParseStep(XPathAstNode* set)
8828 throw_error(
"Step has to be applied to node set");
8830 bool axis_specified =
false;
8831 axis_t axis = axis_GetChild;
8833 if (_lexer.current() == lex_axis_attribute)
8835 axis = axis_attribute;
8836 axis_specified =
true;
8840 else if (_lexer.current() == lex_dot)
8844 return new (alloc_node()) XPathAstNode(ast_step, set, axis_self, nodetest_type_node, 0);
8846 else if (_lexer.current() == lex_double_dot)
8850 return new (alloc_node()) XPathAstNode(ast_step, set, axis_GetParent, nodetest_type_node, 0);
8853 nodetest_t nt_type = nodetest_none;
8854 XPathLexerString nt_Name;
8856 if (_lexer.current() == lex_string)
8859 nt_Name = _lexer.contents();
8863 if (_lexer.current() == lex_double_colon)
8866 if (axis_specified) throw_error(
"Two axis specifiers in one step");
8868 axis = ParseAxisName(nt_Name, axis_specified);
8870 if (!axis_specified) throw_error(
"Unknown axis");
8875 if (_lexer.current() == lex_multiply)
8877 nt_type = nodetest_all;
8878 nt_Name = XPathLexerString();
8881 else if (_lexer.current() == lex_string)
8883 nt_Name = _lexer.contents();
8886 else throw_error(
"Unrecognized node test");
8889 if (nt_type == nodetest_none)
8892 if (_lexer.current() == lex_open_brace)
8896 if (_lexer.current() == lex_close_brace)
8900 nt_type = ParseNodeTest_type(nt_Name);
8902 if (nt_type == nodetest_none) throw_error(
"Unrecognized node Type");
8904 nt_Name = XPathLexerString();
8906 else if (nt_Name ==
"processing-instruction")
8908 if (_lexer.current() != lex_quoted_string)
8909 throw_error(
"Only literals are allowed as arguments to processing-instruction()");
8911 nt_type = nodetest_pi;
8912 nt_Name = _lexer.contents();
8915 if (_lexer.current() != lex_close_brace)
8916 throw_error(
"Unmatched brace near processing-instruction()");
8920 throw_error(
"Unmatched brace near node Type test");
8926 if (nt_Name.end - nt_Name.begin > 2 && nt_Name.end[-2] ==
':' && nt_Name.end[-1] ==
'*')
8930 nt_type = nodetest_all_in_namespace;
8932 else nt_type = nodetest_Name;
8936 else if (_lexer.current() == lex_multiply)
8938 nt_type = nodetest_all;
8941 else throw_error(
"Unrecognized node test");
8943 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_step, set, axis, nt_type, alloc_string(nt_Name));
8945 XPathAstNode* last = 0;
8947 while (_lexer.current() == lex_open_square_brace)
8951 XPathAstNode* expr = ParseExpression();
8953 XPathAstNode* pred =
new (alloc_node()) XPathAstNode(ast_predicate,
XPathTypeNodeSet, expr);
8955 if (_lexer.current() != lex_close_square_brace)
8956 throw_error(
"Unmatched square brace");
8959 if (last) last->SetNext(pred);
8960 else n->SetRight(pred);
8969 XPathAstNode* ParseRelativeLocation_Path(XPathAstNode* set)
8971 XPathAstNode* n = ParseStep(set);
8973 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
8975 lexeme_t l = _lexer.current();
8978 if (l == lex_double_slash)
8979 n =
new (alloc_node()) XPathAstNode(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
8989 XPathAstNode* ParseLocationPath()
8991 if (_lexer.current() == lex_slash)
8995 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_step_GetRoot,
XPathTypeNodeSet);
8998 lexeme_t l = _lexer.current();
9000 if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
9001 return ParseRelativeLocation_Path(n);
9005 else if (_lexer.current() == lex_double_slash)
9009 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_step_GetRoot,
XPathTypeNodeSet);
9010 n =
new (alloc_node()) XPathAstNode(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9012 return ParseRelativeLocation_Path(n);
9016 return ParseRelativeLocation_Path(0);
9023 XPathAstNode* ParsePathExpression()
9032 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
9033 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
9034 _lexer.current() == lex_string)
9036 if (_lexer.current() == lex_string)
9039 const Char8* state = _lexer.state();
9041 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
9043 if (*state !=
'(')
return ParseLocationPath();
9046 if (ParseNodeTest_type(_lexer.contents()) != nodetest_none)
return ParseLocationPath();
9049 XPathAstNode* n = ParseFilterExpression();
9051 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
9053 lexeme_t l = _lexer.current();
9056 if (l == lex_double_slash)
9058 if (n->retType() !=
XPathTypeNodeSet) throw_error(
"Step has to be applied to node set");
9060 n =
new (alloc_node()) XPathAstNode(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9064 return ParseRelativeLocation_Path(n);
9069 else return ParseLocationPath();
9073 XPathAstNode* ParseUnionExpression()
9075 XPathAstNode* n = ParsePathExpression();
9077 while (_lexer.current() == lex_union)
9081 XPathAstNode* expr = ParseUnionExpression();
9084 throw_error(
"Union operator has to be applied to node sets");
9086 n =
new (alloc_node()) XPathAstNode(ast_op_union,
XPathTypeNodeSet, n, expr);
9093 XPathAstNode* ParseUnaryExpression()
9095 if (_lexer.current() == lex_minus)
9099 XPathAstNode* expr = ParseUnaryExpression();
9101 return new (alloc_node()) XPathAstNode(ast_op_negate,
XPathTypeNumber, expr);
9103 else return ParseUnionExpression();
9110 XPathAstNode* ParseMultiplicativeExpression()
9112 XPathAstNode* n = ParseUnaryExpression();
9114 while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string &&
9115 (_lexer.contents() ==
"mod" || _lexer.contents() ==
"div")))
9117 ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply :
9118 _lexer.contents().begin[0] ==
'd' ? ast_op_divide : ast_op_mod;
9121 XPathAstNode* expr = ParseUnaryExpression();
9132 XPathAstNode* ParseAdditiveExpression()
9134 XPathAstNode* n = ParseMultiplicativeExpression();
9136 while (_lexer.current() == lex_plus || _lexer.current() == lex_minus)
9138 lexeme_t l = _lexer.current();
9142 XPathAstNode* expr = ParseMultiplicativeExpression();
9144 n =
new (alloc_node()) XPathAstNode(l == lex_plus ? ast_op_add : ast_op_subtract,
XPathTypeNumber, n, expr);
9155 XPathAstNode* ParseRelationalExpression()
9157 XPathAstNode* n = ParseAdditiveExpression();
9159 while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal ||
9160 _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal)
9162 lexeme_t l = _lexer.current();
9165 XPathAstNode* expr = ParseAdditiveExpression();
9167 n =
new (alloc_node()) XPathAstNode(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater :
9168 l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal,
XPathTypeBoolean, n, expr);
9177 XPathAstNode* ParseEqualityExpression()
9179 XPathAstNode* n = ParseRelationalExpression();
9181 while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal)
9183 lexeme_t l = _lexer.current();
9187 XPathAstNode* expr = ParseRelationalExpression();
9189 n =
new (alloc_node()) XPathAstNode(l == lex_equal ? ast_op_equal : ast_op_not_equal,
XPathTypeBoolean, n, expr);
9196 XPathAstNode* ParseAndExpression()
9198 XPathAstNode* n = ParseEqualityExpression();
9200 while (_lexer.current() == lex_string && _lexer.contents() ==
"and")
9204 XPathAstNode* expr = ParseEqualityExpression();
9206 n =
new (alloc_node()) XPathAstNode(ast_op_and,
XPathTypeBoolean, n, expr);
9213 XPathAstNode* ParseOrExpression()
9215 XPathAstNode* n = ParseAndExpression();
9217 while (_lexer.current() == lex_string && _lexer.contents() ==
"or")
9221 XPathAstNode* expr = ParseAndExpression();
9230 XPathAstNode* ParseExpression()
9232 return ParseOrExpression();
9235 XPathParser(
const Char8* query, XPathVariableSet* variables, XPathAllocator* alloc, XPathParseResult* Result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _Result(Result)
9239 XPathAstNode* parse()
9241 XPathAstNode* Result = ParseExpression();
9243 if (_lexer.current() != lex_eof)
9246 throw_error(
"Incorrect query");
9252 static XPathAstNode* parse(
const Char8* query, XPathVariableSet* variables, XPathAllocator* alloc, XPathParseResult* Result)
9254 XPathParser parser(query, variables, alloc, Result);
9256 return parser.parse();
9260 struct XPathQueryImpl
9262 static XPathQueryImpl* create()
9264 void* memory = Memory::allocate(
sizeof(XPathQueryImpl));
9266 return new (memory) XPathQueryImpl();
9269 static void destroy(
void* ptr)
9274 static_cast<XPathQueryImpl*
>(ptr)->alloc.release();
9277 Memory::deallocate(ptr);
9280 XPathQueryImpl(): GetRoot(0), alloc(&block)
9285 XPathAstNode* GetRoot;
9286 XPathAllocator alloc;
9287 XPathMemoryBlock block;
9290 PUGI__FN XPathString EvaluateString_impl(XPathQueryImpl* impl,
const XPathNode& n, XPathStackData& sd)
9292 if (!impl)
return XPathString();
9294 XPathContext c(n, 1, 1);
9296 return impl->GetRoot->eval_string(c, sd.stack);
9310 PUGI__FN
XPathNode::XPathNode(
const Attribute& attribute_,
const Node& GetParent_): TargetNode(attribute_ ? GetParent_ : Node()), _attribute(attribute_)
9316 return _attribute ? Node() : TargetNode;
9326 return _attribute ? TargetNode : TargetNode.
GetParent();
9329 PUGI__FN
static void unspecified_bool_XPathNode(XPathNode***)
9333 PUGI__FN XPathNode::operator XPathNode::unspecified_bool_type()
const
9335 return (TargetNode || _attribute) ? unspecified_bool_XPathNode : 0;
9340 return !(TargetNode || _attribute);
9345 return TargetNode == n.TargetNode && _attribute == n._attribute;
9350 return TargetNode != n.TargetNode || _attribute != n._attribute;
9354 PUGI__FN
bool operator&&(
const XPathNode& lhs,
bool rhs)
9356 return (
bool)lhs && rhs;
9359 PUGI__FN
bool operator||(
const XPathNode& lhs,
bool rhs)
9361 return (
bool)lhs || rhs;
9365 PUGI__FN
void XPathNodeSet::_assign(const_iterator begin_, const_iterator end_)
9367 assert(begin_ <= end_);
9369 size_t size_ =
static_cast<size_t>(end_ - begin_);
9374 if (Begin != &Storage) internal::Memory::deallocate(Begin);
9377 if (begin_ != end_) Storage = *begin_;
9380 End = &Storage + size_;
9385 XPathNode* storage =
static_cast<XPathNode*
>(internal::Memory::allocate(size_ *
sizeof(XPathNode)));
9389 throw std::bad_alloc();
9392 memcpy(storage, begin_, size_ *
sizeof(XPathNode));
9395 if (Begin != &Storage) internal::Memory::deallocate(Begin);
9399 End = storage + size_;
9407 PUGI__FN
XPathNodeSet::XPathNodeSet(const_iterator begin_, const_iterator end_, CollectionType Type_): TypeOrder(Type_), Begin(&Storage), End(&Storage)
9409 _assign(begin_, end_);
9414 if (Begin != &Storage) internal::Memory::deallocate(Begin);
9419 _assign(ns.Begin, ns.End);
9424 if (
this == &ns)
return *
this;
9426 TypeOrder = ns.TypeOrder;
9427 _assign(ns.Begin, ns.End);
9444 return Begin == End;
9449 assert(index <
size());
9450 return Begin[index];
9465 TypeOrder = internal::XPathSort(Begin, End, TypeOrder, reverse);
9470 return internal::XPathFirst(Begin, End, TypeOrder);
9477 PUGI__FN XPathParseResult::operator bool()
const
9496 return static_cast<const internal::XPathVariableNodeSet*
>(
this)->Name;
9499 return static_cast<const internal::XPathVariableNumber*
>(
this)->Name;
9502 return static_cast<const internal::XPathVariableString*
>(
this)->Name;
9505 return static_cast<const internal::XPathVariableBoolean*
>(
this)->Name;
9508 assert(!
"Invalid variable Type");
9525 return (
ValueType ==
XPathTypeNumber) ?
static_cast<const internal::XPathVariableNumber*
>(
this)->Value : internal::gen_nan();
9531 return Value ? Value :
"";
9536 return (
ValueType ==
XPathTypeNodeSet) ?
static_cast<const internal::XPathVariableNodeSet*
>(
this)->Value : internal::dummy_NodeSet;
9543 static_cast<internal::XPathVariableBoolean*
>(
this)->Value = Value;
9551 static_cast<internal::XPathVariableNumber*
>(
this)->Value = Value;
9559 internal::XPathVariableString* var =
static_cast<internal::XPathVariableString*
>(
this);
9562 size_t size = (internal::strlength(Value) + 1) *
sizeof(
Char8);
9564 Char8* copy =
static_cast<Char8*
>(internal::Memory::allocate(size));
9565 if (!copy)
return false;
9567 memcpy(copy, Value, size);
9570 if (var->Value) internal::Memory::deallocate(var->Value);
9580 static_cast<internal::XPathVariableNodeSet*
>(
this)->Value = Value;
9586 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i) _data[i] = 0;
9591 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
9593 XPathVariable* var = _data[i];
9599 internal::delete_XPathVariable(var->ValueType, var);
9606 PUGI__FN XPathVariable* XPathVariableSet::Find(
const Char8* Name)
const
9608 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
9609 size_t hash = internal::hash_string(Name) % hash_size;
9612 for (XPathVariable* var = _data[hash]; var; var = var->NextVariable)
9613 if (internal::strequal(var->Name(), Name))
9621 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
9622 size_t hash = internal::hash_string(Name) % hash_size;
9625 for (XPathVariable* var = _data[hash]; var; var = var->NextVariable)
9626 if (internal::strequal(var->Name(), Name))
9627 return var->
Type() == Type ? var : 0;
9630 XPathVariable* Result = internal::new_XPathVariable(Type, Name);
9634 Result->ValueType = Type;
9635 Result->NextVariable = _data[hash];
9637 _data[hash] = Result;
9646 return var ? var->Set(Value) :
false;
9652 return var ? var->Set(Value) :
false;
9658 return var ? var->Set(Value) :
false;
9664 return var ? var->Set(Value) :
false;
9677 PUGI__FN XPathQuery::XPathQuery(
const Char8* query, XPathVariableSet* variables): QueryImplementation(0)
9679 internal::XPathQueryImpl* qimpl = internal::XPathQueryImpl::create();
9683 throw std::bad_alloc();
9687 internal::buffer_holder impl_holder(qimpl, internal::XPathQueryImpl::destroy);
9689 qimpl->GetRoot = internal::XPathParser::parse(query, variables, &qimpl->alloc, &ResultCache);
9693 QueryImplementation =
static_cast<internal::XPathQueryImpl*
>(impl_holder.release());
9694 ResultCache.error = 0;
9701 internal::XPathQueryImpl::destroy(QueryImplementation);
9708 return static_cast<internal::XPathQueryImpl*
>(QueryImplementation)->GetRoot->retType();
9713 if (!QueryImplementation)
return false;
9715 internal::XPathContext c(n, 1, 1);
9716 internal::XPathStackData sd;
9718 return static_cast<internal::XPathQueryImpl*
>(QueryImplementation)->GetRoot->eval_boolean(c, sd.stack);
9723 if (!QueryImplementation)
return internal::gen_nan();
9725 internal::XPathContext c(n, 1, 1);
9726 internal::XPathStackData sd;
9728 return static_cast<internal::XPathQueryImpl*
>(QueryImplementation)->GetRoot->eval_number(c, sd.stack);
9733 internal::XPathStackData sd;
9735 return internal::EvaluateString_impl(static_cast<internal::XPathQueryImpl*>(QueryImplementation), n, sd).c_str();
9740 internal::XPathStackData sd;
9742 internal::XPathString r = internal::EvaluateString_impl(static_cast<internal::XPathQueryImpl*>(QueryImplementation), n, sd);
9744 size_t full_size = r.length() + 1;
9748 size_t size = (full_size < capacity) ? full_size : capacity;
9751 memcpy(buffer, r.c_str(), (size - 1) *
sizeof(
Char8));
9752 buffer[size - 1] = 0;
9760 if (!QueryImplementation)
return XPathNodeSet();
9762 internal::XPathAstNode* GetRoot =
static_cast<internal::XPathQueryImpl*
>(QueryImplementation)->GetRoot;
9766 XPathParseResult res;
9767 res.error =
"Expression does not evaluate to node set";
9769 String ErrorMessage(
String(res.Description()) +
"\nError:" + res.error +
"\nAt Offset: " +
ToString(res.Offset));
9774 internal::XPathContext c(n, 1, 1);
9775 internal::XPathStackData sd;
9778 internal::XPathNodeSet_raw r = GetRoot->eval_NodeSet(c, sd.stack);
9780 return XPathNodeSet(r.begin(), r.end(), r.Type());
9788 PUGI__FN
static void unspecified_bool_XPathQuery(XPathQuery***)
9792 PUGI__FN XPathQuery::operator XPathQuery::unspecified_bool_type()
const
9794 return QueryImplementation ? unspecified_bool_XPathQuery : 0;
9799 return !QueryImplementation;
9804 XPathQuery q(query, variables);
9810 XPathNodeSet s = query.EvaluateNodeSet(*
this);
9811 return s.Empty() ? XPathNode() : s.first();
9816 XPathQuery q(query, variables);
9822 return query.EvaluateNodeSet(*
this);
9832 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
9833 # pragma warning(pop)
9837 #undef PUGI__NO_INLINE
9838 #undef PUGI__STATIC_ASSERT
9839 #undef PUGI__DMC_VOLATILE
9840 #undef PUGI__MSVC_CRT_VERSION
9841 #undef PUGI__NS_BEGIN
9844 #undef PUGI__FN_NO_INLINE
9845 #undef PUGI__IS_CHARTYPE_IMPL
9846 #undef PUGI__IS_CHARTYPE
9847 #undef PUGI__IS_CHARTYPEX
9850 #undef PUGI__PUSHNODE
9851 #undef PUGI__POPNODE
9852 #undef PUGI__SCANFOR
9853 #undef PUGI__SCANWHILE
9855 #undef PUGI__THROW_ERROR
9856 #undef PUGI__CHECK_ERROR