19 #ifndef SOURCE_PUGIXML_CPP
20 #define SOURCE_PUGIXML_CPP
30 #ifndef PUGIXML_NO_XPATH
33 # ifdef PUGIXML_NO_EXCEPTIONS
38 #ifndef PUGIXML_NO_STL
48 # pragma warning(push)
49 # pragma warning(disable: 4127) // conditional expression is constant
50 # pragma warning(disable: 4324) // structure was padded due to __declspec(align())
51 # pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
52 # pragma warning(disable: 4702) // unreachable code
53 # pragma warning(disable: 4996) // this function or variable may be unsafe
54 # pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
57 #ifdef __INTEL_COMPILER
58 # pragma warning(disable: 177) // function was declared but never referenced
59 # pragma warning(disable: 279) // controlling expression is constant
60 # pragma warning(disable: 1478 1786) // function was declared "deprecated"
61 # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type
64 #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
65 # pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away
70 # pragma warn -8008 // condition is always false
71 # pragma warn -8066 // unreachable code
76 # pragma diag_suppress=178 // function was declared but never referenced
77 # pragma diag_suppress=237 // controlling expression is constant
81 #if defined(_MSC_VER) && _MSC_VER >= 1300
82 # define PUGI__NO_INLINE __declspec(noinline)
83 #elif defined(__GNUC__)
84 # define PUGI__NO_INLINE __attribute__((noinline))
86 # define PUGI__NO_INLINE
90 #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
94 # define PUGI__DMC_VOLATILE volatile
96 # define PUGI__DMC_VOLATILE
100 #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
106 #if defined(_MSC_VER) && !defined(__S3E__)
107 # define PUGI__MSVC_CRT_VERSION _MSC_VER
110 #ifdef PUGIXML_HEADER_ONLY
111 # define PUGI__NS_BEGIN namespace pugi { namespace impl {
112 # define PUGI__NS_END } }
113 # define PUGI__FN inline
114 # define PUGI__FN_NO_INLINE inline
116 # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
117 # define PUGI__NS_BEGIN namespace pugi { namespace impl {
118 # define PUGI__NS_END } }
120 # define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace {
121 # define PUGI__NS_END } } }
124 # define PUGI__FN_NO_INLINE PUGI__NO_INLINE
128 #if !defined(_MSC_VER) || _MSC_VER >= 1600
131 # ifndef _UINTPTR_T_DEFINED
133 typedef size_t uintptr_t;
134 #define _UINTPTR_T_DEFINED
137 typedef unsigned __int8 uint8_t;
138 typedef unsigned __int16 uint16_t;
139 typedef unsigned __int32 uint32_t;
145 PUGI__FN
void* default_allocate(
size_t size)
150 PUGI__FN
void default_deallocate(
void* ptr)
155 template <
typename T>
156 struct xml_memory_management_function_storage
158 static allocation_function allocate;
159 static deallocation_function deallocate;
162 template <
typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate;
163 template <
typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;
165 typedef xml_memory_management_function_storage<int> xml_memory;
171 PUGI__FN
size_t strlength(
const char_t* s)
175 #ifdef PUGIXML_WCHAR_MODE
183 PUGI__FN
bool strequal(
const char_t* src,
const char_t* dst)
187 #ifdef PUGIXML_WCHAR_MODE
188 return wcscmp(src, dst) == 0;
190 return strcmp(src, dst) == 0;
195 PUGI__FN
bool strequalrange(
const char_t* lhs,
const char_t* rhs,
size_t count)
197 for (
size_t i = 0; i < count; ++i)
198 if (lhs[i] != rhs[i])
201 return lhs[count] == 0;
204 #ifdef PUGIXML_WCHAR_MODE
206 PUGI__FN
void widen_ascii(
wchar_t* dest,
const char* source)
208 for (
const char* i = source; *i; ++i) *dest++ = *i;
214 #if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH)
220 void (*deleter)(
void*);
222 buffer_holder(
void* data_,
void (*deleter_)(
void*)): data(data_), deleter(deleter_)
228 if (data) deleter(data);
242 static const size_t xml_memory_page_size =
243 #ifdef PUGIXML_MEMORY_PAGE_SIZE
244 PUGIXML_MEMORY_PAGE_SIZE
250 static const uintptr_t xml_memory_page_alignment = 32;
251 static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1);
252 static const uintptr_t xml_memory_page_name_allocated_mask = 16;
253 static const uintptr_t xml_memory_page_value_allocated_mask = 8;
254 static const uintptr_t xml_memory_page_type_mask = 7;
256 struct xml_allocator;
258 struct xml_memory_page
260 static xml_memory_page* construct(
void* memory)
262 if (!memory)
return 0;
264 xml_memory_page* result =
static_cast<xml_memory_page*
>(memory);
266 result->allocator = 0;
270 result->busy_size = 0;
271 result->freed_size = 0;
276 xml_allocator* allocator;
280 xml_memory_page* prev;
281 xml_memory_page* next;
289 struct xml_memory_string_header
291 uint16_t page_offset;
297 xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
301 xml_memory_page* allocate_page(
size_t data_size)
303 size_t size = offsetof(xml_memory_page, data) + data_size;
306 void* memory = xml_memory::allocate(size + xml_memory_page_alignment);
307 if (!memory)
return 0;
310 void* page_memory =
reinterpret_cast<void*
>((
reinterpret_cast<uintptr_t
>(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1));
313 xml_memory_page* page = xml_memory_page::construct(page_memory);
315 page->memory = memory;
316 page->allocator = _root->allocator;
321 static void deallocate_page(xml_memory_page* page)
323 xml_memory::deallocate(page->memory);
326 void* allocate_memory_oob(
size_t size, xml_memory_page*& out_page);
328 void* allocate_memory(
size_t size, xml_memory_page*& out_page)
330 if (_busy_size + size > xml_memory_page_size)
return allocate_memory_oob(size, out_page);
332 void* buf = _root->data + _busy_size;
341 void deallocate_memory(
void* ptr,
size_t size, xml_memory_page* page)
343 if (page == _root) page->busy_size = _busy_size;
345 assert(ptr >= page->data && ptr < page->data + page->busy_size);
348 page->freed_size += size;
349 assert(page->freed_size <= page->busy_size);
351 if (page->freed_size == page->busy_size)
355 assert(_root == page);
358 page->busy_size = page->freed_size = 0;
363 assert(_root != page);
367 page->prev->next = page->next;
368 page->next->prev = page->prev;
371 deallocate_page(page);
376 char_t* allocate_string(
size_t length)
379 size_t size =
sizeof(xml_memory_string_header) + length *
sizeof(char_t);
382 size_t full_size = (size + (
sizeof(
void*) - 1)) & ~(
sizeof(
void*) - 1);
384 xml_memory_page* page;
385 xml_memory_string_header* header =
static_cast<xml_memory_string_header*
>(allocate_memory(full_size, page));
387 if (!header)
return 0;
390 ptrdiff_t page_offset =
reinterpret_cast<char*
>(header) - page->data;
392 assert(page_offset >= 0 && page_offset < (1 << 16));
393 header->page_offset =
static_cast<uint16_t
>(page_offset);
396 assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0));
397 header->full_size =
static_cast<uint16_t
>(full_size < (1 << 16) ? full_size : 0);
401 return static_cast<char_t*
>(
static_cast<void*
>(header + 1));
404 void deallocate_string(char_t*
string)
410 xml_memory_string_header* header =
static_cast<xml_memory_string_header*
>(
static_cast<void*
>(string)) - 1;
413 size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset;
414 xml_memory_page* page =
reinterpret_cast<xml_memory_page*
>(
static_cast<void*
>(
reinterpret_cast<char*
>(header) - page_offset));
417 size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size;
419 deallocate_memory(header, full_size, page);
422 xml_memory_page* _root;
426 PUGI__FN_NO_INLINE
void* xml_allocator::allocate_memory_oob(
size_t size, xml_memory_page*& out_page)
428 const size_t large_allocation_threshold = xml_memory_page_size / 4;
430 xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
435 if (size <= large_allocation_threshold)
437 _root->busy_size = _busy_size;
452 page->prev = _root->prev;
455 _root->prev->next = page;
460 page->busy_size = size;
469 struct xml_attribute_struct
472 xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0)
481 xml_attribute_struct* prev_attribute_c;
482 xml_attribute_struct* next_attribute;
486 struct xml_node_struct
490 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast<uintptr_t>(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
496 xml_node_struct* parent;
501 xml_node_struct* first_child;
503 xml_node_struct* prev_sibling_c;
504 xml_node_struct* next_sibling;
506 xml_attribute_struct* first_attribute;
511 struct xml_document_struct:
public xml_node_struct,
public xml_allocator
513 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0)
517 const char_t* buffer;
520 inline xml_allocator& get_allocator(
const xml_node_struct* node)
524 return *
reinterpret_cast<xml_memory_page*
>(node->header & xml_memory_page_pointer_mask)->allocator;
530 inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
532 xml_memory_page* page;
533 void* memory = alloc.allocate_memory(
sizeof(xml_attribute_struct), page);
535 return new (memory) xml_attribute_struct(page);
538 inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type)
540 xml_memory_page* page;
541 void* memory = alloc.allocate_memory(
sizeof(xml_node_struct), page);
543 return new (memory) xml_node_struct(page, type);
546 inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
548 uintptr_t header = a->header;
550 if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name);
551 if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value);
553 alloc.deallocate_memory(a,
sizeof(xml_attribute_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
556 inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
558 uintptr_t header = n->header;
560 if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name);
561 if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value);
563 for (xml_attribute_struct* attr = n->first_attribute; attr; )
565 xml_attribute_struct* next = attr->next_attribute;
567 destroy_attribute(attr, alloc);
572 for (xml_node_struct* child = n->first_child; child; )
574 xml_node_struct* next = child->next_sibling;
576 destroy_node(child, alloc);
581 alloc.deallocate_memory(n,
sizeof(xml_node_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
584 PUGI__FN_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
586 xml_node_struct* child = allocate_node(alloc, type);
587 if (!child)
return 0;
589 child->parent = node;
591 xml_node_struct* first_child = node->first_child;
595 xml_node_struct* last_child = first_child->prev_sibling_c;
597 last_child->next_sibling = child;
598 child->prev_sibling_c = last_child;
599 first_child->prev_sibling_c = child;
603 node->first_child = child;
604 child->prev_sibling_c = child;
610 PUGI__FN_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc)
612 xml_attribute_struct* a = allocate_attribute(alloc);
615 xml_attribute_struct* first_attribute = node->first_attribute;
619 xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c;
621 last_attribute->next_attribute = a;
622 a->prev_attribute_c = last_attribute;
623 first_attribute->prev_attribute_c = a;
627 node->first_attribute = a;
628 a->prev_attribute_c = a;
650 inline uint16_t endian_swap(uint16_t value)
652 return static_cast<uint16_t
>(((value & 0xff) << 8) | (value >> 8));
655 inline uint32_t endian_swap(uint32_t value)
657 return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
662 typedef size_t value_type;
664 static value_type low(value_type result, uint32_t ch)
667 if (ch < 0x80)
return result + 1;
669 else if (ch < 0x800)
return result + 2;
671 else return result + 3;
674 static value_type high(value_type result, uint32_t)
683 typedef uint8_t* value_type;
685 static value_type low(value_type result, uint32_t ch)
690 *result =
static_cast<uint8_t
>(ch);
696 result[0] =
static_cast<uint8_t
>(0xC0 | (ch >> 6));
697 result[1] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
703 result[0] =
static_cast<uint8_t
>(0xE0 | (ch >> 12));
704 result[1] =
static_cast<uint8_t
>(0x80 | ((ch >> 6) & 0x3F));
705 result[2] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
710 static value_type high(value_type result, uint32_t ch)
713 result[0] =
static_cast<uint8_t
>(0xF0 | (ch >> 18));
714 result[1] =
static_cast<uint8_t
>(0x80 | ((ch >> 12) & 0x3F));
715 result[2] =
static_cast<uint8_t
>(0x80 | ((ch >> 6) & 0x3F));
716 result[3] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
720 static value_type any(value_type result, uint32_t ch)
722 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
728 typedef size_t value_type;
730 static value_type low(value_type result, uint32_t)
735 static value_type high(value_type result, uint32_t)
743 typedef uint16_t* value_type;
745 static value_type low(value_type result, uint32_t ch)
747 *result =
static_cast<uint16_t
>(ch);
752 static value_type high(value_type result, uint32_t ch)
754 uint32_t msh =
static_cast<uint32_t
>(ch - 0x10000) >> 10;
755 uint32_t lsh =
static_cast<uint32_t
>(ch - 0x10000) & 0x3ff;
757 result[0] =
static_cast<uint16_t
>(0xD800 + msh);
758 result[1] =
static_cast<uint16_t
>(0xDC00 + lsh);
763 static value_type any(value_type result, uint32_t ch)
765 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
771 typedef size_t value_type;
773 static value_type low(value_type result, uint32_t)
778 static value_type high(value_type result, uint32_t)
786 typedef uint32_t* value_type;
788 static value_type low(value_type result, uint32_t ch)
795 static value_type high(value_type result, uint32_t ch)
802 static value_type any(value_type result, uint32_t ch)
812 typedef uint8_t* value_type;
814 static value_type low(value_type result, uint32_t ch)
816 *result =
static_cast<uint8_t
>(ch > 255 ?
'?' : ch);
821 static value_type high(value_type result, uint32_t ch)
831 template <
size_t size>
struct wchar_selector;
833 template <>
struct wchar_selector<2>
835 typedef uint16_t type;
836 typedef utf16_counter counter;
837 typedef utf16_writer writer;
840 template <>
struct wchar_selector<4>
842 typedef uint32_t type;
843 typedef utf32_counter counter;
844 typedef utf32_writer writer;
847 typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
848 typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
850 template <
typename Traits,
typename opt_swap = opt_false>
struct utf_decoder
852 static inline typename Traits::value_type decode_utf8_block(
const uint8_t* data,
size_t size,
typename Traits::value_type result)
854 const uint8_t utf8_byte_mask = 0x3f;
858 uint8_t lead = *data;
863 result = Traits::low(result, lead);
868 if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
871 while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)
873 result = Traits::low(result, data[0]);
874 result = Traits::low(result, data[1]);
875 result = Traits::low(result, data[2]);
876 result = Traits::low(result, data[3]);
883 else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
885 result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
890 else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
892 result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
897 else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
899 result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
914 static inline typename Traits::value_type decode_utf16_block(
const uint16_t* data,
size_t size,
typename Traits::value_type result)
916 const uint16_t* end = data + size;
920 uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
925 result = Traits::low(result, lead);
929 else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
931 result = Traits::low(result, lead);
935 else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && data + 1 < end)
937 uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
939 if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
941 result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
958 static inline typename Traits::value_type decode_utf32_block(
const uint32_t* data,
size_t size,
typename Traits::value_type result)
960 const uint32_t* end = data + size;
964 uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
969 result = Traits::low(result, lead);
975 result = Traits::high(result, lead);
983 static inline typename Traits::value_type decode_latin1_block(
const uint8_t* data,
size_t size,
typename Traits::value_type result)
985 for (
size_t i = 0; i < size; ++i)
987 result = Traits::low(result, data[i]);
993 static inline typename Traits::value_type decode_wchar_block_impl(
const uint16_t* data,
size_t size,
typename Traits::value_type result)
995 return decode_utf16_block(data, size, result);
998 static inline typename Traits::value_type decode_wchar_block_impl(
const uint32_t* data,
size_t size,
typename Traits::value_type result)
1000 return decode_utf32_block(data, size, result);
1003 static inline typename Traits::value_type decode_wchar_block(
const wchar_t* data,
size_t size,
typename Traits::value_type result)
1005 return decode_wchar_block_impl(
reinterpret_cast<const wchar_selector<sizeof(wchar_t)>::type*
>(data), size, result);
1009 template <
typename T> PUGI__FN
void convert_utf_endian_swap(T* result,
const T* data,
size_t length)
1011 for (
size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]);
1014 #ifdef PUGIXML_WCHAR_MODE
1015 PUGI__FN
void convert_wchar_endian_swap(
wchar_t* result,
const wchar_t* data,
size_t length)
1017 for (
size_t i = 0; i < length; ++i) result[i] = static_cast<wchar_t>(endian_swap(
static_cast<wchar_selector<sizeof(wchar_t)>::type
>(data[i])));
1025 ct_parse_pcdata = 1,
1027 ct_parse_attr_ws = 4,
1029 ct_parse_cdata = 16,
1030 ct_parse_comment = 32,
1032 ct_start_symbol = 128
1035 static const unsigned char chartype_table[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 #ifdef PUGIXML_WCHAR_MODE
1088 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
1090 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
1093 #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
1094 #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
1096 PUGI__FN
bool is_little_endian()
1098 unsigned int ui = 1;
1100 return *
reinterpret_cast<unsigned char*
>(&ui) == 1;
1103 PUGI__FN xml_encoding get_wchar_encoding()
1105 PUGI__STATIC_ASSERT(
sizeof(
wchar_t) == 2 ||
sizeof(
wchar_t) == 4);
1107 if (
sizeof(
wchar_t) == 2)
1108 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1110 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1113 PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
1116 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff)
return encoding_utf32_be;
1117 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0)
return encoding_utf32_le;
1118 if (d0 == 0xfe && d1 == 0xff)
return encoding_utf16_be;
1119 if (d0 == 0xff && d1 == 0xfe)
return encoding_utf16_le;
1120 if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf)
return encoding_utf8;
1123 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c)
return encoding_utf32_be;
1124 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0)
return encoding_utf32_le;
1125 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f)
return encoding_utf16_be;
1126 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0)
return encoding_utf16_le;
1127 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d)
return encoding_utf8;
1130 if (d0 == 0 && d1 == 0x3c)
return encoding_utf16_be;
1131 if (d0 == 0x3c && d1 == 0)
return encoding_utf16_le;
1134 return encoding_utf8;
1137 PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding,
const void* contents,
size_t size)
1140 if (encoding == encoding_wchar)
return get_wchar_encoding();
1143 if (encoding == encoding_utf16)
return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1146 if (encoding == encoding_utf32)
return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1149 if (encoding != encoding_auto)
return encoding;
1152 if (size < 4)
return encoding_utf8;
1155 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
1157 PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1159 return guess_buffer_encoding(d0, d1, d2, d3);
1162 PUGI__FN
bool get_mutable_buffer(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size,
bool is_mutable)
1166 out_buffer =
static_cast<char_t*
>(
const_cast<void*
>(contents));
1170 void* buffer = xml_memory::allocate(size > 0 ? size : 1);
1171 if (!buffer)
return false;
1173 memcpy(buffer, contents, size);
1175 out_buffer =
static_cast<char_t*
>(buffer);
1178 out_length = size /
sizeof(char_t);
1183 #ifdef PUGIXML_WCHAR_MODE
1184 PUGI__FN
bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
1186 return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
1187 (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
1190 PUGI__FN
bool convert_buffer_endian_swap(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size,
bool is_mutable)
1192 const char_t* data =
static_cast<const char_t*
>(contents);
1196 out_buffer =
const_cast<char_t*
>(data);
1200 out_buffer =
static_cast<char_t*
>(xml_memory::allocate(size > 0 ? size : 1));
1201 if (!out_buffer)
return false;
1204 out_length = size /
sizeof(char_t);
1206 convert_wchar_endian_swap(out_buffer, data, out_length);
1211 PUGI__FN
bool convert_buffer_utf8(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size)
1213 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
1216 out_length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
1219 out_buffer =
static_cast<char_t*
>(xml_memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(char_t)));
1220 if (!out_buffer)
return false;
1223 wchar_writer::value_type out_begin =
reinterpret_cast<wchar_writer::value_type
>(out_buffer);
1224 wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, out_begin);
1226 assert(out_end == out_begin + out_length);
1232 template <
typename opt_swap> PUGI__FN
bool convert_buffer_utf16(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size, opt_swap)
1234 const uint16_t* data =
static_cast<const uint16_t*
>(contents);
1235 size_t length = size /
sizeof(uint16_t);
1238 out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf16_block(data, length, 0);
1241 out_buffer =
static_cast<char_t*
>(xml_memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(char_t)));
1242 if (!out_buffer)
return false;
1245 wchar_writer::value_type out_begin =
reinterpret_cast<wchar_writer::value_type
>(out_buffer);
1246 wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, length, out_begin);
1248 assert(out_end == out_begin + out_length);
1254 template <
typename opt_swap> PUGI__FN
bool convert_buffer_utf32(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size, opt_swap)
1256 const uint32_t* data =
static_cast<const uint32_t*
>(contents);
1257 size_t length = size /
sizeof(uint32_t);
1260 out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf32_block(data, length, 0);
1263 out_buffer =
static_cast<char_t*
>(xml_memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(char_t)));
1264 if (!out_buffer)
return false;
1267 wchar_writer::value_type out_begin =
reinterpret_cast<wchar_writer::value_type
>(out_buffer);
1268 wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, length, out_begin);
1270 assert(out_end == out_begin + out_length);
1276 PUGI__FN
bool convert_buffer_latin1(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size)
1278 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
1284 out_buffer =
static_cast<char_t*
>(xml_memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(char_t)));
1285 if (!out_buffer)
return false;
1288 wchar_writer::value_type out_begin =
reinterpret_cast<wchar_writer::value_type
>(out_buffer);
1289 wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_latin1_block(data, size, out_begin);
1291 assert(out_end == out_begin + out_length);
1297 PUGI__FN
bool convert_buffer(char_t*& out_buffer,
size_t& out_length, xml_encoding encoding,
const void* contents,
size_t size,
bool is_mutable)
1300 xml_encoding wchar_encoding = get_wchar_encoding();
1303 if (encoding == wchar_encoding)
return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1306 if (need_endian_swap_utf(encoding, wchar_encoding))
return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
1309 if (encoding == encoding_utf8)
return convert_buffer_utf8(out_buffer, out_length, contents, size);
1312 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
1314 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1316 return (native_encoding == encoding) ?
1317 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
1318 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1322 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
1324 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1326 return (native_encoding == encoding) ?
1327 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
1328 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1332 if (encoding == encoding_latin1)
return convert_buffer_latin1(out_buffer, out_length, contents, size);
1334 assert(!
"Invalid encoding");
1338 template <
typename opt_swap> PUGI__FN
bool convert_buffer_utf16(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size, opt_swap)
1340 const uint16_t* data =
static_cast<const uint16_t*
>(contents);
1341 size_t length = size /
sizeof(uint16_t);
1344 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, length, 0);
1347 out_buffer =
static_cast<char_t*
>(xml_memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(char_t)));
1348 if (!out_buffer)
return false;
1351 uint8_t* out_begin =
reinterpret_cast<uint8_t*
>(out_buffer);
1352 uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, length, out_begin);
1354 assert(out_end == out_begin + out_length);
1360 template <
typename opt_swap> PUGI__FN
bool convert_buffer_utf32(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size, opt_swap)
1362 const uint32_t* data =
static_cast<const uint32_t*
>(contents);
1363 size_t length = size /
sizeof(uint32_t);
1366 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, length, 0);
1369 out_buffer =
static_cast<char_t*
>(xml_memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(char_t)));
1370 if (!out_buffer)
return false;
1373 uint8_t* out_begin =
reinterpret_cast<uint8_t*
>(out_buffer);
1374 uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, length, out_begin);
1376 assert(out_end == out_begin + out_length);
1382 PUGI__FN
size_t get_latin1_7bit_prefix_length(
const uint8_t* data,
size_t size)
1384 for (
size_t i = 0; i < size; ++i)
1391 PUGI__FN
bool convert_buffer_latin1(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size,
bool is_mutable)
1393 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
1396 size_t prefix_length = get_latin1_7bit_prefix_length(data, size);
1397 assert(prefix_length <= size);
1399 const uint8_t* postfix = data + prefix_length;
1400 size_t postfix_length = size - prefix_length;
1403 if (postfix_length == 0)
return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1406 out_length = prefix_length + utf_decoder<utf8_counter>::decode_latin1_block(postfix, postfix_length, 0);
1409 out_buffer =
static_cast<char_t*
>(xml_memory::allocate((out_length > 0 ? out_length : 1) *
sizeof(char_t)));
1410 if (!out_buffer)
return false;
1413 memcpy(out_buffer, data, prefix_length);
1415 uint8_t* out_begin =
reinterpret_cast<uint8_t*
>(out_buffer);
1416 uint8_t* out_end = utf_decoder<utf8_writer>::decode_latin1_block(postfix, postfix_length, out_begin + prefix_length);
1418 assert(out_end == out_begin + out_length);
1424 PUGI__FN
bool convert_buffer(char_t*& out_buffer,
size_t& out_length, xml_encoding encoding,
const void* contents,
size_t size,
bool is_mutable)
1427 if (encoding == encoding_utf8)
return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
1430 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
1432 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1434 return (native_encoding == encoding) ?
1435 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
1436 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
1440 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
1442 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1444 return (native_encoding == encoding) ?
1445 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
1446 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
1450 if (encoding == encoding_latin1)
return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
1452 assert(!
"Invalid encoding");
1457 PUGI__FN
size_t as_utf8_begin(
const wchar_t* str,
size_t length)
1460 return utf_decoder<utf8_counter>::decode_wchar_block(str, length, 0);
1463 PUGI__FN
void as_utf8_end(
char* buffer,
size_t size,
const wchar_t* str,
size_t length)
1466 uint8_t* begin =
reinterpret_cast<uint8_t*
>(buffer);
1467 uint8_t* end = utf_decoder<utf8_writer>::decode_wchar_block(str, length, begin);
1469 assert(begin + size == end);
1476 #ifndef PUGIXML_NO_STL
1477 PUGI__FN std::string as_utf8_impl(
const wchar_t* str,
size_t length)
1480 size_t size = as_utf8_begin(str, length);
1484 result.resize(size);
1487 if (size > 0) as_utf8_end(&result[0], size, str, length);
1492 PUGI__FN std::basic_string<wchar_t> as_wide_impl(
const char* str,
size_t size)
1494 const uint8_t* data =
reinterpret_cast<const uint8_t*
>(str);
1497 size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
1500 std::basic_string<wchar_t> result;
1501 result.resize(length);
1506 wchar_writer::value_type begin =
reinterpret_cast<wchar_writer::value_type
>(&result[0]);
1507 wchar_writer::value_type end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, begin);
1509 assert(begin + length == end);
1517 inline bool strcpy_insitu_allow(
size_t length, uintptr_t allocated, char_t* target)
1520 size_t target_length = strlength(target);
1523 if (!allocated)
return target_length >= length;
1526 const size_t reuse_threshold = 32;
1528 return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
1531 PUGI__FN
bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask,
const char_t* source)
1533 size_t source_length = strlength(source);
1535 if (source_length == 0)
1538 xml_allocator* alloc =
reinterpret_cast<xml_memory_page*
>(header & xml_memory_page_pointer_mask)->allocator;
1540 if (header & header_mask) alloc->deallocate_string(dest);
1544 header &= ~header_mask;
1548 else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest))
1551 memcpy(dest, source, (source_length + 1) *
sizeof(char_t));
1557 xml_allocator* alloc =
reinterpret_cast<xml_memory_page*
>(header & xml_memory_page_pointer_mask)->allocator;
1560 char_t* buf = alloc->allocate_string(source_length + 1);
1561 if (!buf)
return false;
1564 memcpy(buf, source, (source_length + 1) *
sizeof(char_t));
1567 if (header & header_mask) alloc->deallocate_string(dest);
1571 header |= header_mask;
1582 gap(): end(0), size(0)
1588 void push(char_t*& s,
size_t count)
1594 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
1605 char_t* flush(char_t* s)
1611 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
1619 PUGI__FN char_t* strconv_escape(char_t* s, gap& g)
1621 char_t* stre = s + 1;
1627 unsigned int ucsc = 0;
1635 if (ch ==
';')
return stre;
1639 if (static_cast<unsigned int>(ch -
'0') <= 9)
1640 ucsc = 16 * ucsc + (ch -
'0');
1641 else if (static_cast<unsigned int>((ch |
' ') -
'a') <= 5)
1642 ucsc = 16 * ucsc + ((ch |
' ') -
'a' + 10);
1655 char_t ch = *++stre;
1657 if (ch ==
';')
return stre;
1661 if (static_cast<unsigned int>(ch -
'0') <= 9)
1662 ucsc = 10 * ucsc + (ch -
'0');
1674 #ifdef PUGIXML_WCHAR_MODE
1675 s =
reinterpret_cast<char_t*
>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
1677 s =
reinterpret_cast<char_t*
>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));
1680 g.push(s, stre - s);
1690 if (*++stre ==
'p' && *++stre ==
';')
1695 g.push(s, stre - s);
1699 else if (*stre ==
'p')
1701 if (*++stre ==
'o' && *++stre ==
's' && *++stre ==
';')
1706 g.push(s, stre - s);
1715 if (*++stre ==
't' && *++stre ==
';')
1720 g.push(s, stre - s);
1728 if (*++stre ==
't' && *++stre ==
';')
1733 g.push(s, stre - s);
1741 if (*++stre ==
'u' && *++stre ==
'o' && *++stre ==
't' && *++stre ==
';')
1746 g.push(s, stre - s);
1760 #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
1762 PUGI__FN char_t* strconv_comment(char_t* s, char_t endch)
1768 while (!PUGI__IS_CHARTYPE(*s, ct_parse_comment)) ++s;
1774 if (*s ==
'\n') g.push(s, 1);
1776 else if (s[0] ==
'-' && s[1] ==
'-' && ENDSWITH(s[2],
'>'))
1780 return s + (s[2] ==
'>' ? 3 : 2);
1790 PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch)
1796 while (!PUGI__IS_CHARTYPE(*s, ct_parse_cdata)) ++s;
1802 if (*s ==
'\n') g.push(s, 1);
1804 else if (s[0] ==
']' && s[1] ==
']' && ENDSWITH(s[2],
'>'))
1818 typedef char_t* (*strconv_pcdata_t)(char_t*);
1820 template <
typename opt_eol,
typename opt_escape>
struct strconv_pcdata_impl
1822 static char_t* parse(char_t* s)
1828 while (!PUGI__IS_CHARTYPE(*s, ct_parse_pcdata)) ++s;
1836 else if (opt_eol::value && *s ==
'\r')
1840 if (*s ==
'\n') g.push(s, 1);
1842 else if (opt_escape::value && *s ==
'&')
1844 s = strconv_escape(s, g);
1855 PUGI__FN strconv_pcdata_t get_strconv_pcdata(
unsigned int optmask)
1857 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20);
1859 switch ((optmask >> 4) & 3)
1861 case 0:
return strconv_pcdata_impl<opt_false, opt_false>::parse;
1862 case 1:
return strconv_pcdata_impl<opt_false, opt_true>::parse;
1863 case 2:
return strconv_pcdata_impl<opt_true, opt_false>::parse;
1864 case 3:
return strconv_pcdata_impl<opt_true, opt_true>::parse;
1869 typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
1871 template <
typename opt_escape>
struct strconv_attribute_impl
1873 static char_t* parse_wnorm(char_t* s, char_t end_quote)
1878 if (PUGI__IS_CHARTYPE(*s, ct_space))
1883 while (PUGI__IS_CHARTYPE(*str, ct_space));
1890 while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s;
1892 if (*s == end_quote)
1894 char_t* str = g.flush(s);
1897 while (PUGI__IS_CHARTYPE(*str, ct_space));
1901 else if (PUGI__IS_CHARTYPE(*s, ct_space))
1905 if (PUGI__IS_CHARTYPE(*s, ct_space))
1907 char_t* str = s + 1;
1908 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
1913 else if (opt_escape::value && *s ==
'&')
1915 s = strconv_escape(s, g);
1925 static char_t* parse_wconv(char_t* s, char_t end_quote)
1931 while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s;
1933 if (*s == end_quote)
1939 else if (PUGI__IS_CHARTYPE(*s, ct_space))
1945 if (*s ==
'\n') g.push(s, 1);
1949 else if (opt_escape::value && *s ==
'&')
1951 s = strconv_escape(s, g);
1961 static char_t* parse_eol(char_t* s, char_t end_quote)
1967 while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s;
1969 if (*s == end_quote)
1975 else if (*s ==
'\r')
1979 if (*s ==
'\n') g.push(s, 1);
1981 else if (opt_escape::value && *s ==
'&')
1983 s = strconv_escape(s, g);
1993 static char_t* parse_simple(char_t* s, char_t end_quote)
1999 while (!PUGI__IS_CHARTYPE(*s, ct_parse_attr)) ++s;
2001 if (*s == end_quote)
2007 else if (opt_escape::value && *s ==
'&')
2009 s = strconv_escape(s, g);
2020 PUGI__FN strconv_attribute_t get_strconv_attribute(
unsigned int optmask)
2022 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
2024 switch ((optmask >> 4) & 15)
2026 case 0:
return strconv_attribute_impl<opt_false>::parse_simple;
2027 case 1:
return strconv_attribute_impl<opt_true>::parse_simple;
2028 case 2:
return strconv_attribute_impl<opt_false>::parse_eol;
2029 case 3:
return strconv_attribute_impl<opt_true>::parse_eol;
2030 case 4:
return strconv_attribute_impl<opt_false>::parse_wconv;
2031 case 5:
return strconv_attribute_impl<opt_true>::parse_wconv;
2032 case 6:
return strconv_attribute_impl<opt_false>::parse_wconv;
2033 case 7:
return strconv_attribute_impl<opt_true>::parse_wconv;
2034 case 8:
return strconv_attribute_impl<opt_false>::parse_wnorm;
2035 case 9:
return strconv_attribute_impl<opt_true>::parse_wnorm;
2036 case 10:
return strconv_attribute_impl<opt_false>::parse_wnorm;
2037 case 11:
return strconv_attribute_impl<opt_true>::parse_wnorm;
2038 case 12:
return strconv_attribute_impl<opt_false>::parse_wnorm;
2039 case 13:
return strconv_attribute_impl<opt_true>::parse_wnorm;
2040 case 14:
return strconv_attribute_impl<opt_false>::parse_wnorm;
2041 case 15:
return strconv_attribute_impl<opt_true>::parse_wnorm;
2046 inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
2048 xml_parse_result result;
2049 result.status = status;
2050 result.offset = offset;
2057 xml_allocator alloc;
2058 char_t* error_offset;
2059 xml_parse_status error_status;
2062 #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
2063 #define PUGI__OPTSET(OPT) ( optmsk & (OPT) )
2064 #define PUGI__PUSHNODE(TYPE) { cursor = append_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
2065 #define PUGI__POPNODE() { cursor = cursor->parent; }
2066 #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
2067 #define PUGI__SCANWHILE(X) { while ((X)) ++s; }
2068 #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; }
2069 #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t*>(0)
2070 #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); }
2072 xml_parser(
const xml_allocator& alloc_): alloc(alloc_), error_offset(0), error_status(status_ok)
2083 char_t* parse_doctype_primitive(char_t* s)
2085 if (*s ==
'"' || *s ==
'\'')
2089 PUGI__SCANFOR(*s == ch);
2090 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2094 else if (s[0] ==
'<' && s[1] ==
'?')
2098 PUGI__SCANFOR(s[0] ==
'?' && s[1] ==
'>');
2099 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2103 else if (s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'-' && s[3] ==
'-')
2106 PUGI__SCANFOR(s[0] ==
'-' && s[1] ==
'-' && s[2] ==
'>');
2107 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2111 else PUGI__THROW_ERROR(status_bad_doctype, s);
2116 char_t* parse_doctype_ignore(char_t* s)
2118 assert(s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'[');
2123 if (s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'[')
2126 s = parse_doctype_ignore(s);
2129 else if (s[0] ==
']' && s[1] ==
']' && s[2] ==
'>')
2139 PUGI__THROW_ERROR(status_bad_doctype, s);
2142 char_t* parse_doctype_group(char_t* s, char_t endch,
bool toplevel)
2144 assert(s[0] ==
'<' && s[1] ==
'!');
2149 if (s[0] ==
'<' && s[1] ==
'!' && s[2] !=
'-')
2154 s = parse_doctype_ignore(s);
2160 s = parse_doctype_group(s, endch,
false);
2164 else if (s[0] ==
'<' || s[0] ==
'"' || s[0] ==
'\'')
2167 s = parse_doctype_primitive(s);
2179 if (!toplevel || endch !=
'>') PUGI__THROW_ERROR(status_bad_doctype, s);
2184 char_t* parse_exclamation(char_t* s, xml_node_struct* cursor,
unsigned int optmsk, char_t endch)
2197 if (PUGI__OPTSET(parse_comments))
2199 PUGI__PUSHNODE(node_comment);
2203 if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments))
2205 s = strconv_comment(s, endch);
2207 if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
2212 PUGI__SCANFOR(s[0] ==
'-' && s[1] ==
'-' && ENDSWITH(s[2],
'>'));
2213 PUGI__CHECK_ERROR(status_bad_comment, s);
2215 if (PUGI__OPTSET(parse_comments))
2218 s += (s[2] ==
'>' ? 3 : 2);
2221 else PUGI__THROW_ERROR(status_bad_comment, s);
2226 if (*++s==
'C' && *++s==
'D' && *++s==
'A' && *++s==
'T' && *++s==
'A' && *++s ==
'[')
2230 if (PUGI__OPTSET(parse_cdata))
2232 PUGI__PUSHNODE(node_cdata);
2235 if (PUGI__OPTSET(parse_eol))
2237 s = strconv_cdata(s, endch);
2239 if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
2244 PUGI__SCANFOR(s[0] ==
']' && s[1] ==
']' && ENDSWITH(s[2],
'>'));
2245 PUGI__CHECK_ERROR(status_bad_cdata, s);
2253 PUGI__SCANFOR(s[0] ==
']' && s[1] ==
']' && ENDSWITH(s[2],
'>'));
2254 PUGI__CHECK_ERROR(status_bad_cdata, s);
2259 s += (s[1] ==
'>' ? 2 : 1);
2261 else PUGI__THROW_ERROR(status_bad_cdata, s);
2263 else if (s[0] ==
'D' && s[1] ==
'O' && s[2] ==
'C' && s[3] ==
'T' && s[4] ==
'Y' && s[5] ==
'P' && ENDSWITH(s[6],
'E'))
2267 if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
2269 char_t* mark = s + 9;
2271 s = parse_doctype_group(s, endch,
true);
2274 if (PUGI__OPTSET(parse_doctype))
2276 while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
2278 PUGI__PUSHNODE(node_doctype);
2280 cursor->value = mark;
2282 assert((s[0] == 0 && endch ==
'>') || s[-1] ==
'>');
2283 s[*s == 0 ? 0 : -1] = 0;
2288 else if (*s == 0 && endch ==
'-') PUGI__THROW_ERROR(status_bad_comment, s);
2289 else if (*s == 0 && endch ==
'[') PUGI__THROW_ERROR(status_bad_cdata, s);
2290 else PUGI__THROW_ERROR(status_unrecognized_tag, s);
2295 char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor,
unsigned int optmsk, char_t endch)
2298 xml_node_struct* cursor = ref_cursor;
2307 if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s);
2309 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
2310 PUGI__CHECK_ERROR(status_bad_pi, s);
2313 bool declaration = (target[0] |
' ') ==
'x' && (target[1] |
' ') ==
'm' && (target[2] |
' ') ==
'l' && target + 3 == s;
2315 if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
2320 if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
2322 PUGI__PUSHNODE(node_declaration);
2326 PUGI__PUSHNODE(node_pi);
2329 cursor->name = target;
2337 if (!ENDSWITH(*s,
'>')) PUGI__THROW_ERROR(status_bad_pi, s);
2342 else if (PUGI__IS_CHARTYPE(ch, ct_space))
2349 PUGI__SCANFOR(s[0] ==
'?' && ENDSWITH(s[1],
'>'));
2350 PUGI__CHECK_ERROR(status_bad_pi, s);
2363 cursor->value = value;
2371 else PUGI__THROW_ERROR(status_bad_pi, s);
2376 PUGI__SCANFOR(s[0] ==
'?' && ENDSWITH(s[1],
'>'));
2377 PUGI__CHECK_ERROR(status_bad_pi, s);
2379 s += (s[1] ==
'>' ? 2 : 1);
2383 ref_cursor = cursor;
2388 char_t* parse(char_t* s, xml_node_struct* xmldoc,
unsigned int optmsk, char_t endch)
2390 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
2391 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
2394 xml_node_struct* cursor = xmldoc;
2404 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
2406 PUGI__PUSHNODE(node_element);
2410 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
2417 else if (PUGI__IS_CHARTYPE(ch, ct_space))
2424 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
2426 xml_attribute_struct* a = append_attribute_ll(cursor, alloc);
2427 if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
2431 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
2432 PUGI__CHECK_ERROR(status_bad_attribute, s);
2435 PUGI__CHECK_ERROR(status_bad_attribute, s);
2437 if (PUGI__IS_CHARTYPE(ch, ct_space))
2440 PUGI__CHECK_ERROR(status_bad_attribute, s);
2450 if (*s ==
'"' || *s ==
'\'')
2456 s = strconv_attribute(s, ch);
2458 if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
2463 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s);
2465 else PUGI__THROW_ERROR(status_bad_attribute, s);
2467 else PUGI__THROW_ERROR(status_bad_attribute, s);
2479 else if (*s == 0 && endch ==
'>')
2484 else PUGI__THROW_ERROR(status_bad_start_element, s);
2492 else if (*s == 0 && endch ==
'>')
2496 else PUGI__THROW_ERROR(status_bad_start_element, s);
2503 if (!ENDSWITH(*s,
'>')) PUGI__THROW_ERROR(status_bad_start_element, s);
2514 if (endch !=
'>') PUGI__THROW_ERROR(status_bad_start_element, s);
2516 else PUGI__THROW_ERROR(status_bad_start_element, s);
2522 char_t* name = cursor->name;
2523 if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s);
2525 while (PUGI__IS_CHARTYPE(*s, ct_symbol))
2527 if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s);
2532 if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
2533 else PUGI__THROW_ERROR(status_end_element_mismatch, s);
2542 if (endch !=
'>') PUGI__THROW_ERROR(status_bad_end_element, s);
2546 if (*s !=
'>') PUGI__THROW_ERROR(status_bad_end_element, s);
2552 s = parse_question(s, cursor, optmsk, endch);
2556 if ((cursor->header & xml_memory_page_type_mask) + 1 == node_declaration)
goto LOC_ATTRIBUTES;
2560 s = parse_exclamation(s, cursor, optmsk, endch);
2563 else if (*s == 0 && endch ==
'?') PUGI__THROW_ERROR(status_bad_pi, s);
2564 else PUGI__THROW_ERROR(status_unrecognized_tag, s);
2577 if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single))
2581 else if (PUGI__OPTSET(parse_ws_pcdata_single))
2583 if (s[1] !=
'/' || cursor->first_child)
continue;
2591 PUGI__PUSHNODE(node_pcdata);
2594 s = strconv_pcdata(s);
2602 PUGI__SCANFOR(*s ==
'<');
2614 if (cursor != xmldoc) PUGI__THROW_ERROR(status_end_element_mismatch, s);
2619 static xml_parse_result parse(char_t* buffer,
size_t length, xml_node_struct* root,
unsigned int optmsk)
2621 xml_document_struct* xmldoc =
static_cast<xml_document_struct*
>(root);
2624 xmldoc->buffer = buffer;
2627 if (length == 0)
return make_parse_result(status_ok);
2630 xml_parser parser(*xmldoc);
2633 char_t endch = buffer[length - 1];
2634 buffer[length - 1] = 0;
2637 parser.parse(buffer, xmldoc, optmsk, endch);
2639 xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
2640 assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
2643 *
static_cast<xml_allocator*
>(xmldoc) = parser.alloc;
2646 if (result && endch ==
'<')
2649 return make_parse_result(status_unrecognized_tag, length);
2657 PUGI__FN xml_encoding get_write_native_encoding()
2659 #ifdef PUGIXML_WCHAR_MODE
2660 return get_wchar_encoding();
2662 return encoding_utf8;
2666 PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
2669 if (encoding == encoding_wchar)
return get_wchar_encoding();
2672 if (encoding == encoding_utf16)
return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2675 if (encoding == encoding_utf32)
return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2678 if (encoding != encoding_auto)
return encoding;
2681 return encoding_utf8;
2684 #ifdef PUGIXML_WCHAR_MODE
2685 PUGI__FN
size_t get_valid_length(
const char_t* data,
size_t length)
2690 return (
sizeof(
wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
2693 PUGI__FN
size_t convert_buffer(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32,
const char_t* data,
size_t length, xml_encoding encoding)
2696 if (need_endian_swap_utf(encoding, get_wchar_encoding()))
2698 convert_wchar_endian_swap(r_char, data, length);
2700 return length *
sizeof(char_t);
2704 if (encoding == encoding_utf8)
2706 uint8_t* dest = r_u8;
2707 uint8_t* end = utf_decoder<utf8_writer>::decode_wchar_block(data, length, dest);
2709 return static_cast<size_t>(end - dest);
2713 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2715 uint16_t* dest = r_u16;
2718 uint16_t* end = utf_decoder<utf16_writer>::decode_wchar_block(data, length, dest);
2721 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2723 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2725 return static_cast<size_t>(end - dest) *
sizeof(uint16_t);
2729 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2731 uint32_t* dest = r_u32;
2734 uint32_t* end = utf_decoder<utf32_writer>::decode_wchar_block(data, length, dest);
2737 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2739 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2741 return static_cast<size_t>(end - dest) *
sizeof(uint32_t);
2745 if (encoding == encoding_latin1)
2747 uint8_t* dest = r_u8;
2748 uint8_t* end = utf_decoder<latin1_writer>::decode_wchar_block(data, length, dest);
2750 return static_cast<size_t>(end - dest);
2753 assert(!
"Invalid encoding");
2757 PUGI__FN
size_t get_valid_length(
const char_t* data,
size_t length)
2761 for (
size_t i = 1; i <= 4; ++i)
2763 uint8_t ch =
static_cast<uint8_t
>(data[length - i]);
2766 if ((ch & 0xc0) != 0x80)
return length - i;
2773 PUGI__FN
size_t convert_buffer(char_t* , uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32,
const char_t* data,
size_t length, xml_encoding encoding)
2775 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2777 uint16_t* dest = r_u16;
2780 uint16_t* end = utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2783 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2785 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2787 return static_cast<size_t>(end - dest) *
sizeof(uint16_t);
2790 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2792 uint32_t* dest = r_u32;
2795 uint32_t* end = utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2798 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2800 if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
2802 return static_cast<size_t>(end - dest) *
sizeof(uint32_t);
2805 if (encoding == encoding_latin1)
2807 uint8_t* dest = r_u8;
2808 uint8_t* end = utf_decoder<latin1_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
2810 return static_cast<size_t>(end - dest);
2813 assert(!
"Invalid encoding");
2818 class xml_buffered_writer
2820 xml_buffered_writer(
const xml_buffered_writer&);
2821 xml_buffered_writer& operator=(
const xml_buffered_writer&);
2824 xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
2826 PUGI__STATIC_ASSERT(bufcapacity >= 8);
2829 ~xml_buffered_writer()
2836 flush(buffer, bufsize);
2840 void flush(
const char_t* data,
size_t size)
2842 if (size == 0)
return;
2845 if (encoding == get_write_native_encoding())
2846 writer.write(data, size *
sizeof(char_t));
2850 size_t result = convert_buffer(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);
2851 assert(result <=
sizeof(scratch));
2854 writer.write(scratch.data_u8, result);
2858 void write(
const char_t* data,
size_t length)
2860 if (bufsize + length > bufcapacity)
2866 if (length > bufcapacity)
2868 if (encoding == get_write_native_encoding())
2871 writer.write(data, length *
sizeof(char_t));
2876 while (length > bufcapacity)
2880 size_t chunk_size = get_valid_length(data, bufcapacity);
2883 flush(data, chunk_size);
2887 length -= chunk_size;
2895 memcpy(buffer + bufsize, data, length *
sizeof(char_t));
2899 void write(
const char_t* data)
2901 write(data, strlength(data));
2904 void write(char_t d0)
2906 if (bufsize + 1 > bufcapacity) flush();
2908 buffer[bufsize + 0] = d0;
2912 void write(char_t d0, char_t d1)
2914 if (bufsize + 2 > bufcapacity) flush();
2916 buffer[bufsize + 0] = d0;
2917 buffer[bufsize + 1] = d1;
2921 void write(char_t d0, char_t d1, char_t d2)
2923 if (bufsize + 3 > bufcapacity) flush();
2925 buffer[bufsize + 0] = d0;
2926 buffer[bufsize + 1] = d1;
2927 buffer[bufsize + 2] = d2;
2931 void write(char_t d0, char_t d1, char_t d2, char_t d3)
2933 if (bufsize + 4 > bufcapacity) flush();
2935 buffer[bufsize + 0] = d0;
2936 buffer[bufsize + 1] = d1;
2937 buffer[bufsize + 2] = d2;
2938 buffer[bufsize + 3] = d3;
2942 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
2944 if (bufsize + 5 > bufcapacity) flush();
2946 buffer[bufsize + 0] = d0;
2947 buffer[bufsize + 1] = d1;
2948 buffer[bufsize + 2] = d2;
2949 buffer[bufsize + 3] = d3;
2950 buffer[bufsize + 4] = d4;
2954 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
2956 if (bufsize + 6 > bufcapacity) flush();
2958 buffer[bufsize + 0] = d0;
2959 buffer[bufsize + 1] = d1;
2960 buffer[bufsize + 2] = d2;
2961 buffer[bufsize + 3] = d3;
2962 buffer[bufsize + 4] = d4;
2963 buffer[bufsize + 5] = d5;
2973 #ifdef PUGIXML_MEMORY_OUTPUT_STACK
2974 PUGIXML_MEMORY_OUTPUT_STACK
2979 bufcapacity = bufcapacitybytes / (
sizeof(char_t) + 4)
2982 char_t buffer[bufcapacity];
2986 uint8_t data_u8[4 * bufcapacity];
2987 uint16_t data_u16[2 * bufcapacity];
2988 uint32_t data_u32[bufcapacity];
2989 char_t data_char[bufcapacity];
2994 xml_encoding encoding;
2997 PUGI__FN
void text_output_escaped(xml_buffered_writer& writer,
const char_t* s, chartypex_t type)
3001 const char_t* prev = s;
3004 while (!PUGI__IS_CHARTYPEX(*s, type)) ++s;
3006 writer.write(prev, static_cast<size_t>(s - prev));
3012 writer.write(
'&',
'a',
'm',
'p',
';');
3016 writer.write(
'&',
'l',
't',
';');
3020 writer.write(
'&',
'g',
't',
';');
3024 writer.write(
'&',
'q',
'u',
'o',
't',
';');
3029 unsigned int ch =
static_cast<unsigned int>(*s++);
3032 writer.write(
'&',
'#', static_cast<char_t>((ch / 10) +
'0'), static_cast<char_t>((ch % 10) +
'0'),
';');
3038 PUGI__FN
void text_output(xml_buffered_writer& writer,
const char_t* s, chartypex_t type,
unsigned int flags)
3040 if (flags & format_no_escapes)
3043 text_output_escaped(writer, s, type);
3046 PUGI__FN
void text_output_cdata(xml_buffered_writer& writer,
const char_t* s)
3050 writer.write(
'<',
'!',
'[',
'C',
'D');
3051 writer.write(
'A',
'T',
'A',
'[');
3053 const char_t* prev = s;
3056 while (*s && !(s[0] ==
']' && s[1] ==
']' && s[2] ==
'>')) ++s;
3061 writer.write(prev, static_cast<size_t>(s - prev));
3063 writer.write(
']',
']',
'>');
3068 PUGI__FN
void node_output_attributes(xml_buffered_writer& writer,
const xml_node& node,
unsigned int flags)
3070 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
3072 for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute())
3075 writer.write(a.name()[0] ? a.name() : default_name);
3076 writer.write(
'=',
'"');
3078 text_output(writer, a.value(), ctx_special_attr, flags);
3084 PUGI__FN
void node_output(xml_buffered_writer& writer,
const xml_node& node,
const char_t* indent,
unsigned int flags,
unsigned int depth)
3086 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
3088 if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
3089 for (
unsigned int i = 0; i < depth; ++i) writer.write(indent);
3091 switch (node.type())
3095 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3096 node_output(writer, n, indent, flags, depth);
3102 const char_t* name = node.name()[0] ? node.name() : default_name;
3107 node_output_attributes(writer, node, flags);
3109 if (flags & format_raw)
3111 if (!node.first_child())
3112 writer.write(
' ',
'/',
'>');
3117 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3118 node_output(writer, n, indent, flags, depth + 1);
3120 writer.write(
'<',
'/');
3125 else if (!node.first_child())
3126 writer.write(
' ',
'/',
'>',
'\n');
3127 else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata))
3131 if (node.first_child().type() == node_pcdata)
3132 text_output(writer, node.first_child().value(), ctx_special_pcdata, flags);
3134 text_output_cdata(writer, node.first_child().value());
3136 writer.write(
'<',
'/');
3138 writer.write(
'>',
'\n');
3142 writer.write(
'>',
'\n');
3144 for (xml_node n = node.first_child(); n; n = n.next_sibling())
3145 node_output(writer, n, indent, flags, depth + 1);
3147 if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
3148 for (
unsigned int i = 0; i < depth; ++i) writer.write(indent);
3150 writer.write(
'<',
'/');
3152 writer.write(
'>',
'\n');
3159 text_output(writer, node.value(), ctx_special_pcdata, flags);
3160 if ((flags & format_raw) == 0) writer.write(
'\n');
3164 text_output_cdata(writer, node.value());
3165 if ((flags & format_raw) == 0) writer.write(
'\n');
3169 writer.write(
'<',
'!',
'-',
'-');
3170 writer.write(node.value());
3171 writer.write(
'-',
'-',
'>');
3172 if ((flags & format_raw) == 0) writer.write(
'\n');
3176 case node_declaration:
3177 writer.write(
'<',
'?');
3178 writer.write(node.name()[0] ? node.name() : default_name);
3180 if (node.type() == node_declaration)
3182 node_output_attributes(writer, node, flags);
3184 else if (node.value()[0])
3187 writer.write(node.value());
3190 writer.write(
'?',
'>');
3191 if ((flags & format_raw) == 0) writer.write(
'\n');
3195 writer.write(
'<',
'!',
'D',
'O',
'C');
3196 writer.write(
'T',
'Y',
'P',
'E');
3198 if (node.value()[0])
3201 writer.write(node.value());
3205 if ((flags & format_raw) == 0) writer.write(
'\n');
3209 assert(!
"Invalid node type");
3213 inline bool has_declaration(
const xml_node& node)
3215 for (xml_node child = node.first_child(); child; child = child.next_sibling())
3217 xml_node_type type = child.type();
3219 if (type == node_declaration)
return true;
3220 if (type == node_element)
return false;
3226 inline bool allow_insert_child(xml_node_type parent, xml_node_type child)
3228 if (parent != node_document && parent != node_element)
return false;
3229 if (child == node_document || child == node_null)
return false;
3230 if (parent != node_document && (child == node_declaration || child == node_doctype))
return false;
3235 PUGI__FN
void recursive_copy_skip(xml_node& dest,
const xml_node& source,
const xml_node& skip)
3237 assert(dest.type() == source.type());
3239 switch (source.type())
3243 dest.set_name(source.name());
3245 for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
3246 dest.append_attribute(a.name()).set_value(a.value());
3248 for (xml_node c = source.first_child(); c; c = c.next_sibling())
3250 if (c == skip)
continue;
3252 xml_node cc = dest.append_child(c.type());
3255 recursive_copy_skip(cc, c, skip);
3265 dest.set_value(source.value());
3269 dest.set_name(source.name());
3270 dest.set_value(source.value());
3273 case node_declaration:
3275 dest.set_name(source.name());
3277 for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
3278 dest.append_attribute(a.name()).set_value(a.value());
3284 assert(!
"Invalid node type");
3288 inline bool is_text_node(xml_node_struct* node)
3290 xml_node_type type =
static_cast<xml_node_type
>((node->header & impl::xml_memory_page_type_mask) + 1);
3292 return type == node_pcdata || type == node_cdata;
3296 PUGI__FN
int get_value_int(
const char_t* value,
int def)
3298 if (!value)
return def;
3300 #ifdef PUGIXML_WCHAR_MODE
3301 return static_cast<int>(wcstol(value, 0, 10));
3303 return static_cast<int>(strtol(value, 0, 10));
3307 PUGI__FN
unsigned int get_value_uint(
const char_t* value,
unsigned int def)
3309 if (!value)
return def;
3311 #ifdef PUGIXML_WCHAR_MODE
3312 return static_cast<unsigned int>(wcstoul(value, 0, 10));
3314 return static_cast<unsigned int>(strtoul(value, 0, 10));
3318 PUGI__FN
double get_value_double(
const char_t* value,
double def)
3320 if (!value)
return def;
3322 #ifdef PUGIXML_WCHAR_MODE
3323 return wcstod(value, 0);
3325 return strtod(value, 0);
3329 PUGI__FN
float get_value_float(
const char_t* value,
float def)
3331 if (!value)
return def;
3333 #ifdef PUGIXML_WCHAR_MODE
3334 return static_cast<float>(wcstod(value, 0));
3336 return static_cast<float>(strtod(value, 0));
3340 PUGI__FN
bool get_value_bool(
const char_t* value,
bool def)
3342 if (!value)
return def;
3345 char_t first = *value;
3348 return (first ==
'1' || first ==
't' || first ==
'T' || first ==
'y' || first ==
'Y');
3352 PUGI__FN
bool set_value_buffer(char_t*& dest, uintptr_t& header, uintptr_t header_mask,
char (&buf)[128])
3354 #ifdef PUGIXML_WCHAR_MODE
3356 impl::widen_ascii(wbuf, buf);
3358 return strcpy_insitu(dest, header, header_mask, wbuf);
3360 return strcpy_insitu(dest, header, header_mask, buf);
3364 PUGI__FN
bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask,
int value)
3367 sprintf(buf,
"%d", value);
3369 return set_value_buffer(dest, header, header_mask, buf);
3372 PUGI__FN
bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask,
unsigned int value)
3375 sprintf(buf,
"%u", value);
3377 return set_value_buffer(dest, header, header_mask, buf);
3380 PUGI__FN
bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask,
double value)
3383 sprintf(buf,
"%g", value);
3385 return set_value_buffer(dest, header, header_mask, buf);
3388 PUGI__FN
bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask,
bool value)
3390 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT(
"true") : PUGIXML_TEXT(
"false"));
3394 PUGI__FN xml_parse_status get_file_size(FILE* file,
size_t& out_result)
3396 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
3398 typedef __int64 length_type;
3400 _fseeki64(file, 0, SEEK_END);
3401 length_type length = _ftelli64(file);
3402 _fseeki64(file, 0, SEEK_SET);
3403 #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__)
3405 typedef off64_t length_type;
3407 fseeko64(file, 0, SEEK_END);
3408 length_type length = ftello64(file);
3409 fseeko64(file, 0, SEEK_SET);
3412 typedef long length_type;
3414 fseek(file, 0, SEEK_END);
3415 length_type length = ftell(file);
3416 fseek(file, 0, SEEK_SET);
3420 if (length < 0)
return status_io_error;
3423 size_t result =
static_cast<size_t>(length);
3425 if (static_cast<length_type>(result) != length)
return status_out_of_memory;
3428 out_result = result;
3433 PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file,
unsigned int options, xml_encoding encoding)
3435 if (!file)
return make_parse_result(status_file_not_found);
3439 xml_parse_status size_status = get_file_size(file, size);
3441 if (size_status != status_ok)
3444 return make_parse_result(size_status);
3448 char* contents =
static_cast<char*
>(xml_memory::allocate(size > 0 ? size : 1));
3453 return make_parse_result(status_out_of_memory);
3457 size_t read_size = fread(contents, 1, size, file);
3460 if (read_size != size)
3462 xml_memory::deallocate(contents);
3463 return make_parse_result(status_io_error);
3466 return doc.load_buffer_inplace_own(contents, size, options, encoding);
3469 #ifndef PUGIXML_NO_STL
3470 template <
typename T>
struct xml_stream_chunk
3472 static xml_stream_chunk* create()
3474 void* memory = xml_memory::allocate(
sizeof(xml_stream_chunk));
3476 return new (memory) xml_stream_chunk();
3479 static void destroy(
void* ptr)
3481 xml_stream_chunk* chunk =
static_cast<xml_stream_chunk*
>(ptr);
3486 xml_stream_chunk* next = chunk->next;
3487 xml_memory::deallocate(chunk);
3492 xml_stream_chunk(): next(0), size(0)
3496 xml_stream_chunk* next;
3499 T data[xml_memory_page_size /
sizeof(T)];
3502 template <
typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream,
void** out_buffer,
size_t* out_size)
3504 buffer_holder chunks(0, xml_stream_chunk<T>::destroy);
3508 xml_stream_chunk<T>* last = 0;
3510 while (!stream.eof())
3513 xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create();
3514 if (!chunk)
return status_out_of_memory;
3517 if (last) last = last->next = chunk;
3518 else chunks.data = last = chunk;
3521 stream.read(chunk->data, static_cast<std::streamsize>(
sizeof(chunk->data) /
sizeof(T)));
3522 chunk->size =
static_cast<size_t>(stream.gcount()) *
sizeof(T);
3525 if (stream.bad() || (!stream.eof() && stream.fail()))
return status_io_error;
3528 if (total + chunk->size < total)
return status_out_of_memory;
3529 total += chunk->size;
3533 char* buffer =
static_cast<char*
>(xml_memory::allocate(total));
3534 if (!buffer)
return status_out_of_memory;
3536 char* write = buffer;
3538 for (xml_stream_chunk<T>* chunk =
static_cast<xml_stream_chunk<T>*
>(chunks.data); chunk; chunk = chunk->next)
3540 assert(write + chunk->size <= buffer + total);
3541 memcpy(write, chunk->data, chunk->size);
3542 write += chunk->size;
3545 assert(write == buffer + total);
3548 *out_buffer = buffer;
3554 template <
typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream,
void** out_buffer,
size_t* out_size)
3557 typename std::basic_istream<T>::pos_type pos = stream.tellg();
3558 stream.seekg(0, std::ios::end);
3559 std::streamoff length = stream.tellg() - pos;
3562 if (stream.fail() || pos < 0)
return status_io_error;
3565 size_t read_length =
static_cast<size_t>(length);
3567 if (static_cast<std::streamsize>(read_length) != length || length < 0)
return status_out_of_memory;
3570 buffer_holder buffer(xml_memory::allocate((read_length > 0 ? read_length : 1) *
sizeof(T)), xml_memory::deallocate);
3571 if (!buffer.data)
return status_out_of_memory;
3573 stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
3576 if (stream.bad() || (!stream.eof() && stream.fail()))
return status_io_error;
3579 size_t actual_length =
static_cast<size_t>(stream.gcount());
3580 assert(actual_length <= read_length);
3582 *out_buffer = buffer.release();
3583 *out_size = actual_length *
sizeof(T);
3588 template <
typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream,
unsigned int options, xml_encoding encoding)
3594 xml_parse_status status = (stream.tellg() < 0) ? load_stream_data_noseek(stream, &buffer, &size) : load_stream_data_seek(stream, &buffer, &size);
3595 if (status != status_ok)
return make_parse_result(status);
3597 return doc.load_buffer_inplace_own(buffer, size, options, encoding);
3601 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__))
3602 PUGI__FN FILE* open_file_wide(
const wchar_t* path,
const wchar_t* mode)
3604 return _wfopen(path, mode);
3607 PUGI__FN
char* convert_path_heap(
const wchar_t* str)
3612 size_t length = wcslen(str);
3613 size_t size = as_utf8_begin(str, length);
3616 char* result =
static_cast<char*
>(xml_memory::allocate(size + 1));
3617 if (!result)
return 0;
3620 as_utf8_end(result, size, str, length);
3625 PUGI__FN FILE* open_file_wide(
const wchar_t* path,
const wchar_t* mode)
3628 char* path_utf8 = convert_path_heap(path);
3629 if (!path_utf8)
return 0;
3632 char mode_ascii[4] = {0};
3633 for (
size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);
3636 FILE* result = fopen(path_utf8, mode_ascii);
3639 xml_memory::deallocate(path_utf8);
3645 PUGI__FN
bool save_file_impl(
const xml_document& doc, FILE* file,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
3647 if (!file)
return false;
3649 xml_writer_file writer(file);
3650 doc.save(writer, indent, flags, encoding);
3652 int result = ferror(file);
3662 PUGI__FN xml_writer_file::xml_writer_file(
void* file_): file(file_)
3666 PUGI__FN
void xml_writer_file::write(
const void* data,
size_t size)
3668 size_t result = fwrite(data, 1, size, static_cast<FILE*>(file));
3672 #ifndef PUGIXML_NO_STL
3673 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<
char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
3677 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
3681 PUGI__FN
void xml_writer_stream::write(
const void* data,
size_t size)
3685 assert(!wide_stream);
3686 narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
3690 assert(wide_stream);
3691 assert(size %
sizeof(
wchar_t) == 0);
3693 wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size /
sizeof(
wchar_t)));
3698 PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0)
3702 PUGI__FN xml_tree_walker::~xml_tree_walker()
3706 PUGI__FN
int xml_tree_walker::depth()
const
3711 PUGI__FN
bool xml_tree_walker::begin(xml_node&)
3716 PUGI__FN
bool xml_tree_walker::end(xml_node&)
3721 PUGI__FN xml_attribute::xml_attribute(): _attr(0)
3725 PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
3729 PUGI__FN
static void unspecified_bool_xml_attribute(xml_attribute***)
3733 PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type()
const
3735 return _attr ? unspecified_bool_xml_attribute : 0;
3738 PUGI__FN
bool xml_attribute::operator!()
const
3743 PUGI__FN
bool xml_attribute::operator==(
const xml_attribute& r)
const
3745 return (_attr == r._attr);
3748 PUGI__FN
bool xml_attribute::operator!=(
const xml_attribute& r)
const
3750 return (_attr != r._attr);
3753 PUGI__FN
bool xml_attribute::operator<(
const xml_attribute& r)
const
3755 return (_attr < r._attr);
3758 PUGI__FN
bool xml_attribute::operator>(
const xml_attribute& r)
const
3760 return (_attr > r._attr);
3763 PUGI__FN
bool xml_attribute::operator<=(
const xml_attribute& r)
const
3765 return (_attr <= r._attr);
3768 PUGI__FN
bool xml_attribute::operator>=(
const xml_attribute& r)
const
3770 return (_attr >= r._attr);
3773 PUGI__FN xml_attribute xml_attribute::next_attribute()
const
3775 return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
3778 PUGI__FN xml_attribute xml_attribute::previous_attribute()
const
3780 return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
3783 PUGI__FN
const char_t* xml_attribute::as_string(
const char_t* def)
const
3785 return (_attr && _attr->value) ? _attr->value : def;
3788 PUGI__FN
int xml_attribute::as_int(
int def)
const
3790 return impl::get_value_int(_attr ? _attr->value : 0, def);
3793 PUGI__FN
unsigned int xml_attribute::as_uint(
unsigned int def)
const
3795 return impl::get_value_uint(_attr ? _attr->value : 0, def);
3798 PUGI__FN
double xml_attribute::as_double(
double def)
const
3800 return impl::get_value_double(_attr ? _attr->value : 0, def);
3803 PUGI__FN
float xml_attribute::as_float(
float def)
const
3805 return impl::get_value_float(_attr ? _attr->value : 0, def);
3808 PUGI__FN
bool xml_attribute::as_bool(
bool def)
const
3810 return impl::get_value_bool(_attr ? _attr->value : 0, def);
3813 PUGI__FN
bool xml_attribute::empty()
const
3818 PUGI__FN
const char_t* xml_attribute::name()
const
3820 return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT(
"");
3823 PUGI__FN
const char_t* xml_attribute::value()
const
3825 return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT(
"");
3828 PUGI__FN
size_t xml_attribute::hash_value()
const
3830 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(_attr) /
sizeof(xml_attribute_struct));
3833 PUGI__FN xml_attribute_struct* xml_attribute::internal_object()
const
3838 PUGI__FN xml_attribute& xml_attribute::operator=(
const char_t* rhs)
3844 PUGI__FN xml_attribute& xml_attribute::operator=(
int rhs)
3850 PUGI__FN xml_attribute& xml_attribute::operator=(
unsigned int rhs)
3856 PUGI__FN xml_attribute& xml_attribute::operator=(
double rhs)
3862 PUGI__FN xml_attribute& xml_attribute::operator=(
bool rhs)
3868 PUGI__FN
bool xml_attribute::set_name(
const char_t* rhs)
3870 if (!_attr)
return false;
3872 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs);
3875 PUGI__FN
bool xml_attribute::set_value(
const char_t* rhs)
3877 if (!_attr)
return false;
3879 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3882 PUGI__FN
bool xml_attribute::set_value(
int rhs)
3884 if (!_attr)
return false;
3886 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3889 PUGI__FN
bool xml_attribute::set_value(
unsigned int rhs)
3891 if (!_attr)
return false;
3893 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3896 PUGI__FN
bool xml_attribute::set_value(
double rhs)
3898 if (!_attr)
return false;
3900 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3903 PUGI__FN
bool xml_attribute::set_value(
bool rhs)
3905 if (!_attr)
return false;
3907 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
3911 PUGI__FN
bool operator&&(
const xml_attribute& lhs,
bool rhs)
3913 return (
bool)lhs && rhs;
3916 PUGI__FN
bool operator||(
const xml_attribute& lhs,
bool rhs)
3918 return (
bool)lhs || rhs;
3922 PUGI__FN xml_node::xml_node(): _root(0)
3926 PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p)
3930 PUGI__FN
static void unspecified_bool_xml_node(xml_node***)
3934 PUGI__FN xml_node::operator xml_node::unspecified_bool_type()
const
3936 return _root ? unspecified_bool_xml_node : 0;
3939 PUGI__FN
bool xml_node::operator!()
const
3944 PUGI__FN xml_node::iterator xml_node::begin()
const
3946 return iterator(_root ? _root->first_child : 0, _root);
3949 PUGI__FN xml_node::iterator xml_node::end()
const
3951 return iterator(0, _root);
3954 PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin()
const
3956 return attribute_iterator(_root ? _root->first_attribute : 0, _root);
3959 PUGI__FN xml_node::attribute_iterator xml_node::attributes_end()
const
3961 return attribute_iterator(0, _root);
3964 PUGI__FN xml_object_range<xml_node_iterator> xml_node::children()
const
3966 return xml_object_range<xml_node_iterator>(begin(), end());
3969 PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(
const char_t* name_)
const
3971 return xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_), name_), xml_named_node_iterator());
3974 PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes()
const
3976 return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());
3979 PUGI__FN
bool xml_node::operator==(
const xml_node& r)
const
3981 return (_root == r._root);
3984 PUGI__FN
bool xml_node::operator!=(
const xml_node& r)
const
3986 return (_root != r._root);
3989 PUGI__FN
bool xml_node::operator<(
const xml_node& r)
const
3991 return (_root < r._root);
3994 PUGI__FN
bool xml_node::operator>(
const xml_node& r)
const
3996 return (_root > r._root);
3999 PUGI__FN
bool xml_node::operator<=(
const xml_node& r)
const
4001 return (_root <= r._root);
4004 PUGI__FN
bool xml_node::operator>=(
const xml_node& r)
const
4006 return (_root >= r._root);
4009 PUGI__FN
bool xml_node::empty()
const
4014 PUGI__FN
const char_t* xml_node::name()
const
4016 return (_root && _root->name) ? _root->name : PUGIXML_TEXT(
"");
4019 PUGI__FN xml_node_type xml_node::type()
const
4021 return _root ?
static_cast<xml_node_type
>((_root->header & impl::xml_memory_page_type_mask) + 1) : node_null;
4024 PUGI__FN
const char_t* xml_node::value()
const
4026 return (_root && _root->value) ? _root->value : PUGIXML_TEXT(
"");
4029 PUGI__FN xml_node xml_node::child(
const char_t* name_)
const
4031 if (!_root)
return xml_node();
4033 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
4034 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
4039 PUGI__FN xml_attribute xml_node::attribute(
const char_t* name_)
const
4041 if (!_root)
return xml_attribute();
4043 for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
4044 if (i->name && impl::strequal(name_, i->name))
4045 return xml_attribute(i);
4047 return xml_attribute();
4050 PUGI__FN xml_node xml_node::next_sibling(
const char_t* name_)
const
4052 if (!_root)
return xml_node();
4054 for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
4055 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
4060 PUGI__FN xml_node xml_node::next_sibling()
const
4062 if (!_root)
return xml_node();
4064 if (_root->next_sibling)
return xml_node(_root->next_sibling);
4065 else return xml_node();
4068 PUGI__FN xml_node xml_node::previous_sibling(
const char_t* name_)
const
4070 if (!_root)
return xml_node();
4072 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
4073 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
4078 PUGI__FN xml_node xml_node::previous_sibling()
const
4080 if (!_root)
return xml_node();
4082 if (_root->prev_sibling_c->next_sibling)
return xml_node(_root->prev_sibling_c);
4083 else return xml_node();
4086 PUGI__FN xml_node xml_node::parent()
const
4088 return _root ? xml_node(_root->parent) : xml_node();
4091 PUGI__FN xml_node xml_node::root()
const
4093 if (!_root)
return xml_node();
4095 impl::xml_memory_page* page =
reinterpret_cast<impl::xml_memory_page*
>(_root->header & impl::xml_memory_page_pointer_mask);
4097 return xml_node(static_cast<impl::xml_document_struct*>(page->allocator));
4100 PUGI__FN xml_text xml_node::text()
const
4102 return xml_text(_root);
4105 PUGI__FN
const char_t* xml_node::child_value()
const
4107 if (!_root)
return PUGIXML_TEXT(
"");
4109 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
4110 if (i->value && impl::is_text_node(i))
4113 return PUGIXML_TEXT(
"");
4116 PUGI__FN
const char_t* xml_node::child_value(
const char_t* name_)
const
4118 return child(name_).child_value();
4121 PUGI__FN xml_attribute xml_node::first_attribute()
const
4123 return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
4126 PUGI__FN xml_attribute xml_node::last_attribute()
const
4128 return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute();
4131 PUGI__FN xml_node xml_node::first_child()
const
4133 return _root ? xml_node(_root->first_child) : xml_node();
4136 PUGI__FN xml_node xml_node::last_child()
const
4138 return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
4141 PUGI__FN
bool xml_node::set_name(
const char_t* rhs)
4146 case node_declaration:
4148 return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs);
4155 PUGI__FN
bool xml_node::set_value(
const char_t* rhs)
4164 return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs);
4171 PUGI__FN xml_attribute xml_node::append_attribute(
const char_t* name_)
4173 if (type() != node_element && type() != node_declaration)
return xml_attribute();
4175 xml_attribute a(impl::append_attribute_ll(_root, impl::get_allocator(_root)));
4181 PUGI__FN xml_attribute xml_node::prepend_attribute(
const char_t* name_)
4183 if (type() != node_element && type() != node_declaration)
return xml_attribute();
4185 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4186 if (!a)
return xml_attribute();
4190 xml_attribute_struct* head = _root->first_attribute;
4194 a._attr->prev_attribute_c = head->prev_attribute_c;
4195 head->prev_attribute_c = a._attr;
4198 a._attr->prev_attribute_c = a._attr;
4200 a._attr->next_attribute = head;
4201 _root->first_attribute = a._attr;
4206 PUGI__FN xml_attribute xml_node::insert_attribute_before(
const char_t* name_,
const xml_attribute& attr)
4208 if ((type() != node_element && type() != node_declaration) || attr.empty())
return xml_attribute();
4211 xml_attribute_struct* cur = attr._attr;
4213 while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c;
4215 if (cur != _root->first_attribute)
return xml_attribute();
4217 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4218 if (!a)
return xml_attribute();
4222 if (attr._attr->prev_attribute_c->next_attribute)
4223 attr._attr->prev_attribute_c->next_attribute = a._attr;
4225 _root->first_attribute = a._attr;
4227 a._attr->prev_attribute_c = attr._attr->prev_attribute_c;
4228 a._attr->next_attribute = attr._attr;
4229 attr._attr->prev_attribute_c = a._attr;
4234 PUGI__FN xml_attribute xml_node::insert_attribute_after(
const char_t* name_,
const xml_attribute& attr)
4236 if ((type() != node_element && type() != node_declaration) || attr.empty())
return xml_attribute();
4239 xml_attribute_struct* cur = attr._attr;
4241 while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c;
4243 if (cur != _root->first_attribute)
return xml_attribute();
4245 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
4246 if (!a)
return xml_attribute();
4250 if (attr._attr->next_attribute)
4251 attr._attr->next_attribute->prev_attribute_c = a._attr;
4253 _root->first_attribute->prev_attribute_c = a._attr;
4255 a._attr->next_attribute = attr._attr->next_attribute;
4256 a._attr->prev_attribute_c = attr._attr;
4257 attr._attr->next_attribute = a._attr;
4262 PUGI__FN xml_attribute xml_node::append_copy(
const xml_attribute& proto)
4264 if (!proto)
return xml_attribute();
4266 xml_attribute result = append_attribute(proto.name());
4267 result.set_value(proto.value());
4272 PUGI__FN xml_attribute xml_node::prepend_copy(
const xml_attribute& proto)
4274 if (!proto)
return xml_attribute();
4276 xml_attribute result = prepend_attribute(proto.name());
4277 result.set_value(proto.value());
4282 PUGI__FN xml_attribute xml_node::insert_copy_after(
const xml_attribute& proto,
const xml_attribute& attr)
4284 if (!proto)
return xml_attribute();
4286 xml_attribute result = insert_attribute_after(proto.name(), attr);
4287 result.set_value(proto.value());
4292 PUGI__FN xml_attribute xml_node::insert_copy_before(
const xml_attribute& proto,
const xml_attribute& attr)
4294 if (!proto)
return xml_attribute();
4296 xml_attribute result = insert_attribute_before(proto.name(), attr);
4297 result.set_value(proto.value());
4302 PUGI__FN xml_node xml_node::append_child(xml_node_type type_)
4304 if (!impl::allow_insert_child(this->type(), type_))
return xml_node();
4306 xml_node n(impl::append_node(_root, impl::get_allocator(_root), type_));
4308 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
4313 PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_)
4315 if (!impl::allow_insert_child(this->type(), type_))
return xml_node();
4317 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
4318 if (!n)
return xml_node();
4320 n._root->parent = _root;
4322 xml_node_struct* head = _root->first_child;
4326 n._root->prev_sibling_c = head->prev_sibling_c;
4327 head->prev_sibling_c = n._root;
4330 n._root->prev_sibling_c = n._root;
4332 n._root->next_sibling = head;
4333 _root->first_child = n._root;
4335 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
4340 PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_,
const xml_node& node)
4342 if (!impl::allow_insert_child(this->type(), type_))
return xml_node();
4343 if (!node._root || node._root->parent != _root)
return xml_node();
4345 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
4346 if (!n)
return xml_node();
4348 n._root->parent = _root;
4350 if (node._root->prev_sibling_c->next_sibling)
4351 node._root->prev_sibling_c->next_sibling = n._root;
4353 _root->first_child = n._root;
4355 n._root->prev_sibling_c = node._root->prev_sibling_c;
4356 n._root->next_sibling = node._root;
4357 node._root->prev_sibling_c = n._root;
4359 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
4364 PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_,
const xml_node& node)
4366 if (!impl::allow_insert_child(this->type(), type_))
return xml_node();
4367 if (!node._root || node._root->parent != _root)
return xml_node();
4369 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
4370 if (!n)
return xml_node();
4372 n._root->parent = _root;
4374 if (node._root->next_sibling)
4375 node._root->next_sibling->prev_sibling_c = n._root;
4377 _root->first_child->prev_sibling_c = n._root;
4379 n._root->next_sibling = node._root->next_sibling;
4380 n._root->prev_sibling_c = node._root;
4381 node._root->next_sibling = n._root;
4383 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
4388 PUGI__FN xml_node xml_node::append_child(
const char_t* name_)
4390 xml_node result = append_child(node_element);
4392 result.set_name(name_);
4397 PUGI__FN xml_node xml_node::prepend_child(
const char_t* name_)
4399 xml_node result = prepend_child(node_element);
4401 result.set_name(name_);
4406 PUGI__FN xml_node xml_node::insert_child_after(
const char_t* name_,
const xml_node& node)
4408 xml_node result = insert_child_after(node_element, node);
4410 result.set_name(name_);
4415 PUGI__FN xml_node xml_node::insert_child_before(
const char_t* name_,
const xml_node& node)
4417 xml_node result = insert_child_before(node_element, node);
4419 result.set_name(name_);
4424 PUGI__FN xml_node xml_node::append_copy(
const xml_node& proto)
4426 xml_node result = append_child(proto.type());
4428 if (result) impl::recursive_copy_skip(result, proto, result);
4433 PUGI__FN xml_node xml_node::prepend_copy(
const xml_node& proto)
4435 xml_node result = prepend_child(proto.type());
4437 if (result) impl::recursive_copy_skip(result, proto, result);
4442 PUGI__FN xml_node xml_node::insert_copy_after(
const xml_node& proto,
const xml_node& node)
4444 xml_node result = insert_child_after(proto.type(), node);
4446 if (result) impl::recursive_copy_skip(result, proto, result);
4451 PUGI__FN xml_node xml_node::insert_copy_before(
const xml_node& proto,
const xml_node& node)
4453 xml_node result = insert_child_before(proto.type(), node);
4455 if (result) impl::recursive_copy_skip(result, proto, result);
4460 PUGI__FN
bool xml_node::remove_attribute(
const char_t* name_)
4462 return remove_attribute(attribute(name_));
4465 PUGI__FN
bool xml_node::remove_attribute(
const xml_attribute& a)
4467 if (!_root || !a._attr)
return false;
4470 xml_attribute_struct* attr = a._attr;
4472 while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c;
4474 if (attr != _root->first_attribute)
return false;
4476 if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c;
4477 else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c;
4479 if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute;
4480 else _root->first_attribute = a._attr->next_attribute;
4482 impl::destroy_attribute(a._attr, impl::get_allocator(_root));
4487 PUGI__FN
bool xml_node::remove_child(
const char_t* name_)
4489 return remove_child(child(name_));
4492 PUGI__FN
bool xml_node::remove_child(
const xml_node& n)
4494 if (!_root || !n._root || n._root->parent != _root)
return false;
4496 if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c;
4497 else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c;
4499 if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling;
4500 else _root->first_child = n._root->next_sibling;
4502 impl::destroy_node(n._root, impl::get_allocator(_root));
4507 PUGI__FN xml_node xml_node::find_child_by_attribute(
const char_t* name_,
const char_t* attr_name,
const char_t* attr_value)
const
4509 if (!_root)
return xml_node();
4511 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
4512 if (i->name && impl::strequal(name_, i->name))
4514 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
4515 if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value))
4522 PUGI__FN xml_node xml_node::find_child_by_attribute(
const char_t* attr_name,
const char_t* attr_value)
const
4524 if (!_root)
return xml_node();
4526 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
4527 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
4528 if (impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value))
4534 #ifndef PUGIXML_NO_STL
4535 PUGI__FN string_t xml_node::path(char_t delimiter)
const
4537 xml_node cursor = *
this;
4539 string_t result = cursor.name();
4541 while (cursor.parent())
4543 cursor = cursor.parent();
4545 string_t temp = cursor.name();
4555 PUGI__FN xml_node xml_node::first_element_by_path(
const char_t* path_, char_t delimiter)
const
4557 xml_node found = *
this;
4559 if (!_root || !path_ || !path_[0])
return found;
4561 if (path_[0] == delimiter)
4564 found = found.root();
4568 const char_t* path_segment = path_;
4570 while (*path_segment == delimiter) ++path_segment;
4572 const char_t* path_segment_end = path_segment;
4574 while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;
4576 if (path_segment == path_segment_end)
return found;
4578 const char_t* next_segment = path_segment_end;
4580 while (*next_segment == delimiter) ++next_segment;
4582 if (*path_segment ==
'.' && path_segment + 1 == path_segment_end)
4583 return found.first_element_by_path(next_segment, delimiter);
4584 else if (*path_segment ==
'.' && *(path_segment+1) ==
'.' && path_segment + 2 == path_segment_end)
4585 return found.parent().first_element_by_path(next_segment, delimiter);
4588 for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling)
4590 if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
4592 xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
4594 if (subsearch)
return subsearch;
4602 PUGI__FN
bool xml_node::traverse(xml_tree_walker& walker)
4606 xml_node arg_begin = *
this;
4607 if (!walker.begin(arg_begin))
return false;
4609 xml_node cur = first_child();
4617 xml_node arg_for_each = cur;
4618 if (!walker.for_each(arg_for_each))
4621 if (cur.first_child())
4624 cur = cur.first_child();
4626 else if (cur.next_sibling())
4627 cur = cur.next_sibling();
4631 while (!cur.next_sibling() && cur != *
this && !cur.parent().empty())
4638 cur = cur.next_sibling();
4641 while (cur && cur != *
this);
4644 assert(walker._depth == -1);
4646 xml_node arg_end = *
this;
4647 return walker.end(arg_end);
4650 PUGI__FN
size_t xml_node::hash_value()
const
4652 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(_root) /
sizeof(xml_node_struct));
4655 PUGI__FN xml_node_struct* xml_node::internal_object()
const
4660 PUGI__FN
void xml_node::print(xml_writer& writer,
const char_t* indent,
unsigned int flags, xml_encoding encoding,
unsigned int depth)
const
4664 impl::xml_buffered_writer buffered_writer(writer, encoding);
4666 impl::node_output(buffered_writer, *
this, indent, flags, depth);
4669 #ifndef PUGIXML_NO_STL
4670 PUGI__FN
void xml_node::print(std::basic_ostream<
char, std::char_traits<char> >& stream,
const char_t* indent,
unsigned int flags, xml_encoding encoding,
unsigned int depth)
const
4672 xml_writer_stream writer(stream);
4674 print(writer, indent, flags, encoding, depth);
4677 PUGI__FN
void xml_node::print(std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream,
const char_t* indent,
unsigned int flags,
unsigned int depth)
const
4679 xml_writer_stream writer(stream);
4681 print(writer, indent, flags, encoding_wchar, depth);
4685 PUGI__FN ptrdiff_t xml_node::offset_debug()
const
4687 xml_node_struct* r = root()._root;
4691 const char_t* buffer =
static_cast<impl::xml_document_struct*
>(r)->buffer;
4693 if (!buffer)
return -1;
4701 case node_declaration:
4703 return (_root->header & impl::xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer;
4709 return (_root->header & impl::xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer;
4717 PUGI__FN
bool operator&&(
const xml_node& lhs,
bool rhs)
4719 return (
bool)lhs && rhs;
4722 PUGI__FN
bool operator||(
const xml_node& lhs,
bool rhs)
4724 return (
bool)lhs || rhs;
4728 PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root)
4732 PUGI__FN xml_node_struct* xml_text::_data()
const
4734 if (!_root || impl::is_text_node(_root))
return _root;
4736 for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
4737 if (impl::is_text_node(node))
4743 PUGI__FN xml_node_struct* xml_text::_data_new()
4745 xml_node_struct* d = _data();
4748 return xml_node(_root).append_child(node_pcdata).internal_object();
4751 PUGI__FN xml_text::xml_text(): _root(0)
4755 PUGI__FN
static void unspecified_bool_xml_text(xml_text***)
4759 PUGI__FN xml_text::operator xml_text::unspecified_bool_type()
const
4761 return _data() ? unspecified_bool_xml_text : 0;
4764 PUGI__FN
bool xml_text::operator!()
const
4769 PUGI__FN
bool xml_text::empty()
const
4771 return _data() == 0;
4774 PUGI__FN
const char_t* xml_text::get()
const
4776 xml_node_struct* d = _data();
4778 return (d && d->value) ? d->value : PUGIXML_TEXT(
"");
4781 PUGI__FN
const char_t* xml_text::as_string(
const char_t* def)
const
4783 xml_node_struct* d = _data();
4785 return (d && d->value) ? d->value : def;
4788 PUGI__FN
int xml_text::as_int(
int def)
const
4790 xml_node_struct* d = _data();
4792 return impl::get_value_int(d ? d->value : 0, def);
4795 PUGI__FN
unsigned int xml_text::as_uint(
unsigned int def)
const
4797 xml_node_struct* d = _data();
4799 return impl::get_value_uint(d ? d->value : 0, def);
4802 PUGI__FN
double xml_text::as_double(
double def)
const
4804 xml_node_struct* d = _data();
4806 return impl::get_value_double(d ? d->value : 0, def);
4809 PUGI__FN
float xml_text::as_float(
float def)
const
4811 xml_node_struct* d = _data();
4813 return impl::get_value_float(d ? d->value : 0, def);
4816 PUGI__FN
bool xml_text::as_bool(
bool def)
const
4818 xml_node_struct* d = _data();
4820 return impl::get_value_bool(d ? d->value : 0, def);
4823 PUGI__FN
bool xml_text::set(
const char_t* rhs)
4825 xml_node_struct* dn = _data_new();
4827 return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4830 PUGI__FN
bool xml_text::set(
int rhs)
4832 xml_node_struct* dn = _data_new();
4834 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4837 PUGI__FN
bool xml_text::set(
unsigned int rhs)
4839 xml_node_struct* dn = _data_new();
4841 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4844 PUGI__FN
bool xml_text::set(
double rhs)
4846 xml_node_struct* dn = _data_new();
4848 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4851 PUGI__FN
bool xml_text::set(
bool rhs)
4853 xml_node_struct* dn = _data_new();
4855 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
4858 PUGI__FN xml_text& xml_text::operator=(
const char_t* rhs)
4864 PUGI__FN xml_text& xml_text::operator=(
int rhs)
4870 PUGI__FN xml_text& xml_text::operator=(
unsigned int rhs)
4876 PUGI__FN xml_text& xml_text::operator=(
double rhs)
4882 PUGI__FN xml_text& xml_text::operator=(
bool rhs)
4888 PUGI__FN xml_node xml_text::data()
const
4890 return xml_node(_data());
4894 PUGI__FN
bool operator&&(
const xml_text& lhs,
bool rhs)
4896 return (
bool)lhs && rhs;
4899 PUGI__FN
bool operator||(
const xml_text& lhs,
bool rhs)
4901 return (
bool)lhs || rhs;
4905 PUGI__FN xml_node_iterator::xml_node_iterator()
4909 PUGI__FN xml_node_iterator::xml_node_iterator(
const xml_node& node): _wrap(node), _parent(node.parent())
4913 PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
4917 PUGI__FN
bool xml_node_iterator::operator==(
const xml_node_iterator& rhs)
const
4919 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
4922 PUGI__FN
bool xml_node_iterator::operator!=(
const xml_node_iterator& rhs)
const
4924 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
4927 PUGI__FN xml_node& xml_node_iterator::operator*()
const
4929 assert(_wrap._root);
4933 PUGI__FN xml_node* xml_node_iterator::operator->()
const
4935 assert(_wrap._root);
4936 return const_cast<xml_node*
>(&_wrap);
4939 PUGI__FN
const xml_node_iterator& xml_node_iterator::operator++()
4941 assert(_wrap._root);
4942 _wrap._root = _wrap._root->next_sibling;
4946 PUGI__FN xml_node_iterator xml_node_iterator::operator++(
int)
4948 xml_node_iterator temp = *
this;
4953 PUGI__FN
const xml_node_iterator& xml_node_iterator::operator--()
4955 _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
4959 PUGI__FN xml_node_iterator xml_node_iterator::operator--(
int)
4961 xml_node_iterator temp = *
this;
4966 PUGI__FN xml_attribute_iterator::xml_attribute_iterator()
4970 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(
const xml_attribute& attr,
const xml_node& parent): _wrap(attr), _parent(parent)
4974 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
4978 PUGI__FN
bool xml_attribute_iterator::operator==(
const xml_attribute_iterator& rhs)
const
4980 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
4983 PUGI__FN
bool xml_attribute_iterator::operator!=(
const xml_attribute_iterator& rhs)
const
4985 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
4988 PUGI__FN xml_attribute& xml_attribute_iterator::operator*()
const
4990 assert(_wrap._attr);
4994 PUGI__FN xml_attribute* xml_attribute_iterator::operator->()
const
4996 assert(_wrap._attr);
4997 return const_cast<xml_attribute*
>(&_wrap);
5000 PUGI__FN
const xml_attribute_iterator& xml_attribute_iterator::operator++()
5002 assert(_wrap._attr);
5003 _wrap._attr = _wrap._attr->next_attribute;
5007 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(
int)
5009 xml_attribute_iterator temp = *
this;
5014 PUGI__FN
const xml_attribute_iterator& xml_attribute_iterator::operator--()
5016 _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
5020 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(
int)
5022 xml_attribute_iterator temp = *
this;
5027 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0)
5031 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(
const xml_node& node,
const char_t* name): _node(node), _name(name)
5035 PUGI__FN
bool xml_named_node_iterator::operator==(
const xml_named_node_iterator& rhs)
const
5037 return _node == rhs._node;
5040 PUGI__FN
bool xml_named_node_iterator::operator!=(
const xml_named_node_iterator& rhs)
const
5042 return _node != rhs._node;
5045 PUGI__FN xml_node& xml_named_node_iterator::operator*()
const
5047 assert(_node._root);
5051 PUGI__FN xml_node* xml_named_node_iterator::operator->()
const
5053 assert(_node._root);
5054 return const_cast<xml_node*
>(&_node);
5057 PUGI__FN
const xml_named_node_iterator& xml_named_node_iterator::operator++()
5059 assert(_node._root);
5060 _node = _node.next_sibling(_name);
5064 PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(
int)
5066 xml_named_node_iterator temp = *
this;
5071 PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
5075 PUGI__FN xml_parse_result::operator bool()
const
5077 return status == status_ok;
5080 PUGI__FN
const char* xml_parse_result::description()
const
5084 case status_ok:
return "No error";
5086 case status_file_not_found:
return "File was not found";
5087 case status_io_error:
return "Error reading from file/stream";
5088 case status_out_of_memory:
return "Could not allocate memory";
5089 case status_internal_error:
return "Internal error occurred";
5091 case status_unrecognized_tag:
return "Could not determine tag type";
5093 case status_bad_pi:
return "Error parsing document declaration/processing instruction";
5094 case status_bad_comment:
return "Error parsing comment";
5095 case status_bad_cdata:
return "Error parsing CDATA section";
5096 case status_bad_doctype:
return "Error parsing document type declaration";
5097 case status_bad_pcdata:
return "Error parsing PCDATA section";
5098 case status_bad_start_element:
return "Error parsing start element tag";
5099 case status_bad_attribute:
return "Error parsing element attribute";
5100 case status_bad_end_element:
return "Error parsing end element tag";
5101 case status_end_element_mismatch:
return "Start-end tags mismatch";
5103 default:
return "Unknown error";
5107 PUGI__FN xml_document::xml_document(): _buffer(0)
5112 PUGI__FN xml_document::~xml_document()
5117 PUGI__FN
void xml_document::reset()
5123 PUGI__FN
void xml_document::reset(
const xml_document& proto)
5127 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
5131 PUGI__FN
void xml_document::create()
5134 PUGI__STATIC_ASSERT(offsetof(impl::xml_memory_page, data) +
sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment <=
sizeof(_memory));
5137 void* page_memory =
reinterpret_cast<void*
>((
reinterpret_cast<uintptr_t
>(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1));
5140 impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory);
5142 page->busy_size = impl::xml_memory_page_size;
5145 _root =
new (page->data) impl::xml_document_struct(page);
5146 _root->prev_sibling_c = _root;
5149 page->allocator =
static_cast<impl::xml_document_struct*
>(_root);
5152 PUGI__FN
void xml_document::destroy()
5157 impl::xml_memory::deallocate(_buffer);
5164 impl::xml_memory_page* root_page =
reinterpret_cast<impl::xml_memory_page*
>(_root->header & impl::xml_memory_page_pointer_mask);
5165 assert(root_page && !root_page->prev && !root_page->memory);
5168 for (impl::xml_memory_page* page = root_page->next; page; )
5170 impl::xml_memory_page* next = page->next;
5172 impl::xml_allocator::deallocate_page(page);
5178 root_page->allocator = 0;
5179 root_page->next = 0;
5180 root_page->busy_size = root_page->freed_size = 0;
5186 #ifndef PUGIXML_NO_STL
5187 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<
char, std::char_traits<char> >& stream,
unsigned int options, xml_encoding encoding)
5191 return impl::load_stream_impl(*
this, stream, options, encoding);
5194 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<
wchar_t, std::char_traits<wchar_t> >& stream,
unsigned int options)
5198 return impl::load_stream_impl(*
this, stream, options, encoding_wchar);
5202 PUGI__FN xml_parse_result xml_document::load(
const char_t* contents,
unsigned int options)
5205 #ifdef PUGIXML_WCHAR_MODE
5206 xml_encoding encoding = encoding_wchar;
5208 xml_encoding encoding = encoding_utf8;
5211 return load_buffer(contents, impl::strlength(contents) *
sizeof(char_t), options, encoding);
5214 PUGI__FN xml_parse_result xml_document::load_file(
const char* path_,
unsigned int options, xml_encoding encoding)
5218 FILE* file = fopen(path_,
"rb");
5220 return impl::load_file_impl(*
this, file, options, encoding);
5223 PUGI__FN xml_parse_result xml_document::load_file(
const wchar_t* path_,
unsigned int options, xml_encoding encoding)
5227 FILE* file = impl::open_file_wide(path_, L
"rb");
5229 return impl::load_file_impl(*
this, file, options, encoding);
5232 PUGI__FN xml_parse_result xml_document::load_buffer_impl(
void* contents,
size_t size,
unsigned int options, xml_encoding encoding,
bool is_mutable,
bool own)
5237 assert(contents || size == 0);
5240 xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
5246 if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable))
return impl::make_parse_result(status_out_of_memory);
5249 if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
5252 xml_parse_result res = impl::xml_parser::parse(buffer, length, _root, options);
5255 res.encoding = buffer_encoding;
5258 if (own || buffer != contents) _buffer = buffer;
5263 PUGI__FN xml_parse_result xml_document::load_buffer(
const void* contents,
size_t size,
unsigned int options, xml_encoding encoding)
5265 return load_buffer_impl(const_cast<void*>(contents), size, options, encoding,
false,
false);
5268 PUGI__FN xml_parse_result xml_document::load_buffer_inplace(
void* contents,
size_t size,
unsigned int options, xml_encoding encoding)
5270 return load_buffer_impl(contents, size, options, encoding,
true,
false);
5273 PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(
void* contents,
size_t size,
unsigned int options, xml_encoding encoding)
5275 return load_buffer_impl(contents, size, options, encoding,
true,
true);
5278 PUGI__FN
void xml_document::save(xml_writer& writer,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
const
5280 impl::xml_buffered_writer buffered_writer(writer, encoding);
5282 if ((flags & format_write_bom) && encoding != encoding_latin1)
5285 #ifdef PUGIXML_WCHAR_MODE
5286 unsigned int bom = 0xfeff;
5287 buffered_writer.write(static_cast<wchar_t>(bom));
5289 buffered_writer.write(
'\xef',
'\xbb',
'\xbf');
5293 if (!(flags & format_no_declaration) && !impl::has_declaration(*
this))
5295 buffered_writer.write(PUGIXML_TEXT(
"<?xml version=\"1.0\""));
5296 if (encoding == encoding_latin1) buffered_writer.write(PUGIXML_TEXT(
" encoding=\"ISO-8859-1\""));
5297 buffered_writer.write(
'?',
'>');
5298 if (!(flags & format_raw)) buffered_writer.write(
'\n');
5301 impl::node_output(buffered_writer, *
this, indent, flags, 0);
5304 #ifndef PUGIXML_NO_STL
5305 PUGI__FN
void xml_document::save(std::basic_ostream<
char, std::char_traits<char> >& stream,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
const
5307 xml_writer_stream writer(stream);
5309 save(writer, indent, flags, encoding);
5312 PUGI__FN
void xml_document::save(std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream,
const char_t* indent,
unsigned int flags)
const
5314 xml_writer_stream writer(stream);
5316 save(writer, indent, flags, encoding_wchar);
5320 PUGI__FN
bool xml_document::save_file(
const char* path_,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
const
5322 FILE* file = fopen(path_, (flags & format_save_file_text) ?
"w" :
"wb");
5323 return impl::save_file_impl(*
this, file, indent, flags, encoding);
5326 PUGI__FN
bool xml_document::save_file(
const wchar_t* path_,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
const
5328 FILE* file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L
"w" : L
"wb");
5329 return impl::save_file_impl(*
this, file, indent, flags, encoding);
5332 PUGI__FN xml_node xml_document::document_element()
const
5334 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5335 if ((i->header & impl::xml_memory_page_type_mask) + 1 == node_element)
5341 #ifndef PUGIXML_NO_STL
5342 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(
const wchar_t* str)
5346 return impl::as_utf8_impl(str, wcslen(str));
5349 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(
const std::basic_string<wchar_t>& str)
5351 return impl::as_utf8_impl(str.c_str(), str.size());
5354 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(
const char* str)
5358 return impl::as_wide_impl(str, strlen(str));
5361 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(
const std::string& str)
5363 return impl::as_wide_impl(str.c_str(), str.size());
5367 PUGI__FN
void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
5369 impl::xml_memory::allocate = allocate;
5370 impl::xml_memory::deallocate = deallocate;
5373 PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
5375 return impl::xml_memory::allocate;
5378 PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
5380 return impl::xml_memory::deallocate;
5384 #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
5388 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(
const pugi::xml_node_iterator&)
5390 return std::bidirectional_iterator_tag();
5393 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(
const pugi::xml_attribute_iterator&)
5395 return std::bidirectional_iterator_tag();
5398 PUGI__FN std::forward_iterator_tag _Iter_cat(
const pugi::xml_named_node_iterator&)
5400 return std::forward_iterator_tag();
5405 #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
5409 PUGI__FN std::bidirectional_iterator_tag __iterator_category(
const pugi::xml_node_iterator&)
5411 return std::bidirectional_iterator_tag();
5414 PUGI__FN std::bidirectional_iterator_tag __iterator_category(
const pugi::xml_attribute_iterator&)
5416 return std::bidirectional_iterator_tag();
5419 PUGI__FN std::forward_iterator_tag __iterator_category(
const pugi::xml_named_node_iterator&)
5421 return std::forward_iterator_tag();
5426 #ifndef PUGIXML_NO_XPATH
5432 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5440 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5448 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5456 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
5462 template <
typename T>
void swap(T& lhs, T& rhs)
5469 template <
typename I,
typename Pred> I min_element(I begin, I end,
const Pred& pred)
5473 for (I it = begin + 1; it != end; ++it)
5474 if (pred(*it, *result))
5480 template <
typename I>
void reverse(I begin, I end)
5482 while (begin + 1 < end) swap(*begin++, *--end);
5485 template <
typename I> I unique(I begin, I end)
5488 while (begin + 1 < end && *begin != *(begin + 1)) begin++;
5490 if (begin == end)
return begin;
5496 while (begin != end)
5498 if (*begin != *write)
5499 *++write = *begin++;
5508 template <
typename I>
void copy_backwards(I begin, I end, I target)
5510 while (begin != end) *--target = *--end;
5513 template <
typename I,
typename Pred,
typename T>
void insertion_sort(I begin, I end,
const Pred& pred, T*)
5515 assert(begin != end);
5517 for (I it = begin + 1; it != end; ++it)
5521 if (pred(val, *begin))
5524 copy_backwards(begin, it, it + 1);
5532 while (pred(val, *(hole - 1)))
5534 *hole = *(hole - 1);
5545 template <
typename I,
typename Pred>
void partition(I begin, I middle, I end,
const Pred& pred, I* out_eqbeg, I* out_eqend)
5547 I eqbeg = middle, eqend = middle + 1;
5550 while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg;
5551 while (eqend != end && *eqend == *eqbeg) ++eqend;
5554 I ltend = eqbeg, gtbeg = eqend;
5559 for (; gtbeg != end; ++gtbeg)
5560 if (!pred(*eqbeg, *gtbeg))
5562 if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++);
5567 for (; ltend != begin; --ltend)
5568 if (!pred(*(ltend - 1), *eqbeg))
5570 if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg);
5575 if (gtbeg == end && ltend == begin)
5585 if (--ltend != --eqbeg) swap(*ltend, *eqbeg);
5586 swap(*eqbeg, *--eqend);
5588 else if (ltend == begin)
5590 if (eqend != gtbeg) swap(*eqbeg, *eqend);
5592 swap(*gtbeg++, *eqbeg++);
5594 else swap(*gtbeg++, *--ltend);
5598 template <
typename I,
typename Pred>
void median3(I first, I middle, I last,
const Pred& pred)
5600 if (pred(*middle, *first)) swap(*middle, *first);
5601 if (pred(*last, *middle)) swap(*last, *middle);
5602 if (pred(*middle, *first)) swap(*middle, *first);
5605 template <
typename I,
typename Pred>
void median(I first, I middle, I last,
const Pred& pred)
5607 if (last - first <= 40)
5610 median3(first, middle, last, pred);
5615 size_t step = (last - first + 1) / 8;
5617 median3(first, first + step, first + 2 * step, pred);
5618 median3(middle - step, middle, middle + step, pred);
5619 median3(last - 2 * step, last - step, last, pred);
5620 median3(first + step, middle, last - step, pred);
5624 template <
typename I,
typename Pred>
void sort(I begin, I end,
const Pred& pred)
5627 while (end - begin > 32)
5630 I middle = begin + (end - begin) / 2;
5631 median(begin, middle, end - 1, pred);
5635 partition(begin, middle, end, pred, &eqbeg, &eqend);
5638 if (eqbeg - begin > end - eqend)
5640 sort(eqend, end, pred);
5645 sort(begin, eqbeg, pred);
5651 if (begin != end) insertion_sort(begin, end, pred, &*begin);
5657 struct xpath_memory_block
5659 xpath_memory_block* next;
5662 #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
5663 PUGIXML_MEMORY_XPATH_PAGE_SIZE
5670 class xpath_allocator
5672 xpath_memory_block* _root;
5676 #ifdef PUGIXML_NO_EXCEPTIONS
5677 jmp_buf* error_handler;
5680 xpath_allocator(xpath_memory_block* root,
size_t root_size = 0): _root(root), _root_size(root_size)
5682 #ifdef PUGIXML_NO_EXCEPTIONS
5687 void* allocate_nothrow(
size_t size)
5689 const size_t block_capacity =
sizeof(_root->data);
5692 size = (size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5694 if (_root_size + size <= block_capacity)
5696 void* buf = _root->data + _root_size;
5702 size_t block_data_size = (size > block_capacity) ? size : block_capacity;
5703 size_t block_size = block_data_size + offsetof(xpath_memory_block, data);
5705 xpath_memory_block* block =
static_cast<xpath_memory_block*
>(xml_memory::allocate(block_size));
5706 if (!block)
return 0;
5708 block->next = _root;
5717 void* allocate(
size_t size)
5719 void* result = allocate_nothrow(size);
5723 #ifdef PUGIXML_NO_EXCEPTIONS
5724 assert(error_handler);
5725 longjmp(*error_handler, 1);
5727 throw std::bad_alloc();
5734 void* reallocate(
void* ptr,
size_t old_size,
size_t new_size)
5737 old_size = (old_size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5738 new_size = (new_size +
sizeof(
void*) - 1) & ~(
sizeof(
void*) - 1);
5741 assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _root->data + _root_size);
5744 bool only_object = (_root_size == old_size);
5746 if (ptr) _root_size -= old_size;
5749 void* result = allocate(new_size);
5753 if (result != ptr && ptr)
5756 assert(new_size > old_size);
5757 memcpy(result, ptr, old_size);
5762 assert(_root->data == result);
5763 assert(_root->next);
5765 xpath_memory_block* next = _root->next->next;
5770 xml_memory::deallocate(_root->next);
5779 void revert(
const xpath_allocator& state)
5782 xpath_memory_block* cur = _root;
5784 while (cur != state._root)
5786 xpath_memory_block* next = cur->next;
5788 xml_memory::deallocate(cur);
5794 _root = state._root;
5795 _root_size = state._root_size;
5800 xpath_memory_block* cur = _root;
5805 xpath_memory_block* next = cur->next;
5807 xml_memory::deallocate(cur);
5814 struct xpath_allocator_capture
5816 xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc)
5820 ~xpath_allocator_capture()
5822 _target->revert(_state);
5825 xpath_allocator* _target;
5826 xpath_allocator _state;
5831 xpath_allocator* result;
5832 xpath_allocator* temp;
5835 struct xpath_stack_data
5837 xpath_memory_block blocks[2];
5838 xpath_allocator result;
5839 xpath_allocator temp;
5842 #ifdef PUGIXML_NO_EXCEPTIONS
5843 jmp_buf error_handler;
5846 xpath_stack_data(): result(blocks + 0), temp(blocks + 1)
5848 blocks[0].next = blocks[1].next = 0;
5850 stack.result = &result;
5853 #ifdef PUGIXML_NO_EXCEPTIONS
5854 result.error_handler = temp.error_handler = &error_handler;
5870 const char_t* _buffer;
5873 static char_t* duplicate_string(
const char_t*
string,
size_t length, xpath_allocator* alloc)
5875 char_t* result =
static_cast<char_t*
>(alloc->allocate((length + 1) *
sizeof(char_t)));
5878 memcpy(result,
string, length *
sizeof(char_t));
5884 static char_t* duplicate_string(
const char_t*
string, xpath_allocator* alloc)
5886 return duplicate_string(
string, strlength(
string), alloc);
5890 xpath_string(): _buffer(PUGIXML_TEXT(
"")), _uses_heap(false)
5894 explicit xpath_string(
const char_t* str, xpath_allocator* alloc)
5896 bool empty_ = (*str == 0);
5898 _buffer = empty_ ? PUGIXML_TEXT(
"") : duplicate_string(str, alloc);
5899 _uses_heap = !empty_;
5902 explicit xpath_string(
const char_t* str,
bool use_heap): _buffer(str), _uses_heap(use_heap)
5906 xpath_string(
const char_t* begin,
const char_t* end, xpath_allocator* alloc)
5908 assert(begin <= end);
5910 bool empty_ = (begin == end);
5912 _buffer = empty_ ? PUGIXML_TEXT(
"") : duplicate_string(begin, static_cast<size_t>(end - begin), alloc);
5913 _uses_heap = !empty_;
5916 void append(
const xpath_string& o, xpath_allocator* alloc)
5919 if (!*o._buffer)
return;
5922 if (!*_buffer && !_uses_heap && !o._uses_heap)
5924 _buffer = o._buffer;
5929 size_t target_length = strlength(_buffer);
5930 size_t source_length = strlength(o._buffer);
5931 size_t result_length = target_length + source_length;
5934 char_t* result =
static_cast<char_t*
>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) *
sizeof(char_t), (result_length + 1) *
sizeof(char_t)));
5938 if (!_uses_heap) memcpy(result, _buffer, target_length *
sizeof(char_t));
5941 memcpy(result + target_length, o._buffer, source_length *
sizeof(char_t));
5942 result[result_length] = 0;
5950 const char_t* c_str()
const
5955 size_t length()
const
5957 return strlength(_buffer);
5960 char_t* data(xpath_allocator* alloc)
5965 _buffer = duplicate_string(_buffer, alloc);
5969 return const_cast<char_t*
>(_buffer);
5974 return *_buffer == 0;
5977 bool operator==(
const xpath_string& o)
const
5979 return strequal(_buffer, o._buffer);
5982 bool operator!=(
const xpath_string& o)
const
5984 return !strequal(_buffer, o._buffer);
5987 bool uses_heap()
const
5993 PUGI__FN xpath_string xpath_string_const(
const char_t* str)
5995 return xpath_string(str,
false);
6000 PUGI__FN
bool starts_with(
const char_t*
string,
const char_t* pattern)
6002 while (*pattern && *
string == *pattern)
6008 return *pattern == 0;
6011 PUGI__FN
const char_t* find_char(
const char_t* s, char_t c)
6013 #ifdef PUGIXML_WCHAR_MODE
6014 return wcschr(s, c);
6016 return strchr(s, c);
6020 PUGI__FN
const char_t* find_substring(
const char_t* s,
const char_t* p)
6022 #ifdef PUGIXML_WCHAR_MODE
6024 return (*p == 0) ? s : wcsstr(s, p);
6026 return strstr(s, p);
6031 PUGI__FN char_t tolower_ascii(char_t ch)
6033 return static_cast<unsigned int>(ch -
'A') < 26 ? static_cast<char_t>(ch |
' ') : ch;
6036 PUGI__FN xpath_string string_value(
const xpath_node& na, xpath_allocator* alloc)
6039 return xpath_string_const(na.attribute().value());
6042 const xml_node& n = na.node();
6050 return xpath_string_const(n.value());
6055 xpath_string result;
6057 xml_node cur = n.first_child();
6059 while (cur && cur != n)
6061 if (cur.type() == node_pcdata || cur.type() == node_cdata)
6062 result.append(xpath_string_const(cur.value()), alloc);
6064 if (cur.first_child())
6065 cur = cur.first_child();
6066 else if (cur.next_sibling())
6067 cur = cur.next_sibling();
6070 while (!cur.next_sibling() && cur != n)
6073 if (cur != n) cur = cur.next_sibling();
6081 return xpath_string();
6086 PUGI__FN
unsigned int node_height(xml_node n)
6088 unsigned int result = 0;
6099 PUGI__FN
bool node_is_before(xml_node ln,
unsigned int lh, xml_node rn,
unsigned int rh)
6102 for (
unsigned int i = rh; i < lh; i++) ln = ln.parent();
6103 for (
unsigned int j = lh; j < rh; j++) rn = rn.parent();
6106 if (ln == rn)
return lh < rh;
6109 while (ln.parent() != rn.parent())
6116 if (!ln.parent())
return ln < rn;
6119 for (; ln; ln = ln.next_sibling())
6126 PUGI__FN
bool node_is_ancestor(xml_node parent, xml_node node)
6128 while (node && node != parent) node = node.parent();
6130 return parent && node == parent;
6133 PUGI__FN
const void* document_order(
const xpath_node& xnode)
6135 xml_node_struct* node = xnode.node().internal_object();
6139 if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0)
return node->name;
6140 if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0)
return node->value;
6144 xml_attribute_struct* attr = xnode.attribute().internal_object();
6148 if ((attr->header & xml_memory_page_name_allocated_mask) == 0)
return attr->name;
6149 if ((attr->header & xml_memory_page_value_allocated_mask) == 0)
return attr->value;
6156 struct document_order_comparator
6158 bool operator()(
const xpath_node& lhs,
const xpath_node& rhs)
const
6161 const void* lo = document_order(lhs);
6162 const void* ro = document_order(rhs);
6164 if (lo && ro)
return lo < ro;
6167 xml_node ln = lhs.node(), rn = rhs.node();
6170 if (lhs.attribute() && rhs.attribute())
6173 if (lhs.parent() == rhs.parent())
6176 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
6177 if (a == rhs.attribute())
6187 else if (lhs.attribute())
6190 if (lhs.parent() == rhs.node())
return false;
6194 else if (rhs.attribute())
6197 if (rhs.parent() == lhs.node())
return true;
6202 if (ln == rn)
return false;
6204 unsigned int lh = node_height(ln);
6205 unsigned int rh = node_height(rn);
6207 return node_is_before(ln, lh, rn, rh);
6211 struct duplicate_comparator
6213 bool operator()(
const xpath_node& lhs,
const xpath_node& rhs)
const
6215 if (lhs.attribute())
return rhs.attribute() ? lhs.attribute() < rhs.attribute() :
true;
6216 else return rhs.attribute() ?
false : lhs.node() < rhs.node();
6220 PUGI__FN
double gen_nan()
6222 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
6223 union {
float f; uint32_t i; } u[
sizeof(float) ==
sizeof(uint32_t) ? 1 : -1];
6224 u[0].i = 0x7fc00000;
6228 const volatile double zero = 0.0;
6233 PUGI__FN
bool is_nan(
double value)
6235 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
6236 return !!_isnan(value);
6237 #elif defined(fpclassify) && defined(FP_NAN)
6238 return fpclassify(value) == FP_NAN;
6241 const volatile double v = value;
6246 PUGI__FN
const char_t* convert_number_to_string_special(
double value)
6248 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
6249 if (_finite(value))
return (value == 0) ? PUGIXML_TEXT(
"0") : 0;
6250 if (_isnan(value))
return PUGIXML_TEXT(
"NaN");
6251 return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
6252 #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
6253 switch (fpclassify(value))
6256 return PUGIXML_TEXT(
"NaN");
6259 return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
6262 return PUGIXML_TEXT(
"0");
6269 const volatile double v = value;
6271 if (v == 0)
return PUGIXML_TEXT(
"0");
6272 if (v != v)
return PUGIXML_TEXT(
"NaN");
6273 if (v * 2 == v)
return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
6278 PUGI__FN
bool convert_number_to_boolean(
double value)
6280 return (value != 0 && !is_nan(value));
6283 PUGI__FN
void truncate_zeros(
char* begin,
char* end)
6285 while (begin != end && end[-1] ==
'0') end--;
6291 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
6292 PUGI__FN
void convert_number_to_mantissa_exponent(
double value,
char* buffer,
size_t buffer_size,
char** out_mantissa,
int* out_exponent)
6296 _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign);
6299 truncate_zeros(buffer, buffer + strlen(buffer));
6302 *out_mantissa = buffer;
6303 *out_exponent = exponent;
6306 PUGI__FN
void convert_number_to_mantissa_exponent(
double value,
char* buffer,
size_t buffer_size,
char** out_mantissa,
int* out_exponent)
6309 sprintf(buffer,
"%.*e", DBL_DIG, value);
6310 assert(strlen(buffer) < buffer_size);
6314 char* exponent_string = strchr(buffer,
'e');
6315 assert(exponent_string);
6317 int exponent = atoi(exponent_string + 1);
6320 char* mantissa = buffer[0] ==
'-' ? buffer + 1 : buffer;
6321 assert(mantissa[0] !=
'0' && mantissa[1] ==
'.');
6324 mantissa[1] = mantissa[0];
6329 truncate_zeros(mantissa, exponent_string);
6332 *out_mantissa = mantissa;
6333 *out_exponent = exponent;
6337 PUGI__FN xpath_string convert_number_to_string(
double value, xpath_allocator* alloc)
6340 const char_t* special = convert_number_to_string_special(value);
6341 if (special)
return xpath_string_const(special);
6344 char mantissa_buffer[64];
6348 convert_number_to_mantissa_exponent(value, mantissa_buffer,
sizeof(mantissa_buffer), &mantissa, &exponent);
6355 if (value < 0) *s++ =
'-';
6364 while (exponent > 0)
6366 assert(*mantissa == 0 || static_cast<unsigned int>(*mantissa -
'0') <= 9);
6367 *s++ = *mantissa ? *mantissa++ :
'0';
6379 while (exponent < 0)
6388 assert(static_cast<unsigned int>(*mantissa -
'0') <= 9);
6394 assert(s < result +
sizeof(result) /
sizeof(result[0]));
6397 return xpath_string(result, alloc);
6400 PUGI__FN
bool check_string_to_number_format(
const char_t*
string)
6403 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
6406 if (*
string ==
'-') ++string;
6408 if (!*
string)
return false;
6411 if (!PUGI__IS_CHARTYPEX(
string[0], ctx_digit) && (
string[0] !=
'.' || !PUGI__IS_CHARTYPEX(
string[1], ctx_digit)))
return false;
6414 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
6421 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
6425 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
6427 return *
string == 0;
6430 PUGI__FN
double convert_string_to_number(
const char_t*
string)
6433 if (!check_string_to_number_format(
string))
return gen_nan();
6436 #ifdef PUGIXML_WCHAR_MODE
6437 return wcstod(
string, 0);
6439 return atof(
string);
6443 PUGI__FN
bool convert_string_to_number(
const char_t* begin,
const char_t* end,
double* out_result)
6447 size_t length =
static_cast<size_t>(end - begin);
6448 char_t* scratch = buffer;
6450 if (length >=
sizeof(buffer) /
sizeof(buffer[0]))
6453 scratch =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
6454 if (!scratch)
return false;
6458 memcpy(scratch, begin, length *
sizeof(char_t));
6459 scratch[length] = 0;
6461 *out_result = convert_string_to_number(scratch);
6464 if (scratch != buffer) xml_memory::deallocate(scratch);
6469 PUGI__FN
double round_nearest(
double value)
6471 return floor(value + 0.5);
6474 PUGI__FN
double round_nearest_nzero(
double value)
6478 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
6481 PUGI__FN
const char_t* qualified_name(
const xpath_node& node)
6483 return node.attribute() ? node.attribute().name() : node.node().name();
6486 PUGI__FN
const char_t* local_name(
const xpath_node& node)
6488 const char_t* name = qualified_name(node);
6489 const char_t* p = find_char(name,
':');
6491 return p ? p + 1 : name;
6494 struct namespace_uri_predicate
6496 const char_t* prefix;
6497 size_t prefix_length;
6499 namespace_uri_predicate(
const char_t* name)
6501 const char_t* pos = find_char(name,
':');
6503 prefix = pos ? name : 0;
6504 prefix_length = pos ?
static_cast<size_t>(pos - name) : 0;
6507 bool operator()(
const xml_attribute& a)
const
6509 const char_t* name = a.name();
6511 if (!starts_with(name, PUGIXML_TEXT(
"xmlns")))
return false;
6513 return prefix ? name[5] ==
':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
6517 PUGI__FN
const char_t* namespace_uri(
const xml_node& node)
6519 namespace_uri_predicate pred = node.name();
6525 xml_attribute a = p.find_attribute(pred);
6527 if (a)
return a.value();
6532 return PUGIXML_TEXT(
"");
6535 PUGI__FN
const char_t* namespace_uri(
const xml_attribute& attr,
const xml_node& parent)
6537 namespace_uri_predicate pred = attr.name();
6540 if (!pred.prefix)
return PUGIXML_TEXT(
"");
6542 xml_node p = parent;
6546 xml_attribute a = p.find_attribute(pred);
6548 if (a)
return a.value();
6553 return PUGIXML_TEXT(
"");
6556 PUGI__FN
const char_t* namespace_uri(
const xpath_node& node)
6558 return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
6561 PUGI__FN
void normalize_space(char_t* buffer)
6563 char_t* write = buffer;
6565 for (char_t* it = buffer; *it; )
6569 if (PUGI__IS_CHARTYPE(ch, ct_space))
6572 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
6575 if (write != buffer) *write++ =
' ';
6581 if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
6587 PUGI__FN
void translate(char_t* buffer,
const char_t* from,
const char_t* to)
6589 size_t to_length = strlength(to);
6591 char_t* write = buffer;
6595 PUGI__DMC_VOLATILE char_t ch = *buffer++;
6597 const char_t* pos = find_char(from, ch);
6601 else if (static_cast<size_t>(pos - from) < to_length)
6602 *write++ = to[pos - from];
6609 struct xpath_variable_boolean: xpath_variable
6611 xpath_variable_boolean(): value(false)
6619 struct xpath_variable_number: xpath_variable
6621 xpath_variable_number(): value(0)
6629 struct xpath_variable_string: xpath_variable
6631 xpath_variable_string(): value(0)
6635 ~xpath_variable_string()
6637 if (value) xml_memory::deallocate(value);
6644 struct xpath_variable_node_set: xpath_variable
6646 xpath_node_set value;
6650 static const xpath_node_set dummy_node_set;
6652 PUGI__FN
unsigned int hash_string(
const char_t* str)
6655 unsigned int result = 0;
6659 result +=
static_cast<unsigned int>(*str++);
6660 result += result << 10;
6661 result ^= result >> 6;
6664 result += result << 3;
6665 result ^= result >> 11;
6666 result += result << 15;
6671 template <
typename T> PUGI__FN T* new_xpath_variable(
const char_t* name)
6673 size_t length = strlength(name);
6674 if (length == 0)
return 0;
6677 void* memory = xml_memory::allocate(
sizeof(T) + length *
sizeof(char_t));
6678 if (!memory)
return 0;
6680 T* result =
new (memory) T();
6682 memcpy(result->name, name, (length + 1) *
sizeof(char_t));
6687 PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type,
const char_t* name)
6691 case xpath_type_node_set:
6692 return new_xpath_variable<xpath_variable_node_set>(name);
6694 case xpath_type_number:
6695 return new_xpath_variable<xpath_variable_number>(name);
6697 case xpath_type_string:
6698 return new_xpath_variable<xpath_variable_string>(name);
6700 case xpath_type_boolean:
6701 return new_xpath_variable<xpath_variable_boolean>(name);
6708 template <
typename T> PUGI__FN
void delete_xpath_variable(T* var)
6711 xml_memory::deallocate(var);
6714 PUGI__FN
void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
6718 case xpath_type_node_set:
6719 delete_xpath_variable(static_cast<xpath_variable_node_set*>(var));
6722 case xpath_type_number:
6723 delete_xpath_variable(static_cast<xpath_variable_number*>(var));
6726 case xpath_type_string:
6727 delete_xpath_variable(static_cast<xpath_variable_string*>(var));
6730 case xpath_type_boolean:
6731 delete_xpath_variable(static_cast<xpath_variable_boolean*>(var));
6735 assert(!
"Invalid variable type");
6739 PUGI__FN xpath_variable* get_variable(xpath_variable_set* set,
const char_t* begin,
const char_t* end)
6743 size_t length =
static_cast<size_t>(end - begin);
6744 char_t* scratch = buffer;
6746 if (length >=
sizeof(buffer) /
sizeof(buffer[0]))
6749 scratch =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
6750 if (!scratch)
return 0;
6754 memcpy(scratch, begin, length *
sizeof(char_t));
6755 scratch[length] = 0;
6757 xpath_variable* result = set->get(scratch);
6760 if (scratch != buffer) xml_memory::deallocate(scratch);
6768 PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type,
bool rev)
6770 xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
6772 if (type == xpath_node_set::type_unsorted)
6774 sort(begin, end, document_order_comparator());
6776 type = xpath_node_set::type_sorted;
6779 if (type != order) reverse(begin, end);
6784 PUGI__FN xpath_node xpath_first(
const xpath_node* begin,
const xpath_node* end, xpath_node_set::type_t type)
6786 if (begin == end)
return xpath_node();
6790 case xpath_node_set::type_sorted:
6793 case xpath_node_set::type_sorted_reverse:
6796 case xpath_node_set::type_unsorted:
6797 return *min_element(begin, end, document_order_comparator());
6800 assert(!
"Invalid node set type");
6801 return xpath_node();
6805 class xpath_node_set_raw
6807 xpath_node_set::type_t _type;
6814 xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0)
6818 xpath_node* begin()
const
6823 xpath_node* end()
const
6830 return _begin == _end;
6835 return static_cast<size_t>(_end - _begin);
6838 xpath_node first()
const
6840 return xpath_first(_begin, _end, _type);
6843 void push_back(
const xpath_node& node, xpath_allocator* alloc)
6847 size_t capacity =
static_cast<size_t>(_eos - _begin);
6850 size_t new_capacity = capacity + capacity / 2 + 1;
6853 xpath_node* data =
static_cast<xpath_node*
>(alloc->reallocate(_begin, capacity *
sizeof(xpath_node), new_capacity *
sizeof(xpath_node)));
6858 _end = data + capacity;
6859 _eos = data + new_capacity;
6865 void append(
const xpath_node* begin_,
const xpath_node* end_, xpath_allocator* alloc)
6867 size_t size_ =
static_cast<size_t>(_end - _begin);
6868 size_t capacity =
static_cast<size_t>(_eos - _begin);
6869 size_t count =
static_cast<size_t>(end_ - begin_);
6871 if (size_ + count > capacity)
6874 xpath_node* data =
static_cast<xpath_node*
>(alloc->reallocate(_begin, capacity *
sizeof(xpath_node), (size_ + count) *
sizeof(xpath_node)));
6879 _end = data + size_;
6880 _eos = data + size_ + count;
6883 memcpy(_end, begin_, count *
sizeof(xpath_node));
6889 _type = xpath_sort(_begin, _end, _type,
false);
6892 void truncate(xpath_node* pos)
6894 assert(_begin <= pos && pos <= _end);
6899 void remove_duplicates()
6901 if (_type == xpath_node_set::type_unsorted)
6902 sort(_begin, _end, duplicate_comparator());
6904 _end = unique(_begin, _end);
6907 xpath_node_set::type_t type()
const
6912 void set_type(xpath_node_set::type_t value)
6920 struct xpath_context
6923 size_t position, size;
6925 xpath_context(
const xpath_node& n_,
size_t position_,
size_t size_): n(n_), position(position_), size(size_)
6938 lex_greater_or_equal,
6950 lex_open_square_brace,
6951 lex_close_square_brace,
6961 struct xpath_lexer_string
6963 const char_t* begin;
6966 xpath_lexer_string(): begin(0), end(0)
6970 bool operator==(
const char_t* other)
const
6972 size_t length =
static_cast<size_t>(end - begin);
6974 return strequalrange(other, begin, length);
6981 const char_t* _cur_lexeme_pos;
6982 xpath_lexer_string _cur_lexeme_contents;
6984 lexeme_t _cur_lexeme;
6987 explicit xpath_lexer(
const char_t* query): _cur(query)
6992 const char_t* state()
const
6999 const char_t* cur = _cur;
7001 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
7004 _cur_lexeme_pos = cur;
7009 _cur_lexeme = lex_eof;
7013 if (*(cur+1) ==
'=')
7016 _cur_lexeme = lex_greater_or_equal;
7021 _cur_lexeme = lex_greater;
7026 if (*(cur+1) ==
'=')
7029 _cur_lexeme = lex_less_or_equal;
7034 _cur_lexeme = lex_less;
7039 if (*(cur+1) ==
'=')
7042 _cur_lexeme = lex_not_equal;
7046 _cur_lexeme = lex_none;
7052 _cur_lexeme = lex_equal;
7058 _cur_lexeme = lex_plus;
7064 _cur_lexeme = lex_minus;
7070 _cur_lexeme = lex_multiply;
7076 _cur_lexeme = lex_union;
7083 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
7085 _cur_lexeme_contents.begin = cur;
7087 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
7089 if (cur[0] ==
':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
7093 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
7096 _cur_lexeme_contents.end = cur;
7098 _cur_lexeme = lex_var_ref;
7102 _cur_lexeme = lex_none;
7109 _cur_lexeme = lex_open_brace;
7115 _cur_lexeme = lex_close_brace;
7121 _cur_lexeme = lex_open_square_brace;
7127 _cur_lexeme = lex_close_square_brace;
7133 _cur_lexeme = lex_comma;
7138 if (*(cur+1) ==
'/')
7141 _cur_lexeme = lex_double_slash;
7146 _cur_lexeme = lex_slash;
7151 if (*(cur+1) ==
'.')
7154 _cur_lexeme = lex_double_dot;
7156 else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
7158 _cur_lexeme_contents.begin = cur;
7162 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
7164 _cur_lexeme_contents.end = cur;
7166 _cur_lexeme = lex_number;
7171 _cur_lexeme = lex_dot;
7177 _cur_lexeme = lex_axis_attribute;
7184 char_t terminator = *cur;
7188 _cur_lexeme_contents.begin = cur;
7189 while (*cur && *cur != terminator) cur++;
7190 _cur_lexeme_contents.end = cur;
7193 _cur_lexeme = lex_none;
7197 _cur_lexeme = lex_quoted_string;
7204 if (*(cur+1) ==
':')
7207 _cur_lexeme = lex_double_colon;
7211 _cur_lexeme = lex_none;
7216 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
7218 _cur_lexeme_contents.begin = cur;
7220 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
7226 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
7229 _cur_lexeme_contents.end = cur;
7231 _cur_lexeme = lex_number;
7233 else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
7235 _cur_lexeme_contents.begin = cur;
7237 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
7245 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
7249 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
7253 _cur_lexeme_contents.end = cur;
7255 _cur_lexeme = lex_string;
7259 _cur_lexeme = lex_none;
7266 lexeme_t current()
const
7271 const char_t* current_pos()
const
7273 return _cur_lexeme_pos;
7276 const xpath_lexer_string& contents()
const
7278 assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
7280 return _cur_lexeme_contents;
7292 ast_op_less_or_equal,
7293 ast_op_greater_or_equal,
7304 ast_string_constant,
7305 ast_number_constant,
7311 ast_func_local_name_0,
7312 ast_func_local_name_1,
7313 ast_func_namespace_uri_0,
7314 ast_func_namespace_uri_1,
7320 ast_func_starts_with,
7322 ast_func_substring_before,
7323 ast_func_substring_after,
7324 ast_func_substring_2,
7325 ast_func_substring_3,
7326 ast_func_string_length_0,
7327 ast_func_string_length_1,
7328 ast_func_normalize_space_0,
7329 ast_func_normalize_space_1,
7349 axis_ancestor_or_self,
7353 axis_descendant_or_self,
7355 axis_following_sibling,
7359 axis_preceding_sibling,
7368 nodetest_type_comment,
7373 nodetest_all_in_namespace
7376 template <axis_t N>
struct axis_to_type
7378 static const axis_t axis;
7381 template <axis_t N>
const axis_t axis_to_type<N>::axis = N;
7383 class xpath_ast_node
7395 xpath_ast_node* _left;
7396 xpath_ast_node* _right;
7397 xpath_ast_node* _next;
7402 const char_t* string;
7406 xpath_variable* variable;
7408 const char_t* nodetest;
7411 xpath_ast_node(
const xpath_ast_node&);
7412 xpath_ast_node& operator=(
const xpath_ast_node&);
7414 template <
class Comp>
static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs,
const xpath_context& c,
const xpath_stack& stack,
const Comp& comp)
7416 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
7418 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
7420 if (lt == xpath_type_boolean || rt == xpath_type_boolean)
7421 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7422 else if (lt == xpath_type_number || rt == xpath_type_number)
7423 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7424 else if (lt == xpath_type_string || rt == xpath_type_string)
7426 xpath_allocator_capture cr(stack.result);
7428 xpath_string ls = lhs->eval_string(c, stack);
7429 xpath_string rs = rhs->eval_string(c, stack);
7431 return comp(ls, rs);
7434 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
7436 xpath_allocator_capture cr(stack.result);
7438 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
7439 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7441 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li)
7442 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7444 xpath_allocator_capture cri(stack.result);
7446 if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
7454 if (lt == xpath_type_node_set)
7460 if (lt == xpath_type_boolean)
7461 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
7462 else if (lt == xpath_type_number)
7464 xpath_allocator_capture cr(stack.result);
7466 double l = lhs->eval_number(c, stack);
7467 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7469 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7471 xpath_allocator_capture cri(stack.result);
7473 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
7479 else if (lt == xpath_type_string)
7481 xpath_allocator_capture cr(stack.result);
7483 xpath_string l = lhs->eval_string(c, stack);
7484 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7486 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7488 xpath_allocator_capture cri(stack.result);
7490 if (comp(l, string_value(*ri, stack.result)))
7498 assert(!
"Wrong types");
7502 template <
class Comp>
static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs,
const xpath_context& c,
const xpath_stack& stack,
const Comp& comp)
7504 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
7506 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
7507 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
7508 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
7510 xpath_allocator_capture cr(stack.result);
7512 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
7513 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7515 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li)
7517 xpath_allocator_capture cri(stack.result);
7519 double l = convert_string_to_number(string_value(*li, stack.result).c_str());
7521 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7523 xpath_allocator_capture crii(stack.result);
7525 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
7532 else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
7534 xpath_allocator_capture cr(stack.result);
7536 double l = lhs->eval_number(c, stack);
7537 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
7539 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
7541 xpath_allocator_capture cri(stack.result);
7543 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
7549 else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
7551 xpath_allocator_capture cr(stack.result);
7553 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
7554 double r = rhs->eval_number(c, stack);
7556 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li)
7558 xpath_allocator_capture cri(stack.result);
7560 if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
7568 assert(!
"Wrong types");
7573 void apply_predicate(xpath_node_set_raw& ns,
size_t first, xpath_ast_node* expr,
const xpath_stack& stack)
7575 assert(ns.size() >= first);
7578 size_t size = ns.size() - first;
7580 xpath_node* last = ns.begin() + first;
7583 for (xpath_node* it = last; it != ns.end(); ++it, ++i)
7585 xpath_context c(*it, i, size);
7587 if (expr->rettype() == xpath_type_number)
7589 if (expr->eval_number(c, stack) == i)
7592 else if (expr->eval_boolean(c, stack))
7599 void apply_predicates(xpath_node_set_raw& ns,
size_t first,
const xpath_stack& stack)
7601 if (ns.size() == first)
return;
7603 for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
7605 apply_predicate(ns, first, pred->_left, stack);
7609 void step_push(xpath_node_set_raw& ns,
const xml_attribute& a,
const xml_node& parent, xpath_allocator* alloc)
7613 const char_t* name = a.name();
7617 if (starts_with(name, PUGIXML_TEXT(
"xmlns")) && (name[5] == 0 || name[5] ==
':'))
return;
7622 if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc);
7625 case nodetest_type_node:
7627 ns.push_back(xpath_node(a, parent), alloc);
7630 case nodetest_all_in_namespace:
7631 if (starts_with(name, _data.nodetest))
7632 ns.push_back(xpath_node(a, parent), alloc);
7640 void step_push(xpath_node_set_raw& ns,
const xml_node& n, xpath_allocator* alloc)
7647 if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc);
7650 case nodetest_type_node:
7651 ns.push_back(n, alloc);
7654 case nodetest_type_comment:
7655 if (n.type() == node_comment)
7656 ns.push_back(n, alloc);
7659 case nodetest_type_text:
7660 if (n.type() == node_pcdata || n.type() == node_cdata)
7661 ns.push_back(n, alloc);
7664 case nodetest_type_pi:
7665 if (n.type() == node_pi)
7666 ns.push_back(n, alloc);
7670 if (n.type() == node_pi && strequal(n.name(), _data.nodetest))
7671 ns.push_back(n, alloc);
7675 if (n.type() == node_element)
7676 ns.push_back(n, alloc);
7679 case nodetest_all_in_namespace:
7680 if (n.type() == node_element && starts_with(n.name(), _data.nodetest))
7681 ns.push_back(n, alloc);
7685 assert(!
"Unknown axis");
7689 template <
class T>
void step_fill(xpath_node_set_raw& ns,
const xml_node& n, xpath_allocator* alloc, T)
7691 const axis_t axis = T::axis;
7695 case axis_attribute:
7697 for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute())
7698 step_push(ns, a, n, alloc);
7705 for (xml_node c = n.first_child(); c; c = c.next_sibling())
7706 step_push(ns, c, alloc);
7711 case axis_descendant:
7712 case axis_descendant_or_self:
7714 if (axis == axis_descendant_or_self)
7715 step_push(ns, n, alloc);
7717 xml_node cur = n.first_child();
7719 while (cur && cur != n)
7721 step_push(ns, cur, alloc);
7723 if (cur.first_child())
7724 cur = cur.first_child();
7725 else if (cur.next_sibling())
7726 cur = cur.next_sibling();
7729 while (!cur.next_sibling() && cur != n)
7732 if (cur != n) cur = cur.next_sibling();
7739 case axis_following_sibling:
7741 for (xml_node c = n.next_sibling(); c; c = c.next_sibling())
7742 step_push(ns, c, alloc);
7747 case axis_preceding_sibling:
7749 for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling())
7750 step_push(ns, c, alloc);
7755 case axis_following:
7760 while (cur && !cur.next_sibling()) cur = cur.parent();
7761 cur = cur.next_sibling();
7765 step_push(ns, cur, alloc);
7767 if (cur.first_child())
7768 cur = cur.first_child();
7769 else if (cur.next_sibling())
7770 cur = cur.next_sibling();
7773 while (cur && !cur.next_sibling()) cur = cur.parent();
7774 cur = cur.next_sibling();
7783 case axis_preceding:
7787 while (cur && !cur.previous_sibling()) cur = cur.parent();
7788 cur = cur.previous_sibling();
7792 if (cur.last_child())
7793 cur = cur.last_child();
7797 step_push(ns, cur, alloc);
7799 if (cur.previous_sibling())
7800 cur = cur.previous_sibling();
7808 if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc);
7810 while (!cur.previous_sibling());
7812 cur = cur.previous_sibling();
7823 case axis_ancestor_or_self:
7825 if (axis == axis_ancestor_or_self)
7826 step_push(ns, n, alloc);
7828 xml_node cur = n.parent();
7832 step_push(ns, cur, alloc);
7842 step_push(ns, n, alloc);
7849 if (n.parent()) step_push(ns, n.parent(), alloc);
7855 assert(!
"Unimplemented axis");
7859 template <
class T>
void step_fill(xpath_node_set_raw& ns,
const xml_attribute& a,
const xml_node& p, xpath_allocator* alloc, T v)
7861 const axis_t axis = T::axis;
7866 case axis_ancestor_or_self:
7868 if (axis == axis_ancestor_or_self && _test == nodetest_type_node)
7869 step_push(ns, a, p, alloc);
7875 step_push(ns, cur, alloc);
7883 case axis_descendant_or_self:
7886 if (_test == nodetest_type_node)
7887 step_push(ns, a, p, alloc);
7892 case axis_following:
7898 if (cur.first_child())
7899 cur = cur.first_child();
7900 else if (cur.next_sibling())
7901 cur = cur.next_sibling();
7904 while (cur && !cur.next_sibling()) cur = cur.parent();
7905 cur = cur.next_sibling();
7910 step_push(ns, cur, alloc);
7918 step_push(ns, p, alloc);
7923 case axis_preceding:
7926 step_fill(ns, p, alloc, v);
7931 assert(!
"Unimplemented axis");
7935 template <
class T> xpath_node_set_raw step_do(
const xpath_context& c,
const xpath_stack& stack, T v)
7937 const axis_t axis = T::axis;
7938 bool attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
7940 xpath_node_set_raw ns;
7941 ns.set_type((axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling) ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted);
7945 xpath_node_set_raw s = _left->eval_node_set(c, stack);
7948 if (axis == axis_self) ns.set_type(s.type());
7950 for (
const xpath_node* it = s.begin(); it != s.end(); ++it)
7952 size_t size = ns.size();
7955 if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
7958 step_fill(ns, it->node(), stack.result, v);
7959 else if (attributes)
7960 step_fill(ns, it->attribute(), it->parent(), stack.result, v);
7962 apply_predicates(ns, size, stack);
7968 step_fill(ns, c.n.node(), stack.result, v);
7969 else if (attributes)
7970 step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v);
7972 apply_predicates(ns, 0, stack);
7977 if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)
7978 ns.remove_duplicates();
7984 xpath_ast_node(ast_type_t type, xpath_value_type rettype_,
const char_t* value):
7985 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7987 assert(type == ast_string_constant);
7988 _data.string = value;
7991 xpath_ast_node(ast_type_t type, xpath_value_type rettype_,
double value):
7992 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
7994 assert(type == ast_number_constant);
7995 _data.number = value;
7998 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):
7999 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
8001 assert(type == ast_variable);
8002 _data.variable = value;
8005 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0):
8006 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
8010 xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test,
const char_t* contents):
8011 _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(0), _next(0)
8013 _data.nodetest = contents;
8016 void set_next(xpath_ast_node* value)
8021 void set_right(xpath_ast_node* value)
8026 bool eval_boolean(
const xpath_context& c,
const xpath_stack& stack)
8031 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
8034 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
8037 return compare_eq(_left, _right, c, stack, equal_to());
8039 case ast_op_not_equal:
8040 return compare_eq(_left, _right, c, stack, not_equal_to());
8043 return compare_rel(_left, _right, c, stack, less());
8045 case ast_op_greater:
8046 return compare_rel(_right, _left, c, stack, less());
8048 case ast_op_less_or_equal:
8049 return compare_rel(_left, _right, c, stack, less_equal());
8051 case ast_op_greater_or_equal:
8052 return compare_rel(_right, _left, c, stack, less_equal());
8054 case ast_func_starts_with:
8056 xpath_allocator_capture cr(stack.result);
8058 xpath_string lr = _left->eval_string(c, stack);
8059 xpath_string rr = _right->eval_string(c, stack);
8061 return starts_with(lr.c_str(), rr.c_str());
8064 case ast_func_contains:
8066 xpath_allocator_capture cr(stack.result);
8068 xpath_string lr = _left->eval_string(c, stack);
8069 xpath_string rr = _right->eval_string(c, stack);
8071 return find_substring(lr.c_str(), rr.c_str()) != 0;
8074 case ast_func_boolean:
8075 return _left->eval_boolean(c, stack);
8078 return !_left->eval_boolean(c, stack);
8083 case ast_func_false:
8088 if (c.n.attribute())
return false;
8090 xpath_allocator_capture cr(stack.result);
8092 xpath_string lang = _left->eval_string(c, stack);
8094 for (xml_node n = c.n.node(); n; n = n.parent())
8096 xml_attribute a = n.attribute(PUGIXML_TEXT(
"xml:lang"));
8100 const char_t* value = a.value();
8103 for (
const char_t* lit = lang.c_str(); *lit; ++lit)
8105 if (tolower_ascii(*lit) != tolower_ascii(*value))
return false;
8109 return *value == 0 || *value ==
'-';
8118 assert(_rettype == _data.variable->type());
8120 if (_rettype == xpath_type_boolean)
8121 return _data.variable->get_boolean();
8130 case xpath_type_number:
8131 return convert_number_to_boolean(eval_number(c, stack));
8133 case xpath_type_string:
8135 xpath_allocator_capture cr(stack.result);
8137 return !eval_string(c, stack).empty();
8140 case xpath_type_node_set:
8142 xpath_allocator_capture cr(stack.result);
8144 return !eval_node_set(c, stack).empty();
8148 assert(!
"Wrong expression for return type boolean");
8155 double eval_number(
const xpath_context& c,
const xpath_stack& stack)
8160 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
8162 case ast_op_subtract:
8163 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
8165 case ast_op_multiply:
8166 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
8169 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
8172 return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
8175 return -_left->eval_number(c, stack);
8177 case ast_number_constant:
8178 return _data.number;
8181 return static_cast<double>(c.size);
8183 case ast_func_position:
8184 return static_cast<double>(c.position);
8186 case ast_func_count:
8188 xpath_allocator_capture cr(stack.result);
8190 return static_cast<double>(_left->eval_node_set(c, stack).size());
8193 case ast_func_string_length_0:
8195 xpath_allocator_capture cr(stack.result);
8197 return static_cast<double>(string_value(c.n, stack.result).length());
8200 case ast_func_string_length_1:
8202 xpath_allocator_capture cr(stack.result);
8204 return static_cast<double>(_left->eval_string(c, stack).length());
8207 case ast_func_number_0:
8209 xpath_allocator_capture cr(stack.result);
8211 return convert_string_to_number(string_value(c.n, stack.result).c_str());
8214 case ast_func_number_1:
8215 return _left->eval_number(c, stack);
8219 xpath_allocator_capture cr(stack.result);
8223 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8225 for (
const xpath_node* it = ns.begin(); it != ns.end(); ++it)
8227 xpath_allocator_capture cri(stack.result);
8229 r += convert_string_to_number(string_value(*it, stack.result).c_str());
8235 case ast_func_floor:
8237 double r = _left->eval_number(c, stack);
8239 return r == r ? floor(r) : r;
8242 case ast_func_ceiling:
8244 double r = _left->eval_number(c, stack);
8246 return r == r ? ceil(r) : r;
8249 case ast_func_round:
8250 return round_nearest_nzero(_left->eval_number(c, stack));
8254 assert(_rettype == _data.variable->type());
8256 if (_rettype == xpath_type_number)
8257 return _data.variable->get_number();
8266 case xpath_type_boolean:
8267 return eval_boolean(c, stack) ? 1 : 0;
8269 case xpath_type_string:
8271 xpath_allocator_capture cr(stack.result);
8273 return convert_string_to_number(eval_string(c, stack).c_str());
8276 case xpath_type_node_set:
8278 xpath_allocator_capture cr(stack.result);
8280 return convert_string_to_number(eval_string(c, stack).c_str());
8284 assert(!
"Wrong expression for return type number");
8292 xpath_string eval_string_concat(
const xpath_context& c,
const xpath_stack& stack)
8294 assert(_type == ast_func_concat);
8296 xpath_allocator_capture ct(stack.temp);
8300 for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
8303 xpath_string static_buffer[4];
8304 xpath_string* buffer = static_buffer;
8307 if (count >
sizeof(static_buffer) /
sizeof(static_buffer[0]))
8309 buffer =
static_cast<xpath_string*
>(stack.temp->allocate(count *
sizeof(xpath_string)));
8314 xpath_stack swapped_stack = {stack.temp, stack.result};
8316 buffer[0] = _left->eval_string(c, swapped_stack);
8319 for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
8320 assert(pos == count);
8324 for (
size_t i = 0; i < count; ++i) length += buffer[i].length();
8327 char_t* result =
static_cast<char_t*
>(stack.result->allocate((length + 1) *
sizeof(char_t)));
8330 char_t* ri = result;
8332 for (
size_t j = 0; j < count; ++j)
8333 for (
const char_t* bi = buffer[j].c_str(); *bi; ++bi)
8338 return xpath_string(result,
true);
8341 xpath_string eval_string(
const xpath_context& c,
const xpath_stack& stack)
8345 case ast_string_constant:
8346 return xpath_string_const(_data.string);
8348 case ast_func_local_name_0:
8350 xpath_node na = c.n;
8352 return xpath_string_const(local_name(na));
8355 case ast_func_local_name_1:
8357 xpath_allocator_capture cr(stack.result);
8359 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8360 xpath_node na = ns.first();
8362 return xpath_string_const(local_name(na));
8365 case ast_func_name_0:
8367 xpath_node na = c.n;
8369 return xpath_string_const(qualified_name(na));
8372 case ast_func_name_1:
8374 xpath_allocator_capture cr(stack.result);
8376 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8377 xpath_node na = ns.first();
8379 return xpath_string_const(qualified_name(na));
8382 case ast_func_namespace_uri_0:
8384 xpath_node na = c.n;
8386 return xpath_string_const(namespace_uri(na));
8389 case ast_func_namespace_uri_1:
8391 xpath_allocator_capture cr(stack.result);
8393 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
8394 xpath_node na = ns.first();
8396 return xpath_string_const(namespace_uri(na));
8399 case ast_func_string_0:
8400 return string_value(c.n, stack.result);
8402 case ast_func_string_1:
8403 return _left->eval_string(c, stack);
8405 case ast_func_concat:
8406 return eval_string_concat(c, stack);
8408 case ast_func_substring_before:
8410 xpath_allocator_capture cr(stack.temp);
8412 xpath_stack swapped_stack = {stack.temp, stack.result};
8414 xpath_string s = _left->eval_string(c, swapped_stack);
8415 xpath_string p = _right->eval_string(c, swapped_stack);
8417 const char_t* pos = find_substring(s.c_str(), p.c_str());
8419 return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string();
8422 case ast_func_substring_after:
8424 xpath_allocator_capture cr(stack.temp);
8426 xpath_stack swapped_stack = {stack.temp, stack.result};
8428 xpath_string s = _left->eval_string(c, swapped_stack);
8429 xpath_string p = _right->eval_string(c, swapped_stack);
8431 const char_t* pos = find_substring(s.c_str(), p.c_str());
8432 if (!pos)
return xpath_string();
8434 const char_t* result = pos + p.length();
8436 return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result);
8439 case ast_func_substring_2:
8441 xpath_allocator_capture cr(stack.temp);
8443 xpath_stack swapped_stack = {stack.temp, stack.result};
8445 xpath_string s = _left->eval_string(c, swapped_stack);
8446 size_t s_length = s.length();
8448 double first = round_nearest(_right->eval_number(c, stack));
8450 if (is_nan(first))
return xpath_string();
8451 else if (first >= s_length + 1)
return xpath_string();
8453 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8454 assert(1 <= pos && pos <= s_length + 1);
8456 const char_t* rbegin = s.c_str() + (pos - 1);
8458 return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin);
8461 case ast_func_substring_3:
8463 xpath_allocator_capture cr(stack.temp);
8465 xpath_stack swapped_stack = {stack.temp, stack.result};
8467 xpath_string s = _left->eval_string(c, swapped_stack);
8468 size_t s_length = s.length();
8470 double first = round_nearest(_right->eval_number(c, stack));
8471 double last = first + round_nearest(_right->_next->eval_number(c, stack));
8473 if (is_nan(first) || is_nan(last))
return xpath_string();
8474 else if (first >= s_length + 1)
return xpath_string();
8475 else if (first >= last)
return xpath_string();
8476 else if (last < 1)
return xpath_string();
8478 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
8479 size_t end = last >= s_length + 1 ? s_length + 1 :
static_cast<size_t>(last);
8481 assert(1 <= pos && pos <= end && end <= s_length + 1);
8482 const char_t* rbegin = s.c_str() + (pos - 1);
8483 const char_t* rend = s.c_str() + (end - 1);
8485 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result);
8488 case ast_func_normalize_space_0:
8490 xpath_string s = string_value(c.n, stack.result);
8492 normalize_space(s.data(stack.result));
8497 case ast_func_normalize_space_1:
8499 xpath_string s = _left->eval_string(c, stack);
8501 normalize_space(s.data(stack.result));
8506 case ast_func_translate:
8508 xpath_allocator_capture cr(stack.temp);
8510 xpath_stack swapped_stack = {stack.temp, stack.result};
8512 xpath_string s = _left->eval_string(c, stack);
8513 xpath_string from = _right->eval_string(c, swapped_stack);
8514 xpath_string to = _right->_next->eval_string(c, swapped_stack);
8516 translate(s.data(stack.result), from.c_str(), to.c_str());
8523 assert(_rettype == _data.variable->type());
8525 if (_rettype == xpath_type_string)
8526 return xpath_string_const(_data.variable->get_string());
8535 case xpath_type_boolean:
8536 return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT(
"true") : PUGIXML_TEXT(
"false"));
8538 case xpath_type_number:
8539 return convert_number_to_string(eval_number(c, stack), stack.result);
8541 case xpath_type_node_set:
8543 xpath_allocator_capture cr(stack.temp);
8545 xpath_stack swapped_stack = {stack.temp, stack.result};
8547 xpath_node_set_raw ns = eval_node_set(c, swapped_stack);
8548 return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
8552 assert(!
"Wrong expression for return type string");
8553 return xpath_string();
8559 xpath_node_set_raw eval_node_set(
const xpath_context& c,
const xpath_stack& stack)
8565 xpath_allocator_capture cr(stack.temp);
8567 xpath_stack swapped_stack = {stack.temp, stack.result};
8569 xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack);
8570 xpath_node_set_raw rs = _right->eval_node_set(c, stack);
8573 rs.set_type(xpath_node_set::type_unsorted);
8575 rs.append(ls.begin(), ls.end(), stack.result);
8576 rs.remove_duplicates();
8582 case ast_filter_posinv:
8584 xpath_node_set_raw set = _left->eval_node_set(c, stack);
8587 if (_type == ast_filter) set.sort_do();
8589 apply_predicate(set, 0, _right, stack);
8595 return xpath_node_set_raw();
8602 return step_do(c, stack, axis_to_type<axis_ancestor>());
8604 case axis_ancestor_or_self:
8605 return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());
8607 case axis_attribute:
8608 return step_do(c, stack, axis_to_type<axis_attribute>());
8611 return step_do(c, stack, axis_to_type<axis_child>());
8613 case axis_descendant:
8614 return step_do(c, stack, axis_to_type<axis_descendant>());
8616 case axis_descendant_or_self:
8617 return step_do(c, stack, axis_to_type<axis_descendant_or_self>());
8619 case axis_following:
8620 return step_do(c, stack, axis_to_type<axis_following>());
8622 case axis_following_sibling:
8623 return step_do(c, stack, axis_to_type<axis_following_sibling>());
8625 case axis_namespace:
8627 return xpath_node_set_raw();
8630 return step_do(c, stack, axis_to_type<axis_parent>());
8632 case axis_preceding:
8633 return step_do(c, stack, axis_to_type<axis_preceding>());
8635 case axis_preceding_sibling:
8636 return step_do(c, stack, axis_to_type<axis_preceding_sibling>());
8639 return step_do(c, stack, axis_to_type<axis_self>());
8642 assert(!
"Unknown axis");
8643 return xpath_node_set_raw();
8651 xpath_node_set_raw ns;
8653 ns.set_type(xpath_node_set::type_sorted);
8655 if (c.n.node()) ns.push_back(c.n.node().root(), stack.result);
8656 else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);
8663 assert(_rettype == _data.variable->type());
8665 if (_rettype == xpath_type_node_set)
8667 const xpath_node_set& s = _data.variable->get_node_set();
8669 xpath_node_set_raw ns;
8671 ns.set_type(s.type());
8672 ns.append(s.begin(), s.end(), stack.result);
8681 assert(!
"Wrong expression for return type node set");
8682 return xpath_node_set_raw();
8690 case ast_func_position:
8693 case ast_string_constant:
8694 case ast_number_constant:
8704 case ast_filter_posinv:
8708 if (_left && !_left->is_posinv())
return false;
8710 for (xpath_ast_node* n = _right; n; n = n->_next)
8711 if (!n->is_posinv())
return false;
8717 xpath_value_type rettype()
const
8719 return static_cast<xpath_value_type
>(_rettype);
8725 xpath_allocator* _alloc;
8728 const char_t* _query;
8729 xpath_variable_set* _variables;
8731 xpath_parse_result* _result;
8733 #ifdef PUGIXML_NO_EXCEPTIONS
8734 jmp_buf _error_handler;
8737 void throw_error(
const char* message)
8739 _result->error = message;
8740 _result->offset = _lexer.current_pos() - _query;
8742 #ifdef PUGIXML_NO_EXCEPTIONS
8743 longjmp(_error_handler, 1);
8745 throw xpath_exception(*_result);
8749 void throw_error_oom()
8751 #ifdef PUGIXML_NO_EXCEPTIONS
8752 throw_error(
"Out of memory");
8754 throw std::bad_alloc();
8760 void* result = _alloc->allocate_nothrow(
sizeof(xpath_ast_node));
8762 if (!result) throw_error_oom();
8767 const char_t* alloc_string(
const xpath_lexer_string& value)
8771 size_t length =
static_cast<size_t>(value.end - value.begin);
8773 char_t* c =
static_cast<char_t*
>(_alloc->allocate_nothrow((length + 1) *
sizeof(char_t)));
8774 if (!c) throw_error_oom();
8776 memcpy(c, value.begin, length *
sizeof(char_t));
8784 xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1,
size_t argc, xpath_ast_node* args[2])
8788 if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error(
"Function has to be applied to node set");
8790 return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
8793 xpath_ast_node* parse_function(
const xpath_lexer_string& name,
size_t argc, xpath_ast_node* args[2])
8795 switch (name.begin[0])
8798 if (name == PUGIXML_TEXT(
"boolean") && argc == 1)
8799 return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]);
8804 if (name == PUGIXML_TEXT(
"count") && argc == 1)
8806 if (args[0]->rettype() != xpath_type_node_set) throw_error(
"Function has to be applied to node set");
8807 return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]);
8809 else if (name == PUGIXML_TEXT(
"contains") && argc == 2)
8810 return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]);
8811 else if (name == PUGIXML_TEXT(
"concat") && argc >= 2)
8812 return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]);
8813 else if (name == PUGIXML_TEXT(
"ceiling") && argc == 1)
8814 return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]);
8819 if (name == PUGIXML_TEXT(
"false") && argc == 0)
8820 return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean);
8821 else if (name == PUGIXML_TEXT(
"floor") && argc == 1)
8822 return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]);
8827 if (name == PUGIXML_TEXT(
"id") && argc == 1)
8828 return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]);
8833 if (name == PUGIXML_TEXT(
"last") && argc == 0)
8834 return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number);
8835 else if (name == PUGIXML_TEXT(
"lang") && argc == 1)
8836 return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]);
8837 else if (name == PUGIXML_TEXT(
"local-name") && argc <= 1)
8838 return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args);
8843 if (name == PUGIXML_TEXT(
"name") && argc <= 1)
8844 return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args);
8845 else if (name == PUGIXML_TEXT(
"namespace-uri") && argc <= 1)
8846 return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args);
8847 else if (name == PUGIXML_TEXT(
"normalize-space") && argc <= 1)
8848 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);
8849 else if (name == PUGIXML_TEXT(
"not") && argc == 1)
8850 return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]);
8851 else if (name == PUGIXML_TEXT(
"number") && argc <= 1)
8852 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
8857 if (name == PUGIXML_TEXT(
"position") && argc == 0)
8858 return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number);
8863 if (name == PUGIXML_TEXT(
"round") && argc == 1)
8864 return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]);
8869 if (name == PUGIXML_TEXT(
"string") && argc <= 1)
8870 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
8871 else if (name == PUGIXML_TEXT(
"string-length") && argc <= 1)
8872 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]);
8873 else if (name == PUGIXML_TEXT(
"starts-with") && argc == 2)
8874 return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
8875 else if (name == PUGIXML_TEXT(
"substring-before") && argc == 2)
8876 return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
8877 else if (name == PUGIXML_TEXT(
"substring-after") && argc == 2)
8878 return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
8879 else if (name == PUGIXML_TEXT(
"substring") && (argc == 2 || argc == 3))
8880 return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
8881 else if (name == PUGIXML_TEXT(
"sum") && argc == 1)
8883 if (args[0]->rettype() != xpath_type_node_set) throw_error(
"Function has to be applied to node set");
8884 return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]);
8890 if (name == PUGIXML_TEXT(
"translate") && argc == 3)
8891 return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]);
8892 else if (name == PUGIXML_TEXT(
"true") && argc == 0)
8893 return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean);
8901 throw_error(
"Unrecognized function or wrong parameter count");
8906 axis_t parse_axis_name(
const xpath_lexer_string& name,
bool& specified)
8910 switch (name.begin[0])
8913 if (name == PUGIXML_TEXT(
"ancestor"))
8914 return axis_ancestor;
8915 else if (name == PUGIXML_TEXT(
"ancestor-or-self"))
8916 return axis_ancestor_or_self;
8917 else if (name == PUGIXML_TEXT(
"attribute"))
8918 return axis_attribute;
8923 if (name == PUGIXML_TEXT(
"child"))
8929 if (name == PUGIXML_TEXT(
"descendant"))
8930 return axis_descendant;
8931 else if (name == PUGIXML_TEXT(
"descendant-or-self"))
8932 return axis_descendant_or_self;
8937 if (name == PUGIXML_TEXT(
"following"))
8938 return axis_following;
8939 else if (name == PUGIXML_TEXT(
"following-sibling"))
8940 return axis_following_sibling;
8945 if (name == PUGIXML_TEXT(
"namespace"))
8946 return axis_namespace;
8951 if (name == PUGIXML_TEXT(
"parent"))
8953 else if (name == PUGIXML_TEXT(
"preceding"))
8954 return axis_preceding;
8955 else if (name == PUGIXML_TEXT(
"preceding-sibling"))
8956 return axis_preceding_sibling;
8961 if (name == PUGIXML_TEXT(
"self"))
8974 nodetest_t parse_node_test_type(
const xpath_lexer_string& name)
8976 switch (name.begin[0])
8979 if (name == PUGIXML_TEXT(
"comment"))
8980 return nodetest_type_comment;
8985 if (name == PUGIXML_TEXT(
"node"))
8986 return nodetest_type_node;
8991 if (name == PUGIXML_TEXT(
"processing-instruction"))
8992 return nodetest_type_pi;
8997 if (name == PUGIXML_TEXT(
"text"))
8998 return nodetest_type_text;
9006 return nodetest_none;
9010 xpath_ast_node* parse_primary_expression()
9012 switch (_lexer.current())
9016 xpath_lexer_string name = _lexer.contents();
9019 throw_error(
"Unknown variable: variable set is not provided");
9021 xpath_variable* var = get_variable(_variables, name.begin, name.end);
9024 throw_error(
"Unknown variable: variable set does not contain the given name");
9028 return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
9031 case lex_open_brace:
9035 xpath_ast_node* n = parse_expression();
9037 if (_lexer.current() != lex_close_brace)
9038 throw_error(
"Unmatched braces");
9045 case lex_quoted_string:
9047 const char_t* value = alloc_string(_lexer.contents());
9049 xpath_ast_node* n =
new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value);
9059 if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value))
9062 xpath_ast_node* n =
new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value);
9070 xpath_ast_node* args[2] = {0};
9073 xpath_lexer_string
function = _lexer.contents();
9076 xpath_ast_node* last_arg = 0;
9078 if (_lexer.current() != lex_open_brace)
9079 throw_error(
"Unrecognized function call");
9082 if (_lexer.current() != lex_close_brace)
9083 args[argc++] = parse_expression();
9085 while (_lexer.current() != lex_close_brace)
9087 if (_lexer.current() != lex_comma)
9088 throw_error(
"No comma between function arguments");
9091 xpath_ast_node* n = parse_expression();
9093 if (argc < 2) args[argc] = n;
9094 else last_arg->set_next(n);
9102 return parse_function(
function, argc, args);
9106 throw_error(
"Unrecognizable primary expression");
9115 xpath_ast_node* parse_filter_expression()
9117 xpath_ast_node* n = parse_primary_expression();
9119 while (_lexer.current() == lex_open_square_brace)
9123 xpath_ast_node* expr = parse_expression();
9125 if (n->rettype() != xpath_type_node_set) throw_error(
"Predicate has to be applied to node set");
9127 bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv();
9129 n =
new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr);
9131 if (_lexer.current() != lex_close_square_brace)
9132 throw_error(
"Unmatched square brace");
9145 xpath_ast_node* parse_step(xpath_ast_node* set)
9147 if (set && set->rettype() != xpath_type_node_set)
9148 throw_error(
"Step has to be applied to node set");
9150 bool axis_specified =
false;
9151 axis_t axis = axis_child;
9153 if (_lexer.current() == lex_axis_attribute)
9155 axis = axis_attribute;
9156 axis_specified =
true;
9160 else if (_lexer.current() == lex_dot)
9164 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0);
9166 else if (_lexer.current() == lex_double_dot)
9170 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0);
9173 nodetest_t nt_type = nodetest_none;
9174 xpath_lexer_string nt_name;
9176 if (_lexer.current() == lex_string)
9179 nt_name = _lexer.contents();
9183 if (_lexer.current() == lex_double_colon)
9186 if (axis_specified) throw_error(
"Two axis specifiers in one step");
9188 axis = parse_axis_name(nt_name, axis_specified);
9190 if (!axis_specified) throw_error(
"Unknown axis");
9195 if (_lexer.current() == lex_multiply)
9197 nt_type = nodetest_all;
9198 nt_name = xpath_lexer_string();
9201 else if (_lexer.current() == lex_string)
9203 nt_name = _lexer.contents();
9206 else throw_error(
"Unrecognized node test");
9209 if (nt_type == nodetest_none)
9212 if (_lexer.current() == lex_open_brace)
9216 if (_lexer.current() == lex_close_brace)
9220 nt_type = parse_node_test_type(nt_name);
9222 if (nt_type == nodetest_none) throw_error(
"Unrecognized node type");
9224 nt_name = xpath_lexer_string();
9226 else if (nt_name == PUGIXML_TEXT(
"processing-instruction"))
9228 if (_lexer.current() != lex_quoted_string)
9229 throw_error(
"Only literals are allowed as arguments to processing-instruction()");
9231 nt_type = nodetest_pi;
9232 nt_name = _lexer.contents();
9235 if (_lexer.current() != lex_close_brace)
9236 throw_error(
"Unmatched brace near processing-instruction()");
9240 throw_error(
"Unmatched brace near node type test");
9246 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] ==
':' && nt_name.end[-1] ==
'*')
9250 nt_type = nodetest_all_in_namespace;
9252 else nt_type = nodetest_name;
9256 else if (_lexer.current() == lex_multiply)
9258 nt_type = nodetest_all;
9261 else throw_error(
"Unrecognized node test");
9263 xpath_ast_node* n =
new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name));
9265 xpath_ast_node* last = 0;
9267 while (_lexer.current() == lex_open_square_brace)
9271 xpath_ast_node* expr = parse_expression();
9273 xpath_ast_node* pred =
new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr);
9275 if (_lexer.current() != lex_close_square_brace)
9276 throw_error(
"Unmatched square brace");
9279 if (last) last->set_next(pred);
9280 else n->set_right(pred);
9289 xpath_ast_node* parse_relative_location_path(xpath_ast_node* set)
9291 xpath_ast_node* n = parse_step(set);
9293 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
9295 lexeme_t l = _lexer.current();
9298 if (l == lex_double_slash)
9299 n =
new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9309 xpath_ast_node* parse_location_path()
9311 if (_lexer.current() == lex_slash)
9315 xpath_ast_node* n =
new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
9318 lexeme_t l = _lexer.current();
9320 if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
9321 return parse_relative_location_path(n);
9325 else if (_lexer.current() == lex_double_slash)
9329 xpath_ast_node* n =
new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
9330 n =
new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9332 return parse_relative_location_path(n);
9336 return parse_relative_location_path(0);
9343 xpath_ast_node* parse_path_expression()
9352 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
9353 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
9354 _lexer.current() == lex_string)
9356 if (_lexer.current() == lex_string)
9359 const char_t* state = _lexer.state();
9361 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
9363 if (*state !=
'(')
return parse_location_path();
9366 if (parse_node_test_type(_lexer.contents()) != nodetest_none)
return parse_location_path();
9369 xpath_ast_node* n = parse_filter_expression();
9371 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
9373 lexeme_t l = _lexer.current();
9376 if (l == lex_double_slash)
9378 if (n->rettype() != xpath_type_node_set) throw_error(
"Step has to be applied to node set");
9380 n =
new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
9384 return parse_relative_location_path(n);
9389 else return parse_location_path();
9393 xpath_ast_node* parse_union_expression()
9395 xpath_ast_node* n = parse_path_expression();
9397 while (_lexer.current() == lex_union)
9401 xpath_ast_node* expr = parse_union_expression();
9403 if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set)
9404 throw_error(
"Union operator has to be applied to node sets");
9406 n =
new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr);
9413 xpath_ast_node* parse_unary_expression()
9415 if (_lexer.current() == lex_minus)
9419 xpath_ast_node* expr = parse_unary_expression();
9421 return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr);
9423 else return parse_union_expression();
9430 xpath_ast_node* parse_multiplicative_expression()
9432 xpath_ast_node* n = parse_unary_expression();
9434 while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string &&
9435 (_lexer.contents() == PUGIXML_TEXT(
"mod") || _lexer.contents() == PUGIXML_TEXT(
"div"))))
9437 ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply :
9438 _lexer.contents().begin[0] ==
'd' ? ast_op_divide : ast_op_mod;
9441 xpath_ast_node* expr = parse_unary_expression();
9443 n =
new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr);
9452 xpath_ast_node* parse_additive_expression()
9454 xpath_ast_node* n = parse_multiplicative_expression();
9456 while (_lexer.current() == lex_plus || _lexer.current() == lex_minus)
9458 lexeme_t l = _lexer.current();
9462 xpath_ast_node* expr = parse_multiplicative_expression();
9464 n =
new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr);
9475 xpath_ast_node* parse_relational_expression()
9477 xpath_ast_node* n = parse_additive_expression();
9479 while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal ||
9480 _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal)
9482 lexeme_t l = _lexer.current();
9485 xpath_ast_node* expr = parse_additive_expression();
9487 n =
new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater :
9488 l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr);
9497 xpath_ast_node* parse_equality_expression()
9499 xpath_ast_node* n = parse_relational_expression();
9501 while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal)
9503 lexeme_t l = _lexer.current();
9507 xpath_ast_node* expr = parse_relational_expression();
9509 n =
new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr);
9516 xpath_ast_node* parse_and_expression()
9518 xpath_ast_node* n = parse_equality_expression();
9520 while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT(
"and"))
9524 xpath_ast_node* expr = parse_equality_expression();
9526 n =
new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr);
9533 xpath_ast_node* parse_or_expression()
9535 xpath_ast_node* n = parse_and_expression();
9537 while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT(
"or"))
9541 xpath_ast_node* expr = parse_and_expression();
9543 n =
new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr);
9550 xpath_ast_node* parse_expression()
9552 return parse_or_expression();
9555 xpath_parser(
const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result)
9559 xpath_ast_node* parse()
9561 xpath_ast_node* result = parse_expression();
9563 if (_lexer.current() != lex_eof)
9566 throw_error(
"Incorrect query");
9572 static xpath_ast_node* parse(
const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)
9574 xpath_parser parser(query, variables, alloc, result);
9576 #ifdef PUGIXML_NO_EXCEPTIONS
9577 int error = setjmp(parser._error_handler);
9579 return (error == 0) ? parser.parse() : 0;
9581 return parser.parse();
9586 struct xpath_query_impl
9588 static xpath_query_impl* create()
9590 void* memory = xml_memory::allocate(
sizeof(xpath_query_impl));
9592 return new (memory) xpath_query_impl();
9595 static void destroy(
void* ptr)
9600 static_cast<xpath_query_impl*
>(ptr)->alloc.release();
9603 xml_memory::deallocate(ptr);
9606 xpath_query_impl(): root(0), alloc(&block)
9611 xpath_ast_node* root;
9612 xpath_allocator alloc;
9613 xpath_memory_block block;
9616 PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl,
const xpath_node& n, xpath_stack_data& sd)
9618 if (!impl)
return xpath_string();
9620 #ifdef PUGIXML_NO_EXCEPTIONS
9621 if (setjmp(sd.error_handler))
return xpath_string();
9624 xpath_context c(n, 1, 1);
9626 return impl->root->eval_string(c, sd.stack);
9632 #ifndef PUGIXML_NO_EXCEPTIONS
9633 PUGI__FN xpath_exception::xpath_exception(
const xpath_parse_result& result_): _result(result_)
9635 assert(_result.error);
9638 PUGI__FN
const char* xpath_exception::what()
const throw()
9640 return _result.error;
9643 PUGI__FN
const xpath_parse_result& xpath_exception::result()
const
9649 PUGI__FN xpath_node::xpath_node()
9653 PUGI__FN xpath_node::xpath_node(
const xml_node& node_): _node(node_)
9657 PUGI__FN xpath_node::xpath_node(
const xml_attribute& attribute_,
const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
9661 PUGI__FN xml_node xpath_node::node()
const
9663 return _attribute ? xml_node() : _node;
9666 PUGI__FN xml_attribute xpath_node::attribute()
const
9671 PUGI__FN xml_node xpath_node::parent()
const
9673 return _attribute ? _node : _node.parent();
9676 PUGI__FN
static void unspecified_bool_xpath_node(xpath_node***)
9680 PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type()
const
9682 return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
9685 PUGI__FN
bool xpath_node::operator!()
const
9687 return !(_node || _attribute);
9690 PUGI__FN
bool xpath_node::operator==(
const xpath_node& n)
const
9692 return _node == n._node && _attribute == n._attribute;
9695 PUGI__FN
bool xpath_node::operator!=(
const xpath_node& n)
const
9697 return _node != n._node || _attribute != n._attribute;
9701 PUGI__FN
bool operator&&(
const xpath_node& lhs,
bool rhs)
9703 return (
bool)lhs && rhs;
9706 PUGI__FN
bool operator||(
const xpath_node& lhs,
bool rhs)
9708 return (
bool)lhs || rhs;
9712 PUGI__FN
void xpath_node_set::_assign(const_iterator begin_, const_iterator end_)
9714 assert(begin_ <= end_);
9716 size_t size_ =
static_cast<size_t>(end_ - begin_);
9721 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
9724 if (begin_ != end_) _storage = *begin_;
9727 _end = &_storage + size_;
9732 xpath_node* storage =
static_cast<xpath_node*
>(impl::xml_memory::allocate(size_ *
sizeof(xpath_node)));
9736 #ifdef PUGIXML_NO_EXCEPTIONS
9739 throw std::bad_alloc();
9743 memcpy(storage, begin_, size_ *
sizeof(xpath_node));
9746 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
9750 _end = storage + size_;
9754 PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage)
9758 PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage)
9760 _assign(begin_, end_);
9763 PUGI__FN xpath_node_set::~xpath_node_set()
9765 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
9768 PUGI__FN xpath_node_set::xpath_node_set(
const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage)
9770 _assign(ns._begin, ns._end);
9773 PUGI__FN xpath_node_set& xpath_node_set::operator=(
const xpath_node_set& ns)
9775 if (
this == &ns)
return *
this;
9778 _assign(ns._begin, ns._end);
9783 PUGI__FN xpath_node_set::type_t xpath_node_set::type()
const
9788 PUGI__FN
size_t xpath_node_set::size()
const
9790 return _end - _begin;
9793 PUGI__FN
bool xpath_node_set::empty()
const
9795 return _begin == _end;
9798 PUGI__FN
const xpath_node& xpath_node_set::operator[](
size_t index)
const
9800 assert(index < size());
9801 return _begin[index];
9804 PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin()
const
9809 PUGI__FN xpath_node_set::const_iterator xpath_node_set::end()
const
9814 PUGI__FN
void xpath_node_set::sort(
bool reverse)
9816 _type = impl::xpath_sort(_begin, _end, _type, reverse);
9819 PUGI__FN xpath_node xpath_node_set::first()
const
9821 return impl::xpath_first(_begin, _end, _type);
9824 PUGI__FN xpath_parse_result::xpath_parse_result(): error(
"Internal error"), offset(0)
9828 PUGI__FN xpath_parse_result::operator bool()
const
9833 PUGI__FN
const char* xpath_parse_result::description()
const
9835 return error ? error :
"No error";
9838 PUGI__FN xpath_variable::xpath_variable()
9842 PUGI__FN
const char_t* xpath_variable::name()
const
9846 case xpath_type_node_set:
9847 return static_cast<const impl::xpath_variable_node_set*
>(
this)->name;
9849 case xpath_type_number:
9850 return static_cast<const impl::xpath_variable_number*
>(
this)->name;
9852 case xpath_type_string:
9853 return static_cast<const impl::xpath_variable_string*
>(
this)->name;
9855 case xpath_type_boolean:
9856 return static_cast<const impl::xpath_variable_boolean*
>(
this)->name;
9859 assert(!
"Invalid variable type");
9864 PUGI__FN xpath_value_type xpath_variable::type()
const
9869 PUGI__FN
bool xpath_variable::get_boolean()
const
9871 return (_type == xpath_type_boolean) ?
static_cast<const impl::xpath_variable_boolean*
>(
this)->value :
false;
9874 PUGI__FN
double xpath_variable::get_number()
const
9876 return (_type == xpath_type_number) ?
static_cast<const impl::xpath_variable_number*
>(
this)->value : impl::gen_nan();
9879 PUGI__FN
const char_t* xpath_variable::get_string()
const
9881 const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(
this)->value : 0;
9882 return value ? value : PUGIXML_TEXT(
"");
9885 PUGI__FN
const xpath_node_set& xpath_variable::get_node_set()
const
9887 return (_type == xpath_type_node_set) ?
static_cast<const impl::xpath_variable_node_set*
>(
this)->value : impl::dummy_node_set;
9890 PUGI__FN
bool xpath_variable::set(
bool value)
9892 if (_type != xpath_type_boolean)
return false;
9894 static_cast<impl::xpath_variable_boolean*
>(
this)->value = value;
9898 PUGI__FN
bool xpath_variable::set(
double value)
9900 if (_type != xpath_type_number)
return false;
9902 static_cast<impl::xpath_variable_number*
>(
this)->value = value;
9906 PUGI__FN
bool xpath_variable::set(
const char_t* value)
9908 if (_type != xpath_type_string)
return false;
9910 impl::xpath_variable_string* var =
static_cast<impl::xpath_variable_string*
>(
this);
9913 size_t size = (impl::strlength(value) + 1) *
sizeof(char_t);
9915 char_t* copy =
static_cast<char_t*
>(impl::xml_memory::allocate(size));
9916 if (!copy)
return false;
9918 memcpy(copy, value, size);
9921 if (var->value) impl::xml_memory::deallocate(var->value);
9927 PUGI__FN
bool xpath_variable::set(
const xpath_node_set& value)
9929 if (_type != xpath_type_node_set)
return false;
9931 static_cast<impl::xpath_variable_node_set*
>(
this)->value = value;
9935 PUGI__FN xpath_variable_set::xpath_variable_set()
9937 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i) _data[i] = 0;
9940 PUGI__FN xpath_variable_set::~xpath_variable_set()
9942 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
9944 xpath_variable* var = _data[i];
9948 xpath_variable* next = var->_next;
9950 impl::delete_xpath_variable(var->_type, var);
9957 PUGI__FN xpath_variable* xpath_variable_set::find(
const char_t* name)
const
9959 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
9960 size_t hash = impl::hash_string(name) % hash_size;
9963 for (xpath_variable* var = _data[hash]; var; var = var->_next)
9964 if (impl::strequal(var->name(), name))
9970 PUGI__FN xpath_variable* xpath_variable_set::add(
const char_t* name, xpath_value_type type)
9972 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
9973 size_t hash = impl::hash_string(name) % hash_size;
9976 for (xpath_variable* var = _data[hash]; var; var = var->_next)
9977 if (impl::strequal(var->name(), name))
9978 return var->type() == type ? var : 0;
9981 xpath_variable* result = impl::new_xpath_variable(type, name);
9985 result->_type = type;
9986 result->_next = _data[hash];
9988 _data[hash] = result;
9994 PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
bool value)
9996 xpath_variable* var = add(name, xpath_type_boolean);
9997 return var ? var->set(value) :
false;
10000 PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
double value)
10002 xpath_variable* var = add(name, xpath_type_number);
10003 return var ? var->set(value) :
false;
10006 PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
const char_t* value)
10008 xpath_variable* var = add(name, xpath_type_string);
10009 return var ? var->set(value) :
false;
10012 PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
const xpath_node_set& value)
10014 xpath_variable* var = add(name, xpath_type_node_set);
10015 return var ? var->set(value) :
false;
10018 PUGI__FN xpath_variable* xpath_variable_set::get(
const char_t* name)
10023 PUGI__FN
const xpath_variable* xpath_variable_set::get(
const char_t* name)
const
10028 PUGI__FN xpath_query::xpath_query(
const char_t* query, xpath_variable_set* variables): _impl(0)
10030 impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
10034 #ifdef PUGIXML_NO_EXCEPTIONS
10035 _result.error =
"Out of memory";
10037 throw std::bad_alloc();
10042 impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy);
10044 qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
10048 _impl =
static_cast<impl::xpath_query_impl*
>(impl_holder.release());
10054 PUGI__FN xpath_query::~xpath_query()
10056 impl::xpath_query_impl::destroy(_impl);
10059 PUGI__FN xpath_value_type xpath_query::return_type()
const
10061 if (!_impl)
return xpath_type_none;
10063 return static_cast<impl::xpath_query_impl*
>(_impl)->root->rettype();
10066 PUGI__FN
bool xpath_query::evaluate_boolean(
const xpath_node& n)
const
10068 if (!_impl)
return false;
10070 impl::xpath_context c(n, 1, 1);
10071 impl::xpath_stack_data sd;
10073 #ifdef PUGIXML_NO_EXCEPTIONS
10074 if (setjmp(sd.error_handler))
return false;
10077 return static_cast<impl::xpath_query_impl*
>(_impl)->root->eval_boolean(c, sd.stack);
10080 PUGI__FN
double xpath_query::evaluate_number(
const xpath_node& n)
const
10082 if (!_impl)
return impl::gen_nan();
10084 impl::xpath_context c(n, 1, 1);
10085 impl::xpath_stack_data sd;
10087 #ifdef PUGIXML_NO_EXCEPTIONS
10088 if (setjmp(sd.error_handler))
return impl::gen_nan();
10091 return static_cast<impl::xpath_query_impl*
>(_impl)->root->eval_number(c, sd.stack);
10094 #ifndef PUGIXML_NO_STL
10095 PUGI__FN string_t xpath_query::evaluate_string(
const xpath_node& n)
const
10097 impl::xpath_stack_data sd;
10099 return impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd).c_str();
10103 PUGI__FN
size_t xpath_query::evaluate_string(char_t* buffer,
size_t capacity,
const xpath_node& n)
const
10105 impl::xpath_stack_data sd;
10107 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd);
10109 size_t full_size = r.length() + 1;
10113 size_t size = (full_size < capacity) ? full_size : capacity;
10116 memcpy(buffer, r.c_str(), (size - 1) *
sizeof(char_t));
10117 buffer[size - 1] = 0;
10123 PUGI__FN xpath_node_set xpath_query::evaluate_node_set(
const xpath_node& n)
const
10125 if (!_impl)
return xpath_node_set();
10127 impl::xpath_ast_node* root =
static_cast<impl::xpath_query_impl*
>(_impl)->root;
10129 if (root->rettype() != xpath_type_node_set)
10131 #ifdef PUGIXML_NO_EXCEPTIONS
10132 return xpath_node_set();
10134 xpath_parse_result res;
10135 res.error =
"Expression does not evaluate to node set";
10137 throw xpath_exception(res);
10141 impl::xpath_context c(n, 1, 1);
10142 impl::xpath_stack_data sd;
10144 #ifdef PUGIXML_NO_EXCEPTIONS
10145 if (setjmp(sd.error_handler))
return xpath_node_set();
10148 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack);
10150 return xpath_node_set(r.begin(), r.end(), r.type());
10153 PUGI__FN
const xpath_parse_result& xpath_query::result()
const
10158 PUGI__FN
static void unspecified_bool_xpath_query(xpath_query***)
10162 PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type()
const
10164 return _impl ? unspecified_bool_xpath_query : 0;
10167 PUGI__FN
bool xpath_query::operator!()
const
10172 PUGI__FN xpath_node xml_node::select_single_node(
const char_t* query, xpath_variable_set* variables)
const
10174 xpath_query q(query, variables);
10175 return select_single_node(q);
10178 PUGI__FN xpath_node xml_node::select_single_node(
const xpath_query& query)
const
10180 xpath_node_set s = query.evaluate_node_set(*
this);
10181 return s.empty() ? xpath_node() : s.first();
10184 PUGI__FN xpath_node_set xml_node::select_nodes(
const char_t* query, xpath_variable_set* variables)
const
10186 xpath_query q(query, variables);
10187 return select_nodes(q);
10190 PUGI__FN xpath_node_set xml_node::select_nodes(
const xpath_query& query)
const
10192 return query.evaluate_node_set(*
this);
10198 #ifdef __BORLANDC__
10199 # pragma option pop
10204 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
10205 # pragma warning(pop)
10209 #undef PUGI__NO_INLINE
10210 #undef PUGI__STATIC_ASSERT
10211 #undef PUGI__DMC_VOLATILE
10212 #undef PUGI__MSVC_CRT_VERSION
10213 #undef PUGI__NS_BEGIN
10214 #undef PUGI__NS_END
10216 #undef PUGI__FN_NO_INLINE
10217 #undef PUGI__IS_CHARTYPE_IMPL
10218 #undef PUGI__IS_CHARTYPE
10219 #undef PUGI__IS_CHARTYPEX
10220 #undef PUGI__SKIPWS
10221 #undef PUGI__OPTSET
10222 #undef PUGI__PUSHNODE
10223 #undef PUGI__POPNODE
10224 #undef PUGI__SCANFOR
10225 #undef PUGI__SCANWHILE
10226 #undef PUGI__ENDSEG
10227 #undef PUGI__THROW_ERROR
10228 #undef PUGI__CHECK_ERROR
To allow this test harness to be used without the mezzanine it uses pugixml for xml parsing and this ...