14#ifndef SOURCE_PUGIXML_CPP
15#define SOURCE_PUGIXML_CPP
25#ifdef PUGIXML_WCHAR_MODE
29#ifndef PUGIXML_NO_XPATH
45# pragma warning(disable: 4127)
46# pragma warning(disable: 4324)
47# pragma warning(disable: 4702)
48# pragma warning(disable: 4996)
51#if defined(_MSC_VER) && defined(__c2__)
52# pragma clang diagnostic push
53# pragma clang diagnostic ignored "-Wdeprecated"
56#ifdef __INTEL_COMPILER
57# pragma warning(disable: 177)
58# pragma warning(disable: 279)
59# pragma warning(disable: 1478 1786)
60# pragma warning(disable: 1684)
63#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
75# pragma diag_suppress=178
76# pragma diag_suppress=237
79#ifdef __TI_COMPILER_VERSION__
80# pragma diag_suppress 179
84#if defined(_MSC_VER) && _MSC_VER >= 1300
85# define PUGI__NO_INLINE __declspec(noinline)
86#elif defined(__GNUC__)
87# define PUGI__NO_INLINE __attribute__((noinline))
89# define PUGI__NO_INLINE
93#if defined(__GNUC__) && !defined(__c2__)
94# define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0)
96# define PUGI__UNLIKELY(cond) (cond)
100#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
104# define PUGI__DMC_VOLATILE volatile
106# define PUGI__DMC_VOLATILE
110#if defined(__clang__) && defined(__has_attribute)
111# if __has_attribute(no_sanitize)
112# define PUGI__UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow")))
114# define PUGI__UNSIGNED_OVERFLOW
117# define PUGI__UNSIGNED_OVERFLOW
121#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
128#if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX)
129# define LLONG_MIN (-LLONG_MAX - 1LL)
130# define LLONG_MAX __LONG_LONG_MAX__
131# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
135#if defined(_MSC_VER) && !defined(__S3E__)
136# define PUGI__MSVC_CRT_VERSION _MSC_VER
140#if __cplusplus >= 201103
141# define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
142#elif defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
143# define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__)
145# define PUGI__SNPRINTF sprintf
149#ifdef PUGIXML_HEADER_ONLY
150# define PUGI__NS_BEGIN namespace pugi { namespace impl {
151# define PUGI__NS_END } }
152# define PUGI__FN inline
153# define PUGI__FN_NO_INLINE inline
155# if defined(_MSC_VER) && _MSC_VER < 1300
156# define PUGI__NS_BEGIN namespace pugi { namespace impl {
157# define PUGI__NS_END } }
159# define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace {
160# define PUGI__NS_END } } }
163# define PUGI__FN_NO_INLINE PUGI__NO_INLINE
167#if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561)
170# ifndef _UINTPTR_T_DEFINED
171 typedef size_t uintptr_t;
174 typedef unsigned __int8 uint8_t;
175 typedef unsigned __int16 uint16_t;
176 typedef unsigned __int32 uint32_t;
184 PUGI__FN
void* default_allocate(
size_t size)
189 PUGI__FN
void default_deallocate(
void* ptr)
194 template <
typename T>
195 struct xml_memory_management_function_storage
197 static allocation_function allocate;
198 static deallocation_function deallocate;
203 template <
typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate;
204 template <
typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;
206 typedef xml_memory_management_function_storage<int> xml_memory;
212 PUGI__FN
size_t strlength(
const char_t* s)
216 #ifdef PUGIXML_WCHAR_MODE
224 PUGI__FN
bool strequal(
const char_t* src,
const char_t* dst)
228 #ifdef PUGIXML_WCHAR_MODE
229 return wcscmp(src, dst) == 0;
231 return strcmp(src, dst) == 0;
236 PUGI__FN
bool strequalrange(
const char_t* lhs,
const char_t* rhs,
size_t count)
238 for (
size_t i = 0; i < count; ++i)
239 if (lhs[i] != rhs[i])
242 return lhs[count] == 0;
246 PUGI__FN
size_t strlength_wide(
const wchar_t* s)
250 #ifdef PUGIXML_WCHAR_MODE
253 const wchar_t* end = s;
255 return static_cast<size_t>(end - s);
262 template <
typename T>
struct auto_deleter
264 typedef void (*D)(T*);
269 auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_)
275 if (data) deleter(data);
287#ifdef PUGIXML_COMPACT
289 class compact_hash_table
292 compact_hash_table(): _items(0), _capacity(0), _count(0)
300 xml_memory::deallocate(_items);
307 void* find(
const void* key)
309 if (_capacity == 0)
return 0;
311 item_t* item = get_item(key);
313 assert(item->key == key || (item->key == 0 && item->value == 0));
318 void insert(
const void* key,
void* value)
320 assert(_capacity != 0 && _count < _capacity - _capacity / 4);
322 item_t* item = get_item(key);
334 bool reserve(
size_t extra = 16)
336 if (_count + extra >= _capacity - _capacity / 4)
337 return rehash(_count + extra);
354 bool rehash(
size_t count);
356 item_t* get_item(
const void* key)
359 assert(_capacity > 0);
361 size_t hashmod = _capacity - 1;
362 size_t bucket = hash(key) & hashmod;
364 for (
size_t probe = 0; probe <= hashmod; ++probe)
366 item_t& probe_item = _items[bucket];
368 if (probe_item.key == key || probe_item.key == 0)
372 bucket = (bucket + probe + 1) & hashmod;
375 assert(
false &&
"Hash table is full");
379 static PUGI__UNSIGNED_OVERFLOW
unsigned int hash(
const void* key)
381 unsigned int h =
static_cast<unsigned int>(
reinterpret_cast<uintptr_t
>(key) & 0xffffffff);
394 PUGI__FN_NO_INLINE
bool compact_hash_table::rehash(
size_t count)
396 size_t capacity = 32;
397 while (count >= capacity - capacity / 4)
400 compact_hash_table rt;
401 rt._capacity = capacity;
402 rt._items =
static_cast<item_t*
>(xml_memory::allocate(
sizeof(item_t) * capacity));
407 memset(rt._items, 0,
sizeof(item_t) * capacity);
409 for (
size_t i = 0; i < _capacity; ++i)
411 rt.insert(_items[i].key, _items[i].value);
414 xml_memory::deallocate(_items);
416 _capacity = capacity;
419 assert(_count == rt._count);
428#ifdef PUGIXML_COMPACT
429 static const uintptr_t xml_memory_block_alignment = 4;
431 static const uintptr_t xml_memory_block_alignment =
sizeof(
void*);
435 static const uintptr_t xml_memory_page_contents_shared_mask = 64;
436 static const uintptr_t xml_memory_page_name_allocated_mask = 32;
437 static const uintptr_t xml_memory_page_value_allocated_mask = 16;
438 static const uintptr_t xml_memory_page_type_mask = 15;
441 static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask;
442 static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask;
444#ifdef PUGIXML_COMPACT
445 #define PUGI__GETHEADER_IMPL(object, page, flags)
446 #define PUGI__GETPAGE_IMPL(header) (header).get_page()
448 #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))
450 #define PUGI__GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8))))
453 #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header)
454 #define PUGI__NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
456 struct xml_allocator;
458 struct xml_memory_page
460 static xml_memory_page* construct(
void* memory)
462 xml_memory_page* result =
static_cast<xml_memory_page*
>(memory);
464 result->allocator = 0;
467 result->busy_size = 0;
468 result->freed_size = 0;
470 #ifdef PUGIXML_COMPACT
471 result->compact_string_base = 0;
472 result->compact_shared_parent = 0;
473 result->compact_page_marker = 0;
479 xml_allocator* allocator;
481 xml_memory_page* prev;
482 xml_memory_page* next;
487 #ifdef PUGIXML_COMPACT
488 char_t* compact_string_base;
489 void* compact_shared_parent;
490 uint32_t* compact_page_marker;
494 static const size_t xml_memory_page_size =
495 #ifdef PUGIXML_MEMORY_PAGE_SIZE
496 (PUGIXML_MEMORY_PAGE_SIZE)
500 -
sizeof(xml_memory_page);
502 struct xml_memory_string_header
504 uint16_t page_offset;
510 xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
512 #ifdef PUGIXML_COMPACT
517 xml_memory_page* allocate_page(
size_t data_size)
519 size_t size =
sizeof(xml_memory_page) + data_size;
522 void* memory = xml_memory::allocate(size);
523 if (!memory)
return 0;
526 xml_memory_page* page = xml_memory_page::construct(memory);
529 assert(
this == _root->allocator);
530 page->allocator =
this;
535 static void deallocate_page(xml_memory_page* page)
537 xml_memory::deallocate(page);
540 void* allocate_memory_oob(
size_t size, xml_memory_page*& out_page);
542 void* allocate_memory(
size_t size, xml_memory_page*& out_page)
544 if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size))
545 return allocate_memory_oob(size, out_page);
547 void* buf =
reinterpret_cast<char*
>(_root) +
sizeof(xml_memory_page) + _busy_size;
556 #ifdef PUGIXML_COMPACT
557 void* allocate_object(
size_t size, xml_memory_page*& out_page)
559 void* result = allocate_memory(size +
sizeof(uint32_t), out_page);
560 if (!result)
return 0;
563 ptrdiff_t offset =
static_cast<char*
>(result) -
reinterpret_cast<char*
>(out_page->compact_page_marker);
565 if (PUGI__UNLIKELY(
static_cast<uintptr_t
>(offset) >= 256 * xml_memory_block_alignment))
568 uint32_t* marker =
static_cast<uint32_t*
>(result);
570 *marker =
static_cast<uint32_t
>(
reinterpret_cast<char*
>(marker) -
reinterpret_cast<char*
>(out_page));
571 out_page->compact_page_marker = marker;
575 out_page->freed_size +=
sizeof(uint32_t);
582 _busy_size -=
sizeof(uint32_t);
588 void* allocate_object(
size_t size, xml_memory_page*& out_page)
590 return allocate_memory(size, out_page);
594 void deallocate_memory(
void* ptr,
size_t size, xml_memory_page* page)
596 if (page == _root) page->busy_size = _busy_size;
598 assert(ptr >=
reinterpret_cast<char*
>(page) +
sizeof(xml_memory_page) && ptr <
reinterpret_cast<char*
>(page) +
sizeof(xml_memory_page) + page->busy_size);
601 page->freed_size += size;
602 assert(page->freed_size <= page->busy_size);
604 if (page->freed_size == page->busy_size)
608 assert(_root == page);
612 page->freed_size = 0;
614 #ifdef PUGIXML_COMPACT
616 page->compact_string_base = 0;
617 page->compact_shared_parent = 0;
618 page->compact_page_marker = 0;
625 assert(_root != page);
629 page->prev->next = page->next;
630 page->next->prev = page->prev;
633 deallocate_page(page);
638 char_t* allocate_string(
size_t length)
640 static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment;
642 PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
645 size_t size =
sizeof(xml_memory_string_header) + length *
sizeof(char_t);
648 size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1);
650 xml_memory_page* page;
651 xml_memory_string_header* header =
static_cast<xml_memory_string_header*
>(allocate_memory(full_size, page));
653 if (!header)
return 0;
656 ptrdiff_t page_offset =
reinterpret_cast<char*
>(header) -
reinterpret_cast<char*
>(page) -
sizeof(xml_memory_page);
658 assert(page_offset % xml_memory_block_alignment == 0);
659 assert(page_offset >= 0 &&
static_cast<size_t>(page_offset) < max_encoded_offset);
660 header->page_offset =
static_cast<uint16_t
>(
static_cast<size_t>(page_offset) / xml_memory_block_alignment);
663 assert(full_size % xml_memory_block_alignment == 0);
664 assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0));
665 header->full_size =
static_cast<uint16_t
>(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0);
669 return static_cast<char_t*
>(
static_cast<void*
>(header + 1));
672 void deallocate_string(char_t*
string)
678 xml_memory_string_header* header =
static_cast<xml_memory_string_header*
>(
static_cast<void*
>(string)) - 1;
682 size_t page_offset =
sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment;
683 xml_memory_page* page =
reinterpret_cast<xml_memory_page*
>(
static_cast<void*
>(
reinterpret_cast<char*
>(header) - page_offset));
686 size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment;
688 deallocate_memory(header, full_size, page);
693 #ifdef PUGIXML_COMPACT
694 return _hash->reserve();
700 xml_memory_page* _root;
703 #ifdef PUGIXML_COMPACT
704 compact_hash_table* _hash;
708 PUGI__FN_NO_INLINE
void* xml_allocator::allocate_memory_oob(
size_t size, xml_memory_page*& out_page)
710 const size_t large_allocation_threshold = xml_memory_page_size / 4;
712 xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
717 if (size <= large_allocation_threshold)
719 _root->busy_size = _busy_size;
734 page->prev = _root->prev;
737 _root->prev->next = page;
740 page->busy_size = size;
743 return reinterpret_cast<char*
>(page) +
sizeof(xml_memory_page);
747#ifdef PUGIXML_COMPACT
749 static const uintptr_t compact_alignment_log2 = 2;
750 static const uintptr_t compact_alignment = 1 << compact_alignment_log2;
755 compact_header(xml_memory_page* page,
unsigned int flags)
757 PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
759 ptrdiff_t offset = (
reinterpret_cast<char*
>(
this) -
reinterpret_cast<char*
>(page->compact_page_marker));
760 assert(offset % compact_alignment == 0 &&
static_cast<uintptr_t
>(offset) < 256 * compact_alignment);
762 _page =
static_cast<unsigned char>(offset >> compact_alignment_log2);
763 _flags =
static_cast<unsigned char>(flags);
766 void operator&=(uintptr_t mod)
768 _flags &=
static_cast<unsigned char>(mod);
771 void operator|=(uintptr_t mod)
773 _flags |=
static_cast<unsigned char>(mod);
776 uintptr_t operator&(uintptr_t mod)
const
781 xml_memory_page* get_page()
const
784 const char* page_marker =
reinterpret_cast<const char*
>(
this) - (_page << compact_alignment_log2);
785 const char* page = page_marker - *
reinterpret_cast<const uint32_t*
>(
static_cast<const void*
>(page_marker));
787 return const_cast<xml_memory_page*
>(
reinterpret_cast<const xml_memory_page*
>(
static_cast<const void*
>(page)));
792 unsigned char _flags;
795 PUGI__FN xml_memory_page* compact_get_page(
const void*
object,
int header_offset)
797 const compact_header* header =
reinterpret_cast<const compact_header*
>(
static_cast<const char*
>(object) - header_offset);
799 return header->get_page();
802 template <
int header_offset,
typename T> PUGI__FN_NO_INLINE T* compact_get_value(
const void*
object)
804 return static_cast<T*
>(compact_get_page(
object, header_offset)->allocator->_hash->find(
object));
807 template <
int header_offset,
typename T> PUGI__FN_NO_INLINE
void compact_set_value(
const void*
object, T* value)
809 compact_get_page(
object, header_offset)->allocator->_hash->insert(
object, value);
812 template <
typename T,
int header_offset,
int start = -126>
class compact_pointer
815 compact_pointer(): _data(0)
819 void operator=(
const compact_pointer& rhs)
824 void operator=(T* value)
832 ptrdiff_t diff =
reinterpret_cast<char*
>(value) -
reinterpret_cast<char*
>(
this);
833 ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start;
835 if (
static_cast<uintptr_t
>(offset) <= 253)
836 _data =
static_cast<unsigned char>(offset + 1);
839 compact_set_value<header_offset>(
this, value);
854 uintptr_t base =
reinterpret_cast<uintptr_t
>(
this) & ~(compact_alignment - 1);
856 return reinterpret_cast<T*
>(base + (_data - 1 + start) * compact_alignment);
859 return compact_get_value<header_offset, T>(
this);
865 T* operator->()
const
874 template <
typename T,
int header_offset>
class compact_pointer_parent
877 compact_pointer_parent(): _data(0)
881 void operator=(
const compact_pointer_parent& rhs)
886 void operator=(T* value)
894 ptrdiff_t diff =
reinterpret_cast<char*
>(value) -
reinterpret_cast<char*
>(
this);
895 ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533;
897 if (
static_cast<uintptr_t
>(offset) <= 65533)
899 _data =
static_cast<unsigned short>(offset + 1);
903 xml_memory_page* page = compact_get_page(
this, header_offset);
905 if (PUGI__UNLIKELY(page->compact_shared_parent == 0))
906 page->compact_shared_parent = value;
908 if (page->compact_shared_parent == value)
914 compact_set_value<header_offset>(
this, value);
932 uintptr_t base =
reinterpret_cast<uintptr_t
>(
this) & ~(compact_alignment - 1);
934 return reinterpret_cast<T*
>(base + (_data - 1 - 65533) * compact_alignment);
936 else if (_data == 65534)
937 return static_cast<T*
>(compact_get_page(
this, header_offset)->compact_shared_parent);
939 return compact_get_value<header_offset, T>(
this);
945 T* operator->()
const
954 template <
int header_offset,
int base_offset>
class compact_string
957 compact_string(): _data(0)
961 void operator=(
const compact_string& rhs)
966 void operator=(char_t* value)
970 xml_memory_page* page = compact_get_page(
this, header_offset);
972 if (PUGI__UNLIKELY(page->compact_string_base == 0))
973 page->compact_string_base = value;
975 ptrdiff_t offset = value - page->compact_string_base;
977 if (
static_cast<uintptr_t
>(offset) < (65535 << 7))
980 uint16_t* base =
reinterpret_cast<uint16_t*
>(
static_cast<void*
>(
reinterpret_cast<char*
>(
this) - base_offset));
984 *base =
static_cast<uint16_t
>((offset >> 7) + 1);
985 _data =
static_cast<unsigned char>((offset & 127) + 1);
989 ptrdiff_t remainder = offset - ((*base - 1) << 7);
991 if (
static_cast<uintptr_t
>(remainder) <= 253)
993 _data =
static_cast<unsigned char>(remainder + 1);
997 compact_set_value<header_offset>(
this, value);
1005 compact_set_value<header_offset>(
this, value);
1016 operator char_t*()
const
1022 xml_memory_page* page = compact_get_page(
this, header_offset);
1025 const uint16_t* base =
reinterpret_cast<const uint16_t*
>(
static_cast<const void*
>(
reinterpret_cast<const char*
>(
this) - base_offset));
1028 ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);
1030 return page->compact_string_base + offset;
1034 return compact_get_value<header_offset, char_t>(
this);
1042 unsigned char _data;
1047#ifdef PUGIXML_COMPACT
1050 struct xml_attribute_struct
1052 xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)
1054 PUGI__STATIC_ASSERT(
sizeof(xml_attribute_struct) == 8);
1057 impl::compact_header header;
1059 uint16_t namevalue_base;
1061 impl::compact_string<4, 2> name;
1062 impl::compact_string<5, 3> value;
1064 impl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c;
1065 impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute;
1068 struct xml_node_struct
1070 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0)
1072 PUGI__STATIC_ASSERT(
sizeof(xml_node_struct) == 12);
1075 impl::compact_header header;
1077 uint16_t namevalue_base;
1079 impl::compact_string<4, 2> name;
1080 impl::compact_string<5, 3> value;
1082 impl::compact_pointer_parent<xml_node_struct, 6> parent;
1084 impl::compact_pointer<xml_node_struct, 8, 0> first_child;
1086 impl::compact_pointer<xml_node_struct, 9> prev_sibling_c;
1087 impl::compact_pointer<xml_node_struct, 10, 0> next_sibling;
1089 impl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute;
1095 struct xml_attribute_struct
1097 xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0)
1099 header = PUGI__GETHEADER_IMPL(
this, page, 0);
1107 xml_attribute_struct* prev_attribute_c;
1108 xml_attribute_struct* next_attribute;
1111 struct xml_node_struct
1113 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
1115 header = PUGI__GETHEADER_IMPL(
this, page, type);
1123 xml_node_struct* parent;
1125 xml_node_struct* first_child;
1127 xml_node_struct* prev_sibling_c;
1128 xml_node_struct* next_sibling;
1130 xml_attribute_struct* first_attribute;
1136 struct xml_extra_buffer
1139 xml_extra_buffer* next;
1142 struct xml_document_struct:
public xml_node_struct,
public xml_allocator
1144 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0)
1148 const char_t* buffer;
1150 xml_extra_buffer* extra_buffers;
1152 #ifdef PUGIXML_COMPACT
1153 compact_hash_table hash;
1157 template <
typename Object>
inline xml_allocator& get_allocator(
const Object*
object)
1161 return *PUGI__GETPAGE(
object)->allocator;
1164 template <
typename Object>
inline xml_document_struct& get_document(
const Object*
object)
1168 return *
static_cast<xml_document_struct*
>(PUGI__GETPAGE(
object)->allocator);
1174 inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
1176 xml_memory_page* page;
1177 void* memory = alloc.allocate_object(
sizeof(xml_attribute_struct), page);
1178 if (!memory)
return 0;
1180 return new (memory) xml_attribute_struct(page);
1183 inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type)
1185 xml_memory_page* page;
1186 void* memory = alloc.allocate_object(
sizeof(xml_node_struct), page);
1187 if (!memory)
return 0;
1189 return new (memory) xml_node_struct(page, type);
1192 inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
1194 if (a->header & impl::xml_memory_page_name_allocated_mask)
1195 alloc.deallocate_string(a->name);
1197 if (a->header & impl::xml_memory_page_value_allocated_mask)
1198 alloc.deallocate_string(a->value);
1200 alloc.deallocate_memory(a,
sizeof(xml_attribute_struct), PUGI__GETPAGE(a));
1203 inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
1205 if (n->header & impl::xml_memory_page_name_allocated_mask)
1206 alloc.deallocate_string(n->name);
1208 if (n->header & impl::xml_memory_page_value_allocated_mask)
1209 alloc.deallocate_string(n->value);
1211 for (xml_attribute_struct* attr = n->first_attribute; attr; )
1213 xml_attribute_struct* next = attr->next_attribute;
1215 destroy_attribute(attr, alloc);
1220 for (xml_node_struct* child = n->first_child; child; )
1222 xml_node_struct* next = child->next_sibling;
1224 destroy_node(child, alloc);
1229 alloc.deallocate_memory(n,
sizeof(xml_node_struct), PUGI__GETPAGE(n));
1232 inline void append_node(xml_node_struct* child, xml_node_struct* node)
1234 child->parent = node;
1236 xml_node_struct* head = node->first_child;
1240 xml_node_struct* tail = head->prev_sibling_c;
1242 tail->next_sibling = child;
1243 child->prev_sibling_c = tail;
1244 head->prev_sibling_c = child;
1248 node->first_child = child;
1249 child->prev_sibling_c = child;
1253 inline void prepend_node(xml_node_struct* child, xml_node_struct* node)
1255 child->parent = node;
1257 xml_node_struct* head = node->first_child;
1261 child->prev_sibling_c = head->prev_sibling_c;
1262 head->prev_sibling_c = child;
1265 child->prev_sibling_c = child;
1267 child->next_sibling = head;
1268 node->first_child = child;
1271 inline void insert_node_after(xml_node_struct* child, xml_node_struct* node)
1273 xml_node_struct* parent = node->parent;
1275 child->parent = parent;
1277 if (node->next_sibling)
1278 node->next_sibling->prev_sibling_c = child;
1280 parent->first_child->prev_sibling_c = child;
1282 child->next_sibling = node->next_sibling;
1283 child->prev_sibling_c = node;
1285 node->next_sibling = child;
1288 inline void insert_node_before(xml_node_struct* child, xml_node_struct* node)
1290 xml_node_struct* parent = node->parent;
1292 child->parent = parent;
1294 if (node->prev_sibling_c->next_sibling)
1295 node->prev_sibling_c->next_sibling = child;
1297 parent->first_child = child;
1299 child->prev_sibling_c = node->prev_sibling_c;
1300 child->next_sibling = node;
1302 node->prev_sibling_c = child;
1305 inline void remove_node(xml_node_struct* node)
1307 xml_node_struct* parent = node->parent;
1309 if (node->next_sibling)
1310 node->next_sibling->prev_sibling_c = node->prev_sibling_c;
1312 parent->first_child->prev_sibling_c = node->prev_sibling_c;
1314 if (node->prev_sibling_c->next_sibling)
1315 node->prev_sibling_c->next_sibling = node->next_sibling;
1317 parent->first_child = node->next_sibling;
1320 node->prev_sibling_c = 0;
1321 node->next_sibling = 0;
1324 inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1326 xml_attribute_struct* head = node->first_attribute;
1330 xml_attribute_struct* tail = head->prev_attribute_c;
1332 tail->next_attribute = attr;
1333 attr->prev_attribute_c = tail;
1334 head->prev_attribute_c = attr;
1338 node->first_attribute = attr;
1339 attr->prev_attribute_c = attr;
1343 inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1345 xml_attribute_struct* head = node->first_attribute;
1349 attr->prev_attribute_c = head->prev_attribute_c;
1350 head->prev_attribute_c = attr;
1353 attr->prev_attribute_c = attr;
1355 attr->next_attribute = head;
1356 node->first_attribute = attr;
1359 inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
1361 if (place->next_attribute)
1362 place->next_attribute->prev_attribute_c = attr;
1364 node->first_attribute->prev_attribute_c = attr;
1366 attr->next_attribute = place->next_attribute;
1367 attr->prev_attribute_c = place;
1368 place->next_attribute = attr;
1371 inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
1373 if (place->prev_attribute_c->next_attribute)
1374 place->prev_attribute_c->next_attribute = attr;
1376 node->first_attribute = attr;
1378 attr->prev_attribute_c = place->prev_attribute_c;
1379 attr->next_attribute = place;
1380 place->prev_attribute_c = attr;
1383 inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node)
1385 if (attr->next_attribute)
1386 attr->next_attribute->prev_attribute_c = attr->prev_attribute_c;
1388 node->first_attribute->prev_attribute_c = attr->prev_attribute_c;
1390 if (attr->prev_attribute_c->next_attribute)
1391 attr->prev_attribute_c->next_attribute = attr->next_attribute;
1393 node->first_attribute = attr->next_attribute;
1395 attr->prev_attribute_c = 0;
1396 attr->next_attribute = 0;
1399 PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
1401 if (!alloc.reserve())
return 0;
1403 xml_node_struct* child = allocate_node(alloc, type);
1404 if (!child)
return 0;
1406 append_node(child, node);
1411 PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)
1413 if (!alloc.reserve())
return 0;
1415 xml_attribute_struct* attr = allocate_attribute(alloc);
1416 if (!attr)
return 0;
1418 append_attribute(attr, node);
1439 inline uint16_t endian_swap(uint16_t value)
1441 return static_cast<uint16_t
>(((value & 0xff) << 8) | (value >> 8));
1444 inline uint32_t endian_swap(uint32_t value)
1446 return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
1451 typedef size_t value_type;
1453 static value_type low(value_type result, uint32_t ch)
1456 if (ch < 0x80)
return result + 1;
1458 else if (ch < 0x800)
return result + 2;
1460 else return result + 3;
1463 static value_type high(value_type result, uint32_t)
1472 typedef uint8_t* value_type;
1474 static value_type low(value_type result, uint32_t ch)
1479 *result =
static_cast<uint8_t
>(ch);
1483 else if (ch < 0x800)
1485 result[0] =
static_cast<uint8_t
>(0xC0 | (ch >> 6));
1486 result[1] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
1492 result[0] =
static_cast<uint8_t
>(0xE0 | (ch >> 12));
1493 result[1] =
static_cast<uint8_t
>(0x80 | ((ch >> 6) & 0x3F));
1494 result[2] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
1499 static value_type high(value_type result, uint32_t ch)
1502 result[0] =
static_cast<uint8_t
>(0xF0 | (ch >> 18));
1503 result[1] =
static_cast<uint8_t
>(0x80 | ((ch >> 12) & 0x3F));
1504 result[2] =
static_cast<uint8_t
>(0x80 | ((ch >> 6) & 0x3F));
1505 result[3] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
1509 static value_type any(value_type result, uint32_t ch)
1511 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
1515 struct utf16_counter
1517 typedef size_t value_type;
1519 static value_type low(value_type result, uint32_t)
1524 static value_type high(value_type result, uint32_t)
1532 typedef uint16_t* value_type;
1534 static value_type low(value_type result, uint32_t ch)
1536 *result =
static_cast<uint16_t
>(ch);
1541 static value_type high(value_type result, uint32_t ch)
1543 uint32_t msh =
static_cast<uint32_t
>(ch - 0x10000) >> 10;
1544 uint32_t lsh =
static_cast<uint32_t
>(ch - 0x10000) & 0x3ff;
1546 result[0] =
static_cast<uint16_t
>(0xD800 + msh);
1547 result[1] =
static_cast<uint16_t
>(0xDC00 + lsh);
1552 static value_type any(value_type result, uint32_t ch)
1554 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
1558 struct utf32_counter
1560 typedef size_t value_type;
1562 static value_type low(value_type result, uint32_t)
1567 static value_type high(value_type result, uint32_t)
1575 typedef uint32_t* value_type;
1577 static value_type low(value_type result, uint32_t ch)
1584 static value_type high(value_type result, uint32_t ch)
1591 static value_type any(value_type result, uint32_t ch)
1599 struct latin1_writer
1601 typedef uint8_t* value_type;
1603 static value_type low(value_type result, uint32_t ch)
1605 *result =
static_cast<uint8_t
>(ch > 255 ?
'?' : ch);
1610 static value_type high(value_type result, uint32_t ch)
1622 typedef uint8_t type;
1624 template <
typename Traits>
static inline typename Traits::value_type process(
const uint8_t* data,
size_t size,
typename Traits::value_type result, Traits)
1626 const uint8_t utf8_byte_mask = 0x3f;
1630 uint8_t lead = *data;
1635 result = Traits::low(result, lead);
1640 if ((
reinterpret_cast<uintptr_t
>(data) & 3) == 0)
1643 while (size >= 4 && (*
static_cast<const uint32_t*
>(
static_cast<const void*
>(data)) & 0x80808080) == 0)
1645 result = Traits::low(result, data[0]);
1646 result = Traits::low(result, data[1]);
1647 result = Traits::low(result, data[2]);
1648 result = Traits::low(result, data[3]);
1655 else if (
static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
1657 result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
1662 else if (
static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
1664 result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
1669 else if (
static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
1671 result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
1687 template <
typename opt_swap>
struct utf16_decoder
1689 typedef uint16_t type;
1691 template <
typename Traits>
static inline typename Traits::value_type process(
const uint16_t* data,
size_t size,
typename Traits::value_type result, Traits)
1695 uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
1700 result = Traits::low(result, lead);
1705 else if (
static_cast<unsigned int>(lead - 0xE000) < 0x2000)
1707 result = Traits::low(result, lead);
1712 else if (
static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
1714 uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
1716 if (
static_cast<unsigned int>(next - 0xDC00) < 0x400)
1718 result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
1739 template <
typename opt_swap>
struct utf32_decoder
1741 typedef uint32_t type;
1743 template <
typename Traits>
static inline typename Traits::value_type process(
const uint32_t* data,
size_t size,
typename Traits::value_type result, Traits)
1747 uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
1752 result = Traits::low(result, lead);
1759 result = Traits::high(result, lead);
1769 struct latin1_decoder
1771 typedef uint8_t type;
1773 template <
typename Traits>
static inline typename Traits::value_type process(
const uint8_t* data,
size_t size,
typename Traits::value_type result, Traits)
1777 result = Traits::low(result, *data);
1786 template <
size_t size>
struct wchar_selector;
1788 template <>
struct wchar_selector<2>
1790 typedef uint16_t type;
1791 typedef utf16_counter counter;
1792 typedef utf16_writer writer;
1793 typedef utf16_decoder<opt_false> decoder;
1796 template <>
struct wchar_selector<4>
1798 typedef uint32_t type;
1799 typedef utf32_counter counter;
1800 typedef utf32_writer writer;
1801 typedef utf32_decoder<opt_false> decoder;
1804 typedef wchar_selector<
sizeof(wchar_t)>::counter wchar_counter;
1805 typedef wchar_selector<
sizeof(wchar_t)>::writer wchar_writer;
1807 struct wchar_decoder
1809 typedef wchar_t type;
1811 template <
typename Traits>
static inline typename Traits::value_type process(
const wchar_t* data,
size_t size,
typename Traits::value_type result, Traits traits)
1813 typedef wchar_selector<
sizeof(wchar_t)>::decoder decoder;
1815 return decoder::process(
reinterpret_cast<const typename decoder::type*
>(data), size, result, traits);
1819#ifdef PUGIXML_WCHAR_MODE
1820 PUGI__FN
void convert_wchar_endian_swap(
wchar_t* result,
const wchar_t* data,
size_t length)
1822 for (
size_t i = 0; i < length; ++i)
1823 result[i] =
static_cast<wchar_t>(endian_swap(
static_cast<wchar_selector<sizeof(
wchar_t)
>::type>(data[i])));
1831 ct_parse_pcdata = 1,
1833 ct_parse_attr_ws = 4,
1835 ct_parse_cdata = 16,
1836 ct_parse_comment = 32,
1838 ct_start_symbol = 128
1841 static const unsigned char chartype_table[256] =
1843 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0,
1844 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1845 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0,
1846 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0,
1847 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1848 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192,
1849 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1850 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0,
1852 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1853 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1854 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1855 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1856 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1857 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1858 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1859 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
1864 ctx_special_pcdata = 1,
1865 ctx_special_attr = 2,
1866 ctx_start_symbol = 4,
1871 static const unsigned char chartypex_table[256] =
1873 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3,
1874 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1875 0, 0, 2, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0, 16, 16, 0,
1876 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 1, 0,
1878 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1879 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20,
1880 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1881 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0,
1883 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1884 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1885 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1886 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1887 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1888 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1889 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1890 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
1893#ifdef PUGIXML_WCHAR_MODE
1894 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
1896 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
1899 #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
1900 #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
1902 PUGI__FN
bool is_little_endian()
1904 unsigned int ui = 1;
1906 return *
reinterpret_cast<unsigned char*
>(&ui) == 1;
1909 PUGI__FN xml_encoding get_wchar_encoding()
1911 PUGI__STATIC_ASSERT(
sizeof(
wchar_t) == 2 ||
sizeof(
wchar_t) == 4);
1913 if (
sizeof(
wchar_t) == 2)
1914 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1916 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1919 PUGI__FN
bool parse_declaration_encoding(
const uint8_t* data,
size_t size,
const uint8_t*& out_encoding,
size_t& out_length)
1921 #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
1922 #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; }
1925 if (size < 6 || !((data[0] ==
'<') & (data[1] ==
'?') & (data[2] ==
'x') & (data[3] ==
'm') & (data[4] ==
'l') && PUGI__IS_CHARTYPE(data[5], ct_space)))
1929 for (
size_t i = 6; i + 1 < size; ++i)
1935 if (data[i] ==
'e' && data[i + 1] ==
'n')
1940 PUGI__SCANCHAR(
'e'); PUGI__SCANCHAR(
'n'); PUGI__SCANCHAR(
'c'); PUGI__SCANCHAR(
'o');
1941 PUGI__SCANCHAR(
'd'); PUGI__SCANCHAR(
'i'); PUGI__SCANCHAR(
'n'); PUGI__SCANCHAR(
'g');
1944 PUGI__SCANCHARTYPE(ct_space);
1945 PUGI__SCANCHAR(
'=');
1946 PUGI__SCANCHARTYPE(ct_space);
1949 uint8_t delimiter = (offset < size && data[offset] ==
'"') ?
'"' :
'\'';
1951 PUGI__SCANCHAR(delimiter);
1953 size_t start = offset;
1955 out_encoding = data + offset;
1957 PUGI__SCANCHARTYPE(ct_symbol);
1959 out_length = offset - start;
1961 PUGI__SCANCHAR(delimiter);
1969 #undef PUGI__SCANCHAR
1970 #undef PUGI__SCANCHARTYPE
1973 PUGI__FN xml_encoding guess_buffer_encoding(
const uint8_t* data,
size_t size)
1976 if (size < 4)
return encoding_utf8;
1978 uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1981 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff)
return encoding_utf32_be;
1982 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0)
return encoding_utf32_le;
1983 if (d0 == 0xfe && d1 == 0xff)
return encoding_utf16_be;
1984 if (d0 == 0xff && d1 == 0xfe)
return encoding_utf16_le;
1985 if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf)
return encoding_utf8;
1988 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c)
return encoding_utf32_be;
1989 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0)
return encoding_utf32_le;
1990 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f)
return encoding_utf16_be;
1991 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0)
return encoding_utf16_le;
1994 if (d0 == 0 && d1 == 0x3c)
return encoding_utf16_be;
1995 if (d0 == 0x3c && d1 == 0)
return encoding_utf16_le;
1998 const uint8_t* enc = 0;
1999 size_t enc_length = 0;
2001 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length))
2004 if (enc_length == 10
2005 && (enc[0] |
' ') ==
'i' && (enc[1] |
' ') ==
's' && (enc[2] |
' ') ==
'o'
2006 && enc[3] ==
'-' && enc[4] ==
'8' && enc[5] ==
'8' && enc[6] ==
'5' && enc[7] ==
'9'
2007 && enc[8] ==
'-' && enc[9] ==
'1')
2008 return encoding_latin1;
2012 && (enc[0] |
' ') ==
'l' && (enc[1] |
' ') ==
'a' && (enc[2] |
' ') ==
't'
2013 && (enc[3] |
' ') ==
'i' && (enc[4] |
' ') ==
'n'
2015 return encoding_latin1;
2018 return encoding_utf8;
2021 PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding,
const void* contents,
size_t size)
2024 if (encoding == encoding_wchar)
return get_wchar_encoding();
2027 if (encoding == encoding_utf16)
return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2030 if (encoding == encoding_utf32)
return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2033 if (encoding != encoding_auto)
return encoding;
2036 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
2038 return guess_buffer_encoding(data, size);
2041 PUGI__FN
bool get_mutable_buffer(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size,
bool is_mutable)
2043 size_t length = size /
sizeof(char_t);
2047 out_buffer =
static_cast<char_t*
>(
const_cast<void*
>(contents));
2048 out_length = length;
2052 char_t* buffer =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
2053 if (!buffer)
return false;
2056 memcpy(buffer, contents, length *
sizeof(char_t));
2058 assert(length == 0);
2062 out_buffer = buffer;
2063 out_length = length + 1;
2069#ifdef PUGIXML_WCHAR_MODE
2070 PUGI__FN
bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
2072 return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
2073 (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
2076 PUGI__FN
bool convert_buffer_endian_swap(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size,
bool is_mutable)
2078 const char_t* data =
static_cast<const char_t*
>(contents);
2079 size_t length = size /
sizeof(char_t);
2083 char_t* buffer =
const_cast<char_t*
>(data);
2085 convert_wchar_endian_swap(buffer, data, length);
2087 out_buffer = buffer;
2088 out_length = length;
2092 char_t* buffer =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
2093 if (!buffer)
return false;
2095 convert_wchar_endian_swap(buffer, data, length);
2098 out_buffer = buffer;
2099 out_length = length + 1;
2105 template <
typename D> PUGI__FN
bool convert_buffer_generic(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size, D)
2107 const typename D::type* data =
static_cast<const typename D::type*
>(contents);
2108 size_t data_length = size /
sizeof(
typename D::type);
2111 size_t length = D::process(data, data_length, 0, wchar_counter());
2114 char_t* buffer =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
2115 if (!buffer)
return false;
2118 wchar_writer::value_type obegin =
reinterpret_cast<wchar_writer::value_type
>(buffer);
2119 wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer());
2121 assert(oend == obegin + length);
2124 out_buffer = buffer;
2125 out_length = length + 1;
2130 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)
2133 xml_encoding wchar_encoding = get_wchar_encoding();
2136 if (encoding == wchar_encoding)
2137 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2140 if (need_endian_swap_utf(encoding, wchar_encoding))
2141 return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
2144 if (encoding == encoding_utf8)
2145 return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder());
2148 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2150 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2152 return (native_encoding == encoding) ?
2153 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
2154 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
2158 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2160 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2162 return (native_encoding == encoding) ?
2163 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
2164 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
2168 if (encoding == encoding_latin1)
2169 return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder());
2171 assert(
false &&
"Invalid encoding");
2175 template <
typename D> PUGI__FN
bool convert_buffer_generic(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size, D)
2177 const typename D::type* data =
static_cast<const typename D::type*
>(contents);
2178 size_t data_length = size /
sizeof(
typename D::type);
2181 size_t length = D::process(data, data_length, 0, utf8_counter());
2184 char_t* buffer =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
2185 if (!buffer)
return false;
2188 uint8_t* obegin =
reinterpret_cast<uint8_t*
>(buffer);
2189 uint8_t* oend = D::process(data, data_length, obegin, utf8_writer());
2191 assert(oend == obegin + length);
2194 out_buffer = buffer;
2195 out_length = length + 1;
2200 PUGI__FN
size_t get_latin1_7bit_prefix_length(
const uint8_t* data,
size_t size)
2202 for (
size_t i = 0; i < size; ++i)
2209 PUGI__FN
bool convert_buffer_latin1(char_t*& out_buffer,
size_t& out_length,
const void* contents,
size_t size,
bool is_mutable)
2211 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
2212 size_t data_length = size;
2215 size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
2216 assert(prefix_length <= data_length);
2218 const uint8_t* postfix = data + prefix_length;
2219 size_t postfix_length = data_length - prefix_length;
2222 if (postfix_length == 0)
return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2225 size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter());
2228 char_t* buffer =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
2229 if (!buffer)
return false;
2232 memcpy(buffer, data, prefix_length);
2234 uint8_t* obegin =
reinterpret_cast<uint8_t*
>(buffer);
2235 uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer());
2237 assert(oend == obegin + length);
2240 out_buffer = buffer;
2241 out_length = length + 1;
2246 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)
2249 if (encoding == encoding_utf8)
2250 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
2253 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
2255 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2257 return (native_encoding == encoding) ?
2258 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
2259 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
2263 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
2265 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2267 return (native_encoding == encoding) ?
2268 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
2269 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
2273 if (encoding == encoding_latin1)
2274 return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
2276 assert(
false &&
"Invalid encoding");
2281 PUGI__FN
size_t as_utf8_begin(
const wchar_t* str,
size_t length)
2284 return wchar_decoder::process(str, length, 0, utf8_counter());
2287 PUGI__FN
void as_utf8_end(
char* buffer,
size_t size,
const wchar_t* str,
size_t length)
2290 uint8_t* begin =
reinterpret_cast<uint8_t*
>(buffer);
2291 uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer());
2293 assert(begin + size == end);
2298#ifndef PUGIXML_NO_STL
2299 PUGI__FN std::string as_utf8_impl(
const wchar_t* str,
size_t length)
2302 size_t size = as_utf8_begin(str, length);
2306 result.resize(size);
2309 if (size > 0) as_utf8_end(&result[0], size, str, length);
2314 PUGI__FN std::basic_string<wchar_t> as_wide_impl(
const char* str,
size_t size)
2316 const uint8_t* data =
reinterpret_cast<const uint8_t*
>(str);
2319 size_t length = utf8_decoder::process(data, size, 0, wchar_counter());
2322 std::basic_string<wchar_t> result;
2323 result.resize(length);
2328 wchar_writer::value_type begin =
reinterpret_cast<wchar_writer::value_type
>(&result[0]);
2329 wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer());
2331 assert(begin + length == end);
2339 template <
typename Header>
2340 inline bool strcpy_insitu_allow(
size_t length,
const Header& header, uintptr_t header_mask, char_t* target)
2343 if (header & xml_memory_page_contents_shared_mask)
return false;
2345 size_t target_length = strlength(target);
2348 if ((header & header_mask) == 0)
return target_length >= length;
2351 const size_t reuse_threshold = 32;
2353 return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
2356 template <
typename String,
typename Header>
2357 PUGI__FN
bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask,
const char_t* source,
size_t source_length)
2359 if (source_length == 0)
2362 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
2364 if (header & header_mask) alloc->deallocate_string(dest);
2368 header &= ~header_mask;
2372 else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest))
2375 memcpy(dest, source, source_length *
sizeof(char_t));
2376 dest[source_length] = 0;
2382 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
2384 if (!alloc->reserve())
return false;
2387 char_t* buf = alloc->allocate_string(source_length + 1);
2388 if (!buf)
return false;
2391 memcpy(buf, source, source_length *
sizeof(char_t));
2392 buf[source_length] = 0;
2395 if (header & header_mask) alloc->deallocate_string(dest);
2399 header |= header_mask;
2410 gap(): end(0), size(0)
2416 void push(char_t*& s,
size_t count)
2422 memmove(end - size, end,
reinterpret_cast<char*
>(s) -
reinterpret_cast<char*
>(end));
2433 char_t* flush(char_t* s)
2439 memmove(end - size, end,
reinterpret_cast<char*
>(s) -
reinterpret_cast<char*
>(end));
2447 PUGI__FN char_t* strconv_escape(char_t* s, gap& g)
2449 char_t* stre = s + 1;
2455 unsigned int ucsc = 0;
2463 if (ch ==
';')
return stre;
2467 if (
static_cast<unsigned int>(ch -
'0') <= 9)
2468 ucsc = 16 * ucsc + (ch -
'0');
2469 else if (
static_cast<unsigned int>((ch |
' ') -
'a') <= 5)
2470 ucsc = 16 * ucsc + ((ch |
' ') -
'a' + 10);
2483 char_t ch = *++stre;
2485 if (ch ==
';')
return stre;
2489 if (
static_cast<unsigned int>(ch -
'0') <= 9)
2490 ucsc = 10 * ucsc + (ch -
'0');
2502 #ifdef PUGIXML_WCHAR_MODE
2503 s =
reinterpret_cast<char_t*
>(wchar_writer::any(
reinterpret_cast<wchar_writer::value_type
>(s), ucsc));
2505 s =
reinterpret_cast<char_t*
>(utf8_writer::any(
reinterpret_cast<uint8_t*
>(s), ucsc));
2508 g.push(s, stre - s);
2518 if (*++stre ==
'p' && *++stre ==
';')
2523 g.push(s, stre - s);
2527 else if (*stre ==
'p')
2529 if (*++stre ==
'o' && *++stre ==
's' && *++stre ==
';')
2534 g.push(s, stre - s);
2543 if (*++stre ==
't' && *++stre ==
';')
2548 g.push(s, stre - s);
2556 if (*++stre ==
't' && *++stre ==
';')
2561 g.push(s, stre - s);
2569 if (*++stre ==
'u' && *++stre ==
'o' && *++stre ==
't' && *++stre ==
';')
2574 g.push(s, stre - s);
2588 #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
2589 #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
2590 #define PUGI__OPTSET(OPT) ( optmsk & (OPT) )
2591 #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
2592 #define PUGI__POPNODE() { cursor = cursor->parent; }
2593 #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
2594 #define PUGI__SCANWHILE(X) { while (X) ++s; }
2595 #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
2596 #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; }
2597 #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t*>(0)
2598 #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); }
2600 PUGI__FN char_t* strconv_comment(char_t* s, char_t endch)
2606 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment));
2612 if (*s ==
'\n') g.push(s, 1);
2614 else if (s[0] ==
'-' && s[1] ==
'-' && PUGI__ENDSWITH(s[2],
'>'))
2618 return s + (s[2] ==
'>' ? 3 : 2);
2628 PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch)
2634 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata));
2640 if (*s ==
'\n') g.push(s, 1);
2642 else if (s[0] ==
']' && s[1] ==
']' && PUGI__ENDSWITH(s[2],
'>'))
2656 typedef char_t* (*strconv_pcdata_t)(char_t*);
2658 template <
typename opt_trim,
typename opt_eol,
typename opt_escape>
struct strconv_pcdata_impl
2660 static char_t* parse(char_t* s)
2668 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata));
2672 char_t* end = g.flush(s);
2674 if (opt_trim::value)
2675 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2682 else if (opt_eol::value && *s ==
'\r')
2686 if (*s ==
'\n') g.push(s, 1);
2688 else if (opt_escape::value && *s ==
'&')
2690 s = strconv_escape(s, g);
2694 char_t* end = g.flush(s);
2696 if (opt_trim::value)
2697 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
2709 PUGI__FN strconv_pcdata_t get_strconv_pcdata(
unsigned int optmask)
2711 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
2713 switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4))
2715 case 0:
return strconv_pcdata_impl<opt_false, opt_false, opt_false>::parse;
2716 case 1:
return strconv_pcdata_impl<opt_false, opt_false, opt_true>::parse;
2717 case 2:
return strconv_pcdata_impl<opt_false, opt_true, opt_false>::parse;
2718 case 3:
return strconv_pcdata_impl<opt_false, opt_true, opt_true>::parse;
2719 case 4:
return strconv_pcdata_impl<opt_true, opt_false, opt_false>::parse;
2720 case 5:
return strconv_pcdata_impl<opt_true, opt_false, opt_true>::parse;
2721 case 6:
return strconv_pcdata_impl<opt_true, opt_true, opt_false>::parse;
2722 case 7:
return strconv_pcdata_impl<opt_true, opt_true, opt_true>::parse;
2723 default: assert(
false);
return 0;
2727 typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
2729 template <
typename opt_escape>
struct strconv_attribute_impl
2731 static char_t* parse_wnorm(char_t* s, char_t end_quote)
2736 if (PUGI__IS_CHARTYPE(*s, ct_space))
2741 while (PUGI__IS_CHARTYPE(*str, ct_space));
2748 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space));
2750 if (*s == end_quote)
2752 char_t* str = g.flush(s);
2755 while (PUGI__IS_CHARTYPE(*str, ct_space));
2759 else if (PUGI__IS_CHARTYPE(*s, ct_space))
2763 if (PUGI__IS_CHARTYPE(*s, ct_space))
2765 char_t* str = s + 1;
2766 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
2771 else if (opt_escape::value && *s ==
'&')
2773 s = strconv_escape(s, g);
2783 static char_t* parse_wconv(char_t* s, char_t end_quote)
2789 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws));
2791 if (*s == end_quote)
2797 else if (PUGI__IS_CHARTYPE(*s, ct_space))
2803 if (*s ==
'\n') g.push(s, 1);
2807 else if (opt_escape::value && *s ==
'&')
2809 s = strconv_escape(s, g);
2819 static char_t* parse_eol(char_t* s, char_t end_quote)
2825 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
2827 if (*s == end_quote)
2833 else if (*s ==
'\r')
2837 if (*s ==
'\n') g.push(s, 1);
2839 else if (opt_escape::value && *s ==
'&')
2841 s = strconv_escape(s, g);
2851 static char_t* parse_simple(char_t* s, char_t end_quote)
2857 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
2859 if (*s == end_quote)
2865 else if (opt_escape::value && *s ==
'&')
2867 s = strconv_escape(s, g);
2878 PUGI__FN strconv_attribute_t get_strconv_attribute(
unsigned int optmask)
2880 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
2882 switch ((optmask >> 4) & 15)
2884 case 0:
return strconv_attribute_impl<opt_false>::parse_simple;
2885 case 1:
return strconv_attribute_impl<opt_true>::parse_simple;
2886 case 2:
return strconv_attribute_impl<opt_false>::parse_eol;
2887 case 3:
return strconv_attribute_impl<opt_true>::parse_eol;
2888 case 4:
return strconv_attribute_impl<opt_false>::parse_wconv;
2889 case 5:
return strconv_attribute_impl<opt_true>::parse_wconv;
2890 case 6:
return strconv_attribute_impl<opt_false>::parse_wconv;
2891 case 7:
return strconv_attribute_impl<opt_true>::parse_wconv;
2892 case 8:
return strconv_attribute_impl<opt_false>::parse_wnorm;
2893 case 9:
return strconv_attribute_impl<opt_true>::parse_wnorm;
2894 case 10:
return strconv_attribute_impl<opt_false>::parse_wnorm;
2895 case 11:
return strconv_attribute_impl<opt_true>::parse_wnorm;
2896 case 12:
return strconv_attribute_impl<opt_false>::parse_wnorm;
2897 case 13:
return strconv_attribute_impl<opt_true>::parse_wnorm;
2898 case 14:
return strconv_attribute_impl<opt_false>::parse_wnorm;
2899 case 15:
return strconv_attribute_impl<opt_true>::parse_wnorm;
2900 default: assert(
false);
return 0;
2904 inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
2906 xml_parse_result result;
2907 result.status = status;
2908 result.offset = offset;
2915 xml_allocator* alloc;
2916 char_t* error_offset;
2917 xml_parse_status error_status;
2919 xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(0), error_status(status_ok)
2930 char_t* parse_doctype_primitive(char_t* s)
2932 if (*s ==
'"' || *s ==
'\'')
2936 PUGI__SCANFOR(*s == ch);
2937 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2941 else if (s[0] ==
'<' && s[1] ==
'?')
2945 PUGI__SCANFOR(s[0] ==
'?' && s[1] ==
'>');
2946 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2950 else if (s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'-' && s[3] ==
'-')
2953 PUGI__SCANFOR(s[0] ==
'-' && s[1] ==
'-' && s[2] ==
'>');
2954 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2958 else PUGI__THROW_ERROR(status_bad_doctype, s);
2963 char_t* parse_doctype_ignore(char_t* s)
2967 assert(s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'[');
2972 if (s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'[')
2978 else if (s[0] ==
']' && s[1] ==
']' && s[2] ==
'>')
2991 PUGI__THROW_ERROR(status_bad_doctype, s);
2994 char_t* parse_doctype_group(char_t* s, char_t endch)
2998 assert((s[0] ==
'<' || s[0] == 0) && s[1] ==
'!');
3003 if (s[0] ==
'<' && s[1] ==
'!' && s[2] !=
'-')
3008 s = parse_doctype_ignore(s);
3018 else if (s[0] ==
'<' || s[0] ==
'"' || s[0] ==
'\'')
3021 s = parse_doctype_primitive(s);
3035 if (depth != 0 || endch !=
'>') PUGI__THROW_ERROR(status_bad_doctype, s);
3040 char_t* parse_exclamation(char_t* s, xml_node_struct* cursor,
unsigned int optmsk, char_t endch)
3053 if (PUGI__OPTSET(parse_comments))
3055 PUGI__PUSHNODE(node_comment);
3059 if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments))
3061 s = strconv_comment(s, endch);
3063 if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
3068 PUGI__SCANFOR(s[0] ==
'-' && s[1] ==
'-' && PUGI__ENDSWITH(s[2],
'>'));
3069 PUGI__CHECK_ERROR(status_bad_comment, s);
3071 if (PUGI__OPTSET(parse_comments))
3074 s += (s[2] ==
'>' ? 3 : 2);
3077 else PUGI__THROW_ERROR(status_bad_comment, s);
3082 if (*++s==
'C' && *++s==
'D' && *++s==
'A' && *++s==
'T' && *++s==
'A' && *++s ==
'[')
3086 if (PUGI__OPTSET(parse_cdata))
3088 PUGI__PUSHNODE(node_cdata);
3091 if (PUGI__OPTSET(parse_eol))
3093 s = strconv_cdata(s, endch);
3095 if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
3100 PUGI__SCANFOR(s[0] ==
']' && s[1] ==
']' && PUGI__ENDSWITH(s[2],
'>'));
3101 PUGI__CHECK_ERROR(status_bad_cdata, s);
3109 PUGI__SCANFOR(s[0] ==
']' && s[1] ==
']' && PUGI__ENDSWITH(s[2],
'>'));
3110 PUGI__CHECK_ERROR(status_bad_cdata, s);
3115 s += (s[1] ==
'>' ? 2 : 1);
3117 else PUGI__THROW_ERROR(status_bad_cdata, s);
3119 else if (s[0] ==
'D' && s[1] ==
'O' && s[2] ==
'C' && s[3] ==
'T' && s[4] ==
'Y' && s[5] ==
'P' && PUGI__ENDSWITH(s[6],
'E'))
3123 if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
3125 char_t* mark = s + 9;
3127 s = parse_doctype_group(s, endch);
3130 assert((*s == 0 && endch ==
'>') || *s ==
'>');
3133 if (PUGI__OPTSET(parse_doctype))
3135 while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
3137 PUGI__PUSHNODE(node_doctype);
3139 cursor->value = mark;
3142 else if (*s == 0 && endch ==
'-') PUGI__THROW_ERROR(status_bad_comment, s);
3143 else if (*s == 0 && endch ==
'[') PUGI__THROW_ERROR(status_bad_cdata, s);
3144 else PUGI__THROW_ERROR(status_unrecognized_tag, s);
3149 char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor,
unsigned int optmsk, char_t endch)
3152 xml_node_struct* cursor = ref_cursor;
3161 if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s);
3163 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
3164 PUGI__CHECK_ERROR(status_bad_pi, s);
3167 bool declaration = (target[0] |
' ') ==
'x' && (target[1] |
' ') ==
'm' && (target[2] |
' ') ==
'l' && target + 3 == s;
3169 if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
3174 if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
3176 PUGI__PUSHNODE(node_declaration);
3180 PUGI__PUSHNODE(node_pi);
3183 cursor->name = target;
3191 if (!PUGI__ENDSWITH(*s,
'>')) PUGI__THROW_ERROR(status_bad_pi, s);
3196 else if (PUGI__IS_CHARTYPE(ch, ct_space))
3203 PUGI__SCANFOR(s[0] ==
'?' && PUGI__ENDSWITH(s[1],
'>'));
3204 PUGI__CHECK_ERROR(status_bad_pi, s);
3217 cursor->value = value;
3226 else PUGI__THROW_ERROR(status_bad_pi, s);
3231 PUGI__SCANFOR(s[0] ==
'?' && PUGI__ENDSWITH(s[1],
'>'));
3232 PUGI__CHECK_ERROR(status_bad_pi, s);
3234 s += (s[1] ==
'>' ? 2 : 1);
3238 ref_cursor = cursor;
3243 char_t* parse_tree(char_t* s, xml_node_struct* root,
unsigned int optmsk, char_t endch)
3245 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
3246 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
3249 xml_node_struct* cursor = root;
3259 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
3261 PUGI__PUSHNODE(node_element);
3265 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol));
3272 else if (PUGI__IS_CHARTYPE(ch, ct_space))
3279 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
3281 xml_attribute_struct* a = append_new_attribute(cursor, *alloc);
3282 if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
3286 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol));
3289 if (PUGI__IS_CHARTYPE(ch, ct_space))
3301 if (*s ==
'"' || *s ==
'\'')
3307 s = strconv_attribute(s, ch);
3309 if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
3314 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s);
3316 else PUGI__THROW_ERROR(status_bad_attribute, s);
3318 else PUGI__THROW_ERROR(status_bad_attribute, s);
3330 else if (*s == 0 && endch ==
'>')
3335 else PUGI__THROW_ERROR(status_bad_start_element, s);
3343 else if (*s == 0 && endch ==
'>')
3347 else PUGI__THROW_ERROR(status_bad_start_element, s);
3354 if (!PUGI__ENDSWITH(*s,
'>')) PUGI__THROW_ERROR(status_bad_start_element, s);
3365 if (endch !=
'>') PUGI__THROW_ERROR(status_bad_start_element, s);
3367 else PUGI__THROW_ERROR(status_bad_start_element, s);
3375 char_t* name = cursor->name;
3376 if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
3378 while (PUGI__IS_CHARTYPE(*s, ct_symbol))
3380 if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
3385 if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
3386 else PUGI__THROW_ERROR(status_end_element_mismatch, mark);
3395 if (endch !=
'>') PUGI__THROW_ERROR(status_bad_end_element, s);
3399 if (*s !=
'>') PUGI__THROW_ERROR(status_bad_end_element, s);
3405 s = parse_question(s, cursor, optmsk, endch);
3409 if (PUGI__NODETYPE(cursor) == node_declaration)
goto LOC_ATTRIBUTES;
3413 s = parse_exclamation(s, cursor, optmsk, endch);
3416 else if (*s == 0 && endch ==
'?') PUGI__THROW_ERROR(status_bad_pi, s);
3417 else PUGI__THROW_ERROR(status_unrecognized_tag, s);
3425 if (*s ==
'<' || !*s)
3430 if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI__OPTSET(parse_trim_pcdata))
3434 else if (PUGI__OPTSET(parse_ws_pcdata_single))
3436 if (s[0] !=
'<' || s[1] !=
'/' || cursor->first_child)
continue;
3440 if (!PUGI__OPTSET(parse_trim_pcdata))
3443 if (cursor->parent || PUGI__OPTSET(parse_fragment))
3445 if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value)
3451 PUGI__PUSHNODE(node_pcdata);
3458 s = strconv_pcdata(s);
3464 PUGI__SCANFOR(*s ==
'<');
3476 if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s);
3481 #ifdef PUGIXML_WCHAR_MODE
3482 static char_t* parse_skip_bom(char_t* s)
3484 unsigned int bom = 0xfeff;
3485 return (s[0] ==
static_cast<wchar_t>(bom)) ? s + 1 : s;
3488 static char_t* parse_skip_bom(char_t* s)
3490 return (s[0] ==
'\xef' && s[1] ==
'\xbb' && s[2] ==
'\xbf') ? s + 3 : s;
3494 static bool has_element_node_siblings(xml_node_struct* node)
3498 if (PUGI__NODETYPE(node) == node_element)
return true;
3500 node = node->next_sibling;
3506 static xml_parse_result parse(char_t* buffer,
size_t length, xml_document_struct* xmldoc, xml_node_struct* root,
unsigned int optmsk)
3510 return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element);
3513 xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
3516 xml_parser parser(
static_cast<xml_allocator*
>(xmldoc));
3519 char_t endch = buffer[length - 1];
3520 buffer[length - 1] = 0;
3523 char_t* buffer_data = parse_skip_bom(buffer);
3526 parser.parse_tree(buffer_data, root, optmsk, endch);
3528 xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
3529 assert(result.offset >= 0 &&
static_cast<size_t>(result.offset) <= length);
3535 return make_parse_result(status_unrecognized_tag, length - 1);
3538 xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0;
3540 if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
3541 return make_parse_result(status_no_document_element, length - 1);
3546 if (result.offset > 0 &&
static_cast<size_t>(result.offset) == length - 1 && endch == 0)
3555 PUGI__FN xml_encoding get_write_native_encoding()
3557 #ifdef PUGIXML_WCHAR_MODE
3558 return get_wchar_encoding();
3560 return encoding_utf8;
3564 PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
3567 if (encoding == encoding_wchar)
return get_wchar_encoding();
3570 if (encoding == encoding_utf16)
return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
3573 if (encoding == encoding_utf32)
return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
3576 if (encoding != encoding_auto)
return encoding;
3579 return encoding_utf8;
3582 template <
typename D,
typename T> PUGI__FN
size_t convert_buffer_output_generic(
typename T::value_type dest,
const char_t* data,
size_t length, D, T)
3584 PUGI__STATIC_ASSERT(
sizeof(char_t) ==
sizeof(
typename D::type));
3586 typename T::value_type end = D::process(
reinterpret_cast<const typename D::type*
>(data), length, dest, T());
3588 return static_cast<size_t>(end - dest) *
sizeof(*dest);
3591 template <
typename D,
typename T> PUGI__FN
size_t convert_buffer_output_generic(
typename T::value_type dest,
const char_t* data,
size_t length, D, T,
bool opt_swap)
3593 PUGI__STATIC_ASSERT(
sizeof(char_t) ==
sizeof(
typename D::type));
3595 typename T::value_type end = D::process(
reinterpret_cast<const typename D::type*
>(data), length, dest, T());
3599 for (
typename T::value_type i = dest; i != end; ++i)
3600 *i = endian_swap(*i);
3603 return static_cast<size_t>(end - dest) *
sizeof(*dest);
3606#ifdef PUGIXML_WCHAR_MODE
3607 PUGI__FN
size_t get_valid_length(
const char_t* data,
size_t length)
3609 if (length < 1)
return 0;
3612 return (
sizeof(
wchar_t) == 2 &&
static_cast<unsigned int>(
static_cast<uint16_t
>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
3615 PUGI__FN
size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32,
const char_t* data,
size_t length, xml_encoding encoding)
3618 if (need_endian_swap_utf(encoding, get_wchar_encoding()))
3620 convert_wchar_endian_swap(r_char, data, length);
3622 return length *
sizeof(char_t);
3626 if (encoding == encoding_utf8)
3627 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer());
3630 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3632 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
3634 return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding);
3638 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3640 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
3642 return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding);
3646 if (encoding == encoding_latin1)
3647 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer());
3649 assert(
false &&
"Invalid encoding");
3653 PUGI__FN
size_t get_valid_length(
const char_t* data,
size_t length)
3655 if (length < 5)
return 0;
3657 for (
size_t i = 1; i <= 4; ++i)
3659 uint8_t ch =
static_cast<uint8_t
>(data[length - i]);
3662 if ((ch & 0xc0) != 0x80)
return length - i;
3669 PUGI__FN
size_t convert_buffer_output(char_t* , uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32,
const char_t* data,
size_t length, xml_encoding encoding)
3671 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
3673 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
3675 return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding);
3678 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
3680 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
3682 return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding);
3685 if (encoding == encoding_latin1)
3686 return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer());
3688 assert(
false &&
"Invalid encoding");
3693 class xml_buffered_writer
3695 xml_buffered_writer(
const xml_buffered_writer&);
3696 xml_buffered_writer& operator=(
const xml_buffered_writer&);
3699 xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
3701 PUGI__STATIC_ASSERT(bufcapacity >= 8);
3706 flush(buffer, bufsize);
3711 void flush(
const char_t* data,
size_t size)
3713 if (size == 0)
return;
3716 if (encoding == get_write_native_encoding())
3717 writer.write(data, size *
sizeof(char_t));
3721 size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);
3722 assert(result <=
sizeof(scratch));
3725 writer.write(scratch.data_u8, result);
3729 void write_direct(
const char_t* data,
size_t length)
3735 if (length > bufcapacity)
3737 if (encoding == get_write_native_encoding())
3740 writer.write(data, length *
sizeof(char_t));
3745 while (length > bufcapacity)
3749 size_t chunk_size = get_valid_length(data, bufcapacity);
3753 flush(data, chunk_size);
3757 length -= chunk_size;
3764 memcpy(buffer + bufsize, data, length *
sizeof(char_t));
3768 void write_buffer(
const char_t* data,
size_t length)
3770 size_t offset = bufsize;
3772 if (offset + length <= bufcapacity)
3774 memcpy(buffer + offset, data, length *
sizeof(char_t));
3775 bufsize = offset + length;
3779 write_direct(data, length);
3783 void write_string(
const char_t* data)
3786 size_t offset = bufsize;
3788 while (*data && offset < bufcapacity)
3789 buffer[offset++] = *data++;
3792 if (offset < bufcapacity)
3799 size_t length = offset - bufsize;
3800 size_t extra = length - get_valid_length(data - length, length);
3802 bufsize = offset - extra;
3804 write_direct(data - extra, strlength(data) + extra);
3808 void write(char_t d0)
3810 size_t offset = bufsize;
3811 if (offset > bufcapacity - 1) offset = flush();
3813 buffer[offset + 0] = d0;
3814 bufsize = offset + 1;
3817 void write(char_t d0, char_t d1)
3819 size_t offset = bufsize;
3820 if (offset > bufcapacity - 2) offset = flush();
3822 buffer[offset + 0] = d0;
3823 buffer[offset + 1] = d1;
3824 bufsize = offset + 2;
3827 void write(char_t d0, char_t d1, char_t d2)
3829 size_t offset = bufsize;
3830 if (offset > bufcapacity - 3) offset = flush();
3832 buffer[offset + 0] = d0;
3833 buffer[offset + 1] = d1;
3834 buffer[offset + 2] = d2;
3835 bufsize = offset + 3;
3838 void write(char_t d0, char_t d1, char_t d2, char_t d3)
3840 size_t offset = bufsize;
3841 if (offset > bufcapacity - 4) offset = flush();
3843 buffer[offset + 0] = d0;
3844 buffer[offset + 1] = d1;
3845 buffer[offset + 2] = d2;
3846 buffer[offset + 3] = d3;
3847 bufsize = offset + 4;
3850 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
3852 size_t offset = bufsize;
3853 if (offset > bufcapacity - 5) offset = flush();
3855 buffer[offset + 0] = d0;
3856 buffer[offset + 1] = d1;
3857 buffer[offset + 2] = d2;
3858 buffer[offset + 3] = d3;
3859 buffer[offset + 4] = d4;
3860 bufsize = offset + 5;
3863 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
3865 size_t offset = bufsize;
3866 if (offset > bufcapacity - 6) offset = flush();
3868 buffer[offset + 0] = d0;
3869 buffer[offset + 1] = d1;
3870 buffer[offset + 2] = d2;
3871 buffer[offset + 3] = d3;
3872 buffer[offset + 4] = d4;
3873 buffer[offset + 5] = d5;
3874 bufsize = offset + 6;
3883 #ifdef PUGIXML_MEMORY_OUTPUT_STACK
3884 PUGIXML_MEMORY_OUTPUT_STACK
3889 bufcapacity = bufcapacitybytes / (
sizeof(char_t) + 4)
3892 char_t buffer[bufcapacity];
3896 uint8_t data_u8[4 * bufcapacity];
3897 uint16_t data_u16[2 * bufcapacity];
3898 uint32_t data_u32[bufcapacity];
3899 char_t data_char[bufcapacity];
3904 xml_encoding encoding;
3907 PUGI__FN
void text_output_escaped(xml_buffered_writer& writer,
const char_t* s, chartypex_t type,
unsigned int flags)
3911 const char_t* prev = s;
3914 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type));
3916 writer.write_buffer(prev,
static_cast<size_t>(s - prev));
3922 writer.write(
'&',
'a',
'm',
'p',
';');
3926 writer.write(
'&',
'l',
't',
';');
3930 writer.write(
'&',
'g',
't',
';');
3934 if (flags & format_attribute_single_quote)
3937 writer.write(
'&',
'q',
'u',
'o',
't',
';');
3941 if (flags & format_attribute_single_quote)
3942 writer.write(
'&',
'a',
'p',
'o',
's',
';');
3949 unsigned int ch =
static_cast<unsigned int>(*s++);
3952 if (!(flags & format_skip_control_chars))
3953 writer.write(
'&',
'#',
static_cast<char_t
>((ch / 10) +
'0'),
static_cast<char_t
>((ch % 10) +
'0'),
';');
3959 PUGI__FN
void text_output(xml_buffered_writer& writer,
const char_t* s, chartypex_t type,
unsigned int flags)
3961 if (flags & format_no_escapes)
3962 writer.write_string(s);
3964 text_output_escaped(writer, s, type, flags);
3967 PUGI__FN
void text_output_cdata(xml_buffered_writer& writer,
const char_t* s)
3971 writer.write(
'<',
'!',
'[',
'C',
'D');
3972 writer.write(
'A',
'T',
'A',
'[');
3974 const char_t* prev = s;
3977 while (*s && !(s[0] ==
']' && s[1] ==
']' && s[2] ==
'>')) ++s;
3982 writer.write_buffer(prev,
static_cast<size_t>(s - prev));
3984 writer.write(
']',
']',
'>');
3989 PUGI__FN
void text_output_indent(xml_buffered_writer& writer,
const char_t* indent,
size_t indent_length,
unsigned int depth)
3991 switch (indent_length)
3995 for (
unsigned int i = 0; i < depth; ++i)
3996 writer.write(indent[0]);
4002 for (
unsigned int i = 0; i < depth; ++i)
4003 writer.write(indent[0], indent[1]);
4009 for (
unsigned int i = 0; i < depth; ++i)
4010 writer.write(indent[0], indent[1], indent[2]);
4016 for (
unsigned int i = 0; i < depth; ++i)
4017 writer.write(indent[0], indent[1], indent[2], indent[3]);
4023 for (
unsigned int i = 0; i < depth; ++i)
4024 writer.write_buffer(indent, indent_length);
4029 PUGI__FN
void node_output_comment(xml_buffered_writer& writer,
const char_t* s)
4031 writer.write(
'<',
'!',
'-',
'-');
4035 const char_t* prev = s;
4038 while (*s && !(s[0] ==
'-' && (s[1] ==
'-' || s[1] == 0))) ++s;
4040 writer.write_buffer(prev,
static_cast<size_t>(s - prev));
4046 writer.write(
'-',
' ');
4051 writer.write(
'-',
'-',
'>');
4054 PUGI__FN
void node_output_pi_value(xml_buffered_writer& writer,
const char_t* s)
4058 const char_t* prev = s;
4061 while (*s && !(s[0] ==
'?' && s[1] ==
'>')) ++s;
4063 writer.write_buffer(prev,
static_cast<size_t>(s - prev));
4067 assert(s[0] ==
'?' && s[1] ==
'>');
4069 writer.write(
'?',
' ',
'>');
4075 PUGI__FN
void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node,
const char_t* indent,
size_t indent_length,
unsigned int flags,
unsigned int depth)
4077 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
4078 const char_t enquotation_char = (flags & format_attribute_single_quote) ?
'\'' :
'"';
4080 for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
4082 if ((flags & (format_indent_attributes | format_raw)) == format_indent_attributes)
4086 text_output_indent(writer, indent, indent_length, depth + 1);
4093 writer.write_string(a->name ? a->name + 0 : default_name);
4094 writer.write(
'=', enquotation_char);
4097 text_output(writer, a->value, ctx_special_attr, flags);
4099 writer.write(enquotation_char);
4103 PUGI__FN
bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node,
const char_t* indent,
size_t indent_length,
unsigned int flags,
unsigned int depth)
4105 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
4106 const char_t* name = node->name ? node->name + 0 : default_name;
4109 writer.write_string(name);
4111 if (node->first_attribute)
4112 node_output_attributes(writer, node, indent, indent_length, flags, depth);
4117 if (!node->first_child)
4119 if (flags & format_no_empty_element_tags)
4121 writer.write(
'>',
'<',
'/');
4122 writer.write_string(name);
4129 if ((flags & format_raw) == 0)
4132 writer.write(
'/',
'>');
4148 text_output(writer, node->value, ctx_special_pcdata, flags);
4150 if (!node->first_child)
4152 writer.write(
'<',
'/');
4153 writer.write_string(name);
4165 PUGI__FN
void node_output_end(xml_buffered_writer& writer, xml_node_struct* node)
4167 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
4168 const char_t* name = node->name ? node->name + 0 : default_name;
4170 writer.write(
'<',
'/');
4171 writer.write_string(name);
4175 PUGI__FN
void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node,
unsigned int flags)
4177 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
4179 switch (PUGI__NODETYPE(node))
4182 text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(
""), ctx_special_pcdata, flags);
4186 text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT(
""));
4190 node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT(
""));
4194 writer.write(
'<',
'?');
4195 writer.write_string(node->name ? node->name + 0 : default_name);
4200 node_output_pi_value(writer, node->value);
4203 writer.write(
'?',
'>');
4206 case node_declaration:
4207 writer.write(
'<',
'?');
4208 writer.write_string(node->name ? node->name + 0 : default_name);
4209 node_output_attributes(writer, node, PUGIXML_TEXT(
""), 0, flags | format_raw, 0);
4210 writer.write(
'?',
'>');
4214 writer.write(
'<',
'!',
'D',
'O',
'C');
4215 writer.write(
'T',
'Y',
'P',
'E');
4220 writer.write_string(node->value);
4227 assert(
false &&
"Invalid node type");
4237 PUGI__FN
void node_output(xml_buffered_writer& writer, xml_node_struct* root,
const char_t* indent,
unsigned int flags,
unsigned int depth)
4239 size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0;
4240 unsigned int indent_flags = indent_indent;
4242 xml_node_struct* node = root;
4249 if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata)
4251 node_output_simple(writer, node, flags);
4257 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4260 if ((indent_flags & indent_indent) && indent_length)
4261 text_output_indent(writer, indent, indent_length, depth);
4263 if (PUGI__NODETYPE(node) == node_element)
4265 indent_flags = indent_newline | indent_indent;
4267 if (node_output_start(writer, node, indent, indent_length, flags, depth))
4273 node = node->first_child;
4278 else if (PUGI__NODETYPE(node) == node_document)
4280 indent_flags = indent_indent;
4282 if (node->first_child)
4284 node = node->first_child;
4290 node_output_simple(writer, node, flags);
4292 indent_flags = indent_newline | indent_indent;
4297 while (node != root)
4299 if (node->next_sibling)
4301 node = node->next_sibling;
4305 node = node->parent;
4308 if (PUGI__NODETYPE(node) == node_element)
4312 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4315 if ((indent_flags & indent_indent) && indent_length)
4316 text_output_indent(writer, indent, indent_length, depth);
4318 node_output_end(writer, node);
4320 indent_flags = indent_newline | indent_indent;
4324 while (node != root);
4326 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4330 PUGI__FN
bool has_declaration(xml_node_struct* node)
4332 for (xml_node_struct* child = node->first_child; child; child = child->next_sibling)
4334 xml_node_type type = PUGI__NODETYPE(child);
4336 if (type == node_declaration)
return true;
4337 if (type == node_element)
return false;
4343 PUGI__FN
bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node)
4345 for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
4352 PUGI__FN
bool allow_insert_attribute(xml_node_type parent)
4354 return parent == node_element || parent == node_declaration;
4357 PUGI__FN
bool allow_insert_child(xml_node_type parent, xml_node_type child)
4359 if (parent != node_document && parent != node_element)
return false;
4360 if (child == node_document || child == node_null)
return false;
4361 if (parent != node_document && (child == node_declaration || child == node_doctype))
return false;
4366 PUGI__FN
bool allow_move(xml_node parent, xml_node child)
4369 if (!allow_insert_child(parent.type(), child.type()))
4373 if (parent.root() != child.root())
4377 xml_node cur = parent;
4390 template <
typename String,
typename Header>
4391 PUGI__FN
void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)
4393 assert(!dest && (header & header_mask) == 0);
4397 if (alloc && (source_header & header_mask) == 0)
4402 header |= xml_memory_page_contents_shared_mask;
4403 source_header |= xml_memory_page_contents_shared_mask;
4406 strcpy_insitu(dest, header, header_mask, source, strlength(source));
4410 PUGI__FN
void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc)
4412 node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc);
4413 node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc);
4415 for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute)
4417 xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn));
4421 node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
4422 node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
4427 PUGI__FN
void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)
4429 xml_allocator& alloc = get_allocator(dn);
4430 xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0;
4432 node_copy_contents(dn, sn, shared_alloc);
4434 xml_node_struct* dit = dn;
4435 xml_node_struct* sit = sn->first_child;
4437 while (sit && sit != sn)
4445 xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit));
4449 node_copy_contents(copy, sit, shared_alloc);
4451 if (sit->first_child)
4454 sit = sit->first_child;
4463 if (sit->next_sibling)
4465 sit = sit->next_sibling;
4473 assert(sit == sn || dit);
4478 assert(!sit || dit == dn->parent);
4481 PUGI__FN
void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
4483 xml_allocator& alloc = get_allocator(da);
4484 xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0;
4486 node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
4487 node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
4490 inline bool is_text_node(xml_node_struct* node)
4492 xml_node_type type = PUGI__NODETYPE(node);
4494 return type == node_pcdata || type == node_cdata;
4498 template <
typename U> PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(
const char_t* value, U minv, U maxv)
4501 const char_t* s = value;
4503 while (PUGI__IS_CHARTYPE(*s, ct_space))
4506 bool negative = (*s ==
'-');
4508 s += (*s ==
'+' || *s ==
'-');
4510 bool overflow =
false;
4512 if (s[0] ==
'0' && (s[1] |
' ') ==
'x')
4520 const char_t* start = s;
4524 if (
static_cast<unsigned>(*s -
'0') < 10)
4525 result = result * 16 + (*s -
'0');
4526 else if (
static_cast<unsigned>((*s |
' ') -
'a') < 6)
4527 result = result * 16 + ((*s |
' ') -
'a' + 10);
4534 size_t digits =
static_cast<size_t>(s - start);
4536 overflow = digits >
sizeof(U) * 2;
4544 const char_t* start = s;
4548 if (
static_cast<unsigned>(*s -
'0') < 10)
4549 result = result * 10 + (*s -
'0');
4556 size_t digits =
static_cast<size_t>(s - start);
4558 PUGI__STATIC_ASSERT(
sizeof(U) == 8 ||
sizeof(U) == 4 ||
sizeof(U) == 2);
4560 const size_t max_digits10 =
sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
4561 const char_t max_lead =
sizeof(U) == 8 ?
'1' :
sizeof(U) == 4 ?
'4' :
'6';
4562 const size_t high_bit =
sizeof(U) * 8 - 1;
4564 overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit)));
4571 return (overflow || result > ~minv + 1) ? minv : ~result + 1;
4573 return (overflow || result > 0 - minv) ? minv : 0 - result;
4577 return (overflow || result > maxv) ? maxv : result;
4580 PUGI__FN
int get_value_int(
const char_t* value)
4582 return string_to_integer<unsigned int>(value,
static_cast<unsigned int>(INT_MIN), INT_MAX);
4585 PUGI__FN
unsigned int get_value_uint(
const char_t* value)
4587 return string_to_integer<unsigned int>(value, 0, UINT_MAX);
4590 PUGI__FN
double get_value_double(
const char_t* value)
4592 #ifdef PUGIXML_WCHAR_MODE
4593 return wcstod(value, 0);
4595 return strtod(value, 0);
4599 PUGI__FN
float get_value_float(
const char_t* value)
4601 #ifdef PUGIXML_WCHAR_MODE
4602 return static_cast<float>(wcstod(value, 0));
4604 return static_cast<float>(strtod(value, 0));
4608 PUGI__FN
bool get_value_bool(
const char_t* value)
4611 char_t first = *value;
4614 return (first ==
'1' || first ==
't' || first ==
'T' || first ==
'y' || first ==
'Y');
4617#ifdef PUGIXML_HAS_LONG_LONG
4618 PUGI__FN
long long get_value_llong(
const char_t* value)
4620 return string_to_integer<unsigned long long>(value,
static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);
4623 PUGI__FN
unsigned long long get_value_ullong(
const char_t* value)
4625 return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);
4629 template <
typename U> PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value,
bool negative)
4631 char_t* result = end - 1;
4632 U rest = negative ? 0 - value : value;
4636 *result-- =
static_cast<char_t
>(
'0' + (rest % 10));
4641 assert(result >= begin);
4646 return result + !negative;
4650 template <
typename String,
typename Header>
4651 PUGI__FN
bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask,
char* buf)
4653 #ifdef PUGIXML_WCHAR_MODE
4655 assert(strlen(buf) <
sizeof(wbuf) /
sizeof(wbuf[0]));
4658 for (; buf[offset]; ++offset) wbuf[offset] = buf[offset];
4660 return strcpy_insitu(dest, header, header_mask, wbuf, offset);
4662 return strcpy_insitu(dest, header, header_mask, buf, strlen(buf));
4666 template <
typename U,
typename String,
typename Header>
4667 PUGI__FN
bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value,
bool negative)
4670 char_t* end = buf +
sizeof(buf) /
sizeof(buf[0]);
4671 char_t* begin = integer_to_string(buf, end, value, negative);
4673 return strcpy_insitu(dest, header, header_mask, begin, end - begin);
4676 template <
typename String,
typename Header>
4677 PUGI__FN
bool set_value_convert(String& dest, Header& header, uintptr_t header_mask,
float value,
int precision)
4680 PUGI__SNPRINTF(buf,
"%.*g", precision,
double(value));
4682 return set_value_ascii(dest, header, header_mask, buf);
4685 template <
typename String,
typename Header>
4686 PUGI__FN
bool set_value_convert(String& dest, Header& header, uintptr_t header_mask,
double value,
int precision)
4689 PUGI__SNPRINTF(buf,
"%.*g", precision, value);
4691 return set_value_ascii(dest, header, header_mask, buf);
4694 template <
typename String,
typename Header>
4695 PUGI__FN
bool set_value_bool(String& dest, Header& header, uintptr_t header_mask,
bool value)
4697 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT(
"true") : PUGIXML_TEXT(
"false"), value ? 4 : 5);
4700 PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root,
void* contents,
size_t size,
unsigned int options, xml_encoding encoding,
bool is_mutable,
bool own, char_t** out_buffer)
4703 if (!contents && size)
return make_parse_result(status_io_error);
4706 xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
4713 if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable))
return impl::make_parse_result(status_out_of_memory);
4716 if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
4719 if (own || buffer != contents) *out_buffer = buffer;
4722 doc->buffer = buffer;
4725 xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
4728 res.encoding = buffer_encoding;
4734 PUGI__FN xml_parse_status get_file_size(FILE* file,
size_t& out_result)
4736 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
4738 typedef __int64 length_type;
4740 _fseeki64(file, 0, SEEK_END);
4741 length_type length = _ftelli64(file);
4742 _fseeki64(file, 0, SEEK_SET);
4743 #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))
4745 typedef off64_t length_type;
4747 fseeko64(file, 0, SEEK_END);
4748 length_type length = ftello64(file);
4749 fseeko64(file, 0, SEEK_SET);
4752 typedef long length_type;
4754 fseek(file, 0, SEEK_END);
4755 length_type length = ftell(file);
4756 fseek(file, 0, SEEK_SET);
4760 if (length < 0)
return status_io_error;
4763 size_t result =
static_cast<size_t>(length);
4765 if (
static_cast<length_type
>(result) != length)
return status_out_of_memory;
4768 out_result = result;
4774 PUGI__FN
size_t zero_terminate_buffer(
void* buffer,
size_t size, xml_encoding encoding)
4777 #ifdef PUGIXML_WCHAR_MODE
4778 xml_encoding wchar_encoding = get_wchar_encoding();
4780 if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding))
4782 size_t length = size /
sizeof(char_t);
4784 static_cast<char_t*
>(buffer)[length] = 0;
4785 return (length + 1) *
sizeof(char_t);
4788 if (encoding == encoding_utf8)
4790 static_cast<char*
>(buffer)[size] = 0;
4798 PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file,
unsigned int options, xml_encoding encoding, char_t** out_buffer)
4800 if (!file)
return make_parse_result(status_file_not_found);
4804 xml_parse_status size_status = get_file_size(file, size);
4805 if (size_status != status_ok)
return make_parse_result(size_status);
4807 size_t max_suffix_size =
sizeof(char_t);
4810 char* contents =
static_cast<char*
>(xml_memory::allocate(size + max_suffix_size));
4811 if (!contents)
return make_parse_result(status_out_of_memory);
4814 size_t read_size = fread(contents, 1, size, file);
4816 if (read_size != size)
4818 xml_memory::deallocate(contents);
4819 return make_parse_result(status_io_error);
4822 xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
4824 return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding,
true,
true, out_buffer);
4827 PUGI__FN
void close_file(FILE* file)
4832#ifndef PUGIXML_NO_STL
4833 template <
typename T>
struct xml_stream_chunk
4835 static xml_stream_chunk* create()
4837 void* memory = xml_memory::allocate(
sizeof(xml_stream_chunk));
4838 if (!memory)
return 0;
4840 return new (memory) xml_stream_chunk();
4843 static void destroy(xml_stream_chunk* chunk)
4848 xml_stream_chunk* next_ = chunk->next;
4850 xml_memory::deallocate(chunk);
4856 xml_stream_chunk(): next(0), size(0)
4860 xml_stream_chunk* next;
4863 T data[xml_memory_page_size /
sizeof(T)];
4866 template <
typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream,
void** out_buffer,
size_t* out_size)
4868 auto_deleter<xml_stream_chunk<T> > chunks(0, xml_stream_chunk<T>::destroy);
4872 xml_stream_chunk<T>* last = 0;
4874 while (!stream.eof())
4877 xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create();
4878 if (!chunk)
return status_out_of_memory;
4881 if (last) last = last->next = chunk;
4882 else chunks.data = last = chunk;
4885 stream.read(chunk->data,
static_cast<std::streamsize
>(
sizeof(chunk->data) /
sizeof(T)));
4886 chunk->size =
static_cast<size_t>(stream.gcount()) *
sizeof(T);
4889 if (stream.bad() || (!stream.eof() && stream.fail()))
return status_io_error;
4892 if (total + chunk->size < total)
return status_out_of_memory;
4893 total += chunk->size;
4896 size_t max_suffix_size =
sizeof(char_t);
4899 char* buffer =
static_cast<char*
>(xml_memory::allocate(total + max_suffix_size));
4900 if (!buffer)
return status_out_of_memory;
4902 char* write = buffer;
4904 for (xml_stream_chunk<T>* chunk = chunks.data; chunk; chunk = chunk->next)
4906 assert(write + chunk->size <= buffer + total);
4907 memcpy(write, chunk->data, chunk->size);
4908 write += chunk->size;
4911 assert(write == buffer + total);
4914 *out_buffer = buffer;
4920 template <
typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream,
void** out_buffer,
size_t* out_size)
4923 typename std::basic_istream<T>::pos_type pos = stream.tellg();
4924 stream.seekg(0, std::ios::end);
4925 std::streamoff length = stream.tellg() - pos;
4928 if (stream.fail() || pos < 0)
return status_io_error;
4931 size_t read_length =
static_cast<size_t>(length);
4933 if (
static_cast<std::streamsize
>(read_length) != length || length < 0)
return status_out_of_memory;
4935 size_t max_suffix_size =
sizeof(char_t);
4938 auto_deleter<void> buffer(xml_memory::allocate(read_length *
sizeof(T) + max_suffix_size), xml_memory::deallocate);
4939 if (!buffer.data)
return status_out_of_memory;
4941 stream.read(
static_cast<T*
>(buffer.data),
static_cast<std::streamsize
>(read_length));
4944 if (stream.bad() || (!stream.eof() && stream.fail()))
return status_io_error;
4947 size_t actual_length =
static_cast<size_t>(stream.gcount());
4948 assert(actual_length <= read_length);
4950 *out_buffer = buffer.release();
4951 *out_size = actual_length *
sizeof(T);
4956 template <
typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream<T>& stream,
unsigned int options, xml_encoding encoding, char_t** out_buffer)
4960 xml_parse_status status = status_ok;
4963 if (stream.fail())
return make_parse_result(status_io_error);
4966 if (stream.tellg() < 0)
4969 status = load_stream_data_noseek(stream, &buffer, &size);
4972 status = load_stream_data_seek(stream, &buffer, &size);
4974 if (status != status_ok)
return make_parse_result(status);
4976 xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
4978 return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding,
true,
true, out_buffer);
4982#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))
4983 PUGI__FN FILE* open_file_wide(
const wchar_t* path,
const wchar_t* mode)
4985#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
4987 return _wfopen_s(&file, path, mode) == 0 ? file : 0;
4989 return _wfopen(path, mode);
4993 PUGI__FN
char* convert_path_heap(
const wchar_t* str)
4998 size_t length = strlength_wide(str);
4999 size_t size = as_utf8_begin(str, length);
5002 char* result =
static_cast<char*
>(xml_memory::allocate(size + 1));
5003 if (!result)
return 0;
5006 as_utf8_end(result, size, str, length);
5014 PUGI__FN FILE* open_file_wide(
const wchar_t* path,
const wchar_t* mode)
5017 char* path_utf8 = convert_path_heap(path);
5018 if (!path_utf8)
return 0;
5021 char mode_ascii[4] = {0};
5022 for (
size_t i = 0; mode[i]; ++i) mode_ascii[i] =
static_cast<char>(mode[i]);
5025 FILE* result = fopen(path_utf8, mode_ascii);
5028 xml_memory::deallocate(path_utf8);
5034 PUGI__FN FILE* open_file(
const char* path,
const char* mode)
5036#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
5038 return fopen_s(&file, path, mode) == 0 ? file : 0;
5040 return fopen(path, mode);
5044 PUGI__FN
bool save_file_impl(
const xml_document& doc, FILE* file,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
5046 if (!file)
return false;
5048 xml_writer_file writer(file);
5049 doc.save(writer, indent, flags, encoding);
5051 return ferror(file) == 0;
5054 struct name_null_sentry
5056 xml_node_struct* node;
5059 name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name)
5073 PUGI__FN xml_writer_file::xml_writer_file(
void* file_): file(file_)
5077 PUGI__FN
void xml_writer_file::write(
const void* data,
size_t size)
5079 size_t result = fwrite(data, 1, size,
static_cast<FILE*
>(file));
5083#ifndef PUGIXML_NO_STL
5084 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<
char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
5088 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)
5092 PUGI__FN
void xml_writer_stream::write(
const void* data,
size_t size)
5096 assert(!wide_stream);
5097 narrow_stream->write(
reinterpret_cast<const char*
>(data),
static_cast<std::streamsize
>(size));
5101 assert(wide_stream);
5102 assert(size %
sizeof(
wchar_t) == 0);
5104 wide_stream->write(
reinterpret_cast<const wchar_t*
>(data),
static_cast<std::streamsize
>(size /
sizeof(
wchar_t)));
5109 PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0)
5113 PUGI__FN xml_tree_walker::~xml_tree_walker()
5117 PUGI__FN
int xml_tree_walker::depth()
const
5122 PUGI__FN
bool xml_tree_walker::begin(xml_node&)
5127 PUGI__FN
bool xml_tree_walker::end(xml_node&)
5132 PUGI__FN xml_attribute::xml_attribute(): _attr(0)
5136 PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
5140 PUGI__FN
static void unspecified_bool_xml_attribute(xml_attribute***)
5144 PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type()
const
5146 return _attr ? unspecified_bool_xml_attribute : 0;
5149 PUGI__FN
bool xml_attribute::operator!()
const
5154 PUGI__FN
bool xml_attribute::operator==(
const xml_attribute& r)
const
5156 return (_attr == r._attr);
5159 PUGI__FN
bool xml_attribute::operator!=(
const xml_attribute& r)
const
5161 return (_attr != r._attr);
5164 PUGI__FN
bool xml_attribute::operator<(
const xml_attribute& r)
const
5166 return (_attr < r._attr);
5169 PUGI__FN
bool xml_attribute::operator>(
const xml_attribute& r)
const
5171 return (_attr > r._attr);
5174 PUGI__FN
bool xml_attribute::operator<=(
const xml_attribute& r)
const
5176 return (_attr <= r._attr);
5179 PUGI__FN
bool xml_attribute::operator>=(
const xml_attribute& r)
const
5181 return (_attr >= r._attr);
5184 PUGI__FN xml_attribute xml_attribute::next_attribute()
const
5186 return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
5189 PUGI__FN xml_attribute xml_attribute::previous_attribute()
const
5191 return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
5194 PUGI__FN
const char_t* xml_attribute::as_string(
const char_t* def)
const
5196 return (_attr && _attr->value) ? _attr->value + 0 : def;
5199 PUGI__FN
int xml_attribute::as_int(
int def)
const
5201 return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def;
5204 PUGI__FN
unsigned int xml_attribute::as_uint(
unsigned int def)
const
5206 return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def;
5209 PUGI__FN
double xml_attribute::as_double(
double def)
const
5211 return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def;
5214 PUGI__FN
float xml_attribute::as_float(
float def)
const
5216 return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def;
5219 PUGI__FN
bool xml_attribute::as_bool(
bool def)
const
5221 return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def;
5224#ifdef PUGIXML_HAS_LONG_LONG
5225 PUGI__FN
long long xml_attribute::as_llong(
long long def)
const
5227 return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def;
5230 PUGI__FN
unsigned long long xml_attribute::as_ullong(
unsigned long long def)
const
5232 return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def;
5236 PUGI__FN
bool xml_attribute::empty()
const
5241 PUGI__FN
const char_t* xml_attribute::name()
const
5243 return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT(
"");
5246 PUGI__FN
const char_t* xml_attribute::value()
const
5248 return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT(
"");
5251 PUGI__FN
size_t xml_attribute::hash_value()
const
5253 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(_attr) /
sizeof(xml_attribute_struct));
5256 PUGI__FN xml_attribute_struct* xml_attribute::internal_object()
const
5261 PUGI__FN xml_attribute& xml_attribute::operator=(
const char_t* rhs)
5267 PUGI__FN xml_attribute& xml_attribute::operator=(
int rhs)
5273 PUGI__FN xml_attribute& xml_attribute::operator=(
unsigned int rhs)
5279 PUGI__FN xml_attribute& xml_attribute::operator=(
long rhs)
5285 PUGI__FN xml_attribute& xml_attribute::operator=(
unsigned long rhs)
5291 PUGI__FN xml_attribute& xml_attribute::operator=(
double rhs)
5297 PUGI__FN xml_attribute& xml_attribute::operator=(
float rhs)
5303 PUGI__FN xml_attribute& xml_attribute::operator=(
bool rhs)
5309#ifdef PUGIXML_HAS_LONG_LONG
5310 PUGI__FN xml_attribute& xml_attribute::operator=(
long long rhs)
5316 PUGI__FN xml_attribute& xml_attribute::operator=(
unsigned long long rhs)
5323 PUGI__FN
bool xml_attribute::set_name(
const char_t* rhs)
5325 if (!_attr)
return false;
5327 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
5330 PUGI__FN
bool xml_attribute::set_value(
const char_t* rhs)
5332 if (!_attr)
return false;
5334 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
5337 PUGI__FN
bool xml_attribute::set_value(
int rhs)
5339 if (!_attr)
return false;
5341 return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5344 PUGI__FN
bool xml_attribute::set_value(
unsigned int rhs)
5346 if (!_attr)
return false;
5348 return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs,
false);
5351 PUGI__FN
bool xml_attribute::set_value(
long rhs)
5353 if (!_attr)
return false;
5355 return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5358 PUGI__FN
bool xml_attribute::set_value(
unsigned long rhs)
5360 if (!_attr)
return false;
5362 return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs,
false);
5365 PUGI__FN
bool xml_attribute::set_value(
double rhs)
5367 if (!_attr)
return false;
5369 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision);
5372 PUGI__FN
bool xml_attribute::set_value(
double rhs,
int precision)
5374 if (!_attr)
return false;
5376 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision);
5379 PUGI__FN
bool xml_attribute::set_value(
float rhs)
5381 if (!_attr)
return false;
5383 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision);
5386 PUGI__FN
bool xml_attribute::set_value(
float rhs,
int precision)
5388 if (!_attr)
return false;
5390 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision);
5393 PUGI__FN
bool xml_attribute::set_value(
bool rhs)
5395 if (!_attr)
return false;
5397 return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
5400#ifdef PUGIXML_HAS_LONG_LONG
5401 PUGI__FN
bool xml_attribute::set_value(
long long rhs)
5403 if (!_attr)
return false;
5405 return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
5408 PUGI__FN
bool xml_attribute::set_value(
unsigned long long rhs)
5410 if (!_attr)
return false;
5412 return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs,
false);
5417 PUGI__FN
bool operator&&(
const xml_attribute& lhs,
bool rhs)
5419 return (
bool)lhs && rhs;
5422 PUGI__FN
bool operator||(
const xml_attribute& lhs,
bool rhs)
5424 return (
bool)lhs || rhs;
5428 PUGI__FN xml_node::xml_node(): _root(0)
5432 PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p)
5436 PUGI__FN
static void unspecified_bool_xml_node(xml_node***)
5440 PUGI__FN xml_node::operator xml_node::unspecified_bool_type()
const
5442 return _root ? unspecified_bool_xml_node : 0;
5445 PUGI__FN
bool xml_node::operator!()
const
5450 PUGI__FN xml_node::iterator xml_node::begin()
const
5452 return iterator(_root ? _root->first_child + 0 : 0, _root);
5455 PUGI__FN xml_node::iterator xml_node::end()
const
5457 return iterator(0, _root);
5460 PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin()
const
5462 return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root);
5465 PUGI__FN xml_node::attribute_iterator xml_node::attributes_end()
const
5467 return attribute_iterator(0, _root);
5470 PUGI__FN xml_object_range<xml_node_iterator> xml_node::children()
const
5472 return xml_object_range<xml_node_iterator>(begin(), end());
5475 PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(
const char_t* name_)
const
5477 return xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_));
5480 PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes()
const
5482 return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());
5485 PUGI__FN
bool xml_node::operator==(
const xml_node& r)
const
5487 return (_root == r._root);
5490 PUGI__FN
bool xml_node::operator!=(
const xml_node& r)
const
5492 return (_root != r._root);
5495 PUGI__FN
bool xml_node::operator<(
const xml_node& r)
const
5497 return (_root < r._root);
5500 PUGI__FN
bool xml_node::operator>(
const xml_node& r)
const
5502 return (_root > r._root);
5505 PUGI__FN
bool xml_node::operator<=(
const xml_node& r)
const
5507 return (_root <= r._root);
5510 PUGI__FN
bool xml_node::operator>=(
const xml_node& r)
const
5512 return (_root >= r._root);
5515 PUGI__FN
bool xml_node::empty()
const
5520 PUGI__FN
const char_t* xml_node::name()
const
5522 return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(
"");
5525 PUGI__FN xml_node_type xml_node::type()
const
5527 return _root ? PUGI__NODETYPE(_root) : node_null;
5530 PUGI__FN
const char_t* xml_node::value()
const
5532 return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(
"");
5535 PUGI__FN xml_node xml_node::child(
const char_t* name_)
const
5537 if (!_root)
return xml_node();
5539 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5540 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
5545 PUGI__FN xml_attribute xml_node::attribute(
const char_t* name_)
const
5547 if (!_root)
return xml_attribute();
5549 for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
5550 if (i->name && impl::strequal(name_, i->name))
5551 return xml_attribute(i);
5553 return xml_attribute();
5556 PUGI__FN xml_node xml_node::next_sibling(
const char_t* name_)
const
5558 if (!_root)
return xml_node();
5560 for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
5561 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
5566 PUGI__FN xml_node xml_node::next_sibling()
const
5568 return _root ? xml_node(_root->next_sibling) : xml_node();
5571 PUGI__FN xml_node xml_node::previous_sibling(
const char_t* name_)
const
5573 if (!_root)
return xml_node();
5575 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
5576 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
5581 PUGI__FN xml_attribute xml_node::attribute(
const char_t* name_, xml_attribute& hint_)
const
5583 xml_attribute_struct* hint = hint_._attr;
5586 assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
5588 if (!_root)
return xml_attribute();
5591 for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
5592 if (i->name && impl::strequal(name_, i->name))
5595 hint_._attr = i->next_attribute;
5597 return xml_attribute(i);
5602 for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)
5603 if (j->name && impl::strequal(name_, j->name))
5606 hint_._attr = j->next_attribute;
5608 return xml_attribute(j);
5611 return xml_attribute();
5614 PUGI__FN xml_node xml_node::previous_sibling()
const
5616 if (!_root)
return xml_node();
5618 if (_root->prev_sibling_c->next_sibling)
return xml_node(_root->prev_sibling_c);
5619 else return xml_node();
5622 PUGI__FN xml_node xml_node::parent()
const
5624 return _root ? xml_node(_root->parent) : xml_node();
5627 PUGI__FN xml_node xml_node::root()
const
5629 return _root ? xml_node(&impl::get_document(_root)) : xml_node();
5632 PUGI__FN xml_text xml_node::text()
const
5634 return xml_text(_root);
5637 PUGI__FN
const char_t* xml_node::child_value()
const
5639 if (!_root)
return PUGIXML_TEXT(
"");
5642 if (PUGI__NODETYPE(_root) == node_element && _root->value)
5643 return _root->value;
5645 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5646 if (impl::is_text_node(i) && i->value)
5649 return PUGIXML_TEXT(
"");
5652 PUGI__FN
const char_t* xml_node::child_value(
const char_t* name_)
const
5654 return child(name_).child_value();
5657 PUGI__FN xml_attribute xml_node::first_attribute()
const
5659 return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
5662 PUGI__FN xml_attribute xml_node::last_attribute()
const
5664 return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute();
5667 PUGI__FN xml_node xml_node::first_child()
const
5669 return _root ? xml_node(_root->first_child) : xml_node();
5672 PUGI__FN xml_node xml_node::last_child()
const
5674 return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
5677 PUGI__FN
bool xml_node::set_name(
const char_t* rhs)
5679 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
5681 if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
5684 return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
5687 PUGI__FN
bool xml_node::set_value(
const char_t* rhs)
5689 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
5691 if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
5694 return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
5697 PUGI__FN xml_attribute xml_node::append_attribute(
const char_t* name_)
5699 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5701 impl::xml_allocator& alloc = impl::get_allocator(_root);
5702 if (!alloc.reserve())
return xml_attribute();
5704 xml_attribute a(impl::allocate_attribute(alloc));
5705 if (!a)
return xml_attribute();
5707 impl::append_attribute(a._attr, _root);
5714 PUGI__FN xml_attribute xml_node::prepend_attribute(
const char_t* name_)
5716 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5718 impl::xml_allocator& alloc = impl::get_allocator(_root);
5719 if (!alloc.reserve())
return xml_attribute();
5721 xml_attribute a(impl::allocate_attribute(alloc));
5722 if (!a)
return xml_attribute();
5724 impl::prepend_attribute(a._attr, _root);
5731 PUGI__FN xml_attribute xml_node::insert_attribute_after(
const char_t* name_,
const xml_attribute& attr)
5733 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5734 if (!attr || !impl::is_attribute_of(attr._attr, _root))
return xml_attribute();
5736 impl::xml_allocator& alloc = impl::get_allocator(_root);
5737 if (!alloc.reserve())
return xml_attribute();
5739 xml_attribute a(impl::allocate_attribute(alloc));
5740 if (!a)
return xml_attribute();
5742 impl::insert_attribute_after(a._attr, attr._attr, _root);
5749 PUGI__FN xml_attribute xml_node::insert_attribute_before(
const char_t* name_,
const xml_attribute& attr)
5751 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5752 if (!attr || !impl::is_attribute_of(attr._attr, _root))
return xml_attribute();
5754 impl::xml_allocator& alloc = impl::get_allocator(_root);
5755 if (!alloc.reserve())
return xml_attribute();
5757 xml_attribute a(impl::allocate_attribute(alloc));
5758 if (!a)
return xml_attribute();
5760 impl::insert_attribute_before(a._attr, attr._attr, _root);
5767 PUGI__FN xml_attribute xml_node::append_copy(
const xml_attribute& proto)
5769 if (!proto)
return xml_attribute();
5770 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5772 impl::xml_allocator& alloc = impl::get_allocator(_root);
5773 if (!alloc.reserve())
return xml_attribute();
5775 xml_attribute a(impl::allocate_attribute(alloc));
5776 if (!a)
return xml_attribute();
5778 impl::append_attribute(a._attr, _root);
5779 impl::node_copy_attribute(a._attr, proto._attr);
5784 PUGI__FN xml_attribute xml_node::prepend_copy(
const xml_attribute& proto)
5786 if (!proto)
return xml_attribute();
5787 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5789 impl::xml_allocator& alloc = impl::get_allocator(_root);
5790 if (!alloc.reserve())
return xml_attribute();
5792 xml_attribute a(impl::allocate_attribute(alloc));
5793 if (!a)
return xml_attribute();
5795 impl::prepend_attribute(a._attr, _root);
5796 impl::node_copy_attribute(a._attr, proto._attr);
5801 PUGI__FN xml_attribute xml_node::insert_copy_after(
const xml_attribute& proto,
const xml_attribute& attr)
5803 if (!proto)
return xml_attribute();
5804 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5805 if (!attr || !impl::is_attribute_of(attr._attr, _root))
return xml_attribute();
5807 impl::xml_allocator& alloc = impl::get_allocator(_root);
5808 if (!alloc.reserve())
return xml_attribute();
5810 xml_attribute a(impl::allocate_attribute(alloc));
5811 if (!a)
return xml_attribute();
5813 impl::insert_attribute_after(a._attr, attr._attr, _root);
5814 impl::node_copy_attribute(a._attr, proto._attr);
5819 PUGI__FN xml_attribute xml_node::insert_copy_before(
const xml_attribute& proto,
const xml_attribute& attr)
5821 if (!proto)
return xml_attribute();
5822 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5823 if (!attr || !impl::is_attribute_of(attr._attr, _root))
return xml_attribute();
5825 impl::xml_allocator& alloc = impl::get_allocator(_root);
5826 if (!alloc.reserve())
return xml_attribute();
5828 xml_attribute a(impl::allocate_attribute(alloc));
5829 if (!a)
return xml_attribute();
5831 impl::insert_attribute_before(a._attr, attr._attr, _root);
5832 impl::node_copy_attribute(a._attr, proto._attr);
5837 PUGI__FN xml_node xml_node::append_child(xml_node_type type_)
5839 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5841 impl::xml_allocator& alloc = impl::get_allocator(_root);
5842 if (!alloc.reserve())
return xml_node();
5844 xml_node n(impl::allocate_node(alloc, type_));
5845 if (!n)
return xml_node();
5847 impl::append_node(n._root, _root);
5849 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
5854 PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_)
5856 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5858 impl::xml_allocator& alloc = impl::get_allocator(_root);
5859 if (!alloc.reserve())
return xml_node();
5861 xml_node n(impl::allocate_node(alloc, type_));
5862 if (!n)
return xml_node();
5864 impl::prepend_node(n._root, _root);
5866 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
5871 PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_,
const xml_node& node)
5873 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5874 if (!node._root || node._root->parent != _root)
return xml_node();
5876 impl::xml_allocator& alloc = impl::get_allocator(_root);
5877 if (!alloc.reserve())
return xml_node();
5879 xml_node n(impl::allocate_node(alloc, type_));
5880 if (!n)
return xml_node();
5882 impl::insert_node_before(n._root, node._root);
5884 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
5889 PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_,
const xml_node& node)
5891 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5892 if (!node._root || node._root->parent != _root)
return xml_node();
5894 impl::xml_allocator& alloc = impl::get_allocator(_root);
5895 if (!alloc.reserve())
return xml_node();
5897 xml_node n(impl::allocate_node(alloc, type_));
5898 if (!n)
return xml_node();
5900 impl::insert_node_after(n._root, node._root);
5902 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
5907 PUGI__FN xml_node xml_node::append_child(
const char_t* name_)
5909 xml_node result = append_child(node_element);
5911 result.set_name(name_);
5916 PUGI__FN xml_node xml_node::prepend_child(
const char_t* name_)
5918 xml_node result = prepend_child(node_element);
5920 result.set_name(name_);
5925 PUGI__FN xml_node xml_node::insert_child_after(
const char_t* name_,
const xml_node& node)
5927 xml_node result = insert_child_after(node_element, node);
5929 result.set_name(name_);
5934 PUGI__FN xml_node xml_node::insert_child_before(
const char_t* name_,
const xml_node& node)
5936 xml_node result = insert_child_before(node_element, node);
5938 result.set_name(name_);
5943 PUGI__FN xml_node xml_node::append_copy(
const xml_node& proto)
5945 xml_node_type type_ = proto.type();
5946 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5948 impl::xml_allocator& alloc = impl::get_allocator(_root);
5949 if (!alloc.reserve())
return xml_node();
5951 xml_node n(impl::allocate_node(alloc, type_));
5952 if (!n)
return xml_node();
5954 impl::append_node(n._root, _root);
5955 impl::node_copy_tree(n._root, proto._root);
5960 PUGI__FN xml_node xml_node::prepend_copy(
const xml_node& proto)
5962 xml_node_type type_ = proto.type();
5963 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5965 impl::xml_allocator& alloc = impl::get_allocator(_root);
5966 if (!alloc.reserve())
return xml_node();
5968 xml_node n(impl::allocate_node(alloc, type_));
5969 if (!n)
return xml_node();
5971 impl::prepend_node(n._root, _root);
5972 impl::node_copy_tree(n._root, proto._root);
5977 PUGI__FN xml_node xml_node::insert_copy_after(
const xml_node& proto,
const xml_node& node)
5979 xml_node_type type_ = proto.type();
5980 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5981 if (!node._root || node._root->parent != _root)
return xml_node();
5983 impl::xml_allocator& alloc = impl::get_allocator(_root);
5984 if (!alloc.reserve())
return xml_node();
5986 xml_node n(impl::allocate_node(alloc, type_));
5987 if (!n)
return xml_node();
5989 impl::insert_node_after(n._root, node._root);
5990 impl::node_copy_tree(n._root, proto._root);
5995 PUGI__FN xml_node xml_node::insert_copy_before(
const xml_node& proto,
const xml_node& node)
5997 xml_node_type type_ = proto.type();
5998 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5999 if (!node._root || node._root->parent != _root)
return xml_node();
6001 impl::xml_allocator& alloc = impl::get_allocator(_root);
6002 if (!alloc.reserve())
return xml_node();
6004 xml_node n(impl::allocate_node(alloc, type_));
6005 if (!n)
return xml_node();
6007 impl::insert_node_before(n._root, node._root);
6008 impl::node_copy_tree(n._root, proto._root);
6013 PUGI__FN xml_node xml_node::append_move(
const xml_node& moved)
6015 if (!impl::allow_move(*
this, moved))
return xml_node();
6017 impl::xml_allocator& alloc = impl::get_allocator(_root);
6018 if (!alloc.reserve())
return xml_node();
6021 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
6023 impl::remove_node(moved._root);
6024 impl::append_node(moved._root, _root);
6029 PUGI__FN xml_node xml_node::prepend_move(
const xml_node& moved)
6031 if (!impl::allow_move(*
this, moved))
return xml_node();
6033 impl::xml_allocator& alloc = impl::get_allocator(_root);
6034 if (!alloc.reserve())
return xml_node();
6037 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
6039 impl::remove_node(moved._root);
6040 impl::prepend_node(moved._root, _root);
6045 PUGI__FN xml_node xml_node::insert_move_after(
const xml_node& moved,
const xml_node& node)
6047 if (!impl::allow_move(*
this, moved))
return xml_node();
6048 if (!node._root || node._root->parent != _root)
return xml_node();
6049 if (moved._root == node._root)
return xml_node();
6051 impl::xml_allocator& alloc = impl::get_allocator(_root);
6052 if (!alloc.reserve())
return xml_node();
6055 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
6057 impl::remove_node(moved._root);
6058 impl::insert_node_after(moved._root, node._root);
6063 PUGI__FN xml_node xml_node::insert_move_before(
const xml_node& moved,
const xml_node& node)
6065 if (!impl::allow_move(*
this, moved))
return xml_node();
6066 if (!node._root || node._root->parent != _root)
return xml_node();
6067 if (moved._root == node._root)
return xml_node();
6069 impl::xml_allocator& alloc = impl::get_allocator(_root);
6070 if (!alloc.reserve())
return xml_node();
6073 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
6075 impl::remove_node(moved._root);
6076 impl::insert_node_before(moved._root, node._root);
6081 PUGI__FN
bool xml_node::remove_attribute(
const char_t* name_)
6083 return remove_attribute(attribute(name_));
6086 PUGI__FN
bool xml_node::remove_attribute(
const xml_attribute& a)
6088 if (!_root || !a._attr)
return false;
6089 if (!impl::is_attribute_of(a._attr, _root))
return false;
6091 impl::xml_allocator& alloc = impl::get_allocator(_root);
6092 if (!alloc.reserve())
return false;
6094 impl::remove_attribute(a._attr, _root);
6095 impl::destroy_attribute(a._attr, alloc);
6100 PUGI__FN
bool xml_node::remove_attributes()
6102 if (!_root)
return false;
6104 impl::xml_allocator& alloc = impl::get_allocator(_root);
6105 if (!alloc.reserve())
return false;
6107 for (xml_attribute_struct* attr = _root->first_attribute; attr; )
6109 xml_attribute_struct* next = attr->next_attribute;
6111 impl::destroy_attribute(attr, alloc);
6116 _root->first_attribute = 0;
6121 PUGI__FN
bool xml_node::remove_child(
const char_t* name_)
6123 return remove_child(child(name_));
6126 PUGI__FN
bool xml_node::remove_child(
const xml_node& n)
6128 if (!_root || !n._root || n._root->parent != _root)
return false;
6130 impl::xml_allocator& alloc = impl::get_allocator(_root);
6131 if (!alloc.reserve())
return false;
6133 impl::remove_node(n._root);
6134 impl::destroy_node(n._root, alloc);
6139 PUGI__FN
bool xml_node::remove_children()
6141 if (!_root)
return false;
6143 impl::xml_allocator& alloc = impl::get_allocator(_root);
6144 if (!alloc.reserve())
return false;
6146 for (xml_node_struct* cur = _root->first_child; cur; )
6148 xml_node_struct* next = cur->next_sibling;
6150 impl::destroy_node(cur, alloc);
6155 _root->first_child = 0;
6160 PUGI__FN xml_parse_result xml_node::append_buffer(
const void* contents,
size_t size,
unsigned int options, xml_encoding encoding)
6163 if (!impl::allow_insert_child(type(), node_element))
return impl::make_parse_result(status_append_invalid_root);
6166 impl::xml_document_struct* doc = &impl::get_document(_root);
6169 doc->header |= impl::xml_memory_page_contents_shared_mask;
6172 impl::xml_memory_page* page = 0;
6173 impl::xml_extra_buffer* extra =
static_cast<impl::xml_extra_buffer*
>(doc->allocate_memory(
sizeof(impl::xml_extra_buffer) +
sizeof(
void*), page));
6176 if (!extra)
return impl::make_parse_result(status_out_of_memory);
6178 #ifdef PUGIXML_COMPACT
6181 extra =
reinterpret_cast<impl::xml_extra_buffer*
>((
reinterpret_cast<uintptr_t
>(extra) + (
sizeof(
void*) - 1)) & ~(
sizeof(
void*) - 1));
6186 extra->next = doc->extra_buffers;
6187 doc->extra_buffers = extra;
6190 impl::name_null_sentry sentry(_root);
6192 return impl::load_buffer_impl(doc, _root,
const_cast<void*
>(contents), size, options, encoding,
false,
false, &extra->buffer);
6195 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
6197 if (!_root)
return xml_node();
6199 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
6200 if (i->name && impl::strequal(name_, i->name))
6202 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
6203 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(
"")))
6210 PUGI__FN xml_node xml_node::find_child_by_attribute(
const char_t* attr_name,
const char_t* attr_value)
const
6212 if (!_root)
return xml_node();
6214 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
6215 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
6216 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(
"")))
6222#ifndef PUGIXML_NO_STL
6223 PUGI__FN string_t xml_node::path(char_t delimiter)
const
6225 if (!_root)
return string_t();
6229 for (xml_node_struct* i = _root; i; i = i->parent)
6231 offset += (i != _root);
6232 offset += i->name ? impl::strlength(i->name) : 0;
6236 result.resize(offset);
6238 for (xml_node_struct* j = _root; j; j = j->parent)
6241 result[--offset] = delimiter;
6245 size_t length = impl::strlength(j->name);
6248 memcpy(&result[offset], j->name, length *
sizeof(char_t));
6252 assert(offset == 0);
6258 PUGI__FN xml_node xml_node::first_element_by_path(
const char_t* path_, char_t delimiter)
const
6260 xml_node context = path_[0] == delimiter ? root() : *this;
6262 if (!context._root)
return xml_node();
6264 const char_t* path_segment = path_;
6266 while (*path_segment == delimiter) ++path_segment;
6268 const char_t* path_segment_end = path_segment;
6270 while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;
6272 if (path_segment == path_segment_end)
return context;
6274 const char_t* next_segment = path_segment_end;
6276 while (*next_segment == delimiter) ++next_segment;
6278 if (*path_segment ==
'.' && path_segment + 1 == path_segment_end)
6279 return context.first_element_by_path(next_segment, delimiter);
6280 else if (*path_segment ==
'.' && *(path_segment+1) ==
'.' && path_segment + 2 == path_segment_end)
6281 return context.parent().first_element_by_path(next_segment, delimiter);
6284 for (xml_node_struct* j = context._root->first_child; j; j = j->next_sibling)
6286 if (j->name && impl::strequalrange(j->name, path_segment,
static_cast<size_t>(path_segment_end - path_segment)))
6288 xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
6290 if (subsearch)
return subsearch;
6298 PUGI__FN
bool xml_node::traverse(xml_tree_walker& walker)
6302 xml_node arg_begin(_root);
6303 if (!walker.begin(arg_begin))
return false;
6305 xml_node_struct* cur = _root ? _root->first_child + 0 : 0;
6313 xml_node arg_for_each(cur);
6314 if (!walker.for_each(arg_for_each))
6317 if (cur->first_child)
6320 cur = cur->first_child;
6322 else if (cur->next_sibling)
6323 cur = cur->next_sibling;
6326 while (!cur->next_sibling && cur != _root && cur->parent)
6333 cur = cur->next_sibling;
6336 while (cur && cur != _root);
6339 assert(walker._depth == -1);
6341 xml_node arg_end(_root);
6342 return walker.end(arg_end);
6345 PUGI__FN
size_t xml_node::hash_value()
const
6347 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(_root) /
sizeof(xml_node_struct));
6350 PUGI__FN xml_node_struct* xml_node::internal_object()
const
6355 PUGI__FN
void xml_node::print(xml_writer& writer,
const char_t* indent,
unsigned int flags, xml_encoding encoding,
unsigned int depth)
const
6359 impl::xml_buffered_writer buffered_writer(writer, encoding);
6361 impl::node_output(buffered_writer, _root, indent, flags, depth);
6363 buffered_writer.flush();
6366#ifndef PUGIXML_NO_STL
6367 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
6369 xml_writer_stream writer(stream);
6371 print(writer, indent, flags, encoding, depth);
6374 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
6376 xml_writer_stream writer(stream);
6378 print(writer, indent, flags, encoding_wchar, depth);
6382 PUGI__FN ptrdiff_t xml_node::offset_debug()
const
6384 if (!_root)
return -1;
6386 impl::xml_document_struct& doc = impl::get_document(_root);
6389 if (!doc.buffer || doc.extra_buffers)
return -1;
6397 case node_declaration:
6399 return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1;
6405 return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1;
6408 assert(
false &&
"Invalid node type");
6414 PUGI__FN
bool operator&&(
const xml_node& lhs,
bool rhs)
6416 return (
bool)lhs && rhs;
6419 PUGI__FN
bool operator||(
const xml_node& lhs,
bool rhs)
6421 return (
bool)lhs || rhs;
6425 PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root)
6429 PUGI__FN xml_node_struct* xml_text::_data()
const
6431 if (!_root || impl::is_text_node(_root))
return _root;
6434 if (PUGI__NODETYPE(_root) == node_element && _root->value)
6437 for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
6438 if (impl::is_text_node(node))
6444 PUGI__FN xml_node_struct* xml_text::_data_new()
6446 xml_node_struct* d = _data();
6449 return xml_node(_root).append_child(node_pcdata).internal_object();
6452 PUGI__FN xml_text::xml_text(): _root(0)
6456 PUGI__FN
static void unspecified_bool_xml_text(xml_text***)
6460 PUGI__FN xml_text::operator xml_text::unspecified_bool_type()
const
6462 return _data() ? unspecified_bool_xml_text : 0;
6465 PUGI__FN
bool xml_text::operator!()
const
6470 PUGI__FN
bool xml_text::empty()
const
6472 return _data() == 0;
6475 PUGI__FN
const char_t* xml_text::get()
const
6477 xml_node_struct* d = _data();
6479 return (d && d->value) ? d->value + 0 : PUGIXML_TEXT(
"");
6482 PUGI__FN
const char_t* xml_text::as_string(
const char_t* def)
const
6484 xml_node_struct* d = _data();
6486 return (d && d->value) ? d->value + 0 : def;
6489 PUGI__FN
int xml_text::as_int(
int def)
const
6491 xml_node_struct* d = _data();
6493 return (d && d->value) ? impl::get_value_int(d->value) : def;
6496 PUGI__FN
unsigned int xml_text::as_uint(
unsigned int def)
const
6498 xml_node_struct* d = _data();
6500 return (d && d->value) ? impl::get_value_uint(d->value) : def;
6503 PUGI__FN
double xml_text::as_double(
double def)
const
6505 xml_node_struct* d = _data();
6507 return (d && d->value) ? impl::get_value_double(d->value) : def;
6510 PUGI__FN
float xml_text::as_float(
float def)
const
6512 xml_node_struct* d = _data();
6514 return (d && d->value) ? impl::get_value_float(d->value) : def;
6517 PUGI__FN
bool xml_text::as_bool(
bool def)
const
6519 xml_node_struct* d = _data();
6521 return (d && d->value) ? impl::get_value_bool(d->value) : def;
6524#ifdef PUGIXML_HAS_LONG_LONG
6525 PUGI__FN
long long xml_text::as_llong(
long long def)
const
6527 xml_node_struct* d = _data();
6529 return (d && d->value) ? impl::get_value_llong(d->value) : def;
6532 PUGI__FN
unsigned long long xml_text::as_ullong(
unsigned long long def)
const
6534 xml_node_struct* d = _data();
6536 return (d && d->value) ? impl::get_value_ullong(d->value) : def;
6540 PUGI__FN
bool xml_text::set(
const char_t* rhs)
6542 xml_node_struct* dn = _data_new();
6544 return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false;
6547 PUGI__FN
bool xml_text::set(
int rhs)
6549 xml_node_struct* dn = _data_new();
6551 return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6554 PUGI__FN
bool xml_text::set(
unsigned int rhs)
6556 xml_node_struct* dn = _data_new();
6558 return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs,
false) : false;
6561 PUGI__FN
bool xml_text::set(
long rhs)
6563 xml_node_struct* dn = _data_new();
6565 return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6568 PUGI__FN
bool xml_text::set(
unsigned long rhs)
6570 xml_node_struct* dn = _data_new();
6572 return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs,
false) : false;
6575 PUGI__FN
bool xml_text::set(
float rhs)
6577 xml_node_struct* dn = _data_new();
6579 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false;
6582 PUGI__FN
bool xml_text::set(
float rhs,
int precision)
6584 xml_node_struct* dn = _data_new();
6586 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false;
6589 PUGI__FN
bool xml_text::set(
double rhs)
6591 xml_node_struct* dn = _data_new();
6593 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false;
6596 PUGI__FN
bool xml_text::set(
double rhs,
int precision)
6598 xml_node_struct* dn = _data_new();
6600 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false;
6603 PUGI__FN
bool xml_text::set(
bool rhs)
6605 xml_node_struct* dn = _data_new();
6607 return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
6610#ifdef PUGIXML_HAS_LONG_LONG
6611 PUGI__FN
bool xml_text::set(
long long rhs)
6613 xml_node_struct* dn = _data_new();
6615 return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
6618 PUGI__FN
bool xml_text::set(
unsigned long long rhs)
6620 xml_node_struct* dn = _data_new();
6622 return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs,
false) : false;
6626 PUGI__FN xml_text& xml_text::operator=(
const char_t* rhs)
6632 PUGI__FN xml_text& xml_text::operator=(
int rhs)
6638 PUGI__FN xml_text& xml_text::operator=(
unsigned int rhs)
6644 PUGI__FN xml_text& xml_text::operator=(
long rhs)
6650 PUGI__FN xml_text& xml_text::operator=(
unsigned long rhs)
6656 PUGI__FN xml_text& xml_text::operator=(
double rhs)
6662 PUGI__FN xml_text& xml_text::operator=(
float rhs)
6668 PUGI__FN xml_text& xml_text::operator=(
bool rhs)
6674#ifdef PUGIXML_HAS_LONG_LONG
6675 PUGI__FN xml_text& xml_text::operator=(
long long rhs)
6681 PUGI__FN xml_text& xml_text::operator=(
unsigned long long rhs)
6688 PUGI__FN xml_node xml_text::data()
const
6690 return xml_node(_data());
6694 PUGI__FN
bool operator&&(
const xml_text& lhs,
bool rhs)
6696 return (
bool)lhs && rhs;
6699 PUGI__FN
bool operator||(
const xml_text& lhs,
bool rhs)
6701 return (
bool)lhs || rhs;
6705 PUGI__FN xml_node_iterator::xml_node_iterator()
6709 PUGI__FN xml_node_iterator::xml_node_iterator(
const xml_node& node): _wrap(node), _parent(node.parent())
6713 PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
6717 PUGI__FN
bool xml_node_iterator::operator==(
const xml_node_iterator& rhs)
const
6719 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
6722 PUGI__FN
bool xml_node_iterator::operator!=(
const xml_node_iterator& rhs)
const
6724 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
6727 PUGI__FN xml_node& xml_node_iterator::operator*()
const
6729 assert(_wrap._root);
6733 PUGI__FN xml_node* xml_node_iterator::operator->()
const
6735 assert(_wrap._root);
6736 return const_cast<xml_node*
>(&_wrap);
6739 PUGI__FN xml_node_iterator& xml_node_iterator::operator++()
6741 assert(_wrap._root);
6742 _wrap._root = _wrap._root->next_sibling;
6746 PUGI__FN xml_node_iterator xml_node_iterator::operator++(
int)
6748 xml_node_iterator temp = *
this;
6753 PUGI__FN xml_node_iterator& xml_node_iterator::operator--()
6755 _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
6759 PUGI__FN xml_node_iterator xml_node_iterator::operator--(
int)
6761 xml_node_iterator temp = *
this;
6766 PUGI__FN xml_attribute_iterator::xml_attribute_iterator()
6770 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(
const xml_attribute& attr,
const xml_node& parent): _wrap(attr), _parent(parent)
6774 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
6778 PUGI__FN
bool xml_attribute_iterator::operator==(
const xml_attribute_iterator& rhs)
const
6780 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
6783 PUGI__FN
bool xml_attribute_iterator::operator!=(
const xml_attribute_iterator& rhs)
const
6785 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
6788 PUGI__FN xml_attribute& xml_attribute_iterator::operator*()
const
6790 assert(_wrap._attr);
6794 PUGI__FN xml_attribute* xml_attribute_iterator::operator->()
const
6796 assert(_wrap._attr);
6797 return const_cast<xml_attribute*
>(&_wrap);
6800 PUGI__FN xml_attribute_iterator& xml_attribute_iterator::operator++()
6802 assert(_wrap._attr);
6803 _wrap._attr = _wrap._attr->next_attribute;
6807 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(
int)
6809 xml_attribute_iterator temp = *
this;
6814 PUGI__FN xml_attribute_iterator& xml_attribute_iterator::operator--()
6816 _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
6820 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(
int)
6822 xml_attribute_iterator temp = *
this;
6827 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0)
6831 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(
const xml_node& node,
const char_t* name): _wrap(node), _parent(node.parent()), _name(name)
6835 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent,
const char_t* name): _wrap(ref), _parent(parent), _name(name)
6839 PUGI__FN
bool xml_named_node_iterator::operator==(
const xml_named_node_iterator& rhs)
const
6841 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
6844 PUGI__FN
bool xml_named_node_iterator::operator!=(
const xml_named_node_iterator& rhs)
const
6846 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
6849 PUGI__FN xml_node& xml_named_node_iterator::operator*()
const
6851 assert(_wrap._root);
6855 PUGI__FN xml_node* xml_named_node_iterator::operator->()
const
6857 assert(_wrap._root);
6858 return const_cast<xml_node*
>(&_wrap);
6861 PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator++()
6863 assert(_wrap._root);
6864 _wrap = _wrap.next_sibling(_name);
6868 PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(
int)
6870 xml_named_node_iterator temp = *
this;
6875 PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator--()
6878 _wrap = _wrap.previous_sibling(_name);
6881 _wrap = _parent.last_child();
6883 if (!impl::strequal(_wrap.name(), _name))
6884 _wrap = _wrap.previous_sibling(_name);
6890 PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(
int)
6892 xml_named_node_iterator temp = *
this;
6897 PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
6901 PUGI__FN xml_parse_result::operator
bool()
const
6903 return status == status_ok;
6906 PUGI__FN
const char* xml_parse_result::description()
const
6910 case status_ok:
return "No error";
6912 case status_file_not_found:
return "File was not found";
6913 case status_io_error:
return "Error reading from file/stream";
6914 case status_out_of_memory:
return "Could not allocate memory";
6915 case status_internal_error:
return "Internal error occurred";
6917 case status_unrecognized_tag:
return "Could not determine tag type";
6919 case status_bad_pi:
return "Error parsing document declaration/processing instruction";
6920 case status_bad_comment:
return "Error parsing comment";
6921 case status_bad_cdata:
return "Error parsing CDATA section";
6922 case status_bad_doctype:
return "Error parsing document type declaration";
6923 case status_bad_pcdata:
return "Error parsing PCDATA section";
6924 case status_bad_start_element:
return "Error parsing start element tag";
6925 case status_bad_attribute:
return "Error parsing element attribute";
6926 case status_bad_end_element:
return "Error parsing end element tag";
6927 case status_end_element_mismatch:
return "Start-end tags mismatch";
6929 case status_append_invalid_root:
return "Unable to append nodes: root is not an element or document";
6931 case status_no_document_element:
return "No document element found";
6933 default:
return "Unknown error";
6937 PUGI__FN xml_document::xml_document(): _buffer(0)
6942 PUGI__FN xml_document::~xml_document()
6947#ifdef PUGIXML_HAS_MOVE
6948 PUGI__FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(0)
6954 PUGI__FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
6956 if (
this == &rhs)
return *
this;
6966 PUGI__FN
void xml_document::reset()
6972 PUGI__FN
void xml_document::reset(
const xml_document& proto)
6976 impl::node_copy_tree(_root, proto._root);
6979 PUGI__FN
void xml_document::_create()
6983 #ifdef PUGIXML_COMPACT
6985 const size_t page_offset =
sizeof(
void*);
6987 const size_t page_offset = 0;
6991 PUGI__STATIC_ASSERT(
sizeof(impl::xml_memory_page) +
sizeof(impl::xml_document_struct) + page_offset <=
sizeof(_memory));
6994 impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory);
6997 page->busy_size = impl::xml_memory_page_size;
7000 #ifdef PUGIXML_COMPACT
7002 page->compact_page_marker =
reinterpret_cast<uint32_t*
>(
static_cast<void*
>(
reinterpret_cast<char*
>(page) +
sizeof(impl::xml_memory_page)));
7003 *page->compact_page_marker =
sizeof(impl::xml_memory_page);
7007 _root =
new (
reinterpret_cast<char*
>(page) +
sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page);
7008 _root->prev_sibling_c = _root;
7011 page->allocator =
static_cast<impl::xml_document_struct*
>(_root);
7014 #ifdef PUGIXML_COMPACT
7015 page->allocator->_hash = &
static_cast<impl::xml_document_struct*
>(_root)->hash;
7019 assert(
reinterpret_cast<char*
>(_root) +
sizeof(impl::xml_document_struct) <= _memory +
sizeof(_memory));
7022 PUGI__FN
void xml_document::_destroy()
7029 impl::xml_memory::deallocate(_buffer);
7034 for (impl::xml_extra_buffer* extra =
static_cast<impl::xml_document_struct*
>(_root)->extra_buffers; extra; extra = extra->next)
7036 if (extra->buffer) impl::xml_memory::deallocate(extra->buffer);
7040 impl::xml_memory_page* root_page = PUGI__GETPAGE(_root);
7041 assert(root_page && !root_page->prev);
7042 assert(
reinterpret_cast<char*
>(root_page) >= _memory &&
reinterpret_cast<char*
>(root_page) < _memory +
sizeof(_memory));
7044 for (impl::xml_memory_page* page = root_page->next; page; )
7046 impl::xml_memory_page* next = page->next;
7048 impl::xml_allocator::deallocate_page(page);
7053 #ifdef PUGIXML_COMPACT
7055 static_cast<impl::xml_document_struct*
>(_root)->hash.clear();
7061#ifdef PUGIXML_HAS_MOVE
7062 PUGI__FN
void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
7064 impl::xml_document_struct* doc =
static_cast<impl::xml_document_struct*
>(_root);
7065 impl::xml_document_struct* other =
static_cast<impl::xml_document_struct*
>(rhs._root);
7068 xml_node_struct* other_first_child = other->first_child;
7070 #ifdef PUGIXML_COMPACT
7073 if (other_first_child)
7075 size_t other_children = 0;
7076 for (xml_node_struct* node = other_first_child; node; node = node->next_sibling)
7083 if (!other->_hash->reserve(other_children + 1))
7085 #ifdef PUGIXML_NO_EXCEPTIONS
7088 throw std::bad_alloc();
7096 if (other->_root != PUGI__GETPAGE(other))
7098 doc->_root = other->_root;
7099 doc->_busy_size = other->_busy_size;
7103 doc->buffer = other->buffer;
7104 doc->extra_buffers = other->extra_buffers;
7105 _buffer = rhs._buffer;
7107 #ifdef PUGIXML_COMPACT
7109 doc->hash = other->hash;
7110 doc->_hash = &doc->hash;
7117 impl::xml_memory_page* doc_page = PUGI__GETPAGE(doc);
7118 assert(doc_page && !doc_page->prev && !doc_page->next);
7120 impl::xml_memory_page* other_page = PUGI__GETPAGE(other);
7121 assert(other_page && !other_page->prev);
7124 if (impl::xml_memory_page* page = other_page->next)
7126 assert(page->prev == other_page);
7128 page->prev = doc_page;
7130 doc_page->next = page;
7131 other_page->next = 0;
7135 for (impl::xml_memory_page* page = doc_page->next; page; page = page->next)
7137 assert(page->allocator == other);
7139 page->allocator = doc;
7141 #ifdef PUGIXML_COMPACT
7143 if (page->compact_shared_parent == other)
7144 page->compact_shared_parent = doc;
7149 assert(!doc->first_child);
7151 doc->first_child = other_first_child;
7153 for (xml_node_struct* node = other_first_child; node; node = node->next_sibling)
7155 #ifdef PUGIXML_COMPACT
7157 assert(node->parent == other || node->parent == doc);
7161 assert(node->parent == other);
7167 new (other) impl::xml_document_struct(PUGI__GETPAGE(other));
7172#ifndef PUGIXML_NO_STL
7173 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<
char, std::char_traits<char> >& stream,
unsigned int options, xml_encoding encoding)
7177 return impl::load_stream_impl(
static_cast<impl::xml_document_struct*
>(_root), stream, options, encoding, &_buffer);
7180 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<
wchar_t, std::char_traits<wchar_t> >& stream,
unsigned int options)
7184 return impl::load_stream_impl(
static_cast<impl::xml_document_struct*
>(_root), stream, options, encoding_wchar, &_buffer);
7188 PUGI__FN xml_parse_result xml_document::load_string(
const char_t* contents,
unsigned int options)
7191 #ifdef PUGIXML_WCHAR_MODE
7192 xml_encoding encoding = encoding_wchar;
7194 xml_encoding encoding = encoding_utf8;
7197 return load_buffer(contents, impl::strlength(contents) *
sizeof(char_t), options, encoding);
7200 PUGI__FN xml_parse_result xml_document::load(
const char_t* contents,
unsigned int options)
7202 return load_string(contents, options);
7205 PUGI__FN xml_parse_result xml_document::load_file(
const char* path_,
unsigned int options, xml_encoding encoding)
7209 using impl::auto_deleter;
7210 auto_deleter<FILE> file(impl::open_file(path_,
"rb"), impl::close_file);
7212 return impl::load_file_impl(
static_cast<impl::xml_document_struct*
>(_root), file.data, options, encoding, &_buffer);
7215 PUGI__FN xml_parse_result xml_document::load_file(
const wchar_t* path_,
unsigned int options, xml_encoding encoding)
7219 using impl::auto_deleter;
7220 auto_deleter<FILE> file(impl::open_file_wide(path_, L
"rb"), impl::close_file);
7222 return impl::load_file_impl(
static_cast<impl::xml_document_struct*
>(_root), file.data, options, encoding, &_buffer);
7225 PUGI__FN xml_parse_result xml_document::load_buffer(
const void* contents,
size_t size,
unsigned int options, xml_encoding encoding)
7229 return impl::load_buffer_impl(
static_cast<impl::xml_document_struct*
>(_root), _root,
const_cast<void*
>(contents), size, options, encoding,
false,
false, &_buffer);
7232 PUGI__FN xml_parse_result xml_document::load_buffer_inplace(
void* contents,
size_t size,
unsigned int options, xml_encoding encoding)
7236 return impl::load_buffer_impl(
static_cast<impl::xml_document_struct*
>(_root), _root, contents, size, options, encoding,
true,
false, &_buffer);
7239 PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(
void* contents,
size_t size,
unsigned int options, xml_encoding encoding)
7243 return impl::load_buffer_impl(
static_cast<impl::xml_document_struct*
>(_root), _root, contents, size, options, encoding,
true,
true, &_buffer);
7246 PUGI__FN
void xml_document::save(xml_writer& writer,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
const
7248 impl::xml_buffered_writer buffered_writer(writer, encoding);
7250 if ((flags & format_write_bom) && encoding != encoding_latin1)
7253 #ifdef PUGIXML_WCHAR_MODE
7254 unsigned int bom = 0xfeff;
7255 buffered_writer.write(
static_cast<wchar_t>(bom));
7257 buffered_writer.write(
'\xef',
'\xbb',
'\xbf');
7261 if (!(flags & format_no_declaration) && !impl::has_declaration(_root))
7263 buffered_writer.write_string(PUGIXML_TEXT(
"<?xml version=\"1.0\""));
7264 if (encoding == encoding_latin1) buffered_writer.write_string(PUGIXML_TEXT(
" encoding=\"ISO-8859-1\""));
7265 buffered_writer.write(
'?',
'>');
7266 if (!(flags & format_raw)) buffered_writer.write(
'\n');
7269 impl::node_output(buffered_writer, _root, indent, flags, 0);
7271 buffered_writer.flush();
7274#ifndef PUGIXML_NO_STL
7275 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
7277 xml_writer_stream writer(stream);
7279 save(writer, indent, flags, encoding);
7282 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
7284 xml_writer_stream writer(stream);
7286 save(writer, indent, flags, encoding_wchar);
7290 PUGI__FN
bool xml_document::save_file(
const char* path_,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
const
7292 using impl::auto_deleter;
7293 auto_deleter<FILE> file(impl::open_file(path_, (flags & format_save_file_text) ?
"w" :
"wb"), impl::close_file);
7295 return impl::save_file_impl(*
this, file.data, indent, flags, encoding);
7298 PUGI__FN
bool xml_document::save_file(
const wchar_t* path_,
const char_t* indent,
unsigned int flags, xml_encoding encoding)
const
7300 using impl::auto_deleter;
7301 auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L
"w" : L
"wb"), impl::close_file);
7303 return impl::save_file_impl(*
this, file.data, indent, flags, encoding);
7306 PUGI__FN xml_node xml_document::document_element()
const
7310 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
7311 if (PUGI__NODETYPE(i) == node_element)
7317#ifndef PUGIXML_NO_STL
7318 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(
const wchar_t* str)
7322 return impl::as_utf8_impl(str, impl::strlength_wide(str));
7325 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(
const std::basic_string<wchar_t>& str)
7327 return impl::as_utf8_impl(str.c_str(), str.size());
7330 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(
const char* str)
7334 return impl::as_wide_impl(str, strlen(str));
7337 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(
const std::string& str)
7339 return impl::as_wide_impl(str.c_str(), str.size());
7343 PUGI__FN
void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
7345 impl::xml_memory::allocate = allocate;
7346 impl::xml_memory::deallocate = deallocate;
7349 PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
7351 return impl::xml_memory::allocate;
7354 PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
7356 return impl::xml_memory::deallocate;
7360#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
7364 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(
const pugi::xml_node_iterator&)
7366 return std::bidirectional_iterator_tag();
7369 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(
const pugi::xml_attribute_iterator&)
7371 return std::bidirectional_iterator_tag();
7374 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(
const pugi::xml_named_node_iterator&)
7376 return std::bidirectional_iterator_tag();
7381#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
7385 PUGI__FN std::bidirectional_iterator_tag __iterator_category(
const pugi::xml_node_iterator&)
7387 return std::bidirectional_iterator_tag();
7390 PUGI__FN std::bidirectional_iterator_tag __iterator_category(
const pugi::xml_attribute_iterator&)
7392 return std::bidirectional_iterator_tag();
7395 PUGI__FN std::bidirectional_iterator_tag __iterator_category(
const pugi::xml_named_node_iterator&)
7397 return std::bidirectional_iterator_tag();
7402#ifndef PUGIXML_NO_XPATH
7407 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
7415 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
7423 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
7431 template <
typename T>
bool operator()(
const T& lhs,
const T& rhs)
const
7437 template <
typename T>
inline void swap(T& lhs, T& rhs)
7444 template <
typename I,
typename Pred> PUGI__FN I min_element(I begin, I end,
const Pred& pred)
7448 for (I it = begin + 1; it != end; ++it)
7449 if (pred(*it, *result))
7455 template <
typename I> PUGI__FN
void reverse(I begin, I end)
7457 while (end - begin > 1)
7458 swap(*begin++, *--end);
7461 template <
typename I> PUGI__FN I unique(I begin, I end)
7464 while (end - begin > 1 && *begin != *(begin + 1))
7474 while (begin != end)
7476 if (*begin != *write)
7477 *++write = *begin++;
7486 template <
typename T,
typename Pred> PUGI__FN
void insertion_sort(T* begin, T* end,
const Pred& pred)
7491 for (T* it = begin + 1; it != end; ++it)
7497 while (hole > begin && pred(val, *(hole - 1)))
7499 *hole = *(hole - 1);
7508 template <
typename I,
typename Pred>
inline I median3(I first, I middle, I last,
const Pred& pred)
7510 if (pred(*middle, *first))
7511 swap(middle, first);
7512 if (pred(*last, *middle))
7514 if (pred(*middle, *first))
7515 swap(middle, first);
7520 template <
typename T,
typename Pred> PUGI__FN
void partition3(T* begin, T* end, T pivot,
const Pred& pred, T** out_eqbeg, T** out_eqend)
7529 if (pred(*lt, pivot))
7531 else if (*lt == pivot)
7540 for (T* it = begin; it != eq; ++it)
7541 swap(*it, *--eqbeg);
7547 template <
typename I,
typename Pred> PUGI__FN
void sort(I begin, I end,
const Pred& pred)
7550 while (end - begin > 16)
7553 I middle = begin + (end - begin) / 2;
7554 I median = median3(begin, middle, end - 1, pred);
7558 partition3(begin, end, *median, pred, &eqbeg, &eqend);
7561 if (eqbeg - begin > end - eqend)
7563 sort(eqend, end, pred);
7568 sort(begin, eqbeg, pred);
7574 insertion_sort(begin, end, pred);
7577 PUGI__FN
bool hash_insert(
const void** table,
size_t size,
const void* key)
7581 unsigned int h =
static_cast<unsigned int>(
reinterpret_cast<uintptr_t
>(key));
7590 size_t hashmod = size - 1;
7591 size_t bucket = h & hashmod;
7593 for (
size_t probe = 0; probe <= hashmod; ++probe)
7595 if (table[bucket] == 0)
7597 table[bucket] = key;
7601 if (table[bucket] == key)
7605 bucket = (bucket + probe + 1) & hashmod;
7608 assert(
false &&
"Hash table is full");
7615 static const size_t xpath_memory_page_size =
7616 #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
7617 PUGIXML_MEMORY_XPATH_PAGE_SIZE
7623 static const uintptr_t xpath_memory_block_alignment =
sizeof(double) >
sizeof(
void*) ?
sizeof(double) : sizeof(void*);
7625 struct xpath_memory_block
7627 xpath_memory_block* next;
7632 char data[xpath_memory_page_size];
7637 struct xpath_allocator
7639 xpath_memory_block* _root;
7643 xpath_allocator(xpath_memory_block* root,
bool* error = 0): _root(root), _root_size(0), _error(error)
7647 void* allocate(
size_t size)
7650 size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7652 if (_root_size + size <= _root->capacity)
7654 void* buf = &_root->data[0] + _root_size;
7661 size_t block_capacity_base =
sizeof(_root->data);
7662 size_t block_capacity_req = size + block_capacity_base / 4;
7663 size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req;
7665 size_t block_size = block_capacity + offsetof(xpath_memory_block, data);
7667 xpath_memory_block* block =
static_cast<xpath_memory_block*
>(xml_memory::allocate(block_size));
7670 if (_error) *_error =
true;
7674 block->next = _root;
7675 block->capacity = block_capacity;
7684 void* reallocate(
void* ptr,
size_t old_size,
size_t new_size)
7687 old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7688 new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
7691 assert(ptr == 0 ||
static_cast<char*
>(ptr) + old_size == &_root->data[0] + _root_size);
7694 if (ptr && _root_size - old_size + new_size <= _root->capacity)
7696 _root_size = _root_size - old_size + new_size;
7701 void* result = allocate(new_size);
7702 if (!result)
return 0;
7708 assert(new_size >= old_size);
7709 memcpy(result, ptr, old_size);
7712 assert(_root->data == result);
7713 assert(_root->next);
7715 if (_root->next->data == ptr)
7718 xpath_memory_block* next = _root->next->next;
7722 xml_memory::deallocate(_root->next);
7731 void revert(
const xpath_allocator& state)
7734 xpath_memory_block* cur = _root;
7736 while (cur != state._root)
7738 xpath_memory_block* next = cur->next;
7740 xml_memory::deallocate(cur);
7746 _root = state._root;
7747 _root_size = state._root_size;
7752 xpath_memory_block* cur = _root;
7757 xpath_memory_block* next = cur->next;
7759 xml_memory::deallocate(cur);
7766 struct xpath_allocator_capture
7768 xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc)
7772 ~xpath_allocator_capture()
7774 _target->revert(_state);
7777 xpath_allocator* _target;
7778 xpath_allocator _state;
7783 xpath_allocator* result;
7784 xpath_allocator* temp;
7787 struct xpath_stack_data
7789 xpath_memory_block blocks[2];
7790 xpath_allocator result;
7791 xpath_allocator temp;
7795 xpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false)
7797 blocks[0].next = blocks[1].next = 0;
7798 blocks[0].capacity = blocks[1].capacity =
sizeof(blocks[0].data);
7800 stack.result = &result;
7816 const char_t* _buffer;
7818 size_t _length_heap;
7820 static char_t* duplicate_string(
const char_t*
string,
size_t length, xpath_allocator* alloc)
7822 char_t* result =
static_cast<char_t*
>(alloc->allocate((length + 1) *
sizeof(char_t)));
7823 if (!result)
return 0;
7825 memcpy(result,
string, length *
sizeof(char_t));
7831 xpath_string(
const char_t* buffer,
bool uses_heap_,
size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap)
7836 static xpath_string from_const(
const char_t* str)
7838 return xpath_string(str,
false, 0);
7841 static xpath_string from_heap_preallocated(
const char_t* begin,
const char_t* end)
7843 assert(begin <= end && *end == 0);
7845 return xpath_string(begin,
true,
static_cast<size_t>(end - begin));
7848 static xpath_string from_heap(
const char_t* begin,
const char_t* end, xpath_allocator* alloc)
7850 assert(begin <= end);
7853 return xpath_string();
7855 size_t length =
static_cast<size_t>(end - begin);
7856 const char_t* data = duplicate_string(begin, length, alloc);
7858 return data ? xpath_string(data,
true, length) : xpath_string();
7861 xpath_string(): _buffer(PUGIXML_TEXT(
"")), _uses_heap(false), _length_heap(0)
7865 void append(
const xpath_string& o, xpath_allocator* alloc)
7868 if (!*o._buffer)
return;
7871 if (!*_buffer && !_uses_heap && !o._uses_heap)
7873 _buffer = o._buffer;
7878 size_t target_length = length();
7879 size_t source_length = o.length();
7880 size_t result_length = target_length + source_length;
7883 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)));
7884 if (!result)
return;
7887 if (!_uses_heap) memcpy(result, _buffer, target_length *
sizeof(char_t));
7890 memcpy(result + target_length, o._buffer, source_length *
sizeof(char_t));
7891 result[result_length] = 0;
7896 _length_heap = result_length;
7900 const char_t* c_str()
const
7905 size_t length()
const
7907 return _uses_heap ? _length_heap : strlength(_buffer);
7910 char_t* data(xpath_allocator* alloc)
7915 size_t length_ = strlength(_buffer);
7916 const char_t* data_ = duplicate_string(_buffer, length_, alloc);
7918 if (!data_)
return 0;
7922 _length_heap = length_;
7925 return const_cast<char_t*
>(_buffer);
7930 return *_buffer == 0;
7933 bool operator==(
const xpath_string& o)
const
7935 return strequal(_buffer, o._buffer);
7938 bool operator!=(
const xpath_string& o)
const
7940 return !strequal(_buffer, o._buffer);
7943 bool uses_heap()
const
7951 PUGI__FN
bool starts_with(
const char_t*
string,
const char_t* pattern)
7953 while (*pattern && *
string == *pattern)
7959 return *pattern == 0;
7962 PUGI__FN
const char_t* find_char(
const char_t* s, char_t c)
7964 #ifdef PUGIXML_WCHAR_MODE
7965 return wcschr(s, c);
7967 return strchr(s, c);
7971 PUGI__FN
const char_t* find_substring(
const char_t* s,
const char_t* p)
7973 #ifdef PUGIXML_WCHAR_MODE
7975 return (*p == 0) ? s : wcsstr(s, p);
7977 return strstr(s, p);
7982 PUGI__FN char_t tolower_ascii(char_t ch)
7984 return static_cast<unsigned int>(ch -
'A') < 26 ?
static_cast<char_t
>(ch |
' ') : ch;
7987 PUGI__FN xpath_string string_value(
const xpath_node& na, xpath_allocator* alloc)
7990 return xpath_string::from_const(na.attribute().value());
7993 xml_node n = na.node();
8001 return xpath_string::from_const(n.value());
8006 xpath_string result;
8010 result.append(xpath_string::from_const(n.value()), alloc);
8012 xml_node cur = n.first_child();
8014 while (cur && cur != n)
8016 if (cur.type() == node_pcdata || cur.type() == node_cdata)
8017 result.append(xpath_string::from_const(cur.value()), alloc);
8019 if (cur.first_child())
8020 cur = cur.first_child();
8021 else if (cur.next_sibling())
8022 cur = cur.next_sibling();
8025 while (!cur.next_sibling() && cur != n)
8028 if (cur != n) cur = cur.next_sibling();
8036 return xpath_string();
8041 PUGI__FN
bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)
8043 assert(ln->parent == rn->parent);
8046 if (!ln->parent)
return ln < rn;
8049 xml_node_struct* ls = ln;
8050 xml_node_struct* rs = rn;
8054 if (ls == rn)
return true;
8055 if (rs == ln)
return false;
8057 ls = ls->next_sibling;
8058 rs = rs->next_sibling;
8065 PUGI__FN
bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
8068 xml_node_struct* lp = ln;
8069 xml_node_struct* rp = rn;
8071 while (lp && rp && lp->parent != rp->parent)
8078 if (lp && rp)
return node_is_before_sibling(lp, rp);
8081 bool left_higher = !lp;
8096 if (ln == rn)
return left_higher;
8099 while (ln->parent != rn->parent)
8105 return node_is_before_sibling(ln, rn);
8108 PUGI__FN
bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)
8110 while (node && node != parent) node = node->parent;
8112 return parent && node == parent;
8115 PUGI__FN
const void* document_buffer_order(
const xpath_node& xnode)
8117 xml_node_struct* node = xnode.node().internal_object();
8121 if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0)
8123 if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0)
return node->name;
8124 if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0)
return node->value;
8130 xml_attribute_struct* attr = xnode.attribute().internal_object();
8134 if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0)
8136 if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0)
return attr->name;
8137 if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0)
return attr->value;
8146 struct document_order_comparator
8148 bool operator()(
const xpath_node& lhs,
const xpath_node& rhs)
const
8151 const void* lo = document_buffer_order(lhs);
8152 const void* ro = document_buffer_order(rhs);
8154 if (lo && ro)
return lo < ro;
8157 xml_node ln = lhs.node(), rn = rhs.node();
8160 if (lhs.attribute() && rhs.attribute())
8163 if (lhs.parent() == rhs.parent())
8166 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
8167 if (a == rhs.attribute())
8177 else if (lhs.attribute())
8180 if (lhs.parent() == rhs.node())
return false;
8184 else if (rhs.attribute())
8187 if (rhs.parent() == lhs.node())
return true;
8192 if (ln == rn)
return false;
8194 if (!ln || !rn)
return ln < rn;
8196 return node_is_before(ln.internal_object(), rn.internal_object());
8200 PUGI__FN
double gen_nan()
8202 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
8203 PUGI__STATIC_ASSERT(
sizeof(
float) ==
sizeof(uint32_t));
8204 typedef uint32_t UI;
8205 union {
float f; UI i; } u;
8210 const volatile double zero = 0.0;
8215 PUGI__FN
bool is_nan(
double value)
8217 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
8218 return !!_isnan(value);
8219 #elif defined(fpclassify) && defined(FP_NAN)
8220 return fpclassify(value) == FP_NAN;
8223 const volatile double v = value;
8228 PUGI__FN
const char_t* convert_number_to_string_special(
double value)
8230 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
8231 if (_finite(value))
return (value == 0) ? PUGIXML_TEXT(
"0") : 0;
8232 if (_isnan(value))
return PUGIXML_TEXT(
"NaN");
8233 return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
8234 #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
8235 switch (fpclassify(value))
8238 return PUGIXML_TEXT(
"NaN");
8241 return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
8244 return PUGIXML_TEXT(
"0");
8251 const volatile double v = value;
8253 if (v == 0)
return PUGIXML_TEXT(
"0");
8254 if (v != v)
return PUGIXML_TEXT(
"NaN");
8255 if (v * 2 == v)
return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
8260 PUGI__FN
bool convert_number_to_boolean(
double value)
8262 return (value != 0 && !is_nan(value));
8265 PUGI__FN
void truncate_zeros(
char* begin,
char* end)
8267 while (begin != end && end[-1] ==
'0') end--;
8273#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
8274 PUGI__FN
void convert_number_to_mantissa_exponent(
double value,
char (&buffer)[32],
char** out_mantissa,
int* out_exponent)
8278 _ecvt_s(buffer,
sizeof(buffer), value, DBL_DIG + 1, &exponent, &sign);
8281 truncate_zeros(buffer, buffer + strlen(buffer));
8284 *out_mantissa = buffer;
8285 *out_exponent = exponent;
8288 PUGI__FN
void convert_number_to_mantissa_exponent(
double value,
char (&buffer)[32],
char** out_mantissa,
int* out_exponent)
8291 PUGI__SNPRINTF(buffer,
"%.*e", DBL_DIG, value);
8294 char* exponent_string = strchr(buffer,
'e');
8295 assert(exponent_string);
8297 int exponent = atoi(exponent_string + 1);
8300 char* mantissa = buffer[0] ==
'-' ? buffer + 1 : buffer;
8301 assert(mantissa[0] !=
'0' && mantissa[1] ==
'.');
8304 mantissa[1] = mantissa[0];
8309 truncate_zeros(mantissa, exponent_string);
8312 *out_mantissa = mantissa;
8313 *out_exponent = exponent;
8317 PUGI__FN xpath_string convert_number_to_string(
double value, xpath_allocator* alloc)
8320 const char_t* special = convert_number_to_string_special(value);
8321 if (special)
return xpath_string::from_const(special);
8324 char mantissa_buffer[32];
8328 convert_number_to_mantissa_exponent(value, mantissa_buffer, &mantissa, &exponent);
8331 size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
8332 char_t* result =
static_cast<char_t*
>(alloc->allocate(
sizeof(char_t) * result_size));
8333 if (!result)
return xpath_string();
8339 if (value < 0) *s++ =
'-';
8348 while (exponent > 0)
8350 assert(*mantissa == 0 ||
static_cast<unsigned int>(*mantissa -
'0') <= 9);
8351 *s++ = *mantissa ? *mantissa++ :
'0';
8363 while (exponent < 0)
8372 assert(
static_cast<unsigned int>(*mantissa -
'0') <= 9);
8378 assert(s < result + result_size);
8381 return xpath_string::from_heap_preallocated(result, s);
8384 PUGI__FN
bool check_string_to_number_format(
const char_t*
string)
8387 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
8390 if (*
string ==
'-') ++string;
8392 if (!*
string)
return false;
8395 if (!PUGI__IS_CHARTYPEX(
string[0], ctx_digit) && (
string[0] !=
'.' || !PUGI__IS_CHARTYPEX(
string[1], ctx_digit)))
return false;
8398 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
8405 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
8409 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
8411 return *
string == 0;
8414 PUGI__FN
double convert_string_to_number(
const char_t*
string)
8417 if (!check_string_to_number_format(
string))
return gen_nan();
8420 #ifdef PUGIXML_WCHAR_MODE
8421 return wcstod(
string, 0);
8423 return strtod(
string, 0);
8427 PUGI__FN
bool convert_string_to_number_scratch(char_t (&buffer)[32],
const char_t* begin,
const char_t* end,
double* out_result)
8429 size_t length =
static_cast<size_t>(end - begin);
8430 char_t* scratch = buffer;
8432 if (length >=
sizeof(buffer) /
sizeof(buffer[0]))
8435 scratch =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
8436 if (!scratch)
return false;
8440 memcpy(scratch, begin, length *
sizeof(char_t));
8441 scratch[length] = 0;
8443 *out_result = convert_string_to_number(scratch);
8446 if (scratch != buffer) xml_memory::deallocate(scratch);
8451 PUGI__FN
double round_nearest(
double value)
8453 return floor(value + 0.5);
8456 PUGI__FN
double round_nearest_nzero(
double value)
8460 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
8463 PUGI__FN
const char_t* qualified_name(
const xpath_node& node)
8465 return node.attribute() ? node.attribute().name() : node.node().name();
8468 PUGI__FN
const char_t* local_name(
const xpath_node& node)
8470 const char_t* name = qualified_name(node);
8471 const char_t* p = find_char(name,
':');
8473 return p ? p + 1 : name;
8476 struct namespace_uri_predicate
8478 const char_t* prefix;
8479 size_t prefix_length;
8481 namespace_uri_predicate(
const char_t* name)
8483 const char_t* pos = find_char(name,
':');
8485 prefix = pos ? name : 0;
8486 prefix_length = pos ?
static_cast<size_t>(pos - name) : 0;
8489 bool operator()(xml_attribute a)
const
8491 const char_t* name = a.name();
8493 if (!starts_with(name, PUGIXML_TEXT(
"xmlns")))
return false;
8495 return prefix ? name[5] ==
':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
8499 PUGI__FN
const char_t* namespace_uri(xml_node node)
8501 namespace_uri_predicate pred = node.name();
8507 xml_attribute a = p.find_attribute(pred);
8509 if (a)
return a.value();
8514 return PUGIXML_TEXT(
"");
8517 PUGI__FN
const char_t* namespace_uri(xml_attribute attr, xml_node parent)
8519 namespace_uri_predicate pred = attr.name();
8522 if (!pred.prefix)
return PUGIXML_TEXT(
"");
8524 xml_node p = parent;
8528 xml_attribute a = p.find_attribute(pred);
8530 if (a)
return a.value();
8535 return PUGIXML_TEXT(
"");
8538 PUGI__FN
const char_t* namespace_uri(
const xpath_node& node)
8540 return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
8543 PUGI__FN char_t* normalize_space(char_t* buffer)
8545 char_t* write = buffer;
8547 for (char_t* it = buffer; *it; )
8551 if (PUGI__IS_CHARTYPE(ch, ct_space))
8554 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
8557 if (write != buffer) *write++ =
' ';
8563 if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
8571 PUGI__FN char_t* translate(char_t* buffer,
const char_t* from,
const char_t* to,
size_t to_length)
8573 char_t* write = buffer;
8577 PUGI__DMC_VOLATILE char_t ch = *buffer++;
8579 const char_t* pos = find_char(from, ch);
8583 else if (
static_cast<size_t>(pos - from) < to_length)
8584 *write++ = to[pos - from];
8593 PUGI__FN
unsigned char* translate_table_generate(xpath_allocator* alloc,
const char_t* from,
const char_t* to)
8595 unsigned char table[128] = {0};
8599 unsigned int fc =
static_cast<unsigned int>(*from);
8600 unsigned int tc =
static_cast<unsigned int>(*to);
8602 if (fc >= 128 || tc >= 128)
8607 table[fc] =
static_cast<unsigned char>(tc ? tc : 128);
8613 for (
int i = 0; i < 128; ++i)
8615 table[i] =
static_cast<unsigned char>(i);
8617 void* result = alloc->allocate(
sizeof(table));
8618 if (!result)
return 0;
8620 memcpy(result, table,
sizeof(table));
8622 return static_cast<unsigned char*
>(result);
8625 PUGI__FN char_t* translate_table(char_t* buffer,
const unsigned char* table)
8627 char_t* write = buffer;
8631 char_t ch = *buffer++;
8632 unsigned int index =
static_cast<unsigned int>(ch);
8636 unsigned char code = table[index];
8640 *write =
static_cast<char_t
>(code);
8641 write += 1 - (code >> 7);
8655 inline bool is_xpath_attribute(
const char_t* name)
8657 return !(starts_with(name, PUGIXML_TEXT(
"xmlns")) && (name[5] == 0 || name[5] ==
':'));
8660 struct xpath_variable_boolean: xpath_variable
8662 xpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false)
8670 struct xpath_variable_number: xpath_variable
8672 xpath_variable_number(): xpath_variable(xpath_type_number), value(0)
8680 struct xpath_variable_string: xpath_variable
8682 xpath_variable_string(): xpath_variable(xpath_type_string), value(0)
8686 ~xpath_variable_string()
8688 if (value) xml_memory::deallocate(value);
8695 struct xpath_variable_node_set: xpath_variable
8697 xpath_variable_node_set(): xpath_variable(xpath_type_node_set)
8701 xpath_node_set value;
8705 static const xpath_node_set dummy_node_set;
8707 PUGI__FN PUGI__UNSIGNED_OVERFLOW
unsigned int hash_string(
const char_t* str)
8710 unsigned int result = 0;
8714 result +=
static_cast<unsigned int>(*str++);
8715 result += result << 10;
8716 result ^= result >> 6;
8719 result += result << 3;
8720 result ^= result >> 11;
8721 result += result << 15;
8726 template <
typename T> PUGI__FN T* new_xpath_variable(
const char_t* name)
8728 size_t length = strlength(name);
8729 if (length == 0)
return 0;
8732 void* memory = xml_memory::allocate(
sizeof(T) + length *
sizeof(char_t));
8733 if (!memory)
return 0;
8735 T* result =
new (memory) T();
8737 memcpy(result->name, name, (length + 1) *
sizeof(char_t));
8742 PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type,
const char_t* name)
8746 case xpath_type_node_set:
8747 return new_xpath_variable<xpath_variable_node_set>(name);
8749 case xpath_type_number:
8750 return new_xpath_variable<xpath_variable_number>(name);
8752 case xpath_type_string:
8753 return new_xpath_variable<xpath_variable_string>(name);
8755 case xpath_type_boolean:
8756 return new_xpath_variable<xpath_variable_boolean>(name);
8763 template <
typename T> PUGI__FN
void delete_xpath_variable(T* var)
8766 xml_memory::deallocate(var);
8769 PUGI__FN
void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
8773 case xpath_type_node_set:
8774 delete_xpath_variable(
static_cast<xpath_variable_node_set*
>(var));
8777 case xpath_type_number:
8778 delete_xpath_variable(
static_cast<xpath_variable_number*
>(var));
8781 case xpath_type_string:
8782 delete_xpath_variable(
static_cast<xpath_variable_string*
>(var));
8785 case xpath_type_boolean:
8786 delete_xpath_variable(
static_cast<xpath_variable_boolean*
>(var));
8790 assert(
false &&
"Invalid variable type");
8794 PUGI__FN
bool copy_xpath_variable(xpath_variable* lhs,
const xpath_variable* rhs)
8796 switch (rhs->type())
8798 case xpath_type_node_set:
8799 return lhs->set(
static_cast<const xpath_variable_node_set*
>(rhs)->value);
8801 case xpath_type_number:
8802 return lhs->set(
static_cast<const xpath_variable_number*
>(rhs)->value);
8804 case xpath_type_string:
8805 return lhs->set(
static_cast<const xpath_variable_string*
>(rhs)->value);
8807 case xpath_type_boolean:
8808 return lhs->set(
static_cast<const xpath_variable_boolean*
>(rhs)->value);
8811 assert(
false &&
"Invalid variable type");
8816 PUGI__FN
bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set*
set,
const char_t* begin,
const char_t* end, xpath_variable** out_result)
8818 size_t length =
static_cast<size_t>(end - begin);
8819 char_t* scratch = buffer;
8821 if (length >=
sizeof(buffer) /
sizeof(buffer[0]))
8824 scratch =
static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
8825 if (!scratch)
return false;
8829 memcpy(scratch, begin, length *
sizeof(char_t));
8830 scratch[length] = 0;
8832 *out_result =
set->get(scratch);
8835 if (scratch != buffer) xml_memory::deallocate(scratch);
8843 PUGI__FN xpath_node_set::type_t xpath_get_order(
const xpath_node* begin,
const xpath_node* end)
8845 if (end - begin < 2)
8846 return xpath_node_set::type_sorted;
8848 document_order_comparator cmp;
8850 bool first = cmp(begin[0], begin[1]);
8852 for (
const xpath_node* it = begin + 1; it + 1 < end; ++it)
8853 if (cmp(it[0], it[1]) != first)
8854 return xpath_node_set::type_unsorted;
8856 return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse;
8859 PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type,
bool rev)
8861 xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
8863 if (type == xpath_node_set::type_unsorted)
8865 xpath_node_set::type_t sorted = xpath_get_order(begin, end);
8867 if (sorted == xpath_node_set::type_unsorted)
8869 sort(begin, end, document_order_comparator());
8871 type = xpath_node_set::type_sorted;
8877 if (type != order) reverse(begin, end);
8882 PUGI__FN xpath_node xpath_first(
const xpath_node* begin,
const xpath_node* end, xpath_node_set::type_t type)
8884 if (begin == end)
return xpath_node();
8888 case xpath_node_set::type_sorted:
8891 case xpath_node_set::type_sorted_reverse:
8894 case xpath_node_set::type_unsorted:
8895 return *min_element(begin, end, document_order_comparator());
8898 assert(
false &&
"Invalid node set type");
8899 return xpath_node();
8903 class xpath_node_set_raw
8905 xpath_node_set::type_t _type;
8912 xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0)
8916 xpath_node* begin()
const
8921 xpath_node* end()
const
8928 return _begin == _end;
8933 return static_cast<size_t>(_end - _begin);
8936 xpath_node first()
const
8938 return xpath_first(_begin, _end, _type);
8941 void push_back_grow(
const xpath_node& node, xpath_allocator* alloc);
8943 void push_back(
const xpath_node& node, xpath_allocator* alloc)
8948 push_back_grow(node, alloc);
8951 void append(
const xpath_node* begin_,
const xpath_node* end_, xpath_allocator* alloc)
8953 if (begin_ == end_)
return;
8955 size_t size_ =
static_cast<size_t>(_end - _begin);
8956 size_t capacity =
static_cast<size_t>(_eos - _begin);
8957 size_t count =
static_cast<size_t>(end_ - begin_);
8959 if (size_ + count > capacity)
8962 xpath_node* data =
static_cast<xpath_node*
>(alloc->reallocate(_begin, capacity *
sizeof(xpath_node), (size_ + count) *
sizeof(xpath_node)));
8967 _end = data + size_;
8968 _eos = data + size_ + count;
8971 memcpy(_end, begin_, count *
sizeof(xpath_node));
8977 _type = xpath_sort(_begin, _end, _type,
false);
8980 void truncate(xpath_node* pos)
8982 assert(_begin <= pos && pos <= _end);
8987 void remove_duplicates(xpath_allocator* alloc)
8989 if (_type == xpath_node_set::type_unsorted && _end - _begin > 2)
8991 xpath_allocator_capture cr(alloc);
8993 size_t size_ =
static_cast<size_t>(_end - _begin);
8995 size_t hash_size = 1;
8996 while (hash_size < size_ + size_ / 2) hash_size *= 2;
8998 const void** hash_data =
static_cast<const void**
>(alloc->allocate(hash_size *
sizeof(
void**)));
8999 if (!hash_data)
return;
9001 memset(hash_data, 0, hash_size *
sizeof(
const void**));
9003 xpath_node* write = _begin;
9005 for (xpath_node* it = _begin; it != _end; ++it)
9007 const void* attr = it->attribute().internal_object();
9008 const void* node = it->node().internal_object();
9009 const void* key = attr ? attr : node;
9011 if (key && hash_insert(hash_data, hash_size, key))
9021 _end = unique(_begin, _end);
9025 xpath_node_set::type_t type()
const
9030 void set_type(xpath_node_set::type_t value)
9036 PUGI__FN_NO_INLINE
void xpath_node_set_raw::push_back_grow(
const xpath_node& node, xpath_allocator* alloc)
9038 size_t capacity =
static_cast<size_t>(_eos - _begin);
9041 size_t new_capacity = capacity + capacity / 2 + 1;
9044 xpath_node* data =
static_cast<xpath_node*
>(alloc->reallocate(_begin, capacity *
sizeof(xpath_node), new_capacity *
sizeof(xpath_node)));
9049 _end = data + capacity;
9050 _eos = data + new_capacity;
9058 struct xpath_context
9061 size_t position, size;
9063 xpath_context(
const xpath_node& n_,
size_t position_,
size_t size_): n(n_), position(position_), size(size_)
9076 lex_greater_or_equal,
9088 lex_open_square_brace,
9089 lex_close_square_brace,
9099 struct xpath_lexer_string
9101 const char_t* begin;
9104 xpath_lexer_string(): begin(0), end(0)
9108 bool operator==(
const char_t* other)
const
9110 size_t length =
static_cast<size_t>(end - begin);
9112 return strequalrange(other, begin, length);
9119 const char_t* _cur_lexeme_pos;
9120 xpath_lexer_string _cur_lexeme_contents;
9122 lexeme_t _cur_lexeme;
9125 explicit xpath_lexer(
const char_t* query): _cur(query)
9130 const char_t* state()
const
9137 const char_t* cur = _cur;
9139 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
9142 _cur_lexeme_pos = cur;
9147 _cur_lexeme = lex_eof;
9151 if (*(cur+1) ==
'=')
9154 _cur_lexeme = lex_greater_or_equal;
9159 _cur_lexeme = lex_greater;
9164 if (*(cur+1) ==
'=')
9167 _cur_lexeme = lex_less_or_equal;
9172 _cur_lexeme = lex_less;
9177 if (*(cur+1) ==
'=')
9180 _cur_lexeme = lex_not_equal;
9184 _cur_lexeme = lex_none;
9190 _cur_lexeme = lex_equal;
9196 _cur_lexeme = lex_plus;
9202 _cur_lexeme = lex_minus;
9208 _cur_lexeme = lex_multiply;
9214 _cur_lexeme = lex_union;
9221 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
9223 _cur_lexeme_contents.begin = cur;
9225 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9227 if (cur[0] ==
':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
9231 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9234 _cur_lexeme_contents.end = cur;
9236 _cur_lexeme = lex_var_ref;
9240 _cur_lexeme = lex_none;
9247 _cur_lexeme = lex_open_brace;
9253 _cur_lexeme = lex_close_brace;
9259 _cur_lexeme = lex_open_square_brace;
9265 _cur_lexeme = lex_close_square_brace;
9271 _cur_lexeme = lex_comma;
9276 if (*(cur+1) ==
'/')
9279 _cur_lexeme = lex_double_slash;
9284 _cur_lexeme = lex_slash;
9289 if (*(cur+1) ==
'.')
9292 _cur_lexeme = lex_double_dot;
9294 else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
9296 _cur_lexeme_contents.begin = cur;
9300 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9302 _cur_lexeme_contents.end = cur;
9304 _cur_lexeme = lex_number;
9309 _cur_lexeme = lex_dot;
9315 _cur_lexeme = lex_axis_attribute;
9322 char_t terminator = *cur;
9326 _cur_lexeme_contents.begin = cur;
9327 while (*cur && *cur != terminator) cur++;
9328 _cur_lexeme_contents.end = cur;
9331 _cur_lexeme = lex_none;
9335 _cur_lexeme = lex_quoted_string;
9342 if (*(cur+1) ==
':')
9345 _cur_lexeme = lex_double_colon;
9349 _cur_lexeme = lex_none;
9354 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
9356 _cur_lexeme_contents.begin = cur;
9358 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9364 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
9367 _cur_lexeme_contents.end = cur;
9369 _cur_lexeme = lex_number;
9371 else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
9373 _cur_lexeme_contents.begin = cur;
9375 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9383 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
9387 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
9391 _cur_lexeme_contents.end = cur;
9393 _cur_lexeme = lex_string;
9397 _cur_lexeme = lex_none;
9404 lexeme_t current()
const
9409 const char_t* current_pos()
const
9411 return _cur_lexeme_pos;
9414 const xpath_lexer_string& contents()
const
9416 assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
9418 return _cur_lexeme_contents;
9431 ast_op_less_or_equal,
9432 ast_op_greater_or_equal,
9442 ast_string_constant,
9443 ast_number_constant,
9449 ast_func_local_name_0,
9450 ast_func_local_name_1,
9451 ast_func_namespace_uri_0,
9452 ast_func_namespace_uri_1,
9458 ast_func_starts_with,
9460 ast_func_substring_before,
9461 ast_func_substring_after,
9462 ast_func_substring_2,
9463 ast_func_substring_3,
9464 ast_func_string_length_0,
9465 ast_func_string_length_1,
9466 ast_func_normalize_space_0,
9467 ast_func_normalize_space_1,
9483 ast_opt_translate_table,
9484 ast_opt_compare_attribute
9490 axis_ancestor_or_self,
9494 axis_descendant_or_self,
9496 axis_following_sibling,
9500 axis_preceding_sibling,
9509 nodetest_type_comment,
9514 nodetest_all_in_namespace
9522 predicate_constant_one
9532 template <axis_t N>
struct axis_to_type
9534 static const axis_t axis;
9537 template <axis_t N>
const axis_t axis_to_type<N>::axis = N;
9539 class xpath_ast_node
9553 xpath_ast_node* _left;
9554 xpath_ast_node* _right;
9555 xpath_ast_node* _next;
9560 const char_t* string;
9564 xpath_variable* variable;
9566 const char_t* nodetest;
9568 const unsigned char* table;
9571 xpath_ast_node(
const xpath_ast_node&);
9572 xpath_ast_node& operator=(
const xpath_ast_node&);
9574 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)
9576 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
9578 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
9580 if (lt == xpath_type_boolean || rt == xpath_type_boolean)
9581 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
9582 else if (lt == xpath_type_number || rt == xpath_type_number)
9583 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
9584 else if (lt == xpath_type_string || rt == xpath_type_string)
9586 xpath_allocator_capture cr(stack.result);
9588 xpath_string ls = lhs->eval_string(c, stack);
9589 xpath_string rs = rhs->eval_string(c, stack);
9591 return comp(ls, rs);
9594 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
9596 xpath_allocator_capture cr(stack.result);
9598 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
9599 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9601 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9602 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9604 xpath_allocator_capture cri(stack.result);
9606 if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
9614 if (lt == xpath_type_node_set)
9620 if (lt == xpath_type_boolean)
9621 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
9622 else if (lt == xpath_type_number)
9624 xpath_allocator_capture cr(stack.result);
9626 double l = lhs->eval_number(c, stack);
9627 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9629 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9631 xpath_allocator_capture cri(stack.result);
9633 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9639 else if (lt == xpath_type_string)
9641 xpath_allocator_capture cr(stack.result);
9643 xpath_string l = lhs->eval_string(c, stack);
9644 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9646 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9648 xpath_allocator_capture cri(stack.result);
9650 if (comp(l, string_value(*ri, stack.result)))
9658 assert(
false &&
"Wrong types");
9662 static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval)
9664 return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any;
9667 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)
9669 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
9671 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
9672 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
9673 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
9675 xpath_allocator_capture cr(stack.result);
9677 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
9678 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9680 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9682 xpath_allocator_capture cri(stack.result);
9684 double l = convert_string_to_number(string_value(*li, stack.result).c_str());
9686 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9688 xpath_allocator_capture crii(stack.result);
9690 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9697 else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
9699 xpath_allocator_capture cr(stack.result);
9701 double l = lhs->eval_number(c, stack);
9702 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
9704 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
9706 xpath_allocator_capture cri(stack.result);
9708 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
9714 else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
9716 xpath_allocator_capture cr(stack.result);
9718 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
9719 double r = rhs->eval_number(c, stack);
9721 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li)
9723 xpath_allocator_capture cri(stack.result);
9725 if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
9733 assert(
false &&
"Wrong types");
9738 static void apply_predicate_boolean(xpath_node_set_raw& ns,
size_t first, xpath_ast_node* expr,
const xpath_stack& stack,
bool once)
9740 assert(ns.size() >= first);
9741 assert(expr->rettype() != xpath_type_number);
9744 size_t size = ns.size() - first;
9746 xpath_node* last = ns.begin() + first;
9749 for (xpath_node* it = last; it != ns.end(); ++it, ++i)
9751 xpath_context c(*it, i, size);
9753 if (expr->eval_boolean(c, stack))
9764 static void apply_predicate_number(xpath_node_set_raw& ns,
size_t first, xpath_ast_node* expr,
const xpath_stack& stack,
bool once)
9766 assert(ns.size() >= first);
9767 assert(expr->rettype() == xpath_type_number);
9770 size_t size = ns.size() - first;
9772 xpath_node* last = ns.begin() + first;
9775 for (xpath_node* it = last; it != ns.end(); ++it, ++i)
9777 xpath_context c(*it, i, size);
9779 if (expr->eval_number(c, stack) ==
static_cast<double>(i))
9790 static void apply_predicate_number_const(xpath_node_set_raw& ns,
size_t first, xpath_ast_node* expr,
const xpath_stack& stack)
9792 assert(ns.size() >= first);
9793 assert(expr->rettype() == xpath_type_number);
9795 size_t size = ns.size() - first;
9797 xpath_node* last = ns.begin() + first;
9799 xpath_context c(xpath_node(), 1, size);
9801 double er = expr->eval_number(c, stack);
9803 if (er >= 1.0 && er <=
static_cast<double>(size))
9805 size_t eri =
static_cast<size_t>(er);
9807 if (er ==
static_cast<double>(eri))
9809 xpath_node r = last[eri - 1];
9818 void apply_predicate(xpath_node_set_raw& ns,
size_t first,
const xpath_stack& stack,
bool once)
9820 if (ns.size() == first)
return;
9822 assert(_type == ast_filter || _type == ast_predicate);
9824 if (_test == predicate_constant || _test == predicate_constant_one)
9825 apply_predicate_number_const(ns, first, _right, stack);
9826 else if (_right->rettype() == xpath_type_number)
9827 apply_predicate_number(ns, first, _right, stack, once);
9829 apply_predicate_boolean(ns, first, _right, stack, once);
9832 void apply_predicates(xpath_node_set_raw& ns,
size_t first,
const xpath_stack& stack, nodeset_eval_t eval)
9834 if (ns.size() == first)
return;
9836 bool last_once = eval_once(ns.type(), eval);
9838 for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
9839 pred->apply_predicate(ns, first, stack, !pred->_next && last_once);
9842 bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc)
9846 const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT(
"");
9851 if (strequal(name, _data.nodetest) && is_xpath_attribute(name))
9853 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9858 case nodetest_type_node:
9860 if (is_xpath_attribute(name))
9862 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9867 case nodetest_all_in_namespace:
9868 if (starts_with(name, _data.nodetest) && is_xpath_attribute(name))
9870 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9882 bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc)
9886 xml_node_type type = PUGI__NODETYPE(n);
9891 if (type == node_element && n->name && strequal(n->name, _data.nodetest))
9893 ns.push_back(xml_node(n), alloc);
9898 case nodetest_type_node:
9899 ns.push_back(xml_node(n), alloc);
9902 case nodetest_type_comment:
9903 if (type == node_comment)
9905 ns.push_back(xml_node(n), alloc);
9910 case nodetest_type_text:
9911 if (type == node_pcdata || type == node_cdata)
9913 ns.push_back(xml_node(n), alloc);
9918 case nodetest_type_pi:
9919 if (type == node_pi)
9921 ns.push_back(xml_node(n), alloc);
9927 if (type == node_pi && n->name && strequal(n->name, _data.nodetest))
9929 ns.push_back(xml_node(n), alloc);
9935 if (type == node_element)
9937 ns.push_back(xml_node(n), alloc);
9942 case nodetest_all_in_namespace:
9943 if (type == node_element && n->name && starts_with(n->name, _data.nodetest))
9945 ns.push_back(xml_node(n), alloc);
9951 assert(
false &&
"Unknown axis");
9957 template <
class T>
void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc,
bool once, T)
9959 const axis_t axis = T::axis;
9963 case axis_attribute:
9965 for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute)
9966 if (step_push(ns, a, n, alloc) & once)
9974 for (xml_node_struct* c = n->first_child; c; c = c->next_sibling)
9975 if (step_push(ns, c, alloc) & once)
9981 case axis_descendant:
9982 case axis_descendant_or_self:
9984 if (axis == axis_descendant_or_self)
9985 if (step_push(ns, n, alloc) & once)
9988 xml_node_struct* cur = n->first_child;
9992 if (step_push(ns, cur, alloc) & once)
9995 if (cur->first_child)
9996 cur = cur->first_child;
9999 while (!cur->next_sibling)
10003 if (cur == n)
return;
10006 cur = cur->next_sibling;
10013 case axis_following_sibling:
10015 for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling)
10016 if (step_push(ns, c, alloc) & once)
10022 case axis_preceding_sibling:
10024 for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c)
10025 if (step_push(ns, c, alloc) & once)
10031 case axis_following:
10033 xml_node_struct* cur = n;
10036 while (!cur->next_sibling)
10043 cur = cur->next_sibling;
10047 if (step_push(ns, cur, alloc) & once)
10050 if (cur->first_child)
10051 cur = cur->first_child;
10054 while (!cur->next_sibling)
10061 cur = cur->next_sibling;
10068 case axis_preceding:
10070 xml_node_struct* cur = n;
10073 while (!cur->prev_sibling_c->next_sibling)
10080 cur = cur->prev_sibling_c;
10084 if (cur->first_child)
10085 cur = cur->first_child->prev_sibling_c;
10089 if (step_push(ns, cur, alloc) & once)
10092 while (!cur->prev_sibling_c->next_sibling)
10098 if (!node_is_ancestor(cur, n))
10099 if (step_push(ns, cur, alloc) & once)
10103 cur = cur->prev_sibling_c;
10110 case axis_ancestor:
10111 case axis_ancestor_or_self:
10113 if (axis == axis_ancestor_or_self)
10114 if (step_push(ns, n, alloc) & once)
10117 xml_node_struct* cur = n->parent;
10121 if (step_push(ns, cur, alloc) & once)
10132 step_push(ns, n, alloc);
10140 step_push(ns, n->parent, alloc);
10146 assert(
false &&
"Unimplemented axis");
10150 template <
class T>
void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc,
bool once, T v)
10152 const axis_t axis = T::axis;
10156 case axis_ancestor:
10157 case axis_ancestor_or_self:
10159 if (axis == axis_ancestor_or_self && _test == nodetest_type_node)
10160 if (step_push(ns, a, p, alloc) & once)
10163 xml_node_struct* cur = p;
10167 if (step_push(ns, cur, alloc) & once)
10176 case axis_descendant_or_self:
10179 if (_test == nodetest_type_node)
10180 step_push(ns, a, p, alloc);
10185 case axis_following:
10187 xml_node_struct* cur = p;
10191 if (cur->first_child)
10192 cur = cur->first_child;
10195 while (!cur->next_sibling)
10202 cur = cur->next_sibling;
10205 if (step_push(ns, cur, alloc) & once)
10214 step_push(ns, p, alloc);
10219 case axis_preceding:
10222 step_fill(ns, p, alloc, once, v);
10227 assert(
false &&
"Unimplemented axis");
10231 template <
class T>
void step_fill(xpath_node_set_raw& ns,
const xpath_node& xn, xpath_allocator* alloc,
bool once, T v)
10233 const axis_t axis = T::axis;
10234 const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
10237 step_fill(ns, xn.node().internal_object(), alloc, once, v);
10238 else if (axis_has_attributes && xn.attribute() && xn.parent())
10239 step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v);
10242 template <
class T> xpath_node_set_raw step_do(
const xpath_context& c,
const xpath_stack& stack, nodeset_eval_t eval, T v)
10244 const axis_t axis = T::axis;
10245 const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);
10246 const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
10249 (axis == axis_attribute && _test == nodetest_name) ||
10250 (!_right && eval_once(axis_type, eval)) ||
10252 (_right && !_right->_next && _right->_test == predicate_constant_one);
10254 xpath_node_set_raw ns;
10255 ns.set_type(axis_type);
10259 xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all);
10262 if (axis == axis_self) ns.set_type(s.type());
10264 for (
const xpath_node* it = s.begin(); it != s.end(); ++it)
10266 size_t size = ns.size();
10269 if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
10271 step_fill(ns, *it, stack.result, once, v);
10272 if (_right) apply_predicates(ns, size, stack, eval);
10277 step_fill(ns, c.n, stack.result, once, v);
10278 if (_right) apply_predicates(ns, 0, stack, eval);
10283 if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)
10284 ns.remove_duplicates(stack.temp);
10290 xpath_ast_node(ast_type_t type, xpath_value_type rettype_,
const char_t* value):
10291 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10293 assert(type == ast_string_constant);
10294 _data.string = value;
10297 xpath_ast_node(ast_type_t type, xpath_value_type rettype_,
double value):
10298 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10300 assert(type == ast_number_constant);
10301 _data.number = value;
10304 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):
10305 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
10307 assert(type == ast_variable);
10308 _data.variable = value;
10311 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0):
10312 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
10316 xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test,
const char_t* contents):
10317 _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)
10319 assert(type == ast_step);
10320 _data.nodetest = contents;
10323 xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test):
10324 _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast<char>(test)), _left(left), _right(right), _next(0)
10326 assert(type == ast_filter || type == ast_predicate);
10329 void set_next(xpath_ast_node* value)
10334 void set_right(xpath_ast_node* value)
10339 bool eval_boolean(
const xpath_context& c,
const xpath_stack& stack)
10344 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
10347 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
10350 return compare_eq(_left, _right, c, stack, equal_to());
10352 case ast_op_not_equal:
10353 return compare_eq(_left, _right, c, stack, not_equal_to());
10356 return compare_rel(_left, _right, c, stack, less());
10358 case ast_op_greater:
10359 return compare_rel(_right, _left, c, stack, less());
10361 case ast_op_less_or_equal:
10362 return compare_rel(_left, _right, c, stack, less_equal());
10364 case ast_op_greater_or_equal:
10365 return compare_rel(_right, _left, c, stack, less_equal());
10367 case ast_func_starts_with:
10369 xpath_allocator_capture cr(stack.result);
10371 xpath_string lr = _left->eval_string(c, stack);
10372 xpath_string rr = _right->eval_string(c, stack);
10374 return starts_with(lr.c_str(), rr.c_str());
10377 case ast_func_contains:
10379 xpath_allocator_capture cr(stack.result);
10381 xpath_string lr = _left->eval_string(c, stack);
10382 xpath_string rr = _right->eval_string(c, stack);
10384 return find_substring(lr.c_str(), rr.c_str()) != 0;
10387 case ast_func_boolean:
10388 return _left->eval_boolean(c, stack);
10391 return !_left->eval_boolean(c, stack);
10393 case ast_func_true:
10396 case ast_func_false:
10399 case ast_func_lang:
10401 if (c.n.attribute())
return false;
10403 xpath_allocator_capture cr(stack.result);
10405 xpath_string lang = _left->eval_string(c, stack);
10407 for (xml_node n = c.n.node(); n; n = n.parent())
10409 xml_attribute a = n.attribute(PUGIXML_TEXT(
"xml:lang"));
10413 const char_t* value = a.value();
10416 for (
const char_t* lit = lang.c_str(); *lit; ++lit)
10418 if (tolower_ascii(*lit) != tolower_ascii(*value))
return false;
10422 return *value == 0 || *value ==
'-';
10429 case ast_opt_compare_attribute:
10431 const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string();
10433 xml_attribute attr = c.n.node().attribute(_left->_data.nodetest);
10435 return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name());
10440 assert(_rettype == _data.variable->type());
10442 if (_rettype == xpath_type_boolean)
10443 return _data.variable->get_boolean();
10456 case xpath_type_number:
10457 return convert_number_to_boolean(eval_number(c, stack));
10459 case xpath_type_string:
10461 xpath_allocator_capture cr(stack.result);
10463 return !eval_string(c, stack).empty();
10466 case xpath_type_node_set:
10468 xpath_allocator_capture cr(stack.result);
10470 return !eval_node_set(c, stack, nodeset_eval_any).empty();
10474 assert(
false &&
"Wrong expression for return type boolean");
10479 double eval_number(
const xpath_context& c,
const xpath_stack& stack)
10484 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
10486 case ast_op_subtract:
10487 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
10489 case ast_op_multiply:
10490 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
10492 case ast_op_divide:
10493 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
10496 return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
10498 case ast_op_negate:
10499 return -_left->eval_number(c, stack);
10501 case ast_number_constant:
10502 return _data.number;
10504 case ast_func_last:
10505 return static_cast<double>(c.size);
10507 case ast_func_position:
10508 return static_cast<double>(c.position);
10510 case ast_func_count:
10512 xpath_allocator_capture cr(stack.result);
10514 return static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size());
10517 case ast_func_string_length_0:
10519 xpath_allocator_capture cr(stack.result);
10521 return static_cast<double>(string_value(c.n, stack.result).length());
10524 case ast_func_string_length_1:
10526 xpath_allocator_capture cr(stack.result);
10528 return static_cast<double>(_left->eval_string(c, stack).length());
10531 case ast_func_number_0:
10533 xpath_allocator_capture cr(stack.result);
10535 return convert_string_to_number(string_value(c.n, stack.result).c_str());
10538 case ast_func_number_1:
10539 return _left->eval_number(c, stack);
10543 xpath_allocator_capture cr(stack.result);
10547 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all);
10549 for (
const xpath_node* it = ns.begin(); it != ns.end(); ++it)
10551 xpath_allocator_capture cri(stack.result);
10553 r += convert_string_to_number(string_value(*it, stack.result).c_str());
10559 case ast_func_floor:
10561 double r = _left->eval_number(c, stack);
10563 return r == r ? floor(r) : r;
10566 case ast_func_ceiling:
10568 double r = _left->eval_number(c, stack);
10570 return r == r ? ceil(r) : r;
10573 case ast_func_round:
10574 return round_nearest_nzero(_left->eval_number(c, stack));
10578 assert(_rettype == _data.variable->type());
10580 if (_rettype == xpath_type_number)
10581 return _data.variable->get_number();
10594 case xpath_type_boolean:
10595 return eval_boolean(c, stack) ? 1 : 0;
10597 case xpath_type_string:
10599 xpath_allocator_capture cr(stack.result);
10601 return convert_string_to_number(eval_string(c, stack).c_str());
10604 case xpath_type_node_set:
10606 xpath_allocator_capture cr(stack.result);
10608 return convert_string_to_number(eval_string(c, stack).c_str());
10612 assert(
false &&
"Wrong expression for return type number");
10617 xpath_string eval_string_concat(
const xpath_context& c,
const xpath_stack& stack)
10619 assert(_type == ast_func_concat);
10621 xpath_allocator_capture ct(stack.temp);
10625 for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
10628 xpath_string* buffer =
static_cast<xpath_string*
>(stack.temp->allocate(count *
sizeof(xpath_string)));
10629 if (!buffer)
return xpath_string();
10632 xpath_stack swapped_stack = {stack.temp, stack.result};
10634 buffer[0] = _left->eval_string(c, swapped_stack);
10637 for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
10638 assert(pos == count);
10642 for (
size_t i = 0; i < count; ++i) length += buffer[i].length();
10645 char_t* result =
static_cast<char_t*
>(stack.result->allocate((length + 1) *
sizeof(char_t)));
10646 if (!result)
return xpath_string();
10648 char_t* ri = result;
10650 for (
size_t j = 0; j < count; ++j)
10651 for (
const char_t* bi = buffer[j].c_str(); *bi; ++bi)
10656 return xpath_string::from_heap_preallocated(result, ri);
10659 xpath_string eval_string(
const xpath_context& c,
const xpath_stack& stack)
10663 case ast_string_constant:
10664 return xpath_string::from_const(_data.string);
10666 case ast_func_local_name_0:
10668 xpath_node na = c.n;
10670 return xpath_string::from_const(local_name(na));
10673 case ast_func_local_name_1:
10675 xpath_allocator_capture cr(stack.result);
10677 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10678 xpath_node na = ns.first();
10680 return xpath_string::from_const(local_name(na));
10683 case ast_func_name_0:
10685 xpath_node na = c.n;
10687 return xpath_string::from_const(qualified_name(na));
10690 case ast_func_name_1:
10692 xpath_allocator_capture cr(stack.result);
10694 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10695 xpath_node na = ns.first();
10697 return xpath_string::from_const(qualified_name(na));
10700 case ast_func_namespace_uri_0:
10702 xpath_node na = c.n;
10704 return xpath_string::from_const(namespace_uri(na));
10707 case ast_func_namespace_uri_1:
10709 xpath_allocator_capture cr(stack.result);
10711 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10712 xpath_node na = ns.first();
10714 return xpath_string::from_const(namespace_uri(na));
10717 case ast_func_string_0:
10718 return string_value(c.n, stack.result);
10720 case ast_func_string_1:
10721 return _left->eval_string(c, stack);
10723 case ast_func_concat:
10724 return eval_string_concat(c, stack);
10726 case ast_func_substring_before:
10728 xpath_allocator_capture cr(stack.temp);
10730 xpath_stack swapped_stack = {stack.temp, stack.result};
10732 xpath_string s = _left->eval_string(c, swapped_stack);
10733 xpath_string p = _right->eval_string(c, swapped_stack);
10735 const char_t* pos = find_substring(s.c_str(), p.c_str());
10737 return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string();
10740 case ast_func_substring_after:
10742 xpath_allocator_capture cr(stack.temp);
10744 xpath_stack swapped_stack = {stack.temp, stack.result};
10746 xpath_string s = _left->eval_string(c, swapped_stack);
10747 xpath_string p = _right->eval_string(c, swapped_stack);
10749 const char_t* pos = find_substring(s.c_str(), p.c_str());
10750 if (!pos)
return xpath_string();
10752 const char_t* rbegin = pos + p.length();
10753 const char_t* rend = s.c_str() + s.length();
10755 return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
10758 case ast_func_substring_2:
10760 xpath_allocator_capture cr(stack.temp);
10762 xpath_stack swapped_stack = {stack.temp, stack.result};
10764 xpath_string s = _left->eval_string(c, swapped_stack);
10765 size_t s_length = s.length();
10767 double first = round_nearest(_right->eval_number(c, stack));
10769 if (is_nan(first))
return xpath_string();
10770 else if (first >=
static_cast<double>(s_length + 1))
return xpath_string();
10772 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
10773 assert(1 <= pos && pos <= s_length + 1);
10775 const char_t* rbegin = s.c_str() + (pos - 1);
10776 const char_t* rend = s.c_str() + s.length();
10778 return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
10781 case ast_func_substring_3:
10783 xpath_allocator_capture cr(stack.temp);
10785 xpath_stack swapped_stack = {stack.temp, stack.result};
10787 xpath_string s = _left->eval_string(c, swapped_stack);
10788 size_t s_length = s.length();
10790 double first = round_nearest(_right->eval_number(c, stack));
10791 double last = first + round_nearest(_right->_next->eval_number(c, stack));
10793 if (is_nan(first) || is_nan(last))
return xpath_string();
10794 else if (first >=
static_cast<double>(s_length + 1))
return xpath_string();
10795 else if (first >= last)
return xpath_string();
10796 else if (last < 1)
return xpath_string();
10798 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
10799 size_t end = last >=
static_cast<double>(s_length + 1) ? s_length + 1 : static_cast<size_t>(last);
10801 assert(1 <= pos && pos <= end && end <= s_length + 1);
10802 const char_t* rbegin = s.c_str() + (pos - 1);
10803 const char_t* rend = s.c_str() + (end - 1);
10805 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result);
10808 case ast_func_normalize_space_0:
10810 xpath_string s = string_value(c.n, stack.result);
10812 char_t* begin = s.data(stack.result);
10813 if (!begin)
return xpath_string();
10815 char_t* end = normalize_space(begin);
10817 return xpath_string::from_heap_preallocated(begin, end);
10820 case ast_func_normalize_space_1:
10822 xpath_string s = _left->eval_string(c, stack);
10824 char_t* begin = s.data(stack.result);
10825 if (!begin)
return xpath_string();
10827 char_t* end = normalize_space(begin);
10829 return xpath_string::from_heap_preallocated(begin, end);
10832 case ast_func_translate:
10834 xpath_allocator_capture cr(stack.temp);
10836 xpath_stack swapped_stack = {stack.temp, stack.result};
10838 xpath_string s = _left->eval_string(c, stack);
10839 xpath_string from = _right->eval_string(c, swapped_stack);
10840 xpath_string to = _right->_next->eval_string(c, swapped_stack);
10842 char_t* begin = s.data(stack.result);
10843 if (!begin)
return xpath_string();
10845 char_t* end = translate(begin, from.c_str(), to.c_str(), to.length());
10847 return xpath_string::from_heap_preallocated(begin, end);
10850 case ast_opt_translate_table:
10852 xpath_string s = _left->eval_string(c, stack);
10854 char_t* begin = s.data(stack.result);
10855 if (!begin)
return xpath_string();
10857 char_t* end = translate_table(begin, _data.table);
10859 return xpath_string::from_heap_preallocated(begin, end);
10864 assert(_rettype == _data.variable->type());
10866 if (_rettype == xpath_type_string)
10867 return xpath_string::from_const(_data.variable->get_string());
10880 case xpath_type_boolean:
10881 return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT(
"true") : PUGIXML_TEXT(
"false"));
10883 case xpath_type_number:
10884 return convert_number_to_string(eval_number(c, stack), stack.result);
10886 case xpath_type_node_set:
10888 xpath_allocator_capture cr(stack.temp);
10890 xpath_stack swapped_stack = {stack.temp, stack.result};
10892 xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first);
10893 return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
10897 assert(
false &&
"Wrong expression for return type string");
10898 return xpath_string();
10902 xpath_node_set_raw eval_node_set(
const xpath_context& c,
const xpath_stack& stack, nodeset_eval_t eval)
10908 xpath_allocator_capture cr(stack.temp);
10910 xpath_stack swapped_stack = {stack.temp, stack.result};
10912 xpath_node_set_raw ls = _left->eval_node_set(c, stack, eval);
10913 xpath_node_set_raw rs = _right->eval_node_set(c, swapped_stack, eval);
10916 ls.set_type(xpath_node_set::type_unsorted);
10918 ls.append(rs.begin(), rs.end(), stack.result);
10919 ls.remove_duplicates(stack.temp);
10926 xpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all);
10929 if (_test != predicate_posinv) set.sort_do();
10931 bool once = eval_once(set.type(), eval);
10933 apply_predicate(set, 0, stack, once);
10939 return xpath_node_set_raw();
10945 case axis_ancestor:
10946 return step_do(c, stack, eval, axis_to_type<axis_ancestor>());
10948 case axis_ancestor_or_self:
10949 return step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>());
10951 case axis_attribute:
10952 return step_do(c, stack, eval, axis_to_type<axis_attribute>());
10955 return step_do(c, stack, eval, axis_to_type<axis_child>());
10957 case axis_descendant:
10958 return step_do(c, stack, eval, axis_to_type<axis_descendant>());
10960 case axis_descendant_or_self:
10961 return step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>());
10963 case axis_following:
10964 return step_do(c, stack, eval, axis_to_type<axis_following>());
10966 case axis_following_sibling:
10967 return step_do(c, stack, eval, axis_to_type<axis_following_sibling>());
10969 case axis_namespace:
10971 return xpath_node_set_raw();
10974 return step_do(c, stack, eval, axis_to_type<axis_parent>());
10976 case axis_preceding:
10977 return step_do(c, stack, eval, axis_to_type<axis_preceding>());
10979 case axis_preceding_sibling:
10980 return step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>());
10983 return step_do(c, stack, eval, axis_to_type<axis_self>());
10986 assert(
false &&
"Unknown axis");
10987 return xpath_node_set_raw();
10991 case ast_step_root:
10995 xpath_node_set_raw ns;
10997 ns.set_type(xpath_node_set::type_sorted);
10999 if (c.n.node()) ns.push_back(c.n.node().root(), stack.result);
11000 else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);
11007 assert(_rettype == _data.variable->type());
11009 if (_rettype == xpath_type_node_set)
11011 const xpath_node_set& s = _data.variable->get_node_set();
11013 xpath_node_set_raw ns;
11015 ns.set_type(s.type());
11016 ns.append(s.begin(), s.end(), stack.result);
11030 assert(
false &&
"Wrong expression for return type node set");
11031 return xpath_node_set_raw();
11034 void optimize(xpath_allocator* alloc)
11037 _left->optimize(alloc);
11040 _right->optimize(alloc);
11043 _next->optimize(alloc);
11046 optimize_self(alloc);
11049 void optimize_self(xpath_allocator* alloc)
11053 if ((_type == ast_filter || _type == ast_predicate) &&
11055 _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number)
11057 _right = _right->_right;
11061 if ((_type == ast_filter || _type == ast_predicate) && _right)
11063 assert(_test == predicate_default);
11065 if (_right->_type == ast_number_constant && _right->_data.number == 1.0)
11066 _test = predicate_constant_one;
11067 else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last))
11068 _test = predicate_constant;
11069 else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr())
11070 _test = predicate_posinv;
11077 if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) &&
11078 _left && _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right &&
11081 if (_axis == axis_child || _axis == axis_descendant)
11082 _axis = axis_descendant;
11084 _axis = axis_descendant_or_self;
11086 _left = _left->_left;
11090 if (_type == ast_func_translate &&
11092 _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant)
11094 unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string);
11098 _type = ast_opt_translate_table;
11099 _data.table = table;
11104 if (_type == ast_op_equal &&
11107 _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right &&
11108 (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string)))
11110 _type = ast_opt_compare_attribute;
11114 bool is_posinv_expr()
const
11118 case ast_func_position:
11119 case ast_func_last:
11122 case ast_string_constant:
11123 case ast_number_constant:
11128 case ast_step_root:
11131 case ast_predicate:
11136 if (_left && !_left->is_posinv_expr())
return false;
11138 for (xpath_ast_node* n = _right; n; n = n->_next)
11139 if (!n->is_posinv_expr())
return false;
11145 bool is_posinv_step()
const
11147 assert(_type == ast_step);
11149 for (xpath_ast_node* n = _right; n; n = n->_next)
11151 assert(n->_type == ast_predicate);
11153 if (n->_test != predicate_posinv)
11160 xpath_value_type rettype()
const
11162 return static_cast<xpath_value_type
>(_rettype);
11166 static const size_t xpath_ast_depth_limit =
11167 #ifdef PUGIXML_XPATH_DEPTH_LIMIT
11168 PUGIXML_XPATH_DEPTH_LIMIT
11174 struct xpath_parser
11176 xpath_allocator* _alloc;
11177 xpath_lexer _lexer;
11179 const char_t* _query;
11180 xpath_variable_set* _variables;
11182 xpath_parse_result* _result;
11184 char_t _scratch[32];
11188 xpath_ast_node* error(
const char* message)
11190 _result->error = message;
11191 _result->offset = _lexer.current_pos() - _query;
11196 xpath_ast_node* error_oom()
11198 assert(_alloc->_error);
11199 *_alloc->_error =
true;
11204 xpath_ast_node* error_rec()
11206 return error(
"Exceeded maximum allowed query depth");
11211 return _alloc->allocate(
sizeof(xpath_ast_node));
11214 xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype,
const char_t* value)
11216 void* memory = alloc_node();
11217 return memory ?
new (memory) xpath_ast_node(type, rettype, value) : 0;
11220 xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype,
double value)
11222 void* memory = alloc_node();
11223 return memory ?
new (memory) xpath_ast_node(type, rettype, value) : 0;
11226 xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value)
11228 void* memory = alloc_node();
11229 return memory ?
new (memory) xpath_ast_node(type, rettype, value) : 0;
11232 xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0)
11234 void* memory = alloc_node();
11235 return memory ?
new (memory) xpath_ast_node(type, rettype, left, right) : 0;
11238 xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test,
const char_t* contents)
11240 void* memory = alloc_node();
11241 return memory ?
new (memory) xpath_ast_node(type, left, axis, test, contents) : 0;
11244 xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test)
11246 void* memory = alloc_node();
11247 return memory ?
new (memory) xpath_ast_node(type, left, right, test) : 0;
11250 const char_t* alloc_string(
const xpath_lexer_string& value)
11253 return PUGIXML_TEXT(
"");
11255 size_t length =
static_cast<size_t>(value.end - value.begin);
11257 char_t* c =
static_cast<char_t*
>(_alloc->allocate((length + 1) *
sizeof(char_t)));
11260 memcpy(c, value.begin, length *
sizeof(char_t));
11266 xpath_ast_node* parse_function(
const xpath_lexer_string& name,
size_t argc, xpath_ast_node* args[2])
11268 switch (name.begin[0])
11271 if (name == PUGIXML_TEXT(
"boolean") && argc == 1)
11272 return alloc_node(ast_func_boolean, xpath_type_boolean, args[0]);
11277 if (name == PUGIXML_TEXT(
"count") && argc == 1)
11279 if (args[0]->rettype() != xpath_type_node_set)
return error(
"Function has to be applied to node set");
11280 return alloc_node(ast_func_count, xpath_type_number, args[0]);
11282 else if (name == PUGIXML_TEXT(
"contains") && argc == 2)
11283 return alloc_node(ast_func_contains, xpath_type_boolean, args[0], args[1]);
11284 else if (name == PUGIXML_TEXT(
"concat") && argc >= 2)
11285 return alloc_node(ast_func_concat, xpath_type_string, args[0], args[1]);
11286 else if (name == PUGIXML_TEXT(
"ceiling") && argc == 1)
11287 return alloc_node(ast_func_ceiling, xpath_type_number, args[0]);
11292 if (name == PUGIXML_TEXT(
"false") && argc == 0)
11293 return alloc_node(ast_func_false, xpath_type_boolean);
11294 else if (name == PUGIXML_TEXT(
"floor") && argc == 1)
11295 return alloc_node(ast_func_floor, xpath_type_number, args[0]);
11300 if (name == PUGIXML_TEXT(
"id") && argc == 1)
11301 return alloc_node(ast_func_id, xpath_type_node_set, args[0]);
11306 if (name == PUGIXML_TEXT(
"last") && argc == 0)
11307 return alloc_node(ast_func_last, xpath_type_number);
11308 else if (name == PUGIXML_TEXT(
"lang") && argc == 1)
11309 return alloc_node(ast_func_lang, xpath_type_boolean, args[0]);
11310 else if (name == PUGIXML_TEXT(
"local-name") && argc <= 1)
11312 if (argc == 1 && args[0]->rettype() != xpath_type_node_set)
return error(
"Function has to be applied to node set");
11313 return alloc_node(argc == 0 ? ast_func_local_name_0 : ast_func_local_name_1, xpath_type_string, args[0]);
11319 if (name == PUGIXML_TEXT(
"name") && argc <= 1)
11321 if (argc == 1 && args[0]->rettype() != xpath_type_node_set)
return error(
"Function has to be applied to node set");
11322 return alloc_node(argc == 0 ? ast_func_name_0 : ast_func_name_1, xpath_type_string, args[0]);
11324 else if (name == PUGIXML_TEXT(
"namespace-uri") && argc <= 1)
11326 if (argc == 1 && args[0]->rettype() != xpath_type_node_set)
return error(
"Function has to be applied to node set");
11327 return alloc_node(argc == 0 ? ast_func_namespace_uri_0 : ast_func_namespace_uri_1, xpath_type_string, args[0]);
11329 else if (name == PUGIXML_TEXT(
"normalize-space") && argc <= 1)
11330 return alloc_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);
11331 else if (name == PUGIXML_TEXT(
"not") && argc == 1)
11332 return alloc_node(ast_func_not, xpath_type_boolean, args[0]);
11333 else if (name == PUGIXML_TEXT(
"number") && argc <= 1)
11334 return alloc_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
11339 if (name == PUGIXML_TEXT(
"position") && argc == 0)
11340 return alloc_node(ast_func_position, xpath_type_number);
11345 if (name == PUGIXML_TEXT(
"round") && argc == 1)
11346 return alloc_node(ast_func_round, xpath_type_number, args[0]);
11351 if (name == PUGIXML_TEXT(
"string") && argc <= 1)
11352 return alloc_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
11353 else if (name == PUGIXML_TEXT(
"string-length") && argc <= 1)
11354 return alloc_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]);
11355 else if (name == PUGIXML_TEXT(
"starts-with") && argc == 2)
11356 return alloc_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
11357 else if (name == PUGIXML_TEXT(
"substring-before") && argc == 2)
11358 return alloc_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
11359 else if (name == PUGIXML_TEXT(
"substring-after") && argc == 2)
11360 return alloc_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
11361 else if (name == PUGIXML_TEXT(
"substring") && (argc == 2 || argc == 3))
11362 return alloc_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
11363 else if (name == PUGIXML_TEXT(
"sum") && argc == 1)
11365 if (args[0]->rettype() != xpath_type_node_set)
return error(
"Function has to be applied to node set");
11366 return alloc_node(ast_func_sum, xpath_type_number, args[0]);
11372 if (name == PUGIXML_TEXT(
"translate") && argc == 3)
11373 return alloc_node(ast_func_translate, xpath_type_string, args[0], args[1]);
11374 else if (name == PUGIXML_TEXT(
"true") && argc == 0)
11375 return alloc_node(ast_func_true, xpath_type_boolean);
11383 return error(
"Unrecognized function or wrong parameter count");
11386 axis_t parse_axis_name(
const xpath_lexer_string& name,
bool& specified)
11390 switch (name.begin[0])
11393 if (name == PUGIXML_TEXT(
"ancestor"))
11394 return axis_ancestor;
11395 else if (name == PUGIXML_TEXT(
"ancestor-or-self"))
11396 return axis_ancestor_or_self;
11397 else if (name == PUGIXML_TEXT(
"attribute"))
11398 return axis_attribute;
11403 if (name == PUGIXML_TEXT(
"child"))
11409 if (name == PUGIXML_TEXT(
"descendant"))
11410 return axis_descendant;
11411 else if (name == PUGIXML_TEXT(
"descendant-or-self"))
11412 return axis_descendant_or_self;
11417 if (name == PUGIXML_TEXT(
"following"))
11418 return axis_following;
11419 else if (name == PUGIXML_TEXT(
"following-sibling"))
11420 return axis_following_sibling;
11425 if (name == PUGIXML_TEXT(
"namespace"))
11426 return axis_namespace;
11431 if (name == PUGIXML_TEXT(
"parent"))
11432 return axis_parent;
11433 else if (name == PUGIXML_TEXT(
"preceding"))
11434 return axis_preceding;
11435 else if (name == PUGIXML_TEXT(
"preceding-sibling"))
11436 return axis_preceding_sibling;
11441 if (name == PUGIXML_TEXT(
"self"))
11454 nodetest_t parse_node_test_type(
const xpath_lexer_string& name)
11456 switch (name.begin[0])
11459 if (name == PUGIXML_TEXT(
"comment"))
11460 return nodetest_type_comment;
11465 if (name == PUGIXML_TEXT(
"node"))
11466 return nodetest_type_node;
11471 if (name == PUGIXML_TEXT(
"processing-instruction"))
11472 return nodetest_type_pi;
11477 if (name == PUGIXML_TEXT(
"text"))
11478 return nodetest_type_text;
11486 return nodetest_none;
11490 xpath_ast_node* parse_primary_expression()
11492 switch (_lexer.current())
11496 xpath_lexer_string name = _lexer.contents();
11499 return error(
"Unknown variable: variable set is not provided");
11501 xpath_variable* var = 0;
11502 if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var))
11503 return error_oom();
11506 return error(
"Unknown variable: variable set does not contain the given name");
11510 return alloc_node(ast_variable, var->type(), var);
11513 case lex_open_brace:
11517 xpath_ast_node* n = parse_expression();
11520 if (_lexer.current() != lex_close_brace)
11521 return error(
"Expected ')' to match an opening '('");
11528 case lex_quoted_string:
11530 const char_t* value = alloc_string(_lexer.contents());
11531 if (!value)
return 0;
11535 return alloc_node(ast_string_constant, xpath_type_string, value);
11542 if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value))
11543 return error_oom();
11547 return alloc_node(ast_number_constant, xpath_type_number, value);
11552 xpath_ast_node* args[2] = {0};
11555 xpath_lexer_string function = _lexer.contents();
11558 xpath_ast_node* last_arg = 0;
11560 if (_lexer.current() != lex_open_brace)
11561 return error(
"Unrecognized function call");
11564 size_t old_depth = _depth;
11566 while (_lexer.current() != lex_close_brace)
11570 if (_lexer.current() != lex_comma)
11571 return error(
"No comma between function arguments");
11575 if (++_depth > xpath_ast_depth_limit)
11576 return error_rec();
11578 xpath_ast_node* n = parse_expression();
11581 if (argc < 2) args[argc] = n;
11582 else last_arg->set_next(n);
11590 _depth = old_depth;
11592 return parse_function(function, argc, args);
11596 return error(
"Unrecognizable primary expression");
11603 xpath_ast_node* parse_filter_expression()
11605 xpath_ast_node* n = parse_primary_expression();
11608 size_t old_depth = _depth;
11610 while (_lexer.current() == lex_open_square_brace)
11614 if (++_depth > xpath_ast_depth_limit)
11615 return error_rec();
11617 if (n->rettype() != xpath_type_node_set)
11618 return error(
"Predicate has to be applied to node set");
11620 xpath_ast_node* expr = parse_expression();
11621 if (!expr)
return 0;
11623 n = alloc_node(ast_filter, n, expr, predicate_default);
11626 if (_lexer.current() != lex_close_square_brace)
11627 return error(
"Expected ']' to match an opening '['");
11632 _depth = old_depth;
11642 xpath_ast_node* parse_step(xpath_ast_node* set)
11644 if (set && set->rettype() != xpath_type_node_set)
11645 return error(
"Step has to be applied to node set");
11647 bool axis_specified =
false;
11648 axis_t axis = axis_child;
11650 if (_lexer.current() == lex_axis_attribute)
11652 axis = axis_attribute;
11653 axis_specified =
true;
11657 else if (_lexer.current() == lex_dot)
11661 if (_lexer.current() == lex_open_square_brace)
11662 return error(
"Predicates are not allowed after an abbreviated step");
11664 return alloc_node(ast_step, set, axis_self, nodetest_type_node, 0);
11666 else if (_lexer.current() == lex_double_dot)
11670 if (_lexer.current() == lex_open_square_brace)
11671 return error(
"Predicates are not allowed after an abbreviated step");
11673 return alloc_node(ast_step, set, axis_parent, nodetest_type_node, 0);
11676 nodetest_t nt_type = nodetest_none;
11677 xpath_lexer_string nt_name;
11679 if (_lexer.current() == lex_string)
11682 nt_name = _lexer.contents();
11686 if (_lexer.current() == lex_double_colon)
11689 if (axis_specified)
11690 return error(
"Two axis specifiers in one step");
11692 axis = parse_axis_name(nt_name, axis_specified);
11694 if (!axis_specified)
11695 return error(
"Unknown axis");
11700 if (_lexer.current() == lex_multiply)
11702 nt_type = nodetest_all;
11703 nt_name = xpath_lexer_string();
11706 else if (_lexer.current() == lex_string)
11708 nt_name = _lexer.contents();
11713 return error(
"Unrecognized node test");
11717 if (nt_type == nodetest_none)
11720 if (_lexer.current() == lex_open_brace)
11724 if (_lexer.current() == lex_close_brace)
11728 nt_type = parse_node_test_type(nt_name);
11730 if (nt_type == nodetest_none)
11731 return error(
"Unrecognized node type");
11733 nt_name = xpath_lexer_string();
11735 else if (nt_name == PUGIXML_TEXT(
"processing-instruction"))
11737 if (_lexer.current() != lex_quoted_string)
11738 return error(
"Only literals are allowed as arguments to processing-instruction()");
11740 nt_type = nodetest_pi;
11741 nt_name = _lexer.contents();
11744 if (_lexer.current() != lex_close_brace)
11745 return error(
"Unmatched brace near processing-instruction()");
11750 return error(
"Unmatched brace near node type test");
11756 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] ==
':' && nt_name.end[-1] ==
'*')
11760 nt_type = nodetest_all_in_namespace;
11764 nt_type = nodetest_name;
11769 else if (_lexer.current() == lex_multiply)
11771 nt_type = nodetest_all;
11776 return error(
"Unrecognized node test");
11779 const char_t* nt_name_copy = alloc_string(nt_name);
11780 if (!nt_name_copy)
return 0;
11782 xpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy);
11785 size_t old_depth = _depth;
11787 xpath_ast_node* last = 0;
11789 while (_lexer.current() == lex_open_square_brace)
11793 if (++_depth > xpath_ast_depth_limit)
11794 return error_rec();
11796 xpath_ast_node* expr = parse_expression();
11797 if (!expr)
return 0;
11799 xpath_ast_node* pred = alloc_node(ast_predicate, 0, expr, predicate_default);
11800 if (!pred)
return 0;
11802 if (_lexer.current() != lex_close_square_brace)
11803 return error(
"Expected ']' to match an opening '['");
11806 if (last) last->set_next(pred);
11807 else n->set_right(pred);
11812 _depth = old_depth;
11818 xpath_ast_node* parse_relative_location_path(xpath_ast_node* set)
11820 xpath_ast_node* n = parse_step(set);
11823 size_t old_depth = _depth;
11825 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
11827 lexeme_t l = _lexer.current();
11830 if (l == lex_double_slash)
11832 n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
11838 if (++_depth > xpath_ast_depth_limit)
11839 return error_rec();
11845 _depth = old_depth;
11852 xpath_ast_node* parse_location_path()
11854 if (_lexer.current() == lex_slash)
11858 xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set);
11862 lexeme_t l = _lexer.current();
11864 if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
11865 return parse_relative_location_path(n);
11869 else if (_lexer.current() == lex_double_slash)
11873 xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set);
11876 n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
11879 return parse_relative_location_path(n);
11883 return parse_relative_location_path(0);
11892 xpath_ast_node* parse_path_or_unary_expression()
11900 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
11901 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
11902 _lexer.current() == lex_string)
11904 if (_lexer.current() == lex_string)
11907 const char_t* state = _lexer.state();
11909 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
11912 return parse_location_path();
11915 if (parse_node_test_type(_lexer.contents()) != nodetest_none)
11916 return parse_location_path();
11919 xpath_ast_node* n = parse_filter_expression();
11922 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
11924 lexeme_t l = _lexer.current();
11927 if (l == lex_double_slash)
11929 if (n->rettype() != xpath_type_node_set)
11930 return error(
"Step has to be applied to node set");
11932 n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
11937 return parse_relative_location_path(n);
11942 else if (_lexer.current() == lex_minus)
11947 xpath_ast_node* n = parse_expression(7);
11950 return alloc_node(ast_op_negate, xpath_type_number, n);
11954 return parse_location_path();
11960 ast_type_t asttype;
11961 xpath_value_type rettype;
11964 binary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0)
11968 binary_op_t(ast_type_t asttype_, xpath_value_type rettype_,
int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_)
11972 static binary_op_t parse(xpath_lexer& lexer)
11974 switch (lexer.current())
11977 if (lexer.contents() == PUGIXML_TEXT(
"or"))
11978 return binary_op_t(ast_op_or, xpath_type_boolean, 1);
11979 else if (lexer.contents() == PUGIXML_TEXT(
"and"))
11980 return binary_op_t(ast_op_and, xpath_type_boolean, 2);
11981 else if (lexer.contents() == PUGIXML_TEXT(
"div"))
11982 return binary_op_t(ast_op_divide, xpath_type_number, 6);
11983 else if (lexer.contents() == PUGIXML_TEXT(
"mod"))
11984 return binary_op_t(ast_op_mod, xpath_type_number, 6);
11986 return binary_op_t();
11989 return binary_op_t(ast_op_equal, xpath_type_boolean, 3);
11991 case lex_not_equal:
11992 return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3);
11995 return binary_op_t(ast_op_less, xpath_type_boolean, 4);
11998 return binary_op_t(ast_op_greater, xpath_type_boolean, 4);
12000 case lex_less_or_equal:
12001 return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4);
12003 case lex_greater_or_equal:
12004 return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4);
12007 return binary_op_t(ast_op_add, xpath_type_number, 5);
12010 return binary_op_t(ast_op_subtract, xpath_type_number, 5);
12013 return binary_op_t(ast_op_multiply, xpath_type_number, 6);
12016 return binary_op_t(ast_op_union, xpath_type_node_set, 7);
12019 return binary_op_t();
12024 xpath_ast_node* parse_expression_rec(xpath_ast_node* lhs,
int limit)
12026 binary_op_t op = binary_op_t::parse(_lexer);
12028 while (op.asttype != ast_unknown && op.precedence >= limit)
12032 if (++_depth > xpath_ast_depth_limit)
12033 return error_rec();
12035 xpath_ast_node* rhs = parse_path_or_unary_expression();
12036 if (!rhs)
return 0;
12038 binary_op_t nextop = binary_op_t::parse(_lexer);
12040 while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)
12042 rhs = parse_expression_rec(rhs, nextop.precedence);
12043 if (!rhs)
return 0;
12045 nextop = binary_op_t::parse(_lexer);
12048 if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))
12049 return error(
"Union operator has to be applied to node sets");
12051 lhs = alloc_node(op.asttype, op.rettype, lhs, rhs);
12052 if (!lhs)
return 0;
12054 op = binary_op_t::parse(_lexer);
12078 xpath_ast_node* parse_expression(
int limit = 0)
12080 size_t old_depth = _depth;
12082 if (++_depth > xpath_ast_depth_limit)
12083 return error_rec();
12085 xpath_ast_node* n = parse_path_or_unary_expression();
12088 n = parse_expression_rec(n, limit);
12090 _depth = old_depth;
12095 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), _depth(0)
12099 xpath_ast_node* parse()
12101 xpath_ast_node* n = parse_expression();
12104 assert(_depth == 0);
12107 if (_lexer.current() != lex_eof)
12108 return error(
"Incorrect query");
12113 static xpath_ast_node* parse(
const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)
12115 xpath_parser parser(query, variables, alloc, result);
12117 return parser.parse();
12121 struct xpath_query_impl
12123 static xpath_query_impl* create()
12125 void* memory = xml_memory::allocate(
sizeof(xpath_query_impl));
12126 if (!memory)
return 0;
12128 return new (memory) xpath_query_impl();
12131 static void destroy(xpath_query_impl* impl)
12134 impl->alloc.release();
12137 xml_memory::deallocate(impl);
12140 xpath_query_impl(): root(0), alloc(&block, &oom), oom(false)
12143 block.capacity =
sizeof(block.data);
12146 xpath_ast_node* root;
12147 xpath_allocator alloc;
12148 xpath_memory_block block;
12152 PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)
12154 if (!impl)
return 0;
12156 if (impl->root->rettype() != xpath_type_node_set)
12158 #ifdef PUGIXML_NO_EXCEPTIONS
12161 xpath_parse_result res;
12162 res.error =
"Expression does not evaluate to node set";
12164 throw xpath_exception(res);
12174#ifndef PUGIXML_NO_EXCEPTIONS
12175 PUGI__FN xpath_exception::xpath_exception(
const xpath_parse_result& result_): _result(result_)
12177 assert(_result.error);
12180 PUGI__FN
const char* xpath_exception::what()
const throw()
12182 return _result.error;
12185 PUGI__FN
const xpath_parse_result& xpath_exception::result()
const
12191 PUGI__FN xpath_node::xpath_node()
12195 PUGI__FN xpath_node::xpath_node(
const xml_node& node_): _node(node_)
12199 PUGI__FN xpath_node::xpath_node(
const xml_attribute& attribute_,
const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
12203 PUGI__FN xml_node xpath_node::node()
const
12205 return _attribute ? xml_node() : _node;
12208 PUGI__FN xml_attribute xpath_node::attribute()
const
12213 PUGI__FN xml_node xpath_node::parent()
const
12215 return _attribute ? _node : _node.parent();
12218 PUGI__FN
static void unspecified_bool_xpath_node(xpath_node***)
12222 PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type()
const
12224 return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
12227 PUGI__FN
bool xpath_node::operator!()
const
12229 return !(_node || _attribute);
12232 PUGI__FN
bool xpath_node::operator==(
const xpath_node& n)
const
12234 return _node == n._node && _attribute == n._attribute;
12237 PUGI__FN
bool xpath_node::operator!=(
const xpath_node& n)
const
12239 return _node != n._node || _attribute != n._attribute;
12243 PUGI__FN
bool operator&&(
const xpath_node& lhs,
bool rhs)
12245 return (
bool)lhs && rhs;
12248 PUGI__FN
bool operator||(
const xpath_node& lhs,
bool rhs)
12250 return (
bool)lhs || rhs;
12254 PUGI__FN
void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)
12256 assert(begin_ <= end_);
12258 size_t size_ =
static_cast<size_t>(end_ - begin_);
12261 xpath_node* storage = (size_ <= 1) ? _storage : static_cast<xpath_node*>(impl::xml_memory::allocate(size_ *
sizeof(xpath_node)));
12265 #ifdef PUGIXML_NO_EXCEPTIONS
12268 throw std::bad_alloc();
12273 if (_begin != _storage)
12274 impl::xml_memory::deallocate(_begin);
12278 memcpy(storage, begin_, size_ *
sizeof(xpath_node));
12281 _end = storage + size_;
12285#ifdef PUGIXML_HAS_MOVE
12286 PUGI__FN
void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT
12289 _storage[0] = rhs._storage[0];
12290 _begin = (rhs._begin == rhs._storage) ? _storage : rhs._begin;
12291 _end = _begin + (rhs._end - rhs._begin);
12293 rhs._type = type_unsorted;
12294 rhs._begin = rhs._storage;
12295 rhs._end = rhs._storage;
12299 PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage)
12303 PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage)
12305 _assign(begin_, end_, type_);
12308 PUGI__FN xpath_node_set::~xpath_node_set()
12310 if (_begin != _storage)
12311 impl::xml_memory::deallocate(_begin);
12314 PUGI__FN xpath_node_set::xpath_node_set(
const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage)
12316 _assign(ns._begin, ns._end, ns._type);
12319 PUGI__FN xpath_node_set& xpath_node_set::operator=(
const xpath_node_set& ns)
12321 if (
this == &ns)
return *
this;
12323 _assign(ns._begin, ns._end, ns._type);
12328#ifdef PUGIXML_HAS_MOVE
12329 PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage)
12334 PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT
12336 if (
this == &rhs)
return *
this;
12338 if (_begin != _storage)
12339 impl::xml_memory::deallocate(_begin);
12347 PUGI__FN xpath_node_set::type_t xpath_node_set::type()
const
12352 PUGI__FN
size_t xpath_node_set::size()
const
12354 return _end - _begin;
12357 PUGI__FN
bool xpath_node_set::empty()
const
12359 return _begin == _end;
12362 PUGI__FN
const xpath_node& xpath_node_set::operator[](
size_t index)
const
12364 assert(index < size());
12365 return _begin[index];
12368 PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin()
const
12373 PUGI__FN xpath_node_set::const_iterator xpath_node_set::end()
const
12378 PUGI__FN
void xpath_node_set::sort(
bool reverse)
12380 _type = impl::xpath_sort(_begin, _end, _type, reverse);
12383 PUGI__FN xpath_node xpath_node_set::first()
const
12385 return impl::xpath_first(_begin, _end, _type);
12388 PUGI__FN xpath_parse_result::xpath_parse_result(): error(
"Internal error"), offset(0)
12392 PUGI__FN xpath_parse_result::operator
bool()
const
12397 PUGI__FN
const char* xpath_parse_result::description()
const
12399 return error ? error :
"No error";
12402 PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0)
12406 PUGI__FN
const char_t* xpath_variable::name()
const
12410 case xpath_type_node_set:
12411 return static_cast<const impl::xpath_variable_node_set*
>(
this)->name;
12413 case xpath_type_number:
12414 return static_cast<const impl::xpath_variable_number*
>(
this)->name;
12416 case xpath_type_string:
12417 return static_cast<const impl::xpath_variable_string*
>(
this)->name;
12419 case xpath_type_boolean:
12420 return static_cast<const impl::xpath_variable_boolean*
>(
this)->name;
12423 assert(
false &&
"Invalid variable type");
12428 PUGI__FN xpath_value_type xpath_variable::type()
const
12433 PUGI__FN
bool xpath_variable::get_boolean()
const
12435 return (_type == xpath_type_boolean) ?
static_cast<const impl::xpath_variable_boolean*
>(
this)->value : false;
12438 PUGI__FN
double xpath_variable::get_number()
const
12440 return (_type == xpath_type_number) ?
static_cast<const impl::xpath_variable_number*
>(
this)->value : impl::gen_nan();
12443 PUGI__FN
const char_t* xpath_variable::get_string()
const
12445 const char_t* value = (_type == xpath_type_string) ?
static_cast<const impl::xpath_variable_string*
>(
this)->value : 0;
12446 return value ? value : PUGIXML_TEXT(
"");
12449 PUGI__FN
const xpath_node_set& xpath_variable::get_node_set()
const
12451 return (_type == xpath_type_node_set) ?
static_cast<const impl::xpath_variable_node_set*
>(
this)->value : impl::dummy_node_set;
12454 PUGI__FN
bool xpath_variable::set(
bool value)
12456 if (_type != xpath_type_boolean)
return false;
12458 static_cast<impl::xpath_variable_boolean*
>(
this)->value = value;
12462 PUGI__FN
bool xpath_variable::set(
double value)
12464 if (_type != xpath_type_number)
return false;
12466 static_cast<impl::xpath_variable_number*
>(
this)->value = value;
12470 PUGI__FN
bool xpath_variable::set(
const char_t* value)
12472 if (_type != xpath_type_string)
return false;
12474 impl::xpath_variable_string* var =
static_cast<impl::xpath_variable_string*
>(
this);
12477 size_t size = (impl::strlength(value) + 1) *
sizeof(char_t);
12479 char_t* copy =
static_cast<char_t*
>(impl::xml_memory::allocate(size));
12480 if (!copy)
return false;
12482 memcpy(copy, value, size);
12485 if (var->value) impl::xml_memory::deallocate(var->value);
12491 PUGI__FN
bool xpath_variable::set(
const xpath_node_set& value)
12493 if (_type != xpath_type_node_set)
return false;
12495 static_cast<impl::xpath_variable_node_set*
>(
this)->value = value;
12499 PUGI__FN xpath_variable_set::xpath_variable_set()
12501 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
12505 PUGI__FN xpath_variable_set::~xpath_variable_set()
12507 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
12508 _destroy(_data[i]);
12511 PUGI__FN xpath_variable_set::xpath_variable_set(
const xpath_variable_set& rhs)
12513 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
12519 PUGI__FN xpath_variable_set& xpath_variable_set::operator=(
const xpath_variable_set& rhs)
12521 if (
this == &rhs)
return *
this;
12528#ifdef PUGIXML_HAS_MOVE
12529 PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT
12531 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
12533 _data[i] = rhs._data[i];
12538 PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT
12540 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
12542 _destroy(_data[i]);
12544 _data[i] = rhs._data[i];
12552 PUGI__FN
void xpath_variable_set::_assign(
const xpath_variable_set& rhs)
12554 xpath_variable_set temp;
12556 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
12557 if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))
12563 PUGI__FN
void xpath_variable_set::_swap(xpath_variable_set& rhs)
12565 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
12567 xpath_variable* chain = _data[i];
12569 _data[i] = rhs._data[i];
12570 rhs._data[i] = chain;
12574 PUGI__FN xpath_variable* xpath_variable_set::_find(
const char_t* name)
const
12576 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
12577 size_t hash = impl::hash_string(name) % hash_size;
12580 for (xpath_variable* var = _data[hash]; var; var = var->_next)
12581 if (impl::strequal(var->name(), name))
12587 PUGI__FN
bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)
12589 xpath_variable* last = 0;
12594 xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
12595 if (!nvar)
return false;
12599 last->_next = nvar;
12601 *out_result = nvar;
12606 if (!impl::copy_xpath_variable(nvar, var))
return false;
12614 PUGI__FN
void xpath_variable_set::_destroy(xpath_variable* var)
12618 xpath_variable* next = var->_next;
12620 impl::delete_xpath_variable(var->_type, var);
12626 PUGI__FN xpath_variable* xpath_variable_set::add(
const char_t* name, xpath_value_type type)
12628 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
12629 size_t hash = impl::hash_string(name) % hash_size;
12632 for (xpath_variable* var = _data[hash]; var; var = var->_next)
12633 if (impl::strequal(var->name(), name))
12634 return var->type() == type ? var : 0;
12637 xpath_variable* result = impl::new_xpath_variable(type, name);
12641 result->_next = _data[hash];
12643 _data[hash] = result;
12649 PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
bool value)
12651 xpath_variable* var = add(name, xpath_type_boolean);
12652 return var ? var->set(value) :
false;
12655 PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
double value)
12657 xpath_variable* var = add(name, xpath_type_number);
12658 return var ? var->set(value) :
false;
12661 PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
const char_t* value)
12663 xpath_variable* var = add(name, xpath_type_string);
12664 return var ? var->set(value) :
false;
12667 PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
const xpath_node_set& value)
12669 xpath_variable* var = add(name, xpath_type_node_set);
12670 return var ? var->set(value) :
false;
12673 PUGI__FN xpath_variable* xpath_variable_set::get(
const char_t* name)
12675 return _find(name);
12678 PUGI__FN
const xpath_variable* xpath_variable_set::get(
const char_t* name)
const
12680 return _find(name);
12683 PUGI__FN xpath_query::xpath_query(
const char_t* query, xpath_variable_set* variables): _impl(0)
12685 impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
12689 #ifdef PUGIXML_NO_EXCEPTIONS
12690 _result.error =
"Out of memory";
12692 throw std::bad_alloc();
12697 using impl::auto_deleter;
12698 auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);
12700 qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
12704 qimpl->root->optimize(&qimpl->alloc);
12706 _impl = impl.release();
12711 #ifdef PUGIXML_NO_EXCEPTIONS
12712 if (qimpl->oom) _result.error =
"Out of memory";
12714 if (qimpl->oom)
throw std::bad_alloc();
12715 throw xpath_exception(_result);
12721 PUGI__FN xpath_query::xpath_query(): _impl(0)
12725 PUGI__FN xpath_query::~xpath_query()
12728 impl::xpath_query_impl::destroy(
static_cast<impl::xpath_query_impl*
>(_impl));
12731#ifdef PUGIXML_HAS_MOVE
12732 PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT
12735 _result = rhs._result;
12737 rhs._result = xpath_parse_result();
12740 PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT
12742 if (
this == &rhs)
return *
this;
12745 impl::xpath_query_impl::destroy(
static_cast<impl::xpath_query_impl*
>(_impl));
12748 _result = rhs._result;
12750 rhs._result = xpath_parse_result();
12756 PUGI__FN xpath_value_type xpath_query::return_type()
const
12758 if (!_impl)
return xpath_type_none;
12760 return static_cast<impl::xpath_query_impl*
>(_impl)->root->rettype();
12763 PUGI__FN
bool xpath_query::evaluate_boolean(
const xpath_node& n)
const
12765 if (!_impl)
return false;
12767 impl::xpath_context c(n, 1, 1);
12768 impl::xpath_stack_data sd;
12770 bool r =
static_cast<impl::xpath_query_impl*
>(_impl)->root->eval_boolean(c, sd.stack);
12774 #ifdef PUGIXML_NO_EXCEPTIONS
12777 throw std::bad_alloc();
12784 PUGI__FN
double xpath_query::evaluate_number(
const xpath_node& n)
const
12786 if (!_impl)
return impl::gen_nan();
12788 impl::xpath_context c(n, 1, 1);
12789 impl::xpath_stack_data sd;
12791 double r =
static_cast<impl::xpath_query_impl*
>(_impl)->root->eval_number(c, sd.stack);
12795 #ifdef PUGIXML_NO_EXCEPTIONS
12796 return impl::gen_nan();
12798 throw std::bad_alloc();
12805#ifndef PUGIXML_NO_STL
12806 PUGI__FN string_t xpath_query::evaluate_string(
const xpath_node& n)
const
12808 if (!_impl)
return string_t();
12810 impl::xpath_context c(n, 1, 1);
12811 impl::xpath_stack_data sd;
12813 impl::xpath_string r =
static_cast<impl::xpath_query_impl*
>(_impl)->root->eval_string(c, sd.stack);
12817 #ifdef PUGIXML_NO_EXCEPTIONS
12820 throw std::bad_alloc();
12824 return string_t(r.c_str(), r.length());
12828 PUGI__FN
size_t xpath_query::evaluate_string(char_t* buffer,
size_t capacity,
const xpath_node& n)
const
12830 impl::xpath_context c(n, 1, 1);
12831 impl::xpath_stack_data sd;
12833 impl::xpath_string r = _impl ?
static_cast<impl::xpath_query_impl*
>(_impl)->root->eval_string(c, sd.stack) : impl::xpath_string();
12837 #ifdef PUGIXML_NO_EXCEPTIONS
12838 r = impl::xpath_string();
12840 throw std::bad_alloc();
12844 size_t full_size = r.length() + 1;
12848 size_t size = (full_size < capacity) ? full_size : capacity;
12851 memcpy(buffer, r.c_str(), (size - 1) *
sizeof(char_t));
12852 buffer[size - 1] = 0;
12858 PUGI__FN xpath_node_set xpath_query::evaluate_node_set(
const xpath_node& n)
const
12860 impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(
static_cast<impl::xpath_query_impl*
>(_impl));
12861 if (!root)
return xpath_node_set();
12863 impl::xpath_context c(n, 1, 1);
12864 impl::xpath_stack_data sd;
12866 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
12870 #ifdef PUGIXML_NO_EXCEPTIONS
12871 return xpath_node_set();
12873 throw std::bad_alloc();
12877 return xpath_node_set(r.begin(), r.end(), r.type());
12880 PUGI__FN xpath_node xpath_query::evaluate_node(
const xpath_node& n)
const
12882 impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(
static_cast<impl::xpath_query_impl*
>(_impl));
12883 if (!root)
return xpath_node();
12885 impl::xpath_context c(n, 1, 1);
12886 impl::xpath_stack_data sd;
12888 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);
12892 #ifdef PUGIXML_NO_EXCEPTIONS
12893 return xpath_node();
12895 throw std::bad_alloc();
12902 PUGI__FN
const xpath_parse_result& xpath_query::result()
const
12907 PUGI__FN
static void unspecified_bool_xpath_query(xpath_query***)
12911 PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type()
const
12913 return _impl ? unspecified_bool_xpath_query : 0;
12916 PUGI__FN
bool xpath_query::operator!()
const
12921 PUGI__FN xpath_node xml_node::select_node(
const char_t* query, xpath_variable_set* variables)
const
12923 xpath_query q(query, variables);
12924 return q.evaluate_node(*
this);
12927 PUGI__FN xpath_node xml_node::select_node(
const xpath_query& query)
const
12929 return query.evaluate_node(*
this);
12932 PUGI__FN xpath_node_set xml_node::select_nodes(
const char_t* query, xpath_variable_set* variables)
const
12934 xpath_query q(query, variables);
12935 return q.evaluate_node_set(*
this);
12938 PUGI__FN xpath_node_set xml_node::select_nodes(
const xpath_query& query)
const
12940 return query.evaluate_node_set(*
this);
12943 PUGI__FN xpath_node xml_node::select_single_node(
const char_t* query, xpath_variable_set* variables)
const
12945 xpath_query q(query, variables);
12946 return q.evaluate_node(*
this);
12949 PUGI__FN xpath_node xml_node::select_single_node(
const xpath_query& query)
const
12951 return query.evaluate_node(*
this);
12963#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
12964# pragma warning(pop)
12967#if defined(_MSC_VER) && defined(__c2__)
12968# pragma clang diagnostic pop
12972#undef PUGI__NO_INLINE
12973#undef PUGI__UNLIKELY
12974#undef PUGI__STATIC_ASSERT
12975#undef PUGI__DMC_VOLATILE
12976#undef PUGI__UNSIGNED_OVERFLOW
12977#undef PUGI__MSVC_CRT_VERSION
12978#undef PUGI__SNPRINTF
12979#undef PUGI__NS_BEGIN
12982#undef PUGI__FN_NO_INLINE
12983#undef PUGI__GETHEADER_IMPL
12984#undef PUGI__GETPAGE_IMPL
12985#undef PUGI__GETPAGE
12986#undef PUGI__NODETYPE
12987#undef PUGI__IS_CHARTYPE_IMPL
12988#undef PUGI__IS_CHARTYPE
12989#undef PUGI__IS_CHARTYPEX
12990#undef PUGI__ENDSWITH
12993#undef PUGI__PUSHNODE
12994#undef PUGI__POPNODE
12995#undef PUGI__SCANFOR
12996#undef PUGI__SCANWHILE
12997#undef PUGI__SCANWHILE_UNROLL
12999#undef PUGI__THROW_ERROR
13000#undef PUGI__CHECK_ERROR