14#ifndef SOURCE_PUGIXML_CPP
15#define SOURCE_PUGIXML_CPP
25#ifdef PUGIXML_WCHAR_MODE
29#ifndef PUGIXML_NO_XPATH
32#ifdef PUGIXML_NO_EXCEPTIONS
48#pragma warning(disable : 4127)
51#pragma warning(disable : 4611)
53#pragma warning(disable : 4702)
54#pragma warning(disable : 4996)
55#pragma warning(disable : 4793)
59#ifdef __INTEL_COMPILER
60#pragma warning(disable : 177)
61#pragma warning(disable : 279)
62#pragma warning(disable : 1478 1786)
67#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
81#pragma diag_suppress = 178
82#pragma diag_suppress = 237
86#if defined(_MSC_VER) && _MSC_VER >= 1300
87#define PUGI__NO_INLINE __declspec(noinline)
88#elif defined(__GNUC__)
89#define PUGI__NO_INLINE __attribute__((noinline))
91#define PUGI__NO_INLINE
96#define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0)
98#define PUGI__UNLIKELY(cond) (cond)
102#define PUGI__STATIC_ASSERT(cond) \
104 static const char condition_failed[(cond) ? 1 : -1] = {0}; \
105 (void)condition_failed[0]; \
110#define PUGI__DMC_VOLATILE volatile
112#define PUGI__DMC_VOLATILE
118#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
126#if defined(PUGIXML_HAS_LONG_LONG) && defined(__MINGW32__) && \
127 defined(__STRICT_ANSI__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && \
129#define LLONG_MAX 9223372036854775807LL
130#define LLONG_MIN (-LLONG_MAX - 1)
131#define ULLONG_MAX (2ULL * LLONG_MAX + 1)
136#if defined(_MSC_VER) && !defined(__S3E__)
137#define PUGI__MSVC_CRT_VERSION _MSC_VER
140#ifdef PUGIXML_HEADER_ONLY
141#define PUGI__NS_BEGIN \
144#define PUGI__NS_END \
147#define PUGI__FN inline
148#define PUGI__FN_NO_INLINE inline
150#if defined(_MSC_VER) && \
153#define PUGI__NS_BEGIN \
156#define PUGI__NS_END \
160#define PUGI__NS_BEGIN \
164#define PUGI__NS_END \
170#define PUGI__FN_NO_INLINE PUGI__NO_INLINE
174#if (defined(_MSC_VER) && _MSC_VER < 1600) || \
175 (defined(__BORLANDC__) && __BORLANDC__ < 0x561)
177#ifndef _UINTPTR_T_DEFINED
178typedef size_t uintptr_t;
181typedef unsigned __int8 uint8_t;
182typedef unsigned __int16 uint16_t;
183typedef unsigned __int32 uint32_t;
191PUGI__FN
void* default_allocate(
size_t size) {
return malloc(size); }
193PUGI__FN
void default_deallocate(
void* ptr) { free(ptr); }
197 static allocation_function allocate;
198 static deallocation_function deallocate;
217PUGI__FN
size_t strlength(
const char_t* s) {
220#ifdef PUGIXML_WCHAR_MODE
228PUGI__FN
bool strequal(
const char_t* src,
const char_t* dst) {
231#ifdef PUGIXML_WCHAR_MODE
232 return wcscmp(src, dst) == 0;
234 return strcmp(src, dst) == 0;
239PUGI__FN
bool strequalrange(
const char_t* lhs,
const char_t* rhs,
241 for (
size_t i = 0; i < count; ++i)
242 if (lhs[i] != rhs[i])
return false;
244 return lhs[count] == 0;
248PUGI__FN
size_t strlength_wide(
const wchar_t* s) {
251#ifdef PUGIXML_WCHAR_MODE
254 const wchar_t* end = s;
256 return static_cast<size_t>(end - s);
265 typedef void (*D)(T*);
270 auto_deleter(T* data_, D deleter_) : data(data_), deleter(deleter_) {}
273 if (data) deleter(data);
284#ifdef PUGIXML_COMPACT
286class compact_hash_table {
288 compact_hash_table() : _items(0), _capacity(0), _count(0) {}
292 xml_memory::deallocate(_items);
299 void** find(
const void* key) {
302 if (_capacity == 0)
return 0;
304 size_t hashmod = _capacity - 1;
305 size_t bucket = hash(key) & hashmod;
307 for (
size_t probe = 0; probe <= hashmod; ++probe) {
308 item_t& probe_item = _items[bucket];
310 if (probe_item.key == key)
return &probe_item.value;
312 if (probe_item.key == 0)
return 0;
315 bucket = (bucket + probe + 1) & hashmod;
318 assert(
false &&
"Hash table is full");
322 void** insert(
const void* key) {
324 assert(_capacity != 0 && _count < _capacity - _capacity / 4);
326 size_t hashmod = _capacity - 1;
327 size_t bucket = hash(key) & hashmod;
329 for (
size_t probe = 0; probe <= hashmod; ++probe) {
330 item_t& probe_item = _items[bucket];
332 if (probe_item.key == 0) {
333 probe_item.key = key;
335 return &probe_item.value;
338 if (probe_item.key == key)
return &probe_item.value;
341 bucket = (bucket + probe + 1) & hashmod;
344 assert(
false &&
"Hash table is full");
349 if (_count + 16 >= _capacity - _capacity / 4)
return rehash();
367 static unsigned int hash(
const void* key) {
369 static_cast<unsigned int>(
reinterpret_cast<uintptr_t
>(key));
382PUGI__FN_NO_INLINE
bool compact_hash_table::rehash() {
383 compact_hash_table rt;
384 rt._capacity = (_capacity == 0) ? 32 : _capacity * 2;
386 static_cast<item_t*
>(xml_memory::allocate(
sizeof(item_t) * rt._capacity));
388 if (!rt._items)
return false;
390 memset(rt._items, 0,
sizeof(item_t) * rt._capacity);
392 for (
size_t i = 0; i < _capacity; ++i)
393 if (_items[i].key) *rt.insert(_items[i].key) = _items[i].value;
395 if (_items) xml_memory::deallocate(_items);
397 _capacity = rt._capacity;
400 assert(_count == rt._count);
409#ifdef PUGIXML_COMPACT
410static const uintptr_t xml_memory_block_alignment = 4;
412static const uintptr_t xml_memory_block_alignment =
sizeof(
void*);
416static const uintptr_t xml_memory_page_contents_shared_mask = 64;
417static const uintptr_t xml_memory_page_name_allocated_mask = 32;
418static const uintptr_t xml_memory_page_value_allocated_mask = 16;
419static const uintptr_t xml_memory_page_type_mask = 15;
422static const uintptr_t xml_memory_page_name_allocated_or_shared_mask =
423 xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask;
424static const uintptr_t xml_memory_page_value_allocated_or_shared_mask =
425 xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask;
427#ifdef PUGIXML_COMPACT
428#define PUGI__GETHEADER_IMPL(object, page, flags)
429#define PUGI__GETPAGE_IMPL(header) (header).get_page()
431#define PUGI__GETHEADER_IMPL(object, page, flags) \
432 (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | \
436#define PUGI__GETPAGE_IMPL(header) \
437 static_cast<impl::xml_memory_page*>( \
438 const_cast<void*>(static_cast<const void*>( \
439 reinterpret_cast<const char*>(&header) - (header >> 8))))
442#define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header)
443#define PUGI__NODETYPE(n) \
444 static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
452 result->allocator = 0;
455 result->busy_size = 0;
456 result->freed_size = 0;
458#ifdef PUGIXML_COMPACT
459 result->compact_string_base = 0;
460 result->compact_shared_parent = 0;
461 result->compact_page_marker = 0;
475#ifdef PUGIXML_COMPACT
476 char_t* compact_string_base;
477 void* compact_shared_parent;
478 uint32_t* compact_page_marker;
482static const size_t xml_memory_page_size =
483#ifdef PUGIXML_MEMORY_PAGE_SIZE
484 (PUGIXML_MEMORY_PAGE_SIZE)
491 uint16_t page_offset;
497 : _root(root), _busy_size(root->busy_size) {
498#ifdef PUGIXML_COMPACT
507 void* memory = xml_memory::allocate(size);
508 if (!memory)
return 0;
514 page->allocator = _root->allocator;
520 xml_memory::deallocate(page);
526 if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size))
527 return allocate_memory_oob(size, out_page);
539#ifdef PUGIXML_COMPACT
541 void* result = allocate_memory(size +
sizeof(uint32_t), out_page);
542 if (!result)
return 0;
545 ptrdiff_t offset =
static_cast<char*
>(result) -
546 reinterpret_cast<char*
>(out_page->compact_page_marker);
548 if (PUGI__UNLIKELY(
static_cast<uintptr_t
>(offset) >=
549 256 * xml_memory_block_alignment)) {
551 uint32_t* marker =
static_cast<uint32_t*
>(result);
553 *marker =
static_cast<uint32_t
>(
reinterpret_cast<char*
>(marker) -
554 reinterpret_cast<char*
>(out_page));
555 out_page->compact_page_marker = marker;
560 out_page->freed_size +=
sizeof(uint32_t);
565 _busy_size -=
sizeof(uint32_t);
572 return allocate_memory(size, out_page);
576 void deallocate_memory(
void* ptr,
size_t size,
xml_memory_page* page) {
577 if (page == _root) page->busy_size = _busy_size;
579 assert(ptr >=
reinterpret_cast<char*
>(page) +
sizeof(
xml_memory_page) &&
584 page->freed_size += size;
585 assert(page->freed_size <= page->busy_size);
587 if (page->freed_size == page->busy_size) {
588 if (page->next == 0) {
589 assert(_root == page);
593 page->freed_size = 0;
595#ifdef PUGIXML_COMPACT
597 page->compact_string_base = 0;
598 page->compact_shared_parent = 0;
599 page->compact_page_marker = 0;
604 assert(_root != page);
608 page->prev->next = page->next;
609 page->next->prev = page->prev;
612 deallocate_page(page);
617 char_t* allocate_string(
size_t length) {
618 static const size_t max_encoded_offset =
619 (1 << 16) * xml_memory_block_alignment;
621 PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
627 size_t full_size = (size + (xml_memory_block_alignment - 1)) &
628 ~(xml_memory_block_alignment - 1);
632 allocate_memory(full_size, page));
634 if (!header)
return 0;
637 ptrdiff_t page_offset =
reinterpret_cast<char*
>(header) -
638 reinterpret_cast<char*
>(page) -
641 assert(page_offset % xml_memory_block_alignment == 0);
642 assert(page_offset >= 0 &&
643 static_cast<size_t>(page_offset) < max_encoded_offset);
644 header->page_offset =
static_cast<uint16_t
>(
645 static_cast<size_t>(page_offset) / xml_memory_block_alignment);
648 assert(full_size % xml_memory_block_alignment == 0);
649 assert(full_size < max_encoded_offset ||
650 (page->busy_size == full_size && page_offset == 0));
651 header->full_size =
static_cast<uint16_t
>(
652 full_size < max_encoded_offset ? full_size / xml_memory_block_alignment
658 return static_cast<char_t*
>(
static_cast<void*
>(header + 1));
661 void deallocate_string(char_t*
string) {
674 header->page_offset * xml_memory_block_alignment;
676 static_cast<void*
>(
reinterpret_cast<char*
>(header) - page_offset));
679 size_t full_size = header->full_size == 0
681 : header->full_size * xml_memory_block_alignment;
683 deallocate_memory(header, full_size, page);
687#ifdef PUGIXML_COMPACT
688 return _hash->reserve();
697#ifdef PUGIXML_COMPACT
698 compact_hash_table* _hash;
702PUGI__FN_NO_INLINE
void* xml_allocator::allocate_memory_oob(
704 const size_t large_allocation_threshold = xml_memory_page_size / 4;
707 size <= large_allocation_threshold ? xml_memory_page_size : size);
712 if (size <= large_allocation_threshold) {
713 _root->busy_size = _busy_size;
727 page->prev = _root->prev;
730 _root->prev->next = page;
733 page->busy_size = size;
740#ifdef PUGIXML_COMPACT
742static const uintptr_t compact_alignment_log2 = 2;
743static const uintptr_t compact_alignment = 1 << compact_alignment_log2;
745class compact_header {
748 PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
750 ptrdiff_t offset = (
reinterpret_cast<char*
>(
this) -
751 reinterpret_cast<char*
>(page->compact_page_marker));
752 assert(offset % compact_alignment == 0 &&
753 static_cast<uintptr_t
>(offset) < 256 * compact_alignment);
755 _page =
static_cast<unsigned char>(offset >> compact_alignment_log2);
756 _flags =
static_cast<unsigned char>(flags);
759 void operator&=(uintptr_t mod) { _flags &=
static_cast<unsigned char>(mod); }
761 void operator|=(uintptr_t mod) { _flags |=
static_cast<unsigned char>(mod); }
763 uintptr_t operator&(uintptr_t mod)
const {
return _flags & mod; }
768 const char* page_marker =
769 reinterpret_cast<const char*
>(
this) - (_page << compact_alignment_log2);
770 const char* page = page_marker - *
reinterpret_cast<const uint32_t*
>(
771 static_cast<const void*
>(page_marker));
775 static_cast<const void*
>(page)));
780 unsigned char _flags;
785 const compact_header* header =
reinterpret_cast<const compact_header*
>(
786 static_cast<const char*
>(object) - header_offset);
788 return header->get_page();
791template <
int header_offset,
typename T>
792PUGI__FN_NO_INLINE T* compact_get_value(
const void*
object) {
793 return static_cast<T*
>(
794 *compact_get_page(
object, header_offset)->allocator->_hash->find(
object));
797template <
int header_offset,
typename T>
798PUGI__FN_NO_INLINE
void compact_set_value(
const void*
object, T* value) {
799 *compact_get_page(
object, header_offset)->allocator->_hash->insert(
object) =
803template <
typename T,
int header_offset,
int start = -126>
804class compact_pointer {
806 compact_pointer() : _data(0) {}
808 void operator=(
const compact_pointer& rhs) { *
this = rhs + 0; }
810 void operator=(T* value) {
818 reinterpret_cast<char*
>(value) -
reinterpret_cast<char*
>(
this);
820 ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) -
823 if (
static_cast<uintptr_t
>(offset) <= 253)
824 _data =
static_cast<unsigned char>(offset + 1);
826 compact_set_value<header_offset>(
this, value);
834 operator T*()
const {
838 reinterpret_cast<uintptr_t
>(
this) & ~(compact_alignment - 1);
840 return reinterpret_cast<T*
>(
841 base + ((_data - 1 + start) << compact_alignment_log2));
843 return compact_get_value<header_offset, T>(
this);
848 T* operator->()
const {
return *
this; }
854template <
typename T,
int header_offset>
855class compact_pointer_parent {
857 compact_pointer_parent() : _data(0) {}
859 void operator=(
const compact_pointer_parent& rhs) { *
this = rhs + 0; }
861 void operator=(T* value) {
869 reinterpret_cast<char*
>(value) -
reinterpret_cast<char*
>(
this);
871 ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) +
874 if (
static_cast<uintptr_t
>(offset) <= 65533) {
875 _data =
static_cast<unsigned short>(offset + 1);
879 if (PUGI__UNLIKELY(page->compact_shared_parent == 0))
880 page->compact_shared_parent = value;
882 if (page->compact_shared_parent == value) {
885 compact_set_value<header_offset>(
this, value);
895 operator T*()
const {
899 reinterpret_cast<uintptr_t
>(
this) & ~(compact_alignment - 1);
901 return reinterpret_cast<T*
>(
902 base + ((_data - 1 - 65533) << compact_alignment_log2));
903 }
else if (_data == 65534)
904 return static_cast<T*
>(
905 compact_get_page(
this, header_offset)->compact_shared_parent);
907 return compact_get_value<header_offset, T>(
this);
912 T* operator->()
const {
return *
this; }
918template <
int header_offset,
int base_offset>
919class compact_string {
921 compact_string() : _data(0) {}
923 void operator=(
const compact_string& rhs) { *
this = rhs + 0; }
925 void operator=(char_t* value) {
929 if (PUGI__UNLIKELY(page->compact_string_base == 0))
930 page->compact_string_base = value;
932 ptrdiff_t offset = value - page->compact_string_base;
934 if (
static_cast<uintptr_t
>(offset) < (65535 << 7)) {
937 uint16_t* base =
reinterpret_cast<uint16_t*
>(
938 static_cast<void*
>(
reinterpret_cast<char*
>(
this) - base_offset));
941 *base =
static_cast<uint16_t
>((offset >> 7) + 1);
942 _data =
static_cast<unsigned char>((offset & 127) + 1);
944 ptrdiff_t remainder = offset - ((*base - 1) << 7);
946 if (
static_cast<uintptr_t
>(remainder) <= 253) {
947 _data =
static_cast<unsigned char>(remainder + 1);
949 compact_set_value<header_offset>(
this, value);
955 compact_set_value<header_offset>(
this, value);
964 operator char_t*()
const {
971 const uint16_t* base =
972 reinterpret_cast<const uint16_t*
>(
static_cast<const void*
>(
973 reinterpret_cast<const char*
>(
this) - base_offset));
976 ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);
978 return page->compact_string_base + offset;
980 return compact_get_value<header_offset, char_t>(
this);
992#ifdef PUGIXML_COMPACT
994struct xml_attribute_struct {
995 xml_attribute_struct(impl::xml_memory_page* page)
996 : header(page, 0), namevalue_base(0) {
997 PUGI__STATIC_ASSERT(
sizeof(xml_attribute_struct) == 8);
1000 impl::compact_header header;
1002 uint16_t namevalue_base;
1004 impl::compact_string<4, 2> name;
1005 impl::compact_string<5, 3> value;
1007 impl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c;
1008 impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute;
1011struct xml_node_struct {
1012 xml_node_struct(impl::xml_memory_page* page, xml_node_type type)
1013 : header(page, type), namevalue_base(0) {
1014 PUGI__STATIC_ASSERT(
sizeof(xml_node_struct) == 12);
1017 impl::compact_header header;
1019 uint16_t namevalue_base;
1021 impl::compact_string<4, 2> name;
1022 impl::compact_string<5, 3> value;
1024 impl::compact_pointer_parent<xml_node_struct, 6> parent;
1026 impl::compact_pointer<xml_node_struct, 8, 0> first_child;
1028 impl::compact_pointer<xml_node_struct, 9> prev_sibling_c;
1029 impl::compact_pointer<xml_node_struct, 10, 0> next_sibling;
1031 impl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute;
1038 : name(0), value(0), prev_attribute_c(0), next_attribute(0) {
1039 header = PUGI__GETHEADER_IMPL(
this, page, 0);
1059 first_attribute(0) {
1060 header = PUGI__GETHEADER_IMPL(
this, page, type);
1088 : xml_node_struct(page, node_document),
1093 const char_t* buffer;
1097#ifdef PUGIXML_COMPACT
1098 compact_hash_table hash;
1102template <
typename Object>
1106 return *PUGI__GETPAGE(
object)->allocator;
1109template <
typename Object>
1119inline xml_attribute_struct* allocate_attribute(
xml_allocator& alloc) {
1121 void* memory = alloc.allocate_object(
sizeof(xml_attribute_struct), page);
1122 if (!memory)
return 0;
1124 return new (memory) xml_attribute_struct(page);
1128 xml_node_type type) {
1130 void* memory = alloc.allocate_object(
sizeof(xml_node_struct), page);
1131 if (!memory)
return 0;
1133 return new (memory) xml_node_struct(page, type);
1136inline void destroy_attribute(xml_attribute_struct* a,
xml_allocator& alloc) {
1137 if (a->header & impl::xml_memory_page_name_allocated_mask)
1138 alloc.deallocate_string(a->name);
1140 if (a->header & impl::xml_memory_page_value_allocated_mask)
1141 alloc.deallocate_string(a->value);
1143 alloc.deallocate_memory(a,
sizeof(xml_attribute_struct), PUGI__GETPAGE(a));
1146inline void destroy_node(xml_node_struct* n,
xml_allocator& alloc) {
1147 if (n->header & impl::xml_memory_page_name_allocated_mask)
1148 alloc.deallocate_string(n->name);
1150 if (n->header & impl::xml_memory_page_value_allocated_mask)
1151 alloc.deallocate_string(n->value);
1153 for (xml_attribute_struct* attr = n->first_attribute; attr;) {
1154 xml_attribute_struct* next = attr->next_attribute;
1156 destroy_attribute(attr, alloc);
1161 for (xml_node_struct* child = n->first_child; child;) {
1162 xml_node_struct* next = child->next_sibling;
1164 destroy_node(child, alloc);
1169 alloc.deallocate_memory(n,
sizeof(xml_node_struct), PUGI__GETPAGE(n));
1172inline void append_node(xml_node_struct* child, xml_node_struct* node) {
1173 child->parent = node;
1175 xml_node_struct* head = node->first_child;
1178 xml_node_struct* tail = head->prev_sibling_c;
1180 tail->next_sibling = child;
1181 child->prev_sibling_c = tail;
1182 head->prev_sibling_c = child;
1184 node->first_child = child;
1185 child->prev_sibling_c = child;
1189inline void prepend_node(xml_node_struct* child, xml_node_struct* node) {
1190 child->parent = node;
1192 xml_node_struct* head = node->first_child;
1195 child->prev_sibling_c = head->prev_sibling_c;
1196 head->prev_sibling_c = child;
1198 child->prev_sibling_c = child;
1200 child->next_sibling = head;
1201 node->first_child = child;
1204inline void insert_node_after(xml_node_struct* child, xml_node_struct* node) {
1205 xml_node_struct* parent = node->parent;
1207 child->parent = parent;
1209 if (node->next_sibling)
1210 node->next_sibling->prev_sibling_c = child;
1212 parent->first_child->prev_sibling_c = child;
1214 child->next_sibling = node->next_sibling;
1215 child->prev_sibling_c = node;
1217 node->next_sibling = child;
1220inline void insert_node_before(xml_node_struct* child, xml_node_struct* node) {
1221 xml_node_struct* parent = node->parent;
1223 child->parent = parent;
1225 if (node->prev_sibling_c->next_sibling)
1226 node->prev_sibling_c->next_sibling = child;
1228 parent->first_child = child;
1230 child->prev_sibling_c = node->prev_sibling_c;
1231 child->next_sibling = node;
1233 node->prev_sibling_c = child;
1236inline void remove_node(xml_node_struct* node) {
1237 xml_node_struct* parent = node->parent;
1239 if (node->next_sibling)
1240 node->next_sibling->prev_sibling_c = node->prev_sibling_c;
1242 parent->first_child->prev_sibling_c = node->prev_sibling_c;
1244 if (node->prev_sibling_c->next_sibling)
1245 node->prev_sibling_c->next_sibling = node->next_sibling;
1247 parent->first_child = node->next_sibling;
1250 node->prev_sibling_c = 0;
1251 node->next_sibling = 0;
1254inline void append_attribute(xml_attribute_struct* attr,
1255 xml_node_struct* node) {
1256 xml_attribute_struct* head = node->first_attribute;
1259 xml_attribute_struct* tail = head->prev_attribute_c;
1261 tail->next_attribute = attr;
1262 attr->prev_attribute_c = tail;
1263 head->prev_attribute_c = attr;
1265 node->first_attribute = attr;
1266 attr->prev_attribute_c = attr;
1270inline void prepend_attribute(xml_attribute_struct* attr,
1271 xml_node_struct* node) {
1272 xml_attribute_struct* head = node->first_attribute;
1275 attr->prev_attribute_c = head->prev_attribute_c;
1276 head->prev_attribute_c = attr;
1278 attr->prev_attribute_c = attr;
1280 attr->next_attribute = head;
1281 node->first_attribute = attr;
1284inline void insert_attribute_after(xml_attribute_struct* attr,
1285 xml_attribute_struct* place,
1286 xml_node_struct* node) {
1287 if (place->next_attribute)
1288 place->next_attribute->prev_attribute_c = attr;
1290 node->first_attribute->prev_attribute_c = attr;
1292 attr->next_attribute = place->next_attribute;
1293 attr->prev_attribute_c = place;
1294 place->next_attribute = attr;
1297inline void insert_attribute_before(xml_attribute_struct* attr,
1298 xml_attribute_struct* place,
1299 xml_node_struct* node) {
1300 if (place->prev_attribute_c->next_attribute)
1301 place->prev_attribute_c->next_attribute = attr;
1303 node->first_attribute = attr;
1305 attr->prev_attribute_c = place->prev_attribute_c;
1306 attr->next_attribute = place;
1307 place->prev_attribute_c = attr;
1310inline void remove_attribute(xml_attribute_struct* attr,
1311 xml_node_struct* node) {
1312 if (attr->next_attribute)
1313 attr->next_attribute->prev_attribute_c = attr->prev_attribute_c;
1315 node->first_attribute->prev_attribute_c = attr->prev_attribute_c;
1317 if (attr->prev_attribute_c->next_attribute)
1318 attr->prev_attribute_c->next_attribute = attr->next_attribute;
1320 node->first_attribute = attr->next_attribute;
1322 attr->prev_attribute_c = 0;
1323 attr->next_attribute = 0;
1326PUGI__FN_NO_INLINE xml_node_struct* append_new_node(
1328 xml_node_type type = node_element) {
1329 if (!alloc.reserve())
return 0;
1331 xml_node_struct* child = allocate_node(alloc, type);
1332 if (!child)
return 0;
1334 append_node(child, node);
1339PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(
1341 if (!alloc.reserve())
return 0;
1343 xml_attribute_struct* attr = allocate_attribute(alloc);
1344 if (!attr)
return 0;
1346 append_attribute(attr, node);
1365inline uint16_t endian_swap(uint16_t value) {
1366 return static_cast<uint16_t
>(((value & 0xff) << 8) | (value >> 8));
1369inline uint32_t endian_swap(uint32_t value) {
1370 return ((value & 0xff) << 24) | ((value & 0xff00) << 8) |
1371 ((value & 0xff0000) >> 8) | (value >> 24);
1375 typedef size_t value_type;
1377 static value_type low(value_type result, uint32_t ch) {
1379 if (ch < 0x80)
return result + 1;
1381 else if (ch < 0x800)
1388 static value_type high(value_type result, uint32_t) {
1395 typedef uint8_t* value_type;
1397 static value_type low(value_type result, uint32_t ch) {
1400 *result =
static_cast<uint8_t
>(ch);
1404 else if (ch < 0x800) {
1405 result[0] =
static_cast<uint8_t
>(0xC0 | (ch >> 6));
1406 result[1] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
1411 result[0] =
static_cast<uint8_t
>(0xE0 | (ch >> 12));
1412 result[1] =
static_cast<uint8_t
>(0x80 | ((ch >> 6) & 0x3F));
1413 result[2] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
1418 static value_type high(value_type result, uint32_t ch) {
1420 result[0] =
static_cast<uint8_t
>(0xF0 | (ch >> 18));
1421 result[1] =
static_cast<uint8_t
>(0x80 | ((ch >> 12) & 0x3F));
1422 result[2] =
static_cast<uint8_t
>(0x80 | ((ch >> 6) & 0x3F));
1423 result[3] =
static_cast<uint8_t
>(0x80 | (ch & 0x3F));
1427 static value_type any(value_type result, uint32_t ch) {
1428 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
1433 typedef size_t value_type;
1435 static value_type low(value_type result, uint32_t) {
return result + 1; }
1437 static value_type high(value_type result, uint32_t) {
return result + 2; }
1441 typedef uint16_t* value_type;
1443 static value_type low(value_type result, uint32_t ch) {
1444 *result =
static_cast<uint16_t
>(ch);
1449 static value_type high(value_type result, uint32_t ch) {
1450 uint32_t msh =
static_cast<uint32_t
>(ch - 0x10000) >> 10;
1451 uint32_t lsh =
static_cast<uint32_t
>(ch - 0x10000) & 0x3ff;
1453 result[0] =
static_cast<uint16_t
>(0xD800 + msh);
1454 result[1] =
static_cast<uint16_t
>(0xDC00 + lsh);
1459 static value_type any(value_type result, uint32_t ch) {
1460 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
1465 typedef size_t value_type;
1467 static value_type low(value_type result, uint32_t) {
return result + 1; }
1469 static value_type high(value_type result, uint32_t) {
return result + 1; }
1473 typedef uint32_t* value_type;
1475 static value_type low(value_type result, uint32_t ch) {
1481 static value_type high(value_type result, uint32_t ch) {
1487 static value_type any(value_type result, uint32_t ch) {
1495 typedef uint8_t* value_type;
1497 static value_type low(value_type result, uint32_t ch) {
1498 *result =
static_cast<uint8_t
>(ch > 255 ?
'?' : ch);
1503 static value_type high(value_type result, uint32_t ch) {
1513 typedef uint8_t type;
1515 template <
typename Traits>
1516 static inline typename Traits::value_type process(
1517 const uint8_t* data,
size_t size,
typename Traits::value_type result,
1519 const uint8_t utf8_byte_mask = 0x3f;
1522 uint8_t lead = *data;
1526 result = Traits::low(result, lead);
1531 if ((
reinterpret_cast<uintptr_t
>(data) & 3) == 0) {
1534 while (size >= 4 && (*
static_cast<const uint32_t*
>(
1535 static_cast<const void*
>(data)) &
1537 result = Traits::low(result, data[0]);
1538 result = Traits::low(result, data[1]);
1539 result = Traits::low(result, data[2]);
1540 result = Traits::low(result, data[3]);
1547 else if (
static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 &&
1548 (data[1] & 0xc0) == 0x80) {
1549 result = Traits::low(
1550 result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
1555 else if (
static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 &&
1556 (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80) {
1557 result = Traits::low(result, ((lead & ~0xE0) << 12) |
1558 ((data[1] & utf8_byte_mask) << 6) |
1559 (data[2] & utf8_byte_mask));
1564 else if (
static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 &&
1565 (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 &&
1566 (data[3] & 0xc0) == 0x80) {
1567 result = Traits::high(result, ((lead & ~0xF0) << 18) |
1568 ((data[1] & utf8_byte_mask) << 12) |
1569 ((data[2] & utf8_byte_mask) << 6) |
1570 (data[3] & utf8_byte_mask));
1585template <
typename opt_swap>
1587 typedef uint16_t type;
1589 template <
typename Traits>
1590 static inline typename Traits::value_type process(
1591 const uint16_t* data,
size_t size,
typename Traits::value_type result,
1594 uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
1597 if (lead < 0xD800) {
1598 result = Traits::low(result, lead);
1603 else if (
static_cast<unsigned int>(lead - 0xE000) < 0x2000) {
1604 result = Traits::low(result, lead);
1609 else if (
static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2) {
1610 uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
1612 if (
static_cast<unsigned int>(next - 0xDC00) < 0x400) {
1613 result = Traits::high(
1614 result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
1631template <
typename opt_swap>
1633 typedef uint32_t type;
1635 template <
typename Traits>
1636 static inline typename Traits::value_type process(
1637 const uint32_t* data,
size_t size,
typename Traits::value_type result,
1640 uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
1643 if (lead < 0x10000) {
1644 result = Traits::low(result, lead);
1650 result = Traits::high(result, lead);
1661 typedef uint8_t type;
1663 template <
typename Traits>
1664 static inline typename Traits::value_type process(
1665 const uint8_t* data,
size_t size,
typename Traits::value_type result,
1668 result = Traits::low(result, *data);
1677template <
size_t size>
1682 typedef uint16_t type;
1690 typedef uint32_t type;
1700 typedef wchar_t type;
1702 template <
typename Traits>
1703 static inline typename Traits::value_type process(
1704 const wchar_t* data,
size_t size,
typename Traits::value_type result,
1708 return decoder::process(
1709 reinterpret_cast<const typename decoder::type*
>(data), size, result,
1714#ifdef PUGIXML_WCHAR_MODE
1715PUGI__FN
void convert_wchar_endian_swap(
wchar_t* result,
const wchar_t* data,
1717 for (
size_t i = 0; i < length; ++i)
1718 result[i] =
static_cast<wchar_t>(endian_swap(
1726 ct_parse_pcdata = 1,
1728 ct_parse_attr_ws = 4,
1730 ct_parse_cdata = 16,
1731 ct_parse_comment = 32,
1733 ct_start_symbol = 128
1736static const unsigned char chartype_table[256] = {
1737 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63,
1739 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1741 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96,
1743 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0,
1745 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1747 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16,
1749 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1751 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0,
1754 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1756 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1757 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1758 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1759 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1760 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1761 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1762 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
1763 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192};
1766 ctx_special_pcdata =
1768 ctx_special_attr = 2,
1769 ctx_start_symbol = 4,
1774static const unsigned char chartypex_table[256] = {
1775 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3,
1776 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
1777 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0,
1778 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0,
1780 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1781 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20,
1782 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1783 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0,
1785 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1786 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1787 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1788 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1789 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1790 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
1791 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
1793#ifdef PUGIXML_WCHAR_MODE
1794#define PUGI__IS_CHARTYPE_IMPL(c, ct, table) \
1795 ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] \
1799#define PUGI__IS_CHARTYPE_IMPL(c, ct, table) \
1800 (table[static_cast<unsigned char>(c)] & (ct))
1803#define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
1804#define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
1806PUGI__FN
bool is_little_endian() {
1807 unsigned int ui = 1;
1809 return *
reinterpret_cast<unsigned char*
>(&ui) == 1;
1812PUGI__FN xml_encoding get_wchar_encoding() {
1813 PUGI__STATIC_ASSERT(
sizeof(
wchar_t) == 2 ||
sizeof(
wchar_t) == 4);
1815 if (
sizeof(
wchar_t) == 2)
1816 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1818 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1821PUGI__FN
bool parse_declaration_encoding(
const uint8_t* data,
size_t size,
1822 const uint8_t*& out_encoding,
1823 size_t& out_length) {
1824#define PUGI__SCANCHAR(ch) \
1826 if (offset >= size || data[offset] != ch) return false; \
1829#define PUGI__SCANCHARTYPE(ct) \
1831 while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; \
1835 if (size < 6 || !((data[0] ==
'<') & (data[1] ==
'?') & (data[2] ==
'x') &
1836 (data[3] ==
'm') & (data[4] ==
'l') &&
1837 PUGI__IS_CHARTYPE(data[5], ct_space)))
1841 for (
size_t i = 6; i + 1 < size; ++i) {
1843 if (data[i] ==
'?')
return false;
1845 if (data[i] ==
'e' && data[i + 1] ==
'n') {
1850 PUGI__SCANCHAR(
'e');
1851 PUGI__SCANCHAR(
'n');
1852 PUGI__SCANCHAR(
'c');
1853 PUGI__SCANCHAR(
'o');
1854 PUGI__SCANCHAR(
'd');
1855 PUGI__SCANCHAR(
'i');
1856 PUGI__SCANCHAR(
'n');
1857 PUGI__SCANCHAR(
'g');
1860 PUGI__SCANCHARTYPE(ct_space);
1861 PUGI__SCANCHAR(
'=');
1862 PUGI__SCANCHARTYPE(ct_space);
1865 uint8_t delimiter = (offset < size && data[offset] ==
'"') ?
'"' :
'\'';
1867 PUGI__SCANCHAR(delimiter);
1869 size_t start = offset;
1871 out_encoding = data + offset;
1873 PUGI__SCANCHARTYPE(ct_symbol);
1875 out_length = offset - start;
1877 PUGI__SCANCHAR(delimiter);
1885#undef PUGI__SCANCHAR
1886#undef PUGI__SCANCHARTYPE
1889PUGI__FN xml_encoding guess_buffer_encoding(
const uint8_t* data,
size_t size) {
1891 if (size < 4)
return encoding_utf8;
1893 uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
1896 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff)
return encoding_utf32_be;
1897 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0)
return encoding_utf32_le;
1898 if (d0 == 0xfe && d1 == 0xff)
return encoding_utf16_be;
1899 if (d0 == 0xff && d1 == 0xfe)
return encoding_utf16_le;
1900 if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf)
return encoding_utf8;
1903 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c)
return encoding_utf32_be;
1904 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0)
return encoding_utf32_le;
1905 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f)
return encoding_utf16_be;
1906 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0)
return encoding_utf16_le;
1910 if (d0 == 0 && d1 == 0x3c)
return encoding_utf16_be;
1911 if (d0 == 0x3c && d1 == 0)
return encoding_utf16_le;
1914 const uint8_t* enc = 0;
1915 size_t enc_length = 0;
1917 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d &&
1918 parse_declaration_encoding(data, size, enc, enc_length)) {
1920 if (enc_length == 10 && (enc[0] |
' ') ==
'i' && (enc[1] |
' ') ==
's' &&
1921 (enc[2] |
' ') ==
'o' && enc[3] ==
'-' && enc[4] ==
'8' &&
1922 enc[5] ==
'8' && enc[6] ==
'5' && enc[7] ==
'9' && enc[8] ==
'-' &&
1924 return encoding_latin1;
1927 if (enc_length == 6 && (enc[0] |
' ') ==
'l' && (enc[1] |
' ') ==
'a' &&
1928 (enc[2] |
' ') ==
't' && (enc[3] |
' ') ==
'i' &&
1929 (enc[4] |
' ') ==
'n' && enc[5] ==
'1')
1930 return encoding_latin1;
1933 return encoding_utf8;
1936PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding,
1937 const void* contents,
size_t size) {
1939 if (encoding == encoding_wchar)
return get_wchar_encoding();
1942 if (encoding == encoding_utf16)
1943 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
1946 if (encoding == encoding_utf32)
1947 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
1950 if (encoding != encoding_auto)
return encoding;
1953 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
1955 return guess_buffer_encoding(data, size);
1958PUGI__FN
bool get_mutable_buffer(char_t*& out_buffer,
size_t& out_length,
1959 const void* contents,
size_t size,
1961 size_t length = size /
sizeof(char_t);
1964 out_buffer =
static_cast<char_t*
>(
const_cast<void*
>(contents));
1965 out_length = length;
1967 char_t* buffer =
static_cast<char_t*
>(
1968 xml_memory::allocate((length + 1) *
sizeof(char_t)));
1969 if (!buffer)
return false;
1972 memcpy(buffer, contents, length *
sizeof(char_t));
1974 assert(length == 0);
1978 out_buffer = buffer;
1979 out_length = length + 1;
1985#ifdef PUGIXML_WCHAR_MODE
1986PUGI__FN
bool need_endian_swap_utf(xml_encoding le, xml_encoding re) {
1987 return (le == encoding_utf16_be && re == encoding_utf16_le) ||
1988 (le == encoding_utf16_le && re == encoding_utf16_be) ||
1989 (le == encoding_utf32_be && re == encoding_utf32_le) ||
1990 (le == encoding_utf32_le && re == encoding_utf32_be);
1993PUGI__FN
bool convert_buffer_endian_swap(char_t*& out_buffer,
1995 const void* contents,
size_t size,
1997 const char_t* data =
static_cast<const char_t*
>(contents);
1998 size_t length = size /
sizeof(char_t);
2001 char_t* buffer =
const_cast<char_t*
>(data);
2003 convert_wchar_endian_swap(buffer, data, length);
2005 out_buffer = buffer;
2006 out_length = length;
2008 char_t* buffer =
static_cast<char_t*
>(
2009 xml_memory::allocate((length + 1) *
sizeof(char_t)));
2010 if (!buffer)
return false;
2012 convert_wchar_endian_swap(buffer, data, length);
2015 out_buffer = buffer;
2016 out_length = length + 1;
2022template <
typename D>
2023PUGI__FN
bool convert_buffer_generic(char_t*& out_buffer,
size_t& out_length,
2024 const void* contents,
size_t size, D) {
2025 const typename D::type* data =
static_cast<const typename D::type*
>(contents);
2026 size_t data_length = size /
sizeof(
typename D::type);
2029 size_t length = D::process(data, data_length, 0, wchar_counter());
2033 static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
2034 if (!buffer)
return false;
2037 wchar_writer::value_type obegin =
2038 reinterpret_cast<wchar_writer::value_type
>(buffer);
2039 wchar_writer::value_type oend =
2040 D::process(data, data_length, obegin, wchar_writer());
2042 assert(oend == obegin + length);
2045 out_buffer = buffer;
2046 out_length = length + 1;
2051PUGI__FN
bool convert_buffer(char_t*& out_buffer,
size_t& out_length,
2052 xml_encoding encoding,
const void* contents,
2053 size_t size,
bool is_mutable) {
2055 xml_encoding wchar_encoding = get_wchar_encoding();
2058 if (encoding == wchar_encoding)
2059 return get_mutable_buffer(out_buffer, out_length, contents, size,
2063 if (need_endian_swap_utf(encoding, wchar_encoding))
2064 return convert_buffer_endian_swap(out_buffer, out_length, contents, size,
2068 if (encoding == encoding_utf8)
2069 return convert_buffer_generic(out_buffer, out_length, contents, size,
2073 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) {
2074 xml_encoding native_encoding =
2075 is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2077 return (native_encoding == encoding)
2078 ? convert_buffer_generic(out_buffer, out_length, contents, size,
2080 : convert_buffer_generic(out_buffer, out_length, contents, size,
2085 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) {
2086 xml_encoding native_encoding =
2087 is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2089 return (native_encoding == encoding)
2090 ? convert_buffer_generic(out_buffer, out_length, contents, size,
2092 : convert_buffer_generic(out_buffer, out_length, contents, size,
2097 if (encoding == encoding_latin1)
2098 return convert_buffer_generic(out_buffer, out_length, contents, size,
2101 assert(
false &&
"Invalid encoding");
2105template <
typename D>
2106PUGI__FN
bool convert_buffer_generic(char_t*& out_buffer,
size_t& out_length,
2107 const void* contents,
size_t size, D) {
2108 const typename D::type* data =
static_cast<const typename D::type*
>(contents);
2109 size_t data_length = size /
sizeof(
typename D::type);
2112 size_t length = D::process(data, data_length, 0,
utf8_counter());
2116 static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
2117 if (!buffer)
return false;
2120 uint8_t* obegin =
reinterpret_cast<uint8_t*
>(buffer);
2121 uint8_t* oend = D::process(data, data_length, obegin,
utf8_writer());
2123 assert(oend == obegin + length);
2126 out_buffer = buffer;
2127 out_length = length + 1;
2132PUGI__FN
size_t get_latin1_7bit_prefix_length(
const uint8_t* data,
2134 for (
size_t i = 0; i < size; ++i)
2135 if (data[i] > 127)
return i;
2140PUGI__FN
bool convert_buffer_latin1(char_t*& out_buffer,
size_t& out_length,
2141 const void* contents,
size_t size,
2143 const uint8_t* data =
static_cast<const uint8_t*
>(contents);
2144 size_t data_length = size;
2147 size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
2148 assert(prefix_length <= data_length);
2150 const uint8_t* postfix = data + prefix_length;
2151 size_t postfix_length = data_length - prefix_length;
2154 if (postfix_length == 0)
2155 return get_mutable_buffer(out_buffer, out_length, contents, size,
2161 latin1_decoder::process(postfix, postfix_length, 0,
utf8_counter());
2165 static_cast<char_t*
>(xml_memory::allocate((length + 1) *
sizeof(char_t)));
2166 if (!buffer)
return false;
2169 memcpy(buffer, data, prefix_length);
2171 uint8_t* obegin =
reinterpret_cast<uint8_t*
>(buffer);
2172 uint8_t* oend = latin1_decoder::process(
2173 postfix, postfix_length, obegin + prefix_length,
utf8_writer());
2175 assert(oend == obegin + length);
2178 out_buffer = buffer;
2179 out_length = length + 1;
2184PUGI__FN
bool convert_buffer(char_t*& out_buffer,
size_t& out_length,
2185 xml_encoding encoding,
const void* contents,
2186 size_t size,
bool is_mutable) {
2188 if (encoding == encoding_utf8)
2189 return get_mutable_buffer(out_buffer, out_length, contents, size,
2193 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) {
2194 xml_encoding native_encoding =
2195 is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
2197 return (native_encoding == encoding)
2198 ? convert_buffer_generic(out_buffer, out_length, contents, size,
2200 : convert_buffer_generic(out_buffer, out_length, contents, size,
2205 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) {
2206 xml_encoding native_encoding =
2207 is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
2209 return (native_encoding == encoding)
2210 ? convert_buffer_generic(out_buffer, out_length, contents, size,
2212 : convert_buffer_generic(out_buffer, out_length, contents, size,
2217 if (encoding == encoding_latin1)
2218 return convert_buffer_latin1(out_buffer, out_length, contents, size,
2221 assert(
false &&
"Invalid encoding");
2226PUGI__FN
size_t as_utf8_begin(
const wchar_t* str,
size_t length) {
2228 return wchar_decoder::process(str, length, 0,
utf8_counter());
2231PUGI__FN
void as_utf8_end(
char* buffer,
size_t size,
const wchar_t* str,
2234 uint8_t* begin =
reinterpret_cast<uint8_t*
>(buffer);
2235 uint8_t* end = wchar_decoder::process(str, length, begin,
utf8_writer());
2237 assert(begin + size == end);
2242#ifndef PUGIXML_NO_STL
2243PUGI__FN std::string as_utf8_impl(
const wchar_t* str,
size_t length) {
2245 size_t size = as_utf8_begin(str, length);
2249 result.resize(size);
2252 if (size > 0) as_utf8_end(&result[0], size, str, length);
2257PUGI__FN std::basic_string<wchar_t> as_wide_impl(
const char* str,
size_t size) {
2258 const uint8_t* data =
reinterpret_cast<const uint8_t*
>(str);
2261 size_t length = utf8_decoder::process(data, size, 0, wchar_counter());
2264 std::basic_string<wchar_t> result;
2265 result.resize(length);
2269 wchar_writer::value_type begin =
2270 reinterpret_cast<wchar_writer::value_type
>(&result[0]);
2271 wchar_writer::value_type end =
2272 utf8_decoder::process(data, size, begin, wchar_writer());
2274 assert(begin + length == end);
2282template <
typename Header>
2283inline bool strcpy_insitu_allow(
size_t length,
const Header& header,
2284 uintptr_t header_mask, char_t* target) {
2286 if (header & xml_memory_page_contents_shared_mask)
return false;
2288 size_t target_length = strlength(target);
2291 if ((header & header_mask) == 0)
return target_length >= length;
2294 const size_t reuse_threshold = 32;
2296 return target_length >= length &&
2297 (target_length < reuse_threshold ||
2298 target_length - length < target_length / 2);
2301template <
typename String,
typename Header>
2302PUGI__FN
bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask,
2303 const char_t* source,
size_t source_length) {
2304 if (source_length == 0) {
2307 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
2309 if (header & header_mask) alloc->deallocate_string(dest);
2313 header &= ~header_mask;
2317 strcpy_insitu_allow(source_length, header, header_mask, dest)) {
2320 memcpy(dest, source, source_length *
sizeof(char_t));
2321 dest[source_length] = 0;
2325 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
2327 if (!alloc->reserve())
return false;
2330 char_t* buf = alloc->allocate_string(source_length + 1);
2331 if (!buf)
return false;
2334 memcpy(buf, source, source_length *
sizeof(char_t));
2335 buf[source_length] = 0;
2339 if (header & header_mask) alloc->deallocate_string(dest);
2343 header |= header_mask;
2353 gap() : end(0), size(0) {}
2357 void push(char_t*& s,
size_t count) {
2362 memmove(end - size, end,
2363 reinterpret_cast<char*
>(s) -
reinterpret_cast<char*
>(end));
2374 char_t* flush(char_t* s) {
2378 memmove(end - size, end,
2379 reinterpret_cast<char*
>(s) -
reinterpret_cast<char*
>(end));
2387PUGI__FN char_t* strconv_escape(char_t* s,
gap& g) {
2388 char_t* stre = s + 1;
2393 unsigned int ucsc = 0;
2401 if (ch ==
';')
return stre;
2404 if (
static_cast<unsigned int>(ch -
'0') <= 9)
2405 ucsc = 16 * ucsc + (ch -
'0');
2406 else if (
static_cast<unsigned int>((ch |
' ') -
'a') <= 5)
2407 ucsc = 16 * ucsc + ((ch |
' ') -
'a' + 10);
2419 char_t ch = *++stre;
2421 if (ch ==
';')
return stre;
2424 if (
static_cast<unsigned int>(
static_cast<unsigned int>(ch) -
'0') <=
2426 ucsc = 10 * ucsc + (ch -
'0');
2438#ifdef PUGIXML_WCHAR_MODE
2439 s =
reinterpret_cast<char_t*
>(wchar_writer::any(
2440 reinterpret_cast<wchar_writer::value_type
>(s), ucsc));
2442 s =
reinterpret_cast<char_t*
>(
2443 utf8_writer::any(
reinterpret_cast<uint8_t*
>(s), ucsc));
2446 g.push(s, stre - s);
2456 if (*++stre ==
'p' && *++stre ==
';')
2461 g.push(s, stre - s);
2464 }
else if (*stre ==
'p')
2466 if (*++stre ==
'o' && *++stre ==
's' && *++stre ==
';')
2471 g.push(s, stre - s);
2480 if (*++stre ==
't' && *++stre ==
';')
2485 g.push(s, stre - s);
2493 if (*++stre ==
't' && *++stre ==
';')
2498 g.push(s, stre - s);
2506 if (*++stre ==
'u' && *++stre ==
'o' && *++stre ==
't' &&
2512 g.push(s, stre - s);
2526#define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
2527#define PUGI__SKIPWS() \
2529 while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; \
2531#define PUGI__OPTSET(OPT) (optmsk & (OPT))
2532#define PUGI__PUSHNODE(TYPE) \
2534 cursor = append_new_node(cursor, *alloc, TYPE); \
2535 if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); \
2537#define PUGI__POPNODE() \
2538 { cursor = cursor->parent; }
2539#define PUGI__SCANFOR(X) \
2541 while (*s != 0 && !(X)) ++s; \
2543#define PUGI__SCANWHILE(X) \
2547#define PUGI__SCANWHILE_UNROLL(X) \
2551 if (PUGI__UNLIKELY(!(X))) { \
2555 if (PUGI__UNLIKELY(!(X))) { \
2560 if (PUGI__UNLIKELY(!(X))) { \
2565 if (PUGI__UNLIKELY(!(X))) { \
2572#define PUGI__ENDSEG() \
2578#define PUGI__THROW_ERROR(err, m) \
2579 return error_offset = m, error_status = err, static_cast<char_t*>(0)
2580#define PUGI__CHECK_ERROR(err, m) \
2582 if (*s == 0) PUGI__THROW_ERROR(err, m); \
2585PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) {
2589 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment));
2595 if (*s ==
'\n') g.push(s, 1);
2596 }
else if (s[0] ==
'-' && s[1] ==
'-' &&
2597 PUGI__ENDSWITH(s[2],
'>'))
2601 return s + (s[2] ==
'>' ? 3 : 2);
2602 }
else if (*s == 0) {
2609PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) {
2613 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata));
2619 if (*s ==
'\n') g.push(s, 1);
2620 }
else if (s[0] ==
']' && s[1] ==
']' &&
2621 PUGI__ENDSWITH(s[2],
'>'))
2626 }
else if (*s == 0) {
2633typedef char_t* (*strconv_pcdata_t)(char_t*);
2635template <
typename opt_trim,
typename opt_eol,
typename opt_escape>
2637 static char_t* parse(char_t* s) {
2643 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata));
2647 char_t* end = g.flush(s);
2649 if (opt_trim::value)
2650 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end;
2655 }
else if (opt_eol::value &&
2660 if (*s ==
'\n') g.push(s, 1);
2661 }
else if (opt_escape::value && *s ==
'&') {
2662 s = strconv_escape(s, g);
2663 }
else if (*s == 0) {
2664 char_t* end = g.flush(s);
2666 if (opt_trim::value)
2667 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) --end;
2678PUGI__FN strconv_pcdata_t get_strconv_pcdata(
unsigned int optmask) {
2679 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 &&
2680 parse_trim_pcdata == 0x0800);
2682 switch (((optmask >> 4) & 3) |
2683 ((optmask >> 9) & 4))
2707typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
2709template <
typename opt_escape>
2711 static char_t* parse_wnorm(char_t* s, char_t end_quote) {
2715 if (PUGI__IS_CHARTYPE(*s, ct_space)) {
2719 while (PUGI__IS_CHARTYPE(*str, ct_space));
2725 PUGI__SCANWHILE_UNROLL(
2726 !PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space));
2728 if (*s == end_quote) {
2729 char_t* str = g.flush(s);
2732 while (PUGI__IS_CHARTYPE(*str, ct_space));
2735 }
else if (PUGI__IS_CHARTYPE(*s, ct_space)) {
2738 if (PUGI__IS_CHARTYPE(*s, ct_space)) {
2739 char_t* str = s + 1;
2740 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
2744 }
else if (opt_escape::value && *s ==
'&') {
2745 s = strconv_escape(s, g);
2753 static char_t* parse_wconv(char_t* s, char_t end_quote) {
2757 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws));
2759 if (*s == end_quote) {
2763 }
else if (PUGI__IS_CHARTYPE(*s, ct_space)) {
2767 if (*s ==
'\n') g.push(s, 1);
2770 }
else if (opt_escape::value && *s ==
'&') {
2771 s = strconv_escape(s, g);
2779 static char_t* parse_eol(char_t* s, char_t end_quote) {
2783 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
2785 if (*s == end_quote) {
2789 }
else if (*s ==
'\r') {
2792 if (*s ==
'\n') g.push(s, 1);
2793 }
else if (opt_escape::value && *s ==
'&') {
2794 s = strconv_escape(s, g);
2802 static char_t* parse_simple(char_t* s, char_t end_quote) {
2806 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
2808 if (*s == end_quote) {
2812 }
else if (opt_escape::value && *s ==
'&') {
2813 s = strconv_escape(s, g);
2822PUGI__FN strconv_attribute_t get_strconv_attribute(
unsigned int optmask) {
2823 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 &&
2824 parse_wconv_attribute == 0x40 &&
2825 parse_wnorm_attribute == 0x80);
2827 switch ((optmask >> 4) &
2868inline xml_parse_result make_parse_result(xml_parse_status status,
2869 ptrdiff_t offset = 0) {
2870 xml_parse_result result;
2871 result.status = status;
2872 result.offset = offset;
2879 char_t* error_offset;
2880 xml_parse_status error_status;
2883 : alloc(alloc_), error_offset(0), error_status(status_ok) {}
2892 char_t* parse_doctype_primitive(char_t* s) {
2893 if (*s ==
'"' || *s ==
'\'') {
2896 PUGI__SCANFOR(*s == ch);
2897 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2900 }
else if (s[0] ==
'<' && s[1] ==
'?') {
2903 PUGI__SCANFOR(s[0] ==
'?' &&
2906 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2909 }
else if (s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'-' && s[3] ==
'-') {
2911 PUGI__SCANFOR(s[0] ==
'-' && s[1] ==
'-' &&
2914 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
2918 PUGI__THROW_ERROR(status_bad_doctype, s);
2923 char_t* parse_doctype_ignore(char_t* s) {
2926 assert(s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'[');
2930 if (s[0] ==
'<' && s[1] ==
'!' && s[2] ==
'[') {
2934 }
else if (s[0] ==
']' && s[1] ==
']' && s[2] ==
'>') {
2938 if (depth == 0)
return s;
2945 PUGI__THROW_ERROR(status_bad_doctype, s);
2948 char_t* parse_doctype_group(char_t* s, char_t endch) {
2951 assert((s[0] ==
'<' || s[0] == 0) && s[1] ==
'!');
2955 if (s[0] ==
'<' && s[1] ==
'!' && s[2] !=
'-') {
2958 s = parse_doctype_ignore(s);
2965 }
else if (s[0] ==
'<' || s[0] ==
'"' || s[0] ==
'\'') {
2967 s = parse_doctype_primitive(s);
2969 }
else if (*s ==
'>') {
2970 if (depth == 0)
return s;
2978 if (depth != 0 || endch !=
'>') PUGI__THROW_ERROR(status_bad_doctype, s);
2983 char_t* parse_exclamation(char_t* s, xml_node_struct* cursor,
2984 unsigned int optmsk, char_t endch) {
2996 if (PUGI__OPTSET(parse_comments)) {
2997 PUGI__PUSHNODE(node_comment);
3001 if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments)) {
3002 s = strconv_comment(s, endch);
3004 if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
3007 PUGI__SCANFOR(s[0] ==
'-' && s[1] ==
'-' &&
3008 PUGI__ENDSWITH(s[2],
'>'));
3009 PUGI__CHECK_ERROR(status_bad_comment, s);
3011 if (PUGI__OPTSET(parse_comments))
3015 s += (s[2] ==
'>' ? 3 : 2);
3018 PUGI__THROW_ERROR(status_bad_comment, s);
3019 }
else if (*s ==
'[') {
3021 if (*++s ==
'C' && *++s ==
'D' && *++s ==
'A' && *++s ==
'T' &&
3022 *++s ==
'A' && *++s ==
'[') {
3025 if (PUGI__OPTSET(parse_cdata)) {
3026 PUGI__PUSHNODE(node_cdata);
3029 if (PUGI__OPTSET(parse_eol)) {
3030 s = strconv_cdata(s, endch);
3032 if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
3035 PUGI__SCANFOR(s[0] ==
']' && s[1] ==
']' &&
3036 PUGI__ENDSWITH(s[2],
'>'));
3037 PUGI__CHECK_ERROR(status_bad_cdata, s);
3045 PUGI__SCANFOR(s[0] ==
']' && s[1] ==
']' &&
3046 PUGI__ENDSWITH(s[2],
'>'));
3047 PUGI__CHECK_ERROR(status_bad_cdata, s);
3052 s += (s[1] ==
'>' ? 2 : 1);
3054 PUGI__THROW_ERROR(status_bad_cdata, s);
3055 }
else if (s[0] ==
'D' && s[1] ==
'O' && s[2] ==
'C' && s[3] ==
'T' &&
3056 s[4] ==
'Y' && s[5] ==
'P' && PUGI__ENDSWITH(s[6],
'E')) {
3059 if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
3061 char_t* mark = s + 9;
3063 s = parse_doctype_group(s, endch);
3066 assert((*s == 0 && endch ==
'>') || *s ==
'>');
3069 if (PUGI__OPTSET(parse_doctype)) {
3070 while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
3072 PUGI__PUSHNODE(node_doctype);
3074 cursor->value = mark;
3076 }
else if (*s == 0 && endch ==
'-')
3077 PUGI__THROW_ERROR(status_bad_comment, s);
3078 else if (*s == 0 && endch ==
'[')
3079 PUGI__THROW_ERROR(status_bad_cdata, s);
3081 PUGI__THROW_ERROR(status_unrecognized_tag, s);
3086 char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor,
3087 unsigned int optmsk, char_t endch) {
3089 xml_node_struct* cursor = ref_cursor;
3098 if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol))
3099 PUGI__THROW_ERROR(status_bad_pi, s);
3101 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
3102 PUGI__CHECK_ERROR(status_bad_pi, s);
3105 bool declaration = (target[0] |
' ') ==
'x' && (target[1] |
' ') ==
'm' &&
3106 (target[2] |
' ') ==
'l' && target + 3 == s;
3108 if (declaration ? PUGI__OPTSET(parse_declaration)
3109 : PUGI__OPTSET(parse_pi)) {
3112 if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
3114 PUGI__PUSHNODE(node_declaration);
3116 PUGI__PUSHNODE(node_pi);
3119 cursor->name = target;
3126 if (!PUGI__ENDSWITH(*s,
'>')) PUGI__THROW_ERROR(status_bad_pi, s);
3130 }
else if (PUGI__IS_CHARTYPE(ch, ct_space)) {
3136 PUGI__SCANFOR(s[0] ==
'?' && PUGI__ENDSWITH(s[1],
'>'));
3137 PUGI__CHECK_ERROR(status_bad_pi, s);
3148 cursor->value = value;
3157 PUGI__THROW_ERROR(status_bad_pi, s);
3160 PUGI__SCANFOR(s[0] ==
'?' && PUGI__ENDSWITH(s[1],
'>'));
3161 PUGI__CHECK_ERROR(status_bad_pi, s);
3163 s += (s[1] ==
'>' ? 2 : 1);
3167 ref_cursor = cursor;
3172 char_t* parse_tree(char_t* s, xml_node_struct* root,
unsigned int optmsk,
3174 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
3175 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
3178 xml_node_struct* cursor = root;
3186 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
3188 PUGI__PUSHNODE(node_element);
3192 PUGI__SCANWHILE_UNROLL(
3193 PUGI__IS_CHARTYPE(ss, ct_symbol));
3198 }
else if (PUGI__IS_CHARTYPE(ch, ct_space)) {
3203 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
3205 xml_attribute_struct* a = append_new_attribute(
3207 if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
3211 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(
3215 if (PUGI__IS_CHARTYPE(ch, ct_space)) {
3226 if (*s ==
'"' || *s ==
'\'')
3233 s = strconv_attribute(s, ch);
3235 if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
3240 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
3241 PUGI__THROW_ERROR(status_bad_attribute, s);
3243 PUGI__THROW_ERROR(status_bad_attribute, s);
3245 PUGI__THROW_ERROR(status_bad_attribute, s);
3246 }
else if (*s ==
'/') {
3253 }
else if (*s == 0 && endch ==
'>') {
3257 PUGI__THROW_ERROR(status_bad_start_element, s);
3258 }
else if (*s ==
'>') {
3262 }
else if (*s == 0 && endch ==
'>') {
3265 PUGI__THROW_ERROR(status_bad_start_element, s);
3269 }
else if (ch ==
'/')
3271 if (!PUGI__ENDSWITH(*s,
'>'))
3272 PUGI__THROW_ERROR(status_bad_start_element, s);
3277 }
else if (ch == 0) {
3281 if (endch !=
'>') PUGI__THROW_ERROR(status_bad_start_element, s);
3283 PUGI__THROW_ERROR(status_bad_start_element, s);
3284 }
else if (*s ==
'/') {
3289 char_t* name = cursor->name;
3290 if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
3292 while (PUGI__IS_CHARTYPE(*s, ct_symbol)) {
3293 if (*s++ != *name++)
3294 PUGI__THROW_ERROR(status_end_element_mismatch, mark);
3298 if (*s == 0 && name[0] == endch && name[1] == 0)
3299 PUGI__THROW_ERROR(status_bad_end_element, s);
3301 PUGI__THROW_ERROR(status_end_element_mismatch, mark);
3309 if (endch !=
'>') PUGI__THROW_ERROR(status_bad_end_element, s);
3311 if (*s !=
'>') PUGI__THROW_ERROR(status_bad_end_element, s);
3314 }
else if (*s ==
'?')
3316 s = parse_question(s, cursor, optmsk, endch);
3320 if (PUGI__NODETYPE(cursor) == node_declaration)
goto LOC_ATTRIBUTES;
3321 }
else if (*s ==
'!')
3323 s = parse_exclamation(s, cursor, optmsk, endch);
3325 }
else if (*s == 0 && endch ==
'?')
3326 PUGI__THROW_ERROR(status_bad_pi, s);
3328 PUGI__THROW_ERROR(status_unrecognized_tag, s);
3334 if (*s ==
'<' || !*s) {
3339 if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) ||
3340 PUGI__OPTSET(parse_trim_pcdata)) {
3342 }
else if (PUGI__OPTSET(parse_ws_pcdata_single)) {
3343 if (s[0] !=
'<' || s[1] !=
'/' || cursor->first_child)
continue;
3347 if (!PUGI__OPTSET(parse_trim_pcdata)) s = mark;
3349 if (cursor->parent || PUGI__OPTSET(parse_fragment)) {
3350 if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent &&
3351 !cursor->first_child && !cursor->value) {
3354 PUGI__PUSHNODE(node_pcdata);
3361 s = strconv_pcdata(s);
3365 PUGI__SCANFOR(*s ==
'<');
3377 if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s);
3382#ifdef PUGIXML_WCHAR_MODE
3383 static char_t* parse_skip_bom(char_t* s) {
3384 unsigned int bom = 0xfeff;
3385 return (s[0] ==
static_cast<wchar_t>(bom)) ? s + 1 : s;
3388 static char_t* parse_skip_bom(char_t* s) {
3389 return (s[0] ==
'\xef' && s[1] ==
'\xbb' && s[2] ==
'\xbf') ? s + 3 : s;
3393 static bool has_element_node_siblings(xml_node_struct* node) {
3395 if (PUGI__NODETYPE(node) == node_element)
return true;
3397 node = node->next_sibling;
3403 static xml_parse_result parse(char_t* buffer,
size_t length,
3405 xml_node_struct* root,
unsigned int optmsk) {
3408 return make_parse_result(PUGI__OPTSET(parse_fragment)
3410 : status_no_document_element);
3413 xml_node_struct* last_root_child =
3414 root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
3420 char_t endch = buffer[length - 1];
3421 buffer[length - 1] = 0;
3424 char_t* buffer_data = parse_skip_bom(buffer);
3427 parser.parse_tree(buffer_data, root, optmsk, endch);
3429 xml_parse_result result = make_parse_result(
3430 parser.error_status,
3431 parser.error_offset ? parser.error_offset - buffer : 0);
3432 assert(result.offset >= 0 &&
static_cast<size_t>(result.offset) <= length);
3438 return make_parse_result(status_unrecognized_tag, length - 1);
3441 xml_node_struct* first_root_child_parsed =
3442 last_root_child ? last_root_child->next_sibling + 0
3443 : root->first_child + 0;
3445 if (!PUGI__OPTSET(parse_fragment) &&
3446 !has_element_node_siblings(first_root_child_parsed))
3447 return make_parse_result(status_no_document_element, length - 1);
3450 if (result.offset > 0 &&
3451 static_cast<size_t>(result.offset) == length - 1 && endch == 0)
3460PUGI__FN xml_encoding get_write_native_encoding() {
3461#ifdef PUGIXML_WCHAR_MODE
3462 return get_wchar_encoding();
3464 return encoding_utf8;
3468PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding) {
3470 if (encoding == encoding_wchar)
return get_wchar_encoding();
3473 if (encoding == encoding_utf16)
3474 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
3477 if (encoding == encoding_utf32)
3478 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
3481 if (encoding != encoding_auto)
return encoding;
3484 return encoding_utf8;
3487template <
typename D,
typename T>
3488PUGI__FN
size_t convert_buffer_output_generic(
typename T::value_type dest,
3489 const char_t* data,
size_t length,
3491 PUGI__STATIC_ASSERT(
sizeof(char_t) ==
sizeof(
typename D::type));
3493 typename T::value_type end = D::process(
3494 reinterpret_cast<const typename D::type*
>(data), length, dest, T());
3496 return static_cast<size_t>(end - dest) *
sizeof(*dest);
3499template <
typename D,
typename T>
3500PUGI__FN
size_t convert_buffer_output_generic(
typename T::value_type dest,
3501 const char_t* data,
size_t length,
3502 D, T,
bool opt_swap) {
3503 PUGI__STATIC_ASSERT(
sizeof(char_t) ==
sizeof(
typename D::type));
3505 typename T::value_type end = D::process(
3506 reinterpret_cast<const typename D::type*
>(data), length, dest, T());
3509 for (
typename T::value_type i = dest; i != end; ++i) *i = endian_swap(*i);
3512 return static_cast<size_t>(end - dest) *
sizeof(*dest);
3515#ifdef PUGIXML_WCHAR_MODE
3516PUGI__FN
size_t get_valid_length(
const char_t* data,
size_t length) {
3517 if (length < 1)
return 0;
3520 return (
sizeof(
wchar_t) == 2 &&
3521 static_cast<unsigned int>(
static_cast<uint16_t
>(data[length - 1]) -
3527PUGI__FN
size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8,
3528 uint16_t* r_u16, uint32_t* r_u32,
3529 const char_t* data,
size_t length,
3530 xml_encoding encoding) {
3532 if (need_endian_swap_utf(encoding, get_wchar_encoding())) {
3533 convert_wchar_endian_swap(r_char, data, length);
3535 return length *
sizeof(char_t);
3539 if (encoding == encoding_utf8)
3540 return convert_buffer_output_generic(r_u8, data, length,
wchar_decoder(),
3544 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) {
3545 xml_encoding native_encoding =
3546 is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
3548 return convert_buffer_output_generic(r_u16, data, length,
wchar_decoder(),
3550 native_encoding != encoding);
3554 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) {
3555 xml_encoding native_encoding =
3556 is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
3558 return convert_buffer_output_generic(r_u32, data, length,
wchar_decoder(),
3560 native_encoding != encoding);
3564 if (encoding == encoding_latin1)
3565 return convert_buffer_output_generic(r_u8, data, length,
wchar_decoder(),
3568 assert(
false &&
"Invalid encoding");
3572PUGI__FN
size_t get_valid_length(
const char_t* data,
size_t length) {
3573 if (length < 5)
return 0;
3575 for (
size_t i = 1; i <= 4; ++i) {
3576 uint8_t ch =
static_cast<uint8_t
>(data[length - i]);
3579 if ((ch & 0xc0) != 0x80)
return length - i;
3587PUGI__FN
size_t convert_buffer_output(char_t* , uint8_t* r_u8,
3588 uint16_t* r_u16, uint32_t* r_u32,
3589 const char_t* data,
size_t length,
3590 xml_encoding encoding) {
3591 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le) {
3592 xml_encoding native_encoding =
3593 is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
3595 return convert_buffer_output_generic(r_u16, data, length,
utf8_decoder(),
3597 native_encoding != encoding);
3600 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le) {
3601 xml_encoding native_encoding =
3602 is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
3604 return convert_buffer_output_generic(r_u32, data, length,
utf8_decoder(),
3606 native_encoding != encoding);
3609 if (encoding == encoding_latin1)
3610 return convert_buffer_output_generic(r_u8, data, length,
utf8_decoder(),
3613 assert(
false &&
"Invalid encoding");
3626 encoding(get_write_encoding(user_encoding)) {
3627 PUGI__STATIC_ASSERT(bufcapacity >= 8);
3631 flush(buffer, bufsize);
3636 void flush(
const char_t* data,
size_t size) {
3637 if (size == 0)
return;
3640 if (encoding == get_write_native_encoding())
3641 writer.write(data, size *
sizeof(char_t));
3644 size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8,
3645 scratch.data_u16, scratch.data_u32,
3646 data, size, encoding);
3647 assert(result <=
sizeof(scratch));
3650 writer.write(scratch.data_u8, result);
3654 void write_direct(
const char_t* data,
size_t length) {
3659 if (length > bufcapacity) {
3660 if (encoding == get_write_native_encoding()) {
3662 writer.write(data, length *
sizeof(char_t));
3667 while (length > bufcapacity) {
3671 size_t chunk_size = get_valid_length(data, bufcapacity);
3675 flush(data, chunk_size);
3679 length -= chunk_size;
3686 memcpy(buffer + bufsize, data, length *
sizeof(char_t));
3690 void write_buffer(
const char_t* data,
size_t length) {
3691 size_t offset = bufsize;
3693 if (offset + length <= bufcapacity) {
3694 memcpy(buffer + offset, data, length *
sizeof(char_t));
3695 bufsize = offset + length;
3697 write_direct(data, length);
3701 void write_string(
const char_t* data) {
3703 size_t offset = bufsize;
3705 while (*data && offset < bufcapacity) buffer[offset++] = *data++;
3708 if (offset < bufcapacity) {
3712 size_t length = offset - bufsize;
3713 size_t extra = length - get_valid_length(data - length, length);
3715 bufsize = offset - extra;
3717 write_direct(data - extra, strlength(data) + extra);
3721 void write(char_t d0) {
3722 size_t offset = bufsize;
3723 if (offset > bufcapacity - 1) offset = flush();
3725 buffer[offset + 0] = d0;
3726 bufsize = offset + 1;
3729 void write(char_t d0, char_t d1) {
3730 size_t offset = bufsize;
3731 if (offset > bufcapacity - 2) offset = flush();
3733 buffer[offset + 0] = d0;
3734 buffer[offset + 1] = d1;
3735 bufsize = offset + 2;
3738 void write(char_t d0, char_t d1, char_t d2) {
3739 size_t offset = bufsize;
3740 if (offset > bufcapacity - 3) offset = flush();
3742 buffer[offset + 0] = d0;
3743 buffer[offset + 1] = d1;
3744 buffer[offset + 2] = d2;
3745 bufsize = offset + 3;
3748 void write(char_t d0, char_t d1, char_t d2, char_t d3) {
3749 size_t offset = bufsize;
3750 if (offset > bufcapacity - 4) offset = flush();
3752 buffer[offset + 0] = d0;
3753 buffer[offset + 1] = d1;
3754 buffer[offset + 2] = d2;
3755 buffer[offset + 3] = d3;
3756 bufsize = offset + 4;
3759 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4) {
3760 size_t offset = bufsize;
3761 if (offset > bufcapacity - 5) offset = flush();
3763 buffer[offset + 0] = d0;
3764 buffer[offset + 1] = d1;
3765 buffer[offset + 2] = d2;
3766 buffer[offset + 3] = d3;
3767 buffer[offset + 4] = d4;
3768 bufsize = offset + 5;
3771 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5) {
3772 size_t offset = bufsize;
3773 if (offset > bufcapacity - 6) offset = flush();
3775 buffer[offset + 0] = d0;
3776 buffer[offset + 1] = d1;
3777 buffer[offset + 2] = d2;
3778 buffer[offset + 3] = d3;
3779 buffer[offset + 4] = d4;
3780 buffer[offset + 5] = d5;
3781 bufsize = offset + 6;
3789#ifdef PUGIXML_MEMORY_OUTPUT_STACK
3790 PUGIXML_MEMORY_OUTPUT_STACK
3795 bufcapacity = bufcapacitybytes / (
sizeof(char_t) + 4)
3798 char_t buffer[bufcapacity];
3801 uint8_t data_u8[4 * bufcapacity];
3802 uint16_t data_u16[2 * bufcapacity];
3803 uint32_t data_u32[bufcapacity];
3804 char_t data_char[bufcapacity];
3809 xml_encoding encoding;
3815 const char_t* prev = s;
3818 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type));
3820 writer.write_buffer(prev,
static_cast<size_t>(s - prev));
3826 writer.write(
'&',
'a',
'm',
'p',
';');
3830 writer.write(
'&',
'l',
't',
';');
3834 writer.write(
'&',
'g',
't',
';');
3838 writer.write(
'&',
'q',
'u',
'o',
't',
';');
3843 unsigned int ch =
static_cast<unsigned int>(*s++);
3846 writer.write(
'&',
'#',
static_cast<char_t
>((ch / 10) +
'0'),
3847 static_cast<char_t
>((ch % 10) +
'0'),
';');
3854 chartypex_t type,
unsigned int flags) {
3855 if (flags & format_no_escapes)
3856 writer.write_string(s);
3858 text_output_escaped(writer, s, type);
3863 writer.write(
'<',
'!',
'[',
'C',
'D');
3864 writer.write(
'A',
'T',
'A',
'[');
3866 const char_t* prev = s;
3870 while (*s && !(s[0] ==
']' && s[1] ==
']' && s[2] ==
'>')) ++s;
3875 writer.write_buffer(prev,
static_cast<size_t>(s - prev));
3877 writer.write(
']',
']',
'>');
3882 const char_t* indent,
size_t indent_length,
3883 unsigned int depth) {
3884 switch (indent_length) {
3886 for (
unsigned int i = 0; i < depth; ++i) writer.write(indent[0]);
3891 for (
unsigned int i = 0; i < depth; ++i)
3892 writer.write(indent[0], indent[1]);
3897 for (
unsigned int i = 0; i < depth; ++i)
3898 writer.write(indent[0], indent[1], indent[2]);
3903 for (
unsigned int i = 0; i < depth; ++i)
3904 writer.write(indent[0], indent[1], indent[2], indent[3]);
3909 for (
unsigned int i = 0; i < depth; ++i)
3910 writer.write_buffer(indent, indent_length);
3917 writer.write(
'<',
'!',
'-',
'-');
3920 const char_t* prev = s;
3924 while (*s && !(s[0] ==
'-' && (s[1] ==
'-' || s[1] == 0))) ++s;
3926 writer.write_buffer(prev,
static_cast<size_t>(s - prev));
3931 writer.write(
'-',
' ');
3936 writer.write(
'-',
'-',
'>');
3942 const char_t* prev = s;
3945 while (*s && !(s[0] ==
'?' && s[1] ==
'>')) ++s;
3947 writer.write_buffer(prev,
static_cast<size_t>(s - prev));
3950 assert(s[0] ==
'?' && s[1] ==
'>');
3952 writer.write(
'?',
' ',
'>');
3959 xml_node_struct* node,
3960 const char_t* indent,
size_t indent_length,
3961 unsigned int flags,
unsigned int depth) {
3962 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
3964 for (xml_attribute_struct* a = node->first_attribute; a;
3965 a = a->next_attribute) {
3966 if ((flags & (format_indent_attributes | format_raw)) ==
3967 format_indent_attributes) {
3970 text_output_indent(writer, indent, indent_length, depth + 1);
3975 writer.write_string(a->name ? a->name + 0 : default_name);
3976 writer.write(
'=',
'"');
3978 if (a->value) text_output(writer, a->value, ctx_special_attr, flags);
3985 xml_node_struct* node,
const char_t* indent,
3986 size_t indent_length,
unsigned int flags,
3987 unsigned int depth) {
3988 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
3989 const char_t* name = node->name ? node->name + 0 : default_name;
3992 writer.write_string(name);
3994 if (node->first_attribute)
3995 node_output_attributes(writer, node, indent, indent_length, flags, depth);
3999 if (!node->first_child) {
4000 if (flags & format_no_empty_element_tags) {
4001 writer.write(
'>',
'<',
'/');
4002 writer.write_string(name);
4007 if ((flags & format_raw) == 0) writer.write(
' ');
4009 writer.write(
'/',
'>');
4021 text_output(writer, node->value, ctx_special_pcdata, flags);
4023 if (!node->first_child) {
4024 writer.write(
'<',
'/');
4025 writer.write_string(name);
4036 xml_node_struct* node) {
4037 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
4038 const char_t* name = node->name ? node->name + 0 : default_name;
4040 writer.write(
'<',
'/');
4041 writer.write_string(name);
4046 xml_node_struct* node,
unsigned int flags) {
4047 const char_t* default_name = PUGIXML_TEXT(
":anonymous");
4049 switch (PUGI__NODETYPE(node)) {
4051 text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(
""),
4052 ctx_special_pcdata, flags);
4056 text_output_cdata(writer,
4057 node->value ? node->value + 0 : PUGIXML_TEXT(
""));
4061 node_output_comment(writer,
4062 node->value ? node->value + 0 : PUGIXML_TEXT(
""));
4066 writer.write(
'<',
'?');
4067 writer.write_string(node->name ? node->name + 0 : default_name);
4071 node_output_pi_value(writer, node->value);
4074 writer.write(
'?',
'>');
4077 case node_declaration:
4078 writer.write(
'<',
'?');
4079 writer.write_string(node->name ? node->name + 0 : default_name);
4080 node_output_attributes(writer, node, PUGIXML_TEXT(
""), 0,
4081 flags | format_raw, 0);
4082 writer.write(
'?',
'>');
4086 writer.write(
'<',
'!',
'D',
'O',
'C');
4087 writer.write(
'T',
'Y',
'P',
'E');
4091 writer.write_string(node->value);
4098 assert(
false &&
"Invalid node type");
4102enum indent_flags_t { indent_newline = 1, indent_indent = 2 };
4105 const char_t* indent,
unsigned int flags,
4106 unsigned int depth) {
4107 size_t indent_length =
4108 ((flags & (format_indent | format_indent_attributes)) &&
4109 (flags & format_raw) == 0)
4112 unsigned int indent_flags = indent_indent;
4114 xml_node_struct* node = root;
4120 if (PUGI__NODETYPE(node) == node_pcdata ||
4121 PUGI__NODETYPE(node) == node_cdata) {
4122 node_output_simple(writer, node, flags);
4126 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4129 if ((indent_flags & indent_indent) && indent_length)
4130 text_output_indent(writer, indent, indent_length, depth);
4132 if (PUGI__NODETYPE(node) == node_element) {
4133 indent_flags = indent_newline | indent_indent;
4135 if (node_output_start(writer, node, indent, indent_length, flags,
4138 if (node->value) indent_flags = 0;
4140 node = node->first_child;
4144 }
else if (PUGI__NODETYPE(node) == node_document) {
4145 indent_flags = indent_indent;
4147 if (node->first_child) {
4148 node = node->first_child;
4152 node_output_simple(writer, node, flags);
4154 indent_flags = indent_newline | indent_indent;
4159 while (node != root) {
4160 if (node->next_sibling) {
4161 node = node->next_sibling;
4165 node = node->parent;
4168 if (PUGI__NODETYPE(node) == node_element) {
4171 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4174 if ((indent_flags & indent_indent) && indent_length)
4175 text_output_indent(writer, indent, indent_length, depth);
4177 node_output_end(writer, node);
4179 indent_flags = indent_newline | indent_indent;
4182 }
while (node != root);
4184 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
4188PUGI__FN
bool has_declaration(xml_node_struct* node) {
4189 for (xml_node_struct* child = node->first_child; child;
4190 child = child->next_sibling) {
4191 xml_node_type type = PUGI__NODETYPE(child);
4193 if (type == node_declaration)
return true;
4194 if (type == node_element)
return false;
4200PUGI__FN
bool is_attribute_of(xml_attribute_struct* attr,
4201 xml_node_struct* node) {
4202 for (xml_attribute_struct* a = node->first_attribute; a;
4203 a = a->next_attribute)
4204 if (a == attr)
return true;
4209PUGI__FN
bool allow_insert_attribute(xml_node_type parent) {
4210 return parent == node_element || parent == node_declaration;
4213PUGI__FN
bool allow_insert_child(xml_node_type parent, xml_node_type child) {
4214 if (parent != node_document && parent != node_element)
return false;
4215 if (child == node_document || child == node_null)
return false;
4216 if (parent != node_document &&
4217 (child == node_declaration || child == node_doctype))
4223PUGI__FN
bool allow_move(xml_node parent, xml_node child) {
4225 if (!allow_insert_child(parent.type(), child.type()))
return false;
4228 if (parent.root() != child.root())
return false;
4231 xml_node cur = parent;
4234 if (cur == child)
return false;
4242template <
typename String,
typename Header>
4243PUGI__FN
void node_copy_string(String& dest, Header& header,
4244 uintptr_t header_mask, char_t* source,
4246 assert(!dest && (header & header_mask) == 0);
4249 if (alloc && (source_header & header_mask) == 0) {
4254 header |= xml_memory_page_contents_shared_mask;
4255 source_header |= xml_memory_page_contents_shared_mask;
4257 strcpy_insitu(dest, header, header_mask, source, strlength(source));
4261PUGI__FN
void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn,
4263 node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask,
4264 sn->name, sn->header, shared_alloc);
4265 node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask,
4266 sn->value, sn->header, shared_alloc);
4268 for (xml_attribute_struct* sa = sn->first_attribute; sa;
4269 sa = sa->next_attribute) {
4270 xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn));
4273 node_copy_string(da->name, da->header,
4274 xml_memory_page_name_allocated_mask, sa->name,
4275 sa->header, shared_alloc);
4276 node_copy_string(da->value, da->header,
4277 xml_memory_page_value_allocated_mask, sa->value,
4278 sa->header, shared_alloc);
4283PUGI__FN
void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn) {
4285 xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0;
4287 node_copy_contents(dn, sn, shared_alloc);
4289 xml_node_struct* dit = dn;
4290 xml_node_struct* sit = sn->first_child;
4292 while (sit && sit != sn) {
4294 xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit));
4297 node_copy_contents(copy, sit, shared_alloc);
4299 if (sit->first_child) {
4301 sit = sit->first_child;
4309 if (sit->next_sibling) {
4310 sit = sit->next_sibling;
4316 }
while (sit != sn);
4320PUGI__FN
void node_copy_attribute(xml_attribute_struct* da,
4321 xml_attribute_struct* sa) {
4323 xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0;
4325 node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask,
4326 sa->name, sa->header, shared_alloc);
4327 node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask,
4328 sa->value, sa->header, shared_alloc);
4331inline bool is_text_node(xml_node_struct* node) {
4332 xml_node_type type = PUGI__NODETYPE(node);
4334 return type == node_pcdata || type == node_cdata;
4338template <
typename U>
4339U string_to_integer(
const char_t* value, U minneg, U maxpos) {
4341 const char_t* s = value;
4343 while (PUGI__IS_CHARTYPE(*s, ct_space)) s++;
4345 bool negative = (*s ==
'-');
4347 s += (*s ==
'+' || *s ==
'-');
4349 bool overflow =
false;
4351 if (s[0] ==
'0' && (s[1] |
' ') ==
'x') {
4356 while (*s ==
'0') s++;
4358 const char_t* start = s;
4361 if (
static_cast<unsigned>(*s -
'0') < 10)
4362 result = result * 16 + (*s -
'0');
4363 else if (
static_cast<unsigned>((*s |
' ') -
'a') < 6)
4364 result = result * 16 + ((*s |
' ') -
'a' + 10);
4371 size_t digits =
static_cast<size_t>(s - start);
4373 overflow = digits >
sizeof(U) * 2;
4377 while (*s ==
'0') s++;
4379 const char_t* start = s;
4382 if (
static_cast<unsigned>(*s -
'0') < 10)
4383 result = result * 10 + (*s -
'0');
4390 size_t digits =
static_cast<size_t>(s - start);
4392 PUGI__STATIC_ASSERT(
sizeof(U) == 8 ||
sizeof(U) == 4 ||
sizeof(U) == 2);
4394 const size_t max_digits10 =
sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
4395 const char_t max_lead =
sizeof(U) == 8 ?
'1' : sizeof(U) == 4 ?
'4' :
'6';
4396 const size_t high_bit =
sizeof(U) * 8 - 1;
4399 digits >= max_digits10 &&
4400 !(digits == max_digits10 &&
4401 (*start < max_lead || (*start == max_lead && result >> high_bit)));
4405 return (overflow || result > minneg) ? 0 - minneg : 0 - result;
4407 return (overflow || result > maxpos) ? maxpos : result;
4410PUGI__FN
int get_value_int(
const char_t* value) {
4411 return string_to_integer<unsigned int>(
4412 value, 0 -
static_cast<unsigned int>(INT_MIN), INT_MAX);
4415PUGI__FN
unsigned int get_value_uint(
const char_t* value) {
4416 return string_to_integer<unsigned int>(value, 0, UINT_MAX);
4419PUGI__FN
double get_value_double(
const char_t* value) {
4420#ifdef PUGIXML_WCHAR_MODE
4421 return wcstod(value, 0);
4423 return strtod(value, 0);
4427PUGI__FN
float get_value_float(
const char_t* value) {
4428#ifdef PUGIXML_WCHAR_MODE
4429 return static_cast<float>(wcstod(value, 0));
4431 return static_cast<float>(strtod(value, 0));
4435PUGI__FN
bool get_value_bool(
const char_t* value) {
4437 char_t first = *value;
4440 return (first ==
'1' || first ==
't' || first ==
'T' || first ==
'y' ||
4444#ifdef PUGIXML_HAS_LONG_LONG
4445PUGI__FN
long long get_value_llong(
const char_t* value) {
4446 return string_to_integer<unsigned long long>(
4447 value, 0 -
static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);
4450PUGI__FN
unsigned long long get_value_ullong(
const char_t* value) {
4451 return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);
4455template <
typename U>
4456PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value,
4458 char_t* result = end - 1;
4459 U rest = negative ? 0 - value : value;
4462 *result-- =
static_cast<char_t
>(
'0' + (rest % 10));
4466 assert(result >= begin);
4471 return result + !negative;
4475template <
typename String,
typename Header>
4476PUGI__FN
bool set_value_ascii(String& dest, Header& header,
4477 uintptr_t header_mask,
char* buf) {
4478#ifdef PUGIXML_WCHAR_MODE
4480 assert(strlen(buf) <
sizeof(wbuf) /
sizeof(wbuf[0]));
4483 for (; buf[offset]; ++offset) wbuf[offset] = buf[offset];
4485 return strcpy_insitu(dest, header, header_mask, wbuf, offset);
4487 return strcpy_insitu(dest, header, header_mask, buf, strlen(buf));
4491template <
typename U,
typename String,
typename Header>
4492PUGI__FN
bool set_value_integer(String& dest, Header& header,
4493 uintptr_t header_mask, U value,
bool negative) {
4495 char_t* end = buf +
sizeof(buf) /
sizeof(buf[0]);
4496 char_t* begin = integer_to_string(buf, end, value, negative);
4498 return strcpy_insitu(dest, header, header_mask, begin, end - begin);
4501template <
typename String,
typename Header>
4502PUGI__FN
bool set_value_convert(String& dest, Header& header,
4503 uintptr_t header_mask,
float value) {
4505 sprintf(buf,
"%.9g", value);
4507 return set_value_ascii(dest, header, header_mask, buf);
4510template <
typename String,
typename Header>
4511PUGI__FN
bool set_value_convert(String& dest, Header& header,
4512 uintptr_t header_mask,
double value) {
4514 sprintf(buf,
"%.17g", value);
4516 return set_value_ascii(dest, header, header_mask, buf);
4519template <
typename String,
typename Header>
4520PUGI__FN
bool set_value_bool(String& dest, Header& header,
4521 uintptr_t header_mask,
bool value) {
4522 return strcpy_insitu(dest, header, header_mask,
4523 value ? PUGIXML_TEXT(
"true") : PUGIXML_TEXT(
"false"),
4527PUGI__FN xml_parse_result load_buffer_impl(
4529 size_t size,
unsigned int options, xml_encoding encoding,
bool is_mutable,
4530 bool own, char_t** out_buffer) {
4532 if (!contents && size)
return make_parse_result(status_io_error);
4535 xml_encoding buffer_encoding =
4536 impl::get_buffer_encoding(encoding, contents, size);
4542 if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size,
4544 return impl::make_parse_result(status_out_of_memory);
4547 if (own && buffer != contents && contents)
4548 impl::xml_memory::deallocate(contents);
4552 if (own || buffer != contents) *out_buffer = buffer;
4555 doc->buffer = buffer;
4558 xml_parse_result res =
4559 impl::xml_parser::parse(buffer, length, doc, root,
options);
4562 res.encoding = buffer_encoding;
4569PUGI__FN xml_parse_status get_file_size(FILE* file,
size_t& out_result) {
4570#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && \
4571 !defined(_WIN32_WCE)
4573 typedef __int64 length_type;
4575 _fseeki64(file, 0, SEEK_END);
4576 length_type length = _ftelli64(file);
4577 _fseeki64(file, 0, SEEK_SET);
4578#elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && \
4579 (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))
4581 typedef off64_t length_type;
4583 fseeko64(file, 0, SEEK_END);
4584 length_type length = ftello64(file);
4585 fseeko64(file, 0, SEEK_SET);
4589 typedef long length_type;
4591 fseek(file, 0, SEEK_END);
4592 length_type length = ftell(file);
4593 fseek(file, 0, SEEK_SET);
4597 if (length < 0)
return status_io_error;
4600 size_t result =
static_cast<size_t>(length);
4602 if (
static_cast<length_type
>(result) != length)
return status_out_of_memory;
4605 out_result = result;
4612PUGI__FN
size_t zero_terminate_buffer(
void* buffer,
size_t size,
4613 xml_encoding encoding) {
4615#ifdef PUGIXML_WCHAR_MODE
4616 xml_encoding wchar_encoding = get_wchar_encoding();
4618 if (encoding == wchar_encoding ||
4619 need_endian_swap_utf(encoding, wchar_encoding)) {
4620 size_t length = size /
sizeof(char_t);
4622 static_cast<char_t*
>(buffer)[length] = 0;
4623 return (length + 1) *
sizeof(char_t);
4626 if (encoding == encoding_utf8) {
4627 static_cast<char*
>(buffer)[size] = 0;
4637 xml_encoding encoding,
4638 char_t** out_buffer) {
4639 if (!file)
return make_parse_result(status_file_not_found);
4643 xml_parse_status size_status = get_file_size(file, size);
4644 if (size_status != status_ok)
return make_parse_result(size_status);
4646 size_t max_suffix_size =
sizeof(char_t);
4650 static_cast<char*
>(xml_memory::allocate(size + max_suffix_size));
4651 if (!contents)
return make_parse_result(status_out_of_memory);
4654 size_t read_size = fread(contents, 1, size, file);
4656 if (read_size != size) {
4657 xml_memory::deallocate(contents);
4658 return make_parse_result(status_io_error);
4661 xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
4663 return load_buffer_impl(doc, doc, contents,
4664 zero_terminate_buffer(contents, size, real_encoding),
4665 options, real_encoding,
true,
true, out_buffer);
4668PUGI__FN
void close_file(FILE* file) { fclose(file); }
4670#ifndef PUGIXML_NO_STL
4671template <
typename T>
4675 if (!memory)
return 0;
4685 xml_memory::deallocate(chunk);
4696 T data[xml_memory_page_size /
sizeof(T)];
4699template <
typename T>
4700PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream,
4709 while (!stream.eof()) {
4712 if (!chunk)
return status_out_of_memory;
4716 last = last->next = chunk;
4718 chunks.data = last = chunk;
4721 stream.read(chunk->data,
4722 static_cast<std::streamsize
>(
sizeof(chunk->data) /
sizeof(T)));
4723 chunk->size =
static_cast<size_t>(stream.gcount()) *
sizeof(T);
4727 if (stream.bad() || (!stream.eof() && stream.fail()))
4728 return status_io_error;
4732 if (total + chunk->size < total)
return status_out_of_memory;
4733 total += chunk->size;
4736 size_t max_suffix_size =
sizeof(char_t);
4740 static_cast<char*
>(xml_memory::allocate(total + max_suffix_size));
4741 if (!buffer)
return status_out_of_memory;
4743 char* write = buffer;
4746 assert(write + chunk->size <= buffer + total);
4747 memcpy(write, chunk->data, chunk->size);
4748 write += chunk->size;
4751 assert(write == buffer + total);
4754 *out_buffer = buffer;
4760template <
typename T>
4761PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream,
4765 typename std::basic_istream<T>::pos_type pos = stream.tellg();
4766 stream.seekg(0, std::ios::end);
4767 std::streamoff length = stream.tellg() - pos;
4770 if (stream.fail() || pos < 0)
return status_io_error;
4773 size_t read_length =
static_cast<size_t>(length);
4775 if (
static_cast<std::streamsize
>(read_length) != length || length < 0)
4776 return status_out_of_memory;
4778 size_t max_suffix_size =
sizeof(char_t);
4783 xml_memory::allocate(read_length *
sizeof(T) + max_suffix_size),
4784 xml_memory::deallocate);
4785 if (!buffer.data)
return status_out_of_memory;
4787 stream.read(
static_cast<T*
>(buffer.data),
4788 static_cast<std::streamsize
>(read_length));
4792 if (stream.bad() || (!stream.eof() && stream.fail()))
return status_io_error;
4795 size_t actual_length =
static_cast<size_t>(stream.gcount());
4796 assert(actual_length <= read_length);
4798 *out_buffer = buffer.release();
4799 *out_size = actual_length *
sizeof(T);
4804template <
typename T>
4806 std::basic_istream<T>& stream,
4808 xml_encoding encoding,
4809 char_t** out_buffer) {
4812 xml_parse_status status = status_ok;
4816 if (stream.fail())
return make_parse_result(status_io_error);
4820 if (stream.tellg() < 0) {
4822 status = load_stream_data_noseek(stream, &buffer, &size);
4824 status = load_stream_data_seek(stream, &buffer, &size);
4826 if (status != status_ok)
return make_parse_result(status);
4828 xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
4830 return load_buffer_impl(doc, doc, buffer,
4831 zero_terminate_buffer(buffer, size, real_encoding),
4832 options, real_encoding,
true,
true, out_buffer);
4836#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || \
4837 (defined(__MINGW32__) && \
4838 (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))
4839PUGI__FN FILE* open_file_wide(
const wchar_t* path,
const wchar_t* mode) {
4840 return _wfopen(path, mode);
4843PUGI__FN
char* convert_path_heap(
const wchar_t* str) {
4847 size_t length = strlength_wide(str);
4848 size_t size = as_utf8_begin(str, length);
4851 char* result =
static_cast<char*
>(xml_memory::allocate(size + 1));
4852 if (!result)
return 0;
4855 as_utf8_end(result, size, str, length);
4863PUGI__FN FILE* open_file_wide(
const wchar_t* path,
const wchar_t* mode) {
4866 char* path_utf8 = convert_path_heap(path);
4867 if (!path_utf8)
return 0;
4870 char mode_ascii[4] = {0};
4871 for (
size_t i = 0; mode[i]; ++i) mode_ascii[i] =
static_cast<char>(mode[i]);
4874 FILE* result = fopen(path_utf8, mode_ascii);
4877 xml_memory::deallocate(path_utf8);
4883PUGI__FN
bool save_file_impl(
const xml_document& doc, FILE* file,
4884 const char_t* indent,
unsigned int flags,
4885 xml_encoding encoding) {
4886 if (!file)
return false;
4888 xml_writer_file writer(file);
4889 doc.save(writer, indent, flags, encoding);
4891 return ferror(file) == 0;
4895 xml_node_struct* node;
4898 name_null_sentry(xml_node_struct* node_) : node(node_), name(node_->name) {
4907PUGI__FN xml_writer_file::xml_writer_file(
void* file_) : file(file_) {}
4909PUGI__FN
void xml_writer_file::write(
const void* data,
size_t size) {
4910 size_t result = fwrite(data, 1, size,
static_cast<FILE*
>(file));
4914#ifndef PUGIXML_NO_STL
4915PUGI__FN xml_writer_stream::xml_writer_stream(
4916 std::basic_ostream<
char, std::char_traits<char> >& stream)
4917 : narrow_stream(&stream), wide_stream(0) {}
4919PUGI__FN xml_writer_stream::xml_writer_stream(
4920 std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream)
4921 : narrow_stream(0), wide_stream(&stream) {}
4923PUGI__FN
void xml_writer_stream::write(
const void* data,
size_t size) {
4924 if (narrow_stream) {
4925 assert(!wide_stream);
4926 narrow_stream->write(
reinterpret_cast<const char*
>(data),
4927 static_cast<std::streamsize
>(size));
4929 assert(wide_stream);
4930 assert(size %
sizeof(
wchar_t) == 0);
4932 wide_stream->write(
reinterpret_cast<const wchar_t*
>(data),
4933 static_cast<std::streamsize
>(size /
sizeof(
wchar_t)));
4938PUGI__FN xml_tree_walker::xml_tree_walker() : _depth(0) {}
4940PUGI__FN xml_tree_walker::~xml_tree_walker() {}
4942PUGI__FN
int xml_tree_walker::depth()
const {
return _depth; }
4944PUGI__FN
bool xml_tree_walker::begin(xml_node&) {
return true; }
4946PUGI__FN
bool xml_tree_walker::end(xml_node&) {
return true; }
4948PUGI__FN xml_attribute::xml_attribute() : _attr(0) {}
4950PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr)
4953PUGI__FN
static void unspecified_bool_xml_attribute(xml_attribute***) {}
4955PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type()
const {
4956 return _attr ? unspecified_bool_xml_attribute : 0;
4959PUGI__FN
bool xml_attribute::operator!()
const {
return !_attr; }
4961PUGI__FN
bool xml_attribute::operator==(
const xml_attribute& r)
const {
4962 return (_attr == r._attr);
4965PUGI__FN
bool xml_attribute::operator!=(
const xml_attribute& r)
const {
4966 return (_attr != r._attr);
4969PUGI__FN
bool xml_attribute::operator<(
const xml_attribute& r)
const {
4970 return (_attr < r._attr);
4973PUGI__FN
bool xml_attribute::operator>(
const xml_attribute& r)
const {
4974 return (_attr > r._attr);
4977PUGI__FN
bool xml_attribute::operator<=(
const xml_attribute& r)
const {
4978 return (_attr <= r._attr);
4981PUGI__FN
bool xml_attribute::operator>=(
const xml_attribute& r)
const {
4982 return (_attr >= r._attr);
4985PUGI__FN xml_attribute xml_attribute::next_attribute()
const {
4986 return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
4989PUGI__FN xml_attribute xml_attribute::previous_attribute()
const {
4990 return _attr && _attr->prev_attribute_c->next_attribute
4991 ? xml_attribute(_attr->prev_attribute_c)
4995PUGI__FN
const char_t* xml_attribute::as_string(
const char_t* def)
const {
4996 return (_attr && _attr->value) ? _attr->value + 0 : def;
4999PUGI__FN
int xml_attribute::as_int(
int def)
const {
5000 return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def;
5003PUGI__FN
unsigned int xml_attribute::as_uint(
unsigned int def)
const {
5004 return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def;
5007PUGI__FN
double xml_attribute::as_double(
double def)
const {
5008 return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def;
5011PUGI__FN
float xml_attribute::as_float(
float def)
const {
5012 return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def;
5015PUGI__FN
bool xml_attribute::as_bool(
bool def)
const {
5016 return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def;
5019#ifdef PUGIXML_HAS_LONG_LONG
5020PUGI__FN
long long xml_attribute::as_llong(
long long def)
const {
5021 return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def;
5024PUGI__FN
unsigned long long xml_attribute::as_ullong(
5025 unsigned long long def)
const {
5026 return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def;
5030PUGI__FN
bool xml_attribute::empty()
const {
return !_attr; }
5032PUGI__FN
const char_t* xml_attribute::name()
const {
5033 return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT(
"");
5036PUGI__FN
const char_t* xml_attribute::value()
const {
5037 return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT(
"");
5040PUGI__FN
size_t xml_attribute::hash_value()
const {
5041 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(_attr) /
5042 sizeof(xml_attribute_struct));
5045PUGI__FN xml_attribute_struct* xml_attribute::internal_object()
const {
5049PUGI__FN xml_attribute& xml_attribute::operator=(
const char_t* rhs) {
5054PUGI__FN xml_attribute& xml_attribute::operator=(
int rhs) {
5059PUGI__FN xml_attribute& xml_attribute::operator=(
unsigned int rhs) {
5064PUGI__FN xml_attribute& xml_attribute::operator=(
long rhs) {
5069PUGI__FN xml_attribute& xml_attribute::operator=(
unsigned long rhs) {
5074PUGI__FN xml_attribute& xml_attribute::operator=(
double rhs) {
5079PUGI__FN xml_attribute& xml_attribute::operator=(
float rhs) {
5084PUGI__FN xml_attribute& xml_attribute::operator=(
bool rhs) {
5089#ifdef PUGIXML_HAS_LONG_LONG
5090PUGI__FN xml_attribute& xml_attribute::operator=(
long long rhs) {
5095PUGI__FN xml_attribute& xml_attribute::operator=(
unsigned long long rhs) {
5101PUGI__FN
bool xml_attribute::set_name(
const char_t* rhs) {
5102 if (!_attr)
return false;
5104 return impl::strcpy_insitu(_attr->name, _attr->header,
5105 impl::xml_memory_page_name_allocated_mask, rhs,
5106 impl::strlength(rhs));
5109PUGI__FN
bool xml_attribute::set_value(
const char_t* rhs) {
5110 if (!_attr)
return false;
5112 return impl::strcpy_insitu(_attr->value, _attr->header,
5113 impl::xml_memory_page_value_allocated_mask, rhs,
5114 impl::strlength(rhs));
5117PUGI__FN
bool xml_attribute::set_value(
int rhs) {
5118 if (!_attr)
return false;
5120 return impl::set_value_integer<unsigned int>(
5121 _attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask,
5125PUGI__FN
bool xml_attribute::set_value(
unsigned int rhs) {
5126 if (!_attr)
return false;
5128 return impl::set_value_integer<unsigned int>(
5129 _attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask,
5133PUGI__FN
bool xml_attribute::set_value(
long rhs) {
5134 if (!_attr)
return false;
5136 return impl::set_value_integer<unsigned long>(
5137 _attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask,
5141PUGI__FN
bool xml_attribute::set_value(
unsigned long rhs) {
5142 if (!_attr)
return false;
5144 return impl::set_value_integer<unsigned long>(
5145 _attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask,
5149PUGI__FN
bool xml_attribute::set_value(
double rhs) {
5150 if (!_attr)
return false;
5152 return impl::set_value_convert(_attr->value, _attr->header,
5153 impl::xml_memory_page_value_allocated_mask,
5157PUGI__FN
bool xml_attribute::set_value(
float rhs) {
5158 if (!_attr)
return false;
5160 return impl::set_value_convert(_attr->value, _attr->header,
5161 impl::xml_memory_page_value_allocated_mask,
5165PUGI__FN
bool xml_attribute::set_value(
bool rhs) {
5166 if (!_attr)
return false;
5168 return impl::set_value_bool(_attr->value, _attr->header,
5169 impl::xml_memory_page_value_allocated_mask, rhs);
5172#ifdef PUGIXML_HAS_LONG_LONG
5173PUGI__FN
bool xml_attribute::set_value(
long long rhs) {
5174 if (!_attr)
return false;
5176 return impl::set_value_integer<unsigned long long>(
5177 _attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask,
5181PUGI__FN
bool xml_attribute::set_value(
unsigned long long rhs) {
5182 if (!_attr)
return false;
5184 return impl::set_value_integer<unsigned long long>(
5185 _attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask,
5191PUGI__FN
bool operator&&(
const xml_attribute& lhs,
bool rhs) {
5192 return (
bool)lhs && rhs;
5195PUGI__FN
bool operator||(
const xml_attribute& lhs,
bool rhs) {
5196 return (
bool)lhs || rhs;
5200PUGI__FN xml_node::xml_node() : _root(0) {}
5202PUGI__FN xml_node::xml_node(xml_node_struct* p) : _root(p) {}
5204PUGI__FN
static void unspecified_bool_xml_node(xml_node***) {}
5206PUGI__FN xml_node::operator xml_node::unspecified_bool_type()
const {
5207 return _root ? unspecified_bool_xml_node : 0;
5210PUGI__FN
bool xml_node::operator!()
const {
return !_root; }
5212PUGI__FN xml_node::iterator xml_node::begin()
const {
5213 return iterator(_root ? _root->first_child + 0 : 0, _root);
5216PUGI__FN xml_node::iterator xml_node::end()
const {
return iterator(0, _root); }
5218PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin()
const {
5219 return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root);
5222PUGI__FN xml_node::attribute_iterator xml_node::attributes_end()
const {
5223 return attribute_iterator(0, _root);
5226PUGI__FN xml_object_range<xml_node_iterator> xml_node::children()
const {
5227 return xml_object_range<xml_node_iterator>(begin(), end());
5230PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(
5231 const char_t* name_)
const {
5232 return xml_object_range<xml_named_node_iterator>(
5233 xml_named_node_iterator(child(name_)._root, _root, name_),
5234 xml_named_node_iterator(0, _root, name_));
5237PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes()
const {
5238 return xml_object_range<xml_attribute_iterator>(attributes_begin(),
5242PUGI__FN
bool xml_node::operator==(
const xml_node& r)
const {
5243 return (_root == r._root);
5246PUGI__FN
bool xml_node::operator!=(
const xml_node& r)
const {
5247 return (_root != r._root);
5250PUGI__FN
bool xml_node::operator<(
const xml_node& r)
const {
5251 return (_root < r._root);
5254PUGI__FN
bool xml_node::operator>(
const xml_node& r)
const {
5255 return (_root > r._root);
5258PUGI__FN
bool xml_node::operator<=(
const xml_node& r)
const {
5259 return (_root <= r._root);
5262PUGI__FN
bool xml_node::operator>=(
const xml_node& r)
const {
5263 return (_root >= r._root);
5266PUGI__FN
bool xml_node::empty()
const {
return !_root; }
5268PUGI__FN
const char_t* xml_node::name()
const {
5269 return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(
"");
5272PUGI__FN xml_node_type xml_node::type()
const {
5273 return _root ? PUGI__NODETYPE(_root) : node_null;
5276PUGI__FN
const char_t* xml_node::value()
const {
5277 return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(
"");
5280PUGI__FN xml_node xml_node::child(
const char_t* name_)
const {
5281 if (!_root)
return xml_node();
5283 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5284 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
5289PUGI__FN xml_attribute xml_node::attribute(
const char_t* name_)
const {
5290 if (!_root)
return xml_attribute();
5292 for (xml_attribute_struct* i = _root->first_attribute; i;
5293 i = i->next_attribute)
5294 if (i->name && impl::strequal(name_, i->name))
return xml_attribute(i);
5296 return xml_attribute();
5299PUGI__FN xml_node xml_node::next_sibling(
const char_t* name_)
const {
5300 if (!_root)
return xml_node();
5302 for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
5303 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
5308PUGI__FN xml_node xml_node::next_sibling()
const {
5309 return _root ? xml_node(_root->next_sibling) : xml_node();
5312PUGI__FN xml_node xml_node::previous_sibling(
const char_t* name_)
const {
5313 if (!_root)
return xml_node();
5315 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling;
5316 i = i->prev_sibling_c)
5317 if (i->name && impl::strequal(name_, i->name))
return xml_node(i);
5322PUGI__FN xml_attribute xml_node::attribute(
const char_t* name_,
5323 xml_attribute& hint_)
const {
5324 xml_attribute_struct* hint = hint_._attr;
5327 assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
5329 if (!_root)
return xml_attribute();
5332 for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
5333 if (i->name && impl::strequal(name_, i->name)) {
5336 hint_._attr = i->next_attribute;
5338 return xml_attribute(i);
5344 for (xml_attribute_struct* j = _root->first_attribute; j && j != hint;
5345 j = j->next_attribute)
5346 if (j->name && impl::strequal(name_, j->name)) {
5349 hint_._attr = j->next_attribute;
5351 return xml_attribute(j);
5354 return xml_attribute();
5357PUGI__FN xml_node xml_node::previous_sibling()
const {
5358 if (!_root)
return xml_node();
5360 if (_root->prev_sibling_c->next_sibling)
5361 return xml_node(_root->prev_sibling_c);
5366PUGI__FN xml_node xml_node::parent()
const {
5367 return _root ? xml_node(_root->parent) : xml_node();
5370PUGI__FN xml_node xml_node::root()
const {
5371 return _root ? xml_node(&impl::get_document(_root)) : xml_node();
5374PUGI__FN xml_text xml_node::text()
const {
return xml_text(_root); }
5376PUGI__FN
const char_t* xml_node::child_value()
const {
5377 if (!_root)
return PUGIXML_TEXT(
"");
5380 if (PUGI__NODETYPE(_root) == node_element && _root->value)
5381 return _root->value;
5383 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5384 if (impl::is_text_node(i) && i->value)
return i->value;
5386 return PUGIXML_TEXT(
"");
5389PUGI__FN
const char_t* xml_node::child_value(
const char_t* name_)
const {
5390 return child(name_).child_value();
5393PUGI__FN xml_attribute xml_node::first_attribute()
const {
5394 return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
5397PUGI__FN xml_attribute xml_node::last_attribute()
const {
5398 return _root && _root->first_attribute
5399 ? xml_attribute(_root->first_attribute->prev_attribute_c)
5403PUGI__FN xml_node xml_node::first_child()
const {
5404 return _root ? xml_node(_root->first_child) : xml_node();
5407PUGI__FN xml_node xml_node::last_child()
const {
5408 return _root && _root->first_child
5409 ? xml_node(_root->first_child->prev_sibling_c)
5413PUGI__FN
bool xml_node::set_name(
const char_t* rhs) {
5414 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
5416 if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
5419 return impl::strcpy_insitu(_root->name, _root->header,
5420 impl::xml_memory_page_name_allocated_mask, rhs,
5421 impl::strlength(rhs));
5424PUGI__FN
bool xml_node::set_value(
const char_t* rhs) {
5425 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
5427 if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment &&
5428 type_ != node_pi && type_ != node_doctype)
5431 return impl::strcpy_insitu(_root->value, _root->header,
5432 impl::xml_memory_page_value_allocated_mask, rhs,
5433 impl::strlength(rhs));
5436PUGI__FN xml_attribute xml_node::append_attribute(
const char_t* name_) {
5437 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5439 impl::xml_allocator& alloc = impl::get_allocator(_root);
5440 if (!alloc.reserve())
return xml_attribute();
5442 xml_attribute a(impl::allocate_attribute(alloc));
5443 if (!a)
return xml_attribute();
5445 impl::append_attribute(a._attr, _root);
5452PUGI__FN xml_attribute xml_node::prepend_attribute(
const char_t* name_) {
5453 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5455 impl::xml_allocator& alloc = impl::get_allocator(_root);
5456 if (!alloc.reserve())
return xml_attribute();
5458 xml_attribute a(impl::allocate_attribute(alloc));
5459 if (!a)
return xml_attribute();
5461 impl::prepend_attribute(a._attr, _root);
5468PUGI__FN xml_attribute xml_node::insert_attribute_after(
5469 const char_t* name_,
const xml_attribute& attr) {
5470 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5471 if (!attr || !impl::is_attribute_of(attr._attr, _root))
5472 return xml_attribute();
5474 impl::xml_allocator& alloc = impl::get_allocator(_root);
5475 if (!alloc.reserve())
return xml_attribute();
5477 xml_attribute a(impl::allocate_attribute(alloc));
5478 if (!a)
return xml_attribute();
5480 impl::insert_attribute_after(a._attr, attr._attr, _root);
5487PUGI__FN xml_attribute xml_node::insert_attribute_before(
5488 const char_t* name_,
const xml_attribute& attr) {
5489 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5490 if (!attr || !impl::is_attribute_of(attr._attr, _root))
5491 return xml_attribute();
5493 impl::xml_allocator& alloc = impl::get_allocator(_root);
5494 if (!alloc.reserve())
return xml_attribute();
5496 xml_attribute a(impl::allocate_attribute(alloc));
5497 if (!a)
return xml_attribute();
5499 impl::insert_attribute_before(a._attr, attr._attr, _root);
5506PUGI__FN xml_attribute xml_node::append_copy(
const xml_attribute& proto) {
5507 if (!proto)
return xml_attribute();
5508 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5510 impl::xml_allocator& alloc = impl::get_allocator(_root);
5511 if (!alloc.reserve())
return xml_attribute();
5513 xml_attribute a(impl::allocate_attribute(alloc));
5514 if (!a)
return xml_attribute();
5516 impl::append_attribute(a._attr, _root);
5517 impl::node_copy_attribute(a._attr, proto._attr);
5522PUGI__FN xml_attribute xml_node::prepend_copy(
const xml_attribute& proto) {
5523 if (!proto)
return xml_attribute();
5524 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5526 impl::xml_allocator& alloc = impl::get_allocator(_root);
5527 if (!alloc.reserve())
return xml_attribute();
5529 xml_attribute a(impl::allocate_attribute(alloc));
5530 if (!a)
return xml_attribute();
5532 impl::prepend_attribute(a._attr, _root);
5533 impl::node_copy_attribute(a._attr, proto._attr);
5538PUGI__FN xml_attribute xml_node::insert_copy_after(
const xml_attribute& proto,
5539 const xml_attribute& attr) {
5540 if (!proto)
return xml_attribute();
5541 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5542 if (!attr || !impl::is_attribute_of(attr._attr, _root))
5543 return xml_attribute();
5545 impl::xml_allocator& alloc = impl::get_allocator(_root);
5546 if (!alloc.reserve())
return xml_attribute();
5548 xml_attribute a(impl::allocate_attribute(alloc));
5549 if (!a)
return xml_attribute();
5551 impl::insert_attribute_after(a._attr, attr._attr, _root);
5552 impl::node_copy_attribute(a._attr, proto._attr);
5557PUGI__FN xml_attribute xml_node::insert_copy_before(
const xml_attribute& proto,
5558 const xml_attribute& attr) {
5559 if (!proto)
return xml_attribute();
5560 if (!impl::allow_insert_attribute(type()))
return xml_attribute();
5561 if (!attr || !impl::is_attribute_of(attr._attr, _root))
5562 return xml_attribute();
5564 impl::xml_allocator& alloc = impl::get_allocator(_root);
5565 if (!alloc.reserve())
return xml_attribute();
5567 xml_attribute a(impl::allocate_attribute(alloc));
5568 if (!a)
return xml_attribute();
5570 impl::insert_attribute_before(a._attr, attr._attr, _root);
5571 impl::node_copy_attribute(a._attr, proto._attr);
5576PUGI__FN xml_node xml_node::append_child(xml_node_type type_) {
5577 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5579 impl::xml_allocator& alloc = impl::get_allocator(_root);
5580 if (!alloc.reserve())
return xml_node();
5582 xml_node n(impl::allocate_node(alloc, type_));
5583 if (!n)
return xml_node();
5585 impl::append_node(n._root, _root);
5587 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
5592PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_) {
5593 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5595 impl::xml_allocator& alloc = impl::get_allocator(_root);
5596 if (!alloc.reserve())
return xml_node();
5598 xml_node n(impl::allocate_node(alloc, type_));
5599 if (!n)
return xml_node();
5601 impl::prepend_node(n._root, _root);
5603 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
5608PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_,
5609 const xml_node& node) {
5610 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5611 if (!node._root || node._root->parent != _root)
return xml_node();
5613 impl::xml_allocator& alloc = impl::get_allocator(_root);
5614 if (!alloc.reserve())
return xml_node();
5616 xml_node n(impl::allocate_node(alloc, type_));
5617 if (!n)
return xml_node();
5619 impl::insert_node_before(n._root, node._root);
5621 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
5626PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_,
5627 const xml_node& node) {
5628 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5629 if (!node._root || node._root->parent != _root)
return xml_node();
5631 impl::xml_allocator& alloc = impl::get_allocator(_root);
5632 if (!alloc.reserve())
return xml_node();
5634 xml_node n(impl::allocate_node(alloc, type_));
5635 if (!n)
return xml_node();
5637 impl::insert_node_after(n._root, node._root);
5639 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT(
"xml"));
5644PUGI__FN xml_node xml_node::append_child(
const char_t* name_) {
5645 xml_node result = append_child(node_element);
5647 result.set_name(name_);
5652PUGI__FN xml_node xml_node::prepend_child(
const char_t* name_) {
5653 xml_node result = prepend_child(node_element);
5655 result.set_name(name_);
5660PUGI__FN xml_node xml_node::insert_child_after(
const char_t* name_,
5661 const xml_node& node) {
5662 xml_node result = insert_child_after(node_element, node);
5664 result.set_name(name_);
5669PUGI__FN xml_node xml_node::insert_child_before(
const char_t* name_,
5670 const xml_node& node) {
5671 xml_node result = insert_child_before(node_element, node);
5673 result.set_name(name_);
5678PUGI__FN xml_node xml_node::append_copy(
const xml_node& proto) {
5679 xml_node_type type_ = proto.type();
5680 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5682 impl::xml_allocator& alloc = impl::get_allocator(_root);
5683 if (!alloc.reserve())
return xml_node();
5685 xml_node n(impl::allocate_node(alloc, type_));
5686 if (!n)
return xml_node();
5688 impl::append_node(n._root, _root);
5689 impl::node_copy_tree(n._root, proto._root);
5694PUGI__FN xml_node xml_node::prepend_copy(
const xml_node& proto) {
5695 xml_node_type type_ = proto.type();
5696 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5698 impl::xml_allocator& alloc = impl::get_allocator(_root);
5699 if (!alloc.reserve())
return xml_node();
5701 xml_node n(impl::allocate_node(alloc, type_));
5702 if (!n)
return xml_node();
5704 impl::prepend_node(n._root, _root);
5705 impl::node_copy_tree(n._root, proto._root);
5710PUGI__FN xml_node xml_node::insert_copy_after(
const xml_node& proto,
5711 const xml_node& node) {
5712 xml_node_type type_ = proto.type();
5713 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5714 if (!node._root || node._root->parent != _root)
return xml_node();
5716 impl::xml_allocator& alloc = impl::get_allocator(_root);
5717 if (!alloc.reserve())
return xml_node();
5719 xml_node n(impl::allocate_node(alloc, type_));
5720 if (!n)
return xml_node();
5722 impl::insert_node_after(n._root, node._root);
5723 impl::node_copy_tree(n._root, proto._root);
5728PUGI__FN xml_node xml_node::insert_copy_before(
const xml_node& proto,
5729 const xml_node& node) {
5730 xml_node_type type_ = proto.type();
5731 if (!impl::allow_insert_child(type(), type_))
return xml_node();
5732 if (!node._root || node._root->parent != _root)
return xml_node();
5734 impl::xml_allocator& alloc = impl::get_allocator(_root);
5735 if (!alloc.reserve())
return xml_node();
5737 xml_node n(impl::allocate_node(alloc, type_));
5738 if (!n)
return xml_node();
5740 impl::insert_node_before(n._root, node._root);
5741 impl::node_copy_tree(n._root, proto._root);
5746PUGI__FN xml_node xml_node::append_move(
const xml_node& moved) {
5747 if (!impl::allow_move(*
this, moved))
return xml_node();
5749 impl::xml_allocator& alloc = impl::get_allocator(_root);
5750 if (!alloc.reserve())
return xml_node();
5754 impl::get_document(_root).header |=
5755 impl::xml_memory_page_contents_shared_mask;
5757 impl::remove_node(moved._root);
5758 impl::append_node(moved._root, _root);
5763PUGI__FN xml_node xml_node::prepend_move(
const xml_node& moved) {
5764 if (!impl::allow_move(*
this, moved))
return xml_node();
5766 impl::xml_allocator& alloc = impl::get_allocator(_root);
5767 if (!alloc.reserve())
return xml_node();
5771 impl::get_document(_root).header |=
5772 impl::xml_memory_page_contents_shared_mask;
5774 impl::remove_node(moved._root);
5775 impl::prepend_node(moved._root, _root);
5780PUGI__FN xml_node xml_node::insert_move_after(
const xml_node& moved,
5781 const xml_node& node) {
5782 if (!impl::allow_move(*
this, moved))
return xml_node();
5783 if (!node._root || node._root->parent != _root)
return xml_node();
5784 if (moved._root == node._root)
return xml_node();
5786 impl::xml_allocator& alloc = impl::get_allocator(_root);
5787 if (!alloc.reserve())
return xml_node();
5791 impl::get_document(_root).header |=
5792 impl::xml_memory_page_contents_shared_mask;
5794 impl::remove_node(moved._root);
5795 impl::insert_node_after(moved._root, node._root);
5800PUGI__FN xml_node xml_node::insert_move_before(
const xml_node& moved,
5801 const xml_node& node) {
5802 if (!impl::allow_move(*
this, moved))
return xml_node();
5803 if (!node._root || node._root->parent != _root)
return xml_node();
5804 if (moved._root == node._root)
return xml_node();
5806 impl::xml_allocator& alloc = impl::get_allocator(_root);
5807 if (!alloc.reserve())
return xml_node();
5811 impl::get_document(_root).header |=
5812 impl::xml_memory_page_contents_shared_mask;
5814 impl::remove_node(moved._root);
5815 impl::insert_node_before(moved._root, node._root);
5820PUGI__FN
bool xml_node::remove_attribute(
const char_t* name_) {
5821 return remove_attribute(attribute(name_));
5824PUGI__FN
bool xml_node::remove_attribute(
const xml_attribute& a) {
5825 if (!_root || !a._attr)
return false;
5826 if (!impl::is_attribute_of(a._attr, _root))
return false;
5828 impl::xml_allocator& alloc = impl::get_allocator(_root);
5829 if (!alloc.reserve())
return false;
5831 impl::remove_attribute(a._attr, _root);
5832 impl::destroy_attribute(a._attr, alloc);
5837PUGI__FN
bool xml_node::remove_child(
const char_t* name_) {
5838 return remove_child(child(name_));
5841PUGI__FN
bool xml_node::remove_child(
const xml_node& n) {
5842 if (!_root || !n._root || n._root->parent != _root)
return false;
5844 impl::xml_allocator& alloc = impl::get_allocator(_root);
5845 if (!alloc.reserve())
return false;
5847 impl::remove_node(n._root);
5848 impl::destroy_node(n._root, alloc);
5853PUGI__FN xml_parse_result xml_node::append_buffer(
const void* contents,
5856 xml_encoding encoding) {
5858 if (!impl::allow_insert_child(type(), node_element))
5859 return impl::make_parse_result(status_append_invalid_root);
5862 impl::xml_document_struct* doc = &impl::get_document(_root);
5866 doc->header |= impl::xml_memory_page_contents_shared_mask;
5870 impl::xml_memory_page* page = 0;
5871 impl::xml_extra_buffer* extra =
static_cast<impl::xml_extra_buffer*
>(
5872 doc->allocate_memory(
sizeof(impl::xml_extra_buffer), page));
5875 if (!extra)
return impl::make_parse_result(status_out_of_memory);
5879 extra->next = doc->extra_buffers;
5880 doc->extra_buffers = extra;
5884 impl::name_null_sentry sentry(_root);
5886 return impl::load_buffer_impl(doc, _root,
const_cast<void*
>(contents), size,
5887 options, encoding,
false,
false,
5892xml_node::find_child_by_attribute(
const char_t* name_,
const char_t* attr_name,
5893 const char_t* attr_value)
const {
5894 if (!_root)
return xml_node();
5896 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5897 if (i->name && impl::strequal(name_, i->name)) {
5898 for (xml_attribute_struct* a = i->first_attribute; a;
5899 a = a->next_attribute)
5900 if (a->name && impl::strequal(attr_name, a->name) &&
5901 impl::strequal(attr_value,
5902 a->value ? a->value + 0 : PUGIXML_TEXT(
"")))
5909PUGI__FN xml_node xml_node::find_child_by_attribute(
5910 const char_t* attr_name,
const char_t* attr_value)
const {
5911 if (!_root)
return xml_node();
5913 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
5914 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
5915 if (a->name && impl::strequal(attr_name, a->name) &&
5916 impl::strequal(attr_value,
5917 a->value ? a->value + 0 : PUGIXML_TEXT(
"")))
5923#ifndef PUGIXML_NO_STL
5924PUGI__FN string_t xml_node::path(char_t delimiter)
const {
5925 if (!_root)
return string_t();
5929 for (xml_node_struct* i = _root; i; i = i->parent) {
5930 offset += (i != _root);
5931 offset += i->name ? impl::strlength(i->name) : 0;
5935 result.resize(offset);
5937 for (xml_node_struct* j = _root; j; j = j->parent) {
5938 if (j != _root) result[--offset] = delimiter;
5940 if (j->name && *j->name) {
5941 size_t length = impl::strlength(j->name);
5944 memcpy(&result[offset], j->name, length *
sizeof(char_t));
5948 assert(offset == 0);
5954PUGI__FN xml_node xml_node::first_element_by_path(
const char_t* path_,
5955 char_t delimiter)
const {
5956 xml_node found = *
this;
5958 if (!_root || !path_ || !path_[0])
return found;
5960 if (path_[0] == delimiter) {
5962 found = found.root();
5966 const char_t* path_segment = path_;
5968 while (*path_segment == delimiter) ++path_segment;
5970 const char_t* path_segment_end = path_segment;
5972 while (*path_segment_end && *path_segment_end != delimiter)
5975 if (path_segment == path_segment_end)
return found;
5977 const char_t* next_segment = path_segment_end;
5979 while (*next_segment == delimiter) ++next_segment;
5981 if (*path_segment ==
'.' && path_segment + 1 == path_segment_end)
5982 return found.first_element_by_path(next_segment, delimiter);
5983 else if (*path_segment ==
'.' && *(path_segment + 1) ==
'.' &&
5984 path_segment + 2 == path_segment_end)
5985 return found.parent().first_element_by_path(next_segment, delimiter);
5987 for (xml_node_struct* j = found._root->first_child; j;
5988 j = j->next_sibling) {
5989 if (j->name && impl::strequalrange(j->name, path_segment,
5990 static_cast<size_t>(path_segment_end -
5992 xml_node subsearch =
5993 xml_node(j).first_element_by_path(next_segment, delimiter);
5995 if (subsearch)
return subsearch;
6003PUGI__FN
bool xml_node::traverse(xml_tree_walker& walker) {
6006 xml_node arg_begin = *
this;
6007 if (!walker.begin(arg_begin))
return false;
6009 xml_node cur = first_child();
6015 xml_node arg_for_each = cur;
6016 if (!walker.for_each(arg_for_each))
return false;
6018 if (cur.first_child()) {
6020 cur = cur.first_child();
6021 }
else if (cur.next_sibling())
6022 cur = cur.next_sibling();
6025 while (!cur.next_sibling() && cur != *
this && !cur.parent().empty()) {
6030 if (cur != *
this) cur = cur.next_sibling();
6032 }
while (cur && cur != *
this);
6035 assert(walker._depth == -1);
6037 xml_node arg_end = *
this;
6038 return walker.end(arg_end);
6041PUGI__FN
size_t xml_node::hash_value()
const {
6042 return static_cast<size_t>(
reinterpret_cast<uintptr_t
>(_root) /
6043 sizeof(xml_node_struct));
6046PUGI__FN xml_node_struct* xml_node::internal_object()
const {
return _root; }
6048PUGI__FN
void xml_node::print(xml_writer& writer,
const char_t* indent,
6049 unsigned int flags, xml_encoding encoding,
6050 unsigned int depth)
const {
6053 impl::xml_buffered_writer buffered_writer(writer, encoding);
6055 impl::node_output(buffered_writer, _root, indent, flags, depth);
6057 buffered_writer.flush();
6060#ifndef PUGIXML_NO_STL
6061PUGI__FN
void xml_node::print(
6062 std::basic_ostream<
char, std::char_traits<char> >& stream,
6063 const char_t* indent,
unsigned int flags, xml_encoding encoding,
6064 unsigned int depth)
const {
6065 xml_writer_stream writer(stream);
6067 print(writer, indent, flags, encoding, depth);
6070PUGI__FN
void xml_node::print(
6071 std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream,
6072 const char_t* indent,
unsigned int flags,
unsigned int depth)
const {
6073 xml_writer_stream writer(stream);
6075 print(writer, indent, flags, encoding_wchar, depth);
6079PUGI__FN ptrdiff_t xml_node::offset_debug()
const {
6080 if (!_root)
return -1;
6082 impl::xml_document_struct& doc = impl::get_document(_root);
6086 if (!doc.buffer || doc.extra_buffers)
return -1;
6093 case node_declaration:
6095 return _root->name &&
6097 impl::xml_memory_page_name_allocated_or_shared_mask) == 0
6098 ? _root->name - doc.buffer
6105 return _root->value &&
6107 impl::xml_memory_page_value_allocated_or_shared_mask) == 0
6108 ? _root->value - doc.buffer
6117PUGI__FN
bool operator&&(
const xml_node& lhs,
bool rhs) {
6118 return (
bool)lhs && rhs;
6121PUGI__FN
bool operator||(
const xml_node& lhs,
bool rhs) {
6122 return (
bool)lhs || rhs;
6126PUGI__FN xml_text::xml_text(xml_node_struct* root) : _root(root) {}
6128PUGI__FN xml_node_struct* xml_text::_data()
const {
6129 if (!_root || impl::is_text_node(_root))
return _root;
6132 if (PUGI__NODETYPE(_root) == node_element && _root->value)
return _root;
6134 for (xml_node_struct* node = _root->first_child; node;
6135 node = node->next_sibling)
6136 if (impl::is_text_node(node))
return node;
6141PUGI__FN xml_node_struct* xml_text::_data_new() {
6142 xml_node_struct* d = _data();
6145 return xml_node(_root).append_child(node_pcdata).internal_object();
6148PUGI__FN xml_text::xml_text() : _root(0) {}
6150PUGI__FN
static void unspecified_bool_xml_text(xml_text***) {}
6152PUGI__FN xml_text::operator xml_text::unspecified_bool_type()
const {
6153 return _data() ? unspecified_bool_xml_text : 0;
6156PUGI__FN
bool xml_text::operator!()
const {
return !_data(); }
6158PUGI__FN
bool xml_text::empty()
const {
return _data() == 0; }
6160PUGI__FN
const char_t* xml_text::get()
const {
6161 xml_node_struct* d = _data();
6163 return (d && d->value) ? d->value + 0 : PUGIXML_TEXT(
"");
6166PUGI__FN
const char_t* xml_text::as_string(
const char_t* def)
const {
6167 xml_node_struct* d = _data();
6169 return (d && d->value) ? d->value + 0 : def;
6172PUGI__FN
int xml_text::as_int(
int def)
const {
6173 xml_node_struct* d = _data();
6175 return (d && d->value) ? impl::get_value_int(d->value) : def;
6178PUGI__FN
unsigned int xml_text::as_uint(
unsigned int def)
const {
6179 xml_node_struct* d = _data();
6181 return (d && d->value) ? impl::get_value_uint(d->value) : def;
6184PUGI__FN
double xml_text::as_double(
double def)
const {
6185 xml_node_struct* d = _data();
6187 return (d && d->value) ? impl::get_value_double(d->value) : def;
6190PUGI__FN
float xml_text::as_float(
float def)
const {
6191 xml_node_struct* d = _data();
6193 return (d && d->value) ? impl::get_value_float(d->value) : def;
6196PUGI__FN
bool xml_text::as_bool(
bool def)
const {
6197 xml_node_struct* d = _data();
6199 return (d && d->value) ? impl::get_value_bool(d->value) : def;
6202#ifdef PUGIXML_HAS_LONG_LONG
6203PUGI__FN
long long xml_text::as_llong(
long long def)
const {
6204 xml_node_struct* d = _data();
6206 return (d && d->value) ? impl::get_value_llong(d->value) : def;
6209PUGI__FN
unsigned long long xml_text::as_ullong(
unsigned long long def)
const {
6210 xml_node_struct* d = _data();
6212 return (d && d->value) ? impl::get_value_ullong(d->value) : def;
6216PUGI__FN
bool xml_text::set(
const char_t* rhs) {
6217 xml_node_struct* dn = _data_new();
6219 return dn ? impl::strcpy_insitu(dn->value, dn->header,
6220 impl::xml_memory_page_value_allocated_mask,
6221 rhs, impl::strlength(rhs))
6225PUGI__FN
bool xml_text::set(
int rhs) {
6226 xml_node_struct* dn = _data_new();
6228 return dn ? impl::set_value_integer<unsigned int>(
6229 dn->value, dn->header,
6230 impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0)
6234PUGI__FN
bool xml_text::set(
unsigned int rhs) {
6235 xml_node_struct* dn = _data_new();
6237 return dn ? impl::set_value_integer<unsigned int>(
6238 dn->value, dn->header,
6239 impl::xml_memory_page_value_allocated_mask, rhs,
false)
6243PUGI__FN
bool xml_text::set(
long rhs) {
6244 xml_node_struct* dn = _data_new();
6246 return dn ? impl::set_value_integer<unsigned long>(
6247 dn->value, dn->header,
6248 impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0)
6252PUGI__FN
bool xml_text::set(
unsigned long rhs) {
6253 xml_node_struct* dn = _data_new();
6255 return dn ? impl::set_value_integer<unsigned long>(
6256 dn->value, dn->header,
6257 impl::xml_memory_page_value_allocated_mask, rhs,
false)
6261PUGI__FN
bool xml_text::set(
float rhs) {
6262 xml_node_struct* dn = _data_new();
6264 return dn ? impl::set_value_convert(
6265 dn->value, dn->header,
6266 impl::xml_memory_page_value_allocated_mask, rhs)
6270PUGI__FN
bool xml_text::set(
double rhs) {
6271 xml_node_struct* dn = _data_new();
6273 return dn ? impl::set_value_convert(
6274 dn->value, dn->header,
6275 impl::xml_memory_page_value_allocated_mask, rhs)
6279PUGI__FN
bool xml_text::set(
bool rhs) {
6280 xml_node_struct* dn = _data_new();
6282 return dn ? impl::set_value_bool(dn->value, dn->header,
6283 impl::xml_memory_page_value_allocated_mask,
6288#ifdef PUGIXML_HAS_LONG_LONG
6289PUGI__FN
bool xml_text::set(
long long rhs) {
6290 xml_node_struct* dn = _data_new();
6292 return dn ? impl::set_value_integer<unsigned long long>(
6293 dn->value, dn->header,
6294 impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0)
6298PUGI__FN
bool xml_text::set(
unsigned long long rhs) {
6299 xml_node_struct* dn = _data_new();
6301 return dn ? impl::set_value_integer<unsigned long long>(
6302 dn->value, dn->header,
6303 impl::xml_memory_page_value_allocated_mask, rhs,
false)
6308PUGI__FN xml_text& xml_text::operator=(
const char_t* rhs) {
6313PUGI__FN xml_text& xml_text::operator=(
int rhs) {
6318PUGI__FN xml_text& xml_text::operator=(
unsigned int rhs) {
6323PUGI__FN xml_text& xml_text::operator=(
long rhs) {
6328PUGI__FN xml_text& xml_text::operator=(
unsigned long rhs) {
6333PUGI__FN xml_text& xml_text::operator=(
double rhs) {
6338PUGI__FN xml_text& xml_text::operator=(
float rhs) {
6343PUGI__FN xml_text& xml_text::operator=(
bool rhs) {
6348#ifdef PUGIXML_HAS_LONG_LONG
6349PUGI__FN xml_text& xml_text::operator=(
long long rhs) {
6354PUGI__FN xml_text& xml_text::operator=(
unsigned long long rhs) {
6360PUGI__FN xml_node xml_text::data()
const {
return xml_node(_data()); }
6363PUGI__FN
bool operator&&(
const xml_text& lhs,
bool rhs) {
6364 return (
bool)lhs && rhs;
6367PUGI__FN
bool operator||(
const xml_text& lhs,
bool rhs) {
6368 return (
bool)lhs || rhs;
6372PUGI__FN xml_node_iterator::xml_node_iterator() {}
6374PUGI__FN xml_node_iterator::xml_node_iterator(
const xml_node& node)
6375 : _wrap(node), _parent(node.parent()) {}
6377PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref,
6378 xml_node_struct* parent)
6379 : _wrap(ref), _parent(parent) {}
6381PUGI__FN
bool xml_node_iterator::operator==(
6382 const xml_node_iterator& rhs)
const {
6383 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
6386PUGI__FN
bool xml_node_iterator::operator!=(
6387 const xml_node_iterator& rhs)
const {
6388 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
6391PUGI__FN xml_node& xml_node_iterator::operator*()
const {
6392 assert(_wrap._root);
6396PUGI__FN xml_node* xml_node_iterator::operator->()
const {
6397 assert(_wrap._root);
6398 return const_cast<xml_node*
>(&_wrap);
6401PUGI__FN
const xml_node_iterator& xml_node_iterator::operator++() {
6402 assert(_wrap._root);
6403 _wrap._root = _wrap._root->next_sibling;
6407PUGI__FN xml_node_iterator xml_node_iterator::operator++(
int) {
6408 xml_node_iterator temp = *
this;
6413PUGI__FN
const xml_node_iterator& xml_node_iterator::operator--() {
6414 _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
6418PUGI__FN xml_node_iterator xml_node_iterator::operator--(
int) {
6419 xml_node_iterator temp = *
this;
6424PUGI__FN xml_attribute_iterator::xml_attribute_iterator() {}
6426PUGI__FN xml_attribute_iterator::xml_attribute_iterator(
6427 const xml_attribute& attr,
const xml_node& parent)
6428 : _wrap(attr), _parent(parent) {}
6430PUGI__FN xml_attribute_iterator::xml_attribute_iterator(
6431 xml_attribute_struct* ref, xml_node_struct* parent)
6432 : _wrap(ref), _parent(parent) {}
6434PUGI__FN
bool xml_attribute_iterator::operator==(
6435 const xml_attribute_iterator& rhs)
const {
6436 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
6439PUGI__FN
bool xml_attribute_iterator::operator!=(
6440 const xml_attribute_iterator& rhs)
const {
6441 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
6444PUGI__FN xml_attribute& xml_attribute_iterator::operator*()
const {
6445 assert(_wrap._attr);
6449PUGI__FN xml_attribute* xml_attribute_iterator::operator->()
const {
6450 assert(_wrap._attr);
6451 return const_cast<xml_attribute*
>(&_wrap);
6454PUGI__FN
const xml_attribute_iterator& xml_attribute_iterator::operator++() {
6455 assert(_wrap._attr);
6456 _wrap._attr = _wrap._attr->next_attribute;
6460PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(
int) {
6461 xml_attribute_iterator temp = *
this;
6466PUGI__FN
const xml_attribute_iterator& xml_attribute_iterator::operator--() {
6467 _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
6471PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(
int) {
6472 xml_attribute_iterator temp = *
this;
6477PUGI__FN xml_named_node_iterator::xml_named_node_iterator() : _name(0) {}
6479PUGI__FN xml_named_node_iterator::xml_named_node_iterator(
const xml_node& node,
6481 : _wrap(node), _parent(node.parent()), _name(name) {}
6483PUGI__FN xml_named_node_iterator::xml_named_node_iterator(
6484 xml_node_struct* ref, xml_node_struct* parent,
const char_t* name)
6485 : _wrap(ref), _parent(parent), _name(name) {}
6487PUGI__FN
bool xml_named_node_iterator::operator==(
6488 const xml_named_node_iterator& rhs)
const {
6489 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
6492PUGI__FN
bool xml_named_node_iterator::operator!=(
6493 const xml_named_node_iterator& rhs)
const {
6494 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
6497PUGI__FN xml_node& xml_named_node_iterator::operator*()
const {
6498 assert(_wrap._root);
6502PUGI__FN xml_node* xml_named_node_iterator::operator->()
const {
6503 assert(_wrap._root);
6504 return const_cast<xml_node*
>(&_wrap);
6507PUGI__FN
const xml_named_node_iterator& xml_named_node_iterator::operator++() {
6508 assert(_wrap._root);
6509 _wrap = _wrap.next_sibling(_name);
6513PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(
int) {
6514 xml_named_node_iterator temp = *
this;
6519PUGI__FN
const xml_named_node_iterator& xml_named_node_iterator::operator--() {
6521 _wrap = _wrap.previous_sibling(_name);
6523 _wrap = _parent.last_child();
6525 if (!impl::strequal(_wrap.name(), _name))
6526 _wrap = _wrap.previous_sibling(_name);
6532PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(
int) {
6533 xml_named_node_iterator temp = *
this;
6538PUGI__FN xml_parse_result::xml_parse_result()
6539 : status(status_internal_error), offset(0), encoding(encoding_auto) {}
6541PUGI__FN xml_parse_result::operator bool()
const {
return status == status_ok; }
6543PUGI__FN
const char* xml_parse_result::description()
const {
6548 case status_file_not_found:
6549 return "File was not found";
6550 case status_io_error:
6551 return "Error reading from file/stream";
6552 case status_out_of_memory:
6553 return "Could not allocate memory";
6554 case status_internal_error:
6555 return "Internal error occurred";
6557 case status_unrecognized_tag:
6558 return "Could not determine tag type";
6561 return "Error parsing document declaration/processing instruction";
6562 case status_bad_comment:
6563 return "Error parsing comment";
6564 case status_bad_cdata:
6565 return "Error parsing CDATA section";
6566 case status_bad_doctype:
6567 return "Error parsing document type declaration";
6568 case status_bad_pcdata:
6569 return "Error parsing PCDATA section";
6570 case status_bad_start_element:
6571 return "Error parsing start element tag";
6572 case status_bad_attribute:
6573 return "Error parsing element attribute";
6574 case status_bad_end_element:
6575 return "Error parsing end element tag";
6576 case status_end_element_mismatch:
6577 return "Start-end tags mismatch";
6579 case status_append_invalid_root:
6580 return "Unable to append nodes: root is not an element or document";
6582 case status_no_document_element:
6583 return "No document element found";
6586 return "Unknown error";
6590PUGI__FN xml_document::xml_document() : _buffer(0) { _create(); }
6592PUGI__FN xml_document::~xml_document() { _destroy(); }
6594PUGI__FN
void xml_document::reset() {
6599PUGI__FN
void xml_document::reset(
const xml_document& proto) {
6602 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
6606PUGI__FN
void xml_document::_create() {
6609#ifdef PUGIXML_COMPACT
6610 const size_t page_offset =
sizeof(uint32_t);
6612 const size_t page_offset = 0;
6616 PUGI__STATIC_ASSERT(
sizeof(impl::xml_memory_page) +
6617 sizeof(impl::xml_document_struct) + page_offset <=
6621 impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory);
6624 page->busy_size = impl::xml_memory_page_size;
6627#ifdef PUGIXML_COMPACT
6630 page->compact_page_marker =
reinterpret_cast<uint32_t*
>(
static_cast<void*
>(
6631 reinterpret_cast<char*
>(page) +
sizeof(impl::xml_memory_page)));
6632 *page->compact_page_marker =
sizeof(impl::xml_memory_page);
6636 _root =
new (
reinterpret_cast<char*
>(page) +
sizeof(impl::xml_memory_page) +
6637 page_offset) impl::xml_document_struct(page);
6638 _root->prev_sibling_c = _root;
6641 page->allocator =
static_cast<impl::xml_document_struct*
>(_root);
6644#ifdef PUGIXML_COMPACT
6645 page->allocator->_hash =
6646 &
static_cast<impl::xml_document_struct*
>(_root)->hash;
6650 assert(
reinterpret_cast<char*
>(_root) +
sizeof(impl::xml_document_struct) <=
6651 _memory +
sizeof(_memory));
6654PUGI__FN
void xml_document::_destroy() {
6659 impl::xml_memory::deallocate(_buffer);
6665 for (impl::xml_extra_buffer* extra =
6666 static_cast<impl::xml_document_struct*
>(_root)->extra_buffers;
6667 extra; extra = extra->next) {
6668 if (extra->buffer) impl::xml_memory::deallocate(extra->buffer);
6672 impl::xml_memory_page* root_page = PUGI__GETPAGE(_root);
6673 assert(root_page && !root_page->prev);
6674 assert(
reinterpret_cast<char*
>(root_page) >= _memory &&
6675 reinterpret_cast<char*
>(root_page) < _memory +
sizeof(_memory));
6677 for (impl::xml_memory_page* page = root_page->next; page;) {
6678 impl::xml_memory_page* next = page->next;
6680 impl::xml_allocator::deallocate_page(page);
6685#ifdef PUGIXML_COMPACT
6687 static_cast<impl::xml_document_struct*
>(_root)->hash.clear();
6693#ifndef PUGIXML_NO_STL
6694PUGI__FN xml_parse_result
6695xml_document::load(std::basic_istream<
char, std::char_traits<char> >& stream,
6696 unsigned int options, xml_encoding encoding) {
6699 return impl::load_stream_impl(
static_cast<impl::xml_document_struct*
>(_root),
6700 stream,
options, encoding, &_buffer);
6703PUGI__FN xml_parse_result xml_document::load(
6704 std::basic_istream<
wchar_t, std::char_traits<wchar_t> >& stream,
6708 return impl::load_stream_impl(
static_cast<impl::xml_document_struct*
>(_root),
6709 stream,
options, encoding_wchar, &_buffer);
6713PUGI__FN xml_parse_result xml_document::load_string(
const char_t* contents,
6716#ifdef PUGIXML_WCHAR_MODE
6717 xml_encoding encoding = encoding_wchar;
6719 xml_encoding encoding = encoding_utf8;
6722 return load_buffer(contents, impl::strlength(contents) *
sizeof(char_t),
6726PUGI__FN xml_parse_result xml_document::load(
const char_t* contents,
6728 return load_string(contents,
options);
6731PUGI__FN xml_parse_result xml_document::load_file(
const char* path_,
6733 xml_encoding encoding) {
6736 using impl::auto_deleter;
6739 return impl::load_file_impl(
static_cast<impl::xml_document_struct*
>(_root),
6740 file.data,
options, encoding, &_buffer);
6743PUGI__FN xml_parse_result xml_document::load_file(
const wchar_t* path_,
6745 xml_encoding encoding) {
6748 using impl::auto_deleter;
6751 return impl::load_file_impl(
static_cast<impl::xml_document_struct*
>(_root),
6752 file.data,
options, encoding, &_buffer);
6755PUGI__FN xml_parse_result xml_document::load_buffer(
const void* contents,
6758 xml_encoding encoding) {
6761 return impl::load_buffer_impl(
static_cast<impl::xml_document_struct*
>(_root),
6762 _root,
const_cast<void*
>(contents), size,
6763 options, encoding,
false,
false, &_buffer);
6766PUGI__FN xml_parse_result xml_document::load_buffer_inplace(
6767 void* contents,
size_t size,
unsigned int options, xml_encoding encoding) {
6770 return impl::load_buffer_impl(
static_cast<impl::xml_document_struct*
>(_root),
6771 _root, contents, size,
options, encoding,
true,
6775PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(
6776 void* contents,
size_t size,
unsigned int options, xml_encoding encoding) {
6779 return impl::load_buffer_impl(
static_cast<impl::xml_document_struct*
>(_root),
6780 _root, contents, size,
options, encoding,
true,
6784PUGI__FN
void xml_document::save(xml_writer& writer,
const char_t* indent,
6786 xml_encoding encoding)
const {
6787 impl::xml_buffered_writer buffered_writer(writer, encoding);
6789 if ((flags & format_write_bom) && encoding != encoding_latin1) {
6792#ifdef PUGIXML_WCHAR_MODE
6793 unsigned int bom = 0xfeff;
6794 buffered_writer.write(
static_cast<wchar_t>(bom));
6796 buffered_writer.write(
'\xef',
'\xbb',
'\xbf');
6800 if (!(flags & format_no_declaration) && !impl::has_declaration(_root)) {
6801 buffered_writer.write_string(PUGIXML_TEXT(
"<?xml version=\"1.0\""));
6802 if (encoding == encoding_latin1)
6803 buffered_writer.write_string(PUGIXML_TEXT(
" encoding=\"ISO-8859-1\""));
6804 buffered_writer.write(
'?',
'>');
6805 if (!(flags & format_raw)) buffered_writer.write(
'\n');
6808 impl::node_output(buffered_writer, _root, indent, flags, 0);
6810 buffered_writer.flush();
6813#ifndef PUGIXML_NO_STL
6814PUGI__FN
void xml_document::save(
6815 std::basic_ostream<
char, std::char_traits<char> >& stream,
6816 const char_t* indent,
unsigned int flags, xml_encoding encoding)
const {
6817 xml_writer_stream writer(stream);
6819 save(writer, indent, flags, encoding);
6822PUGI__FN
void xml_document::save(
6823 std::basic_ostream<
wchar_t, std::char_traits<wchar_t> >& stream,
6824 const char_t* indent,
unsigned int flags)
const {
6825 xml_writer_stream writer(stream);
6827 save(writer, indent, flags, encoding_wchar);
6831PUGI__FN
bool xml_document::save_file(
const char* path_,
const char_t* indent,
6833 xml_encoding encoding)
const {
6834 using impl::auto_deleter;
6836 fopen(path_, (flags & format_save_file_text) ?
"w" :
"wb"),
6839 return impl::save_file_impl(*
this, file.data, indent, flags, encoding);
6842PUGI__FN
bool xml_document::save_file(
const wchar_t* path_,
6843 const char_t* indent,
unsigned int flags,
6844 xml_encoding encoding)
const {
6845 using impl::auto_deleter;
6847 impl::open_file_wide(path_,
6848 (flags & format_save_file_text) ? L
"w" : L
"wb"),
6851 return impl::save_file_impl(*
this, file.data, indent, flags, encoding);
6854PUGI__FN xml_node xml_document::document_element()
const {
6857 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
6858 if (PUGI__NODETYPE(i) == node_element)
return xml_node(i);
6863#ifndef PUGIXML_NO_STL
6864PUGI__FN std::string PUGIXML_FUNCTION as_utf8(
const wchar_t* str) {
6867 return impl::as_utf8_impl(str, impl::strlength_wide(str));
6870PUGI__FN std::string PUGIXML_FUNCTION
6871as_utf8(
const std::basic_string<wchar_t>& str) {
6872 return impl::as_utf8_impl(str.c_str(), str.size());
6875PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(
const char* str) {
6878 return impl::as_wide_impl(str, strlen(str));
6881PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION
6882as_wide(
const std::string& str) {
6883 return impl::as_wide_impl(str.c_str(), str.size());
6887PUGI__FN
void PUGIXML_FUNCTION set_memory_management_functions(
6888 allocation_function allocate, deallocation_function deallocate) {
6889 impl::xml_memory::allocate = allocate;
6890 impl::xml_memory::deallocate = deallocate;
6893PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function() {
6894 return impl::xml_memory::allocate;
6897PUGI__FN deallocation_function PUGIXML_FUNCTION
6898get_memory_deallocation_function() {
6899 return impl::xml_memory::deallocate;
6903#if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
6907PUGI__FN std::bidirectional_iterator_tag _Iter_cat(
6909 return std::bidirectional_iterator_tag();
6912PUGI__FN std::bidirectional_iterator_tag _Iter_cat(
6914 return std::bidirectional_iterator_tag();
6917PUGI__FN std::bidirectional_iterator_tag _Iter_cat(
6919 return std::bidirectional_iterator_tag();
6924#if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
6927PUGI__FN std::bidirectional_iterator_tag __iterator_category(
6929 return std::bidirectional_iterator_tag();
6932PUGI__FN std::bidirectional_iterator_tag __iterator_category(
6934 return std::bidirectional_iterator_tag();
6937PUGI__FN std::bidirectional_iterator_tag __iterator_category(
6939 return std::bidirectional_iterator_tag();
6944#ifndef PUGIXML_NO_XPATH
6948 template <
typename T>
6949 bool operator()(
const T& lhs,
const T& rhs)
const {
6955 template <
typename T>
6956 bool operator()(
const T& lhs,
const T& rhs)
const {
6962 template <
typename T>
6963 bool operator()(
const T& lhs,
const T& rhs)
const {
6969 template <
typename T>
6970 bool operator()(
const T& lhs,
const T& rhs)
const {
6975template <
typename T>
6976void swap(T& lhs, T& rhs) {
6982template <
typename I,
typename Pred>
6983I min_element(I begin, I end,
const Pred& pred) {
6986 for (I it = begin + 1; it != end; ++it)
6987 if (pred(*it, *result)) result = it;
6992template <
typename I>
6993void reverse(I begin, I end) {
6994 while (end - begin > 1) swap(*begin++, *--end);
6997template <
typename I>
6998I unique(I begin, I end) {
7000 while (end - begin > 1 && *begin != *(begin + 1)) begin++;
7002 if (begin == end)
return begin;
7008 while (begin != end) {
7009 if (*begin != *write)
7010 *++write = *begin++;
7019template <
typename I>
7020void copy_backwards(I begin, I end, I target) {
7021 while (begin != end) *--target = *--end;
7024template <
typename I,
typename Pred,
typename T>
7025void insertion_sort(I begin, I end,
const Pred& pred, T*) {
7026 assert(begin != end);
7028 for (I it = begin + 1; it != end; ++it) {
7031 if (pred(val, *begin)) {
7033 copy_backwards(begin, it, it + 1);
7039 while (pred(val, *(hole - 1))) {
7040 *hole = *(hole - 1);
7051template <
typename I,
typename Pred>
7052void partition(I begin, I middle, I end,
const Pred& pred, I* out_eqbeg,
7054 I eqbeg = middle, eqend = middle + 1;
7057 while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg;
7058 while (eqend != end && *eqend == *eqbeg) ++eqend;
7061 I ltend = eqbeg, gtbeg = eqend;
7065 for (; gtbeg != end; ++gtbeg)
7066 if (!pred(*eqbeg, *gtbeg)) {
7067 if (*gtbeg == *eqbeg)
7068 swap(*gtbeg, *eqend++);
7074 for (; ltend != begin; --ltend)
7075 if (!pred(*(ltend - 1), *eqbeg)) {
7076 if (*eqbeg == *(ltend - 1))
7077 swap(*(ltend - 1), *--eqbeg);
7083 if (gtbeg == end && ltend == begin) {
7091 if (--ltend != --eqbeg) swap(*ltend, *eqbeg);
7092 swap(*eqbeg, *--eqend);
7093 }
else if (ltend == begin) {
7094 if (eqend != gtbeg) swap(*eqbeg, *eqend);
7096 swap(*gtbeg++, *eqbeg++);
7098 swap(*gtbeg++, *--ltend);
7102template <
typename I,
typename Pred>
7103void median3(I first, I middle, I last,
const Pred& pred) {
7104 if (pred(*middle, *first)) swap(*middle, *first);
7105 if (pred(*last, *middle)) swap(*last, *middle);
7106 if (pred(*middle, *first)) swap(*middle, *first);
7109template <
typename I,
typename Pred>
7110void median(I first, I middle, I last,
const Pred& pred) {
7111 if (last - first <= 40) {
7113 median3(first, middle, last, pred);
7116 size_t step = (last - first + 1) / 8;
7118 median3(first, first + step, first + 2 * step, pred);
7119 median3(middle - step, middle, middle + step, pred);
7120 median3(last - 2 * step, last - step, last, pred);
7121 median3(first + step, middle, last - step, pred);
7125template <
typename I,
typename Pred>
7126void sort(I begin, I end,
const Pred& pred) {
7128 while (end - begin > 32) {
7130 I middle = begin + (end - begin) / 2;
7131 median(begin, middle, end - 1, pred);
7135 partition(begin, middle, end, pred, &eqbeg, &eqend);
7138 if (eqbeg - begin > end - eqend) {
7139 sort(eqend, end, pred);
7142 sort(begin, eqbeg, pred);
7148 if (begin != end) insertion_sort(begin, end, pred, &*begin);
7154static const size_t xpath_memory_page_size =
7155#ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
7156 PUGIXML_MEMORY_XPATH_PAGE_SIZE
7162static const uintptr_t xpath_memory_block_alignment =
sizeof(double) >
7172 char data[xpath_memory_page_size];
7182#ifdef PUGIXML_NO_EXCEPTIONS
7183 jmp_buf* error_handler;
7187 : _root(root), _root_size(root_size) {
7188#ifdef PUGIXML_NO_EXCEPTIONS
7193 void* allocate_nothrow(
size_t size) {
7195 size = (size + xpath_memory_block_alignment - 1) &
7196 ~(xpath_memory_block_alignment - 1);
7198 if (_root_size + size <= _root->capacity) {
7199 void* buf = &_root->data[0] + _root_size;
7205 size_t block_capacity_base =
sizeof(_root->data);
7206 size_t block_capacity_req = size + block_capacity_base / 4;
7207 size_t block_capacity = (block_capacity_base > block_capacity_req)
7208 ? block_capacity_base
7209 : block_capacity_req;
7215 if (!
block)
return 0;
7217 block->next = _root;
7218 block->capacity = block_capacity;
7227 void* allocate(
size_t size) {
7228 void* result = allocate_nothrow(size);
7231#ifdef PUGIXML_NO_EXCEPTIONS
7232 assert(error_handler);
7233 longjmp(*error_handler, 1);
7235 throw std::bad_alloc();
7242 void* reallocate(
void* ptr,
size_t old_size,
size_t new_size) {
7244 old_size = (old_size + xpath_memory_block_alignment - 1) &
7245 ~(xpath_memory_block_alignment - 1);
7246 new_size = (new_size + xpath_memory_block_alignment - 1) &
7247 ~(xpath_memory_block_alignment - 1);
7251 static_cast<char*
>(ptr) + old_size == &_root->data[0] + _root_size);
7254 bool only_object = (_root_size == old_size);
7256 if (ptr) _root_size -= old_size;
7259 void* result = allocate(new_size);
7263 if (result != ptr && ptr) {
7265 assert(new_size >= old_size);
7266 memcpy(result, ptr, old_size);
7270 assert(_root->data == result);
7271 assert(_root->next);
7277 xml_memory::deallocate(_root->next);
7290 while (cur != state._root) {
7293 xml_memory::deallocate(cur);
7299 _root = state._root;
7300 _root_size = state._root_size;
7310 xml_memory::deallocate(cur);
7319 : _target(alloc), _state(*alloc) {}
7338#ifdef PUGIXML_NO_EXCEPTIONS
7339 jmp_buf error_handler;
7343 blocks[0].next = blocks[1].next = 0;
7344 blocks[0].capacity = blocks[1].capacity =
sizeof(blocks[0].data);
7346 stack.result = &result;
7349#ifdef PUGIXML_NO_EXCEPTIONS
7350 result.error_handler = temp.error_handler = &error_handler;
7364 const char_t* _buffer;
7366 size_t _length_heap;
7368 static char_t* duplicate_string(
const char_t*
string,
size_t length,
7371 static_cast<char_t*
>(alloc->allocate((length + 1) *
sizeof(char_t)));
7374 memcpy(result,
string, length *
sizeof(char_t));
7380 xpath_string(
const char_t* buffer,
bool uses_heap_,
size_t length_heap)
7381 : _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap) {}
7388 static xpath_string from_heap_preallocated(
const char_t* begin,
7389 const char_t* end) {
7390 assert(begin <= end && *end == 0);
7392 return xpath_string(begin,
true,
static_cast<size_t>(end - begin));
7395 static xpath_string from_heap(
const char_t* begin,
const char_t* end,
7397 assert(begin <= end);
7399 size_t length =
static_cast<size_t>(end - begin);
7407 : _buffer(PUGIXML_TEXT(
"")), _uses_heap(
false), _length_heap(0) {}
7411 if (!*o._buffer)
return;
7414 if (!*_buffer && !_uses_heap && !o._uses_heap) {
7415 _buffer = o._buffer;
7418 size_t target_length = length();
7419 size_t source_length = o.length();
7420 size_t result_length = target_length + source_length;
7423 char_t* result =
static_cast<char_t*
>(
7424 alloc->reallocate(_uses_heap ?
const_cast<char_t*
>(_buffer) : 0,
7425 (target_length + 1) *
sizeof(char_t),
7426 (result_length + 1) *
sizeof(char_t)));
7430 if (!_uses_heap) memcpy(result, _buffer, target_length *
sizeof(char_t));
7433 memcpy(result + target_length, o._buffer, source_length *
sizeof(char_t));
7434 result[result_length] = 0;
7439 _length_heap = result_length;
7443 const char_t* c_str()
const {
return _buffer; }
7445 size_t length()
const {
7446 return _uses_heap ? _length_heap : strlength(_buffer);
7452 size_t length_ = strlength(_buffer);
7454 _buffer = duplicate_string(_buffer, length_, alloc);
7456 _length_heap = length_;
7459 return const_cast<char_t*
>(_buffer);
7462 bool empty()
const {
return *_buffer == 0; }
7465 return strequal(_buffer, o._buffer);
7469 return !strequal(_buffer, o._buffer);
7472 bool uses_heap()
const {
return _uses_heap; }
7477PUGI__FN
bool starts_with(
const char_t*
string,
const char_t* pattern) {
7478 while (*pattern && *
string == *pattern) {
7483 return *pattern == 0;
7486PUGI__FN
const char_t* find_char(
const char_t* s, char_t c) {
7487#ifdef PUGIXML_WCHAR_MODE
7488 return wcschr(s, c);
7490 return strchr(s, c);
7494PUGI__FN
const char_t* find_substring(
const char_t* s,
const char_t* p) {
7495#ifdef PUGIXML_WCHAR_MODE
7497 return (*p == 0) ? s : wcsstr(s, p);
7499 return strstr(s, p);
7504PUGI__FN char_t tolower_ascii(char_t ch) {
7505 return static_cast<unsigned int>(ch -
'A') < 26
7506 ?
static_cast<char_t
>(ch |
' ')
7510PUGI__FN
xpath_string string_value(
const xpath_node& na,
7513 return xpath_string::from_const(na.attribute().value());
7515 xml_node n = na.node();
7522 return xpath_string::from_const(n.value());
7525 case node_element: {
7530 result.append(xpath_string::from_const(n.value()), alloc);
7532 xml_node cur = n.first_child();
7534 while (cur && cur != n) {
7535 if (cur.type() == node_pcdata || cur.type() == node_cdata)
7536 result.append(xpath_string::from_const(cur.value()), alloc);
7538 if (cur.first_child())
7539 cur = cur.first_child();
7540 else if (cur.next_sibling())
7541 cur = cur.next_sibling();
7543 while (!cur.next_sibling() && cur != n) cur = cur.parent();
7545 if (cur != n) cur = cur.next_sibling();
7558PUGI__FN
bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) {
7559 assert(ln->parent == rn->parent);
7563 if (!ln->parent)
return ln < rn;
7566 xml_node_struct* ls = ln;
7567 xml_node_struct* rs = rn;
7570 if (ls == rn)
return true;
7571 if (rs == ln)
return false;
7573 ls = ls->next_sibling;
7574 rs = rs->next_sibling;
7581PUGI__FN
bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) {
7583 xml_node_struct* lp = ln;
7584 xml_node_struct* rp = rn;
7586 while (lp && rp && lp->parent != rp->parent) {
7592 if (lp && rp)
return node_is_before_sibling(lp, rp);
7595 bool left_higher = !lp;
7608 if (ln == rn)
return left_higher;
7611 while (ln->parent != rn->parent) {
7616 return node_is_before_sibling(ln, rn);
7619PUGI__FN
bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node) {
7620 while (node && node != parent) node = node->parent;
7622 return parent && node == parent;
7625PUGI__FN
const void* document_buffer_order(
const xpath_node& xnode) {
7626 xml_node_struct* node = xnode.node().internal_object();
7629 if ((get_document(node).header & xml_memory_page_contents_shared_mask) ==
7633 impl::xml_memory_page_name_allocated_or_shared_mask) == 0)
7637 impl::xml_memory_page_value_allocated_or_shared_mask) == 0)
7644 xml_attribute_struct* attr = xnode.attribute().internal_object();
7647 if ((get_document(attr).header & xml_memory_page_contents_shared_mask) ==
7650 impl::xml_memory_page_name_allocated_or_shared_mask) == 0)
7653 impl::xml_memory_page_value_allocated_or_shared_mask) == 0)
7664 bool operator()(
const xpath_node& lhs,
const xpath_node& rhs)
const {
7666 const void* lo = document_buffer_order(lhs);
7667 const void* ro = document_buffer_order(rhs);
7669 if (lo && ro)
return lo < ro;
7672 xml_node ln = lhs.node(), rn = rhs.node();
7675 if (lhs.attribute() && rhs.attribute()) {
7677 if (lhs.parent() == rhs.parent()) {
7679 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
7680 if (a == rhs.attribute())
return true;
7688 }
else if (lhs.attribute()) {
7690 if (lhs.parent() == rhs.node())
return false;
7693 }
else if (rhs.attribute()) {
7695 if (rhs.parent() == lhs.node())
return true;
7700 if (ln == rn)
return false;
7702 if (!ln || !rn)
return ln < rn;
7704 return node_is_before(ln.internal_object(), rn.internal_object());
7709 bool operator()(
const xpath_node& lhs,
const xpath_node& rhs)
const {
7710 if (lhs.attribute())
7711 return rhs.attribute() ? lhs.attribute() < rhs.attribute() :
true;
7713 return rhs.attribute() ? false : lhs.node() < rhs.node();
7717PUGI__FN
double gen_nan() {
7718#if defined(__STDC_IEC_559__) || \
7719 ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && \
7720 (FLT_MANT_DIG - 0 == 24))
7721 PUGI__STATIC_ASSERT(
sizeof(
float) ==
sizeof(uint32_t));
7722 typedef uint32_t UI;
7731 const volatile double zero = 0.0;
7736PUGI__FN
bool is_nan(
double value) {
7737#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
7738 return !!_isnan(value);
7739#elif defined(fpclassify) && defined(FP_NAN)
7740 return fpclassify(value) == FP_NAN;
7743 const volatile double v = value;
7748PUGI__FN
const char_t* convert_number_to_string_special(
double value) {
7749#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
7750 if (_finite(value))
return (value == 0) ? PUGIXML_TEXT(
"0") : 0;
7751 if (_isnan(value))
return PUGIXML_TEXT(
"NaN");
7752 return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
7753#elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && \
7755 switch (fpclassify(value)) {
7757 return PUGIXML_TEXT(
"NaN");
7760 return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
7763 return PUGIXML_TEXT(
"0");
7770 const volatile double v = value;
7772 if (v == 0)
return PUGIXML_TEXT(
"0");
7773 if (v != v)
return PUGIXML_TEXT(
"NaN");
7775 return value > 0 ? PUGIXML_TEXT(
"Infinity") : PUGIXML_TEXT(
"-Infinity");
7780PUGI__FN
bool convert_number_to_boolean(
double value) {
7781 return (value != 0 && !is_nan(value));
7784PUGI__FN
void truncate_zeros(
char* begin,
char* end) {
7785 while (begin != end && end[-1] ==
'0') end--;
7791#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && \
7792 !defined(_WIN32_WCE)
7793PUGI__FN
void convert_number_to_mantissa_exponent(
double value,
char* buffer,
7795 char** out_mantissa,
7796 int* out_exponent) {
7799 _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign);
7802 truncate_zeros(buffer, buffer + strlen(buffer));
7805 *out_mantissa = buffer;
7806 *out_exponent = exponent;
7809PUGI__FN
void convert_number_to_mantissa_exponent(
double value,
char* buffer,
7811 char** out_mantissa,
7812 int* out_exponent) {
7814 sprintf(buffer,
"%.*e", DBL_DIG, value);
7815 assert(strlen(buffer) < buffer_size);
7819 char* exponent_string = strchr(buffer,
'e');
7820 assert(exponent_string);
7822 int exponent = atoi(exponent_string + 1);
7825 char* mantissa = buffer[0] ==
'-' ? buffer + 1 : buffer;
7826 assert(mantissa[0] !=
'0' && mantissa[1] ==
'.');
7829 mantissa[1] = mantissa[0];
7834 truncate_zeros(mantissa, exponent_string);
7837 *out_mantissa = mantissa;
7838 *out_exponent = exponent;
7842PUGI__FN
xpath_string convert_number_to_string(
double value,
7845 const char_t* special = convert_number_to_string_special(value);
7846 if (special)
return xpath_string::from_const(special);
7849 char mantissa_buffer[32];
7853 convert_number_to_mantissa_exponent(
7854 value, mantissa_buffer,
sizeof(mantissa_buffer), &mantissa, &exponent);
7857 size_t result_size =
7858 strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
7860 static_cast<char_t*
>(alloc->allocate(
sizeof(char_t) * result_size));
7867 if (value < 0) *s++ =
'-';
7870 if (exponent <= 0) {
7873 while (exponent > 0) {
7874 assert(*mantissa == 0 ||
7875 static_cast<unsigned int>(
static_cast<unsigned int>(*mantissa) -
7877 *s++ = *mantissa ? *mantissa++ :
'0';
7888 while (exponent < 0) {
7895 assert(
static_cast<unsigned int>(*mantissa -
'0') <= 9);
7901 assert(s < result + result_size);
7904 return xpath_string::from_heap_preallocated(result, s);
7907PUGI__FN
bool check_string_to_number_format(
const char_t*
string) {
7909 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
7912 if (*
string ==
'-') ++string;
7914 if (!*
string)
return false;
7918 if (!PUGI__IS_CHARTYPEX(
string[0], ctx_digit) &&
7919 (
string[0] !=
'.' || !PUGI__IS_CHARTYPEX(
string[1], ctx_digit)))
7923 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
7926 if (*
string ==
'.') {
7929 while (PUGI__IS_CHARTYPEX(*
string, ctx_digit)) ++string;
7933 while (PUGI__IS_CHARTYPE(*
string, ct_space)) ++string;
7935 return *
string == 0;
7938PUGI__FN
double convert_string_to_number(
const char_t*
string) {
7940 if (!check_string_to_number_format(
string))
return gen_nan();
7943#ifdef PUGIXML_WCHAR_MODE
7944 return wcstod(
string, 0);
7946 return strtod(
string, 0);
7950PUGI__FN
bool convert_string_to_number_scratch(char_t (&buffer)[32],
7951 const char_t* begin,
7953 double* out_result) {
7954 size_t length =
static_cast<size_t>(end - begin);
7955 char_t* scratch = buffer;
7957 if (length >=
sizeof(buffer) /
sizeof(buffer[0])) {
7959 scratch =
static_cast<char_t*
>(
7960 xml_memory::allocate((length + 1) *
sizeof(char_t)));
7961 if (!scratch)
return false;
7965 memcpy(scratch, begin, length *
sizeof(char_t));
7966 scratch[length] = 0;
7968 *out_result = convert_string_to_number(scratch);
7971 if (scratch != buffer) xml_memory::deallocate(scratch);
7976PUGI__FN
double round_nearest(
double value) {
return floor(value + 0.5); }
7978PUGI__FN
double round_nearest_nzero(
double value) {
7982 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
7985PUGI__FN
const char_t* qualified_name(
const xpath_node& node) {
7986 return node.attribute() ? node.attribute().name() : node.node().name();
7989PUGI__FN
const char_t* local_name(
const xpath_node& node) {
7990 const char_t* name = qualified_name(node);
7991 const char_t* p = find_char(name,
':');
7993 return p ? p + 1 : name;
7997 const char_t* prefix;
7998 size_t prefix_length;
8001 const char_t* pos = find_char(name,
':');
8003 prefix = pos ? name : 0;
8004 prefix_length = pos ?
static_cast<size_t>(pos - name) : 0;
8007 bool operator()(xml_attribute a)
const {
8008 const char_t* name = a.name();
8010 if (!starts_with(name, PUGIXML_TEXT(
"xmlns")))
return false;
8012 return prefix ? name[5] ==
':' &&
8013 strequalrange(name + 6, prefix, prefix_length)
8018PUGI__FN
const char_t* namespace_uri(xml_node node) {
8024 xml_attribute a = p.find_attribute(pred);
8026 if (a)
return a.value();
8031 return PUGIXML_TEXT(
"");
8034PUGI__FN
const char_t* namespace_uri(xml_attribute attr, xml_node parent) {
8038 if (!pred.prefix)
return PUGIXML_TEXT(
"");
8040 xml_node p = parent;
8043 xml_attribute a = p.find_attribute(pred);
8045 if (a)
return a.value();
8050 return PUGIXML_TEXT(
"");
8053PUGI__FN
const char_t* namespace_uri(
const xpath_node& node) {
8054 return node.attribute() ? namespace_uri(node.attribute(), node.parent())
8055 : namespace_uri(node.node());
8058PUGI__FN char_t* normalize_space(char_t* buffer) {
8059 char_t* write = buffer;
8061 for (char_t* it = buffer; *it;) {
8064 if (PUGI__IS_CHARTYPE(ch, ct_space)) {
8066 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
8069 if (write != buffer) *write++ =
' ';
8075 if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
8083PUGI__FN char_t* translate(char_t* buffer,
const char_t* from,
const char_t* to,
8085 char_t* write = buffer;
8088 PUGI__DMC_VOLATILE char_t ch = *buffer++;
8090 const char_t* pos = find_char(from, ch);
8094 else if (
static_cast<size_t>(pos - from) < to_length)
8095 *write++ = to[pos - from];
8104PUGI__FN
unsigned char* translate_table_generate(
xpath_allocator* alloc,
8107 unsigned char table[128] = {0};
8110 unsigned int fc =
static_cast<unsigned int>(*from);
8111 unsigned int tc =
static_cast<unsigned int>(*to);
8113 if (fc >= 128 || tc >= 128)
return 0;
8116 if (!table[fc]) table[fc] =
static_cast<unsigned char>(tc ? tc : 128);
8122 for (
int i = 0; i < 128; ++i)
8123 if (!table[i]) table[i] =
static_cast<unsigned char>(i);
8125 void* result = alloc->allocate_nothrow(
sizeof(table));
8128 memcpy(result, table,
sizeof(table));
8131 return static_cast<unsigned char*
>(result);
8134PUGI__FN char_t* translate_table(char_t* buffer,
const unsigned char* table) {
8135 char_t* write = buffer;
8138 char_t ch = *buffer++;
8139 unsigned int index =
static_cast<unsigned int>(ch);
8142 unsigned char code = table[index];
8146 *write =
static_cast<char_t
>(code);
8147 write += 1 - (code >> 7);
8159inline bool is_xpath_attribute(
const char_t* name) {
8160 return !(starts_with(name, PUGIXML_TEXT(
"xmlns")) &&
8161 (name[5] == 0 || name[5] ==
':'));
8182 if (value) xml_memory::deallocate(value);
8192 xpath_node_set value;
8196static const xpath_node_set dummy_node_set;
8198PUGI__FN
unsigned int hash_string(
const char_t* str) {
8201 unsigned int result = 0;
8204 result +=
static_cast<unsigned int>(*str++);
8205 result += result << 10;
8206 result ^= result >> 6;
8209 result += result << 3;
8210 result ^= result >> 11;
8211 result += result << 15;
8216template <
typename T>
8217PUGI__FN T* new_xpath_variable(
const char_t* name) {
8218 size_t length = strlength(name);
8219 if (length == 0)
return 0;
8223 void* memory = xml_memory::allocate(
sizeof(T) + length *
sizeof(char_t));
8224 if (!memory)
return 0;
8226 T* result =
new (memory) T();
8228 memcpy(result->name, name, (length + 1) *
sizeof(char_t));
8233PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type,
8234 const char_t* name) {
8236 case xpath_type_node_set:
8237 return new_xpath_variable<xpath_variable_node_set>(name);
8239 case xpath_type_number:
8240 return new_xpath_variable<xpath_variable_number>(name);
8242 case xpath_type_string:
8243 return new_xpath_variable<xpath_variable_string>(name);
8245 case xpath_type_boolean:
8246 return new_xpath_variable<xpath_variable_boolean>(name);
8253template <
typename T>
8254PUGI__FN
void delete_xpath_variable(T* var) {
8256 xml_memory::deallocate(var);
8259PUGI__FN
void delete_xpath_variable(xpath_value_type type,
8260 xpath_variable* var) {
8262 case xpath_type_node_set:
8266 case xpath_type_number:
8270 case xpath_type_string:
8274 case xpath_type_boolean:
8279 assert(
false &&
"Invalid variable type");
8283PUGI__FN
bool copy_xpath_variable(xpath_variable* lhs,
8284 const xpath_variable* rhs) {
8285 switch (rhs->type()) {
8286 case xpath_type_node_set:
8289 case xpath_type_number:
8292 case xpath_type_string:
8295 case xpath_type_boolean:
8299 assert(
false &&
"Invalid variable type");
8304PUGI__FN
bool get_variable_scratch(char_t (&buffer)[32],
8305 xpath_variable_set* set,
const char_t* begin,
8307 xpath_variable** out_result) {
8308 size_t length =
static_cast<size_t>(end - begin);
8309 char_t* scratch = buffer;
8311 if (length >=
sizeof(buffer) /
sizeof(buffer[0])) {
8313 scratch =
static_cast<char_t*
>(
8314 xml_memory::allocate((length + 1) *
sizeof(char_t)));
8315 if (!scratch)
return false;
8319 memcpy(scratch, begin, length *
sizeof(char_t));
8320 scratch[length] = 0;
8322 *out_result = set->get(scratch);
8325 if (scratch != buffer) xml_memory::deallocate(scratch);
8333PUGI__FN xpath_node_set::type_t xpath_get_order(
const xpath_node* begin,
8334 const xpath_node* end) {
8335 if (end - begin < 2)
return xpath_node_set::type_sorted;
8339 bool first = cmp(begin[0], begin[1]);
8341 for (
const xpath_node* it = begin + 1; it + 1 < end; ++it)
8342 if (cmp(it[0], it[1]) != first)
return xpath_node_set::type_unsorted;
8344 return first ? xpath_node_set::type_sorted
8345 : xpath_node_set::type_sorted_reverse;
8348PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end,
8349 xpath_node_set::type_t type,
8351 xpath_node_set::type_t order =
8352 rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
8354 if (type == xpath_node_set::type_unsorted) {
8355 xpath_node_set::type_t sorted = xpath_get_order(begin, end);
8357 if (sorted == xpath_node_set::type_unsorted) {
8360 type = xpath_node_set::type_sorted;
8365 if (type != order) reverse(begin, end);
8370PUGI__FN xpath_node xpath_first(
const xpath_node* begin,
const xpath_node* end,
8371 xpath_node_set::type_t type) {
8372 if (begin == end)
return xpath_node();
8375 case xpath_node_set::type_sorted:
8378 case xpath_node_set::type_sorted_reverse:
8381 case xpath_node_set::type_unsorted:
8385 assert(
false &&
"Invalid node set type");
8386 return xpath_node();
8391 xpath_node_set::type_t _type;
8399 : _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0) {}
8401 xpath_node* begin()
const {
return _begin; }
8403 xpath_node* end()
const {
return _end; }
8405 bool empty()
const {
return _begin == _end; }
8407 size_t size()
const {
return static_cast<size_t>(_end - _begin); }
8409 xpath_node first()
const {
return xpath_first(_begin, _end, _type); }
8417 push_back_grow(node, alloc);
8420 void append(
const xpath_node* begin_,
const xpath_node* end_,
8422 if (begin_ == end_)
return;
8424 size_t size_ =
static_cast<size_t>(_end - _begin);
8425 size_t capacity =
static_cast<size_t>(_eos - _begin);
8426 size_t count =
static_cast<size_t>(end_ - begin_);
8428 if (size_ + count > capacity) {
8430 xpath_node* data =
static_cast<xpath_node*
>(
8431 alloc->reallocate(_begin, capacity *
sizeof(xpath_node),
8432 (size_ + count) *
sizeof(xpath_node)));
8437 _end = data + size_;
8438 _eos = data + size_ + count;
8441 memcpy(_end, begin_, count *
sizeof(xpath_node));
8445 void sort_do() { _type = xpath_sort(_begin, _end, _type,
false); }
8447 void truncate(xpath_node* pos) {
8448 assert(_begin <= pos && pos <= _end);
8453 void remove_duplicates() {
8454 if (_type == xpath_node_set::type_unsorted)
8457 _end = unique(_begin, _end);
8460 xpath_node_set::type_t type()
const {
return _type; }
8462 void set_type(xpath_node_set::type_t value) { _type = value; }
8465PUGI__FN_NO_INLINE
void xpath_node_set_raw::push_back_grow(
8467 size_t capacity =
static_cast<size_t>(_eos - _begin);
8470 size_t new_capacity = capacity + capacity / 2 + 1;
8473 xpath_node* data =
static_cast<xpath_node*
>(
8474 alloc->reallocate(_begin, capacity *
sizeof(xpath_node),
8475 new_capacity *
sizeof(xpath_node)));
8480 _end = data + capacity;
8481 _eos = data + new_capacity;
8491 size_t position, size;
8493 xpath_context(
const xpath_node& n_,
size_t position_,
size_t size_)
8494 : n(n_), position(position_), size(size_) {}
8504 lex_greater_or_equal,
8516 lex_open_square_brace,
8517 lex_close_square_brace,
8528 const char_t* begin;
8533 bool operator==(
const char_t* other)
const {
8534 size_t length =
static_cast<size_t>(end - begin);
8536 return strequalrange(other, begin, length);
8542 const char_t* _cur_lexeme_pos;
8545 lexeme_t _cur_lexeme;
8548 explicit xpath_lexer(
const char_t* query) : _cur(query) { next(); }
8550 const char_t* state()
const {
return _cur; }
8553 const char_t* cur = _cur;
8555 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
8558 _cur_lexeme_pos = cur;
8562 _cur_lexeme = lex_eof;
8566 if (*(cur + 1) ==
'=') {
8568 _cur_lexeme = lex_greater_or_equal;
8571 _cur_lexeme = lex_greater;
8576 if (*(cur + 1) ==
'=') {
8578 _cur_lexeme = lex_less_or_equal;
8581 _cur_lexeme = lex_less;
8586 if (*(cur + 1) ==
'=') {
8588 _cur_lexeme = lex_not_equal;
8590 _cur_lexeme = lex_none;
8596 _cur_lexeme = lex_equal;
8602 _cur_lexeme = lex_plus;
8608 _cur_lexeme = lex_minus;
8614 _cur_lexeme = lex_multiply;
8620 _cur_lexeme = lex_union;
8627 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) {
8628 _cur_lexeme_contents.begin = cur;
8630 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
8632 if (cur[0] ==
':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
8636 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
8639 _cur_lexeme_contents.end = cur;
8641 _cur_lexeme = lex_var_ref;
8643 _cur_lexeme = lex_none;
8650 _cur_lexeme = lex_open_brace;
8656 _cur_lexeme = lex_close_brace;
8662 _cur_lexeme = lex_open_square_brace;
8668 _cur_lexeme = lex_close_square_brace;
8674 _cur_lexeme = lex_comma;
8679 if (*(cur + 1) ==
'/') {
8681 _cur_lexeme = lex_double_slash;
8684 _cur_lexeme = lex_slash;
8689 if (*(cur + 1) ==
'.') {
8691 _cur_lexeme = lex_double_dot;
8692 }
else if (PUGI__IS_CHARTYPEX(*(cur + 1), ctx_digit)) {
8693 _cur_lexeme_contents.begin = cur;
8697 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
8699 _cur_lexeme_contents.end = cur;
8701 _cur_lexeme = lex_number;
8704 _cur_lexeme = lex_dot;
8710 _cur_lexeme = lex_axis_attribute;
8716 char_t terminator = *cur;
8720 _cur_lexeme_contents.begin = cur;
8721 while (*cur && *cur != terminator) cur++;
8722 _cur_lexeme_contents.end = cur;
8725 _cur_lexeme = lex_none;
8728 _cur_lexeme = lex_quoted_string;
8735 if (*(cur + 1) ==
':') {
8737 _cur_lexeme = lex_double_colon;
8739 _cur_lexeme = lex_none;
8744 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) {
8745 _cur_lexeme_contents.begin = cur;
8747 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
8752 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
8755 _cur_lexeme_contents.end = cur;
8757 _cur_lexeme = lex_number;
8758 }
else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) {
8759 _cur_lexeme_contents.begin = cur;
8761 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
8763 if (cur[0] ==
':') {
8767 }
else if (PUGI__IS_CHARTYPEX(cur[1],
8772 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
8776 _cur_lexeme_contents.end = cur;
8778 _cur_lexeme = lex_string;
8780 _cur_lexeme = lex_none;
8787 lexeme_t current()
const {
return _cur_lexeme; }
8789 const char_t* current_pos()
const {
return _cur_lexeme_pos; }
8792 assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number ||
8793 _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
8795 return _cur_lexeme_contents;
8807 ast_op_less_or_equal,
8808 ast_op_greater_or_equal,
8818 ast_string_constant,
8819 ast_number_constant,
8825 ast_func_local_name_0,
8826 ast_func_local_name_1,
8827 ast_func_namespace_uri_0,
8828 ast_func_namespace_uri_1,
8834 ast_func_starts_with,
8836 ast_func_substring_before,
8837 ast_func_substring_after,
8838 ast_func_substring_2,
8839 ast_func_substring_3,
8840 ast_func_string_length_0,
8841 ast_func_string_length_1,
8842 ast_func_normalize_space_0,
8843 ast_func_normalize_space_1,
8859 ast_opt_translate_table,
8861 ast_opt_compare_attribute
8866 axis_ancestor_or_self,
8870 axis_descendant_or_self,
8872 axis_following_sibling,
8876 axis_preceding_sibling,
8884 nodetest_type_comment,
8889 nodetest_all_in_namespace
8896 predicate_constant_one
8899enum nodeset_eval_t { nodeset_eval_all, nodeset_eval_any, nodeset_eval_first };
8903 static const axis_t axis;
8928 const char_t* string;
8932 xpath_variable* variable;
8934 const char_t* nodetest;
8936 const unsigned char* table;
8942 template <
class Comp>
8946 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
8948 if (lt != xpath_type_node_set && rt != xpath_type_node_set) {
8949 if (lt == xpath_type_boolean || rt == xpath_type_boolean)
8950 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
8951 else if (lt == xpath_type_number || rt == xpath_type_number)
8952 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
8953 else if (lt == xpath_type_string || rt == xpath_type_string) {
8959 return comp(ls, rs);
8961 }
else if (lt == xpath_type_node_set && rt == xpath_type_node_set) {
8967 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li)
8968 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) {
8971 if (comp(string_value(*li, stack.result),
8972 string_value(*ri, stack.result)))
8978 if (lt == xpath_type_node_set) {
8983 if (lt == xpath_type_boolean)
8984 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
8985 else if (lt == xpath_type_number) {
8988 double l = lhs->eval_number(c, stack);
8991 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) {
8994 if (comp(l, convert_string_to_number(
8995 string_value(*ri, stack.result).c_str())))
9000 }
else if (lt == xpath_type_string) {
9006 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) {
9009 if (comp(l, string_value(*ri, stack.result)))
return true;
9016 assert(
false &&
"Wrong types");
9020 static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) {
9021 return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all
9022 : eval == nodeset_eval_any;
9025 template <
class Comp>
9029 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
9031 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
9032 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
9033 else if (lt == xpath_type_node_set && rt == xpath_type_node_set) {
9039 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li) {
9043 convert_string_to_number(string_value(*li, stack.result).c_str());
9045 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) {
9048 if (comp(l, convert_string_to_number(
9049 string_value(*ri, stack.result).c_str())))
9055 }
else if (lt != xpath_type_node_set && rt == xpath_type_node_set) {
9058 double l = lhs->eval_number(c, stack);
9061 for (
const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri) {
9064 if (comp(l, convert_string_to_number(
9065 string_value(*ri, stack.result).c_str())))
9070 }
else if (lt == xpath_type_node_set && rt != xpath_type_node_set) {
9074 double r = rhs->eval_number(c, stack);
9076 for (
const xpath_node* li = ls.begin(); li != ls.end(); ++li) {
9079 if (comp(convert_string_to_number(
9080 string_value(*li, stack.result).c_str()),
9087 assert(
false &&
"Wrong types");
9095 assert(ns.size() >= first);
9096 assert(expr->rettype() != xpath_type_number);
9099 size_t size = ns.size() - first;
9101 xpath_node* last = ns.begin() + first;
9104 for (xpath_node* it = last; it != ns.end(); ++it, ++i) {
9107 if (expr->eval_boolean(c, stack)) {
9120 assert(ns.size() >= first);
9121 assert(expr->rettype() == xpath_type_number);
9124 size_t size = ns.size() - first;
9126 xpath_node* last = ns.begin() + first;
9129 for (xpath_node* it = last; it != ns.end(); ++it, ++i) {
9132 if (expr->eval_number(c, stack) == i) {
9145 assert(ns.size() >= first);
9146 assert(expr->rettype() == xpath_type_number);
9148 size_t size = ns.size() - first;
9150 xpath_node* last = ns.begin() + first;
9154 double er = expr->eval_number(c, stack);
9156 if (er >= 1.0 && er <= size) {
9157 size_t eri =
static_cast<size_t>(er);
9160 xpath_node r = last[eri - 1];
9171 if (ns.size() == first)
return;
9173 assert(_type == ast_filter || _type == ast_predicate);
9175 if (_test == predicate_constant || _test == predicate_constant_one)
9176 apply_predicate_number_const(ns, first, _right, stack);
9177 else if (_right->rettype() == xpath_type_number)
9178 apply_predicate_number(ns, first, _right, stack, once);
9180 apply_predicate_boolean(ns, first, _right, stack, once);
9185 if (ns.size() == first)
return;
9187 bool last_once = eval_once(ns.type(), eval);
9190 pred->apply_predicate(ns, first, stack, !pred->_next && last_once);
9197 const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT(
"");
9201 if (strequal(name, _data.nodetest) && is_xpath_attribute(name)) {
9202 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9207 case nodetest_type_node:
9209 if (is_xpath_attribute(name)) {
9210 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9215 case nodetest_all_in_namespace:
9216 if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) {
9217 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
9232 xml_node_type type = PUGI__NODETYPE(n);
9236 if (type == node_element && n->name &&
9237 strequal(n->name, _data.nodetest)) {
9238 ns.push_back(xml_node(n), alloc);
9243 case nodetest_type_node:
9244 ns.push_back(xml_node(n), alloc);
9247 case nodetest_type_comment:
9248 if (type == node_comment) {
9249 ns.push_back(xml_node(n), alloc);
9254 case nodetest_type_text:
9255 if (type == node_pcdata || type == node_cdata) {
9256 ns.push_back(xml_node(n), alloc);
9261 case nodetest_type_pi:
9262 if (type == node_pi) {
9263 ns.push_back(xml_node(n), alloc);
9269 if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) {
9270 ns.push_back(xml_node(n), alloc);
9276 if (type == node_element) {
9277 ns.push_back(xml_node(n), alloc);
9282 case nodetest_all_in_namespace:
9283 if (type == node_element && n->name &&
9284 starts_with(n->name, _data.nodetest)) {
9285 ns.push_back(xml_node(n), alloc);
9291 assert(
false &&
"Unknown axis");
9300 const axis_t axis = T::axis;
9303 case axis_attribute: {
9304 for (xml_attribute_struct* a = n->first_attribute; a;
9305 a = a->next_attribute)
9306 if (step_push(ns, a, n, alloc) & once)
return;
9312 for (xml_node_struct* c = n->first_child; c; c = c->next_sibling)
9313 if (step_push(ns, c, alloc) & once)
return;
9318 case axis_descendant:
9319 case axis_descendant_or_self: {
9320 if (axis == axis_descendant_or_self)
9321 if (step_push(ns, n, alloc) & once)
return;
9323 xml_node_struct* cur = n->first_child;
9326 if (step_push(ns, cur, alloc) & once)
return;
9328 if (cur->first_child)
9329 cur = cur->first_child;
9331 while (!cur->next_sibling) {
9334 if (cur == n)
return;
9337 cur = cur->next_sibling;
9344 case axis_following_sibling: {
9345 for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling)
9346 if (step_push(ns, c, alloc) & once)
return;
9351 case axis_preceding_sibling: {
9352 for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling;
9353 c = c->prev_sibling_c)
9354 if (step_push(ns, c, alloc) & once)
return;
9359 case axis_following: {
9360 xml_node_struct* cur = n;
9363 while (!cur->next_sibling) {
9369 cur = cur->next_sibling;
9372 if (step_push(ns, cur, alloc) & once)
return;
9374 if (cur->first_child)
9375 cur = cur->first_child;
9377 while (!cur->next_sibling) {
9383 cur = cur->next_sibling;
9390 case axis_preceding: {
9391 xml_node_struct* cur = n;
9394 while (!cur->prev_sibling_c->next_sibling) {
9400 cur = cur->prev_sibling_c;
9403 if (cur->first_child)
9404 cur = cur->first_child->prev_sibling_c;
9407 if (step_push(ns, cur, alloc) & once)
return;
9409 while (!cur->prev_sibling_c->next_sibling) {
9414 if (!node_is_ancestor(cur, n))
9415 if (step_push(ns, cur, alloc) & once)
return;
9418 cur = cur->prev_sibling_c;
9426 case axis_ancestor_or_self: {
9427 if (axis == axis_ancestor_or_self)
9428 if (step_push(ns, n, alloc) & once)
return;
9430 xml_node_struct* cur = n->parent;
9433 if (step_push(ns, cur, alloc) & once)
return;
9442 step_push(ns, n, alloc);
9448 if (n->parent) step_push(ns, n->parent, alloc);
9454 assert(
false &&
"Unimplemented axis");
9461 const axis_t axis = T::axis;
9465 case axis_ancestor_or_self: {
9466 if (axis == axis_ancestor_or_self &&
9467 _test == nodetest_type_node)
9469 if (step_push(ns, a, p, alloc) & once)
return;
9471 xml_node_struct* cur = p;
9474 if (step_push(ns, cur, alloc) & once)
return;
9482 case axis_descendant_or_self:
9484 if (_test == nodetest_type_node)
9486 step_push(ns, a, p, alloc);
9491 case axis_following: {
9492 xml_node_struct* cur = p;
9495 if (cur->first_child)
9496 cur = cur->first_child;
9498 while (!cur->next_sibling) {
9504 cur = cur->next_sibling;
9507 if (step_push(ns, cur, alloc) & once)
return;
9514 step_push(ns, p, alloc);
9519 case axis_preceding: {
9523 step_fill(ns, p, alloc, once, v);
9528 assert(
false &&
"Unimplemented axis");
9535 const axis_t axis = T::axis;
9536 const bool axis_has_attributes =
9537 (axis == axis_ancestor || axis == axis_ancestor_or_self ||
9538 axis == axis_descendant_or_self || axis == axis_following ||
9539 axis == axis_parent || axis == axis_preceding || axis == axis_self);
9542 step_fill(ns, xn.node().internal_object(), alloc, once, v);
9543 else if (axis_has_attributes && xn.attribute() && xn.parent())
9544 step_fill(ns, xn.attribute().internal_object(),
9545 xn.parent().internal_object(), alloc, once, v);
9550 nodeset_eval_t eval, T v) {
9551 const axis_t axis = T::axis;
9552 const bool axis_reverse =
9553 (axis == axis_ancestor || axis == axis_ancestor_or_self ||
9554 axis == axis_preceding || axis == axis_preceding_sibling);
9555 const xpath_node_set::type_t axis_type =
9556 axis_reverse ? xpath_node_set::type_sorted_reverse
9557 : xpath_node_set::type_sorted;
9560 (axis == axis_attribute && _test == nodetest_name) ||
9561 (!_right && eval_once(axis_type, eval)) ||
9562 (_right && !_right->_next && _right->_test == predicate_constant_one);
9565 ns.set_type(axis_type);
9571 if (axis == axis_self) ns.set_type(s.type());
9573 for (
const xpath_node* it = s.begin(); it != s.end(); ++it) {
9574 size_t size = ns.size();
9578 if (axis != axis_self && size != 0)
9579 ns.set_type(xpath_node_set::type_unsorted);
9581 step_fill(ns, *it, stack.result, once, v);
9582 if (_right) apply_predicates(ns, size, stack, eval);
9585 step_fill(ns, c.n, stack.result, once, v);
9586 if (_right) apply_predicates(ns, 0, stack, eval);
9592 if (axis != axis_child && axis != axis_attribute && axis != axis_self &&
9593 ns.type() == xpath_node_set::type_unsorted)
9594 ns.remove_duplicates();
9601 const char_t* value)
9602 : _type(
static_cast<char>(type)),
9603 _rettype(
static_cast<char>(rettype_)),
9609 assert(type == ast_string_constant);
9610 _data.string = value;
9613 xpath_ast_node(ast_type_t type, xpath_value_type rettype_,
double value)
9614 : _type(
static_cast<char>(type)),
9615 _rettype(
static_cast<char>(rettype_)),
9621 assert(type == ast_number_constant);
9622 _data.number = value;
9626 xpath_variable* value)
9627 : _type(
static_cast<char>(type)),
9628 _rettype(
static_cast<char>(rettype_)),
9634 assert(type == ast_variable);
9635 _data.variable = value;
9640 : _type(
static_cast<char>(type)),
9641 _rettype(
static_cast<char>(rettype_)),
9649 nodetest_t test,
const char_t* contents)
9650 : _type(
static_cast<char>(type)),
9651 _rettype(xpath_type_node_set),
9652 _axis(
static_cast<char>(axis)),
9653 _test(
static_cast<char>(test)),
9657 assert(type == ast_step);
9658 _data.nodetest = contents;
9663 : _type(
static_cast<char>(type)),
9664 _rettype(xpath_type_node_set),
9666 _test(
static_cast<char>(test)),
9670 assert(type == ast_filter || type == ast_predicate);
9680 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
9683 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
9686 return compare_eq(_left, _right, c, stack,
equal_to());
9688 case ast_op_not_equal:
9689 return compare_eq(_left, _right, c, stack,
not_equal_to());
9692 return compare_rel(_left, _right, c, stack,
less());
9694 case ast_op_greater:
9695 return compare_rel(_right, _left, c, stack,
less());
9697 case ast_op_less_or_equal:
9698 return compare_rel(_left, _right, c, stack,
less_equal());
9700 case ast_op_greater_or_equal:
9701 return compare_rel(_right, _left, c, stack,
less_equal());
9703 case ast_func_starts_with: {
9709 return starts_with(lr.c_str(), rr.c_str());
9712 case ast_func_contains: {
9718 return find_substring(lr.c_str(), rr.c_str()) != 0;
9721 case ast_func_boolean:
9722 return _left->eval_boolean(c, stack);
9725 return !_left->eval_boolean(c, stack);
9730 case ast_func_false:
9733 case ast_func_lang: {
9734 if (c.n.attribute())
return false;
9740 for (xml_node n = c.n.node(); n; n = n.parent()) {
9741 xml_attribute a = n.attribute(PUGIXML_TEXT(
"xml:lang"));
9744 const char_t* value = a.value();
9747 for (
const char_t* lit = lang.c_str(); *lit; ++lit) {
9748 if (tolower_ascii(*lit) != tolower_ascii(*value))
return false;
9752 return *value == 0 || *value ==
'-';
9759 case ast_opt_compare_attribute: {
9760 const char_t* value = (_right->_type == ast_string_constant)
9761 ? _right->_data.string
9762 : _right->_data.variable->get_string();
9764 xml_attribute attr = c.n.node().attribute(_left->_data.nodetest);
9766 return attr && strequal(attr.value(), value) &&
9767 is_xpath_attribute(attr.name());
9770 case ast_variable: {
9771 assert(_rettype == _data.variable->type());
9773 if (_rettype == xpath_type_boolean)
9774 return _data.variable->get_boolean();
9780 case xpath_type_number:
9781 return convert_number_to_boolean(eval_number(c, stack));
9783 case xpath_type_string: {
9786 return !eval_string(c, stack).empty();
9789 case xpath_type_node_set: {
9792 return !eval_node_set(c, stack, nodeset_eval_any).empty();
9796 assert(
false &&
"Wrong expression for return type boolean");
9806 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
9808 case ast_op_subtract:
9809 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
9811 case ast_op_multiply:
9812 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
9815 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
9818 return fmod(_left->eval_number(c, stack),
9819 _right->eval_number(c, stack));
9822 return -_left->eval_number(c, stack);
9824 case ast_number_constant:
9825 return _data.number;
9828 return static_cast<double>(c.size);
9830 case ast_func_position:
9831 return static_cast<double>(c.position);
9833 case ast_func_count: {
9836 return static_cast<double>(
9837 _left->eval_node_set(c, stack, nodeset_eval_all).size());
9840 case ast_func_string_length_0: {
9843 return static_cast<double>(string_value(c.n, stack.result).length());
9846 case ast_func_string_length_1: {
9849 return static_cast<double>(_left->eval_string(c, stack).length());
9852 case ast_func_number_0: {
9855 return convert_string_to_number(
9856 string_value(c.n, stack.result).c_str());
9859 case ast_func_number_1:
9860 return _left->eval_number(c, stack);
9862 case ast_func_sum: {
9868 _left->eval_node_set(c, stack, nodeset_eval_all);
9870 for (
const xpath_node* it = ns.begin(); it != ns.end(); ++it) {
9874 convert_string_to_number(string_value(*it, stack.result).c_str());
9880 case ast_func_floor: {
9881 double r = _left->eval_number(c, stack);
9883 return r == r ? floor(r) : r;
9886 case ast_func_ceiling: {
9887 double r = _left->eval_number(c, stack);
9889 return r == r ? ceil(r) : r;
9892 case ast_func_round:
9893 return round_nearest_nzero(_left->eval_number(c, stack));
9895 case ast_variable: {
9896 assert(_rettype == _data.variable->type());
9898 if (_rettype == xpath_type_number)
return _data.variable->get_number();
9904 case xpath_type_boolean:
9905 return eval_boolean(c, stack) ? 1 : 0;
9907 case xpath_type_string: {
9910 return convert_string_to_number(eval_string(c, stack).c_str());
9913 case xpath_type_node_set: {
9916 return convert_string_to_number(eval_string(c, stack).c_str());
9920 assert(
false &&
"Wrong expression for return type number");
9929 assert(_type == ast_func_concat);
9942 if (count >
sizeof(static_buffer) /
sizeof(static_buffer[0])) {
9949 xpath_stack swapped_stack = {stack.temp, stack.result};
9951 buffer[0] = _left->eval_string(c, swapped_stack);
9955 buffer[pos] = n->eval_string(c, swapped_stack);
9956 assert(pos == count);
9960 for (
size_t i = 0; i < count; ++i) length += buffer[i].length();
9963 char_t* result =
static_cast<char_t*
>(
9964 stack.result->allocate((length + 1) *
sizeof(char_t)));
9967 char_t* ri = result;
9969 for (
size_t j = 0; j < count; ++j)
9970 for (
const char_t* bi = buffer[j].c_str(); *bi; ++bi) *ri++ = *bi;
9974 return xpath_string::from_heap_preallocated(result, ri);
9979 case ast_string_constant:
9980 return xpath_string::from_const(_data.string);
9982 case ast_func_local_name_0: {
9983 xpath_node na = c.n;
9985 return xpath_string::from_const(local_name(na));
9988 case ast_func_local_name_1: {
9992 _left->eval_node_set(c, stack, nodeset_eval_first);
9993 xpath_node na = ns.first();
9995 return xpath_string::from_const(local_name(na));
9998 case ast_func_name_0: {
9999 xpath_node na = c.n;
10001 return xpath_string::from_const(qualified_name(na));
10004 case ast_func_name_1: {
10008 _left->eval_node_set(c, stack, nodeset_eval_first);
10009 xpath_node na = ns.first();
10011 return xpath_string::from_const(qualified_name(na));
10014 case ast_func_namespace_uri_0: {
10015 xpath_node na = c.n;
10017 return xpath_string::from_const(namespace_uri(na));
10020 case ast_func_namespace_uri_1: {
10024 _left->eval_node_set(c, stack, nodeset_eval_first);
10025 xpath_node na = ns.first();
10027 return xpath_string::from_const(namespace_uri(na));
10030 case ast_func_string_0:
10031 return string_value(c.n, stack.result);
10033 case ast_func_string_1:
10034 return _left->eval_string(c, stack);
10036 case ast_func_concat:
10037 return eval_string_concat(c, stack);
10039 case ast_func_substring_before: {
10042 xpath_stack swapped_stack = {stack.temp, stack.result};
10044 xpath_string s = _left->eval_string(c, swapped_stack);
10045 xpath_string p = _right->eval_string(c, swapped_stack);
10047 const char_t* pos = find_substring(s.c_str(), p.c_str());
10049 return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result)
10053 case ast_func_substring_after: {
10056 xpath_stack swapped_stack = {stack.temp, stack.result};
10058 xpath_string s = _left->eval_string(c, swapped_stack);
10059 xpath_string p = _right->eval_string(c, swapped_stack);
10061 const char_t* pos = find_substring(s.c_str(), p.c_str());
10064 const char_t* rbegin = pos + p.length();
10065 const char_t* rend = s.c_str() + s.length();
10067 return s.uses_heap()
10068 ? xpath_string::from_heap(rbegin, rend, stack.result)
10069 : xpath_string::from_const(rbegin);
10072 case ast_func_substring_2: {
10075 xpath_stack swapped_stack = {stack.temp, stack.result};
10077 xpath_string s = _left->eval_string(c, swapped_stack);
10078 size_t s_length = s.length();
10080 double first = round_nearest(_right->eval_number(c, stack));
10084 else if (first >= s_length + 1)
10087 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
10088 assert(1 <= pos && pos <= s_length + 1);
10090 const char_t* rbegin = s.c_str() + (pos - 1);
10091 const char_t* rend = s.c_str() + s.length();
10093 return s.uses_heap()
10094 ? xpath_string::from_heap(rbegin, rend, stack.result)
10095 : xpath_string::from_const(rbegin);
10098 case ast_func_substring_3: {
10101 xpath_stack swapped_stack = {stack.temp, stack.result};
10103 xpath_string s = _left->eval_string(c, swapped_stack);
10104 size_t s_length = s.length();
10106 double first = round_nearest(_right->eval_number(c, stack));
10108 first + round_nearest(_right->_next->eval_number(c, stack));
10110 if (is_nan(first) || is_nan(last))
10112 else if (first >= s_length + 1)
10114 else if (first >= last)
10119 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
10121 last >= s_length + 1 ? s_length + 1 :
static_cast<size_t>(last);
10123 assert(1 <= pos && pos <= end && end <= s_length + 1);
10124 const char_t* rbegin = s.c_str() + (pos - 1);
10125 const char_t* rend = s.c_str() + (end - 1);
10127 return (end == s_length + 1 && !s.uses_heap())
10128 ? xpath_string::from_const(rbegin)
10129 : xpath_string::from_heap(rbegin, rend, stack.result);
10132 case ast_func_normalize_space_0: {
10135 char_t* begin = s.data(stack.result);
10136 char_t* end = normalize_space(begin);
10138 return xpath_string::from_heap_preallocated(begin, end);
10141 case ast_func_normalize_space_1: {
10144 char_t* begin = s.data(stack.result);
10145 char_t* end = normalize_space(begin);
10147 return xpath_string::from_heap_preallocated(begin, end);
10150 case ast_func_translate: {
10153 xpath_stack swapped_stack = {stack.temp, stack.result};
10156 xpath_string from = _right->eval_string(c, swapped_stack);
10157 xpath_string to = _right->_next->eval_string(c, swapped_stack);
10159 char_t* begin = s.data(stack.result);
10160 char_t* end = translate(begin, from.c_str(), to.c_str(), to.length());
10162 return xpath_string::from_heap_preallocated(begin, end);
10165 case ast_opt_translate_table: {
10168 char_t* begin = s.data(stack.result);
10169 char_t* end = translate_table(begin, _data.table);
10171 return xpath_string::from_heap_preallocated(begin, end);
10174 case ast_variable: {
10175 assert(_rettype == _data.variable->type());
10177 if (_rettype == xpath_type_string)
10178 return xpath_string::from_const(_data.variable->get_string());
10183 switch (_rettype) {
10184 case xpath_type_boolean:
10185 return xpath_string::from_const(eval_boolean(c, stack)
10186 ? PUGIXML_TEXT(
"true")
10187 : PUGIXML_TEXT(
"false"));
10189 case xpath_type_number:
10190 return convert_number_to_string(eval_number(c, stack),
10193 case xpath_type_node_set: {
10196 xpath_stack swapped_stack = {stack.temp, stack.result};
10199 eval_node_set(c, swapped_stack, nodeset_eval_first);
10201 : string_value(ns.first(), stack.result);
10205 assert(
false &&
"Wrong expression for return type string");
10214 nodeset_eval_t eval) {
10216 case ast_op_union: {
10219 xpath_stack swapped_stack = {stack.temp, stack.result};
10226 rs.set_type(xpath_node_set::type_unsorted);
10228 rs.append(ls.begin(), ls.end(), stack.result);
10229 rs.remove_duplicates();
10237 _test == predicate_constant_one ? nodeset_eval_first
10238 : nodeset_eval_all);
10242 if (_test != predicate_posinv) set.sort_do();
10244 bool once = eval_once(set.type(), eval);
10246 apply_predicate(set, 0, stack, once);
10256 case axis_ancestor:
10259 case axis_ancestor_or_self:
10260 return step_do(c, stack, eval,
10263 case axis_attribute:
10269 case axis_descendant:
10272 case axis_descendant_or_self:
10273 return step_do(c, stack, eval,
10276 case axis_following:
10279 case axis_following_sibling:
10280 return step_do(c, stack, eval,
10283 case axis_namespace:
10290 case axis_preceding:
10293 case axis_preceding_sibling:
10294 return step_do(c, stack, eval,
10301 assert(
false &&
"Unknown axis");
10306 case ast_step_root: {
10311 ns.set_type(xpath_node_set::type_sorted);
10314 ns.push_back(c.n.node().root(), stack.result);
10315 else if (c.n.attribute())
10316 ns.push_back(c.n.parent().root(), stack.result);
10321 case ast_variable: {
10322 assert(_rettype == _data.variable->type());
10324 if (_rettype == xpath_type_node_set) {
10325 const xpath_node_set& s = _data.variable->get_node_set();
10329 ns.set_type(s.type());
10330 ns.append(s.begin(), s.end(), stack.result);
10338 assert(
false &&
"Wrong expression for return type node set");
10344 if (_left) _left->optimize(alloc);
10346 if (_right) _right->optimize(alloc);
10348 if (_next) _next->optimize(alloc);
10350 optimize_self(alloc);
10357 if ((_type == ast_filter || _type == ast_predicate) &&
10358 _right->_type == ast_op_equal &&
10359 _right->_left->_type == ast_func_position &&
10360 _right->_right->_rettype == xpath_type_number) {
10361 _right = _right->_right;
10366 if (_type == ast_filter || _type == ast_predicate) {
10367 assert(_test == predicate_default);
10369 if (_right->_type == ast_number_constant && _right->_data.number == 1.0)
10370 _test = predicate_constant_one;
10371 else if (_right->_rettype == xpath_type_number &&
10372 (_right->_type == ast_number_constant ||
10373 _right->_type == ast_variable ||
10374 _right->_type == ast_func_last))
10375 _test = predicate_constant;
10376 else if (_right->_rettype != xpath_type_number &&
10377 _right->is_posinv_expr())
10378 _test = predicate_posinv;
10386 if (_type == ast_step &&
10387 (_axis == axis_child || _axis == axis_self ||
10388 _axis == axis_descendant || _axis == axis_descendant_or_self) &&
10389 _left && _left->_type == ast_step &&
10390 _left->_axis == axis_descendant_or_self &&
10391 _left->_test == nodetest_type_node && !_left->_right &&
10392 is_posinv_step()) {
10393 if (_axis == axis_child || _axis == axis_descendant)
10394 _axis = axis_descendant;
10396 _axis = axis_descendant_or_self;
10398 _left = _left->_left;
10403 if (_type == ast_func_translate && _right->_type == ast_string_constant &&
10404 _right->_next->_type == ast_string_constant) {
10405 unsigned char* table = translate_table_generate(
10406 alloc, _right->_data.string, _right->_next->_data.string);
10409 _type = ast_opt_translate_table;
10410 _data.table = table;
10415 if (_type == ast_op_equal && _left->_type == ast_step &&
10416 _left->_axis == axis_attribute && _left->_test == nodetest_name &&
10417 !_left->_left && !_left->_right &&
10418 (_right->_type == ast_string_constant ||
10419 (_right->_type == ast_variable &&
10420 _right->_rettype == xpath_type_string))) {
10421 _type = ast_opt_compare_attribute;
10425 bool is_posinv_expr()
const {
10427 case ast_func_position:
10428 case ast_func_last:
10431 case ast_string_constant:
10432 case ast_number_constant:
10437 case ast_step_root:
10440 case ast_predicate:
10445 if (_left && !_left->is_posinv_expr())
return false;
10448 if (!n->is_posinv_expr())
return false;
10454 bool is_posinv_step()
const {
10455 assert(_type == ast_step);
10458 assert(n->_type == ast_predicate);
10460 if (n->_test != predicate_posinv)
return false;
10466 xpath_value_type rettype()
const {
10467 return static_cast<xpath_value_type
>(_rettype);
10475 const char_t* _query;
10476 xpath_variable_set* _variables;
10478 xpath_parse_result* _result;
10480 char_t _scratch[32];
10482#ifdef PUGIXML_NO_EXCEPTIONS
10483 jmp_buf _error_handler;
10486 void throw_error(
const char* message) {
10487 _result->error = message;
10488 _result->offset = _lexer.current_pos() - _query;
10490#ifdef PUGIXML_NO_EXCEPTIONS
10491 longjmp(_error_handler, 1);
10493 throw xpath_exception(*_result);
10497 void throw_error_oom() {
10498#ifdef PUGIXML_NO_EXCEPTIONS
10499 throw_error(
"Out of memory");
10501 throw std::bad_alloc();
10505 void* alloc_node() {
10506 void* result = _alloc->allocate_nothrow(
sizeof(
xpath_ast_node));
10508 if (!result) throw_error_oom();
10515 size_t length =
static_cast<size_t>(value.end - value.begin);
10517 char_t* c =
static_cast<char_t*
>(
10518 _alloc->allocate_nothrow((length + 1) *
sizeof(char_t)));
10519 if (!c) throw_error_oom();
10522 memcpy(c, value.begin, length *
sizeof(char_t));
10530 xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1,
10534 if (argc == 1 && args[0]->rettype() != xpath_type_node_set)
10535 throw_error(
"Function has to be applied to node set");
10537 return new (alloc_node())
10538 xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
10543 switch (name.begin[0]) {
10545 if (name == PUGIXML_TEXT(
"boolean") && argc == 1)
10546 return new (alloc_node())
10552 if (name == PUGIXML_TEXT(
"count") && argc == 1) {
10553 if (args[0]->rettype() != xpath_type_node_set)
10554 throw_error(
"Function has to be applied to node set");
10556 return new (alloc_node())
10558 }
else if (name == PUGIXML_TEXT(
"contains") && argc == 2)
10560 ast_func_contains, xpath_type_boolean, args[0], args[1]);
10561 else if (name == PUGIXML_TEXT(
"concat") && argc >= 2)
10563 ast_func_concat, xpath_type_string, args[0], args[1]);
10564 else if (name == PUGIXML_TEXT(
"ceiling") && argc == 1)
10565 return new (alloc_node())
10571 if (name == PUGIXML_TEXT(
"false") && argc == 0)
10572 return new (alloc_node())
10574 else if (name == PUGIXML_TEXT(
"floor") && argc == 1)
10575 return new (alloc_node())
10581 if (name == PUGIXML_TEXT(
"id") && argc == 1)
10582 return new (alloc_node())
10588 if (name == PUGIXML_TEXT(
"last") && argc == 0)
10589 return new (alloc_node())
10591 else if (name == PUGIXML_TEXT(
"lang") && argc == 1)
10592 return new (alloc_node())
10594 else if (name == PUGIXML_TEXT(
"local-name") && argc <= 1)
10595 return parse_function_helper(ast_func_local_name_0,
10596 ast_func_local_name_1, argc, args);
10601 if (name == PUGIXML_TEXT(
"name") && argc <= 1)
10602 return parse_function_helper(ast_func_name_0, ast_func_name_1, argc,
10604 else if (name == PUGIXML_TEXT(
"namespace-uri") && argc <= 1)
10605 return parse_function_helper(ast_func_namespace_uri_0,
10606 ast_func_namespace_uri_1, argc, args);
10607 else if (name == PUGIXML_TEXT(
"normalize-space") && argc <= 1)
10608 return new (alloc_node())
10610 : ast_func_normalize_space_1,
10611 xpath_type_string, args[0], args[1]);
10612 else if (name == PUGIXML_TEXT(
"not") && argc == 1)
10613 return new (alloc_node())
10615 else if (name == PUGIXML_TEXT(
"number") && argc <= 1)
10616 return new (alloc_node())
10617 xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1,
10618 xpath_type_number, args[0]);
10623 if (name == PUGIXML_TEXT(
"position") && argc == 0)
10624 return new (alloc_node())
10630 if (name == PUGIXML_TEXT(
"round") && argc == 1)
10631 return new (alloc_node())
10637 if (name == PUGIXML_TEXT(
"string") && argc <= 1)
10638 return new (alloc_node())
10639 xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1,
10640 xpath_type_string, args[0]);
10641 else if (name == PUGIXML_TEXT(
"string-length") && argc <= 1)
10643 argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1,
10644 xpath_type_number, args[0]);
10645 else if (name == PUGIXML_TEXT(
"starts-with") && argc == 2)
10647 ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
10648 else if (name == PUGIXML_TEXT(
"substring-before") && argc == 2)
10650 ast_func_substring_before, xpath_type_string, args[0], args[1]);
10651 else if (name == PUGIXML_TEXT(
"substring-after") && argc == 2)
10653 ast_func_substring_after, xpath_type_string, args[0], args[1]);
10654 else if (name == PUGIXML_TEXT(
"substring") && (argc == 2 || argc == 3))
10656 argc == 2 ? ast_func_substring_2 : ast_func_substring_3,
10657 xpath_type_string, args[0], args[1]);
10658 else if (name == PUGIXML_TEXT(
"sum") && argc == 1) {
10659 if (args[0]->rettype() != xpath_type_node_set)
10660 throw_error(
"Function has to be applied to node set");
10661 return new (alloc_node())
10668 if (name == PUGIXML_TEXT(
"translate") && argc == 3)
10670 ast_func_translate, xpath_type_string, args[0], args[1]);
10671 else if (name == PUGIXML_TEXT(
"true") && argc == 0)
10672 return new (alloc_node())
10681 throw_error(
"Unrecognized function or wrong parameter count");
10689 switch (name.begin[0]) {
10691 if (name == PUGIXML_TEXT(
"ancestor"))
10692 return axis_ancestor;
10693 else if (name == PUGIXML_TEXT(
"ancestor-or-self"))
10694 return axis_ancestor_or_self;
10695 else if (name == PUGIXML_TEXT(
"attribute"))
10696 return axis_attribute;
10701 if (name == PUGIXML_TEXT(
"child"))
return axis_child;
10706 if (name == PUGIXML_TEXT(
"descendant"))
10707 return axis_descendant;
10708 else if (name == PUGIXML_TEXT(
"descendant-or-self"))
10709 return axis_descendant_or_self;
10714 if (name == PUGIXML_TEXT(
"following"))
10715 return axis_following;
10716 else if (name == PUGIXML_TEXT(
"following-sibling"))
10717 return axis_following_sibling;
10722 if (name == PUGIXML_TEXT(
"namespace"))
return axis_namespace;
10727 if (name == PUGIXML_TEXT(
"parent"))
10728 return axis_parent;
10729 else if (name == PUGIXML_TEXT(
"preceding"))
10730 return axis_preceding;
10731 else if (name == PUGIXML_TEXT(
"preceding-sibling"))
10732 return axis_preceding_sibling;
10737 if (name == PUGIXML_TEXT(
"self"))
return axis_self;
10750 switch (name.begin[0]) {
10752 if (name == PUGIXML_TEXT(
"comment"))
return nodetest_type_comment;
10757 if (name == PUGIXML_TEXT(
"node"))
return nodetest_type_node;
10762 if (name == PUGIXML_TEXT(
"processing-instruction"))
10763 return nodetest_type_pi;
10768 if (name == PUGIXML_TEXT(
"text"))
return nodetest_type_text;
10776 return nodetest_none;
10782 switch (_lexer.current()) {
10783 case lex_var_ref: {
10787 throw_error(
"Unknown variable: variable set is not provided");
10789 xpath_variable* var = 0;
10790 if (!get_variable_scratch(_scratch, _variables, name.begin, name.end,
10796 "Unknown variable: variable set does not contain the given name");
10800 return new (alloc_node())
10804 case lex_open_brace: {
10809 if (_lexer.current() != lex_close_brace)
10810 throw_error(
"Unmatched braces");
10817 case lex_quoted_string: {
10818 const char_t* value = alloc_string(_lexer.contents());
10830 if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin,
10831 _lexer.contents().end, &value))
10850 if (_lexer.current() != lex_open_brace)
10851 throw_error(
"Unrecognized function call");
10854 if (_lexer.current() != lex_close_brace)
10855 args[argc++] = parse_expression();
10857 while (_lexer.current() != lex_close_brace) {
10858 if (_lexer.current() != lex_comma)
10859 throw_error(
"No comma between function arguments");
10867 last_arg->set_next(n);
10875 return parse_function(function, argc, args);
10879 throw_error(
"Unrecognizable primary expression");
10891 while (_lexer.current() == lex_open_square_brace) {
10896 if (n->rettype() != xpath_type_node_set)
10897 throw_error(
"Predicate has to be applied to node set");
10899 n =
new (alloc_node())
10902 if (_lexer.current() != lex_close_square_brace)
10903 throw_error(
"Unmatched square brace");
10917 if (set && set->rettype() != xpath_type_node_set)
10918 throw_error(
"Step has to be applied to node set");
10920 bool axis_specified =
false;
10921 axis_t axis = axis_child;
10923 if (_lexer.current() == lex_axis_attribute) {
10924 axis = axis_attribute;
10925 axis_specified =
true;
10928 }
else if (_lexer.current() == lex_dot) {
10931 return new (alloc_node())
10932 xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0);
10933 }
else if (_lexer.current() == lex_double_dot) {
10936 return new (alloc_node())
10937 xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0);
10940 nodetest_t nt_type = nodetest_none;
10943 if (_lexer.current() == lex_string) {
10945 nt_name = _lexer.contents();
10949 if (_lexer.current() == lex_double_colon) {
10951 if (axis_specified) throw_error(
"Two axis specifiers in one step");
10953 axis = parse_axis_name(nt_name, axis_specified);
10955 if (!axis_specified) throw_error(
"Unknown axis");
10960 if (_lexer.current() == lex_multiply) {
10961 nt_type = nodetest_all;
10964 }
else if (_lexer.current() == lex_string) {
10965 nt_name = _lexer.contents();
10968 throw_error(
"Unrecognized node test");
10971 if (nt_type == nodetest_none) {
10973 if (_lexer.current() == lex_open_brace) {
10976 if (_lexer.current() == lex_close_brace) {
10979 nt_type = parse_node_test_type(nt_name);
10981 if (nt_type == nodetest_none) throw_error(
"Unrecognized node type");
10984 }
else if (nt_name == PUGIXML_TEXT(
"processing-instruction")) {
10985 if (_lexer.current() != lex_quoted_string)
10987 "Only literals are allowed as arguments to "
10988 "processing-instruction()");
10990 nt_type = nodetest_pi;
10991 nt_name = _lexer.contents();
10994 if (_lexer.current() != lex_close_brace)
10995 throw_error(
"Unmatched brace near processing-instruction()");
10998 throw_error(
"Unmatched brace near node type test");
11003 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] ==
':' &&
11004 nt_name.end[-1] ==
'*')
11008 nt_type = nodetest_all_in_namespace;
11010 nt_type = nodetest_name;
11014 }
else if (_lexer.current() == lex_multiply) {
11015 nt_type = nodetest_all;
11018 throw_error(
"Unrecognized node test");
11021 const char_t* nt_name_copy = alloc_string(nt_name);
11027 while (_lexer.current() == lex_open_square_brace) {
11035 if (_lexer.current() != lex_close_square_brace)
11036 throw_error(
"Unmatched square brace");
11040 last->set_next(pred);
11042 n->set_right(pred);
11055 while (_lexer.current() == lex_slash ||
11056 _lexer.current() == lex_double_slash) {
11057 lexeme_t l = _lexer.current();
11060 if (l == lex_double_slash)
11062 ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
11074 if (_lexer.current() == lex_slash) {
11078 new (alloc_node())
xpath_ast_node(ast_step_root, xpath_type_node_set);
11083 lexeme_t l = _lexer.current();
11085 if (l == lex_string || l == lex_axis_attribute || l == lex_dot ||
11086 l == lex_double_dot || l == lex_multiply)
11087 return parse_relative_location_path(n);
11090 }
else if (_lexer.current() == lex_double_slash) {
11094 new (alloc_node())
xpath_ast_node(ast_step_root, xpath_type_node_set);
11096 ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
11098 return parse_relative_location_path(n);
11103 return parse_relative_location_path(0);
11120 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
11121 _lexer.current() == lex_quoted_string ||
11122 _lexer.current() == lex_number || _lexer.current() == lex_string) {
11123 if (_lexer.current() == lex_string) {
11126 const char_t* state = _lexer.state();
11128 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
11130 if (*state !=
'(')
return parse_location_path();
11134 if (parse_node_test_type(_lexer.contents()) != nodetest_none)
11135 return parse_location_path();
11140 if (_lexer.current() == lex_slash ||
11141 _lexer.current() == lex_double_slash) {
11142 lexeme_t l = _lexer.current();
11145 if (l == lex_double_slash) {
11146 if (n->rettype() != xpath_type_node_set)
11147 throw_error(
"Step has to be applied to node set");
11150 ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
11154 return parse_relative_location_path(n);
11158 }
else if (_lexer.current() == lex_minus) {
11163 parse_expression_rec(parse_path_or_unary_expression(), 7);
11165 return new (alloc_node())
11168 return parse_location_path();
11173 ast_type_t asttype;
11174 xpath_value_type rettype;
11178 : asttype(ast_unknown), rettype(xpath_type_none), precedence(0) {}
11180 binary_op_t(ast_type_t asttype_, xpath_value_type rettype_,
int precedence_)
11181 : asttype(asttype_), rettype(rettype_), precedence(precedence_) {}
11184 switch (lexer.current()) {
11186 if (lexer.contents() == PUGIXML_TEXT(
"or"))
11187 return binary_op_t(ast_op_or, xpath_type_boolean, 1);
11188 else if (lexer.contents() == PUGIXML_TEXT(
"and"))
11189 return binary_op_t(ast_op_and, xpath_type_boolean, 2);
11190 else if (lexer.contents() == PUGIXML_TEXT(
"div"))
11191 return binary_op_t(ast_op_divide, xpath_type_number, 6);
11192 else if (lexer.contents() == PUGIXML_TEXT(
"mod"))
11193 return binary_op_t(ast_op_mod, xpath_type_number, 6);
11198 return binary_op_t(ast_op_equal, xpath_type_boolean, 3);
11200 case lex_not_equal:
11201 return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3);
11204 return binary_op_t(ast_op_less, xpath_type_boolean, 4);
11207 return binary_op_t(ast_op_greater, xpath_type_boolean, 4);
11209 case lex_less_or_equal:
11210 return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4);
11212 case lex_greater_or_equal:
11213 return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4);
11216 return binary_op_t(ast_op_add, xpath_type_number, 5);
11219 return binary_op_t(ast_op_subtract, xpath_type_number, 5);
11222 return binary_op_t(ast_op_multiply, xpath_type_number, 6);
11225 return binary_op_t(ast_op_union, xpath_type_node_set, 7);
11236 while (op.asttype != ast_unknown && op.precedence >= limit) {
11243 while (nextop.asttype != ast_unknown &&
11244 nextop.precedence > op.precedence) {
11245 rhs = parse_expression_rec(rhs, nextop.precedence);
11247 nextop = binary_op_t::parse(_lexer);
11250 if (op.asttype == ast_op_union &&
11251 (lhs->rettype() != xpath_type_node_set ||
11252 rhs->rettype() != xpath_type_node_set))
11253 throw_error(
"Union operator has to be applied to node sets");
11255 lhs =
new (alloc_node())
xpath_ast_node(op.asttype, op.rettype, lhs, rhs);
11257 op = binary_op_t::parse(_lexer);
11282 return parse_expression_rec(parse_path_or_unary_expression(), 0);
11285 xpath_parser(
const char_t* query, xpath_variable_set* variables,
11290 _variables(variables),
11297 if (_lexer.current() != lex_eof) throw_error(
"Incorrect query");
11303 xpath_variable_set* variables,
11305 xpath_parse_result* result) {
11308#ifdef PUGIXML_NO_EXCEPTIONS
11309 int error = setjmp(parser._error_handler);
11311 return (error == 0) ? parser.parse() : 0;
11313 return parser.parse();
11321 if (!memory)
return 0;
11328 impl->alloc.release();
11331 xml_memory::deallocate(impl);
11345 const xpath_node& n,
11349#ifdef PUGIXML_NO_EXCEPTIONS
11355 return impl->root->eval_string(c, sd.stack);
11358PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(
11360 if (!impl)
return 0;
11362 if (impl->root->rettype() != xpath_type_node_set) {
11363#ifdef PUGIXML_NO_EXCEPTIONS
11366 xpath_parse_result res;
11367 res.error =
"Expression does not evaluate to node set";
11369 throw xpath_exception(res);
11378#ifndef PUGIXML_NO_EXCEPTIONS
11379PUGI__FN xpath_exception::xpath_exception(
const xpath_parse_result& result_)
11380 : _result(result_) {
11381 assert(_result.error);
11384PUGI__FN
const char* xpath_exception::what()
const throw() {
11385 return _result.error;
11388PUGI__FN
const xpath_parse_result& xpath_exception::result()
const {
11393PUGI__FN xpath_node::xpath_node() {}
11395PUGI__FN xpath_node::xpath_node(
const xml_node& node_) : _node(node_) {}
11397PUGI__FN xpath_node::xpath_node(
const xml_attribute& attribute_,
11398 const xml_node& parent_)
11399 : _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) {}
11401PUGI__FN xml_node xpath_node::node()
const {
11402 return _attribute ? xml_node() : _node;
11405PUGI__FN xml_attribute xpath_node::attribute()
const {
return _attribute; }
11407PUGI__FN xml_node xpath_node::parent()
const {
11408 return _attribute ? _node : _node.parent();
11411PUGI__FN
static void unspecified_bool_xpath_node(xpath_node***) {}
11413PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type()
const {
11414 return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
11417PUGI__FN
bool xpath_node::operator!()
const {
return !(_node || _attribute); }
11419PUGI__FN
bool xpath_node::operator==(
const xpath_node& n)
const {
11420 return _node == n._node && _attribute == n._attribute;
11423PUGI__FN
bool xpath_node::operator!=(
const xpath_node& n)
const {
11424 return _node != n._node || _attribute != n._attribute;
11428PUGI__FN
bool operator&&(
const xpath_node& lhs,
bool rhs) {
11429 return (
bool)lhs && rhs;
11432PUGI__FN
bool operator||(
const xpath_node& lhs,
bool rhs) {
11433 return (
bool)lhs || rhs;
11437PUGI__FN
void xpath_node_set::_assign(const_iterator begin_,
11438 const_iterator end_, type_t type_) {
11439 assert(begin_ <= end_);
11441 size_t size_ =
static_cast<size_t>(end_ - begin_);
11445 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
11448 if (begin_ != end_) _storage = *begin_;
11450 _begin = &_storage;
11451 _end = &_storage + size_;
11455 xpath_node* storage =
static_cast<xpath_node*
>(
11456 impl::xml_memory::allocate(size_ *
sizeof(xpath_node)));
11459#ifdef PUGIXML_NO_EXCEPTIONS
11462 throw std::bad_alloc();
11466 memcpy(storage, begin_, size_ *
sizeof(xpath_node));
11469 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
11473 _end = storage + size_;
11478#ifdef PUGIXML_HAS_MOVE
11479PUGI__FN
void xpath_node_set::_move(xpath_node_set& rhs) {
11481 _storage = rhs._storage;
11482 _begin = (rhs._begin == &rhs._storage) ? &_storage : rhs._begin;
11483 _end = _begin + (rhs._end - rhs._begin);
11485 rhs._type = type_unsorted;
11486 rhs._begin = &rhs._storage;
11487 rhs._end = rhs._begin;
11491PUGI__FN xpath_node_set::xpath_node_set()
11492 : _type(type_unsorted), _begin(&_storage), _end(&_storage) {}
11494PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_,
11495 const_iterator end_, type_t type_)
11496 : _type(type_unsorted), _begin(&_storage), _end(&_storage) {
11497 _assign(begin_, end_, type_);
11500PUGI__FN xpath_node_set::~xpath_node_set() {
11501 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
11504PUGI__FN xpath_node_set::xpath_node_set(
const xpath_node_set& ns)
11505 : _type(type_unsorted), _begin(&_storage), _end(&_storage) {
11506 _assign(ns._begin, ns._end, ns._type);
11509PUGI__FN xpath_node_set& xpath_node_set::operator=(
const xpath_node_set& ns) {
11510 if (
this == &ns)
return *
this;
11512 _assign(ns._begin, ns._end, ns._type);
11517#ifdef PUGIXML_HAS_MOVE
11518PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs)
11519 : _type(type_unsorted), _begin(&_storage), _end(&_storage) {
11523PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) {
11524 if (
this == &rhs)
return *
this;
11526 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
11534PUGI__FN xpath_node_set::type_t xpath_node_set::type()
const {
return _type; }
11536PUGI__FN
size_t xpath_node_set::size()
const {
return _end - _begin; }
11538PUGI__FN
bool xpath_node_set::empty()
const {
return _begin == _end; }
11540PUGI__FN
const xpath_node& xpath_node_set::operator[](
size_t index)
const {
11541 assert(index < size());
11542 return _begin[index];
11545PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin()
const {
11549PUGI__FN xpath_node_set::const_iterator xpath_node_set::end()
const {
11553PUGI__FN
void xpath_node_set::sort(
bool reverse) {
11554 _type = impl::xpath_sort(_begin, _end, _type, reverse);
11557PUGI__FN xpath_node xpath_node_set::first()
const {
11558 return impl::xpath_first(_begin, _end, _type);
11561PUGI__FN xpath_parse_result::xpath_parse_result()
11562 : error(
"Internal error"), offset(0) {}
11564PUGI__FN xpath_parse_result::operator bool()
const {
return error == 0; }
11566PUGI__FN
const char* xpath_parse_result::description()
const {
11567 return error ? error :
"No error";
11570PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_)
11571 : _type(type_), _next(0) {}
11573PUGI__FN
const char_t* xpath_variable::name()
const {
11575 case xpath_type_node_set:
11576 return static_cast<const impl::xpath_variable_node_set*
>(
this)->name;
11578 case xpath_type_number:
11579 return static_cast<const impl::xpath_variable_number*
>(
this)->name;
11581 case xpath_type_string:
11582 return static_cast<const impl::xpath_variable_string*
>(
this)->name;
11584 case xpath_type_boolean:
11585 return static_cast<const impl::xpath_variable_boolean*
>(
this)->name;
11588 assert(
false &&
"Invalid variable type");
11593PUGI__FN xpath_value_type xpath_variable::type()
const {
return _type; }
11595PUGI__FN
bool xpath_variable::get_boolean()
const {
11596 return (_type == xpath_type_boolean)
11597 ?
static_cast<const impl::xpath_variable_boolean*
>(
this)->value
11601PUGI__FN
double xpath_variable::get_number()
const {
11602 return (_type == xpath_type_number)
11603 ?
static_cast<const impl::xpath_variable_number*
>(
this)->value
11607PUGI__FN
const char_t* xpath_variable::get_string()
const {
11608 const char_t* value =
11609 (_type == xpath_type_string)
11610 ?
static_cast<const impl::xpath_variable_string*
>(
this)->value
11612 return value ? value : PUGIXML_TEXT(
"");
11615PUGI__FN
const xpath_node_set& xpath_variable::get_node_set()
const {
11616 return (_type == xpath_type_node_set)
11617 ?
static_cast<const impl::xpath_variable_node_set*
>(
this)->value
11618 : impl::dummy_node_set;
11621PUGI__FN
bool xpath_variable::set(
bool value) {
11622 if (_type != xpath_type_boolean)
return false;
11624 static_cast<impl::xpath_variable_boolean*
>(
this)->value = value;
11628PUGI__FN
bool xpath_variable::set(
double value) {
11629 if (_type != xpath_type_number)
return false;
11631 static_cast<impl::xpath_variable_number*
>(
this)->value = value;
11635PUGI__FN
bool xpath_variable::set(
const char_t* value) {
11636 if (_type != xpath_type_string)
return false;
11638 impl::xpath_variable_string* var =
11639 static_cast<impl::xpath_variable_string*
>(
this);
11642 size_t size = (impl::strlength(value) + 1) *
sizeof(char_t);
11644 char_t* copy =
static_cast<char_t*
>(impl::xml_memory::allocate(size));
11645 if (!copy)
return false;
11647 memcpy(copy, value, size);
11650 if (var->value) impl::xml_memory::deallocate(var->value);
11656PUGI__FN
bool xpath_variable::set(
const xpath_node_set& value) {
11657 if (_type != xpath_type_node_set)
return false;
11659 static_cast<impl::xpath_variable_node_set*
>(
this)->value = value;
11663PUGI__FN xpath_variable_set::xpath_variable_set() {
11664 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i) _data[i] = 0;
11667PUGI__FN xpath_variable_set::~xpath_variable_set() {
11668 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
11669 _destroy(_data[i]);
11672PUGI__FN xpath_variable_set::xpath_variable_set(
const xpath_variable_set& rhs) {
11673 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i) _data[i] = 0;
11678PUGI__FN xpath_variable_set& xpath_variable_set::operator=(
11679 const xpath_variable_set& rhs) {
11680 if (
this == &rhs)
return *
this;
11687#ifdef PUGIXML_HAS_MOVE
11688PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) {
11689 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i) {
11690 _data[i] = rhs._data[i];
11695PUGI__FN xpath_variable_set& xpath_variable_set::operator=(
11696 xpath_variable_set&& rhs) {
11697 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i) {
11698 _destroy(_data[i]);
11700 _data[i] = rhs._data[i];
11708PUGI__FN
void xpath_variable_set::_assign(
const xpath_variable_set& rhs) {
11709 xpath_variable_set temp;
11711 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i)
11712 if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))
return;
11717PUGI__FN
void xpath_variable_set::_swap(xpath_variable_set& rhs) {
11718 for (
size_t i = 0; i <
sizeof(_data) /
sizeof(_data[0]); ++i) {
11719 xpath_variable* chain = _data[i];
11721 _data[i] = rhs._data[i];
11722 rhs._data[i] = chain;
11726PUGI__FN xpath_variable* xpath_variable_set::_find(
const char_t* name)
const {
11727 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
11728 size_t hash = impl::hash_string(name) % hash_size;
11731 for (xpath_variable* var = _data[hash]; var; var = var->_next)
11732 if (impl::strequal(var->name(), name))
return var;
11737PUGI__FN
bool xpath_variable_set::_clone(xpath_variable* var,
11738 xpath_variable** out_result) {
11739 xpath_variable* last = 0;
11743 xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
11744 if (!nvar)
return false;
11748 last->_next = nvar;
11750 *out_result = nvar;
11755 if (!impl::copy_xpath_variable(nvar, var))
return false;
11763PUGI__FN
void xpath_variable_set::_destroy(xpath_variable* var) {
11765 xpath_variable* next = var->_next;
11767 impl::delete_xpath_variable(var->_type, var);
11773PUGI__FN xpath_variable* xpath_variable_set::add(
const char_t* name,
11774 xpath_value_type type) {
11775 const size_t hash_size =
sizeof(_data) /
sizeof(_data[0]);
11776 size_t hash = impl::hash_string(name) % hash_size;
11779 for (xpath_variable* var = _data[hash]; var; var = var->_next)
11780 if (impl::strequal(var->name(), name))
return var->type() == type ? var : 0;
11783 xpath_variable* result = impl::new_xpath_variable(type, name);
11786 result->_next = _data[hash];
11788 _data[hash] = result;
11794PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
bool value) {
11795 xpath_variable* var = add(name, xpath_type_boolean);
11796 return var ? var->set(value) :
false;
11799PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
double value) {
11800 xpath_variable* var = add(name, xpath_type_number);
11801 return var ? var->set(value) :
false;
11804PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
const char_t* value) {
11805 xpath_variable* var = add(name, xpath_type_string);
11806 return var ? var->set(value) :
false;
11809PUGI__FN
bool xpath_variable_set::set(
const char_t* name,
11810 const xpath_node_set& value) {
11811 xpath_variable* var = add(name, xpath_type_node_set);
11812 return var ? var->set(value) :
false;
11815PUGI__FN xpath_variable* xpath_variable_set::get(
const char_t* name) {
11816 return _find(name);
11819PUGI__FN
const xpath_variable* xpath_variable_set::get(
11820 const char_t* name)
const {
11821 return _find(name);
11824PUGI__FN xpath_query::xpath_query(
const char_t* query,
11825 xpath_variable_set* variables)
11827 impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
11830#ifdef PUGIXML_NO_EXCEPTIONS
11831 _result.error =
"Out of memory";
11833 throw std::bad_alloc();
11836 using impl::auto_deleter;
11838 impl::xpath_query_impl::destroy);
11841 impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
11844 qimpl->root->optimize(&qimpl->alloc);
11846 _impl = impl.release();
11852PUGI__FN xpath_query::xpath_query() : _impl(0) {}
11854PUGI__FN xpath_query::~xpath_query() {
11856 impl::xpath_query_impl::destroy(
11857 static_cast<impl::xpath_query_impl*
>(_impl));
11860#ifdef PUGIXML_HAS_MOVE
11861PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) {
11863 _result = rhs._result;
11865 rhs._result = xpath_parse_result();
11868PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) {
11869 if (
this == &rhs)
return *
this;
11872 impl::xpath_query_impl::destroy(
11873 static_cast<impl::xpath_query_impl*
>(_impl));
11876 _result = rhs._result;
11878 rhs._result = xpath_parse_result();
11884PUGI__FN xpath_value_type xpath_query::return_type()
const {
11885 if (!_impl)
return xpath_type_none;
11887 return static_cast<impl::xpath_query_impl*
>(_impl)->root->rettype();
11890PUGI__FN
bool xpath_query::evaluate_boolean(
const xpath_node& n)
const {
11891 if (!_impl)
return false;
11893 impl::xpath_context c(n, 1, 1);
11894 impl::xpath_stack_data sd;
11896#ifdef PUGIXML_NO_EXCEPTIONS
11897 if (setjmp(sd.error_handler))
return false;
11900 return static_cast<impl::xpath_query_impl*
>(_impl)->root->eval_boolean(
11904PUGI__FN
double xpath_query::evaluate_number(
const xpath_node& n)
const {
11905 if (!_impl)
return impl::gen_nan();
11907 impl::xpath_context c(n, 1, 1);
11908 impl::xpath_stack_data sd;
11910#ifdef PUGIXML_NO_EXCEPTIONS
11911 if (setjmp(sd.error_handler))
return impl::gen_nan();
11914 return static_cast<impl::xpath_query_impl*
>(_impl)->root->eval_number(
11918#ifndef PUGIXML_NO_STL
11919PUGI__FN string_t xpath_query::evaluate_string(
const xpath_node& n)
const {
11920 impl::xpath_stack_data sd;
11922 impl::xpath_string r = impl::evaluate_string_impl(
11923 static_cast<impl::xpath_query_impl*
>(_impl), n, sd);
11925 return string_t(r.c_str(), r.length());
11929PUGI__FN
size_t xpath_query::evaluate_string(char_t* buffer,
size_t capacity,
11930 const xpath_node& n)
const {
11931 impl::xpath_stack_data sd;
11933 impl::xpath_string r = impl::evaluate_string_impl(
11934 static_cast<impl::xpath_query_impl*
>(_impl), n, sd);
11936 size_t full_size = r.length() + 1;
11938 if (capacity > 0) {
11939 size_t size = (full_size < capacity) ? full_size : capacity;
11942 memcpy(buffer, r.c_str(), (size - 1) *
sizeof(char_t));
11943 buffer[size - 1] = 0;
11949PUGI__FN xpath_node_set
11950xpath_query::evaluate_node_set(
const xpath_node& n)
const {
11951 impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(
11952 static_cast<impl::xpath_query_impl*
>(_impl));
11953 if (!root)
return xpath_node_set();
11955 impl::xpath_context c(n, 1, 1);
11956 impl::xpath_stack_data sd;
11958#ifdef PUGIXML_NO_EXCEPTIONS
11959 if (setjmp(sd.error_handler))
return xpath_node_set();
11962 impl::xpath_node_set_raw r =
11963 root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
11965 return xpath_node_set(r.begin(), r.end(), r.type());
11968PUGI__FN xpath_node xpath_query::evaluate_node(
const xpath_node& n)
const {
11969 impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(
11970 static_cast<impl::xpath_query_impl*
>(_impl));
11971 if (!root)
return xpath_node();
11973 impl::xpath_context c(n, 1, 1);
11974 impl::xpath_stack_data sd;
11976#ifdef PUGIXML_NO_EXCEPTIONS
11977 if (setjmp(sd.error_handler))
return xpath_node();
11980 impl::xpath_node_set_raw r =
11981 root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);
11986PUGI__FN
const xpath_parse_result& xpath_query::result()
const {
11990PUGI__FN
static void unspecified_bool_xpath_query(xpath_query***) {}
11992PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type()
const {
11993 return _impl ? unspecified_bool_xpath_query : 0;
11996PUGI__FN
bool xpath_query::operator!()
const {
return !_impl; }
11998PUGI__FN xpath_node xml_node::select_node(
const char_t* query,
11999 xpath_variable_set* variables)
const {
12000 xpath_query q(query, variables);
12001 return select_node(q);
12004PUGI__FN xpath_node xml_node::select_node(
const xpath_query& query)
const {
12005 return query.evaluate_node(*
this);
12008PUGI__FN xpath_node_set xml_node::select_nodes(
12009 const char_t* query, xpath_variable_set* variables)
const {
12010 xpath_query q(query, variables);
12011 return select_nodes(q);
12014PUGI__FN xpath_node_set xml_node::select_nodes(
const xpath_query& query)
const {
12015 return query.evaluate_node_set(*
this);
12018PUGI__FN xpath_node xml_node::select_single_node(
12019 const char_t* query, xpath_variable_set* variables)
const {
12020 xpath_query q(query, variables);
12021 return select_single_node(q);
12025xml_node::select_single_node(
const xpath_query& query)
const {
12026 return query.evaluate_node(*
this);
12039#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
12040#pragma warning(pop)
12045#undef PUGI__NO_INLINE
12046#undef PUGI__UNLIKELY
12047#undef PUGI__STATIC_ASSERT
12048#undef PUGI__DMC_VOLATILE
12049#undef PUGI__MSVC_CRT_VERSION
12050#undef PUGI__NS_BEGIN
12053#undef PUGI__FN_NO_INLINE
12054#undef PUGI__GETHEADER_IMPL
12055#undef PUGI__GETPAGE_IMPL
12056#undef PUGI__GETPAGE
12057#undef PUGI__NODETYPE
12058#undef PUGI__IS_CHARTYPE_IMPL
12059#undef PUGI__IS_CHARTYPE
12060#undef PUGI__IS_CHARTYPEX
12061#undef PUGI__ENDSWITH
12064#undef PUGI__PUSHNODE
12065#undef PUGI__POPNODE
12066#undef PUGI__SCANFOR
12067#undef PUGI__SCANWHILE
12068#undef PUGI__SCANWHILE_UNROLL
12070#undef PUGI__THROW_ERROR
12071#undef PUGI__CHECK_ERROR
Runtime representation of a plugin block.