56 #ifndef SOURCE_XML_CPP
57 #define SOURCE_XML_CPP
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;
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
1712 static Char8* ParseWnorm(Char8* s, Char8 end_quote)
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);
1764 static Char8* ParseWconv(Char8* s, Char8 end_quote)
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);
1800 static Char8*
ParseEol(Char8* s, Char8 end_quote)
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);
1832 static Char8* ParseSimple(Char8* s, Char8 end_quote)
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)
1922 Char8* ParseDocTypePrimitive(Char8* s)
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] ==
'>');
1955 Char8* ParseDocTypeIgnore(Char8* s)
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] ==
'>')
1981 Char8* ParseDocTypeGroup(Char8* s, Char8 endch,
bool toplevel)
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;
2674 void Write(Char8 d0, Char8 d1)
2676 if (bufsize + 2 > bufcapacity) flush();
2678 buffer[bufsize + 0] = d0;
2679 buffer[bufsize + 1] = d1;
2683 void Write(Char8 d0, Char8 d1, Char8 d2)
2685 if (bufsize + 3 > bufcapacity) flush();
2687 buffer[bufsize + 0] = d0;
2688 buffer[bufsize + 1] = d1;
2689 buffer[bufsize + 2] = d2;
2693 void Write(Char8 d0, Char8 d1, Char8 d2, Char8 d3)
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;
2704 void Write(Char8 d0, Char8 d1, Char8 d2, Char8 d3, Char8 d4)
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;
2716 void Write(Char8 d0, Char8 d1, Char8 d2, Char8 d3, Char8 d4, Char8 d5)
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;
3156 PUGI__FN ParseResult LoadFileImpl(Document& doc, FILE* file,
unsigned int options,
Encoding DocumentEncoding)
3162 ParseStatus size_Status = GetFile_size(file, size);
3167 return make_ParseResult(size_Status);
3171 char* contents =
static_cast<char*
>(Memory::allocate(size > 0 ? size : 1));
3180 size_t read_size = fread(contents, 1, size, file);
3183 if (read_size != size)
3185 Memory::deallocate(contents);
3189 return doc.LoadBufferInplaceOwn(contents, size, options, DocumentEncoding);
3192 template <
typename T>
struct StreamChunk
3194 static StreamChunk* create()
3196 void* memory = Memory::allocate(
sizeof(StreamChunk));
3198 return new (memory) StreamChunk();
3201 static void destroy(
void* ptr)
3203 StreamChunk* chunk =
static_cast<StreamChunk*
>(ptr);
3208 StreamChunk* next = chunk->next;
3209 Memory::deallocate(chunk);
3214 StreamChunk(): next(0), size(0)
3221 T data[MemoryPage_size /
sizeof(T)];
3224 template <
typename T> PUGI__FN
ParseStatus LoadStreamDataNoseek(std::basic_istream<T>& stream,
void** out_buffer,
size_t* out_size)
3226 buffer_holder chunks(0, StreamChunk<T>::destroy);
3230 StreamChunk<T>* last = 0;
3232 while (!stream.eof())
3235 StreamChunk<T>* chunk = StreamChunk<T>::create();
3239 if (last) last = last->next = chunk;
3240 else chunks.data = last = chunk;
3243 stream.read(chunk->data, static_cast<std::streamsize>(
sizeof(chunk->data) /
sizeof(T)));
3244 chunk->size =
static_cast<size_t>(stream.gcount()) *
sizeof(T);
3247 if (stream.bad() || (!stream.eof() && stream.fail()))
return StatusIOError;
3251 total += chunk->size;
3255 char* buffer =
static_cast<char*
>(Memory::allocate(total));
3258 char* Write = buffer;
3260 for (StreamChunk<T>* chunk =
static_cast<StreamChunk<T>*
>(chunks.data); chunk; chunk = chunk->next)
3262 assert(Write + chunk->size <= buffer + total);
3263 memcpy(Write, chunk->data, chunk->size);
3264 Write += chunk->size;
3267 assert(Write == buffer + total);
3270 *out_buffer = buffer;
3276 template <
typename T> PUGI__FN
ParseStatus LoadStreamDataSeek(std::basic_istream<T>& stream,
void** out_buffer,
size_t* out_size)
3279 typename std::basic_istream<T>::pos_type pos = stream.tellg();
3280 stream.seekg(0, std::ios::end);
3281 std::streamoff length = stream.tellg() - pos;
3287 size_t read_length =
static_cast<size_t>(length);
3289 if (static_cast<std::streamsize>(read_length) != length || length < 0)
return StatusOutOfMemory;
3292 buffer_holder buffer(Memory::allocate((read_length > 0 ? read_length : 1) *
sizeof(T)), Memory::deallocate);
3295 stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
3298 if (stream.bad() || (!stream.eof() && stream.fail()))
return StatusIOError;
3301 size_t actual_length =
static_cast<size_t>(stream.gcount());
3302 assert(actual_length <= read_length);
3304 *out_buffer = buffer.release();
3305 *out_size = actual_length *
sizeof(T);
3310 template <
typename T> PUGI__FN ParseResult LoadStreamImpl(Document& doc, std::basic_istream<T>& stream,
unsigned int options,
Encoding DocumentEncoding)
3316 ParseStatus Status = (stream.tellg() < 0) ? LoadStreamDataNoseek(stream, &buffer, &size) : LoadStreamDataSeek(stream, &buffer, &size);
3317 if (Status !=
StatusOk)
return make_ParseResult(Status);
3319 return doc.LoadBufferInplaceOwn(buffer, size, options, DocumentEncoding);
3323 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__))
3324 PUGI__FN FILE* open_file_wide(
const wchar_t* Path,
const wchar_t* mode)
3326 return _wfopen(Path, mode);
3329 PUGI__FN
char* convert_Path_heap(
const wchar_t* str)
3334 size_t length = wcslen(str);
3335 size_t size = AsUtf8_begin(str, length);
3338 char* Result =
static_cast<char*
>(Memory::allocate(size + 1));
3339 if (!Result)
return 0;
3342 AsUtf8_end(Result, size, str, length);
3347 PUGI__FN FILE* open_file_wide(
const wchar_t* Path,
const wchar_t* mode)
3350 char* Path_utf8 = convert_Path_heap(Path);
3351 if (!Path_utf8)
return 0;
3354 char mode_ascii[4] = {0};
3355 for (
size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);
3358 FILE* Result = fopen(Path_utf8, mode_ascii);
3361 Memory::deallocate(Path_utf8);
3367 PUGI__FN
bool SaveFileImpl(
const Document& doc, FILE* file,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding)
3369 if (!file)
return false;
3371 WriterFile WriterInstance(file);
3372 doc.Save(WriterInstance, indent, flags, DocumentEncoding);
3374 int Result = ferror(file);
3391 size_t Result = fwrite(data, 1, size, static_cast<FILE*>(TargetFile));
3396 PUGI__FN
WriterStream::WriterStream(std::basic_ostream<
char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
3400 PUGI__FN
WriterStream::WriterStream(std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
3408 assert(!wide_stream);
3409 narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
3413 assert(wide_stream);
3414 assert(size %
sizeof(
wchar_t) == 0);
3416 wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size /
sizeof(
wchar_t)));
3431 return TraversalDepth;
3452 PUGI__FN
static void unspecified_bool_Attribute(Attribute***)
3456 PUGI__FN Attribute::operator Attribute::unspecified_bool_type()
const
3458 return AttributeData ? unspecified_bool_Attribute : 0;
3463 return !AttributeData;
3468 return (AttributeData == r.AttributeData);
3473 return (AttributeData != r.AttributeData);
3478 return (AttributeData < r.AttributeData);
3483 return (AttributeData > r.AttributeData);
3488 return (AttributeData <= r.AttributeData);
3493 return (AttributeData >= r.AttributeData);
3498 return AttributeData ?
Attribute(AttributeData->GetNextAttribute) : Attribute();
3503 return AttributeData && AttributeData->prev_attribute_c->GetNextAttribute ?
Attribute(AttributeData->prev_attribute_c) :
Attribute();
3508 return (AttributeData && AttributeData->Value) ? AttributeData->Value : def;
3513 return internal::GetValue_int(AttributeData ? AttributeData->Value : 0, def);
3518 return internal::GetValue_uint(AttributeData ? AttributeData->Value : 0, def);
3523 return internal::GetValue_double(AttributeData ? AttributeData->Value : 0, def);
3527 {
return (AttributeData ?
ToWhole(AttributeData->Value) : def); }
3530 {
return (AttributeData ?
ToInteger(AttributeData->Value) : def); }
3533 {
return (AttributeData ?
ToReal(AttributeData->Value) : def); }
3537 return internal::GetValue_float(AttributeData ? AttributeData->Value : 0, def);
3542 return internal::GetValue_bool(AttributeData ? AttributeData->Value : 0, def);
3547 return !AttributeData;
3552 return (AttributeData && AttributeData->Name) ? AttributeData->Name :
"";
3557 return (AttributeData && AttributeData->Value) ? AttributeData->Value :
"";
3562 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(AttributeData) /
sizeof(AttributeStruct));
3567 return AttributeData;
3602 if (!AttributeData)
return false;
3604 return internal::strcpy_insitu(AttributeData->Name, AttributeData->header, internal::MemoryPage_Name_allocated_mask, rhs);
3609 if (!AttributeData)
return false;
3611 return internal::strcpy_insitu(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3616 if (!AttributeData)
return false;
3618 return internal::SetValue_convert(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3623 if (!AttributeData)
return false;
3625 return internal::SetValue_convert(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3630 if (!AttributeData)
return false;
3632 return internal::SetValue_convert(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3637 if (!AttributeData)
return false;
3639 return internal::SetValue_convert(AttributeData->Value, AttributeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3643 PUGI__FN
bool operator&&(
const Attribute& lhs,
bool rhs)
3645 return (
bool)lhs && rhs;
3648 PUGI__FN
bool operator||(
const Attribute& lhs,
bool rhs)
3650 return (
bool)lhs || rhs;
3662 PUGI__FN
Node::Node(NodeStruct* p): NodeData(p)
3666 PUGI__FN
static void unspecified_bool_Node(Node***)
3672 return NodeData ? unspecified_bool_Node : 0;
3702 return ObjectRange<NodeIterator>(
begin(),
end());
3705 PUGI__FN ObjectRange<NamedNodeIterator>
Node::GetChildren(
const Char8* Name_)
const
3707 return ObjectRange<NamedNodeIterator>(NamedNodeIterator(
GetChild(Name_), Name_), NamedNodeIterator());
3769 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
3770 if (i->Name && internal::strequal(Name_, i->Name))
return Node(i);
3779 for (AttributeStruct* i =
NodeData->GetFirstAttribute; i; i = i->GetNextAttribute)
3780 if (i->Name && internal::strequal(Name_, i->Name))
3781 return Attribute(i);
3790 for (NodeStruct* i =
NodeData->GetNextSibling; i; i = i->GetNextSibling)
3791 if (i->Name && internal::strequal(Name_, i->Name))
return Node(i);
3808 for (NodeStruct* i =
NodeData->prev_sibling_c; i->GetNextSibling; i = i->prev_sibling_c)
3809 if (i->Name && internal::strequal(Name_, i->Name))
return Node(i);
3831 internal::MemoryPage* page =
reinterpret_cast<internal::MemoryPage*
>(
NodeData->header & internal::MemoryPage_pointer_mask);
3833 return Node(static_cast<internal::DocumentStruct*>(page->allocator));
3845 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
3846 if (i->Value && internal::is_text_node(i))
3864 return NodeData &&
NodeData->GetFirstAttribute ? Attribute(
NodeData->GetFirstAttribute->prev_attribute_c) : Attribute();
3884 return internal::strcpy_insitu(
NodeData->Name,
NodeData->header, internal::MemoryPage_Name_allocated_mask, rhs);
3900 return internal::strcpy_insitu(
NodeData->Value,
NodeData->header, internal::MemoryPage_Value_allocated_mask, rhs);
3911 Attribute a(internal::AppendAttribute_ll(
NodeData, internal::GetAllocator(
NodeData)));
3921 Attribute a(internal::allocate_attribute(internal::GetAllocator(
NodeData)));
3922 if (!a)
return Attribute();
3926 AttributeStruct* head =
NodeData->GetFirstAttribute;
3930 a.AttributeData->prev_attribute_c = head->prev_attribute_c;
3931 head->prev_attribute_c = a.AttributeData;
3934 a.AttributeData->prev_attribute_c = a.AttributeData;
3936 a.AttributeData->GetNextAttribute = head;
3937 NodeData->GetFirstAttribute = a.AttributeData;
3947 AttributeStruct* cur = attr.AttributeData;
3949 while (cur->prev_attribute_c->GetNextAttribute) cur = cur->prev_attribute_c;
3951 if (cur !=
NodeData->GetFirstAttribute)
return Attribute();
3953 Attribute a(internal::allocate_attribute(internal::GetAllocator(
NodeData)));
3954 if (!a)
return Attribute();
3958 if (attr.AttributeData->prev_attribute_c->GetNextAttribute)
3959 attr.AttributeData->prev_attribute_c->GetNextAttribute = a.AttributeData;
3961 NodeData->GetFirstAttribute = a.AttributeData;
3963 a.AttributeData->prev_attribute_c = attr.AttributeData->prev_attribute_c;
3964 a.AttributeData->GetNextAttribute = attr.AttributeData;
3965 attr.AttributeData->prev_attribute_c = a.AttributeData;
3975 AttributeStruct* cur = attr.AttributeData;
3977 while (cur->prev_attribute_c->GetNextAttribute) cur = cur->prev_attribute_c;
3979 if (cur !=
NodeData->GetFirstAttribute)
return Attribute();
3981 Attribute a(internal::allocate_attribute(internal::GetAllocator(
NodeData)));
3982 if (!a)
return Attribute();
3986 if (attr.AttributeData->GetNextAttribute)
3987 attr.AttributeData->GetNextAttribute->prev_attribute_c = a.AttributeData;
3989 NodeData->GetFirstAttribute->prev_attribute_c = a.AttributeData;
3991 a.AttributeData->GetNextAttribute = attr.AttributeData->GetNextAttribute;
3992 a.AttributeData->prev_attribute_c = attr.AttributeData;
3993 attr.AttributeData->GetNextAttribute = a.AttributeData;
4000 if (!proto)
return Attribute();
4010 if (!proto)
return Attribute();
4020 if (!proto)
return Attribute();
4030 if (!proto)
return Attribute();
4040 if (!internal::allow_InsertChild(this->
Type(), Type_))
return Node();
4051 if (!internal::allow_InsertChild(this->
Type(), Type_))
return Node();
4053 Node n(internal::allocate_node(internal::GetAllocator(
NodeData), Type_));
4054 if (!n)
return Node();
4058 NodeStruct* head =
NodeData->GetFirstChild;
4062 n.NodeData->prev_sibling_c = head->prev_sibling_c;
4063 head->prev_sibling_c = n.NodeData;
4066 n.NodeData->prev_sibling_c = n.NodeData;
4068 n.NodeData->GetNextSibling = head;
4069 NodeData->GetFirstChild = n.NodeData;
4078 if (!internal::allow_InsertChild(this->
Type(), Type_))
return Node();
4079 if (!node.NodeData || node.NodeData->GetParent !=
NodeData)
return Node();
4081 Node n(internal::allocate_node(internal::GetAllocator(
NodeData), Type_));
4082 if (!n)
return Node();
4086 if (node.NodeData->prev_sibling_c->GetNextSibling)
4087 node.NodeData->prev_sibling_c->GetNextSibling = n.NodeData;
4089 NodeData->GetFirstChild = n.NodeData;
4091 n.NodeData->prev_sibling_c = node.NodeData->prev_sibling_c;
4092 n.NodeData->GetNextSibling = node.NodeData;
4093 node.NodeData->prev_sibling_c = n.NodeData;
4102 if (!internal::allow_InsertChild(this->
Type(), Type_))
return Node();
4103 if (!node.NodeData || node.NodeData->GetParent !=
NodeData)
return Node();
4105 Node n(internal::allocate_node(internal::GetAllocator(
NodeData), Type_));
4106 if (!n)
return Node();
4110 if (node.NodeData->GetNextSibling)
4111 node.NodeData->GetNextSibling->prev_sibling_c = n.NodeData;
4113 NodeData->GetFirstChild->prev_sibling_c = n.NodeData;
4115 n.NodeData->GetNextSibling = node.NodeData->GetNextSibling;
4116 n.NodeData->prev_sibling_c = node.NodeData;
4117 node.NodeData->GetNextSibling = n.NodeData;
4128 Result.SetName(Name_);
4137 Result.SetName(Name_);
4146 Result.SetName(Name_);
4155 Result.SetName(Name_);
4164 if (Result) internal::recursive_copy_skip(Result, proto, Result);
4173 if (Result) internal::recursive_copy_skip(Result, proto, Result);
4182 if (Result) internal::recursive_copy_skip(Result, proto, Result);
4191 if (Result) internal::recursive_copy_skip(Result, proto, Result);
4203 if (!
NodeData || !a.AttributeData)
return false;
4206 AttributeStruct* attr = a.AttributeData;
4208 while (attr->prev_attribute_c->GetNextAttribute) attr = attr->prev_attribute_c;
4210 if (attr !=
NodeData->GetFirstAttribute)
return false;
4212 if (a.AttributeData->GetNextAttribute) a.AttributeData->GetNextAttribute->prev_attribute_c = a.AttributeData->prev_attribute_c;
4213 else if (
NodeData->GetFirstAttribute)
NodeData->GetFirstAttribute->prev_attribute_c = a.AttributeData->prev_attribute_c;
4215 if (a.AttributeData->prev_attribute_c->GetNextAttribute) a.AttributeData->prev_attribute_c->GetNextAttribute = a.AttributeData->GetNextAttribute;
4216 else NodeData->GetFirstAttribute = a.AttributeData->GetNextAttribute;
4218 internal::destroy_attribute(a.AttributeData, internal::GetAllocator(
NodeData));
4230 if (!
NodeData || !n.NodeData || n.NodeData->GetParent !=
NodeData)
return false;
4232 if (n.NodeData->GetNextSibling) n.NodeData->GetNextSibling->prev_sibling_c = n.NodeData->prev_sibling_c;
4233 else if (
NodeData->GetFirstChild)
NodeData->GetFirstChild->prev_sibling_c = n.NodeData->prev_sibling_c;
4235 if (n.NodeData->prev_sibling_c->GetNextSibling) n.NodeData->prev_sibling_c->GetNextSibling = n.NodeData->GetNextSibling;
4236 else NodeData->GetFirstChild = n.NodeData->GetNextSibling;
4238 internal::destroy_node(n.NodeData, internal::GetAllocator(
NodeData));
4247 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
4248 if (i->Name && internal::strequal(Name_, i->Name))
4250 for (AttributeStruct* a = i->GetFirstAttribute; a; a = a->GetNextAttribute)
4251 if (internal::strequal(AttrName, a->Name) && internal::strequal(AttrValue, a->Value))
4262 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
4263 for (AttributeStruct* a = i->GetFirstAttribute; a; a = a->GetNextAttribute)
4264 if (internal::strequal(AttrName, a->Name) && internal::strequal(AttrValue, a->Value))
4272 Node cursor = *
this;
4274 String Result = cursor.Name();
4276 while (cursor.GetParent())
4278 cursor = cursor.GetParent();
4280 String temp = cursor.Name();
4293 if (!
NodeData || !Path_ || !Path_[0])
return found;
4295 if (Path_[0] == delimiter)
4298 found = found.GetRoot();
4302 const Char8* Path_segment = Path_;
4304 while (*Path_segment == delimiter) ++Path_segment;
4306 const Char8* Path_segment_end = Path_segment;
4308 while (*Path_segment_end && *Path_segment_end != delimiter) ++Path_segment_end;
4310 if (Path_segment == Path_segment_end)
return found;
4312 const Char8* NextSegment = Path_segment_end;
4314 while (*NextSegment == delimiter) ++NextSegment;
4316 if (*Path_segment ==
'.' && Path_segment + 1 == Path_segment_end)
4317 return found.FirstElementByPath(NextSegment, delimiter);
4318 else if (*Path_segment ==
'.' && *(Path_segment+1) ==
'.' && Path_segment + 2 == Path_segment_end)
4319 return found.GetParent().FirstElementByPath(NextSegment, delimiter);
4322 for (NodeStruct* j = found.NodeData->GetFirstChild; j; j = j->GetNextSibling)
4324 if (j->Name && internal::strequalrange(j->Name, Path_segment, static_cast<size_t>(Path_segment_end - Path_segment)))
4326 Node subsearch =
Node(j).FirstElementByPath(NextSegment, delimiter);
4328 if (subsearch)
return subsearch;
4338 walker.TraversalDepth = -1;
4340 Node arg_begin = *
this;
4341 if (!walker.OnTraversalBegin(arg_begin))
return false;
4347 ++walker.TraversalDepth;
4351 Node arg_for_each = cur;
4352 if (!walker.OnEachNode(arg_for_each))
4355 if (cur.GetFirstChild())
4357 ++walker.TraversalDepth;
4358 cur = cur.GetFirstChild();
4360 else if (cur.GetNextSibling())
4361 cur = cur.GetNextSibling();
4365 while (!cur.GetNextSibling() && cur != *
this && !cur.GetParent().Empty())
4367 --walker.TraversalDepth;
4368 cur = cur.GetParent();
4372 cur = cur.GetNextSibling();
4375 while (cur && cur != *
this);
4378 assert(walker.TraversalDepth == -1);
4380 Node arg_end = *
this;
4381 return walker.OnTraversalEnd(arg_end);
4386 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(
NodeData) /
sizeof(NodeStruct));
4394 PUGI__FN
void Node::Print(Writer& WriterInstance,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding,
unsigned int Depth)
const
4398 internal::BufferedWriter buffered_WriterInstance(WriterInstance, DocumentEncoding);
4400 internal::NodeOutput(buffered_WriterInstance, *
this, indent, flags, Depth);
4403 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
4405 WriterStream WriterInstance(stream);
4407 Print(WriterInstance, indent, flags, DocumentEncoding, Depth);
4410 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
4412 WriterStream WriterInstance(stream);
4423 const Char8* buffer =
static_cast<internal::DocumentStruct*
>(r)->buffer;
4425 if (!buffer)
return -1;
4435 return (
NodeData->header & internal::MemoryPage_Name_allocated_mask) ? -1 :
NodeData->Name - buffer;
4441 return (
NodeData->header & internal::MemoryPage_Value_allocated_mask) ? -1 :
NodeData->Value - buffer;
4449 PUGI__FN
bool operator&&(
const Node& lhs,
bool rhs)
4451 return (
bool)lhs && rhs;
4454 PUGI__FN
bool operator||(
const Node& lhs,
bool rhs)
4456 return (
bool)lhs || rhs;
4464 PUGI__FN NodeStruct* NodeText::Data()
const
4466 if (!RootNode || internal::is_text_node(RootNode))
return RootNode;
4468 for (NodeStruct* node = RootNode->GetFirstChild; node; node = node->GetNextSibling)
4469 if (internal::is_text_node(node))
4475 PUGI__FN NodeStruct* NodeText::DataNew()
4477 NodeStruct* d = Data();
4480 return Node(RootNode).AppendChild(
NodePcdata).InternalObject();
4487 PUGI__FN
static void unspecified_bool_Text(NodeText***)
4491 PUGI__FN NodeText::operator NodeText::unspecified_bool_type()
const
4493 return Data() ? unspecified_bool_Text : 0;
4508 NodeStruct* d = Data();
4510 return (d && d->Value) ? d->Value :
"";
4515 NodeStruct* d = Data();
4517 return (d && d->Value) ? d->Value : def;
4522 NodeStruct* d = Data();
4524 return internal::GetValue_int(d ? d->Value : 0, def);
4529 NodeStruct* d = Data();
4531 return internal::GetValue_uint(d ? d->Value : 0, def);
4536 NodeStruct* d = Data();
4538 return internal::GetValue_double(d ? d->Value : 0, def);
4543 NodeStruct* d = Data();
4545 return internal::GetValue_float(d ? d->Value : 0, def);
4565 NodeStruct* d = Data();
4567 return internal::GetValue_bool(d ? d->Value : 0, def);
4572 NodeStruct* dn = DataNew();
4574 return dn ? internal::strcpy_insitu(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4579 NodeStruct* dn = DataNew();
4581 return dn ? internal::SetValue_convert(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4586 NodeStruct* dn = DataNew();
4588 return dn ? internal::SetValue_convert(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4593 NodeStruct* dn = DataNew();
4595 return dn ? internal::SetValue_convert(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4600 NodeStruct* dn = DataNew();
4602 return dn ? internal::SetValue_convert(dn->Value, dn->header, internal::MemoryPage_Value_allocated_mask, rhs) : false;
4637 return Node(Data());
4641 PUGI__FN
bool operator&&(
const Text& lhs,
bool rhs)
4643 return (
bool)lhs && rhs;
4646 PUGI__FN
bool operator||(
const Text& lhs,
bool rhs)
4648 return (
bool)lhs || rhs;
4666 return TargetNode.
NodeData == rhs.TargetNode.NodeData && ParentNode.
NodeData == rhs.ParentNode.NodeData;
4671 return TargetNode.
NodeData != rhs.TargetNode.NodeData || ParentNode.
NodeData != rhs.ParentNode.NodeData;
4683 return const_cast<Node*
>(&TargetNode);
4727 return TargetAttribute.AttributeData == rhs.TargetAttribute.AttributeData && ParentNode.
NodeData == rhs.ParentNode.NodeData;
4732 return TargetAttribute.AttributeData != rhs.TargetAttribute.AttributeData || ParentNode.
NodeData != rhs.ParentNode.NodeData;
4737 assert(TargetAttribute.AttributeData);
4738 return TargetAttribute;
4743 assert(TargetAttribute.AttributeData);
4744 return const_cast<Attribute*
>(&TargetAttribute);
4749 assert(TargetAttribute.AttributeData);
4750 TargetAttribute.AttributeData = TargetAttribute.AttributeData->GetNextAttribute;
4784 return TargetNode == rhs.TargetNode;
4789 return TargetNode != rhs.TargetNode;
4801 return const_cast<Node*
>(&TargetNode);
4822 PUGI__FN ParseResult::operator bool()
const
4834 case StatusIOError:
return "Error reading from file/stream";
4850 default:
return "Unknown error";
4874 for (
Node cur = proto.GetFirstChild(); cur; cur = cur.GetNextSibling())
4878 PUGI__FN
void Document::create()
4881 PUGI__STATIC_ASSERT(offsetof(internal::MemoryPage, data) +
sizeof(internal::DocumentStruct) + internal::MemoryPage_alignment <=
sizeof(_memory));
4884 void* page_memory =
reinterpret_cast<void*
>((
reinterpret_cast<uintptr_t
>(_memory) + (internal::MemoryPage_alignment - 1)) & ~(internal::MemoryPage_alignment - 1));
4887 internal::MemoryPage* page = internal::MemoryPage::construct(page_memory);
4889 page->busy_size = internal::MemoryPage_size;
4892 NodeData =
new (page->data) internal::DocumentStruct(page);
4896 page->allocator =
static_cast<internal::DocumentStruct*
>(
NodeData);
4899 PUGI__FN
void Document::destroy()
4904 internal::Memory::deallocate(_buffer);
4911 internal::MemoryPage* GetRoot_page =
reinterpret_cast<internal::MemoryPage*
>(
NodeData->header & internal::MemoryPage_pointer_mask);
4912 assert(GetRoot_page && !GetRoot_page->prev && !GetRoot_page->memory);
4915 for (internal::MemoryPage* page = GetRoot_page->next; page; )
4917 internal::MemoryPage* next = page->next;
4919 internal::Allocator::deallocate_page(page);
4925 GetRoot_page->allocator = 0;
4926 GetRoot_page->next = 0;
4927 GetRoot_page->busy_size = GetRoot_page->freed_size = 0;
4933 PUGI__FN ParseResult
Document::Load(std::basic_istream<
char, std::char_traits<char> >& stream,
unsigned int options,
Encoding DocumentEncoding)
4937 return internal::LoadStreamImpl(*
this, stream, options, DocumentEncoding);
4940 PUGI__FN ParseResult
Document::Load(std::basic_istream<
wchar_t, std::char_traits<wchar_t> >& stream,
unsigned int options)
4944 return internal::LoadStreamImpl(*
this, stream, options,
Encodingwchar_t);
4947 PUGI__FN ParseResult
Document::Load(
const Char8* contents,
unsigned int options)
4952 return LoadBuffer(contents, internal::strlength(contents) *
sizeof(Char8), options, DocumentEncoding);
4959 FILE* file = fopen(Path_,
"rb");
4961 return internal::LoadFileImpl(*
this, file, options, DocumentEncoding);
4968 FILE* file = internal::open_file_wide(Path_, L
"rb");
4970 return internal::LoadFileImpl(*
this, file, options, DocumentEncoding);
4973 PUGI__FN ParseResult Document::LoadBufferImpl(
void* contents,
size_t size,
unsigned int options,
Encoding DocumentEncoding,
bool is_mutable,
bool own)
4978 assert(contents || size == 0);
4981 Encoding buffer_DocumentEncoding = internal::GetBuffer_DocumentEncoding(DocumentEncoding, contents, size);
4987 if (!internal::convert_buffer(buffer, length, buffer_DocumentEncoding, contents, size, is_mutable))
return internal::make_ParseResult(
StatusOutOfMemory);
4990 if (own && buffer != contents && contents) internal::Memory::deallocate(contents);
4993 ParseResult res = internal::Parser::parse(buffer, length,
NodeData, options);
4996 res.DocumentEncoding = buffer_DocumentEncoding;
4999 if (own || buffer != contents) _buffer = buffer;
5006 return LoadBufferImpl(const_cast<void*>(contents), size, options, DocumentEncoding,
false,
false);
5011 return LoadBufferImpl(contents, size, options, DocumentEncoding,
true,
false);
5016 return LoadBufferImpl(contents, size, options, DocumentEncoding,
true,
true);
5019 PUGI__FN
void Document::Save(Writer& WriterInstance,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding)
const
5021 internal::BufferedWriter buffered_WriterInstance(WriterInstance, DocumentEncoding);
5026 buffered_WriterInstance.Write(
'\xef',
'\xbb',
'\xbf');
5031 buffered_WriterInstance.Write(
"<?xml version=\"1.0\"");
5032 if (DocumentEncoding ==
EncodingLatin1) buffered_WriterInstance.Write(
" DocumentEncoding=\"ISO-8859-1\"");
5033 buffered_WriterInstance.Write(
'?',
'>');
5034 if (!(flags & FormatRaw)) buffered_WriterInstance.Write(
'\n');
5037 internal::NodeOutput(buffered_WriterInstance, *
this, indent, flags, 0);
5040 PUGI__FN
void Document::Save(std::basic_ostream<
char, std::char_traits<char> >& stream,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding)
const
5042 WriterStream WriterInstance(stream);
5044 Save(WriterInstance, indent, flags, DocumentEncoding);
5047 PUGI__FN
void Document::Save(std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream,
const Char8* indent,
unsigned int flags)
const
5049 WriterStream WriterInstance(stream);
5054 PUGI__FN
bool Document::SaveFile(
const char* Path_,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding)
const
5057 return internal::SaveFileImpl(*
this, file, indent, flags, DocumentEncoding);
5060 PUGI__FN
bool Document::SaveFile(
const wchar_t* Path_,
const Char8* indent,
unsigned int flags,
Encoding DocumentEncoding)
const
5062 FILE* file = internal::open_file_wide(Path_, (flags &
FormatSaveFileText) ? L
"w" : L
"wb");
5063 return internal::SaveFileImpl(*
this, file, indent, flags, DocumentEncoding);
5068 for (NodeStruct* i =
NodeData->GetFirstChild; i; i = i->GetNextSibling)
5069 if ((i->header & internal::MemoryPage_type_mask) + 1 ==
NodeElement)
5079 return internal::AsUtf8_impl(str, wcslen(str));
5082 PUGI__FN std::string
MEZZ_LIB AsUtf8(
const std::basic_string<wchar_t>& str)
5084 return internal::AsUtf8_impl(str.c_str(), str.size());
5087 PUGI__FN std::basic_string<wchar_t>
MEZZ_LIB AsWide(
const char* str)
5091 return internal::AsWide_impl(str, strlen(str));
5094 PUGI__FN std::basic_string<wchar_t>
MEZZ_LIB AsWide(
const std::string& str)
5096 return internal::AsWide_impl(str.c_str(), str.size());
5102 internal::Memory::allocate = allocate;
5103 internal::Memory::deallocate = deallocate;
5108 return internal::Memory::allocate;
5113 return internal::Memory::deallocate;
5123 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5131 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5139 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5147 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5153 template <
typename T>
void swap(T& lhs, T& rhs)
5160 template <
typename I,
typename Pred> I min_element(I begin, I end,
const Pred& pred)
5164 for (I it = begin + 1; it != end; ++it)
5165 if (pred(*it, *Result))
5171 template <
typename I>
void reverse(I begin, I end)
5173 while (begin + 1 < end) swap(*begin++, *--end);
5176 template <
typename I> I unique(I begin, I end)
5179 while (begin + 1 < end && *begin != *(begin + 1)) begin++;
5181 if (begin == end)
return begin;
5187 while (begin != end)
5189 if (*begin != *Write)
5190 *++Write = *begin++;
5199 template <
typename I>
void copy_backwards(I begin, I end, I target)
5201 while (begin != end) *--target = *--end;
5204 template <
typename I,
typename Pred,
typename T>
void insertion_sort(I begin, I end,
const Pred& pred, T*)
5206 assert(begin != end);
5208 for (I it = begin + 1; it != end; ++it)
5212 if (pred(val, *begin))
5215 copy_backwards(begin, it, it + 1);
5223 while (pred(val, *(hole - 1)))
5225 *hole = *(hole - 1);
5236 template <
typename I,
typename Pred>
void partition(I begin, I middle, I end,
const Pred& pred, I* out_eqbeg, I* out_eqend)
5238 I eqbeg = middle, eqend = middle + 1;
5241 while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg;
5242 while (eqend != end && *eqend == *eqbeg) ++eqend;
5245 I ltend = eqbeg, gtbeg = eqend;
5250 for (; gtbeg != end; ++gtbeg)
5251 if (!pred(*eqbeg, *gtbeg))
5253 if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++);
5258 for (; ltend != begin; --ltend)
5259 if (!pred(*(ltend - 1), *eqbeg))
5261 if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg);
5266 if (gtbeg == end && ltend == begin)
5276 if (--ltend != --eqbeg) swap(*ltend, *eqbeg);
5277 swap(*eqbeg, *--eqend);
5279 else if (ltend == begin)
5281 if (eqend != gtbeg) swap(*eqbeg, *eqend);
5283 swap(*gtbeg++, *eqbeg++);
5285 else swap(*gtbeg++, *--ltend);
5289 template <
typename I,
typename Pred>
void median3(I first, I middle, I last,
const Pred& pred)
5291 if (pred(*middle, *first)) swap(*middle, *first);
5292 if (pred(*last, *middle)) swap(*last, *middle);
5293 if (pred(*middle, *first)) swap(*middle, *first);
5296 template <
typename I,
typename Pred>
void median(I first, I middle, I last,
const Pred& pred)
5298 if (last - first <= 40)
5301 median3(first, middle, last, pred);
5306 size_t step = (last - first + 1) / 8;
5308 median3(first, first + step, first + 2 * step, pred);
5309 median3(middle - step, middle, middle + step, pred);
5310 median3(last - 2 * step, last - step, last, pred);
5311 median3(first + step, middle, last - step, pred);
5315 template <
typename I,
typename Pred>
void sort(I begin, I end,
const Pred& pred)
5318 while (end - begin > 32)
5321 I middle = begin + (end - begin) / 2;
5322 median(begin, middle, end - 1, pred);
5326 partition(begin, middle, end, pred, &eqbeg, &eqend);
5329 if (eqbeg - begin > end - eqend)
5331 sort(eqend, end, pred);
5336 sort(begin, eqbeg, pred);
5342 if (begin != end) insertion_sort(begin, end, pred, &*begin);
5348 struct XPathMemoryBlock
5350 XPathMemoryBlock* next;
5353 #ifdef XML_MEMORY_XPATH_PAGE_SIZE
5354 XML_MEMORY_XPATH_PAGE_SIZE
5361 class XPathAllocator
5363 XPathMemoryBlock* _GetRoot;
5364 size_t _GetRoot_size;
5369 XPathAllocator(XPathMemoryBlock* GetRoot,
size_t GetRoot_size = 0): _GetRoot(GetRoot), _GetRoot_size(GetRoot_size)
5374 void* allocate_nothrow(
size_t size)
5376 const size_t block_capacity =
sizeof(_GetRoot->data);
5379 size = (size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5381 if (_GetRoot_size + size <= block_capacity)
5383 void* buf = _GetRoot->data + _GetRoot_size;
5384 _GetRoot_size += size;
5389 size_t block_data_size = (size > block_capacity) ? size : block_capacity;
5390 size_t block_size = block_data_size + offsetof(XPathMemoryBlock, data);
5392 XPathMemoryBlock* block =
static_cast<XPathMemoryBlock*
>(Memory::allocate(block_size));
5393 if (!block)
return 0;
5395 block->next = _GetRoot;
5398 _GetRoot_size = size;
5404 void* allocate(
size_t size)
5406 void* Result = allocate_nothrow(size);
5410 throw std::bad_alloc();
5416 void* reallocate(
void* ptr,
size_t old_size,
size_t new_size)
5419 old_size = (old_size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5420 new_size = (new_size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5423 assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _GetRoot->data + _GetRoot_size);
5426 bool only_object = (_GetRoot_size == old_size);
5428 if (ptr) _GetRoot_size -= old_size;
5431 void* Result = allocate(new_size);
5435 if (Result != ptr && ptr)
5438 assert(new_size > old_size);
5439 memcpy(Result, ptr, old_size);
5444 assert(_GetRoot->data == Result);
5445 assert(_GetRoot->next);
5447 XPathMemoryBlock* next = _GetRoot->next->next;
5452 Memory::deallocate(_GetRoot->next);
5453 _GetRoot->next = next;
5461 void revert(
const XPathAllocator& state)
5464 XPathMemoryBlock* cur = _GetRoot;
5466 while (cur != state._GetRoot)
5468 XPathMemoryBlock* next = cur->next;
5470 Memory::deallocate(cur);
5476 _GetRoot = state._GetRoot;
5477 _GetRoot_size = state._GetRoot_size;
5482 XPathMemoryBlock* cur = _GetRoot;
5487 XPathMemoryBlock* next = cur->next;
5489 Memory::deallocate(cur);
5496 struct XPathAllocatorCapture
5498 XPathAllocatorCapture(XPathAllocator* alloc): _target(alloc), _state(*alloc)
5502 ~XPathAllocatorCapture()
5504 _target->revert(_state);
5507 XPathAllocator* _target;
5508 XPathAllocator _state;
5513 XPathAllocator* Result;
5514 XPathAllocator* temp;
5517 struct XPathStackData
5519 XPathMemoryBlock blocks[2];
5520 XPathAllocator Result;
5521 XPathAllocator temp;
5524 XPathStackData(): Result(blocks + 0), temp(blocks + 1)
5526 blocks[0].next = blocks[1].next = 0;
5528 stack.Result = &Result;
5545 const Char8* _buffer;
5548 static Char8* duplicate_string(
const Char8*
string,
size_t length, XPathAllocator* alloc)
5550 Char8* Result =
static_cast<Char8*
>(alloc->allocate((length + 1) *
sizeof(Char8)));
5553 memcpy(Result,
string, length *
sizeof(Char8));
5559 static Char8* duplicate_string(
const Char8*
string, XPathAllocator* alloc)
5561 return duplicate_string(
string, strlength(
string), alloc);
5565 XPathString(): _buffer(
""), _uses_heap(false)
5569 explicit XPathString(
const Char8* str, XPathAllocator* alloc)
5571 bool empty_ = (*str == 0);
5573 _buffer = empty_ ?
"" : duplicate_string(str, alloc);
5574 _uses_heap = !empty_;
5577 explicit XPathString(
const Char8* str,
bool use_heap): _buffer(str), _uses_heap(use_heap)
5581 XPathString(
const Char8* begin,
const Char8* end, XPathAllocator* alloc)
5583 assert(begin <= end);
5585 bool empty_ = (begin == end);
5587 _buffer = empty_ ?
"" : duplicate_string(begin, static_cast<size_t>(end - begin), alloc);
5588 _uses_heap = !empty_;
5591 void append(
const XPathString& o, XPathAllocator* alloc)
5594 if (!*o._buffer)
return;
5597 if (!*_buffer && !_uses_heap && !o._uses_heap)
5599 _buffer = o._buffer;
5604 size_t tarGetLength = strlength(_buffer);
5605 size_t source_length = strlength(o._buffer);
5606 size_t Result_length = tarGetLength + source_length;
5609 Char8* Result =
static_cast<Char8*
>(alloc->reallocate(_uses_heap ? const_cast<Char8*>(_buffer) : 0, (tarGetLength + 1) *
sizeof(Char8), (Result_length + 1) *
sizeof(Char8)));
5613 if (!_uses_heap) memcpy(Result, _buffer, tarGetLength *
sizeof(Char8));
5616 memcpy(Result + tarGetLength, o._buffer, source_length *
sizeof(Char8));
5617 Result[Result_length] = 0;
5625 const Char8* c_str()
const
5630 size_t length()
const
5632 return strlength(_buffer);
5635 Char8* data(XPathAllocator* alloc)
5640 _buffer = duplicate_string(_buffer, alloc);
5644 return const_cast<Char8*
>(_buffer);
5649 return *_buffer == 0;
5652 bool operator==(
const XPathString& o)
const
5654 return strequal(_buffer, o._buffer);
5657 bool operator!=(
const XPathString& o)
const
5659 return !strequal(_buffer, o._buffer);
5662 bool uses_heap()
const
5668 PUGI__FN XPathString XPathStringConst(
const Char8* str)
5670 return XPathString(str,
false);
5675 PUGI__FN
bool starts_with(
const Char8*
string,
const Char8* pattern)
5677 while (*pattern && *
string == *pattern)
5683 return *pattern == 0;
5686 PUGI__FN
const Char8* FindChar(
const Char8* s, Char8 c)
5688 return strchr(s, c);
5691 PUGI__FN
const Char8* FindSubstring(
const Char8* s,
const Char8* p)
5693 return strstr(s, p);
5697 PUGI__FN Char8 tolower_ascii(Char8 ch)
5699 return static_cast<unsigned int>(ch -
'A') < 26 ? static_cast<Char8>(ch |
' ') : ch;
5702 PUGI__FN XPathString string_Value(
const XPathNode& na, XPathAllocator* alloc)
5704 if (na.GetAttribute())
5705 return XPathStringConst(na.GetAttribute().Value());
5708 const Node& n = na.GetNode();
5716 return XPathStringConst(n.Value());
5723 Node cur = n.GetFirstChild();
5725 while (cur && cur != n)
5728 Result.append(XPathStringConst(cur.Value()), alloc);
5730 if (cur.GetFirstChild())
5731 cur = cur.GetFirstChild();
5732 else if (cur.GetNextSibling())
5733 cur = cur.GetNextSibling();
5736 while (!cur.GetNextSibling() && cur != n)
5737 cur = cur.GetParent();
5739 if (cur != n) cur = cur.GetNextSibling();
5747 return XPathString();
5752 PUGI__FN
unsigned int NodeHeight(Node n)
5754 unsigned int Result = 0;
5765 PUGI__FN
bool NodeIs_before(Node ln,
unsigned int lh, Node rn,
unsigned int rh)
5768 for (
unsigned int i = rh; i < lh; i++) ln = ln.GetParent();
5769 for (
unsigned int j = lh; j < rh; j++) rn = rn.GetParent();
5772 if (ln == rn)
return lh < rh;
5775 while (ln.GetParent() != rn.GetParent())
5777 ln = ln.GetParent();
5778 rn = rn.GetParent();
5782 if (!ln.GetParent())
return ln < rn;
5785 for (; ln; ln = ln.GetNextSibling())
5792 PUGI__FN
bool NodeIs_ancestor(Node GetParent, Node node)
5794 while (node && node != GetParent) node = node.GetParent();
5796 return GetParent && node == GetParent;
5799 PUGI__FN
const void* document_order(
const XPathNode& xnode)
5801 NodeStruct* node = xnode.GetNode().InternalObject();
5805 if (node->Name && (node->header & MemoryPage_Name_allocated_mask) == 0)
return node->Name;
5806 if (node->Value && (node->header & MemoryPage_Value_allocated_mask) == 0)
return node->Value;
5810 AttributeStruct* attr = xnode.GetAttribute().InternalObject();
5814 if ((attr->header & MemoryPage_Name_allocated_mask) == 0)
return attr->Name;
5815 if ((attr->header & MemoryPage_Value_allocated_mask) == 0)
return attr->Value;
5822 struct document_order_comparator
5824 bool operator()(
const XPathNode& lhs,
const XPathNode& rhs)
const
5827 const void* lo = document_order(lhs);
5828 const void* ro = document_order(rhs);
5830 if (lo && ro)
return lo < ro;
5833 Node ln = lhs.GetNode(), rn = rhs.GetNode();
5836 if (lhs.GetAttribute() && rhs.GetAttribute())
5839 if (lhs.GetParent() == rhs.GetParent())
5842 for (Attribute a = lhs.GetAttribute(); a; a = a.GetNextAttribute())
5843 if (a == rhs.GetAttribute())
5850 ln = lhs.GetParent();
5851 rn = rhs.GetParent();
5853 else if (lhs.GetAttribute())
5856 if (lhs.GetParent() == rhs.GetNode())
return false;
5858 ln = lhs.GetParent();
5860 else if (rhs.GetAttribute())
5863 if (rhs.GetParent() == lhs.GetNode())
return true;
5865 rn = rhs.GetParent();
5868 if (ln == rn)
return false;
5870 unsigned int lh = NodeHeight(ln);
5871 unsigned int rh = NodeHeight(rn);
5873 return NodeIs_before(ln, lh, rn, rh);
5877 struct duplicate_comparator
5879 bool operator()(
const XPathNode& lhs,
const XPathNode& rhs)
const
5881 if (lhs.GetAttribute())
return rhs.GetAttribute() ? lhs.GetAttribute() < rhs.GetAttribute() :
true;
5882 else return rhs.GetAttribute() ?
false : lhs.GetNode() < rhs.GetNode();
5886 PUGI__FN
double gen_nan()
5888 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
5889 union {
float f; uint32_t i; } u[
sizeof(float) ==
sizeof(uint32_t) ? 1 : -1];
5890 u[0].i = 0x7fc00000;
5894 const volatile double zero = 0.0;
5899 PUGI__FN
bool is_nan(
double Value)
5901 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
5902 return !!_isnan(Value);
5903 #elif defined(fpclassify) && defined(FP_NAN)
5904 return fpclassify(Value) == FP_NAN;
5907 const volatile double v = Value;
5912 PUGI__FN
const Char8* convert_number_to_string_special(
double Value)
5914 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
5915 if (_finite(Value))
return (Value == 0) ?
"0" : 0;
5916 if (_isnan(Value))
return "NaN";
5917 return Value > 0 ?
"Infinity" :
"-Infinity";
5918 #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
5919 switch (fpclassify(Value))
5925 return Value > 0 ?
"Infinity" :
"-Infinity";
5935 const volatile double v = Value;
5937 if (v == 0)
return "0";
5938 if (v != v)
return "NaN";
5939 if (v * 2 == v)
return Value > 0 ?
"Infinity" :
"-Infinity";
5944 PUGI__FN
bool convert_number_to_boolean(
double Value)
5946 return (Value != 0 && !is_nan(Value));
5949 PUGI__FN
void truncate_zeros(
char* begin,
char* end)
5951 while (begin != end && end[-1] ==
'0') end--;
5957 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
5958 PUGI__FN
void convert_number_to_mantissa_exponent(
double Value,
char* buffer,
size_t buffer_size,
char** out_mantissa,
int* out_exponent)
5962 _ecvt_s(buffer, buffer_size, Value, DBL_DIG + 1, &exponent, &sign);
5965 truncate_zeros(buffer, buffer + strlen(buffer));
5968 *out_mantissa = buffer;
5969 *out_exponent = exponent;
5972 PUGI__FN
void convert_number_to_mantissa_exponent(
double Value,
char* buffer,
size_t buffer_size,
char** out_mantissa,
int* out_exponent)
5975 sprintf(buffer,
"%.*e", DBL_DIG, Value);
5976 assert(strlen(buffer) < buffer_size);
5980 char* exponent_string = strchr(buffer,
'e');
5981 assert(exponent_string);
5983 int exponent = atoi(exponent_string + 1);
5986 char* mantissa = buffer[0] ==
'-' ? buffer + 1 : buffer;
5987 assert(mantissa[0] !=
'0' && mantissa[1] ==
'.');
5990 mantissa[1] = mantissa[0];
5995 truncate_zeros(mantissa, exponent_string);
5998 *out_mantissa = mantissa;
5999 *out_exponent = exponent;
6003 PUGI__FN XPathString convert_number_to_string(
double Value, XPathAllocator* alloc)
6006 const Char8* special = convert_number_to_string_special(Value);
6007 if (special)
return XPathStringConst(special);
6010 char mantissa_buffer[64];
6014 convert_number_to_mantissa_exponent(Value, mantissa_buffer,
sizeof(mantissa_buffer), &mantissa, &exponent);
6021 if (Value < 0) *s++ =
'-';
6030 while (exponent > 0)
6032 assert(*mantissa == 0 || static_cast<unsigned int>(*mantissa -
'0') <= 9);
6033 *s++ = *mantissa ? *mantissa++ :
'0';
6045 while (exponent < 0)
6054 assert(static_cast<unsigned int>(*mantissa -
'0') <= 9);
6060 assert(s < Result +
sizeof(Result) /
sizeof(Result[0]));
6063 return XPathString(Result, alloc);
6066 PUGI__FN
bool check_Stringo_number_format(
const Char8*
string)
6069 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
6072 if (*
string ==
'-') ++string;
6074 if (!*
string)
return false;
6077 if (!PUGI__IS_CHARTYPEX(
string[0], ctx_digit) && (
string[0] !=
'.' || !PUGI__IS_CHARTYPEX(
string[1], ctx_digit)))
return false;
6080 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
6087 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
6091 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
6093 return *
string == 0;
6096 PUGI__FN
double convert_Stringo_number(
const Char8*
string)
6099 if (!check_Stringo_number_format(
string))
return gen_nan();
6102 return atof(
string);
6105 PUGI__FN
bool convert_Stringo_number(
const Char8* begin,
const Char8* end,
double* out_Result)
6109 size_t length =
static_cast<size_t>(end - begin);
6110 Char8* scratch = buffer;
6112 if (length >=
sizeof(buffer) /
sizeof(buffer[0]))
6115 scratch =
static_cast<Char8*
>(Memory::allocate((length + 1) *
sizeof(Char8)));
6116 if (!scratch)
return false;
6120 memcpy(scratch, begin, length *
sizeof(Char8));
6121 scratch[length] = 0;
6123 *out_Result = convert_Stringo_number(scratch);
6126 if (scratch != buffer) Memory::deallocate(scratch);
6131 PUGI__FN
double round_nearest(
double Value)
6133 return floor(Value + 0.5);
6136 PUGI__FN
double round_nearest_nzero(
double Value)
6140 return (Value >= -0.5 && Value <= 0) ? ceil(Value) : floor(Value + 0.5);
6143 PUGI__FN
const Char8* qualified_Name(
const XPathNode& node)
6145 return node.GetAttribute() ? node.GetAttribute().Name() : node.GetNode().Name();
6148 PUGI__FN
const Char8* local_Name(
const XPathNode& node)
6150 const Char8* Name = qualified_Name(node);
6151 const Char8* p = FindChar(Name,
':');
6153 return p ? p + 1 : Name;
6156 struct namespace_uri_predicate
6158 const Char8* prefix;
6159 size_t prefix_length;
6161 namespace_uri_predicate(
const Char8* Name)
6163 const Char8* pos = FindChar(Name,
':');
6165 prefix = pos ? Name : 0;
6166 prefix_length = pos ?
static_cast<size_t>(pos - Name) : 0;
6169 bool operator()(
const Attribute& a)
const
6171 const Char8* Name = a.Name();
6173 if (!starts_with(Name,
"xmlns"))
return false;
6175 return prefix ? Name[5] ==
':' && strequalrange(Name + 6, prefix, prefix_length) : Name[5] == 0;
6179 PUGI__FN
const Char8* namespace_uri(
const Node& node)
6181 namespace_uri_predicate pred = node.Name();
6187 Attribute a = p.FindAttribute(pred);
6189 if (a)
return a.Value();
6197 PUGI__FN
const Char8* namespace_uri(
const Attribute& attr,
const Node& GetParent)
6199 namespace_uri_predicate pred = attr.Name();
6202 if (!pred.prefix)
return "";
6208 Attribute a = p.FindAttribute(pred);
6210 if (a)
return a.Value();
6218 PUGI__FN
const Char8* namespace_uri(
const XPathNode& node)
6220 return node.GetAttribute() ? namespace_uri(node.GetAttribute(), node.GetParent()) : namespace_uri(node.GetNode());
6223 PUGI__FN
void normalize_space(Char8* buffer)
6225 Char8* Write = buffer;
6227 for (Char8* it = buffer; *it; )
6231 if (PUGI__IS_CHARTYPE(ch, ct_space))
6234 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
6237 if (Write != buffer) *Write++ =
' ';
6243 if (Write != buffer && PUGI__IS_CHARTYPE(Write[-1], ct_space)) Write--;
6249 PUGI__FN
void translate(Char8* buffer,
const Char8* from,
const Char8* to)
6251 size_t to_length = strlength(to);
6253 Char8* Write = buffer;
6257 PUGI__DMC_VOLATILE Char8 ch = *buffer++;
6259 const Char8* pos = FindChar(from, ch);
6263 else if (static_cast<size_t>(pos - from) < to_length)
6264 *Write++ = to[pos - from];
6271 struct XPathVariableBoole: XPathVariable
6273 XPathVariableBoole(): Value(false)
6281 struct XPathVariableNumber: XPathVariable
6283 XPathVariableNumber(): Value(0)
6291 struct XPathVariableString: XPathVariable
6293 XPathVariableString(): Value(0)
6297 ~XPathVariableString()
6299 if (Value) Memory::deallocate(Value);
6306 struct XPathVariableNodeSet: XPathVariable
6312 static const XPathNodeSet dummy_NodeSet;
6314 PUGI__FN
unsigned int hash_string(
const Char8* str)
6317 unsigned int Result = 0;
6321 Result +=
static_cast<unsigned int>(*str++);
6322 Result += Result << 10;
6323 Result ^= Result >> 6;
6326 Result += Result << 3;
6327 Result ^= Result >> 11;
6328 Result += Result << 15;
6333 template <
typename T> PUGI__FN T* new_XPathVariable(
const Char8* Name)
6335 size_t length = strlength(Name);
6336 if (length == 0)
return 0;
6339 void* memory = Memory::allocate(
sizeof(T) + length *
sizeof(Char8));
6340 if (!memory)
return 0;
6342 T* Result =
new (memory) T();
6344 memcpy(Result->Name, Name, (length + 1) *
sizeof(Char8));
6349 PUGI__FN XPathVariable* new_XPathVariable(
XPathValueType Type,
const Char8* Name)
6354 return new_XPathVariable<XPathVariableNodeSet>(Name);
6357 return new_XPathVariable<XPathVariableNumber>(Name);
6360 return new_XPathVariable<XPathVariableString>(Name);
6363 return new_XPathVariable<XPathVariableBoole>(Name);
6370 template <
typename T> PUGI__FN
void delete_XPathVariable(T* var)
6373 Memory::deallocate(var);
6376 PUGI__FN
void delete_XPathVariable(
XPathValueType Type, XPathVariable* var)
6381 delete_XPathVariable(static_cast<XPathVariableNodeSet*>(var));
6385 delete_XPathVariable(static_cast<XPathVariableNumber*>(var));
6389 delete_XPathVariable(static_cast<XPathVariableString*>(var));
6393 delete_XPathVariable(static_cast<XPathVariableBoole*>(var));
6397 assert(!
"Invalid variable Type");
6401 PUGI__FN XPathVariable* GetVariable(XPathVariableSet* set,
const Char8* begin,
const Char8* end)
6405 size_t length =
static_cast<size_t>(end - begin);
6406 Char8* scratch = buffer;
6408 if (length >=
sizeof(buffer) /
sizeof(buffer[0]))
6411 scratch =
static_cast<Char8*
>(Memory::allocate((length + 1) *
sizeof(Char8)));
6412 if (!scratch)
return 0;
6416 memcpy(scratch, begin, length *
sizeof(Char8));
6417 scratch[length] = 0;
6419 XPathVariable* Result = set->Get(scratch);
6422 if (scratch != buffer) Memory::deallocate(scratch);
6430 PUGI__FN XPathNodeSet::CollectionType XPathSort(XPathNode* begin, XPathNode* end, XPathNodeSet::CollectionType Type,
bool rev)
6432 XPathNodeSet::CollectionType order = rev ? XPathNodeSet::TypeSortedReverse : XPathNodeSet::TypeSorted;
6434 if (Type == XPathNodeSet::TypeUnsorted)
6436 sort(begin, end, document_order_comparator());
6438 Type = XPathNodeSet::TypeSorted;
6441 if (Type != order) reverse(begin, end);
6446 PUGI__FN XPathNode XPathFirst(
const XPathNode* begin,
const XPathNode* end, XPathNodeSet::CollectionType Type)
6448 if (begin == end)
return XPathNode();
6452 case XPathNodeSet::TypeSorted:
6455 case XPathNodeSet::TypeSortedReverse:
6458 case XPathNodeSet::TypeUnsorted:
6459 return *min_element(begin, end, document_order_comparator());
6462 assert(!
"Invalid node set Type");
6467 class XPathNodeSet_raw
6469 XPathNodeSet::CollectionType _type;
6476 XPathNodeSet_raw(): _type(XPathNodeSet::TypeUnsorted), _begin(0), _end(0), _eos(0)
6480 XPathNode* begin()
const
6485 XPathNode* end()
const
6492 return _begin == _end;
6497 return static_cast<size_t>(_end - _begin);
6500 XPathNode first()
const
6502 return XPathFirst(_begin, _end, _type);
6505 void push_back(
const XPathNode& node, XPathAllocator* alloc)
6509 size_t capacity =
static_cast<size_t>(_eos - _begin);
6512 size_t new_capacity = capacity + capacity / 2 + 1;
6515 XPathNode* data =
static_cast<XPathNode*
>(alloc->reallocate(_begin, capacity *
sizeof(XPathNode), new_capacity *
sizeof(XPathNode)));
6520 _end = data + capacity;
6521 _eos = data + new_capacity;
6527 void append(
const XPathNode* begin_,
const XPathNode* end_, XPathAllocator* alloc)
6529 size_t size_ =
static_cast<size_t>(_end - _begin);
6530 size_t capacity =
static_cast<size_t>(_eos - _begin);
6531 size_t count =
static_cast<size_t>(end_ - begin_);
6533 if (size_ + count > capacity)
6536 XPathNode* data =
static_cast<XPathNode*
>(alloc->reallocate(_begin, capacity *
sizeof(XPathNode), (size_ + count) *
sizeof(XPathNode)));
6541 _end = data + size_;
6542 _eos = data + size_ + count;
6545 memcpy(_end, begin_, count *
sizeof(XPathNode));
6551 _type = XPathSort(_begin, _end, _type,
false);
6554 void truncate(XPathNode* pos)
6556 assert(_begin <= pos && pos <= _end);
6561 void RemoveDuplicates()
6563 if (_type == XPathNodeSet::TypeUnsorted)
6564 sort(_begin, _end, duplicate_comparator());
6566 _end = unique(_begin, _end);
6569 XPathNodeSet::CollectionType Type()
const
6574 void SetType(XPathNodeSet::CollectionType Value)
6585 size_t position, size;
6587 XPathContext(
const XPathNode& n_,
size_t position_,
size_t size_): n(n_), position(position_), size(size_)
6600 lex_greater_or_equal,
6612 lex_open_square_brace,
6613 lex_close_square_brace,
6623 struct XPathLexerString
6628 XPathLexerString(): begin(0), end(0)
6632 bool operator==(
const Char8* other)
const
6634 size_t length =
static_cast<size_t>(end - begin);
6636 return strequalrange(other, begin, length);
6643 const Char8* _cur_lexeme_pos;
6644 XPathLexerString _cur_lexeme_contents;
6646 lexeme_t _cur_lexeme;
6649 explicit XPathLexer(
const Char8* query): _cur(query)
6654 const Char8* state()
const
6661 const Char8* cur = _cur;
6663 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
6666 _cur_lexeme_pos = cur;
6671 _cur_lexeme = lex_eof;
6675 if (*(cur+1) ==
'=')
6678 _cur_lexeme = lex_greater_or_equal;
6683 _cur_lexeme = lex_greater;
6688 if (*(cur+1) ==
'=')
6691 _cur_lexeme = lex_less_or_equal;
6696 _cur_lexeme = lex_less;
6701 if (*(cur+1) ==
'=')
6704 _cur_lexeme = lex_not_equal;
6708 _cur_lexeme = lex_none;
6714 _cur_lexeme = lex_equal;
6720 _cur_lexeme = lex_plus;
6726 _cur_lexeme = lex_minus;
6732 _cur_lexeme = lex_multiply;
6738 _cur_lexeme = lex_union;
6745 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
6747 _cur_lexeme_contents.begin = cur;
6749 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
6751 if (cur[0] ==
':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
6755 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
6758 _cur_lexeme_contents.end = cur;
6760 _cur_lexeme = lex_var_ref;
6764 _cur_lexeme = lex_none;
6771 _cur_lexeme = lex_open_brace;
6777 _cur_lexeme = lex_close_brace;
6783 _cur_lexeme = lex_open_square_brace;
6789 _cur_lexeme = lex_close_square_brace;
6795 _cur_lexeme = lex_comma;
6800 if (*(cur+1) ==
'/')
6803 _cur_lexeme = lex_double_slash;
6808 _cur_lexeme = lex_slash;
6813 if (*(cur+1) ==
'.')
6816 _cur_lexeme = lex_double_dot;
6818 else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
6820 _cur_lexeme_contents.begin = cur;
6824 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
6826 _cur_lexeme_contents.end = cur;
6828 _cur_lexeme = lex_number;
6833 _cur_lexeme = lex_dot;
6839 _cur_lexeme = lex_axis_attribute;
6846 Char8 terminator = *cur;
6850 _cur_lexeme_contents.begin = cur;
6851 while (*cur && *cur != terminator) cur++;
6852 _cur_lexeme_contents.end = cur;
6855 _cur_lexeme = lex_none;
6859 _cur_lexeme = lex_quoted_string;
6866 if (*(cur+1) ==
':')
6869 _cur_lexeme = lex_double_colon;
6873 _cur_lexeme = lex_none;
6878 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
6880 _cur_lexeme_contents.begin = cur;
6882 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
6888 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
6891 _cur_lexeme_contents.end = cur;
6893 _cur_lexeme = lex_number;
6895 else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
6897 _cur_lexeme_contents.begin = cur;
6899 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
6907 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
6911 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
6915 _cur_lexeme_contents.end = cur;
6917 _cur_lexeme = lex_string;
6921 _cur_lexeme = lex_none;
6928 lexeme_t current()
const
6933 const Char8* current_pos()
const
6935 return _cur_lexeme_pos;
6938 const XPathLexerString& contents()
const
6940 assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
6942 return _cur_lexeme_contents;
6954 ast_op_less_or_equal,
6955 ast_op_greater_or_equal,
6966 ast_string_constant,
6967 ast_number_constant,
6973 ast_func_local_Name_0,
6974 ast_func_local_Name_1,
6975 ast_func_namespace_uri_0,
6976 ast_func_namespace_uri_1,
6982 ast_func_starts_with,
6984 ast_func_substring_before,
6985 ast_func_substring_after,
6986 ast_func_substring_2,
6987 ast_func_substring_3,
6988 ast_func_string_length_0,
6989 ast_func_string_length_1,
6990 ast_func_normalize_space_0,
6991 ast_func_normalize_space_1,
7011 axis_ancestor_or_self,
7015 axis_descendant_or_self,
7017 axis_following_sibling,
7021 axis_preceding_sibling,
7030 nodetest_type_comment,
7035 nodetest_all_in_namespace
7038 template <axis_t N>
struct axis_to_type
7040 static const axis_t axis;
7043 template <axis_t N>
const axis_t axis_to_type<N>::axis = N;
7057 XPathAstNode* _left;
7058 XPathAstNode* _right;
7059 XPathAstNode* _next;
7064 const Char8* string;
7068 XPathVariable* variable;
7070 const Char8* nodetest;
7073 XPathAstNode(
const XPathAstNode&);
7074 XPathAstNode& operator=(
const XPathAstNode&);
7076 template <
class Comp>
static bool compare_eq(XPathAstNode* lhs, XPathAstNode* rhs,
const XPathContext& c,
const XPathStack& stack,
const Comp& comp)
7083 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7085 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7088 XPathAllocatorCapture cr(stack.Result);
7090 XPathString ls = lhs->eval_string(c, stack);
7091 XPathString rs = rhs->eval_string(c, stack);
7093 return comp(ls, rs);
7098 XPathAllocatorCapture cr(stack.Result);
7100 XPathNodeSet_raw ls = lhs->eval_NodeSet(c, stack);
7101 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7103 for (
const XPathNode* li = ls.begin(); li != ls.end(); ++li)
7104 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7106 XPathAllocatorCapture cri(stack.Result);
7108 if (comp(string_Value(*li, stack.Result), string_Value(*ri, stack.Result)))
7123 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7126 XPathAllocatorCapture cr(stack.Result);
7128 double l = lhs->eval_number(c, stack);
7129 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7131 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7133 XPathAllocatorCapture cri(stack.Result);
7135 if (comp(l, convert_Stringo_number(string_Value(*ri, stack.Result).c_str())))
7143 XPathAllocatorCapture cr(stack.Result);
7145 XPathString l = lhs->eval_string(c, stack);
7146 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7148 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7150 XPathAllocatorCapture cri(stack.Result);
7152 if (comp(l, string_Value(*ri, stack.Result)))
7160 assert(!
"Wrong Types");
7164 template <
class Comp>
static bool compare_rel(XPathAstNode* lhs, XPathAstNode* rhs,
const XPathContext& c,
const XPathStack& stack,
const Comp& comp)
7169 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7172 XPathAllocatorCapture cr(stack.Result);
7174 XPathNodeSet_raw ls = lhs->eval_NodeSet(c, stack);
7175 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7177 for (
const XPathNode* li = ls.begin(); li != ls.end(); ++li)
7179 XPathAllocatorCapture cri(stack.Result);
7181 double l = convert_Stringo_number(string_Value(*li, stack.Result).c_str());
7183 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7185 XPathAllocatorCapture crii(stack.Result);
7187 if (comp(l, convert_Stringo_number(string_Value(*ri, stack.Result).c_str())))
7196 XPathAllocatorCapture cr(stack.Result);
7198 double l = lhs->eval_number(c, stack);
7199 XPathNodeSet_raw rs = rhs->eval_NodeSet(c, stack);
7201 for (
const XPathNode* ri = rs.begin(); ri != rs.end(); ++ri)
7203 XPathAllocatorCapture cri(stack.Result);
7205 if (comp(l, convert_Stringo_number(string_Value(*ri, stack.Result).c_str())))
7213 XPathAllocatorCapture cr(stack.Result);
7215 XPathNodeSet_raw ls = lhs->eval_NodeSet(c, stack);
7216 double r = rhs->eval_number(c, stack);
7218 for (
const XPathNode* li = ls.begin(); li != ls.end(); ++li)
7220 XPathAllocatorCapture cri(stack.Result);
7222 if (comp(convert_Stringo_number(string_Value(*li, stack.Result).c_str()), r))
7230 assert(!
"Wrong Types");
7235 void apply_predicate(XPathNodeSet_raw& ns,
size_t first, XPathAstNode* expr,
const XPathStack& stack)
7237 assert(ns.size() >= first);
7240 size_t size = ns.size() - first;
7242 XPathNode* last = ns.begin() + first;
7245 for (XPathNode* it = last; it != ns.end(); ++it, ++i)
7247 XPathContext c(*it, i, size);
7251 if (expr->eval_number(c, stack) == i)
7254 else if (expr->eval_boolean(c, stack))
7261 void apply_predicates(XPathNodeSet_raw& ns,
size_t first,
const XPathStack& stack)
7263 if (ns.size() == first)
return;
7265 for (XPathAstNode* pred = _right; pred; pred = pred->_next)
7267 apply_predicate(ns, first, pred->_left, stack);
7271 void step_push(XPathNodeSet_raw& ns,
const Attribute& a,
const Node& GetParent, XPathAllocator* alloc)
7275 const Char8* Name = a.Name();
7279 if (starts_with(Name,
"xmlns") && (Name[5] == 0 || Name[5] ==
':'))
return;
7284 if (strequal(Name, _data.nodetest)) ns.push_back(XPathNode(a, GetParent), alloc);
7287 case nodetest_type_node:
7289 ns.push_back(XPathNode(a, GetParent), alloc);
7292 case nodetest_all_in_namespace:
7293 if (starts_with(Name, _data.nodetest))
7294 ns.push_back(XPathNode(a, GetParent), alloc);
7302 void step_push(XPathNodeSet_raw& ns,
const Node& n, XPathAllocator* alloc)
7309 if (n.Type() ==
NodeElement && strequal(n.Name(), _data.nodetest)) ns.push_back(n, alloc);
7312 case nodetest_type_node:
7313 ns.push_back(n, alloc);
7316 case nodetest_type_comment:
7318 ns.push_back(n, alloc);
7321 case nodetest_type_text:
7323 ns.push_back(n, alloc);
7326 case nodetest_type_pi:
7328 ns.push_back(n, alloc);
7332 if (n.Type() ==
NodePi && strequal(n.Name(), _data.nodetest))
7333 ns.push_back(n, alloc);
7338 ns.push_back(n, alloc);
7341 case nodetest_all_in_namespace:
7342 if (n.Type() ==
NodeElement && starts_with(n.Name(), _data.nodetest))
7343 ns.push_back(n, alloc);
7347 assert(!
"Unknown axis");
7351 template <
class T>
void step_fill(XPathNodeSet_raw& ns,
const Node& n, XPathAllocator* alloc, T)
7353 const axis_t axis = T::axis;
7357 case axis_attribute:
7359 for (Attribute a = n.GetFirstAttribute(); a; a = a.GetNextAttribute())
7360 step_push(ns, a, n, alloc);
7367 for (Node c = n.GetFirstChild(); c; c = c.GetNextSibling())
7368 step_push(ns, c, alloc);
7373 case axis_descendant:
7374 case axis_descendant_or_self:
7376 if (axis == axis_descendant_or_self)
7377 step_push(ns, n, alloc);
7379 Node cur = n.GetFirstChild();
7381 while (cur && cur != n)
7383 step_push(ns, cur, alloc);
7385 if (cur.GetFirstChild())
7386 cur = cur.GetFirstChild();
7387 else if (cur.GetNextSibling())
7388 cur = cur.GetNextSibling();
7391 while (!cur.GetNextSibling() && cur != n)
7392 cur = cur.GetParent();
7394 if (cur != n) cur = cur.GetNextSibling();
7401 case axis_following_sibling:
7403 for (Node c = n.GetNextSibling(); c; c = c.GetNextSibling())
7404 step_push(ns, c, alloc);
7409 case axis_preceding_sibling:
7411 for (Node c = n.GetPreviousSibling(); c; c = c.GetPreviousSibling())
7412 step_push(ns, c, alloc);
7417 case axis_following:
7422 while (cur && !cur.GetNextSibling()) cur = cur.GetParent();
7423 cur = cur.GetNextSibling();
7427 step_push(ns, cur, alloc);
7429 if (cur.GetFirstChild())
7430 cur = cur.GetFirstChild();
7431 else if (cur.GetNextSibling())
7432 cur = cur.GetNextSibling();
7435 while (cur && !cur.GetNextSibling()) cur = cur.GetParent();
7436 cur = cur.GetNextSibling();
7445 case axis_preceding:
7449 while (cur && !cur.GetPreviousSibling()) cur = cur.GetParent();
7450 cur = cur.GetPreviousSibling();
7454 if (cur.GetLastChild())
7455 cur = cur.GetLastChild();
7459 step_push(ns, cur, alloc);
7461 if (cur.GetPreviousSibling())
7462 cur = cur.GetPreviousSibling();
7467 cur = cur.GetParent();
7470 if (!NodeIs_ancestor(cur, n)) step_push(ns, cur, alloc);
7472 while (!cur.GetPreviousSibling());
7474 cur = cur.GetPreviousSibling();
7485 case axis_ancestor_or_self:
7487 if (axis == axis_ancestor_or_self)
7488 step_push(ns, n, alloc);
7490 Node cur = n.GetParent();
7494 step_push(ns, cur, alloc);
7496 cur = cur.GetParent();
7504 step_push(ns, n, alloc);
7509 case axis_GetParent:
7511 if (n.GetParent()) step_push(ns, n.GetParent(), alloc);
7517 assert(!
"Unimplemented axis");
7521 template <
class T>
void step_fill(XPathNodeSet_raw& ns,
const Attribute& a,
const Node& p, XPathAllocator* alloc, T v)
7523 const axis_t axis = T::axis;
7528 case axis_ancestor_or_self:
7530 if (axis == axis_ancestor_or_self && _test == nodetest_type_node)
7531 step_push(ns, a, p, alloc);
7537 step_push(ns, cur, alloc);
7539 cur = cur.GetParent();
7545 case axis_descendant_or_self:
7548 if (_test == nodetest_type_node)
7549 step_push(ns, a, p, alloc);
7554 case axis_following:
7560 if (cur.GetFirstChild())
7561 cur = cur.GetFirstChild();
7562 else if (cur.GetNextSibling())
7563 cur = cur.GetNextSibling();
7566 while (cur && !cur.GetNextSibling()) cur = cur.GetParent();
7567 cur = cur.GetNextSibling();
7572 step_push(ns, cur, alloc);
7578 case axis_GetParent:
7580 step_push(ns, p, alloc);
7585 case axis_preceding:
7588 step_fill(ns, p, alloc, v);
7593 assert(!
"Unimplemented axis");
7597 template <
class T> XPathNodeSet_raw step_do(
const XPathContext& c,
const XPathStack& stack, T v)
7599 const axis_t axis = T::axis;
7600 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);
7602 XPathNodeSet_raw ns;
7603 ns.SetType((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? XPathNodeSet::TypeSortedReverse : XPathNodeSet::TypeSorted);
7607 XPathNodeSet_raw s = _left->eval_NodeSet(c, stack);
7610 if (axis == axis_self) ns.SetType(s.Type());
7612 for (
const XPathNode* it = s.begin(); it != s.end(); ++it)
7614 size_t size = ns.size();
7617 if (axis != axis_self && size != 0) ns.SetType(XPathNodeSet::TypeUnsorted);
7620 step_fill(ns, it->GetNode(), stack.Result, v);
7621 else if (attributes)
7622 step_fill(ns, it->GetAttribute(), it->GetParent(), stack.Result, v);
7624 apply_predicates(ns, size, stack);
7630 step_fill(ns, c.n.GetNode(), stack.Result, v);
7631 else if (attributes)
7632 step_fill(ns, c.n.GetAttribute(), c.n.GetParent(), stack.Result, v);
7634 apply_predicates(ns, 0, stack);
7639 if (axis != axis_GetChild && axis != axis_attribute && axis != axis_self && ns.Type() == XPathNodeSet::TypeUnsorted)
7640 ns.RemoveDuplicates();
7646 XPathAstNode(ast_type_t Type,
XPathValueType retType_,
const Char8* Value):
7647 _type(static_cast<char>(Type)), _retType(static_cast<char>(retType_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7649 assert(Type == ast_string_constant);
7650 _data.string = Value;
7653 XPathAstNode(ast_type_t Type,
XPathValueType retType_,
double Value):
7654 _type(static_cast<char>(Type)), _retType(static_cast<char>(retType_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7656 assert(Type == ast_number_constant);
7657 _data.number = Value;
7660 XPathAstNode(ast_type_t Type,
XPathValueType retType_, XPathVariable* Value):
7661 _type(static_cast<char>(Type)), _retType(static_cast<char>(retType_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7663 assert(Type == ast_variable);
7664 _data.variable = Value;
7667 XPathAstNode(ast_type_t Type,
XPathValueType retType_, XPathAstNode* left = 0, XPathAstNode* right = 0):
7668 _type(static_cast<char>(Type)), _retType(static_cast<char>(retType_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
7672 XPathAstNode(ast_type_t Type, XPathAstNode* left, axis_t axis, nodetest_t test,
const Char8* contents):
7673 _type(static_cast<char>(Type)), _retType(
XPathTypeNodeSet), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(0), _next(0)
7675 _data.nodetest = contents;
7678 void SetNext(XPathAstNode* Value)
7683 void SetRight(XPathAstNode* Value)
7688 bool eval_boolean(
const XPathContext& c,
const XPathStack& stack)
7693 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
7696 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
7699 return compare_eq(_left, _right, c, stack, equal_to());
7701 case ast_op_not_equal:
7702 return compare_eq(_left, _right, c, stack, not_equal_to());
7705 return compare_rel(_left, _right, c, stack, less());
7707 case ast_op_greater:
7708 return compare_rel(_right, _left, c, stack, less());
7710 case ast_op_less_or_equal:
7711 return compare_rel(_left, _right, c, stack, less_equal());
7713 case ast_op_greater_or_equal:
7714 return compare_rel(_right, _left, c, stack, less_equal());
7716 case ast_func_starts_with:
7718 XPathAllocatorCapture cr(stack.Result);
7720 XPathString lr = _left->eval_string(c, stack);
7721 XPathString rr = _right->eval_string(c, stack);
7723 return starts_with(lr.c_str(), rr.c_str());
7726 case ast_func_contains:
7728 XPathAllocatorCapture cr(stack.Result);
7730 XPathString lr = _left->eval_string(c, stack);
7731 XPathString rr = _right->eval_string(c, stack);
7733 return FindSubstring(lr.c_str(), rr.c_str()) != 0;
7736 case ast_func_boolean:
7737 return _left->eval_boolean(c, stack);
7740 return !_left->eval_boolean(c, stack);
7745 case ast_func_false:
7750 if (c.n.GetAttribute())
return false;
7752 XPathAllocatorCapture cr(stack.Result);
7754 XPathString lang = _left->eval_string(c, stack);
7756 for (Node n = c.n.GetNode(); n; n = n.GetParent())
7758 Attribute a = n.GetAttribute(
"xml:lang");
7762 const Char8* Value = a.Value();
7765 for (
const Char8* lit = lang.c_str(); *lit; ++lit)
7767 if (tolower_ascii(*lit) != tolower_ascii(*Value))
return false;
7771 return *Value == 0 || *Value ==
'-';
7780 assert(_retType == _data.variable->Type());
7783 return _data.variable->GetBoole();
7793 return convert_number_to_boolean(eval_number(c, stack));
7797 XPathAllocatorCapture cr(stack.Result);
7799 return !eval_string(c, stack).Empty();
7804 XPathAllocatorCapture cr(stack.Result);
7806 return !eval_NodeSet(c, stack).Empty();
7810 assert(!
"Wrong expression for return Type boolean");
7817 double eval_number(
const XPathContext& c,
const XPathStack& stack)
7822 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
7824 case ast_op_subtract:
7825 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
7827 case ast_op_multiply:
7828 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
7831 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
7834 return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
7837 return -_left->eval_number(c, stack);
7839 case ast_number_constant:
7840 return _data.number;
7843 return static_cast<double>(c.size);
7845 case ast_func_position:
7846 return static_cast<double>(c.position);
7848 case ast_func_count:
7850 XPathAllocatorCapture cr(stack.Result);
7852 return static_cast<double>(_left->eval_NodeSet(c, stack).size());
7855 case ast_func_string_length_0:
7857 XPathAllocatorCapture cr(stack.Result);
7859 return static_cast<double>(string_Value(c.n, stack.Result).length());
7862 case ast_func_string_length_1:
7864 XPathAllocatorCapture cr(stack.Result);
7866 return static_cast<double>(_left->eval_string(c, stack).length());
7869 case ast_func_number_0:
7871 XPathAllocatorCapture cr(stack.Result);
7873 return convert_Stringo_number(string_Value(c.n, stack.Result).c_str());
7876 case ast_func_number_1:
7877 return _left->eval_number(c, stack);
7881 XPathAllocatorCapture cr(stack.Result);
7885 XPathNodeSet_raw ns = _left->eval_NodeSet(c, stack);
7887 for (
const XPathNode* it = ns.begin(); it != ns.end(); ++it)
7889 XPathAllocatorCapture cri(stack.Result);
7891 r += convert_Stringo_number(string_Value(*it, stack.Result).c_str());
7897 case ast_func_floor:
7899 double r = _left->eval_number(c, stack);
7901 return r == r ? floor(r) : r;
7904 case ast_func_ceiling:
7906 double r = _left->eval_number(c, stack);
7908 return r == r ? ceil(r) : r;
7911 case ast_func_round:
7912 return round_nearest_nzero(_left->eval_number(c, stack));
7916 assert(_retType == _data.variable->Type());
7919 return _data.variable->GetNumber();
7929 return eval_boolean(c, stack) ? 1 : 0;
7933 XPathAllocatorCapture cr(stack.Result);
7935 return convert_Stringo_number(eval_string(c, stack).c_str());
7940 XPathAllocatorCapture cr(stack.Result);
7942 return convert_Stringo_number(eval_string(c, stack).c_str());
7946 assert(!
"Wrong expression for return Type number");
7954 XPathString eval_string_concat(
const XPathContext& c,
const XPathStack& stack)
7956 assert(_type == ast_func_concat);
7958 XPathAllocatorCapture ct(stack.temp);
7962 for (XPathAstNode* nc = _right; nc; nc = nc->_next) count++;
7965 XPathString static_buffer[4];
7966 XPathString* buffer = static_buffer;
7969 if (count >
sizeof(static_buffer) /
sizeof(static_buffer[0]))
7971 buffer =
static_cast<XPathString*
>(stack.temp->allocate(count *
sizeof(XPathString)));
7976 XPathStack swapped_stack = {stack.temp, stack.Result};
7978 buffer[0] = _left->eval_string(c, swapped_stack);
7981 for (XPathAstNode* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
7982 assert(pos == count);
7986 for (
size_t i = 0; i < count; ++i) length += buffer[i].length();
7989 Char8* Result =
static_cast<Char8*
>(stack.Result->allocate((length + 1) *
sizeof(Char8)));
7994 for (
size_t j = 0; j < count; ++j)
7995 for (
const Char8* bi = buffer[j].c_str(); *bi; ++bi)
8000 return XPathString(Result,
true);
8003 XPathString eval_string(
const XPathContext& c,
const XPathStack& stack)
8007 case ast_string_constant:
8008 return XPathStringConst(_data.string);
8010 case ast_func_local_Name_0:
8014 return XPathStringConst(local_Name(na));
8017 case ast_func_local_Name_1:
8019 XPathAllocatorCapture cr(stack.Result);
8021 XPathNodeSet_raw ns = _left->eval_NodeSet(c, stack);
8022 XPathNode na = ns.first();
8024 return XPathStringConst(local_Name(na));
8027 case ast_func_Name_0:
8031 return XPathStringConst(qualified_Name(na));
8034 case ast_func_Name_1:
8036 XPathAllocatorCapture cr(stack.Result);
8038 XPathNodeSet_raw ns = _left->eval_NodeSet(c, stack);
8039 XPathNode na = ns.first();
8041 return XPathStringConst(qualified_Name(na));
8044 case ast_func_namespace_uri_0:
8048 return XPathStringConst(namespace_uri(na));
8051 case ast_func_namespace_uri_1:
8053 XPathAllocatorCapture cr(stack.Result);
8055 XPathNodeSet_raw ns = _left->eval_NodeSet(c, stack);
8056 XPathNode na = ns.first();
8058 return XPathStringConst(namespace_uri(na));
8061 case ast_func_string_0:
8062 return string_Value(c.n, stack.Result);
8064 case ast_func_string_1:
8065 return _left->eval_string(c, stack);
8067 case ast_func_concat:
8068 return eval_string_concat(c, stack);
8070 case ast_func_substring_before:
8072 XPathAllocatorCapture cr(stack.temp);
8074 XPathStack swapped_stack = {stack.temp, stack.Result};
8076 XPathString s = _left->eval_string(c, swapped_stack);
8077 XPathString p = _right->eval_string(c, swapped_stack);
8079 const Char8* pos = FindSubstring(s.c_str(), p.c_str());
8081 return pos ? XPathString(s.c_str(), pos, stack.Result) : XPathString();
8084 case ast_func_substring_after:
8086 XPathAllocatorCapture cr(stack.temp);
8088 XPathStack swapped_stack = {stack.temp, stack.Result};
8090 XPathString s = _left->eval_string(c, swapped_stack);
8091 XPathString p = _right->eval_string(c, swapped_stack);
8093 const Char8* pos = FindSubstring(s.c_str(), p.c_str());
8094 if (!pos)
return XPathString();
8096 const Char8* Result = pos + p.length();
8098 return s.uses_heap() ? XPathString(Result, stack.Result) : XPathStringConst(Result);
8101 case ast_func_substring_2:
8103 XPathAllocatorCapture cr(stack.temp);
8105 XPathStack swapped_stack = {stack.temp, stack.Result};
8107 XPathString s = _left->eval_string(c, swapped_stack);
8108 size_t s_length = s.length();
8110 double first = round_nearest(_right->eval_number(c, stack));
8112 if (is_nan(first))
return XPathString();
8113 else if (first >= s_length + 1)
return XPathString();
8115 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8116 assert(1 <= pos && pos <= s_length + 1);
8118 const Char8* rbegin = s.c_str() + (pos - 1);
8120 return s.uses_heap() ? XPathString(rbegin, stack.Result) : XPathStringConst(rbegin);
8123 case ast_func_substring_3:
8125 XPathAllocatorCapture cr(stack.temp);
8127 XPathStack swapped_stack = {stack.temp, stack.Result};
8129 XPathString s = _left->eval_string(c, swapped_stack);
8130 size_t s_length = s.length();
8132 double first = round_nearest(_right->eval_number(c, stack));
8133 double last = first + round_nearest(_right->_next->eval_number(c, stack));
8135 if (is_nan(first) || is_nan(last))
return XPathString();
8136 else if (first >= s_length + 1)
return XPathString();
8137 else if (first >= last)
return XPathString();
8138 else if (last < 1)
return XPathString();
8140 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8141 size_t end = last >= s_length + 1 ? s_length + 1 :
static_cast<size_t>(last);
8143 assert(1 <= pos && pos <= end && end <= s_length + 1);
8144 const Char8* rbegin = s.c_str() + (pos - 1);
8145 const Char8* rend = s.c_str() + (end - 1);
8147 return (end == s_length + 1 && !s.uses_heap()) ? XPathStringConst(rbegin) : XPathString(rbegin, rend, stack.Result);
8150 case ast_func_normalize_space_0:
8152 XPathString s = string_Value(c.n, stack.Result);
8154 normalize_space(s.data(stack.Result));
8159 case ast_func_normalize_space_1:
8161 XPathString s = _left->eval_string(c, stack);
8163 normalize_space(s.data(stack.Result));
8168 case ast_func_translate:
8170 XPathAllocatorCapture cr(stack.temp);
8172 XPathStack swapped_stack = {stack.temp, stack.Result};
8174 XPathString s = _left->eval_string(c, stack);
8175 XPathString from = _right->eval_string(c, swapped_stack);
8176 XPathString to = _right->_next->eval_string(c, swapped_stack);
8178 translate(s.data(stack.Result), from.c_str(), to.c_str());
8185 assert(_retType == _data.variable->Type());
8188 return XPathStringConst(_data.variable->GetString());
8198 return XPathStringConst(eval_boolean(c, stack) ?
"true" :
"false");
8201 return convert_number_to_string(eval_number(c, stack), stack.Result);
8205 XPathAllocatorCapture cr(stack.temp);
8207 XPathStack swapped_stack = {stack.temp, stack.Result};
8209 XPathNodeSet_raw ns = eval_NodeSet(c, swapped_stack);
8210 return ns.Empty() ? XPathString() : string_Value(ns.first(), stack.Result);
8214 assert(!
"Wrong expression for return Type string");
8215 return XPathString();
8221 XPathNodeSet_raw eval_NodeSet(
const XPathContext& c,
const XPathStack& stack)
8227 XPathAllocatorCapture cr(stack.temp);
8229 XPathStack swapped_stack = {stack.temp, stack.Result};
8231 XPathNodeSet_raw ls = _left->eval_NodeSet(c, swapped_stack);
8232 XPathNodeSet_raw rs = _right->eval_NodeSet(c, stack);
8235 rs.SetType(XPathNodeSet::TypeUnsorted);
8237 rs.append(ls.begin(), ls.end(), stack.Result);
8238 rs.RemoveDuplicates();
8244 case ast_filter_posinv:
8246 XPathNodeSet_raw set = _left->eval_NodeSet(c, stack);
8249 if (_type == ast_filter) set.sort_do();
8251 apply_predicate(set, 0, _right, stack);
8257 return XPathNodeSet_raw();
8264 return step_do(c, stack, axis_to_type<axis_ancestor>());
8266 case axis_ancestor_or_self:
8267 return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());
8269 case axis_attribute:
8270 return step_do(c, stack, axis_to_type<axis_attribute>());
8273 return step_do(c, stack, axis_to_type<axis_GetChild>());
8275 case axis_descendant:
8276 return step_do(c, stack, axis_to_type<axis_descendant>());
8278 case axis_descendant_or_self:
8279 return step_do(c, stack, axis_to_type<axis_descendant_or_self>());
8281 case axis_following:
8282 return step_do(c, stack, axis_to_type<axis_following>());
8284 case axis_following_sibling:
8285 return step_do(c, stack, axis_to_type<axis_following_sibling>());
8287 case axis_namespace:
8289 return XPathNodeSet_raw();
8291 case axis_GetParent:
8292 return step_do(c, stack, axis_to_type<axis_GetParent>());
8294 case axis_preceding:
8295 return step_do(c, stack, axis_to_type<axis_preceding>());
8297 case axis_preceding_sibling:
8298 return step_do(c, stack, axis_to_type<axis_preceding_sibling>());
8301 return step_do(c, stack, axis_to_type<axis_self>());
8304 assert(!
"Unknown axis");
8305 return XPathNodeSet_raw();
8309 case ast_step_GetRoot:
8313 XPathNodeSet_raw ns;
8315 ns.SetType(XPathNodeSet::TypeSorted);
8317 if (c.n.GetNode()) ns.push_back(c.n.GetNode().GetRoot(), stack.Result);
8318 else if (c.n.GetAttribute()) ns.push_back(c.n.GetParent().GetRoot(), stack.Result);
8325 assert(_retType == _data.variable->Type());
8329 const XPathNodeSet& s = _data.variable->GetNodeSet();
8331 XPathNodeSet_raw ns;
8333 ns.SetType(s.Type());
8334 ns.append(s.begin(), s.end(), stack.Result);
8343 assert(!
"Wrong expression for return Type node set");
8344 return XPathNodeSet_raw();
8352 case ast_func_position:
8355 case ast_string_constant:
8356 case ast_number_constant:
8361 case ast_step_GetRoot:
8366 case ast_filter_posinv:
8370 if (_left && !_left->is_posinv())
return false;
8372 for (XPathAstNode* n = _right; n; n = n->_next)
8373 if (!n->is_posinv())
return false;
8387 XPathAllocator* _alloc;
8390 const Char8* _query;
8391 XPathVariableSet* _variables;
8393 XPathParseResult* _Result;
8395 void throw_error(
const char* message)
8397 _Result->error = message;
8398 _Result->Offset = _lexer.current_pos() - _query;
8403 void throw_error_oom()
8405 throw std::bad_alloc();
8410 void* Result = _alloc->allocate_nothrow(
sizeof(XPathAstNode));
8412 if (!Result) throw_error_oom();
8417 const Char8* alloc_string(
const XPathLexerString& Value)
8421 size_t length =
static_cast<size_t>(Value.end - Value.begin);
8423 Char8* c =
static_cast<Char8*
>(_alloc->allocate_nothrow((length + 1) *
sizeof(Char8)));
8424 if (!c) throw_error_oom();
8426 memcpy(c, Value.begin, length *
sizeof(Char8));
8434 XPathAstNode* ParseFunctionHelper(ast_type_t Type0, ast_type_t Type1,
size_t argc, XPathAstNode* args[2])
8438 if (argc == 1 && args[0]->retType() !=
XPathTypeNodeSet) throw_error(
"Function has to be applied to node set");
8440 return new (alloc_node()) XPathAstNode(argc == 0 ? Type0 : Type1,
XPathTypeString, args[0]);
8443 XPathAstNode* ParseFunction(
const XPathLexerString& Name,
size_t argc, XPathAstNode* args[2])
8445 switch (Name.begin[0])
8448 if (Name ==
"boolean" && argc == 1)
8449 return new (alloc_node()) XPathAstNode(ast_func_boolean,
XPathTypeBoole, args[0]);
8454 if (Name ==
"count" && argc == 1)
8456 if (args[0]->retType() !=
XPathTypeNodeSet) throw_error(
"Function has to be applied to node set");
8457 return new (alloc_node()) XPathAstNode(ast_func_count,
XPathTypeNumber, args[0]);
8459 else if (Name ==
"contains" && argc == 2)
8460 return new (alloc_node()) XPathAstNode(ast_func_contains,
XPathTypeString, args[0], args[1]);
8461 else if (Name ==
"concat" && argc >= 2)
8462 return new (alloc_node()) XPathAstNode(ast_func_concat,
XPathTypeString, args[0], args[1]);
8463 else if (Name ==
"ceiling" && argc == 1)
8464 return new (alloc_node()) XPathAstNode(ast_func_ceiling,
XPathTypeNumber, args[0]);
8469 if (Name ==
"false" && argc == 0)
8470 return new (alloc_node()) XPathAstNode(ast_func_false,
XPathTypeBoole);
8471 else if (Name ==
"floor" && argc == 1)
8472 return new (alloc_node()) XPathAstNode(ast_func_floor,
XPathTypeNumber, args[0]);
8477 if (Name ==
"id" && argc == 1)
8478 return new (alloc_node()) XPathAstNode(ast_func_id,
XPathTypeNodeSet, args[0]);
8483 if (Name ==
"last" && argc == 0)
8484 return new (alloc_node()) XPathAstNode(ast_func_last,
XPathTypeNumber);
8485 else if (Name ==
"lang" && argc == 1)
8486 return new (alloc_node()) XPathAstNode(ast_func_lang,
XPathTypeBoole, args[0]);
8487 else if (Name ==
"local-Name" && argc <= 1)
8488 return ParseFunctionHelper(ast_func_local_Name_0, ast_func_local_Name_1, argc, args);
8493 if (Name ==
"Name" && argc <= 1)
8494 return ParseFunctionHelper(ast_func_Name_0, ast_func_Name_1, argc, args);
8495 else if (Name ==
"namespace-uri" && argc <= 1)
8496 return ParseFunctionHelper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args);
8497 else if (Name ==
"normalize-space" && argc <= 1)
8498 return new (alloc_node()) XPathAstNode(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1,
XPathTypeString, args[0], args[1]);
8499 else if (Name ==
"not" && argc == 1)
8500 return new (alloc_node()) XPathAstNode(ast_func_not,
XPathTypeBoole, args[0]);
8501 else if (Name ==
"number" && argc <= 1)
8502 return new (alloc_node()) XPathAstNode(argc == 0 ? ast_func_number_0 : ast_func_number_1,
XPathTypeNumber, args[0]);
8507 if (Name ==
"position" && argc == 0)
8508 return new (alloc_node()) XPathAstNode(ast_func_position,
XPathTypeNumber);
8513 if (Name ==
"round" && argc == 1)
8514 return new (alloc_node()) XPathAstNode(ast_func_round,
XPathTypeNumber, args[0]);
8519 if (Name ==
"string" && argc <= 1)
8520 return new (alloc_node()) XPathAstNode(argc == 0 ? ast_func_string_0 : ast_func_string_1,
XPathTypeString, args[0]);
8521 else if (Name ==
"string-length" && argc <= 1)
8522 return new (alloc_node()) XPathAstNode(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1,
XPathTypeString, args[0]);
8523 else if (Name ==
"starts-with" && argc == 2)
8524 return new (alloc_node()) XPathAstNode(ast_func_starts_with,
XPathTypeBoole, args[0], args[1]);
8525 else if (Name ==
"substring-before" && argc == 2)
8526 return new (alloc_node()) XPathAstNode(ast_func_substring_before,
XPathTypeString, args[0], args[1]);
8527 else if (Name ==
"substring-after" && argc == 2)
8528 return new (alloc_node()) XPathAstNode(ast_func_substring_after,
XPathTypeString, args[0], args[1]);
8529 else if (Name ==
"substring" && (argc == 2 || argc == 3))
8530 return new (alloc_node()) XPathAstNode(argc == 2 ? ast_func_substring_2 : ast_func_substring_3,
XPathTypeString, args[0], args[1]);
8531 else if (Name ==
"sum" && argc == 1)
8533 if (args[0]->retType() !=
XPathTypeNodeSet) throw_error(
"Function has to be applied to node set");
8534 return new (alloc_node()) XPathAstNode(ast_func_sum,
XPathTypeNumber, args[0]);
8540 if (Name ==
"translate" && argc == 3)
8541 return new (alloc_node()) XPathAstNode(ast_func_translate,
XPathTypeString, args[0], args[1]);
8542 else if (Name ==
"true" && argc == 0)
8543 return new (alloc_node()) XPathAstNode(ast_func_true,
XPathTypeBoole);
8551 throw_error(
"Unrecognized function or wrong parameter count");
8556 axis_t ParseAxisName(
const XPathLexerString& Name,
bool& specified)
8560 switch (Name.begin[0])
8563 if (Name ==
"ancestor")
8564 return axis_ancestor;
8565 else if (Name ==
"ancestor-or-self")
8566 return axis_ancestor_or_self;
8567 else if (Name ==
"GetAttribute")
8568 return axis_attribute;
8573 if (Name ==
"GetChild")
8574 return axis_GetChild;
8579 if (Name ==
"descendant")
8580 return axis_descendant;
8581 else if (Name ==
"descendant-or-self")
8582 return axis_descendant_or_self;
8587 if (Name ==
"following")
8588 return axis_following;
8589 else if (Name ==
"following-sibling")
8590 return axis_following_sibling;
8595 if (Name ==
"namespace")
8596 return axis_namespace;
8601 if (Name ==
"GetParent")
8602 return axis_GetParent;
8603 else if (Name ==
"preceding")
8604 return axis_preceding;
8605 else if (Name ==
"preceding-sibling")
8606 return axis_preceding_sibling;
8621 return axis_GetChild;
8624 nodetest_t ParseNodeTest_type(
const XPathLexerString& Name)
8626 switch (Name.begin[0])
8629 if (Name ==
"comment")
8630 return nodetest_type_comment;
8636 return nodetest_type_node;
8641 if (Name ==
"processing-instruction")
8642 return nodetest_type_pi;
8648 return nodetest_type_text;
8656 return nodetest_none;
8660 XPathAstNode* ParsePrimaryExpression()
8662 switch (_lexer.current())
8666 XPathLexerString Name = _lexer.contents();
8669 throw_error(
"Unknown variable: variable set is not provided");
8671 XPathVariable* var = GetVariable(_variables, Name.begin, Name.end);
8674 throw_error(
"Unknown variable: variable set does not contain the given Name");
8678 return new (alloc_node()) XPathAstNode(ast_variable, var->Type(), var);
8681 case lex_open_brace:
8685 XPathAstNode* n = ParseExpression();
8687 if (_lexer.current() != lex_close_brace)
8688 throw_error(
"Unmatched braces");
8695 case lex_quoted_string:
8697 const Char8* Value = alloc_string(_lexer.contents());
8699 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_string_constant,
XPathTypeString, Value);
8709 if (!convert_Stringo_number(_lexer.contents().begin, _lexer.contents().end, &Value))
8712 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_number_constant,
XPathTypeNumber, Value);
8720 XPathAstNode* args[2] = {0};
8723 XPathLexerString
function = _lexer.contents();
8726 XPathAstNode* LastArg = 0;
8728 if (_lexer.current() != lex_open_brace)
8729 throw_error(
"Unrecognized function call");
8732 if (_lexer.current() != lex_close_brace)
8733 args[argc++] = ParseExpression();
8735 while (_lexer.current() != lex_close_brace)
8737 if (_lexer.current() != lex_comma)
8738 throw_error(
"No comma between function arguments");
8741 XPathAstNode* n = ParseExpression();
8743 if (argc < 2) args[argc] = n;
8744 else LastArg->SetNext(n);
8752 return ParseFunction(
function, argc, args);
8756 throw_error(
"Unrecognizable primary expression");
8765 XPathAstNode* ParseFilterExpression()
8767 XPathAstNode* n = ParsePrimaryExpression();
8769 while (_lexer.current() == lex_open_square_brace)
8773 XPathAstNode* expr = ParseExpression();
8775 if (n->retType() !=
XPathTypeNodeSet) throw_error(
"Predicate has to be applied to node set");
8777 bool posinv = expr->retType() !=
XPathTypeNumber && expr->is_posinv();
8779 n =
new (alloc_node()) XPathAstNode(posinv ? ast_filter_posinv : ast_filter,
XPathTypeNodeSet, n, expr);
8781 if (_lexer.current() != lex_close_square_brace)
8782 throw_error(
"Unmatched square brace");
8795 XPathAstNode* ParseStep(XPathAstNode* set)
8798 throw_error(
"Step has to be applied to node set");
8800 bool axis_specified =
false;
8801 axis_t axis = axis_GetChild;
8803 if (_lexer.current() == lex_axis_attribute)
8805 axis = axis_attribute;
8806 axis_specified =
true;
8810 else if (_lexer.current() == lex_dot)
8814 return new (alloc_node()) XPathAstNode(ast_step, set, axis_self, nodetest_type_node, 0);
8816 else if (_lexer.current() == lex_double_dot)
8820 return new (alloc_node()) XPathAstNode(ast_step, set, axis_GetParent, nodetest_type_node, 0);
8823 nodetest_t nt_type = nodetest_none;
8824 XPathLexerString nt_Name;
8826 if (_lexer.current() == lex_string)
8829 nt_Name = _lexer.contents();
8833 if (_lexer.current() == lex_double_colon)
8836 if (axis_specified) throw_error(
"Two axis specifiers in one step");
8838 axis = ParseAxisName(nt_Name, axis_specified);
8840 if (!axis_specified) throw_error(
"Unknown axis");
8845 if (_lexer.current() == lex_multiply)
8847 nt_type = nodetest_all;
8848 nt_Name = XPathLexerString();
8851 else if (_lexer.current() == lex_string)
8853 nt_Name = _lexer.contents();
8856 else throw_error(
"Unrecognized node test");
8859 if (nt_type == nodetest_none)
8862 if (_lexer.current() == lex_open_brace)
8866 if (_lexer.current() == lex_close_brace)
8870 nt_type = ParseNodeTest_type(nt_Name);
8872 if (nt_type == nodetest_none) throw_error(
"Unrecognized node Type");
8874 nt_Name = XPathLexerString();
8876 else if (nt_Name ==
"processing-instruction")
8878 if (_lexer.current() != lex_quoted_string)
8879 throw_error(
"Only literals are allowed as arguments to processing-instruction()");
8881 nt_type = nodetest_pi;
8882 nt_Name = _lexer.contents();
8885 if (_lexer.current() != lex_close_brace)
8886 throw_error(
"Unmatched brace near processing-instruction()");
8890 throw_error(
"Unmatched brace near node Type test");
8896 if (nt_Name.end - nt_Name.begin > 2 && nt_Name.end[-2] ==
':' && nt_Name.end[-1] ==
'*')
8900 nt_type = nodetest_all_in_namespace;
8902 else nt_type = nodetest_Name;
8906 else if (_lexer.current() == lex_multiply)
8908 nt_type = nodetest_all;
8911 else throw_error(
"Unrecognized node test");
8913 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_step, set, axis, nt_type, alloc_string(nt_Name));
8915 XPathAstNode* last = 0;
8917 while (_lexer.current() == lex_open_square_brace)
8921 XPathAstNode* expr = ParseExpression();
8923 XPathAstNode* pred =
new (alloc_node()) XPathAstNode(ast_predicate,
XPathTypeNodeSet, expr);
8925 if (_lexer.current() != lex_close_square_brace)
8926 throw_error(
"Unmatched square brace");
8929 if (last) last->SetNext(pred);
8930 else n->SetRight(pred);
8939 XPathAstNode* ParseRelativeLocation_Path(XPathAstNode* set)
8941 XPathAstNode* n = ParseStep(set);
8943 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
8945 lexeme_t l = _lexer.current();
8948 if (l == lex_double_slash)
8949 n =
new (alloc_node()) XPathAstNode(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
8959 XPathAstNode* ParseLocationPath()
8961 if (_lexer.current() == lex_slash)
8965 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_step_GetRoot,
XPathTypeNodeSet);
8968 lexeme_t l = _lexer.current();
8970 if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
8971 return ParseRelativeLocation_Path(n);
8975 else if (_lexer.current() == lex_double_slash)
8979 XPathAstNode* n =
new (alloc_node()) XPathAstNode(ast_step_GetRoot,
XPathTypeNodeSet);
8980 n =
new (alloc_node()) XPathAstNode(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
8982 return ParseRelativeLocation_Path(n);
8986 return ParseRelativeLocation_Path(0);
8993 XPathAstNode* ParsePathExpression()
9002 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
9003 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
9004 _lexer.current() == lex_string)
9006 if (_lexer.current() == lex_string)
9009 const Char8* state = _lexer.state();
9011 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
9013 if (*state !=
'(')
return ParseLocationPath();
9016 if (ParseNodeTest_type(_lexer.contents()) != nodetest_none)
return ParseLocationPath();
9019 XPathAstNode* n = ParseFilterExpression();
9021 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
9023 lexeme_t l = _lexer.current();
9026 if (l == lex_double_slash)
9028 if (n->retType() !=
XPathTypeNodeSet) throw_error(
"Step has to be applied to node set");
9030 n =
new (alloc_node()) XPathAstNode(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9034 return ParseRelativeLocation_Path(n);
9039 else return ParseLocationPath();
9043 XPathAstNode* ParseUnionExpression()
9045 XPathAstNode* n = ParsePathExpression();
9047 while (_lexer.current() == lex_union)
9051 XPathAstNode* expr = ParseUnionExpression();
9054 throw_error(
"Union operator has to be applied to node sets");
9056 n =
new (alloc_node()) XPathAstNode(ast_op_union,
XPathTypeNodeSet, n, expr);
9063 XPathAstNode* ParseUnaryExpression()
9065 if (_lexer.current() == lex_minus)
9069 XPathAstNode* expr = ParseUnaryExpression();
9071 return new (alloc_node()) XPathAstNode(ast_op_negate,
XPathTypeNumber, expr);
9073 else return ParseUnionExpression();
9080 XPathAstNode* ParseMultiplicativeExpression()
9082 XPathAstNode* n = ParseUnaryExpression();
9084 while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string &&
9085 (_lexer.contents() ==
"mod" || _lexer.contents() ==
"div")))
9087 ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply :
9088 _lexer.contents().begin[0] ==
'd' ? ast_op_divide : ast_op_mod;
9091 XPathAstNode* expr = ParseUnaryExpression();
9102 XPathAstNode* ParseAdditiveExpression()
9104 XPathAstNode* n = ParseMultiplicativeExpression();
9106 while (_lexer.current() == lex_plus || _lexer.current() == lex_minus)
9108 lexeme_t l = _lexer.current();
9112 XPathAstNode* expr = ParseMultiplicativeExpression();
9114 n =
new (alloc_node()) XPathAstNode(l == lex_plus ? ast_op_add : ast_op_subtract,
XPathTypeNumber, n, expr);
9125 XPathAstNode* ParseRelationalExpression()
9127 XPathAstNode* n = ParseAdditiveExpression();
9129 while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal ||
9130 _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal)
9132 lexeme_t l = _lexer.current();
9135 XPathAstNode* expr = ParseAdditiveExpression();
9137 n =
new (alloc_node()) XPathAstNode(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater :
9138 l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal,
XPathTypeBoole, n, expr);
9147 XPathAstNode* ParseEqualityExpression()
9149 XPathAstNode* n = ParseRelationalExpression();
9151 while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal)
9153 lexeme_t l = _lexer.current();
9157 XPathAstNode* expr = ParseRelationalExpression();
9159 n =
new (alloc_node()) XPathAstNode(l == lex_equal ? ast_op_equal : ast_op_not_equal,
XPathTypeBoole, n, expr);
9166 XPathAstNode* ParseAndExpression()
9168 XPathAstNode* n = ParseEqualityExpression();
9170 while (_lexer.current() == lex_string && _lexer.contents() ==
"and")
9174 XPathAstNode* expr = ParseEqualityExpression();
9176 n =
new (alloc_node()) XPathAstNode(ast_op_and,
XPathTypeBoole, n, expr);
9183 XPathAstNode* ParseOrExpression()
9185 XPathAstNode* n = ParseAndExpression();
9187 while (_lexer.current() == lex_string && _lexer.contents() ==
"or")
9191 XPathAstNode* expr = ParseAndExpression();
9193 n =
new (alloc_node()) XPathAstNode(ast_op_or,
XPathTypeBoole, n, expr);
9200 XPathAstNode* ParseExpression()
9202 return ParseOrExpression();
9205 XPathParser(
const Char8* query, XPathVariableSet* variables, XPathAllocator* alloc, XPathParseResult* Result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _Result(Result)
9209 XPathAstNode* parse()
9211 XPathAstNode* Result = ParseExpression();
9213 if (_lexer.current() != lex_eof)
9216 throw_error(
"Incorrect query");
9222 static XPathAstNode* parse(
const Char8* query, XPathVariableSet* variables, XPathAllocator* alloc, XPathParseResult* Result)
9224 XPathParser parser(query, variables, alloc, Result);
9226 return parser.parse();
9230 struct XPathQueryImpl
9232 static XPathQueryImpl* create()
9234 void* memory = Memory::allocate(
sizeof(XPathQueryImpl));
9236 return new (memory) XPathQueryImpl();
9239 static void destroy(
void* ptr)
9244 static_cast<XPathQueryImpl*
>(ptr)->alloc.release();
9247 Memory::deallocate(ptr);
9250 XPathQueryImpl(): GetRoot(0), alloc(&block)
9255 XPathAstNode* GetRoot;
9256 XPathAllocator alloc;
9257 XPathMemoryBlock block;
9260 PUGI__FN XPathString EvaluateString_impl(XPathQueryImpl* impl,
const XPathNode& n, XPathStackData& sd)
9262 if (!impl)
return XPathString();
9264 XPathContext c(n, 1, 1);
9266 return impl->GetRoot->eval_string(c, sd.stack);
9280 PUGI__FN
XPathNode::XPathNode(
const Attribute& attribute_,
const Node& GetParent_): TargetNode(attribute_ ? GetParent_ : Node()), _attribute(attribute_)
9286 return _attribute ? Node() : TargetNode;
9296 return _attribute ? TargetNode : TargetNode.
GetParent();
9299 PUGI__FN
static void unspecified_bool_XPathNode(XPathNode***)
9303 PUGI__FN XPathNode::operator XPathNode::unspecified_bool_type()
const
9305 return (TargetNode || _attribute) ? unspecified_bool_XPathNode : 0;
9310 return !(TargetNode || _attribute);
9315 return TargetNode == n.TargetNode && _attribute == n._attribute;
9320 return TargetNode != n.TargetNode || _attribute != n._attribute;
9324 PUGI__FN
bool operator&&(
const XPathNode& lhs,
bool rhs)
9326 return (
bool)lhs && rhs;
9329 PUGI__FN
bool operator||(
const XPathNode& lhs,
bool rhs)
9331 return (
bool)lhs || rhs;
9335 PUGI__FN
void XPathNodeSet::_assign(const_iterator begin_, const_iterator end_)
9337 assert(begin_ <= end_);
9339 size_t size_ =
static_cast<size_t>(end_ - begin_);
9344 if (Begin != &Storage) internal::Memory::deallocate(Begin);
9347 if (begin_ != end_) Storage = *begin_;
9350 End = &Storage + size_;
9355 XPathNode* storage =
static_cast<XPathNode*
>(internal::Memory::allocate(size_ *
sizeof(XPathNode)));
9359 throw std::bad_alloc();
9362 memcpy(storage, begin_, size_ *
sizeof(XPathNode));
9365 if (Begin != &Storage) internal::Memory::deallocate(Begin);
9369 End = storage + size_;
9377 PUGI__FN
XPathNodeSet::XPathNodeSet(const_iterator begin_, const_iterator end_, CollectionType Type_): TypeOrder(Type_), Begin(&Storage), End(&Storage)
9379 _assign(begin_, end_);
9384 if (Begin != &Storage) internal::Memory::deallocate(Begin);
9389 _assign(ns.Begin, ns.End);
9394 if (
this == &ns)
return *
this;
9396 TypeOrder = ns.TypeOrder;
9397 _assign(ns.Begin, ns.End);
9414 return Begin == End;
9419 assert(index <
size());
9420 return Begin[index];
9435 TypeOrder = internal::XPathSort(Begin, End, TypeOrder, reverse);
9440 return internal::XPathFirst(Begin, End, TypeOrder);
9447 PUGI__FN XPathParseResult::operator bool()
const
9466 return static_cast<const internal::XPathVariableNodeSet*
>(
this)->Name;
9469 return static_cast<const internal::XPathVariableNumber*
>(
this)->Name;
9472 return static_cast<const internal::XPathVariableString*
>(
this)->Name;
9475 return static_cast<const internal::XPathVariableBoole*
>(
this)->Name;
9478 assert(!
"Invalid variable Type");
9495 return (
ValueType ==
XPathTypeNumber) ?
static_cast<const internal::XPathVariableNumber*
>(
this)->Value : internal::gen_nan();
9500 const Char8* Value = (
ValueType ==
XPathTypeString) ? static_cast<const internal::XPathVariableString*>(
this)->Value : 0;
9501 return Value ? Value :
"";
9506 return (
ValueType ==
XPathTypeNodeSet) ?
static_cast<const internal::XPathVariableNodeSet*
>(
this)->Value : internal::dummy_NodeSet;
9513 static_cast<internal::XPathVariableBoole*
>(
this)->Value = Value;
9521 static_cast<internal::XPathVariableNumber*
>(
this)->Value = Value;
9529 internal::XPathVariableString* var =
static_cast<internal::XPathVariableString*
>(
this);
9532 size_t size = (internal::strlength(Value) + 1) *
sizeof(Char8);
9534 Char8* copy =
static_cast<Char8*
>(internal::Memory::allocate(size));
9535 if (!copy)
return false;
9537 memcpy(copy, Value, size);
9540 if (var->Value) internal::Memory::deallocate(var->Value);
9550 static_cast<internal::XPathVariableNodeSet*
>(
this)->Value = Value;
9556 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i) _data[i] = 0;
9561 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
9563 XPathVariable* var = _data[i];
9569 internal::delete_XPathVariable(var->ValueType, var);
9576 PUGI__FN XPathVariable* XPathVariableSet::Find(
const Char8* Name)
const
9578 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
9579 size_t hash = internal::hash_string(Name) % hash_size;
9582 for (XPathVariable* var = _data[hash]; var; var = var->NextVariable)
9583 if (internal::strequal(var->Name(), Name))
9591 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
9592 size_t hash = internal::hash_string(Name) % hash_size;
9595 for (XPathVariable* var = _data[hash]; var; var = var->NextVariable)
9596 if (internal::strequal(var->Name(), Name))
9597 return var->
Type() == Type ? var : 0;
9600 XPathVariable* Result = internal::new_XPathVariable(Type, Name);
9604 Result->ValueType = Type;
9605 Result->NextVariable = _data[hash];
9607 _data[hash] = Result;
9616 return var ? var->Set(Value) :
false;
9622 return var ? var->Set(Value) :
false;
9628 return var ? var->Set(Value) :
false;
9634 return var ? var->Set(Value) :
false;
9647 PUGI__FN XPathQuery::XPathQuery(
const Char8* query, XPathVariableSet* variables): QueryImplementation(0)
9649 internal::XPathQueryImpl* qimpl = internal::XPathQueryImpl::create();
9653 throw std::bad_alloc();
9657 internal::buffer_holder impl_holder(qimpl, internal::XPathQueryImpl::destroy);
9659 qimpl->GetRoot = internal::XPathParser::parse(query, variables, &qimpl->alloc, &ResultCache);
9663 QueryImplementation =
static_cast<internal::XPathQueryImpl*
>(impl_holder.release());
9664 ResultCache.error = 0;
9671 internal::XPathQueryImpl::destroy(QueryImplementation);
9678 return static_cast<internal::XPathQueryImpl*
>(QueryImplementation)->GetRoot->retType();
9683 if (!QueryImplementation)
return false;
9685 internal::XPathContext c(n, 1, 1);
9686 internal::XPathStackData sd;
9688 return static_cast<internal::XPathQueryImpl*
>(QueryImplementation)->GetRoot->eval_boolean(c, sd.stack);
9693 if (!QueryImplementation)
return internal::gen_nan();
9695 internal::XPathContext c(n, 1, 1);
9696 internal::XPathStackData sd;
9698 return static_cast<internal::XPathQueryImpl*
>(QueryImplementation)->GetRoot->eval_number(c, sd.stack);
9703 internal::XPathStackData sd;
9705 return internal::EvaluateString_impl(static_cast<internal::XPathQueryImpl*>(QueryImplementation), n, sd).c_str();
9710 internal::XPathStackData sd;
9712 internal::XPathString r = internal::EvaluateString_impl(static_cast<internal::XPathQueryImpl*>(QueryImplementation), n, sd);
9714 size_t full_size = r.length() + 1;
9718 size_t size = (full_size < capacity) ? full_size : capacity;
9721 memcpy(buffer, r.c_str(), (size - 1) *
sizeof(Char8));
9722 buffer[size - 1] = 0;
9730 if (!QueryImplementation)
return XPathNodeSet();
9732 internal::XPathAstNode* GetRoot =
static_cast<internal::XPathQueryImpl*
>(QueryImplementation)->GetRoot;
9736 XPathParseResult res;
9737 res.error =
"Expression does not evaluate to node set";
9739 String ErrorMessage(
String(res.Description()) +
"\nError:" + res.error +
"\nAt Offset: " +
ToString(res.Offset));
9744 internal::XPathContext c(n, 1, 1);
9745 internal::XPathStackData sd;
9748 internal::XPathNodeSet_raw r = GetRoot->eval_NodeSet(c, sd.stack);
9750 return XPathNodeSet(r.begin(), r.end(), r.Type());
9758 PUGI__FN
static void unspecified_bool_XPathQuery(XPathQuery***)
9762 PUGI__FN XPathQuery::operator XPathQuery::unspecified_bool_type()
const
9764 return QueryImplementation ? unspecified_bool_XPathQuery : 0;
9769 return !QueryImplementation;
9774 XPathQuery q(query, variables);
9780 XPathNodeSet s = query.EvaluateNodeSet(*
this);
9781 return s.Empty() ? XPathNode() : s.first();
9784 PUGI__FN XPathNodeSet
Node::FindNodes(
const Char8* query, XPathVariableSet* variables)
const
9786 XPathQuery q(query, variables);
9792 return query.EvaluateNodeSet(*
this);
9802 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
9803 # pragma warning(pop)
9807 #undef PUGI__NO_INLINE
9808 #undef PUGI__STATIC_ASSERT
9809 #undef PUGI__DMC_VOLATILE
9810 #undef PUGI__MSVC_CRT_VERSION
9811 #undef PUGI__NS_BEGIN
9814 #undef PUGI__FN_NO_INLINE
9815 #undef PUGI__IS_CHARTYPE_IMPL
9816 #undef PUGI__IS_CHARTYPE
9817 #undef PUGI__IS_CHARTYPEX
9820 #undef PUGI__PUSHNODE
9821 #undef PUGI__POPNODE
9822 #undef PUGI__SCANFOR
9823 #undef PUGI__SCANWHILE
9825 #undef PUGI__THROW_ERROR
9826 #undef PUGI__CHECK_ERROR
bool Set(const Char8 *rhs)
Set text.
Node GetNode() const
Get the XML::Node this is referencing.
const unsigned int ParseWnormAttribute
This flag determines if attribute values are normalized using NMTOKENS normalization rules during par...
bool operator!() const
Logical not operator, used a workaround for borland compiler.
size_t HashValue() const
Get a unique identifying value for the Attribute this represents.
Attribute AppendAttribute(const Char8 *Name)
Creates an Attribute and puts it at the end of this Nodes attributes.
bool operator==(const AttributeIterator &rhs) const
Compares this AttributeIterator to another AttributeIterator for equality.
NodeStruct * NodeData
Stores pointers to the Node data and some metadata.
const XPathNode & operator[](size_t index) const
Indexing operator.
Attribute GetNextAttribute() const
Get the next attribute.
bool operator>(const Attribute &r) const
Compares the internal values to check for inequality.
attribute_iterator attributes_end() const
Get an Attribute iterator that references the one past the last Attribute on this Node...
const Char8 * GetChildValue() const
Retrieve the value of this(or a child's) Nodes PCDATA child Node.
const unsigned int ParseEol
This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default.
Node FirstElementByPath(const Char8 *Path, Char8 delimiter= '/') const
Search for a node by Path consisting of node names and . or .. elements.
XPathValueType
XPathQuery return type.
const AttributeIterator & operator--()
Decrement the iterator to the next member of the container.
bool operator==(const NamedNodeIterator &rhs) const
Compares this NamedNodeIterator to another NamedNodeIterator for equality.
const unsigned int ParseWconvAttribute
This flag determines if attribute values are normalized using CDATA normalization rules during parsin...
const XPathNode * const_iterator
An iterator trait. Const iterator for XPathNodes.
AttributeStruct * InternalObject() const
Retrieve a pointer to the internal data.
double GetNumber() const
Get this as a double.
bool AsBool(bool def=false) const
Attempts to convert the value of the attribute to a float and returns the results.
XPathNodeSet FindNodes(const Char8 *query, XPathVariableSet *variables=0) const
Select a group of nodes by evaluating an XPath query.
Node()
Default constructor. Constructs an empty node.
void Print(Writer &WriterInstance, const Char8 *indent="\t", unsigned int flags=FormatDefault, Encoding DocumentEncoding=EncodingAuto, unsigned int Depth=0) const
Output the XML document using a Writer.
XPathNode()
Default constructor; constructs empty XPath node.
const NodeIterator & operator++()
Increment the iterator to the next member of the container.
Node GetParent() const
Attempt to retrieve the parent of this Node.
bool SetName(const Char8 *rhs)
Set the name of .
bool Set(bool Value)
Set variable Value; no Type conversion is performed.
Whole AsWhole(Whole def=0) const
Get text as a number, or the default Value if conversion did not succeed or object is empty...
bool operator!() const
Used to convert this attribute the opposite of it's normal boolean value.
~Node()
Virtual deconstructor.
TreeWalker()
Default constructor, initializes depth, and can do little else without a fully implemented treewalker...
String ToString(const T &Datum)
Converts whatever to a String as long as a streaming operator is available for it.
attribute_iterator attributes_begin() const
Get an Attribute iterator that references the first Attribute on this Node.
The parser could not determine type of tag.
void sort(bool reverse=false)
Sort the collection in ascending/descending order by document order.
Attribute GetFirstAttribute() const
Get the First Attribute in this Node.
const Char8 * Value() const
Get the Value of this Attribute.
std::basic_string< wchar_t, std::char_traits< wchar_t >, std::allocator< wchar_t > > MEZZ_LIB AsWide(const char *str)
Convert a Convert a c-style string to std::wstring containing native encoding (Usually UCS2 on window...
XPathVariable()
Protected Default constructor to prevent default constrution.
bool operator>(const Node &r) const
Compares the internal values to check for greaterthanness.
void *(* AllocationFunction)(size_t size)
Memory allocation function interface; returns pointer to allocated memory or NULL on failure...
virtual void Write(const void *data, size_t size)
Actually issues the write commands.
Node GetFirstChild() const
Get the first child Node of this Node.
WriterFile(void *FilePtr)
Construct WriterInstance from a FILE* object; void* is used to avoid header dependencies on stdio...
#define MEZZ_EXCEPTION(num, desc)
An easy way to throw exceptions with rich information.
XPathNodeSet()
Default constructor. Constructs empty set.
int Integer
A datatype used to represent any integer close to.
Node GetParent() const
Get the parent of the XML::Node or XML::Attribute this refers to.
Attribute InsertAttributeAfter(const Char8 *Name, const Attribute &attr)
Creates an Attribute and puts it into the list of this Nodes attributes.
XPathNode first() const
Get first node in the collection by document order.
CollectionType
The different ways a collection may or may not be ordered.
CollectionType Type() const
Get collection Type.
bool operator==(const XPathNode &n) const
Called when comparing two XPathNode instances for equality.
bool RemoveAttribute(const Attribute &a)
Remove specified Attribute.
const Char8 * AsString(const Char8 *def="") const
Attempts to convert the value of the attribute to a String and returns the results.
NamedNodeIterator()
Default constructor.
bool operator>=(const Node &r) const
Compares the internal values to check for inequality and greaterthanness.
bool operator!() const
Used to convert this node the opposite of it's normal boolean value.
double EvaluateNumber(const XPathNode &n) const
Evaluate expression as double value in the specified context; performs Type conversion if necessary...
bool operator!() const
Used to convert this attribute the opposite of it's normal boolean value.
NodeText & operator=(const Char8 *rhs)
Set text (equivalent to set without error checking)
Parsing error occurred while parsing comment.
A document tree's absolute GetRoot.
bool EvaluateBoole(const XPathNode &n) const
Evaluate expression as boolean value in the specified context; performs Type conversion if necessary...
const_iterator end() const
Get Ending iterator.
bool SetValue(const Char8 *rhs)
Set the value of this.
size_t size() const
Get collection size.
bool operator==(const Node &r) const
Compares the internal values to check equality.
NodeStruct * InternalObject() const
Get internal pointer.
bool operator!=(const NodeIterator &rhs) const
Compares this NodeIterator to another NodeIterator for inequality.
bool SaveFile(const char *Path, const Char8 *indent="\t", unsigned int flags=FormatDefault, Encoding DocumentEncoding=EncodingAuto) const
Save XML to file.
bool Empty() const
Is this storing anything at all?
Node * operator->() const
Get the pointer the Node this points to.
ParseResult Load(std::basic_istream< char, std::char_traits< char > > &stream, unsigned int options=ParseDefault, Encoding DocumentEncoding=EncodingAuto)
Load XML from a stream.
This implements the exception hiearchy for Mezzanine.
const char * Description() const
Get error Description.
Processing instruction, i.e. ''.
Parsing error occurred while parsing document type declaration.
Node GetNextSibling() const
Attempt to retrieve the next sibling of this Node.
const char * Description() const
Error message (0 if no error).
Error reading from file or stream.
Node DocumentElement() const
Get document element.
float AsFloat(float def=0) const
Get text as a number, or the default Value if conversion did not succeed or object is empty...
XPathValueType Type() const
Get variable type.
XPathNodeSet & operator=(const XPathNodeSet &ns)
Assignment Operator.
const unsigned int ParseWsPcdata
This flag determines if plain character data (NodePcdata) that consist only of whitespace are added t...
Node & operator*() const
Deferences this Iterator.
This is returned to indicated there where no issues parsing the XML document.
AllocationFunction MEZZ_LIB GetMemoryAllocationFunction()
Get the current allocation funciton.
float Real
A Datatype used to represent a real floating point number.
char Char8
A datatype to represent one character.
Number This corresponds to a double or Real.
const unsigned int FormatSaveFileText
Open file using text mode in XML::Document::SaveFile. This enables special character (i...
void Save(Writer &WriterInstance, const Char8 *indent="\t", unsigned int flags=FormatDefault, Encoding DocumentEncoding=EncodingAuto) const
Save XML document to WriterInstance.
const Char8 * Value() const
Get the Value of this Node.
Node & operator*() const
Deferences this Iterator.
bool RemoveChild(const Node &n)
Remove specified child element.
bool SetValue(const Char8 *rhs)
Set the value of this.
bool operator<(const Node &r) const
Compares the internal values to check for lessthanness.
AttributeIterator()
Default Constructor, makes a blank iterator.
Node GetLastChild() const
Get the last child Node of this Node.
int AsInt(int def=0) const
Get text as a number, or the default Value if conversion did not succeed or object is empty...
Encoding
These flags determine the encoding of input data for an XML document.
bool operator!=(const AttributeIterator &rhs) const
Compares this AttributeIterator to another AttributeIterator for inequality.
double AsDouble(double def=0) const
Get text as a number, or the default Value if conversion did not succeed or object is empty...
bool SetName(const Char8 *rhs)
Set the name of .
virtual ~TreeWalker()
Virtual deconstructor. Tears down a TreeWalker.
void(* DeAllocationFunction)(void *ptr)
Function pointer type for a memory deallocation function interface.
Whole AsWhole(Whole def=0) const
Attempts to convert the value of the attribute to a Whole and returns the results.
std::basic_string< char, std::char_traits< char >, std::allocator< char > > MEZZ_LIB AsUtf8(const wchar_t *str)
Convert a c-style string of wchar_t to std::string containing UTF8.
Plain character data, i.e. 'text'.
Attribute PrependCopy(const Attribute &proto)
Copies an Attribute and puts the copy at the beginning of this Nodes attributes.
const_iterator begin() const
Get Beginning iterator.
Attribute InsertAttributeBefore(const Char8 *Name, const Attribute &attr)
Creates an Attribute and puts it into the list of this Nodes attributes.
Node data() const
Get the data node (NodePcdata or NodeCdata) for this object.
Auto-detect input DocumentEncoding using BOM or < / detection; use UTF8 if BOM is not found...
ptrdiff_t OffSetDebug() const
Get node Offset in parsed file/string (in char_t units) for debugging purposes.
Node FindChildbyAttribute(const Char8 *Name, const Char8 *AttrName, const Char8 *AttrValue) const
Find a Node by an Attribute it has.
const NodeIterator & operator--()
Decrement the iterator to the next member of the container.
Real AsReal(Real def=0) const
Get text as a number, or the default Value if conversion did not succeed or object is empty...
String Path(Char8 delimiter= '/') const
Get the absolute path to this Node.
iterator begin() const
Get a Child node iterator that references the first child Node.
const AttributeIterator & operator++()
Increment the iterator to the next member of the container.
unsigned int AsUint(unsigned int def=0) const
Attempts to convert the value of the attribute to an unsigned int and returns the results...
const unsigned int FormatNoDeclaration
Omit default XML declaration even if there is no declaration in the document. This flag is off by def...
void Reset()
Removes all nodes, leaving the empty document.
int AsInt(int def=0) const
Attempts to convert the value of the attribute to an int and returns the results. ...
~XPathNodeSet()
Destructor.
virtual void Write(const void *data, size_t size)
Construct a Writer from a FILE* object.
iterator end() const
Get a Child node iterator that references one past the last child Node.
ProcessDepth Depth
The current process depth as interpretted by Main.
AttributeIterator attribute_iterator
An iterator for Attribute members on this Node.
bool Empty() const
Is this storing anything at all?
Parsing error occurred while parsing document declaration/processing instruction. ...
ParseResult LoadBuffer(const void *contents, size_t size, unsigned int options=ParseDefault, Encoding DocumentEncoding=EncodingAuto)
Load document from buffer. Copies/converts the buffer, so it may be deleted or changed after the func...
bool operator==(const Attribute &r) const
Compares the internal values to check equality.
bool operator!() const
Logical not operator, used a workaround for borland compiler.
Attribute GetLastAttribute() const
Get the Last Attribute in this Node.
bool operator!=(const Attribute &r) const
Compares the internal values to check inequality.
Node GetRoot() const
Attempt to retrieve the root Node, or the most base Node containing this Node.
bool operator<=(const Attribute &r) const
Compares the internal values to check for inequality.
Parsing error occurred while parsing end element tag.
Integer AsInteger(Integer def=0) const
Attempts to convert the value of the attribute to a Integer and returns the results.
void(* unspecified_bool_type)(Node ***)
Used to prevent casting to numerical types acccidentally.
void MEZZ_LIB SetMemoryManagementFunctions(AllocationFunction allocate, DeAllocationFunction deallocate)
Override default memory management functions. All subsequent allocations/deallocations will be perfor...
XPathValueType ReturnType() const
Get query expression return Type.
Real AsReal(Real def=0) const
Attempts to convert the value of the attribute to a Real and returns the results. ...
NodeType
The types of nodes that could be in the XML Tree.
Node InsertChildAfter(NodeType Type, const Node &node)
Creates a Node and makes it a child of this one, and puts at the middle of the Child Nodes...
bool operator!=(const Node &r) const
Compares the internal values to check inequality.
ParseResult LoadBufferInplace(void *contents, size_t size, unsigned int options=ParseDefault, Encoding DocumentEncoding=EncodingAuto)
Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for...
bool Traverse(TreeWalker &walker)
Perform sophisticated (or whatever) algorithms on this and all descendant Nodes in the XML tree...
Thrown when an XPath query is being parsed but is invalid.
const unsigned int ParseDeclaration
This flag determines if document declaration (NodeDeclaration) is added to the DOM tree...
XPathNode FindSingleNode(const Char8 *query, XPathVariableSet *variables=0) const
Select single node by evaluating an XPath query. Returns first node from the resulting node set...
Node PrependChild(NodeType Type=NodeElement)
Creates a Node and makes it a child of this one, and puts at the beginning of the Child Nodes...
const char * error
Error message (0 if no error)
XPathValueType ValueType
What kind of data does this variable store.
bool operator>=(const Attribute &r) const
Compares the internal values to check for inequality.
virtual bool OnTraversalEnd(Node &node)
Called on the root Node of the xml subtree when traversal ends.
Parsing error occurred while parsing start element tag.
Attribute InsertCopyBefore(const Attribute &proto, const Attribute &attr)
Copies an Attribute and puts the copy into the list of this Nodes attributes.
String EvaluateString(const XPathNode &n) const
Evaluate expression as string value in the specified context; performs Type conversion if necessary...
An unkown error, currently nothing should be able to return this status.
File was not found during a loading from filename attempt.
The same document encoding wchar_t has (usually either UTF16 or UTF32)
Attribute GetAttribute() const
Get the XML::Attribute this is referencing.
XPathParseResult()
Default constructor, initializes object to failed state.
Node InsertChildBefore(NodeType Type, const Node &node)
Creates a Node and makes it a child of this one, and puts at the middle of the Child Nodes...
bool operator!=(const NamedNodeIterator &rhs) const
Compares this NamedNodeIterator to another NamedNodeIterator for inequality.
const XPathNodeSet & GetNodeSet() const
Get this as a XPathNodeSet.
XPathNodeSet EvaluateNodeSet(const XPathNode &n) const
Evaluate expression as node set in the specified context.
virtual bool OnTraversalBegin(Node &node)
Called by the root Node of the xml subtree when traversal begins.
Corresponds to the String type.
~XPathVariableSet()
Default Deconstructor, Deletes any XPathVariable it contains.
bool Empty() const
Check if collection is empty.
Document()
Creates an empty document with just a root Node.
Attribute GetPreviousAttribute() const
Get the previous attribute.
float AsFloat(float def=0) const
Attempts to convert the value of the attribute to a float and returns the results.
const Char8 * Name() const
Get the variable name.
Attribute()
Constructs an empty Attribute.
NodeIterator iterator
An iterator for child Nodes that will be easier for members of the std namespace to work with...
Parsing error occurred while parsing CDATA section.
Attribute & operator=(const Char8 *rhs)
The same as Attribute::SetValue(); without the error return.
unsigned int AsUint(unsigned int def=0) const
Get text as a number, or the default Value if conversion did not succeed or object is empty...
Document Type declaration, i.e. ''.
WriterStream(std::basic_ostream< char, std::char_traits< char > > &stream)
A constructor that accepts a stream of characters.
XPathVariable * NextVariable
The Next Variable in a linked structure of XPathVariables.
NodeIterator()
Default Constructor, makes a blank iterator.
bool operator<(const Attribute &r) const
Compares the internal values to check for inequality.
NodeText()
Default constructor. Constructs an empty object.
Real ToReal(const T &Datum)
Converts whatever to a Real as long as the proper streaming operators are available for it...
XPathVariable * Add(const Char8 *Name, XPathValueType Type)
Add a new variable or get the existing one, if the Types match.
const Char8 * Name() const
Get the name of this Attribute.
DeAllocationFunction MEZZ_LIB GetMemoryDeallocationFunction()
Get the current allocation funciton.
Attribute & operator*() const
Deferences this Iterator.
Unknown Type (query failed to compile)
Node GetPreviousSibling() const
Attempt to retrieve the prvious sibling of this Node.
UTF32 with native endianness.
ParseStatus
These statuses are used to help determine what issues, if any the parser had. Returned by Mezzanine::...
Document declaration, i.e. ''.
UTF16 with native endianness.
ParseResult LoadBufferInplaceOwn(void *contents, size_t size, unsigned int options=ParseDefault, Encoding DocumentEncoding=EncodingAuto)
Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for...
const unsigned int ParseEscapes
This flag determines if character and entity references are expanded during parsing. This flag is on by default.
The bulk of the engine components go in this namspace.
const unsigned int ParseDocType
This flag determines if document type declaration (NodeDoctype) is added to the DOM tree...
ParseResult()
Default constructor, initializes object to failed state.
unsigned long Whole
Whole is an unsigned integer, it will be at least 32bits in size.
bool Empty() const
Is this storing anything at all?
Parsing error occurred while parsing element attribute.
Integer AsInteger(Integer def=0) const
Get text as a number, or the default Value if conversion did not succeed or object is empty...
const unsigned int FormatRaw
Use raw output mode (no indentation and no line breaks are written). This flag is on by default...
ObjectRange< NodeIterator > GetChildren() const
Get an iterator range for this node's children nodes.
int Depth() const
How many descendants deep are we during traversal.
const unsigned int ParseCdata
This flag determines if CDATA sections (NodeCdata) are added to the DOM tree. This flag is on by defa...
There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or th...
const Char8 * AsString(const Char8 *def="") const
Get text, or the default Value if object is empty.
double AsDouble(double def=0) const
Attempts to convert the value of the attribute to a double and returns the results.
const NamedNodeIterator & operator++()
Increment the iterator to the next member of the container.
Parsing error occurred while parsing PCDATA section.
XPathVariableSet()
Default Constructor, Blanks any XPathVariable it contains.
ObjectRange< AttributeIterator > attributes() const
A range of iterators for just the attributes of this node.
const unsigned int ParseComments
This flag determines if comments (NodeComment) are added to the DOM tree. This flag is off by default...
const Char8 * GetString() const
Get text, or "" if object is empty.
bool GetBoole() const
Get this as a bool.
const Char8 * GetString() const
Get this as a c-string.
virtual ~Document()
Tears down a document, and incidentally invalidates all Node and Attribute handles to this document...
bool operator<=(const Node &r) const
Compares the internal values to check for inequality and lessthanness.
const Char8 * Name() const
ptrdiff_tGet the name of this Node.
NodeText GetText() const
Get text object for the current node.
Attribute * operator->() const
Get the pointer the Attribute this points to.
bool AsBool(bool def=false) const
Get text as bool.
Attribute PrependAttribute(const Char8 *Name)
Creates an Attribute and puts it at the begining of this Nodes attributes.
size_t HashValue() const
Get hash Value (unique for handles to the same object)
XPathVariable * Get(const Char8 *Name)
Get the named XPathVariable.
Could not allocate memory.
Attribute InsertCopyAfter(const Attribute &proto, const Attribute &attr)
Copies an Attribute and puts the copy into the list of this Nodes attributes.
bool Set(const Char8 *Name, bool Value)
Set contained variable Value; no Type conversion is performed.
Node AppendChild(NodeType Type=NodeElement)
Creates a Node and makes it a child of this one.
ParseResult LoadFile(const char *Path, unsigned int options=ParseDefault, Encoding DocumentEncoding=EncodingAuto)
Load document from file.
NodeType Type() const
Identify what kind of Node this is.
const unsigned int FormatWriteBom
Write encoding-specific Byte Order Mark (BOM) to the output stream. This flag is off by default...
Also called IEC_8859-1 a common encoding on windows, see http://en.wikipedia.org/wiki/ISO/IEC_8859-1 ...
std::string String
A datatype used to a series of characters.
Attribute AppendCopy(const Attribute &proto)
Copies an Attribute and puts the copy at the end of this Nodes attributes.
bool operator==(const NodeIterator &rhs) const
Compares this NodeIterator to another NodeIterator for equality.
const unsigned int ParseWsPcdata_single
This flag determines if plain character data (NodePcdata) that is the only child of the parent node a...
const unsigned int FormatNoEscapes
Don't escape GetAttribute Values and PCDATA contents. This flag is off by default.
Node * operator->() const
Get the pointer the Node this points to.
Attribute GetAttribute(const Char8 *Name) const
Attempt to get an Attribute on this Node with a given name.
const unsigned int ParsePi
This flag determines if processing instructions (NodePi) are added to the DOM tree. This flag is off by default.
Empty (null) node handle.
Node GetChild(const Char8 *Name) const
Attempt to get a child Node with a given name.
Integer ToInteger(const T &Datum)
Converts whatever to an Integer as long as the proper streaming operators are available for it...
Whole ToWhole(const T &Datum)
Converts whatever to a Whole as long as the proper streaming operators are available for it...
bool operator!=(const XPathNode &n) const
Called when comparing two XPathNode instances for inequality.
const XPathParseResult & Result() const
Get parsing Result (used to get compilation errors when XML_NO_EXCEPTIONS is enabled) ...
const unsigned int FormatIndent
Indent the nodes that are written to output stream with as many indentation strings as deep the node ...