Mercurial > embed
comparison pugixml/src/pugixml.cpp @ 47:8a8de065f049
pugixml: upgrade to 1.8, closes #614
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 20 Jan 2017 10:44:37 +0100 |
parents | 22ae219278af |
children | 1a32b6d17c8e |
comparison
equal
deleted
inserted
replaced
46:fa2587b194ee | 47:8a8de065f049 |
---|---|
1 /** | 1 /** |
2 * pugixml parser - version 1.7 | 2 * pugixml parser - version 1.8 |
3 * -------------------------------------------------------- | 3 * -------------------------------------------------------- |
4 * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) | 4 * Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) |
5 * Report bugs and download new versions at http://pugixml.org/ | 5 * Report bugs and download new versions at http://pugixml.org/ |
6 * | 6 * |
7 * This library is distributed under the MIT License. See notice at the end | 7 * This library is distributed under the MIT License. See notice at the end |
8 * of this file. | 8 * of this file. |
9 * | 9 * |
52 # pragma warning(disable: 4996) // this function or variable may be unsafe | 52 # pragma warning(disable: 4996) // this function or variable may be unsafe |
53 # pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged | 53 # pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged |
54 #endif | 54 #endif |
55 | 55 |
56 #ifdef __INTEL_COMPILER | 56 #ifdef __INTEL_COMPILER |
57 # pragma warning(disable: 177) // function was declared but never referenced | 57 # pragma warning(disable: 177) // function was declared but never referenced |
58 # pragma warning(disable: 279) // controlling expression is constant | 58 # pragma warning(disable: 279) // controlling expression is constant |
59 # pragma warning(disable: 1478 1786) // function was declared "deprecated" | 59 # pragma warning(disable: 1478 1786) // function was declared "deprecated" |
60 # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type | 60 # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type |
61 #endif | 61 #endif |
62 | 62 |
80 #if defined(_MSC_VER) && _MSC_VER >= 1300 | 80 #if defined(_MSC_VER) && _MSC_VER >= 1300 |
81 # define PUGI__NO_INLINE __declspec(noinline) | 81 # define PUGI__NO_INLINE __declspec(noinline) |
82 #elif defined(__GNUC__) | 82 #elif defined(__GNUC__) |
83 # define PUGI__NO_INLINE __attribute__((noinline)) | 83 # define PUGI__NO_INLINE __attribute__((noinline)) |
84 #else | 84 #else |
85 # define PUGI__NO_INLINE | 85 # define PUGI__NO_INLINE |
86 #endif | 86 #endif |
87 | 87 |
88 // Branch weight controls | 88 // Branch weight controls |
89 #if defined(__GNUC__) | 89 #if defined(__GNUC__) |
90 # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0) | 90 # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0) |
105 // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) | 105 // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all) |
106 #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) | 106 #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST) |
107 using std::memcpy; | 107 using std::memcpy; |
108 using std::memmove; | 108 using std::memmove; |
109 using std::memset; | 109 using std::memset; |
110 #endif | |
111 | |
112 // Some MinGW versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions in strict ANSI mode | |
113 #if defined(PUGIXML_HAS_LONG_LONG) && defined(__MINGW32__) && defined(__STRICT_ANSI__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX) | |
114 # define LLONG_MAX 9223372036854775807LL | |
115 # define LLONG_MIN (-LLONG_MAX-1) | |
116 # define ULLONG_MAX (2ULL*LLONG_MAX+1) | |
110 #endif | 117 #endif |
111 | 118 |
112 // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features | 119 // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features |
113 #if defined(_MSC_VER) && !defined(__S3E__) | 120 #if defined(_MSC_VER) && !defined(__S3E__) |
114 # define PUGI__MSVC_CRT_VERSION _MSC_VER | 121 # define PUGI__MSVC_CRT_VERSION _MSC_VER |
130 # define PUGI__FN | 137 # define PUGI__FN |
131 # define PUGI__FN_NO_INLINE PUGI__NO_INLINE | 138 # define PUGI__FN_NO_INLINE PUGI__NO_INLINE |
132 #endif | 139 #endif |
133 | 140 |
134 // uintptr_t | 141 // uintptr_t |
135 #if !defined(_MSC_VER) || _MSC_VER >= 1600 | 142 #if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561) |
136 # include <stdint.h> | |
137 #else | |
138 namespace pugi | 143 namespace pugi |
139 { | 144 { |
140 # ifndef _UINTPTR_T_DEFINED | 145 # ifndef _UINTPTR_T_DEFINED |
141 typedef size_t uintptr_t; | 146 typedef size_t uintptr_t; |
142 # endif | 147 # endif |
143 | 148 |
144 typedef unsigned __int8 uint8_t; | 149 typedef unsigned __int8 uint8_t; |
145 typedef unsigned __int16 uint16_t; | 150 typedef unsigned __int16 uint16_t; |
146 typedef unsigned __int32 uint32_t; | 151 typedef unsigned __int32 uint32_t; |
147 } | 152 } |
153 #else | |
154 # include <stdint.h> | |
148 #endif | 155 #endif |
149 | 156 |
150 // Memory allocation | 157 // Memory allocation |
151 PUGI__NS_BEGIN | 158 PUGI__NS_BEGIN |
152 PUGI__FN void* default_allocate(size_t size) | 159 PUGI__FN void* default_allocate(size_t size) |
204 PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) | 211 PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count) |
205 { | 212 { |
206 for (size_t i = 0; i < count; ++i) | 213 for (size_t i = 0; i < count; ++i) |
207 if (lhs[i] != rhs[i]) | 214 if (lhs[i] != rhs[i]) |
208 return false; | 215 return false; |
209 | 216 |
210 return lhs[count] == 0; | 217 return lhs[count] == 0; |
211 } | 218 } |
212 | 219 |
213 // Get length of wide string, even if CRT lacks wide character support | 220 // Get length of wide string, even if CRT lacks wide character support |
214 PUGI__FN size_t strlength_wide(const wchar_t* s) | 221 PUGI__FN size_t strlength_wide(const wchar_t* s) |
225 } | 232 } |
226 PUGI__NS_END | 233 PUGI__NS_END |
227 | 234 |
228 // auto_ptr-like object for exception recovery | 235 // auto_ptr-like object for exception recovery |
229 PUGI__NS_BEGIN | 236 PUGI__NS_BEGIN |
230 template <typename T, typename D = void(*)(T*)> struct auto_deleter | 237 template <typename T> struct auto_deleter |
231 { | 238 { |
239 typedef void (*D)(T*); | |
240 | |
232 T* data; | 241 T* data; |
233 D deleter; | 242 D deleter; |
234 | 243 |
235 auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_) | 244 auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_) |
236 { | 245 { |
291 | 300 |
292 // hash collision, quadratic probing | 301 // hash collision, quadratic probing |
293 bucket = (bucket + probe + 1) & hashmod; | 302 bucket = (bucket + probe + 1) & hashmod; |
294 } | 303 } |
295 | 304 |
296 assert(!"Hash table is full"); | 305 assert(false && "Hash table is full"); |
297 return 0; | 306 return 0; |
298 } | 307 } |
299 | 308 |
300 void** insert(const void* key) | 309 void** insert(const void* key) |
301 { | 310 { |
321 | 330 |
322 // hash collision, quadratic probing | 331 // hash collision, quadratic probing |
323 bucket = (bucket + probe + 1) & hashmod; | 332 bucket = (bucket + probe + 1) & hashmod; |
324 } | 333 } |
325 | 334 |
326 assert(!"Hash table is full"); | 335 assert(false && "Hash table is full"); |
327 return 0; | 336 return 0; |
328 } | 337 } |
329 | 338 |
330 bool reserve() | 339 bool reserve() |
331 { | 340 { |
392 | 401 |
393 PUGI__NS_END | 402 PUGI__NS_END |
394 #endif | 403 #endif |
395 | 404 |
396 PUGI__NS_BEGIN | 405 PUGI__NS_BEGIN |
397 static const size_t xml_memory_page_size = | |
398 #ifdef PUGIXML_MEMORY_PAGE_SIZE | |
399 PUGIXML_MEMORY_PAGE_SIZE | |
400 #else | |
401 32768 | |
402 #endif | |
403 ; | |
404 | |
405 #ifdef PUGIXML_COMPACT | 406 #ifdef PUGIXML_COMPACT |
406 static const uintptr_t xml_memory_block_alignment = 4; | 407 static const uintptr_t xml_memory_block_alignment = 4; |
407 | |
408 static const uintptr_t xml_memory_page_alignment = sizeof(void*); | |
409 #else | 408 #else |
410 static const uintptr_t xml_memory_block_alignment = sizeof(void*); | 409 static const uintptr_t xml_memory_block_alignment = sizeof(void*); |
411 | |
412 static const uintptr_t xml_memory_page_alignment = 64; | |
413 static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1); | |
414 #endif | 410 #endif |
415 | 411 |
416 // extra metadata bits | 412 // extra metadata bits |
417 static const uintptr_t xml_memory_page_contents_shared_mask = 32; | 413 static const uintptr_t xml_memory_page_contents_shared_mask = 64; |
418 static const uintptr_t xml_memory_page_name_allocated_mask = 16; | 414 static const uintptr_t xml_memory_page_name_allocated_mask = 32; |
419 static const uintptr_t xml_memory_page_value_allocated_mask = 8; | 415 static const uintptr_t xml_memory_page_value_allocated_mask = 16; |
420 static const uintptr_t xml_memory_page_type_mask = 7; | 416 static const uintptr_t xml_memory_page_type_mask = 15; |
421 | 417 |
422 // combined masks for string uniqueness | 418 // combined masks for string uniqueness |
423 static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; | 419 static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask; |
424 static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; | 420 static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask; |
425 | 421 |
426 #ifdef PUGIXML_COMPACT | 422 #ifdef PUGIXML_COMPACT |
423 #define PUGI__GETHEADER_IMPL(object, page, flags) // unused | |
427 #define PUGI__GETPAGE_IMPL(header) (header).get_page() | 424 #define PUGI__GETPAGE_IMPL(header) (header).get_page() |
428 #else | 425 #else |
429 #define PUGI__GETPAGE_IMPL(header) reinterpret_cast<impl::xml_memory_page*>((header) & impl::xml_memory_page_pointer_mask) | 426 #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags)) |
427 // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings | |
428 #define PUGI__GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8)))) | |
430 #endif | 429 #endif |
431 | 430 |
432 #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header) | 431 #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header) |
433 #define PUGI__NODETYPE(n) static_cast<xml_node_type>(((n)->header & impl::xml_memory_page_type_mask) + 1) | 432 #define PUGI__NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask) |
434 | 433 |
435 struct xml_allocator; | 434 struct xml_allocator; |
436 | 435 |
437 struct xml_memory_page | 436 struct xml_memory_page |
438 { | 437 { |
468 void* compact_shared_parent; | 467 void* compact_shared_parent; |
469 uint32_t* compact_page_marker; | 468 uint32_t* compact_page_marker; |
470 #endif | 469 #endif |
471 }; | 470 }; |
472 | 471 |
472 static const size_t xml_memory_page_size = | |
473 #ifdef PUGIXML_MEMORY_PAGE_SIZE | |
474 (PUGIXML_MEMORY_PAGE_SIZE) | |
475 #else | |
476 32768 | |
477 #endif | |
478 - sizeof(xml_memory_page); | |
479 | |
473 struct xml_memory_string_header | 480 struct xml_memory_string_header |
474 { | 481 { |
475 uint16_t page_offset; // offset from page->data | 482 uint16_t page_offset; // offset from page->data |
476 uint16_t full_size; // 0 if string occupies whole page | 483 uint16_t full_size; // 0 if string occupies whole page |
477 }; | 484 }; |
488 xml_memory_page* allocate_page(size_t data_size) | 495 xml_memory_page* allocate_page(size_t data_size) |
489 { | 496 { |
490 size_t size = sizeof(xml_memory_page) + data_size; | 497 size_t size = sizeof(xml_memory_page) + data_size; |
491 | 498 |
492 // allocate block with some alignment, leaving memory for worst-case padding | 499 // allocate block with some alignment, leaving memory for worst-case padding |
493 void* memory = xml_memory::allocate(size + xml_memory_page_alignment); | 500 void* memory = xml_memory::allocate(size); |
494 if (!memory) return 0; | 501 if (!memory) return 0; |
495 | 502 |
496 // align to next page boundary (note: this guarantees at least 1 usable byte before the page) | |
497 char* page_memory = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1)); | |
498 | |
499 // prepare page structure | 503 // prepare page structure |
500 xml_memory_page* page = xml_memory_page::construct(page_memory); | 504 xml_memory_page* page = xml_memory_page::construct(memory); |
501 assert(page); | 505 assert(page); |
502 | 506 |
503 page->allocator = _root->allocator; | 507 page->allocator = _root->allocator; |
504 | 508 |
505 // record the offset for freeing the memory block | |
506 assert(page_memory > memory && page_memory - static_cast<char*>(memory) <= 127); | |
507 page_memory[-1] = static_cast<char>(page_memory - static_cast<char*>(memory)); | |
508 | |
509 return page; | 509 return page; |
510 } | 510 } |
511 | 511 |
512 static void deallocate_page(xml_memory_page* page) | 512 static void deallocate_page(xml_memory_page* page) |
513 { | 513 { |
514 char* page_memory = reinterpret_cast<char*>(page); | 514 xml_memory::deallocate(page); |
515 | |
516 xml_memory::deallocate(page_memory - page_memory[-1]); | |
517 } | 515 } |
518 | 516 |
519 void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); | 517 void* allocate_memory_oob(size_t size, xml_memory_page*& out_page); |
520 | 518 |
521 void* allocate_memory(size_t size, xml_memory_page*& out_page) | 519 void* allocate_memory(size_t size, xml_memory_page*& out_page) |
620 | 618 |
621 PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); | 619 PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset); |
622 | 620 |
623 // allocate memory for string and header block | 621 // allocate memory for string and header block |
624 size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); | 622 size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t); |
625 | 623 |
626 // round size up to block alignment boundary | 624 // round size up to block alignment boundary |
627 size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1); | 625 size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1); |
628 | 626 |
629 xml_memory_page* page; | 627 xml_memory_page* page; |
630 xml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page)); | 628 xml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page)); |
1044 impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute; | 1042 impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute; |
1045 }; | 1043 }; |
1046 | 1044 |
1047 struct xml_node_struct | 1045 struct xml_node_struct |
1048 { | 1046 { |
1049 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type - 1), namevalue_base(0) | 1047 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0) |
1050 { | 1048 { |
1051 PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); | 1049 PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12); |
1052 } | 1050 } |
1053 | 1051 |
1054 impl::compact_header header; | 1052 impl::compact_header header; |
1071 #else | 1069 #else |
1072 namespace pugi | 1070 namespace pugi |
1073 { | 1071 { |
1074 struct xml_attribute_struct | 1072 struct xml_attribute_struct |
1075 { | 1073 { |
1076 xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0) | 1074 xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0) |
1077 { | 1075 { |
1076 header = PUGI__GETHEADER_IMPL(this, page, 0); | |
1078 } | 1077 } |
1079 | 1078 |
1080 uintptr_t header; | 1079 uintptr_t header; |
1081 | 1080 |
1082 char_t* name; | 1081 char_t* name; |
1086 xml_attribute_struct* next_attribute; | 1085 xml_attribute_struct* next_attribute; |
1087 }; | 1086 }; |
1088 | 1087 |
1089 struct xml_node_struct | 1088 struct xml_node_struct |
1090 { | 1089 { |
1091 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast<uintptr_t>(page) | (type - 1)), name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) | 1090 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0) |
1092 { | 1091 { |
1092 header = PUGI__GETHEADER_IMPL(this, page, type); | |
1093 } | 1093 } |
1094 | 1094 |
1095 uintptr_t header; | 1095 uintptr_t header; |
1096 | 1096 |
1097 char_t* name; | 1097 char_t* name; |
1118 | 1118 |
1119 struct xml_document_struct: public xml_node_struct, public xml_allocator | 1119 struct xml_document_struct: public xml_node_struct, public xml_allocator |
1120 { | 1120 { |
1121 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) | 1121 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0) |
1122 { | 1122 { |
1123 #ifdef PUGIXML_COMPACT | |
1124 _hash = &hash; | |
1125 #endif | |
1126 } | 1123 } |
1127 | 1124 |
1128 const char_t* buffer; | 1125 const char_t* buffer; |
1129 | 1126 |
1130 xml_extra_buffer* extra_buffers; | 1127 xml_extra_buffer* extra_buffers; |
1845 ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " | 1842 ctx_special_attr = 2, // Any symbol >= 0 and < 32 (except \t), &, <, >, " |
1846 ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ | 1843 ctx_start_symbol = 4, // Any symbol > 127, a-z, A-Z, _ |
1847 ctx_digit = 8, // 0-9 | 1844 ctx_digit = 8, // 0-9 |
1848 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . | 1845 ctx_symbol = 16 // Any symbol > 127, a-z, A-Z, 0-9, _, -, . |
1849 }; | 1846 }; |
1850 | 1847 |
1851 static const unsigned char chartypex_table[256] = | 1848 static const unsigned char chartypex_table[256] = |
1852 { | 1849 { |
1853 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 | 1850 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3, // 0-15 |
1854 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 | 1851 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 16-31 |
1855 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 | 1852 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0, // 32-47 |
1867 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, | 1864 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, |
1868 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, | 1865 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, |
1869 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, | 1866 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, |
1870 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 | 1867 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 |
1871 }; | 1868 }; |
1872 | 1869 |
1873 #ifdef PUGIXML_WCHAR_MODE | 1870 #ifdef PUGIXML_WCHAR_MODE |
1874 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct)) | 1871 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct)) |
1875 #else | 1872 #else |
1876 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct)) | 1873 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct)) |
1877 #endif | 1874 #endif |
1890 { | 1887 { |
1891 PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); | 1888 PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4); |
1892 | 1889 |
1893 if (sizeof(wchar_t) == 2) | 1890 if (sizeof(wchar_t) == 2) |
1894 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; | 1891 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be; |
1895 else | 1892 else |
1896 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; | 1893 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; |
1897 } | 1894 } |
1898 | 1895 |
1899 PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3) | 1896 PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length) |
1900 { | 1897 { |
1898 #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; } | |
1899 #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; } | |
1900 | |
1901 // check if we have a non-empty XML declaration | |
1902 if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space))) | |
1903 return false; | |
1904 | |
1905 // scan XML declaration until the encoding field | |
1906 for (size_t i = 6; i + 1 < size; ++i) | |
1907 { | |
1908 // declaration can not contain ? in quoted values | |
1909 if (data[i] == '?') | |
1910 return false; | |
1911 | |
1912 if (data[i] == 'e' && data[i + 1] == 'n') | |
1913 { | |
1914 size_t offset = i; | |
1915 | |
1916 // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed | |
1917 PUGI__SCANCHAR('e'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('c'); PUGI__SCANCHAR('o'); | |
1918 PUGI__SCANCHAR('d'); PUGI__SCANCHAR('i'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('g'); | |
1919 | |
1920 // S? = S? | |
1921 PUGI__SCANCHARTYPE(ct_space); | |
1922 PUGI__SCANCHAR('='); | |
1923 PUGI__SCANCHARTYPE(ct_space); | |
1924 | |
1925 // the only two valid delimiters are ' and " | |
1926 uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\''; | |
1927 | |
1928 PUGI__SCANCHAR(delimiter); | |
1929 | |
1930 size_t start = offset; | |
1931 | |
1932 out_encoding = data + offset; | |
1933 | |
1934 PUGI__SCANCHARTYPE(ct_symbol); | |
1935 | |
1936 out_length = offset - start; | |
1937 | |
1938 PUGI__SCANCHAR(delimiter); | |
1939 | |
1940 return true; | |
1941 } | |
1942 } | |
1943 | |
1944 return false; | |
1945 | |
1946 #undef PUGI__SCANCHAR | |
1947 #undef PUGI__SCANCHARTYPE | |
1948 } | |
1949 | |
1950 PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size) | |
1951 { | |
1952 // skip encoding autodetection if input buffer is too small | |
1953 if (size < 4) return encoding_utf8; | |
1954 | |
1955 uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; | |
1956 | |
1901 // look for BOM in first few bytes | 1957 // look for BOM in first few bytes |
1902 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; | 1958 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be; |
1903 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; | 1959 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le; |
1904 if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; | 1960 if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be; |
1905 if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; | 1961 if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le; |
1908 // look for <, <? or <?xm in various encodings | 1964 // look for <, <? or <?xm in various encodings |
1909 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be; | 1965 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be; |
1910 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le; | 1966 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le; |
1911 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be; | 1967 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be; |
1912 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le; | 1968 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le; |
1913 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8; | |
1914 | 1969 |
1915 // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early) | 1970 // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early) |
1916 if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be; | 1971 if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be; |
1917 if (d0 == 0x3c && d1 == 0) return encoding_utf16_le; | 1972 if (d0 == 0x3c && d1 == 0) return encoding_utf16_le; |
1918 | 1973 |
1919 // no known BOM detected, assume utf8 | 1974 // no known BOM detected; parse declaration |
1975 const uint8_t* enc = 0; | |
1976 size_t enc_length = 0; | |
1977 | |
1978 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length)) | |
1979 { | |
1980 // iso-8859-1 (case-insensitive) | |
1981 if (enc_length == 10 | |
1982 && (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o' | |
1983 && enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9' | |
1984 && enc[8] == '-' && enc[9] == '1') | |
1985 return encoding_latin1; | |
1986 | |
1987 // latin1 (case-insensitive) | |
1988 if (enc_length == 6 | |
1989 && (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't' | |
1990 && (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n' | |
1991 && enc[5] == '1') | |
1992 return encoding_latin1; | |
1993 } | |
1994 | |
1920 return encoding_utf8; | 1995 return encoding_utf8; |
1921 } | 1996 } |
1922 | 1997 |
1923 PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size) | 1998 PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size) |
1924 { | 1999 { |
1932 if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; | 2007 if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be; |
1933 | 2008 |
1934 // only do autodetection if no explicit encoding is requested | 2009 // only do autodetection if no explicit encoding is requested |
1935 if (encoding != encoding_auto) return encoding; | 2010 if (encoding != encoding_auto) return encoding; |
1936 | 2011 |
1937 // skip encoding autodetection if input buffer is too small | |
1938 if (size < 4) return encoding_utf8; | |
1939 | |
1940 // try to guess encoding (based on XML specification, Appendix F.1) | 2012 // try to guess encoding (based on XML specification, Appendix F.1) |
1941 const uint8_t* data = static_cast<const uint8_t*>(contents); | 2013 const uint8_t* data = static_cast<const uint8_t*>(contents); |
1942 | 2014 |
1943 PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3]; | 2015 return guess_buffer_encoding(data, size); |
1944 | |
1945 return guess_buffer_encoding(d0, d1, d2, d3); | |
1946 } | 2016 } |
1947 | 2017 |
1948 PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) | 2018 PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable) |
1949 { | 2019 { |
1950 size_t length = size / sizeof(char_t); | 2020 size_t length = size / sizeof(char_t); |
2073 | 2143 |
2074 // source encoding is latin1 | 2144 // source encoding is latin1 |
2075 if (encoding == encoding_latin1) | 2145 if (encoding == encoding_latin1) |
2076 return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder()); | 2146 return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder()); |
2077 | 2147 |
2078 assert(!"Invalid encoding"); | 2148 assert(false && "Invalid encoding"); |
2079 return false; | 2149 return false; |
2080 } | 2150 } |
2081 #else | 2151 #else |
2082 template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) | 2152 template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D) |
2083 { | 2153 { |
2178 | 2248 |
2179 // source encoding is latin1 | 2249 // source encoding is latin1 |
2180 if (encoding == encoding_latin1) | 2250 if (encoding == encoding_latin1) |
2181 return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); | 2251 return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable); |
2182 | 2252 |
2183 assert(!"Invalid encoding"); | 2253 assert(false && "Invalid encoding"); |
2184 return false; | 2254 return false; |
2185 } | 2255 } |
2186 #endif | 2256 #endif |
2187 | 2257 |
2188 PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) | 2258 PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length) |
2194 PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) | 2264 PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length) |
2195 { | 2265 { |
2196 // convert to utf8 | 2266 // convert to utf8 |
2197 uint8_t* begin = reinterpret_cast<uint8_t*>(buffer); | 2267 uint8_t* begin = reinterpret_cast<uint8_t*>(buffer); |
2198 uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer()); | 2268 uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer()); |
2199 | 2269 |
2200 assert(begin + size == end); | 2270 assert(begin + size == end); |
2201 (void)!end; | 2271 (void)!end; |
2202 (void)!size; | 2272 (void)!size; |
2203 } | 2273 } |
2204 | 2274 |
2205 #ifndef PUGIXML_NO_STL | 2275 #ifndef PUGIXML_NO_STL |
2206 PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) | 2276 PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length) |
2207 { | 2277 { |
2208 // first pass: get length in utf8 characters | 2278 // first pass: get length in utf8 characters |
2209 size_t size = as_utf8_begin(str, length); | 2279 size_t size = as_utf8_begin(str, length); |
2267 { | 2337 { |
2268 // empty string and null pointer are equivalent, so just deallocate old memory | 2338 // empty string and null pointer are equivalent, so just deallocate old memory |
2269 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; | 2339 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; |
2270 | 2340 |
2271 if (header & header_mask) alloc->deallocate_string(dest); | 2341 if (header & header_mask) alloc->deallocate_string(dest); |
2272 | 2342 |
2273 // mark the string as not allocated | 2343 // mark the string as not allocated |
2274 dest = 0; | 2344 dest = 0; |
2275 header &= ~header_mask; | 2345 header &= ~header_mask; |
2276 | 2346 |
2277 return true; | 2347 return true; |
2279 else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) | 2349 else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest)) |
2280 { | 2350 { |
2281 // we can reuse old buffer, so just copy the new data (including zero terminator) | 2351 // we can reuse old buffer, so just copy the new data (including zero terminator) |
2282 memcpy(dest, source, source_length * sizeof(char_t)); | 2352 memcpy(dest, source, source_length * sizeof(char_t)); |
2283 dest[source_length] = 0; | 2353 dest[source_length] = 0; |
2284 | 2354 |
2285 return true; | 2355 return true; |
2286 } | 2356 } |
2287 else | 2357 else |
2288 { | 2358 { |
2289 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; | 2359 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator; |
2298 memcpy(buf, source, source_length * sizeof(char_t)); | 2368 memcpy(buf, source, source_length * sizeof(char_t)); |
2299 buf[source_length] = 0; | 2369 buf[source_length] = 0; |
2300 | 2370 |
2301 // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) | 2371 // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) |
2302 if (header & header_mask) alloc->deallocate_string(dest); | 2372 if (header & header_mask) alloc->deallocate_string(dest); |
2303 | 2373 |
2304 // the string is now allocated, so set the flag | 2374 // the string is now allocated, so set the flag |
2305 dest = buf; | 2375 dest = buf; |
2306 header |= header_mask; | 2376 header |= header_mask; |
2307 | 2377 |
2308 return true; | 2378 return true; |
2311 | 2381 |
2312 struct gap | 2382 struct gap |
2313 { | 2383 { |
2314 char_t* end; | 2384 char_t* end; |
2315 size_t size; | 2385 size_t size; |
2316 | 2386 |
2317 gap(): end(0), size(0) | 2387 gap(): end(0), size(0) |
2318 { | 2388 { |
2319 } | 2389 } |
2320 | 2390 |
2321 // Push new gap, move s count bytes further (skipping the gap). | 2391 // Push new gap, move s count bytes further (skipping the gap). |
2322 // Collapse previous gap. | 2392 // Collapse previous gap. |
2323 void push(char_t*& s, size_t count) | 2393 void push(char_t*& s, size_t count) |
2324 { | 2394 { |
2325 if (end) // there was a gap already; collapse it | 2395 if (end) // there was a gap already; collapse it |
2326 { | 2396 { |
2327 // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) | 2397 // Move [old_gap_end, new_gap_start) to [old_gap_start, ...) |
2328 assert(s >= end); | 2398 assert(s >= end); |
2329 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end)); | 2399 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end)); |
2330 } | 2400 } |
2331 | 2401 |
2332 s += count; // end of current gap | 2402 s += count; // end of current gap |
2333 | 2403 |
2334 // "merge" two gaps | 2404 // "merge" two gaps |
2335 end = s; | 2405 end = s; |
2336 size += count; | 2406 size += count; |
2337 } | 2407 } |
2338 | 2408 |
2339 // Collapse all gaps, return past-the-end pointer | 2409 // Collapse all gaps, return past-the-end pointer |
2340 char_t* flush(char_t* s) | 2410 char_t* flush(char_t* s) |
2341 { | 2411 { |
2342 if (end) | 2412 if (end) |
2343 { | 2413 { |
2348 return s - size; | 2418 return s - size; |
2349 } | 2419 } |
2350 else return s; | 2420 else return s; |
2351 } | 2421 } |
2352 }; | 2422 }; |
2353 | 2423 |
2354 PUGI__FN char_t* strconv_escape(char_t* s, gap& g) | 2424 PUGI__FN char_t* strconv_escape(char_t* s, gap& g) |
2355 { | 2425 { |
2356 char_t* stre = s + 1; | 2426 char_t* stre = s + 1; |
2357 | 2427 |
2358 switch (*stre) | 2428 switch (*stre) |
2380 else // cancel | 2450 else // cancel |
2381 return stre; | 2451 return stre; |
2382 | 2452 |
2383 ch = *++stre; | 2453 ch = *++stre; |
2384 } | 2454 } |
2385 | 2455 |
2386 ++stre; | 2456 ++stre; |
2387 } | 2457 } |
2388 else // &#... (dec code) | 2458 else // &#... (dec code) |
2389 { | 2459 { |
2390 char_t ch = *++stre; | 2460 char_t ch = *++stre; |
2400 else // cancel | 2470 else // cancel |
2401 return stre; | 2471 return stre; |
2402 | 2472 |
2403 ch = *++stre; | 2473 ch = *++stre; |
2404 } | 2474 } |
2405 | 2475 |
2406 ++stre; | 2476 ++stre; |
2407 } | 2477 } |
2408 | 2478 |
2409 #ifdef PUGIXML_WCHAR_MODE | 2479 #ifdef PUGIXML_WCHAR_MODE |
2410 s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc)); | 2480 s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc)); |
2411 #else | 2481 #else |
2412 s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc)); | 2482 s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc)); |
2413 #endif | 2483 #endif |
2414 | 2484 |
2415 g.push(s, stre - s); | 2485 g.push(s, stre - s); |
2416 return stre; | 2486 return stre; |
2417 } | 2487 } |
2418 | 2488 |
2419 case 'a': // &a | 2489 case 'a': // &a |
2424 { | 2494 { |
2425 if (*++stre == 'p' && *++stre == ';') // & | 2495 if (*++stre == 'p' && *++stre == ';') // & |
2426 { | 2496 { |
2427 *s++ = '&'; | 2497 *s++ = '&'; |
2428 ++stre; | 2498 ++stre; |
2429 | 2499 |
2430 g.push(s, stre - s); | 2500 g.push(s, stre - s); |
2431 return stre; | 2501 return stre; |
2432 } | 2502 } |
2433 } | 2503 } |
2434 else if (*stre == 'p') // &ap | 2504 else if (*stre == 'p') // &ap |
2449 { | 2519 { |
2450 if (*++stre == 't' && *++stre == ';') // > | 2520 if (*++stre == 't' && *++stre == ';') // > |
2451 { | 2521 { |
2452 *s++ = '>'; | 2522 *s++ = '>'; |
2453 ++stre; | 2523 ++stre; |
2454 | 2524 |
2455 g.push(s, stre - s); | 2525 g.push(s, stre - s); |
2456 return stre; | 2526 return stre; |
2457 } | 2527 } |
2458 break; | 2528 break; |
2459 } | 2529 } |
2462 { | 2532 { |
2463 if (*++stre == 't' && *++stre == ';') // < | 2533 if (*++stre == 't' && *++stre == ';') // < |
2464 { | 2534 { |
2465 *s++ = '<'; | 2535 *s++ = '<'; |
2466 ++stre; | 2536 ++stre; |
2467 | 2537 |
2468 g.push(s, stre - s); | 2538 g.push(s, stre - s); |
2469 return stre; | 2539 return stre; |
2470 } | 2540 } |
2471 break; | 2541 break; |
2472 } | 2542 } |
2475 { | 2545 { |
2476 if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " | 2546 if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // " |
2477 { | 2547 { |
2478 *s++ = '"'; | 2548 *s++ = '"'; |
2479 ++stre; | 2549 ++stre; |
2480 | 2550 |
2481 g.push(s, stre - s); | 2551 g.push(s, stre - s); |
2482 return stre; | 2552 return stre; |
2483 } | 2553 } |
2484 break; | 2554 break; |
2485 } | 2555 } |
2486 | 2556 |
2487 default: | 2557 default: |
2488 break; | 2558 break; |
2489 } | 2559 } |
2490 | 2560 |
2491 return stre; | 2561 return stre; |
2492 } | 2562 } |
2493 | 2563 |
2494 // Parser utilities | 2564 // Parser utilities |
2495 #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) | 2565 #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e))) |
2496 #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } | 2566 #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; } |
2497 #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) | 2567 #define PUGI__OPTSET(OPT) ( optmsk & (OPT) ) |
2498 #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } | 2568 #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); } |
2499 #define PUGI__POPNODE() { cursor = cursor->parent; } | 2569 #define PUGI__POPNODE() { cursor = cursor->parent; } |
2500 #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } | 2570 #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; } |
2501 #define PUGI__SCANWHILE(X) { while (X) ++s; } | 2571 #define PUGI__SCANWHILE(X) { while (X) ++s; } |
2502 #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } | 2572 #define PUGI__SCANWHILE_UNROLL(X) { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } } |
2503 #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } | 2573 #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; } |
2505 #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } | 2575 #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); } |
2506 | 2576 |
2507 PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) | 2577 PUGI__FN char_t* strconv_comment(char_t* s, char_t endch) |
2508 { | 2578 { |
2509 gap g; | 2579 gap g; |
2510 | 2580 |
2511 while (true) | 2581 while (true) |
2512 { | 2582 { |
2513 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); | 2583 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment)); |
2514 | 2584 |
2515 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair | 2585 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair |
2516 { | 2586 { |
2517 *s++ = '\n'; // replace first one with 0x0a | 2587 *s++ = '\n'; // replace first one with 0x0a |
2518 | 2588 |
2519 if (*s == '\n') g.push(s, 1); | 2589 if (*s == '\n') g.push(s, 1); |
2520 } | 2590 } |
2521 else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here | 2591 else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here |
2522 { | 2592 { |
2523 *g.flush(s) = 0; | 2593 *g.flush(s) = 0; |
2524 | 2594 |
2525 return s + (s[2] == '>' ? 3 : 2); | 2595 return s + (s[2] == '>' ? 3 : 2); |
2526 } | 2596 } |
2527 else if (*s == 0) | 2597 else if (*s == 0) |
2528 { | 2598 { |
2529 return 0; | 2599 return 0; |
2533 } | 2603 } |
2534 | 2604 |
2535 PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) | 2605 PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch) |
2536 { | 2606 { |
2537 gap g; | 2607 gap g; |
2538 | 2608 |
2539 while (true) | 2609 while (true) |
2540 { | 2610 { |
2541 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); | 2611 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata)); |
2542 | 2612 |
2543 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair | 2613 if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair |
2544 { | 2614 { |
2545 *s++ = '\n'; // replace first one with 0x0a | 2615 *s++ = '\n'; // replace first one with 0x0a |
2546 | 2616 |
2547 if (*s == '\n') g.push(s, 1); | 2617 if (*s == '\n') g.push(s, 1); |
2548 } | 2618 } |
2549 else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here | 2619 else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here |
2550 { | 2620 { |
2551 *g.flush(s) = 0; | 2621 *g.flush(s) = 0; |
2552 | 2622 |
2553 return s + 1; | 2623 return s + 1; |
2554 } | 2624 } |
2555 else if (*s == 0) | 2625 else if (*s == 0) |
2556 { | 2626 { |
2557 return 0; | 2627 return 0; |
2558 } | 2628 } |
2559 else ++s; | 2629 else ++s; |
2560 } | 2630 } |
2561 } | 2631 } |
2562 | 2632 |
2563 typedef char_t* (*strconv_pcdata_t)(char_t*); | 2633 typedef char_t* (*strconv_pcdata_t)(char_t*); |
2564 | 2634 |
2565 template <typename opt_trim, typename opt_eol, typename opt_escape> struct strconv_pcdata_impl | 2635 template <typename opt_trim, typename opt_eol, typename opt_escape> struct strconv_pcdata_impl |
2566 { | 2636 { |
2567 static char_t* parse(char_t* s) | 2637 static char_t* parse(char_t* s) |
2568 { | 2638 { |
2569 gap g; | 2639 gap g; |
2581 if (opt_trim::value) | 2651 if (opt_trim::value) |
2582 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) | 2652 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space)) |
2583 --end; | 2653 --end; |
2584 | 2654 |
2585 *end = 0; | 2655 *end = 0; |
2586 | 2656 |
2587 return s + 1; | 2657 return s + 1; |
2588 } | 2658 } |
2589 else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair | 2659 else if (opt_eol::value && *s == '\r') // Either a single 0x0d or 0x0d 0x0a pair |
2590 { | 2660 { |
2591 *s++ = '\n'; // replace first one with 0x0a | 2661 *s++ = '\n'; // replace first one with 0x0a |
2592 | 2662 |
2593 if (*s == '\n') g.push(s, 1); | 2663 if (*s == '\n') g.push(s, 1); |
2594 } | 2664 } |
2595 else if (opt_escape::value && *s == '&') | 2665 else if (opt_escape::value && *s == '&') |
2596 { | 2666 { |
2597 s = strconv_escape(s, g); | 2667 s = strconv_escape(s, g); |
2610 } | 2680 } |
2611 else ++s; | 2681 else ++s; |
2612 } | 2682 } |
2613 } | 2683 } |
2614 }; | 2684 }; |
2615 | 2685 |
2616 PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) | 2686 PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask) |
2617 { | 2687 { |
2618 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); | 2688 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800); |
2619 | 2689 |
2620 switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (eol escapes trim) | 2690 switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (eol escapes trim) |
2630 default: assert(false); return 0; // should not get here | 2700 default: assert(false); return 0; // should not get here |
2631 } | 2701 } |
2632 } | 2702 } |
2633 | 2703 |
2634 typedef char_t* (*strconv_attribute_t)(char_t*, char_t); | 2704 typedef char_t* (*strconv_attribute_t)(char_t*, char_t); |
2635 | 2705 |
2636 template <typename opt_escape> struct strconv_attribute_impl | 2706 template <typename opt_escape> struct strconv_attribute_impl |
2637 { | 2707 { |
2638 static char_t* parse_wnorm(char_t* s, char_t end_quote) | 2708 static char_t* parse_wnorm(char_t* s, char_t end_quote) |
2639 { | 2709 { |
2640 gap g; | 2710 gap g; |
2641 | 2711 |
2642 // trim leading whitespaces | 2712 // trim leading whitespaces |
2643 if (PUGI__IS_CHARTYPE(*s, ct_space)) | 2713 if (PUGI__IS_CHARTYPE(*s, ct_space)) |
2644 { | 2714 { |
2645 char_t* str = s; | 2715 char_t* str = s; |
2646 | 2716 |
2647 do ++str; | 2717 do ++str; |
2648 while (PUGI__IS_CHARTYPE(*str, ct_space)); | 2718 while (PUGI__IS_CHARTYPE(*str, ct_space)); |
2649 | 2719 |
2650 g.push(s, str - s); | 2720 g.push(s, str - s); |
2651 } | 2721 } |
2652 | 2722 |
2653 while (true) | 2723 while (true) |
2654 { | 2724 { |
2655 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); | 2725 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space)); |
2656 | 2726 |
2657 if (*s == end_quote) | 2727 if (*s == end_quote) |
2658 { | 2728 { |
2659 char_t* str = g.flush(s); | 2729 char_t* str = g.flush(s); |
2660 | 2730 |
2661 do *str-- = 0; | 2731 do *str-- = 0; |
2662 while (PUGI__IS_CHARTYPE(*str, ct_space)); | 2732 while (PUGI__IS_CHARTYPE(*str, ct_space)); |
2663 | 2733 |
2664 return s + 1; | 2734 return s + 1; |
2665 } | 2735 } |
2666 else if (PUGI__IS_CHARTYPE(*s, ct_space)) | 2736 else if (PUGI__IS_CHARTYPE(*s, ct_space)) |
2667 { | 2737 { |
2668 *s++ = ' '; | 2738 *s++ = ' '; |
2669 | 2739 |
2670 if (PUGI__IS_CHARTYPE(*s, ct_space)) | 2740 if (PUGI__IS_CHARTYPE(*s, ct_space)) |
2671 { | 2741 { |
2672 char_t* str = s + 1; | 2742 char_t* str = s + 1; |
2673 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; | 2743 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str; |
2674 | 2744 |
2675 g.push(s, str - s); | 2745 g.push(s, str - s); |
2676 } | 2746 } |
2677 } | 2747 } |
2678 else if (opt_escape::value && *s == '&') | 2748 else if (opt_escape::value && *s == '&') |
2679 { | 2749 { |
2692 gap g; | 2762 gap g; |
2693 | 2763 |
2694 while (true) | 2764 while (true) |
2695 { | 2765 { |
2696 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); | 2766 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws)); |
2697 | 2767 |
2698 if (*s == end_quote) | 2768 if (*s == end_quote) |
2699 { | 2769 { |
2700 *g.flush(s) = 0; | 2770 *g.flush(s) = 0; |
2701 | 2771 |
2702 return s + 1; | 2772 return s + 1; |
2703 } | 2773 } |
2704 else if (PUGI__IS_CHARTYPE(*s, ct_space)) | 2774 else if (PUGI__IS_CHARTYPE(*s, ct_space)) |
2705 { | 2775 { |
2706 if (*s == '\r') | 2776 if (*s == '\r') |
2707 { | 2777 { |
2708 *s++ = ' '; | 2778 *s++ = ' '; |
2709 | 2779 |
2710 if (*s == '\n') g.push(s, 1); | 2780 if (*s == '\n') g.push(s, 1); |
2711 } | 2781 } |
2712 else *s++ = ' '; | 2782 else *s++ = ' '; |
2713 } | 2783 } |
2714 else if (opt_escape::value && *s == '&') | 2784 else if (opt_escape::value && *s == '&') |
2728 gap g; | 2798 gap g; |
2729 | 2799 |
2730 while (true) | 2800 while (true) |
2731 { | 2801 { |
2732 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); | 2802 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); |
2733 | 2803 |
2734 if (*s == end_quote) | 2804 if (*s == end_quote) |
2735 { | 2805 { |
2736 *g.flush(s) = 0; | 2806 *g.flush(s) = 0; |
2737 | 2807 |
2738 return s + 1; | 2808 return s + 1; |
2739 } | 2809 } |
2740 else if (*s == '\r') | 2810 else if (*s == '\r') |
2741 { | 2811 { |
2742 *s++ = '\n'; | 2812 *s++ = '\n'; |
2743 | 2813 |
2744 if (*s == '\n') g.push(s, 1); | 2814 if (*s == '\n') g.push(s, 1); |
2745 } | 2815 } |
2746 else if (opt_escape::value && *s == '&') | 2816 else if (opt_escape::value && *s == '&') |
2747 { | 2817 { |
2748 s = strconv_escape(s, g); | 2818 s = strconv_escape(s, g); |
2760 gap g; | 2830 gap g; |
2761 | 2831 |
2762 while (true) | 2832 while (true) |
2763 { | 2833 { |
2764 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); | 2834 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr)); |
2765 | 2835 |
2766 if (*s == end_quote) | 2836 if (*s == end_quote) |
2767 { | 2837 { |
2768 *g.flush(s) = 0; | 2838 *g.flush(s) = 0; |
2769 | 2839 |
2770 return s + 1; | 2840 return s + 1; |
2771 } | 2841 } |
2772 else if (opt_escape::value && *s == '&') | 2842 else if (opt_escape::value && *s == '&') |
2773 { | 2843 { |
2774 s = strconv_escape(s, g); | 2844 s = strconv_escape(s, g); |
2783 }; | 2853 }; |
2784 | 2854 |
2785 PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) | 2855 PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask) |
2786 { | 2856 { |
2787 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); | 2857 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80); |
2788 | 2858 |
2789 switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) | 2859 switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes) |
2790 { | 2860 { |
2791 case 0: return strconv_attribute_impl<opt_false>::parse_simple; | 2861 case 0: return strconv_attribute_impl<opt_false>::parse_simple; |
2792 case 1: return strconv_attribute_impl<opt_true>::parse_simple; | 2862 case 1: return strconv_attribute_impl<opt_true>::parse_simple; |
2793 case 2: return strconv_attribute_impl<opt_false>::parse_eol; | 2863 case 2: return strconv_attribute_impl<opt_false>::parse_eol; |
2817 return result; | 2887 return result; |
2818 } | 2888 } |
2819 | 2889 |
2820 struct xml_parser | 2890 struct xml_parser |
2821 { | 2891 { |
2822 xml_allocator alloc; | 2892 xml_allocator* alloc; |
2823 xml_allocator* alloc_state; | |
2824 char_t* error_offset; | 2893 char_t* error_offset; |
2825 xml_parse_status error_status; | 2894 xml_parse_status error_status; |
2826 | 2895 |
2827 xml_parser(xml_allocator* alloc_): alloc(*alloc_), alloc_state(alloc_), error_offset(0), error_status(status_ok) | 2896 xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(0), error_status(status_ok) |
2828 { | 2897 { |
2829 } | |
2830 | |
2831 ~xml_parser() | |
2832 { | |
2833 *alloc_state = alloc; | |
2834 } | 2898 } |
2835 | 2899 |
2836 // DOCTYPE consists of nested sections of the following possible types: | 2900 // DOCTYPE consists of nested sections of the following possible types: |
2837 // <!-- ... -->, <? ... ?>, "...", '...' | 2901 // <!-- ... -->, <? ... ?>, "...", '...' |
2838 // <![...]]> | 2902 // <![...]]> |
3155 | 3219 |
3156 char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch) | 3220 char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch) |
3157 { | 3221 { |
3158 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); | 3222 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk); |
3159 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); | 3223 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk); |
3160 | 3224 |
3161 char_t ch = 0; | 3225 char_t ch = 0; |
3162 xml_node_struct* cursor = root; | 3226 xml_node_struct* cursor = root; |
3163 char_t* mark = s; | 3227 char_t* mark = s; |
3164 | 3228 |
3165 while (*s != 0) | 3229 while (*s != 0) |
3186 { | 3250 { |
3187 LOC_ATTRIBUTES: | 3251 LOC_ATTRIBUTES: |
3188 while (true) | 3252 while (true) |
3189 { | 3253 { |
3190 PUGI__SKIPWS(); // Eat any whitespace. | 3254 PUGI__SKIPWS(); // Eat any whitespace. |
3191 | 3255 |
3192 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... | 3256 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #... |
3193 { | 3257 { |
3194 xml_attribute_struct* a = append_new_attribute(cursor, alloc); // Make space for this attribute. | 3258 xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute. |
3195 if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); | 3259 if (!a) PUGI__THROW_ERROR(status_out_of_memory, s); |
3196 | 3260 |
3197 a->name = s; // Save the offset. | 3261 a->name = s; // Save the offset. |
3198 | 3262 |
3199 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. | 3263 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator. |
3204 PUGI__SKIPWS(); // Eat any whitespace. | 3268 PUGI__SKIPWS(); // Eat any whitespace. |
3205 | 3269 |
3206 ch = *s; | 3270 ch = *s; |
3207 ++s; | 3271 ++s; |
3208 } | 3272 } |
3209 | 3273 |
3210 if (ch == '=') // '<... #=...' | 3274 if (ch == '=') // '<... #=...' |
3211 { | 3275 { |
3212 PUGI__SKIPWS(); // Eat any whitespace. | 3276 PUGI__SKIPWS(); // Eat any whitespace. |
3213 | 3277 |
3214 if (*s == '"' || *s == '\'') // '<... #="...' | 3278 if (*s == '"' || *s == '\'') // '<... #="...' |
3216 ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. | 3280 ch = *s; // Save quote char to avoid breaking on "''" -or- '""'. |
3217 ++s; // Step over the quote. | 3281 ++s; // Step over the quote. |
3218 a->value = s; // Save the offset. | 3282 a->value = s; // Save the offset. |
3219 | 3283 |
3220 s = strconv_attribute(s, ch); | 3284 s = strconv_attribute(s, ch); |
3221 | 3285 |
3222 if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); | 3286 if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value); |
3223 | 3287 |
3224 // After this line the loop continues from the start; | 3288 // After this line the loop continues from the start; |
3225 // Whitespaces, / and > are ok, symbols and EOF are wrong, | 3289 // Whitespaces, / and > are ok, symbols and EOF are wrong, |
3226 // everything else will be detected | 3290 // everything else will be detected |
3231 else PUGI__THROW_ERROR(status_bad_attribute, s); | 3295 else PUGI__THROW_ERROR(status_bad_attribute, s); |
3232 } | 3296 } |
3233 else if (*s == '/') | 3297 else if (*s == '/') |
3234 { | 3298 { |
3235 ++s; | 3299 ++s; |
3236 | 3300 |
3237 if (*s == '>') | 3301 if (*s == '>') |
3238 { | 3302 { |
3239 PUGI__POPNODE(); | 3303 PUGI__POPNODE(); |
3240 s++; | 3304 s++; |
3241 break; | 3305 break; |
3272 } | 3336 } |
3273 else if (ch == 0) | 3337 else if (ch == 0) |
3274 { | 3338 { |
3275 // we stepped over null terminator, backtrack & handle closing tag | 3339 // we stepped over null terminator, backtrack & handle closing tag |
3276 --s; | 3340 --s; |
3277 | 3341 |
3278 if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); | 3342 if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s); |
3279 } | 3343 } |
3280 else PUGI__THROW_ERROR(status_bad_start_element, s); | 3344 else PUGI__THROW_ERROR(status_bad_start_element, s); |
3281 } | 3345 } |
3282 else if (*s == '/') | 3346 else if (*s == '/') |
3283 { | 3347 { |
3284 ++s; | 3348 ++s; |
3285 | 3349 |
3350 mark = s; | |
3351 | |
3286 char_t* name = cursor->name; | 3352 char_t* name = cursor->name; |
3287 if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s); | 3353 if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark); |
3288 | 3354 |
3289 while (PUGI__IS_CHARTYPE(*s, ct_symbol)) | 3355 while (PUGI__IS_CHARTYPE(*s, ct_symbol)) |
3290 { | 3356 { |
3291 if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s); | 3357 if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark); |
3292 } | 3358 } |
3293 | 3359 |
3294 if (*name) | 3360 if (*name) |
3295 { | 3361 { |
3296 if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); | 3362 if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s); |
3297 else PUGI__THROW_ERROR(status_end_element_mismatch, s); | 3363 else PUGI__THROW_ERROR(status_end_element_mismatch, mark); |
3298 } | 3364 } |
3299 | 3365 |
3300 PUGI__POPNODE(); // Pop. | 3366 PUGI__POPNODE(); // Pop. |
3301 | 3367 |
3302 PUGI__SKIPWS(); | 3368 PUGI__SKIPWS(); |
3303 | 3369 |
3304 if (*s == 0) | 3370 if (*s == 0) |
3348 } | 3414 } |
3349 } | 3415 } |
3350 | 3416 |
3351 if (!PUGI__OPTSET(parse_trim_pcdata)) | 3417 if (!PUGI__OPTSET(parse_trim_pcdata)) |
3352 s = mark; | 3418 s = mark; |
3353 | 3419 |
3354 if (cursor->parent || PUGI__OPTSET(parse_fragment)) | 3420 if (cursor->parent || PUGI__OPTSET(parse_fragment)) |
3355 { | 3421 { |
3356 PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. | 3422 if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value) |
3357 cursor->value = s; // Save the offset. | 3423 { |
3424 cursor->value = s; // Save the offset. | |
3425 } | |
3426 else | |
3427 { | |
3428 PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree. | |
3429 | |
3430 cursor->value = s; // Save the offset. | |
3431 | |
3432 PUGI__POPNODE(); // Pop since this is a standalone. | |
3433 } | |
3358 | 3434 |
3359 s = strconv_pcdata(s); | 3435 s = strconv_pcdata(s); |
3360 | 3436 |
3361 PUGI__POPNODE(); // Pop since this is a standalone. | |
3362 | |
3363 if (!*s) break; | 3437 if (!*s) break; |
3364 } | 3438 } |
3365 else | 3439 else |
3366 { | 3440 { |
3367 PUGI__SCANFOR(*s == '<'); // '...<' | 3441 PUGI__SCANFOR(*s == '<'); // '...<' |
3368 if (!*s) break; | 3442 if (!*s) break; |
3369 | 3443 |
3370 ++s; | 3444 ++s; |
3371 } | 3445 } |
3372 | 3446 |
3373 // We're after '<' | 3447 // We're after '<' |
3374 goto LOC_TAG; | 3448 goto LOC_TAG; |
3412 if (length == 0) | 3486 if (length == 0) |
3413 return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element); | 3487 return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element); |
3414 | 3488 |
3415 // get last child of the root before parsing | 3489 // get last child of the root before parsing |
3416 xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0; | 3490 xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0; |
3417 | 3491 |
3418 // create parser on stack | 3492 // create parser on stack |
3419 xml_parser parser(static_cast<xml_allocator*>(xmldoc)); | 3493 xml_parser parser(static_cast<xml_allocator*>(xmldoc)); |
3420 | 3494 |
3421 // save last character and make buffer zero-terminated (speeds up parsing) | 3495 // save last character and make buffer zero-terminated (speeds up parsing) |
3422 char_t endch = buffer[length - 1]; | 3496 char_t endch = buffer[length - 1]; |
3423 buffer[length - 1] = 0; | 3497 buffer[length - 1] = 0; |
3424 | 3498 |
3425 // skip BOM to make sure it does not end up as part of parse output | 3499 // skip BOM to make sure it does not end up as part of parse output |
3426 char_t* buffer_data = parse_skip_bom(buffer); | 3500 char_t* buffer_data = parse_skip_bom(buffer); |
3427 | 3501 |
3428 // perform actual parsing | 3502 // perform actual parsing |
3429 parser.parse_tree(buffer_data, root, optmsk, endch); | 3503 parser.parse_tree(buffer_data, root, optmsk, endch); |
3509 #ifdef PUGIXML_WCHAR_MODE | 3583 #ifdef PUGIXML_WCHAR_MODE |
3510 PUGI__FN size_t get_valid_length(const char_t* data, size_t length) | 3584 PUGI__FN size_t get_valid_length(const char_t* data, size_t length) |
3511 { | 3585 { |
3512 if (length < 1) return 0; | 3586 if (length < 1) return 0; |
3513 | 3587 |
3514 // discard last character if it's the lead of a surrogate pair | 3588 // discard last character if it's the lead of a surrogate pair |
3515 return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; | 3589 return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length; |
3516 } | 3590 } |
3517 | 3591 |
3518 PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) | 3592 PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding) |
3519 { | 3593 { |
3522 { | 3596 { |
3523 convert_wchar_endian_swap(r_char, data, length); | 3597 convert_wchar_endian_swap(r_char, data, length); |
3524 | 3598 |
3525 return length * sizeof(char_t); | 3599 return length * sizeof(char_t); |
3526 } | 3600 } |
3527 | 3601 |
3528 // convert to utf8 | 3602 // convert to utf8 |
3529 if (encoding == encoding_utf8) | 3603 if (encoding == encoding_utf8) |
3530 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer()); | 3604 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer()); |
3531 | 3605 |
3532 // convert to utf16 | 3606 // convert to utf16 |
3547 | 3621 |
3548 // convert to latin1 | 3622 // convert to latin1 |
3549 if (encoding == encoding_latin1) | 3623 if (encoding == encoding_latin1) |
3550 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer()); | 3624 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer()); |
3551 | 3625 |
3552 assert(!"Invalid encoding"); | 3626 assert(false && "Invalid encoding"); |
3553 return 0; | 3627 return 0; |
3554 } | 3628 } |
3555 #else | 3629 #else |
3556 PUGI__FN size_t get_valid_length(const char_t* data, size_t length) | 3630 PUGI__FN size_t get_valid_length(const char_t* data, size_t length) |
3557 { | 3631 { |
3586 } | 3660 } |
3587 | 3661 |
3588 if (encoding == encoding_latin1) | 3662 if (encoding == encoding_latin1) |
3589 return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer()); | 3663 return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer()); |
3590 | 3664 |
3591 assert(!"Invalid encoding"); | 3665 assert(false && "Invalid encoding"); |
3592 return 0; | 3666 return 0; |
3593 } | 3667 } |
3594 #endif | 3668 #endif |
3595 | 3669 |
3596 class xml_buffered_writer | 3670 class xml_buffered_writer |
3810 PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) | 3884 PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type) |
3811 { | 3885 { |
3812 while (*s) | 3886 while (*s) |
3813 { | 3887 { |
3814 const char_t* prev = s; | 3888 const char_t* prev = s; |
3815 | 3889 |
3816 // While *s is a usual symbol | 3890 // While *s is a usual symbol |
3817 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); | 3891 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type)); |
3818 | 3892 |
3819 writer.write_buffer(prev, static_cast<size_t>(s - prev)); | 3893 writer.write_buffer(prev, static_cast<size_t>(s - prev)); |
3820 | 3894 |
3821 switch (*s) | 3895 switch (*s) |
3822 { | 3896 { |
3823 case 0: break; | 3897 case 0: break; |
4000 writer.write_string(name); | 4074 writer.write_string(name); |
4001 | 4075 |
4002 if (node->first_attribute) | 4076 if (node->first_attribute) |
4003 node_output_attributes(writer, node, indent, indent_length, flags, depth); | 4077 node_output_attributes(writer, node, indent, indent_length, flags, depth); |
4004 | 4078 |
4005 if (!node->first_child) | 4079 // element nodes can have value if parse_embed_pcdata was used |
4006 { | 4080 if (!node->value) |
4007 writer.write(' ', '/', '>'); | 4081 { |
4008 | 4082 if (!node->first_child) |
4009 return false; | 4083 { |
4084 if (flags & format_no_empty_element_tags) | |
4085 { | |
4086 writer.write('>', '<', '/'); | |
4087 writer.write_string(name); | |
4088 writer.write('>'); | |
4089 | |
4090 return false; | |
4091 } | |
4092 else | |
4093 { | |
4094 if ((flags & format_raw) == 0) | |
4095 writer.write(' '); | |
4096 | |
4097 writer.write('/', '>'); | |
4098 | |
4099 return false; | |
4100 } | |
4101 } | |
4102 else | |
4103 { | |
4104 writer.write('>'); | |
4105 | |
4106 return true; | |
4107 } | |
4010 } | 4108 } |
4011 else | 4109 else |
4012 { | 4110 { |
4013 writer.write('>'); | 4111 writer.write('>'); |
4014 | 4112 |
4015 return true; | 4113 text_output(writer, node->value, ctx_special_pcdata, flags); |
4114 | |
4115 if (!node->first_child) | |
4116 { | |
4117 writer.write('<', '/'); | |
4118 writer.write_string(name); | |
4119 writer.write('>'); | |
4120 | |
4121 return false; | |
4122 } | |
4123 else | |
4124 { | |
4125 return true; | |
4126 } | |
4016 } | 4127 } |
4017 } | 4128 } |
4018 | 4129 |
4019 PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) | 4130 PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node) |
4020 { | 4131 { |
4076 | 4187 |
4077 writer.write('>'); | 4188 writer.write('>'); |
4078 break; | 4189 break; |
4079 | 4190 |
4080 default: | 4191 default: |
4081 assert(!"Invalid node type"); | 4192 assert(false && "Invalid node type"); |
4082 } | 4193 } |
4083 } | 4194 } |
4084 | 4195 |
4085 enum indent_flags_t | 4196 enum indent_flags_t |
4086 { | 4197 { |
4118 { | 4229 { |
4119 indent_flags = indent_newline | indent_indent; | 4230 indent_flags = indent_newline | indent_indent; |
4120 | 4231 |
4121 if (node_output_start(writer, node, indent, indent_length, flags, depth)) | 4232 if (node_output_start(writer, node, indent, indent_length, flags, depth)) |
4122 { | 4233 { |
4234 // element nodes can have value if parse_embed_pcdata was used | |
4235 if (node->value) | |
4236 indent_flags = 0; | |
4237 | |
4123 node = node->first_child; | 4238 node = node->first_child; |
4124 depth++; | 4239 depth++; |
4125 continue; | 4240 continue; |
4126 } | 4241 } |
4127 } | 4242 } |
4458 { | 4573 { |
4459 return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX); | 4574 return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX); |
4460 } | 4575 } |
4461 #endif | 4576 #endif |
4462 | 4577 |
4463 template <typename U> | 4578 template <typename U> PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) |
4464 PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative) | |
4465 { | 4579 { |
4466 char_t* result = end - 1; | 4580 char_t* result = end - 1; |
4467 U rest = negative ? 0 - value : value; | 4581 U rest = negative ? 0 - value : value; |
4468 | 4582 |
4469 do | 4583 do |
4496 #else | 4610 #else |
4497 return strcpy_insitu(dest, header, header_mask, buf, strlen(buf)); | 4611 return strcpy_insitu(dest, header, header_mask, buf, strlen(buf)); |
4498 #endif | 4612 #endif |
4499 } | 4613 } |
4500 | 4614 |
4501 template <typename String, typename Header> | 4615 template <typename U, typename String, typename Header> |
4502 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, int value) | 4616 PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative) |
4503 { | 4617 { |
4504 char_t buf[64]; | 4618 char_t buf[64]; |
4505 char_t* end = buf + sizeof(buf) / sizeof(buf[0]); | 4619 char_t* end = buf + sizeof(buf) / sizeof(buf[0]); |
4506 char_t* begin = integer_to_string<unsigned int>(buf, end, value, value < 0); | 4620 char_t* begin = integer_to_string(buf, end, value, negative); |
4507 | |
4508 return strcpy_insitu(dest, header, header_mask, begin, end - begin); | |
4509 } | |
4510 | |
4511 template <typename String, typename Header> | |
4512 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned int value) | |
4513 { | |
4514 char_t buf[64]; | |
4515 char_t* end = buf + sizeof(buf) / sizeof(buf[0]); | |
4516 char_t* begin = integer_to_string<unsigned int>(buf, end, value, false); | |
4517 | 4621 |
4518 return strcpy_insitu(dest, header, header_mask, begin, end - begin); | 4622 return strcpy_insitu(dest, header, header_mask, begin, end - begin); |
4519 } | 4623 } |
4520 | 4624 |
4521 template <typename String, typename Header> | 4625 template <typename String, typename Header> |
4533 char buf[128]; | 4637 char buf[128]; |
4534 sprintf(buf, "%.17g", value); | 4638 sprintf(buf, "%.17g", value); |
4535 | 4639 |
4536 return set_value_ascii(dest, header, header_mask, buf); | 4640 return set_value_ascii(dest, header, header_mask, buf); |
4537 } | 4641 } |
4538 | 4642 |
4539 template <typename String, typename Header> | 4643 template <typename String, typename Header> |
4540 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, bool value) | 4644 PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value) |
4541 { | 4645 { |
4542 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); | 4646 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5); |
4543 } | 4647 } |
4544 | |
4545 #ifdef PUGIXML_HAS_LONG_LONG | |
4546 template <typename String, typename Header> | |
4547 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, long long value) | |
4548 { | |
4549 char_t buf[64]; | |
4550 char_t* end = buf + sizeof(buf) / sizeof(buf[0]); | |
4551 char_t* begin = integer_to_string<unsigned long long>(buf, end, value, value < 0); | |
4552 | |
4553 return strcpy_insitu(dest, header, header_mask, begin, end - begin); | |
4554 } | |
4555 | |
4556 template <typename String, typename Header> | |
4557 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned long long value) | |
4558 { | |
4559 char_t buf[64]; | |
4560 char_t* end = buf + sizeof(buf) / sizeof(buf[0]); | |
4561 char_t* begin = integer_to_string<unsigned long long>(buf, end, value, false); | |
4562 | |
4563 return strcpy_insitu(dest, header, header_mask, begin, end - begin); | |
4564 } | |
4565 #endif | |
4566 | 4648 |
4567 PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) | 4649 PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer) |
4568 { | 4650 { |
4569 // check input buffer | 4651 // check input buffer |
4570 if (!contents && size) return make_parse_result(status_io_error); | 4652 if (!contents && size) return make_parse_result(status_io_error); |
4622 fseek(file, 0, SEEK_SET); | 4704 fseek(file, 0, SEEK_SET); |
4623 #endif | 4705 #endif |
4624 | 4706 |
4625 // check for I/O errors | 4707 // check for I/O errors |
4626 if (length < 0) return status_io_error; | 4708 if (length < 0) return status_io_error; |
4627 | 4709 |
4628 // check for overflow | 4710 // check for overflow |
4629 size_t result = static_cast<size_t>(length); | 4711 size_t result = static_cast<size_t>(length); |
4630 | 4712 |
4631 if (static_cast<length_type>(result) != length) return status_out_of_memory; | 4713 if (static_cast<length_type>(result) != length) return status_out_of_memory; |
4632 | 4714 |
4635 | 4717 |
4636 return status_ok; | 4718 return status_ok; |
4637 } | 4719 } |
4638 | 4720 |
4639 // This function assumes that buffer has extra sizeof(char_t) writable bytes after size | 4721 // This function assumes that buffer has extra sizeof(char_t) writable bytes after size |
4640 PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) | 4722 PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) |
4641 { | 4723 { |
4642 // We only need to zero-terminate if encoding conversion does not do it for us | 4724 // We only need to zero-terminate if encoding conversion does not do it for us |
4643 #ifdef PUGIXML_WCHAR_MODE | 4725 #ifdef PUGIXML_WCHAR_MODE |
4644 xml_encoding wchar_encoding = get_wchar_encoding(); | 4726 xml_encoding wchar_encoding = get_wchar_encoding(); |
4645 | 4727 |
4667 | 4749 |
4668 // get file size (can result in I/O errors) | 4750 // get file size (can result in I/O errors) |
4669 size_t size = 0; | 4751 size_t size = 0; |
4670 xml_parse_status size_status = get_file_size(file, size); | 4752 xml_parse_status size_status = get_file_size(file, size); |
4671 if (size_status != status_ok) return make_parse_result(size_status); | 4753 if (size_status != status_ok) return make_parse_result(size_status); |
4672 | 4754 |
4673 size_t max_suffix_size = sizeof(char_t); | 4755 size_t max_suffix_size = sizeof(char_t); |
4674 | 4756 |
4675 // allocate buffer for the whole file | 4757 // allocate buffer for the whole file |
4676 char* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size)); | 4758 char* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size)); |
4677 if (!contents) return make_parse_result(status_out_of_memory); | 4759 if (!contents) return make_parse_result(status_out_of_memory); |
4688 xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size); | 4770 xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size); |
4689 | 4771 |
4690 return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer); | 4772 return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer); |
4691 } | 4773 } |
4692 | 4774 |
4775 PUGI__FN void close_file(FILE* file) | |
4776 { | |
4777 fclose(file); | |
4778 } | |
4779 | |
4693 #ifndef PUGIXML_NO_STL | 4780 #ifndef PUGIXML_NO_STL |
4694 template <typename T> struct xml_stream_chunk | 4781 template <typename T> struct xml_stream_chunk |
4695 { | 4782 { |
4696 static xml_stream_chunk* create() | 4783 static xml_stream_chunk* create() |
4697 { | 4784 { |
4698 void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); | 4785 void* memory = xml_memory::allocate(sizeof(xml_stream_chunk)); |
4699 if (!memory) return 0; | 4786 if (!memory) return 0; |
4700 | 4787 |
4701 return new (memory) xml_stream_chunk(); | 4788 return new (memory) xml_stream_chunk(); |
4702 } | 4789 } |
4703 | 4790 |
4704 static void destroy(xml_stream_chunk* chunk) | 4791 static void destroy(xml_stream_chunk* chunk) |
4705 { | 4792 { |
4805 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; | 4892 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error; |
4806 | 4893 |
4807 // return buffer | 4894 // return buffer |
4808 size_t actual_length = static_cast<size_t>(stream.gcount()); | 4895 size_t actual_length = static_cast<size_t>(stream.gcount()); |
4809 assert(actual_length <= read_length); | 4896 assert(actual_length <= read_length); |
4810 | 4897 |
4811 *out_buffer = buffer.release(); | 4898 *out_buffer = buffer.release(); |
4812 *out_size = actual_length * sizeof(T); | 4899 *out_size = actual_length * sizeof(T); |
4813 | 4900 |
4814 return status_ok; | 4901 return status_ok; |
4815 } | 4902 } |
4833 status = load_stream_data_seek(stream, &buffer, &size); | 4920 status = load_stream_data_seek(stream, &buffer, &size); |
4834 | 4921 |
4835 if (status != status_ok) return make_parse_result(status); | 4922 if (status != status_ok) return make_parse_result(status); |
4836 | 4923 |
4837 xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); | 4924 xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size); |
4838 | 4925 |
4839 return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer); | 4926 return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer); |
4840 } | 4927 } |
4841 #endif | 4928 #endif |
4842 | 4929 |
4843 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) | 4930 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))) |
4953 #endif | 5040 #endif |
4954 | 5041 |
4955 PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) | 5042 PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0) |
4956 { | 5043 { |
4957 } | 5044 } |
4958 | 5045 |
4959 PUGI__FN xml_tree_walker::~xml_tree_walker() | 5046 PUGI__FN xml_tree_walker::~xml_tree_walker() |
4960 { | 5047 { |
4961 } | 5048 } |
4962 | 5049 |
4963 PUGI__FN int xml_tree_walker::depth() const | 5050 PUGI__FN int xml_tree_walker::depth() const |
4999 | 5086 |
5000 PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const | 5087 PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const |
5001 { | 5088 { |
5002 return (_attr == r._attr); | 5089 return (_attr == r._attr); |
5003 } | 5090 } |
5004 | 5091 |
5005 PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const | 5092 PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const |
5006 { | 5093 { |
5007 return (_attr != r._attr); | 5094 return (_attr != r._attr); |
5008 } | 5095 } |
5009 | 5096 |
5010 PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const | 5097 PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const |
5011 { | 5098 { |
5012 return (_attr < r._attr); | 5099 return (_attr < r._attr); |
5013 } | 5100 } |
5014 | 5101 |
5015 PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const | 5102 PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const |
5016 { | 5103 { |
5017 return (_attr > r._attr); | 5104 return (_attr > r._attr); |
5018 } | 5105 } |
5019 | 5106 |
5020 PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const | 5107 PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const |
5021 { | 5108 { |
5022 return (_attr <= r._attr); | 5109 return (_attr <= r._attr); |
5023 } | 5110 } |
5024 | 5111 |
5025 PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const | 5112 PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const |
5026 { | 5113 { |
5027 return (_attr >= r._attr); | 5114 return (_attr >= r._attr); |
5028 } | 5115 } |
5029 | 5116 |
5107 PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) | 5194 PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs) |
5108 { | 5195 { |
5109 set_value(rhs); | 5196 set_value(rhs); |
5110 return *this; | 5197 return *this; |
5111 } | 5198 } |
5112 | 5199 |
5113 PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) | 5200 PUGI__FN xml_attribute& xml_attribute::operator=(int rhs) |
5114 { | 5201 { |
5115 set_value(rhs); | 5202 set_value(rhs); |
5116 return *this; | 5203 return *this; |
5117 } | 5204 } |
5120 { | 5207 { |
5121 set_value(rhs); | 5208 set_value(rhs); |
5122 return *this; | 5209 return *this; |
5123 } | 5210 } |
5124 | 5211 |
5125 PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) | 5212 PUGI__FN xml_attribute& xml_attribute::operator=(long rhs) |
5126 { | 5213 { |
5127 set_value(rhs); | 5214 set_value(rhs); |
5128 return *this; | 5215 return *this; |
5129 } | 5216 } |
5130 | 5217 |
5131 PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) | 5218 PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs) |
5132 { | 5219 { |
5133 set_value(rhs); | 5220 set_value(rhs); |
5134 return *this; | 5221 return *this; |
5135 } | 5222 } |
5136 | 5223 |
5137 PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) | 5224 PUGI__FN xml_attribute& xml_attribute::operator=(double rhs) |
5138 { | 5225 { |
5139 set_value(rhs); | 5226 set_value(rhs); |
5140 return *this; | 5227 return *this; |
5141 } | 5228 } |
5142 | 5229 |
5230 PUGI__FN xml_attribute& xml_attribute::operator=(float rhs) | |
5231 { | |
5232 set_value(rhs); | |
5233 return *this; | |
5234 } | |
5235 | |
5236 PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs) | |
5237 { | |
5238 set_value(rhs); | |
5239 return *this; | |
5240 } | |
5241 | |
5143 #ifdef PUGIXML_HAS_LONG_LONG | 5242 #ifdef PUGIXML_HAS_LONG_LONG |
5144 PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs) | 5243 PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs) |
5145 { | 5244 { |
5146 set_value(rhs); | 5245 set_value(rhs); |
5147 return *this; | 5246 return *this; |
5155 #endif | 5254 #endif |
5156 | 5255 |
5157 PUGI__FN bool xml_attribute::set_name(const char_t* rhs) | 5256 PUGI__FN bool xml_attribute::set_name(const char_t* rhs) |
5158 { | 5257 { |
5159 if (!_attr) return false; | 5258 if (!_attr) return false; |
5160 | 5259 |
5161 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); | 5260 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); |
5162 } | 5261 } |
5163 | 5262 |
5164 PUGI__FN bool xml_attribute::set_value(const char_t* rhs) | 5263 PUGI__FN bool xml_attribute::set_value(const char_t* rhs) |
5165 { | 5264 { |
5166 if (!_attr) return false; | 5265 if (!_attr) return false; |
5167 | 5266 |
5168 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); | 5267 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)); |
5170 | 5269 |
5171 PUGI__FN bool xml_attribute::set_value(int rhs) | 5270 PUGI__FN bool xml_attribute::set_value(int rhs) |
5172 { | 5271 { |
5173 if (!_attr) return false; | 5272 if (!_attr) return false; |
5174 | 5273 |
5274 return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); | |
5275 } | |
5276 | |
5277 PUGI__FN bool xml_attribute::set_value(unsigned int rhs) | |
5278 { | |
5279 if (!_attr) return false; | |
5280 | |
5281 return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); | |
5282 } | |
5283 | |
5284 PUGI__FN bool xml_attribute::set_value(long rhs) | |
5285 { | |
5286 if (!_attr) return false; | |
5287 | |
5288 return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); | |
5289 } | |
5290 | |
5291 PUGI__FN bool xml_attribute::set_value(unsigned long rhs) | |
5292 { | |
5293 if (!_attr) return false; | |
5294 | |
5295 return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); | |
5296 } | |
5297 | |
5298 PUGI__FN bool xml_attribute::set_value(double rhs) | |
5299 { | |
5300 if (!_attr) return false; | |
5301 | |
5175 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); | 5302 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); |
5176 } | 5303 } |
5177 | 5304 |
5178 PUGI__FN bool xml_attribute::set_value(unsigned int rhs) | 5305 PUGI__FN bool xml_attribute::set_value(float rhs) |
5179 { | 5306 { |
5180 if (!_attr) return false; | 5307 if (!_attr) return false; |
5181 | 5308 |
5182 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); | 5309 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); |
5183 } | 5310 } |
5184 | 5311 |
5185 PUGI__FN bool xml_attribute::set_value(double rhs) | 5312 PUGI__FN bool xml_attribute::set_value(bool rhs) |
5186 { | 5313 { |
5187 if (!_attr) return false; | 5314 if (!_attr) return false; |
5188 | 5315 |
5189 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); | 5316 return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); |
5190 } | |
5191 | |
5192 PUGI__FN bool xml_attribute::set_value(float rhs) | |
5193 { | |
5194 if (!_attr) return false; | |
5195 | |
5196 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); | |
5197 } | |
5198 | |
5199 PUGI__FN bool xml_attribute::set_value(bool rhs) | |
5200 { | |
5201 if (!_attr) return false; | |
5202 | |
5203 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); | |
5204 } | 5317 } |
5205 | 5318 |
5206 #ifdef PUGIXML_HAS_LONG_LONG | 5319 #ifdef PUGIXML_HAS_LONG_LONG |
5207 PUGI__FN bool xml_attribute::set_value(long long rhs) | 5320 PUGI__FN bool xml_attribute::set_value(long long rhs) |
5208 { | 5321 { |
5209 if (!_attr) return false; | 5322 if (!_attr) return false; |
5210 | 5323 |
5211 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); | 5324 return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0); |
5212 } | 5325 } |
5213 | 5326 |
5214 PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) | 5327 PUGI__FN bool xml_attribute::set_value(unsigned long long rhs) |
5215 { | 5328 { |
5216 if (!_attr) return false; | 5329 if (!_attr) return false; |
5217 | 5330 |
5218 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs); | 5331 return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false); |
5219 } | 5332 } |
5220 #endif | 5333 #endif |
5221 | 5334 |
5222 #ifdef __BORLANDC__ | 5335 #ifdef __BORLANDC__ |
5223 PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) | 5336 PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs) |
5236 } | 5349 } |
5237 | 5350 |
5238 PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) | 5351 PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p) |
5239 { | 5352 { |
5240 } | 5353 } |
5241 | 5354 |
5242 PUGI__FN static void unspecified_bool_xml_node(xml_node***) | 5355 PUGI__FN static void unspecified_bool_xml_node(xml_node***) |
5243 { | 5356 { |
5244 } | 5357 } |
5245 | 5358 |
5246 PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const | 5359 PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const |
5260 | 5373 |
5261 PUGI__FN xml_node::iterator xml_node::end() const | 5374 PUGI__FN xml_node::iterator xml_node::end() const |
5262 { | 5375 { |
5263 return iterator(0, _root); | 5376 return iterator(0, _root); |
5264 } | 5377 } |
5265 | 5378 |
5266 PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const | 5379 PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const |
5267 { | 5380 { |
5268 return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root); | 5381 return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root); |
5269 } | 5382 } |
5270 | 5383 |
5271 PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const | 5384 PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const |
5272 { | 5385 { |
5273 return attribute_iterator(0, _root); | 5386 return attribute_iterator(0, _root); |
5274 } | 5387 } |
5275 | 5388 |
5276 PUGI__FN xml_object_range<xml_node_iterator> xml_node::children() const | 5389 PUGI__FN xml_object_range<xml_node_iterator> xml_node::children() const |
5277 { | 5390 { |
5278 return xml_object_range<xml_node_iterator>(begin(), end()); | 5391 return xml_object_range<xml_node_iterator>(begin(), end()); |
5279 } | 5392 } |
5280 | 5393 |
5300 | 5413 |
5301 PUGI__FN bool xml_node::operator<(const xml_node& r) const | 5414 PUGI__FN bool xml_node::operator<(const xml_node& r) const |
5302 { | 5415 { |
5303 return (_root < r._root); | 5416 return (_root < r._root); |
5304 } | 5417 } |
5305 | 5418 |
5306 PUGI__FN bool xml_node::operator>(const xml_node& r) const | 5419 PUGI__FN bool xml_node::operator>(const xml_node& r) const |
5307 { | 5420 { |
5308 return (_root > r._root); | 5421 return (_root > r._root); |
5309 } | 5422 } |
5310 | 5423 |
5311 PUGI__FN bool xml_node::operator<=(const xml_node& r) const | 5424 PUGI__FN bool xml_node::operator<=(const xml_node& r) const |
5312 { | 5425 { |
5313 return (_root <= r._root); | 5426 return (_root <= r._root); |
5314 } | 5427 } |
5315 | 5428 |
5316 PUGI__FN bool xml_node::operator>=(const xml_node& r) const | 5429 PUGI__FN bool xml_node::operator>=(const xml_node& r) const |
5317 { | 5430 { |
5318 return (_root >= r._root); | 5431 return (_root >= r._root); |
5319 } | 5432 } |
5320 | 5433 |
5321 PUGI__FN bool xml_node::empty() const | 5434 PUGI__FN bool xml_node::empty() const |
5322 { | 5435 { |
5323 return !_root; | 5436 return !_root; |
5324 } | 5437 } |
5325 | 5438 |
5326 PUGI__FN const char_t* xml_node::name() const | 5439 PUGI__FN const char_t* xml_node::name() const |
5327 { | 5440 { |
5328 return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); | 5441 return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); |
5329 } | 5442 } |
5330 | 5443 |
5331 PUGI__FN xml_node_type xml_node::type() const | 5444 PUGI__FN xml_node_type xml_node::type() const |
5332 { | 5445 { |
5333 return _root ? PUGI__NODETYPE(_root) : node_null; | 5446 return _root ? PUGI__NODETYPE(_root) : node_null; |
5334 } | 5447 } |
5335 | 5448 |
5336 PUGI__FN const char_t* xml_node::value() const | 5449 PUGI__FN const char_t* xml_node::value() const |
5337 { | 5450 { |
5338 return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); | 5451 return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); |
5339 } | 5452 } |
5340 | 5453 |
5341 PUGI__FN xml_node xml_node::child(const char_t* name_) const | 5454 PUGI__FN xml_node xml_node::child(const char_t* name_) const |
5342 { | 5455 { |
5343 if (!_root) return xml_node(); | 5456 if (!_root) return xml_node(); |
5344 | 5457 |
5345 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) | 5458 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) |
5353 if (!_root) return xml_attribute(); | 5466 if (!_root) return xml_attribute(); |
5354 | 5467 |
5355 for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) | 5468 for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) |
5356 if (i->name && impl::strequal(name_, i->name)) | 5469 if (i->name && impl::strequal(name_, i->name)) |
5357 return xml_attribute(i); | 5470 return xml_attribute(i); |
5358 | 5471 |
5359 return xml_attribute(); | 5472 return xml_attribute(); |
5360 } | 5473 } |
5361 | 5474 |
5362 PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const | 5475 PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const |
5363 { | 5476 { |
5364 if (!_root) return xml_node(); | 5477 if (!_root) return xml_node(); |
5365 | 5478 |
5366 for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) | 5479 for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) |
5367 if (i->name && impl::strequal(name_, i->name)) return xml_node(i); | 5480 if (i->name && impl::strequal(name_, i->name)) return xml_node(i); |
5368 | 5481 |
5369 return xml_node(); | 5482 return xml_node(); |
5370 } | 5483 } |
5375 } | 5488 } |
5376 | 5489 |
5377 PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const | 5490 PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const |
5378 { | 5491 { |
5379 if (!_root) return xml_node(); | 5492 if (!_root) return xml_node(); |
5380 | 5493 |
5381 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) | 5494 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) |
5382 if (i->name && impl::strequal(name_, i->name)) return xml_node(i); | 5495 if (i->name && impl::strequal(name_, i->name)) return xml_node(i); |
5383 | 5496 |
5384 return xml_node(); | 5497 return xml_node(); |
5385 } | 5498 } |
5418 } | 5531 } |
5419 | 5532 |
5420 PUGI__FN xml_node xml_node::previous_sibling() const | 5533 PUGI__FN xml_node xml_node::previous_sibling() const |
5421 { | 5534 { |
5422 if (!_root) return xml_node(); | 5535 if (!_root) return xml_node(); |
5423 | 5536 |
5424 if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); | 5537 if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); |
5425 else return xml_node(); | 5538 else return xml_node(); |
5426 } | 5539 } |
5427 | 5540 |
5428 PUGI__FN xml_node xml_node::parent() const | 5541 PUGI__FN xml_node xml_node::parent() const |
5441 } | 5554 } |
5442 | 5555 |
5443 PUGI__FN const char_t* xml_node::child_value() const | 5556 PUGI__FN const char_t* xml_node::child_value() const |
5444 { | 5557 { |
5445 if (!_root) return PUGIXML_TEXT(""); | 5558 if (!_root) return PUGIXML_TEXT(""); |
5446 | 5559 |
5560 // element nodes can have value if parse_embed_pcdata was used | |
5561 if (PUGI__NODETYPE(_root) == node_element && _root->value) | |
5562 return _root->value; | |
5563 | |
5447 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) | 5564 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) |
5448 if (impl::is_text_node(i) && i->value) | 5565 if (impl::is_text_node(i) && i->value) |
5449 return i->value; | 5566 return i->value; |
5450 | 5567 |
5451 return PUGIXML_TEXT(""); | 5568 return PUGIXML_TEXT(""); |
5483 if (type_ != node_element && type_ != node_pi && type_ != node_declaration) | 5600 if (type_ != node_element && type_ != node_pi && type_ != node_declaration) |
5484 return false; | 5601 return false; |
5485 | 5602 |
5486 return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); | 5603 return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); |
5487 } | 5604 } |
5488 | 5605 |
5489 PUGI__FN bool xml_node::set_value(const char_t* rhs) | 5606 PUGI__FN bool xml_node::set_value(const char_t* rhs) |
5490 { | 5607 { |
5491 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; | 5608 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; |
5492 | 5609 |
5493 if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) | 5610 if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) |
5497 } | 5614 } |
5498 | 5615 |
5499 PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) | 5616 PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_) |
5500 { | 5617 { |
5501 if (!impl::allow_insert_attribute(type())) return xml_attribute(); | 5618 if (!impl::allow_insert_attribute(type())) return xml_attribute(); |
5502 | 5619 |
5503 impl::xml_allocator& alloc = impl::get_allocator(_root); | 5620 impl::xml_allocator& alloc = impl::get_allocator(_root); |
5504 if (!alloc.reserve()) return xml_attribute(); | 5621 if (!alloc.reserve()) return xml_attribute(); |
5505 | 5622 |
5506 xml_attribute a(impl::allocate_attribute(alloc)); | 5623 xml_attribute a(impl::allocate_attribute(alloc)); |
5507 if (!a) return xml_attribute(); | 5624 if (!a) return xml_attribute(); |
5508 | 5625 |
5509 impl::append_attribute(a._attr, _root); | 5626 impl::append_attribute(a._attr, _root); |
5510 | 5627 |
5511 a.set_name(name_); | 5628 a.set_name(name_); |
5512 | 5629 |
5513 return a; | 5630 return a; |
5514 } | 5631 } |
5515 | 5632 |
5516 PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) | 5633 PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_) |
5517 { | 5634 { |
5518 if (!impl::allow_insert_attribute(type())) return xml_attribute(); | 5635 if (!impl::allow_insert_attribute(type())) return xml_attribute(); |
5519 | 5636 |
5520 impl::xml_allocator& alloc = impl::get_allocator(_root); | 5637 impl::xml_allocator& alloc = impl::get_allocator(_root); |
5521 if (!alloc.reserve()) return xml_attribute(); | 5638 if (!alloc.reserve()) return xml_attribute(); |
5522 | 5639 |
5523 xml_attribute a(impl::allocate_attribute(alloc)); | 5640 xml_attribute a(impl::allocate_attribute(alloc)); |
5524 if (!a) return xml_attribute(); | 5641 if (!a) return xml_attribute(); |
5532 | 5649 |
5533 PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) | 5650 PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr) |
5534 { | 5651 { |
5535 if (!impl::allow_insert_attribute(type())) return xml_attribute(); | 5652 if (!impl::allow_insert_attribute(type())) return xml_attribute(); |
5536 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); | 5653 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); |
5537 | 5654 |
5538 impl::xml_allocator& alloc = impl::get_allocator(_root); | 5655 impl::xml_allocator& alloc = impl::get_allocator(_root); |
5539 if (!alloc.reserve()) return xml_attribute(); | 5656 if (!alloc.reserve()) return xml_attribute(); |
5540 | 5657 |
5541 xml_attribute a(impl::allocate_attribute(alloc)); | 5658 xml_attribute a(impl::allocate_attribute(alloc)); |
5542 if (!a) return xml_attribute(); | 5659 if (!a) return xml_attribute(); |
5550 | 5667 |
5551 PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) | 5668 PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr) |
5552 { | 5669 { |
5553 if (!impl::allow_insert_attribute(type())) return xml_attribute(); | 5670 if (!impl::allow_insert_attribute(type())) return xml_attribute(); |
5554 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); | 5671 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute(); |
5555 | 5672 |
5556 impl::xml_allocator& alloc = impl::get_allocator(_root); | 5673 impl::xml_allocator& alloc = impl::get_allocator(_root); |
5557 if (!alloc.reserve()) return xml_attribute(); | 5674 if (!alloc.reserve()) return xml_attribute(); |
5558 | 5675 |
5559 xml_attribute a(impl::allocate_attribute(alloc)); | 5676 xml_attribute a(impl::allocate_attribute(alloc)); |
5560 if (!a) return xml_attribute(); | 5677 if (!a) return xml_attribute(); |
5637 } | 5754 } |
5638 | 5755 |
5639 PUGI__FN xml_node xml_node::append_child(xml_node_type type_) | 5756 PUGI__FN xml_node xml_node::append_child(xml_node_type type_) |
5640 { | 5757 { |
5641 if (!impl::allow_insert_child(type(), type_)) return xml_node(); | 5758 if (!impl::allow_insert_child(type(), type_)) return xml_node(); |
5642 | 5759 |
5643 impl::xml_allocator& alloc = impl::get_allocator(_root); | 5760 impl::xml_allocator& alloc = impl::get_allocator(_root); |
5644 if (!alloc.reserve()) return xml_node(); | 5761 if (!alloc.reserve()) return xml_node(); |
5645 | 5762 |
5646 xml_node n(impl::allocate_node(alloc, type_)); | 5763 xml_node n(impl::allocate_node(alloc, type_)); |
5647 if (!n) return xml_node(); | 5764 if (!n) return xml_node(); |
5657 { | 5774 { |
5658 if (!impl::allow_insert_child(type(), type_)) return xml_node(); | 5775 if (!impl::allow_insert_child(type(), type_)) return xml_node(); |
5659 | 5776 |
5660 impl::xml_allocator& alloc = impl::get_allocator(_root); | 5777 impl::xml_allocator& alloc = impl::get_allocator(_root); |
5661 if (!alloc.reserve()) return xml_node(); | 5778 if (!alloc.reserve()) return xml_node(); |
5662 | 5779 |
5663 xml_node n(impl::allocate_node(alloc, type_)); | 5780 xml_node n(impl::allocate_node(alloc, type_)); |
5664 if (!n) return xml_node(); | 5781 if (!n) return xml_node(); |
5665 | 5782 |
5666 impl::prepend_node(n._root, _root); | 5783 impl::prepend_node(n._root, _root); |
5667 | 5784 |
5668 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); | 5785 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml")); |
5669 | 5786 |
5670 return n; | 5787 return n; |
5671 } | 5788 } |
5672 | 5789 |
5675 if (!impl::allow_insert_child(type(), type_)) return xml_node(); | 5792 if (!impl::allow_insert_child(type(), type_)) return xml_node(); |
5676 if (!node._root || node._root->parent != _root) return xml_node(); | 5793 if (!node._root || node._root->parent != _root) return xml_node(); |
5677 | 5794 |
5678 impl::xml_allocator& alloc = impl::get_allocator(_root); | 5795 impl::xml_allocator& alloc = impl::get_allocator(_root); |
5679 if (!alloc.reserve()) return xml_node(); | 5796 if (!alloc.reserve()) return xml_node(); |
5680 | 5797 |
5681 xml_node n(impl::allocate_node(alloc, type_)); | 5798 xml_node n(impl::allocate_node(alloc, type_)); |
5682 if (!n) return xml_node(); | 5799 if (!n) return xml_node(); |
5683 | 5800 |
5684 impl::insert_node_before(n._root, node._root); | 5801 impl::insert_node_before(n._root, node._root); |
5685 | 5802 |
5693 if (!impl::allow_insert_child(type(), type_)) return xml_node(); | 5810 if (!impl::allow_insert_child(type(), type_)) return xml_node(); |
5694 if (!node._root || node._root->parent != _root) return xml_node(); | 5811 if (!node._root || node._root->parent != _root) return xml_node(); |
5695 | 5812 |
5696 impl::xml_allocator& alloc = impl::get_allocator(_root); | 5813 impl::xml_allocator& alloc = impl::get_allocator(_root); |
5697 if (!alloc.reserve()) return xml_node(); | 5814 if (!alloc.reserve()) return xml_node(); |
5698 | 5815 |
5699 xml_node n(impl::allocate_node(alloc, type_)); | 5816 xml_node n(impl::allocate_node(alloc, type_)); |
5700 if (!n) return xml_node(); | 5817 if (!n) return xml_node(); |
5701 | 5818 |
5702 impl::insert_node_after(n._root, node._root); | 5819 impl::insert_node_after(n._root, node._root); |
5703 | 5820 |
5925 // get document node | 6042 // get document node |
5926 impl::xml_document_struct* doc = &impl::get_document(_root); | 6043 impl::xml_document_struct* doc = &impl::get_document(_root); |
5927 | 6044 |
5928 // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense | 6045 // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense |
5929 doc->header |= impl::xml_memory_page_contents_shared_mask; | 6046 doc->header |= impl::xml_memory_page_contents_shared_mask; |
5930 | 6047 |
5931 // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) | 6048 // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later) |
5932 impl::xml_memory_page* page = 0; | 6049 impl::xml_memory_page* page = 0; |
5933 impl::xml_extra_buffer* extra = static_cast<impl::xml_extra_buffer*>(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page)); | 6050 impl::xml_extra_buffer* extra = static_cast<impl::xml_extra_buffer*>(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page)); |
5934 (void)page; | 6051 (void)page; |
5935 | 6052 |
5947 } | 6064 } |
5948 | 6065 |
5949 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const | 6066 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const |
5950 { | 6067 { |
5951 if (!_root) return xml_node(); | 6068 if (!_root) return xml_node(); |
5952 | 6069 |
5953 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) | 6070 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) |
5954 if (i->name && impl::strequal(name_, i->name)) | 6071 if (i->name && impl::strequal(name_, i->name)) |
5955 { | 6072 { |
5956 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) | 6073 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) |
5957 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) | 6074 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) |
5962 } | 6079 } |
5963 | 6080 |
5964 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const | 6081 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const |
5965 { | 6082 { |
5966 if (!_root) return xml_node(); | 6083 if (!_root) return xml_node(); |
5967 | 6084 |
5968 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) | 6085 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) |
5969 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) | 6086 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) |
5970 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) | 6087 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) |
5971 return xml_node(i); | 6088 return xml_node(i); |
5972 | 6089 |
6057 } | 6174 } |
6058 | 6175 |
6059 PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) | 6176 PUGI__FN bool xml_node::traverse(xml_tree_walker& walker) |
6060 { | 6177 { |
6061 walker._depth = -1; | 6178 walker._depth = -1; |
6062 | 6179 |
6063 xml_node arg_begin = *this; | 6180 xml_node arg_begin = *this; |
6064 if (!walker.begin(arg_begin)) return false; | 6181 if (!walker.begin(arg_begin)) return false; |
6065 | 6182 |
6066 xml_node cur = first_child(); | 6183 xml_node cur = first_child(); |
6067 | 6184 |
6068 if (cur) | 6185 if (cur) |
6069 { | 6186 { |
6070 ++walker._depth; | 6187 ++walker._depth; |
6071 | 6188 |
6072 do | 6189 do |
6073 { | 6190 { |
6074 xml_node arg_for_each = cur; | 6191 xml_node arg_for_each = cur; |
6075 if (!walker.for_each(arg_for_each)) | 6192 if (!walker.for_each(arg_for_each)) |
6076 return false; | 6193 return false; |
6077 | 6194 |
6078 if (cur.first_child()) | 6195 if (cur.first_child()) |
6079 { | 6196 { |
6080 ++walker._depth; | 6197 ++walker._depth; |
6081 cur = cur.first_child(); | 6198 cur = cur.first_child(); |
6082 } | 6199 } |
6088 while (!cur.next_sibling() && cur != *this && !cur.parent().empty()) | 6205 while (!cur.next_sibling() && cur != *this && !cur.parent().empty()) |
6089 { | 6206 { |
6090 --walker._depth; | 6207 --walker._depth; |
6091 cur = cur.parent(); | 6208 cur = cur.parent(); |
6092 } | 6209 } |
6093 | 6210 |
6094 if (cur != *this) | 6211 if (cur != *this) |
6095 cur = cur.next_sibling(); | 6212 cur = cur.next_sibling(); |
6096 } | 6213 } |
6097 } | 6214 } |
6098 while (cur && cur != *this); | 6215 while (cur && cur != *this); |
6189 | 6306 |
6190 PUGI__FN xml_node_struct* xml_text::_data() const | 6307 PUGI__FN xml_node_struct* xml_text::_data() const |
6191 { | 6308 { |
6192 if (!_root || impl::is_text_node(_root)) return _root; | 6309 if (!_root || impl::is_text_node(_root)) return _root; |
6193 | 6310 |
6311 // element nodes can have value if parse_embed_pcdata was used | |
6312 if (PUGI__NODETYPE(_root) == node_element && _root->value) | |
6313 return _root; | |
6314 | |
6194 for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) | 6315 for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling) |
6195 if (impl::is_text_node(node)) | 6316 if (impl::is_text_node(node)) |
6196 return node; | 6317 return node; |
6197 | 6318 |
6198 return 0; | 6319 return 0; |
6303 | 6424 |
6304 PUGI__FN bool xml_text::set(int rhs) | 6425 PUGI__FN bool xml_text::set(int rhs) |
6305 { | 6426 { |
6306 xml_node_struct* dn = _data_new(); | 6427 xml_node_struct* dn = _data_new(); |
6307 | 6428 |
6429 return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; | |
6430 } | |
6431 | |
6432 PUGI__FN bool xml_text::set(unsigned int rhs) | |
6433 { | |
6434 xml_node_struct* dn = _data_new(); | |
6435 | |
6436 return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; | |
6437 } | |
6438 | |
6439 PUGI__FN bool xml_text::set(long rhs) | |
6440 { | |
6441 xml_node_struct* dn = _data_new(); | |
6442 | |
6443 return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; | |
6444 } | |
6445 | |
6446 PUGI__FN bool xml_text::set(unsigned long rhs) | |
6447 { | |
6448 xml_node_struct* dn = _data_new(); | |
6449 | |
6450 return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; | |
6451 } | |
6452 | |
6453 PUGI__FN bool xml_text::set(float rhs) | |
6454 { | |
6455 xml_node_struct* dn = _data_new(); | |
6456 | |
6308 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; | 6457 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; |
6309 } | 6458 } |
6310 | 6459 |
6311 PUGI__FN bool xml_text::set(unsigned int rhs) | 6460 PUGI__FN bool xml_text::set(double rhs) |
6312 { | 6461 { |
6313 xml_node_struct* dn = _data_new(); | 6462 xml_node_struct* dn = _data_new(); |
6314 | 6463 |
6315 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; | 6464 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; |
6316 } | 6465 } |
6317 | 6466 |
6318 PUGI__FN bool xml_text::set(float rhs) | 6467 PUGI__FN bool xml_text::set(bool rhs) |
6319 { | 6468 { |
6320 xml_node_struct* dn = _data_new(); | 6469 xml_node_struct* dn = _data_new(); |
6321 | 6470 |
6322 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; | 6471 return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; |
6323 } | |
6324 | |
6325 PUGI__FN bool xml_text::set(double rhs) | |
6326 { | |
6327 xml_node_struct* dn = _data_new(); | |
6328 | |
6329 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; | |
6330 } | |
6331 | |
6332 PUGI__FN bool xml_text::set(bool rhs) | |
6333 { | |
6334 xml_node_struct* dn = _data_new(); | |
6335 | |
6336 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; | |
6337 } | 6472 } |
6338 | 6473 |
6339 #ifdef PUGIXML_HAS_LONG_LONG | 6474 #ifdef PUGIXML_HAS_LONG_LONG |
6340 PUGI__FN bool xml_text::set(long long rhs) | 6475 PUGI__FN bool xml_text::set(long long rhs) |
6341 { | 6476 { |
6342 xml_node_struct* dn = _data_new(); | 6477 xml_node_struct* dn = _data_new(); |
6343 | 6478 |
6344 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; | 6479 return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false; |
6345 } | 6480 } |
6346 | 6481 |
6347 PUGI__FN bool xml_text::set(unsigned long long rhs) | 6482 PUGI__FN bool xml_text::set(unsigned long long rhs) |
6348 { | 6483 { |
6349 xml_node_struct* dn = _data_new(); | 6484 xml_node_struct* dn = _data_new(); |
6350 | 6485 |
6351 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false; | 6486 return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false; |
6352 } | 6487 } |
6353 #endif | 6488 #endif |
6354 | 6489 |
6355 PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) | 6490 PUGI__FN xml_text& xml_text::operator=(const char_t* rhs) |
6356 { | 6491 { |
6368 { | 6503 { |
6369 set(rhs); | 6504 set(rhs); |
6370 return *this; | 6505 return *this; |
6371 } | 6506 } |
6372 | 6507 |
6373 PUGI__FN xml_text& xml_text::operator=(double rhs) | 6508 PUGI__FN xml_text& xml_text::operator=(long rhs) |
6374 { | 6509 { |
6375 set(rhs); | 6510 set(rhs); |
6376 return *this; | 6511 return *this; |
6377 } | 6512 } |
6378 | 6513 |
6379 PUGI__FN xml_text& xml_text::operator=(float rhs) | 6514 PUGI__FN xml_text& xml_text::operator=(unsigned long rhs) |
6380 { | 6515 { |
6381 set(rhs); | 6516 set(rhs); |
6382 return *this; | 6517 return *this; |
6383 } | 6518 } |
6384 | 6519 |
6385 PUGI__FN xml_text& xml_text::operator=(bool rhs) | 6520 PUGI__FN xml_text& xml_text::operator=(double rhs) |
6386 { | 6521 { |
6387 set(rhs); | 6522 set(rhs); |
6388 return *this; | 6523 return *this; |
6389 } | 6524 } |
6390 | 6525 |
6526 PUGI__FN xml_text& xml_text::operator=(float rhs) | |
6527 { | |
6528 set(rhs); | |
6529 return *this; | |
6530 } | |
6531 | |
6532 PUGI__FN xml_text& xml_text::operator=(bool rhs) | |
6533 { | |
6534 set(rhs); | |
6535 return *this; | |
6536 } | |
6537 | |
6391 #ifdef PUGIXML_HAS_LONG_LONG | 6538 #ifdef PUGIXML_HAS_LONG_LONG |
6392 PUGI__FN xml_text& xml_text::operator=(long long rhs) | 6539 PUGI__FN xml_text& xml_text::operator=(long long rhs) |
6393 { | 6540 { |
6394 set(rhs); | 6541 set(rhs); |
6395 return *this; | 6542 return *this; |
6433 | 6580 |
6434 PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const | 6581 PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const |
6435 { | 6582 { |
6436 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; | 6583 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root; |
6437 } | 6584 } |
6438 | 6585 |
6439 PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const | 6586 PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const |
6440 { | 6587 { |
6441 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; | 6588 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root; |
6442 } | 6589 } |
6443 | 6590 |
6448 } | 6595 } |
6449 | 6596 |
6450 PUGI__FN xml_node* xml_node_iterator::operator->() const | 6597 PUGI__FN xml_node* xml_node_iterator::operator->() const |
6451 { | 6598 { |
6452 assert(_wrap._root); | 6599 assert(_wrap._root); |
6453 return const_cast<xml_node*>(&_wrap); // BCC32 workaround | 6600 return const_cast<xml_node*>(&_wrap); // BCC5 workaround |
6454 } | 6601 } |
6455 | 6602 |
6456 PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() | 6603 PUGI__FN const xml_node_iterator& xml_node_iterator::operator++() |
6457 { | 6604 { |
6458 assert(_wrap._root); | 6605 assert(_wrap._root); |
6494 | 6641 |
6495 PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const | 6642 PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const |
6496 { | 6643 { |
6497 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; | 6644 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root; |
6498 } | 6645 } |
6499 | 6646 |
6500 PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const | 6647 PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const |
6501 { | 6648 { |
6502 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; | 6649 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root; |
6503 } | 6650 } |
6504 | 6651 |
6509 } | 6656 } |
6510 | 6657 |
6511 PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const | 6658 PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const |
6512 { | 6659 { |
6513 assert(_wrap._attr); | 6660 assert(_wrap._attr); |
6514 return const_cast<xml_attribute*>(&_wrap); // BCC32 workaround | 6661 return const_cast<xml_attribute*>(&_wrap); // BCC5 workaround |
6515 } | 6662 } |
6516 | 6663 |
6517 PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() | 6664 PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++() |
6518 { | 6665 { |
6519 assert(_wrap._attr); | 6666 assert(_wrap._attr); |
6570 } | 6717 } |
6571 | 6718 |
6572 PUGI__FN xml_node* xml_named_node_iterator::operator->() const | 6719 PUGI__FN xml_node* xml_named_node_iterator::operator->() const |
6573 { | 6720 { |
6574 assert(_wrap._root); | 6721 assert(_wrap._root); |
6575 return const_cast<xml_node*>(&_wrap); // BCC32 workaround | 6722 return const_cast<xml_node*>(&_wrap); // BCC5 workaround |
6576 } | 6723 } |
6577 | 6724 |
6578 PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() | 6725 PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++() |
6579 { | 6726 { |
6580 assert(_wrap._root); | 6727 assert(_wrap._root); |
6651 } | 6798 } |
6652 } | 6799 } |
6653 | 6800 |
6654 PUGI__FN xml_document::xml_document(): _buffer(0) | 6801 PUGI__FN xml_document::xml_document(): _buffer(0) |
6655 { | 6802 { |
6656 create(); | 6803 _create(); |
6657 } | 6804 } |
6658 | 6805 |
6659 PUGI__FN xml_document::~xml_document() | 6806 PUGI__FN xml_document::~xml_document() |
6660 { | 6807 { |
6661 destroy(); | 6808 _destroy(); |
6662 } | 6809 } |
6663 | 6810 |
6664 PUGI__FN void xml_document::reset() | 6811 PUGI__FN void xml_document::reset() |
6665 { | 6812 { |
6666 destroy(); | 6813 _destroy(); |
6667 create(); | 6814 _create(); |
6668 } | 6815 } |
6669 | 6816 |
6670 PUGI__FN void xml_document::reset(const xml_document& proto) | 6817 PUGI__FN void xml_document::reset(const xml_document& proto) |
6671 { | 6818 { |
6672 reset(); | 6819 reset(); |
6673 | 6820 |
6674 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) | 6821 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling()) |
6675 append_copy(cur); | 6822 append_copy(cur); |
6676 } | 6823 } |
6677 | 6824 |
6678 PUGI__FN void xml_document::create() | 6825 PUGI__FN void xml_document::_create() |
6679 { | 6826 { |
6680 assert(!_root); | 6827 assert(!_root); |
6681 | 6828 |
6682 #ifdef PUGIXML_COMPACT | 6829 #ifdef PUGIXML_COMPACT |
6683 const size_t page_offset = sizeof(uint32_t); | 6830 const size_t page_offset = sizeof(uint32_t); |
6684 #else | 6831 #else |
6685 const size_t page_offset = 0; | 6832 const size_t page_offset = 0; |
6686 #endif | 6833 #endif |
6687 | 6834 |
6688 // initialize sentinel page | 6835 // initialize sentinel page |
6689 PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment - sizeof(void*) + page_offset <= sizeof(_memory)); | 6836 PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory)); |
6690 | |
6691 // align upwards to page boundary | |
6692 void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1)); | |
6693 | 6837 |
6694 // prepare page structure | 6838 // prepare page structure |
6695 impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory); | 6839 impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory); |
6696 assert(page); | 6840 assert(page); |
6697 | 6841 |
6698 page->busy_size = impl::xml_memory_page_size; | 6842 page->busy_size = impl::xml_memory_page_size; |
6699 | 6843 |
6700 // setup first page marker | 6844 // setup first page marker |
6709 _root->prev_sibling_c = _root; | 6853 _root->prev_sibling_c = _root; |
6710 | 6854 |
6711 // setup sentinel page | 6855 // setup sentinel page |
6712 page->allocator = static_cast<impl::xml_document_struct*>(_root); | 6856 page->allocator = static_cast<impl::xml_document_struct*>(_root); |
6713 | 6857 |
6858 // setup hash table pointer in allocator | |
6859 #ifdef PUGIXML_COMPACT | |
6860 page->allocator->_hash = &static_cast<impl::xml_document_struct*>(_root)->hash; | |
6861 #endif | |
6862 | |
6714 // verify the document allocation | 6863 // verify the document allocation |
6715 assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); | 6864 assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory)); |
6716 } | 6865 } |
6717 | 6866 |
6718 PUGI__FN void xml_document::destroy() | 6867 PUGI__FN void xml_document::_destroy() |
6719 { | 6868 { |
6720 assert(_root); | 6869 assert(_root); |
6721 | 6870 |
6722 // destroy static storage | 6871 // destroy static storage |
6723 if (_buffer) | 6872 if (_buffer) |
6790 PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) | 6939 PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding) |
6791 { | 6940 { |
6792 reset(); | 6941 reset(); |
6793 | 6942 |
6794 using impl::auto_deleter; // MSVC7 workaround | 6943 using impl::auto_deleter; // MSVC7 workaround |
6795 auto_deleter<FILE, int(*)(FILE*)> file(fopen(path_, "rb"), fclose); | 6944 auto_deleter<FILE> file(fopen(path_, "rb"), impl::close_file); |
6796 | 6945 |
6797 return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer); | 6946 return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer); |
6798 } | 6947 } |
6799 | 6948 |
6800 PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) | 6949 PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding) |
6801 { | 6950 { |
6802 reset(); | 6951 reset(); |
6803 | 6952 |
6804 using impl::auto_deleter; // MSVC7 workaround | 6953 using impl::auto_deleter; // MSVC7 workaround |
6805 auto_deleter<FILE, int(*)(FILE*)> file(impl::open_file_wide(path_, L"rb"), fclose); | 6954 auto_deleter<FILE> file(impl::open_file_wide(path_, L"rb"), impl::close_file); |
6806 | 6955 |
6807 return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer); | 6956 return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer); |
6808 } | 6957 } |
6809 | 6958 |
6810 PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) | 6959 PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding) |
6873 #endif | 7022 #endif |
6874 | 7023 |
6875 PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const | 7024 PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const |
6876 { | 7025 { |
6877 using impl::auto_deleter; // MSVC7 workaround | 7026 using impl::auto_deleter; // MSVC7 workaround |
6878 auto_deleter<FILE, int(*)(FILE*)> file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), fclose); | 7027 auto_deleter<FILE> file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file); |
6879 | 7028 |
6880 return impl::save_file_impl(*this, file.data, indent, flags, encoding); | 7029 return impl::save_file_impl(*this, file.data, indent, flags, encoding); |
6881 } | 7030 } |
6882 | 7031 |
6883 PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const | 7032 PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const |
6884 { | 7033 { |
6885 using impl::auto_deleter; // MSVC7 workaround | 7034 using impl::auto_deleter; // MSVC7 workaround |
6886 auto_deleter<FILE, int(*)(FILE*)> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), fclose); | 7035 auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file); |
6887 | 7036 |
6888 return impl::save_file_impl(*this, file.data, indent, flags, encoding); | 7037 return impl::save_file_impl(*this, file.data, indent, flags, encoding); |
6889 } | 7038 } |
6890 | 7039 |
6891 PUGI__FN xml_node xml_document::document_element() const | 7040 PUGI__FN xml_node xml_document::document_element() const |
6909 | 7058 |
6910 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str) | 7059 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str) |
6911 { | 7060 { |
6912 return impl::as_utf8_impl(str.c_str(), str.size()); | 7061 return impl::as_utf8_impl(str.c_str(), str.size()); |
6913 } | 7062 } |
6914 | 7063 |
6915 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str) | 7064 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str) |
6916 { | 7065 { |
6917 assert(str); | 7066 assert(str); |
6918 | 7067 |
6919 return impl::as_wide_impl(str, strlen(str)); | 7068 return impl::as_wide_impl(str, strlen(str)); |
6920 } | 7069 } |
6921 | 7070 |
6922 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str) | 7071 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str) |
6923 { | 7072 { |
6924 return impl::as_wide_impl(str.c_str(), str.size()); | 7073 return impl::as_wide_impl(str.c_str(), str.size()); |
6925 } | 7074 } |
6926 #endif | 7075 #endif |
7048 while (end - begin > 1 && *begin != *(begin + 1)) begin++; | 7197 while (end - begin > 1 && *begin != *(begin + 1)) begin++; |
7049 | 7198 |
7050 if (begin == end) return begin; | 7199 if (begin == end) return begin; |
7051 | 7200 |
7052 // last written element | 7201 // last written element |
7053 I write = begin++; | 7202 I write = begin++; |
7054 | 7203 |
7055 // merge unique elements | 7204 // merge unique elements |
7056 while (begin != end) | 7205 while (begin != end) |
7057 { | 7206 { |
7058 if (*begin != *write) | 7207 if (*begin != *write) |
7223 ; | 7372 ; |
7224 | 7373 |
7225 static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*); | 7374 static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*); |
7226 | 7375 |
7227 struct xpath_memory_block | 7376 struct xpath_memory_block |
7228 { | 7377 { |
7229 xpath_memory_block* next; | 7378 xpath_memory_block* next; |
7230 size_t capacity; | 7379 size_t capacity; |
7231 | 7380 |
7232 union | 7381 union |
7233 { | 7382 { |
7234 char data[xpath_memory_page_size]; | 7383 char data[xpath_memory_page_size]; |
7235 double alignment; | 7384 double alignment; |
7236 }; | 7385 }; |
7237 }; | 7386 }; |
7238 | 7387 |
7239 class xpath_allocator | 7388 class xpath_allocator |
7240 { | 7389 { |
7241 xpath_memory_block* _root; | 7390 xpath_memory_block* _root; |
7242 size_t _root_size; | 7391 size_t _root_size; |
7243 | 7392 |
7250 { | 7399 { |
7251 #ifdef PUGIXML_NO_EXCEPTIONS | 7400 #ifdef PUGIXML_NO_EXCEPTIONS |
7252 error_handler = 0; | 7401 error_handler = 0; |
7253 #endif | 7402 #endif |
7254 } | 7403 } |
7255 | 7404 |
7256 void* allocate_nothrow(size_t size) | 7405 void* allocate_nothrow(size_t size) |
7257 { | 7406 { |
7258 // round size up to block alignment boundary | 7407 // round size up to block alignment boundary |
7259 size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); | 7408 size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1); |
7260 | 7409 |
7273 | 7422 |
7274 size_t block_size = block_capacity + offsetof(xpath_memory_block, data); | 7423 size_t block_size = block_capacity + offsetof(xpath_memory_block, data); |
7275 | 7424 |
7276 xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size)); | 7425 xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size)); |
7277 if (!block) return 0; | 7426 if (!block) return 0; |
7278 | 7427 |
7279 block->next = _root; | 7428 block->next = _root; |
7280 block->capacity = block_capacity; | 7429 block->capacity = block_capacity; |
7281 | 7430 |
7282 _root = block; | 7431 _root = block; |
7283 _root_size = size; | 7432 _root_size = size; |
7284 | 7433 |
7285 return block->data; | 7434 return block->data; |
7286 } | 7435 } |
7287 } | 7436 } |
7288 | 7437 |
7289 void* allocate(size_t size) | 7438 void* allocate(size_t size) |
7527 | 7676 |
7528 size_t length() const | 7677 size_t length() const |
7529 { | 7678 { |
7530 return _uses_heap ? _length_heap : strlength(_buffer); | 7679 return _uses_heap ? _length_heap : strlength(_buffer); |
7531 } | 7680 } |
7532 | 7681 |
7533 char_t* data(xpath_allocator* alloc) | 7682 char_t* data(xpath_allocator* alloc) |
7534 { | 7683 { |
7535 // make private heap copy | 7684 // make private heap copy |
7536 if (!_uses_heap) | 7685 if (!_uses_heap) |
7537 { | 7686 { |
7617 case node_pcdata: | 7766 case node_pcdata: |
7618 case node_cdata: | 7767 case node_cdata: |
7619 case node_comment: | 7768 case node_comment: |
7620 case node_pi: | 7769 case node_pi: |
7621 return xpath_string::from_const(n.value()); | 7770 return xpath_string::from_const(n.value()); |
7622 | 7771 |
7623 case node_document: | 7772 case node_document: |
7624 case node_element: | 7773 case node_element: |
7625 { | 7774 { |
7626 xpath_string result; | 7775 xpath_string result; |
7627 | 7776 |
7777 // element nodes can have value if parse_embed_pcdata was used | |
7778 if (n.value()[0]) | |
7779 result.append(xpath_string::from_const(n.value()), alloc); | |
7780 | |
7628 xml_node cur = n.first_child(); | 7781 xml_node cur = n.first_child(); |
7629 | 7782 |
7630 while (cur && cur != n) | 7783 while (cur && cur != n) |
7631 { | 7784 { |
7632 if (cur.type() == node_pcdata || cur.type() == node_cdata) | 7785 if (cur.type() == node_pcdata || cur.type() == node_cdata) |
7633 result.append(xpath_string::from_const(cur.value()), alloc); | 7786 result.append(xpath_string::from_const(cur.value()), alloc); |
7634 | 7787 |
7642 cur = cur.parent(); | 7795 cur = cur.parent(); |
7643 | 7796 |
7644 if (cur != n) cur = cur.next_sibling(); | 7797 if (cur != n) cur = cur.next_sibling(); |
7645 } | 7798 } |
7646 } | 7799 } |
7647 | 7800 |
7648 return result; | 7801 return result; |
7649 } | 7802 } |
7650 | 7803 |
7651 default: | 7804 default: |
7652 return xpath_string(); | 7805 return xpath_string(); |
7653 } | 7806 } |
7654 } | 7807 } |
7655 } | 7808 } |
7656 | 7809 |
7657 PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) | 7810 PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn) |
7658 { | 7811 { |
7659 assert(ln->parent == rn->parent); | 7812 assert(ln->parent == rn->parent); |
7660 | 7813 |
7661 // there is no common ancestor (the shared parent is null), nodes are from different documents | 7814 // there is no common ancestor (the shared parent is null), nodes are from different documents |
7675 } | 7828 } |
7676 | 7829 |
7677 // if rn sibling chain ended ln must be before rn | 7830 // if rn sibling chain ended ln must be before rn |
7678 return !rs; | 7831 return !rs; |
7679 } | 7832 } |
7680 | 7833 |
7681 PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) | 7834 PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn) |
7682 { | 7835 { |
7683 // find common ancestor at the same depth, if any | 7836 // find common ancestor at the same depth, if any |
7684 xml_node_struct* lp = ln; | 7837 xml_node_struct* lp = ln; |
7685 xml_node_struct* rp = rn; | 7838 xml_node_struct* rp = rn; |
7756 return 0; | 7909 return 0; |
7757 } | 7910 } |
7758 | 7911 |
7759 return 0; | 7912 return 0; |
7760 } | 7913 } |
7761 | 7914 |
7762 struct document_order_comparator | 7915 struct document_order_comparator |
7763 { | 7916 { |
7764 bool operator()(const xpath_node& lhs, const xpath_node& rhs) const | 7917 bool operator()(const xpath_node& lhs, const xpath_node& rhs) const |
7765 { | 7918 { |
7766 // optimized document order based check | 7919 // optimized document order based check |
7780 { | 7933 { |
7781 // determine sibling order | 7934 // determine sibling order |
7782 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) | 7935 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute()) |
7783 if (a == rhs.attribute()) | 7936 if (a == rhs.attribute()) |
7784 return true; | 7937 return true; |
7785 | 7938 |
7786 return false; | 7939 return false; |
7787 } | 7940 } |
7788 | 7941 |
7789 // compare attribute parents | 7942 // compare attribute parents |
7790 ln = lhs.parent(); | 7943 ln = lhs.parent(); |
7791 rn = rhs.parent(); | 7944 rn = rhs.parent(); |
7792 } | 7945 } |
7793 else if (lhs.attribute()) | 7946 else if (lhs.attribute()) |
7794 { | 7947 { |
7795 // attributes go after the parent element | 7948 // attributes go after the parent element |
7796 if (lhs.parent() == rhs.node()) return false; | 7949 if (lhs.parent() == rhs.node()) return false; |
7797 | 7950 |
7798 ln = lhs.parent(); | 7951 ln = lhs.parent(); |
7799 } | 7952 } |
7800 else if (rhs.attribute()) | 7953 else if (rhs.attribute()) |
7801 { | 7954 { |
7802 // attributes go after the parent element | 7955 // attributes go after the parent element |
7803 if (rhs.parent() == lhs.node()) return true; | 7956 if (rhs.parent() == lhs.node()) return true; |
7804 | 7957 |
7805 rn = rhs.parent(); | 7958 rn = rhs.parent(); |
7806 } | 7959 } |
7807 | 7960 |
7808 if (ln == rn) return false; | 7961 if (ln == rn) return false; |
7809 | 7962 |
7810 if (!ln || !rn) return ln < rn; | 7963 if (!ln || !rn) return ln < rn; |
7811 | 7964 |
7812 return node_is_before(ln.internal_object(), rn.internal_object()); | 7965 return node_is_before(ln.internal_object(), rn.internal_object()); |
7813 } | 7966 } |
7814 }; | 7967 }; |
7815 | 7968 |
7816 struct duplicate_comparator | 7969 struct duplicate_comparator |
7819 { | 7972 { |
7820 if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; | 7973 if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true; |
7821 else return rhs.attribute() ? false : lhs.node() < rhs.node(); | 7974 else return rhs.attribute() ? false : lhs.node() < rhs.node(); |
7822 } | 7975 } |
7823 }; | 7976 }; |
7824 | 7977 |
7825 PUGI__FN double gen_nan() | 7978 PUGI__FN double gen_nan() |
7826 { | 7979 { |
7827 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) | 7980 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24)) |
7828 union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1]; | 7981 PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t)); |
7829 u[0].i = 0x7fc00000; | 7982 typedef uint32_t UI; // BCC5 workaround |
7830 return u[0].f; | 7983 union { float f; UI i; } u; |
7984 u.i = 0x7fc00000; | |
7985 return u.f; | |
7831 #else | 7986 #else |
7832 // fallback | 7987 // fallback |
7833 const volatile double zero = 0.0; | 7988 const volatile double zero = 0.0; |
7834 return zero / zero; | 7989 return zero / zero; |
7835 #endif | 7990 #endif |
7836 } | 7991 } |
7837 | 7992 |
7838 PUGI__FN bool is_nan(double value) | 7993 PUGI__FN bool is_nan(double value) |
7839 { | 7994 { |
7840 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) | 7995 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) |
7841 return !!_isnan(value); | 7996 return !!_isnan(value); |
7842 #elif defined(fpclassify) && defined(FP_NAN) | 7997 #elif defined(fpclassify) && defined(FP_NAN) |
7845 // fallback | 8000 // fallback |
7846 const volatile double v = value; | 8001 const volatile double v = value; |
7847 return v != v; | 8002 return v != v; |
7848 #endif | 8003 #endif |
7849 } | 8004 } |
7850 | 8005 |
7851 PUGI__FN const char_t* convert_number_to_string_special(double value) | 8006 PUGI__FN const char_t* convert_number_to_string_special(double value) |
7852 { | 8007 { |
7853 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) | 8008 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) |
7854 if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; | 8009 if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0; |
7855 if (_isnan(value)) return PUGIXML_TEXT("NaN"); | 8010 if (_isnan(value)) return PUGIXML_TEXT("NaN"); |
7877 if (v != v) return PUGIXML_TEXT("NaN"); | 8032 if (v != v) return PUGIXML_TEXT("NaN"); |
7878 if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); | 8033 if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity"); |
7879 return 0; | 8034 return 0; |
7880 #endif | 8035 #endif |
7881 } | 8036 } |
7882 | 8037 |
7883 PUGI__FN bool convert_number_to_boolean(double value) | 8038 PUGI__FN bool convert_number_to_boolean(double value) |
7884 { | 8039 { |
7885 return (value != 0 && !is_nan(value)); | 8040 return (value != 0 && !is_nan(value)); |
7886 } | 8041 } |
7887 | 8042 |
7888 PUGI__FN void truncate_zeros(char* begin, char* end) | 8043 PUGI__FN void truncate_zeros(char* begin, char* end) |
7889 { | 8044 { |
7890 while (begin != end && end[-1] == '0') end--; | 8045 while (begin != end && end[-1] == '0') end--; |
7891 | 8046 |
7892 *end = 0; | 8047 *end = 0; |
8003 assert(s < result + result_size); | 8158 assert(s < result + result_size); |
8004 *s = 0; | 8159 *s = 0; |
8005 | 8160 |
8006 return xpath_string::from_heap_preallocated(result, s); | 8161 return xpath_string::from_heap_preallocated(result, s); |
8007 } | 8162 } |
8008 | 8163 |
8009 PUGI__FN bool check_string_to_number_format(const char_t* string) | 8164 PUGI__FN bool check_string_to_number_format(const char_t* string) |
8010 { | 8165 { |
8011 // parse leading whitespace | 8166 // parse leading whitespace |
8012 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; | 8167 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string; |
8013 | 8168 |
8070 // free dummy buffer | 8225 // free dummy buffer |
8071 if (scratch != buffer) xml_memory::deallocate(scratch); | 8226 if (scratch != buffer) xml_memory::deallocate(scratch); |
8072 | 8227 |
8073 return true; | 8228 return true; |
8074 } | 8229 } |
8075 | 8230 |
8076 PUGI__FN double round_nearest(double value) | 8231 PUGI__FN double round_nearest(double value) |
8077 { | 8232 { |
8078 return floor(value + 0.5); | 8233 return floor(value + 0.5); |
8079 } | 8234 } |
8080 | 8235 |
8082 { | 8237 { |
8083 // same as round_nearest, but returns -0 for [-0.5, -0] | 8238 // same as round_nearest, but returns -0 for [-0.5, -0] |
8084 // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) | 8239 // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0) |
8085 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); | 8240 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5); |
8086 } | 8241 } |
8087 | 8242 |
8088 PUGI__FN const char_t* qualified_name(const xpath_node& node) | 8243 PUGI__FN const char_t* qualified_name(const xpath_node& node) |
8089 { | 8244 { |
8090 return node.attribute() ? node.attribute().name() : node.node().name(); | 8245 return node.attribute() ? node.attribute().name() : node.node().name(); |
8091 } | 8246 } |
8092 | 8247 |
8093 PUGI__FN const char_t* local_name(const xpath_node& node) | 8248 PUGI__FN const char_t* local_name(const xpath_node& node) |
8094 { | 8249 { |
8095 const char_t* name = qualified_name(node); | 8250 const char_t* name = qualified_name(node); |
8096 const char_t* p = find_char(name, ':'); | 8251 const char_t* p = find_char(name, ':'); |
8097 | 8252 |
8098 return p ? p + 1 : name; | 8253 return p ? p + 1 : name; |
8099 } | 8254 } |
8100 | 8255 |
8101 struct namespace_uri_predicate | 8256 struct namespace_uri_predicate |
8102 { | 8257 { |
8122 }; | 8277 }; |
8123 | 8278 |
8124 PUGI__FN const char_t* namespace_uri(xml_node node) | 8279 PUGI__FN const char_t* namespace_uri(xml_node node) |
8125 { | 8280 { |
8126 namespace_uri_predicate pred = node.name(); | 8281 namespace_uri_predicate pred = node.name(); |
8127 | 8282 |
8128 xml_node p = node; | 8283 xml_node p = node; |
8129 | 8284 |
8130 while (p) | 8285 while (p) |
8131 { | 8286 { |
8132 xml_attribute a = p.find_attribute(pred); | 8287 xml_attribute a = p.find_attribute(pred); |
8133 | 8288 |
8134 if (a) return a.value(); | 8289 if (a) return a.value(); |
8135 | 8290 |
8136 p = p.parent(); | 8291 p = p.parent(); |
8137 } | 8292 } |
8138 | 8293 |
8139 return PUGIXML_TEXT(""); | 8294 return PUGIXML_TEXT(""); |
8140 } | 8295 } |
8141 | 8296 |
8142 PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) | 8297 PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent) |
8143 { | 8298 { |
8144 namespace_uri_predicate pred = attr.name(); | 8299 namespace_uri_predicate pred = attr.name(); |
8145 | 8300 |
8146 // Default namespace does not apply to attributes | 8301 // Default namespace does not apply to attributes |
8147 if (!pred.prefix) return PUGIXML_TEXT(""); | 8302 if (!pred.prefix) return PUGIXML_TEXT(""); |
8148 | 8303 |
8149 xml_node p = parent; | 8304 xml_node p = parent; |
8150 | 8305 |
8151 while (p) | 8306 while (p) |
8152 { | 8307 { |
8153 xml_attribute a = p.find_attribute(pred); | 8308 xml_attribute a = p.find_attribute(pred); |
8154 | 8309 |
8155 if (a) return a.value(); | 8310 if (a) return a.value(); |
8156 | 8311 |
8157 p = p.parent(); | 8312 p = p.parent(); |
8158 } | 8313 } |
8159 | 8314 |
8160 return PUGIXML_TEXT(""); | 8315 return PUGIXML_TEXT(""); |
8161 } | 8316 } |
8162 | 8317 |
8163 PUGI__FN const char_t* namespace_uri(const xpath_node& node) | 8318 PUGI__FN const char_t* namespace_uri(const xpath_node& node) |
8164 { | 8319 { |
8340 { | 8495 { |
8341 result += static_cast<unsigned int>(*str++); | 8496 result += static_cast<unsigned int>(*str++); |
8342 result += result << 10; | 8497 result += result << 10; |
8343 result ^= result >> 6; | 8498 result ^= result >> 6; |
8344 } | 8499 } |
8345 | 8500 |
8346 result += result << 3; | 8501 result += result << 3; |
8347 result ^= result >> 11; | 8502 result ^= result >> 11; |
8348 result += result << 15; | 8503 result += result << 15; |
8349 | 8504 |
8350 return result; | 8505 return result; |
8351 } | 8506 } |
8352 | 8507 |
8353 template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name) | 8508 template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name) |
8354 { | 8509 { |
8412 case xpath_type_boolean: | 8567 case xpath_type_boolean: |
8413 delete_xpath_variable(static_cast<xpath_variable_boolean*>(var)); | 8568 delete_xpath_variable(static_cast<xpath_variable_boolean*>(var)); |
8414 break; | 8569 break; |
8415 | 8570 |
8416 default: | 8571 default: |
8417 assert(!"Invalid variable type"); | 8572 assert(false && "Invalid variable type"); |
8418 } | 8573 } |
8419 } | 8574 } |
8420 | 8575 |
8421 PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs) | 8576 PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs) |
8422 { | 8577 { |
8433 | 8588 |
8434 case xpath_type_boolean: | 8589 case xpath_type_boolean: |
8435 return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value); | 8590 return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value); |
8436 | 8591 |
8437 default: | 8592 default: |
8438 assert(!"Invalid variable type"); | 8593 assert(false && "Invalid variable type"); |
8439 return false; | 8594 return false; |
8440 } | 8595 } |
8441 } | 8596 } |
8442 | 8597 |
8443 PUGI__FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result) | 8598 PUGI__FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result) |
8498 type = xpath_node_set::type_sorted; | 8653 type = xpath_node_set::type_sorted; |
8499 } | 8654 } |
8500 else | 8655 else |
8501 type = sorted; | 8656 type = sorted; |
8502 } | 8657 } |
8503 | 8658 |
8504 if (type != order) reverse(begin, end); | 8659 if (type != order) reverse(begin, end); |
8505 | 8660 |
8506 return order; | 8661 return order; |
8507 } | 8662 } |
8508 | 8663 |
8509 PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) | 8664 PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type) |
8510 { | 8665 { |
8520 | 8675 |
8521 case xpath_node_set::type_unsorted: | 8676 case xpath_node_set::type_unsorted: |
8522 return *min_element(begin, end, document_order_comparator()); | 8677 return *min_element(begin, end, document_order_comparator()); |
8523 | 8678 |
8524 default: | 8679 default: |
8525 assert(!"Invalid node set type"); | 8680 assert(false && "Invalid node set type"); |
8526 return xpath_node(); | 8681 return xpath_node(); |
8527 } | 8682 } |
8528 } | 8683 } |
8529 | 8684 |
8530 class xpath_node_set_raw | 8685 class xpath_node_set_raw |
8613 | 8768 |
8614 void remove_duplicates() | 8769 void remove_duplicates() |
8615 { | 8770 { |
8616 if (_type == xpath_node_set::type_unsorted) | 8771 if (_type == xpath_node_set::type_unsorted) |
8617 sort(_begin, _end, duplicate_comparator()); | 8772 sort(_begin, _end, duplicate_comparator()); |
8618 | 8773 |
8619 _end = unique(_begin, _end); | 8774 _end = unique(_begin, _end); |
8620 } | 8775 } |
8621 | 8776 |
8622 xpath_node_set::type_t type() const | 8777 xpath_node_set::type_t type() const |
8623 { | 8778 { |
8721 public: | 8876 public: |
8722 explicit xpath_lexer(const char_t* query): _cur(query) | 8877 explicit xpath_lexer(const char_t* query): _cur(query) |
8723 { | 8878 { |
8724 next(); | 8879 next(); |
8725 } | 8880 } |
8726 | 8881 |
8727 const char_t* state() const | 8882 const char_t* state() const |
8728 { | 8883 { |
8729 return _cur; | 8884 return _cur; |
8730 } | 8885 } |
8731 | 8886 |
8732 void next() | 8887 void next() |
8733 { | 8888 { |
8734 const char_t* cur = _cur; | 8889 const char_t* cur = _cur; |
8735 | 8890 |
8736 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; | 8891 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur; |
8741 switch (*cur) | 8896 switch (*cur) |
8742 { | 8897 { |
8743 case 0: | 8898 case 0: |
8744 _cur_lexeme = lex_eof; | 8899 _cur_lexeme = lex_eof; |
8745 break; | 8900 break; |
8746 | 8901 |
8747 case '>': | 8902 case '>': |
8748 if (*(cur+1) == '=') | 8903 if (*(cur+1) == '=') |
8749 { | 8904 { |
8750 cur += 2; | 8905 cur += 2; |
8751 _cur_lexeme = lex_greater_or_equal; | 8906 _cur_lexeme = lex_greater_or_equal; |
8785 case '=': | 8940 case '=': |
8786 cur += 1; | 8941 cur += 1; |
8787 _cur_lexeme = lex_equal; | 8942 _cur_lexeme = lex_equal; |
8788 | 8943 |
8789 break; | 8944 break; |
8790 | 8945 |
8791 case '+': | 8946 case '+': |
8792 cur += 1; | 8947 cur += 1; |
8793 _cur_lexeme = lex_plus; | 8948 _cur_lexeme = lex_plus; |
8794 | 8949 |
8795 break; | 8950 break; |
8809 case '|': | 8964 case '|': |
8810 cur += 1; | 8965 cur += 1; |
8811 _cur_lexeme = lex_union; | 8966 _cur_lexeme = lex_union; |
8812 | 8967 |
8813 break; | 8968 break; |
8814 | 8969 |
8815 case '$': | 8970 case '$': |
8816 cur += 1; | 8971 cur += 1; |
8817 | 8972 |
8818 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) | 8973 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol)) |
8819 { | 8974 { |
8827 | 8982 |
8828 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; | 8983 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; |
8829 } | 8984 } |
8830 | 8985 |
8831 _cur_lexeme_contents.end = cur; | 8986 _cur_lexeme_contents.end = cur; |
8832 | 8987 |
8833 _cur_lexeme = lex_var_ref; | 8988 _cur_lexeme = lex_var_ref; |
8834 } | 8989 } |
8835 else | 8990 else |
8836 { | 8991 { |
8837 _cur_lexeme = lex_none; | 8992 _cur_lexeme = lex_none; |
8848 case ')': | 9003 case ')': |
8849 cur += 1; | 9004 cur += 1; |
8850 _cur_lexeme = lex_close_brace; | 9005 _cur_lexeme = lex_close_brace; |
8851 | 9006 |
8852 break; | 9007 break; |
8853 | 9008 |
8854 case '[': | 9009 case '[': |
8855 cur += 1; | 9010 cur += 1; |
8856 _cur_lexeme = lex_open_square_brace; | 9011 _cur_lexeme = lex_open_square_brace; |
8857 | 9012 |
8858 break; | 9013 break; |
8879 { | 9034 { |
8880 cur += 1; | 9035 cur += 1; |
8881 _cur_lexeme = lex_slash; | 9036 _cur_lexeme = lex_slash; |
8882 } | 9037 } |
8883 break; | 9038 break; |
8884 | 9039 |
8885 case '.': | 9040 case '.': |
8886 if (*(cur+1) == '.') | 9041 if (*(cur+1) == '.') |
8887 { | 9042 { |
8888 cur += 2; | 9043 cur += 2; |
8889 _cur_lexeme = lex_double_dot; | 9044 _cur_lexeme = lex_double_dot; |
8895 ++cur; | 9050 ++cur; |
8896 | 9051 |
8897 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; | 9052 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; |
8898 | 9053 |
8899 _cur_lexeme_contents.end = cur; | 9054 _cur_lexeme_contents.end = cur; |
8900 | 9055 |
8901 _cur_lexeme = lex_number; | 9056 _cur_lexeme = lex_number; |
8902 } | 9057 } |
8903 else | 9058 else |
8904 { | 9059 { |
8905 cur += 1; | 9060 cur += 1; |
8921 ++cur; | 9076 ++cur; |
8922 | 9077 |
8923 _cur_lexeme_contents.begin = cur; | 9078 _cur_lexeme_contents.begin = cur; |
8924 while (*cur && *cur != terminator) cur++; | 9079 while (*cur && *cur != terminator) cur++; |
8925 _cur_lexeme_contents.end = cur; | 9080 _cur_lexeme_contents.end = cur; |
8926 | 9081 |
8927 if (!*cur) | 9082 if (!*cur) |
8928 _cur_lexeme = lex_none; | 9083 _cur_lexeme = lex_none; |
8929 else | 9084 else |
8930 { | 9085 { |
8931 cur += 1; | 9086 cur += 1; |
8951 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) | 9106 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) |
8952 { | 9107 { |
8953 _cur_lexeme_contents.begin = cur; | 9108 _cur_lexeme_contents.begin = cur; |
8954 | 9109 |
8955 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; | 9110 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; |
8956 | 9111 |
8957 if (*cur == '.') | 9112 if (*cur == '.') |
8958 { | 9113 { |
8959 cur++; | 9114 cur++; |
8960 | 9115 |
8961 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; | 9116 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++; |
8984 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; | 9139 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++; |
8985 } | 9140 } |
8986 } | 9141 } |
8987 | 9142 |
8988 _cur_lexeme_contents.end = cur; | 9143 _cur_lexeme_contents.end = cur; |
8989 | 9144 |
8990 _cur_lexeme = lex_string; | 9145 _cur_lexeme = lex_string; |
8991 } | 9146 } |
8992 else | 9147 else |
8993 { | 9148 { |
8994 _cur_lexeme = lex_none; | 9149 _cur_lexeme = lex_none; |
9095 axis_parent, | 9250 axis_parent, |
9096 axis_preceding, | 9251 axis_preceding, |
9097 axis_preceding_sibling, | 9252 axis_preceding_sibling, |
9098 axis_self | 9253 axis_self |
9099 }; | 9254 }; |
9100 | 9255 |
9101 enum nodetest_t | 9256 enum nodetest_t |
9102 { | 9257 { |
9103 nodetest_none, | 9258 nodetest_none, |
9104 nodetest_name, | 9259 nodetest_name, |
9105 nodetest_type_node, | 9260 nodetest_type_node, |
9130 { | 9285 { |
9131 static const axis_t axis; | 9286 static const axis_t axis; |
9132 }; | 9287 }; |
9133 | 9288 |
9134 template <axis_t N> const axis_t axis_to_type<N>::axis = N; | 9289 template <axis_t N> const axis_t axis_to_type<N>::axis = N; |
9135 | 9290 |
9136 class xpath_ast_node | 9291 class xpath_ast_node |
9137 { | 9292 { |
9138 private: | 9293 private: |
9139 // node type | 9294 // node type |
9140 char _type; | 9295 char _type; |
9250 | 9405 |
9251 return false; | 9406 return false; |
9252 } | 9407 } |
9253 } | 9408 } |
9254 | 9409 |
9255 assert(!"Wrong types"); | 9410 assert(false && "Wrong types"); |
9256 return false; | 9411 return false; |
9257 } | 9412 } |
9258 | 9413 |
9259 static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) | 9414 static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval) |
9260 { | 9415 { |
9325 | 9480 |
9326 return false; | 9481 return false; |
9327 } | 9482 } |
9328 else | 9483 else |
9329 { | 9484 { |
9330 assert(!"Wrong types"); | 9485 assert(false && "Wrong types"); |
9331 return false; | 9486 return false; |
9332 } | 9487 } |
9333 } | 9488 } |
9334 | 9489 |
9335 static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) | 9490 static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) |
9449 { | 9604 { |
9450 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); | 9605 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); |
9451 return true; | 9606 return true; |
9452 } | 9607 } |
9453 break; | 9608 break; |
9454 | 9609 |
9455 case nodetest_type_node: | 9610 case nodetest_type_node: |
9456 case nodetest_all: | 9611 case nodetest_all: |
9457 if (is_xpath_attribute(name)) | 9612 if (is_xpath_attribute(name)) |
9458 { | 9613 { |
9459 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); | 9614 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); |
9460 return true; | 9615 return true; |
9461 } | 9616 } |
9462 break; | 9617 break; |
9463 | 9618 |
9464 case nodetest_all_in_namespace: | 9619 case nodetest_all_in_namespace: |
9465 if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) | 9620 if (starts_with(name, _data.nodetest) && is_xpath_attribute(name)) |
9466 { | 9621 { |
9467 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); | 9622 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc); |
9468 return true; | 9623 return true; |
9469 } | 9624 } |
9470 break; | 9625 break; |
9471 | 9626 |
9472 default: | 9627 default: |
9473 ; | 9628 ; |
9474 } | 9629 } |
9475 | 9630 |
9476 return false; | 9631 return false; |
9477 } | 9632 } |
9478 | 9633 |
9479 bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) | 9634 bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc) |
9480 { | 9635 { |
9481 assert(n); | 9636 assert(n); |
9482 | 9637 |
9483 xml_node_type type = PUGI__NODETYPE(n); | 9638 xml_node_type type = PUGI__NODETYPE(n); |
9489 { | 9644 { |
9490 ns.push_back(xml_node(n), alloc); | 9645 ns.push_back(xml_node(n), alloc); |
9491 return true; | 9646 return true; |
9492 } | 9647 } |
9493 break; | 9648 break; |
9494 | 9649 |
9495 case nodetest_type_node: | 9650 case nodetest_type_node: |
9496 ns.push_back(xml_node(n), alloc); | 9651 ns.push_back(xml_node(n), alloc); |
9497 return true; | 9652 return true; |
9498 | 9653 |
9499 case nodetest_type_comment: | 9654 case nodetest_type_comment: |
9500 if (type == node_comment) | 9655 if (type == node_comment) |
9501 { | 9656 { |
9502 ns.push_back(xml_node(n), alloc); | 9657 ns.push_back(xml_node(n), alloc); |
9503 return true; | 9658 return true; |
9504 } | 9659 } |
9505 break; | 9660 break; |
9506 | 9661 |
9507 case nodetest_type_text: | 9662 case nodetest_type_text: |
9508 if (type == node_pcdata || type == node_cdata) | 9663 if (type == node_pcdata || type == node_cdata) |
9509 { | 9664 { |
9510 ns.push_back(xml_node(n), alloc); | 9665 ns.push_back(xml_node(n), alloc); |
9511 return true; | 9666 return true; |
9512 } | 9667 } |
9513 break; | 9668 break; |
9514 | 9669 |
9515 case nodetest_type_pi: | 9670 case nodetest_type_pi: |
9516 if (type == node_pi) | 9671 if (type == node_pi) |
9517 { | 9672 { |
9518 ns.push_back(xml_node(n), alloc); | 9673 ns.push_back(xml_node(n), alloc); |
9519 return true; | 9674 return true; |
9520 } | 9675 } |
9521 break; | 9676 break; |
9522 | 9677 |
9523 case nodetest_pi: | 9678 case nodetest_pi: |
9524 if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) | 9679 if (type == node_pi && n->name && strequal(n->name, _data.nodetest)) |
9525 { | 9680 { |
9526 ns.push_back(xml_node(n), alloc); | 9681 ns.push_back(xml_node(n), alloc); |
9527 return true; | 9682 return true; |
9528 } | 9683 } |
9529 break; | 9684 break; |
9530 | 9685 |
9531 case nodetest_all: | 9686 case nodetest_all: |
9532 if (type == node_element) | 9687 if (type == node_element) |
9533 { | 9688 { |
9534 ns.push_back(xml_node(n), alloc); | 9689 ns.push_back(xml_node(n), alloc); |
9535 return true; | 9690 return true; |
9536 } | 9691 } |
9537 break; | 9692 break; |
9538 | 9693 |
9539 case nodetest_all_in_namespace: | 9694 case nodetest_all_in_namespace: |
9540 if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) | 9695 if (type == node_element && n->name && starts_with(n->name, _data.nodetest)) |
9541 { | 9696 { |
9542 ns.push_back(xml_node(n), alloc); | 9697 ns.push_back(xml_node(n), alloc); |
9543 return true; | 9698 return true; |
9544 } | 9699 } |
9545 break; | 9700 break; |
9546 | 9701 |
9547 default: | 9702 default: |
9548 assert(!"Unknown axis"); | 9703 assert(false && "Unknown axis"); |
9549 } | 9704 } |
9550 | 9705 |
9551 return false; | 9706 return false; |
9552 } | 9707 } |
9553 | 9708 |
9560 case axis_attribute: | 9715 case axis_attribute: |
9561 { | 9716 { |
9562 for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) | 9717 for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute) |
9563 if (step_push(ns, a, n, alloc) & once) | 9718 if (step_push(ns, a, n, alloc) & once) |
9564 return; | 9719 return; |
9565 | 9720 |
9566 break; | 9721 break; |
9567 } | 9722 } |
9568 | 9723 |
9569 case axis_child: | 9724 case axis_child: |
9570 { | 9725 { |
9571 for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) | 9726 for (xml_node_struct* c = n->first_child; c; c = c->next_sibling) |
9572 if (step_push(ns, c, alloc) & once) | 9727 if (step_push(ns, c, alloc) & once) |
9573 return; | 9728 return; |
9574 | 9729 |
9575 break; | 9730 break; |
9576 } | 9731 } |
9577 | 9732 |
9578 case axis_descendant: | 9733 case axis_descendant: |
9579 case axis_descendant_or_self: | 9734 case axis_descendant_or_self: |
9580 { | 9735 { |
9581 if (axis == axis_descendant_or_self) | 9736 if (axis == axis_descendant_or_self) |
9582 if (step_push(ns, n, alloc) & once) | 9737 if (step_push(ns, n, alloc) & once) |
9583 return; | 9738 return; |
9584 | 9739 |
9585 xml_node_struct* cur = n->first_child; | 9740 xml_node_struct* cur = n->first_child; |
9586 | 9741 |
9587 while (cur) | 9742 while (cur) |
9588 { | 9743 { |
9589 if (step_push(ns, cur, alloc) & once) | 9744 if (step_push(ns, cur, alloc) & once) |
9590 return; | 9745 return; |
9591 | 9746 |
9592 if (cur->first_child) | 9747 if (cur->first_child) |
9593 cur = cur->first_child; | 9748 cur = cur->first_child; |
9594 else | 9749 else |
9595 { | 9750 { |
9596 while (!cur->next_sibling) | 9751 while (!cur->next_sibling) |
9597 { | 9752 { |
9598 cur = cur->parent; | 9753 cur = cur->parent; |
9599 | 9754 |
9600 if (cur == n) return; | 9755 if (cur == n) return; |
9601 } | 9756 } |
9602 | 9757 |
9603 cur = cur->next_sibling; | 9758 cur = cur->next_sibling; |
9604 } | 9759 } |
9605 } | 9760 } |
9606 | 9761 |
9607 break; | 9762 break; |
9608 } | 9763 } |
9609 | 9764 |
9610 case axis_following_sibling: | 9765 case axis_following_sibling: |
9611 { | 9766 { |
9612 for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) | 9767 for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling) |
9613 if (step_push(ns, c, alloc) & once) | 9768 if (step_push(ns, c, alloc) & once) |
9614 return; | 9769 return; |
9615 | 9770 |
9616 break; | 9771 break; |
9617 } | 9772 } |
9618 | 9773 |
9619 case axis_preceding_sibling: | 9774 case axis_preceding_sibling: |
9620 { | 9775 { |
9621 for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) | 9776 for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c) |
9622 if (step_push(ns, c, alloc) & once) | 9777 if (step_push(ns, c, alloc) & once) |
9623 return; | 9778 return; |
9624 | 9779 |
9625 break; | 9780 break; |
9626 } | 9781 } |
9627 | 9782 |
9628 case axis_following: | 9783 case axis_following: |
9629 { | 9784 { |
9630 xml_node_struct* cur = n; | 9785 xml_node_struct* cur = n; |
9631 | 9786 |
9632 // exit from this node so that we don't include descendants | 9787 // exit from this node so that we don't include descendants |
9701 } | 9856 } |
9702 } | 9857 } |
9703 | 9858 |
9704 break; | 9859 break; |
9705 } | 9860 } |
9706 | 9861 |
9707 case axis_ancestor: | 9862 case axis_ancestor: |
9708 case axis_ancestor_or_self: | 9863 case axis_ancestor_or_self: |
9709 { | 9864 { |
9710 if (axis == axis_ancestor_or_self) | 9865 if (axis == axis_ancestor_or_self) |
9711 if (step_push(ns, n, alloc) & once) | 9866 if (step_push(ns, n, alloc) & once) |
9712 return; | 9867 return; |
9713 | 9868 |
9714 xml_node_struct* cur = n->parent; | 9869 xml_node_struct* cur = n->parent; |
9715 | 9870 |
9716 while (cur) | 9871 while (cur) |
9717 { | 9872 { |
9718 if (step_push(ns, cur, alloc) & once) | 9873 if (step_push(ns, cur, alloc) & once) |
9719 return; | 9874 return; |
9720 | 9875 |
9721 cur = cur->parent; | 9876 cur = cur->parent; |
9722 } | 9877 } |
9723 | 9878 |
9724 break; | 9879 break; |
9725 } | 9880 } |
9726 | 9881 |
9727 case axis_self: | 9882 case axis_self: |
9728 { | 9883 { |
9736 if (n->parent) | 9891 if (n->parent) |
9737 step_push(ns, n->parent, alloc); | 9892 step_push(ns, n->parent, alloc); |
9738 | 9893 |
9739 break; | 9894 break; |
9740 } | 9895 } |
9741 | 9896 |
9742 default: | 9897 default: |
9743 assert(!"Unimplemented axis"); | 9898 assert(false && "Unimplemented axis"); |
9744 } | 9899 } |
9745 } | 9900 } |
9746 | 9901 |
9747 template <class T> void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) | 9902 template <class T> void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v) |
9748 { | 9903 { |
9749 const axis_t axis = T::axis; | 9904 const axis_t axis = T::axis; |
9750 | 9905 |
9751 switch (axis) | 9906 switch (axis) |
9756 if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test | 9911 if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test |
9757 if (step_push(ns, a, p, alloc) & once) | 9912 if (step_push(ns, a, p, alloc) & once) |
9758 return; | 9913 return; |
9759 | 9914 |
9760 xml_node_struct* cur = p; | 9915 xml_node_struct* cur = p; |
9761 | 9916 |
9762 while (cur) | 9917 while (cur) |
9763 { | 9918 { |
9764 if (step_push(ns, cur, alloc) & once) | 9919 if (step_push(ns, cur, alloc) & once) |
9765 return; | 9920 return; |
9766 | 9921 |
9767 cur = cur->parent; | 9922 cur = cur->parent; |
9768 } | 9923 } |
9769 | 9924 |
9770 break; | 9925 break; |
9771 } | 9926 } |
9772 | 9927 |
9773 case axis_descendant_or_self: | 9928 case axis_descendant_or_self: |
9774 case axis_self: | 9929 case axis_self: |
9780 } | 9935 } |
9781 | 9936 |
9782 case axis_following: | 9937 case axis_following: |
9783 { | 9938 { |
9784 xml_node_struct* cur = p; | 9939 xml_node_struct* cur = p; |
9785 | 9940 |
9786 while (cur) | 9941 while (cur) |
9787 { | 9942 { |
9788 if (cur->first_child) | 9943 if (cur->first_child) |
9789 cur = cur->first_child; | 9944 cur = cur->first_child; |
9790 else | 9945 else |
9817 { | 9972 { |
9818 // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding | 9973 // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding |
9819 step_fill(ns, p, alloc, once, v); | 9974 step_fill(ns, p, alloc, once, v); |
9820 break; | 9975 break; |
9821 } | 9976 } |
9822 | 9977 |
9823 default: | 9978 default: |
9824 assert(!"Unimplemented axis"); | 9979 assert(false && "Unimplemented axis"); |
9825 } | 9980 } |
9826 } | 9981 } |
9827 | 9982 |
9828 template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v) | 9983 template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v) |
9829 { | 9984 { |
9861 { | 10016 { |
9862 size_t size = ns.size(); | 10017 size_t size = ns.size(); |
9863 | 10018 |
9864 // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes | 10019 // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes |
9865 if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); | 10020 if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted); |
9866 | 10021 |
9867 step_fill(ns, *it, stack.result, once, v); | 10022 step_fill(ns, *it, stack.result, once, v); |
9868 if (_right) apply_predicates(ns, size, stack, eval); | 10023 if (_right) apply_predicates(ns, size, stack, eval); |
9869 } | 10024 } |
9870 } | 10025 } |
9871 else | 10026 else |
9879 if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) | 10034 if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted) |
9880 ns.remove_duplicates(); | 10035 ns.remove_duplicates(); |
9881 | 10036 |
9882 return ns; | 10037 return ns; |
9883 } | 10038 } |
9884 | 10039 |
9885 public: | 10040 public: |
9886 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): | 10041 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value): |
9887 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) | 10042 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) |
9888 { | 10043 { |
9889 assert(type == ast_string_constant); | 10044 assert(type == ast_string_constant); |
9894 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) | 10049 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) |
9895 { | 10050 { |
9896 assert(type == ast_number_constant); | 10051 assert(type == ast_number_constant); |
9897 _data.number = value; | 10052 _data.number = value; |
9898 } | 10053 } |
9899 | 10054 |
9900 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): | 10055 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value): |
9901 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) | 10056 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0) |
9902 { | 10057 { |
9903 assert(type == ast_variable); | 10058 assert(type == ast_variable); |
9904 _data.variable = value; | 10059 _data.variable = value; |
9905 } | 10060 } |
9906 | 10061 |
9907 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): | 10062 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0): |
9908 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) | 10063 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0) |
9909 { | 10064 { |
9910 } | 10065 } |
9911 | 10066 |
9936 { | 10091 { |
9937 switch (_type) | 10092 switch (_type) |
9938 { | 10093 { |
9939 case ast_op_or: | 10094 case ast_op_or: |
9940 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); | 10095 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack); |
9941 | 10096 |
9942 case ast_op_and: | 10097 case ast_op_and: |
9943 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); | 10098 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack); |
9944 | 10099 |
9945 case ast_op_equal: | 10100 case ast_op_equal: |
9946 return compare_eq(_left, _right, c, stack, equal_to()); | 10101 return compare_eq(_left, _right, c, stack, equal_to()); |
9947 | 10102 |
9948 case ast_op_not_equal: | 10103 case ast_op_not_equal: |
9949 return compare_eq(_left, _right, c, stack, not_equal_to()); | 10104 return compare_eq(_left, _right, c, stack, not_equal_to()); |
9950 | 10105 |
9951 case ast_op_less: | 10106 case ast_op_less: |
9952 return compare_rel(_left, _right, c, stack, less()); | 10107 return compare_rel(_left, _right, c, stack, less()); |
9953 | 10108 |
9954 case ast_op_greater: | 10109 case ast_op_greater: |
9955 return compare_rel(_right, _left, c, stack, less()); | 10110 return compare_rel(_right, _left, c, stack, less()); |
9956 | 10111 |
9957 case ast_op_less_or_equal: | 10112 case ast_op_less_or_equal: |
9958 return compare_rel(_left, _right, c, stack, less_equal()); | 10113 return compare_rel(_left, _right, c, stack, less_equal()); |
9959 | 10114 |
9960 case ast_op_greater_or_equal: | 10115 case ast_op_greater_or_equal: |
9961 return compare_rel(_right, _left, c, stack, less_equal()); | 10116 return compare_rel(_right, _left, c, stack, less_equal()); |
9962 | 10117 |
9963 case ast_func_starts_with: | 10118 case ast_func_starts_with: |
9964 { | 10119 { |
9980 return find_substring(lr.c_str(), rr.c_str()) != 0; | 10135 return find_substring(lr.c_str(), rr.c_str()) != 0; |
9981 } | 10136 } |
9982 | 10137 |
9983 case ast_func_boolean: | 10138 case ast_func_boolean: |
9984 return _left->eval_boolean(c, stack); | 10139 return _left->eval_boolean(c, stack); |
9985 | 10140 |
9986 case ast_func_not: | 10141 case ast_func_not: |
9987 return !_left->eval_boolean(c, stack); | 10142 return !_left->eval_boolean(c, stack); |
9988 | 10143 |
9989 case ast_func_true: | 10144 case ast_func_true: |
9990 return true; | 10145 return true; |
9991 | 10146 |
9992 case ast_func_false: | 10147 case ast_func_false: |
9993 return false; | 10148 return false; |
9994 | 10149 |
9995 case ast_func_lang: | 10150 case ast_func_lang: |
9996 { | 10151 { |
9997 if (c.n.attribute()) return false; | 10152 if (c.n.attribute()) return false; |
9998 | 10153 |
9999 xpath_allocator_capture cr(stack.result); | 10154 xpath_allocator_capture cr(stack.result); |
10000 | 10155 |
10001 xpath_string lang = _left->eval_string(c, stack); | 10156 xpath_string lang = _left->eval_string(c, stack); |
10002 | 10157 |
10003 for (xml_node n = c.n.node(); n; n = n.parent()) | 10158 for (xml_node n = c.n.node(); n; n = n.parent()) |
10004 { | 10159 { |
10005 xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); | 10160 xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang")); |
10006 | 10161 |
10007 if (a) | 10162 if (a) |
10008 { | 10163 { |
10009 const char_t* value = a.value(); | 10164 const char_t* value = a.value(); |
10010 | 10165 |
10011 // strnicmp / strncasecmp is not portable | 10166 // strnicmp / strncasecmp is not portable |
10012 for (const char_t* lit = lang.c_str(); *lit; ++lit) | 10167 for (const char_t* lit = lang.c_str(); *lit; ++lit) |
10013 { | 10168 { |
10014 if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; | 10169 if (tolower_ascii(*lit) != tolower_ascii(*value)) return false; |
10015 ++value; | 10170 ++value; |
10016 } | 10171 } |
10017 | 10172 |
10018 return *value == 0 || *value == '-'; | 10173 return *value == 0 || *value == '-'; |
10019 } | 10174 } |
10020 } | 10175 } |
10021 | 10176 |
10022 return false; | 10177 return false; |
10023 } | 10178 } |
10024 | 10179 |
10025 case ast_opt_compare_attribute: | 10180 case ast_opt_compare_attribute: |
10026 { | 10181 { |
10045 { | 10200 { |
10046 switch (_rettype) | 10201 switch (_rettype) |
10047 { | 10202 { |
10048 case xpath_type_number: | 10203 case xpath_type_number: |
10049 return convert_number_to_boolean(eval_number(c, stack)); | 10204 return convert_number_to_boolean(eval_number(c, stack)); |
10050 | 10205 |
10051 case xpath_type_string: | 10206 case xpath_type_string: |
10052 { | 10207 { |
10053 xpath_allocator_capture cr(stack.result); | 10208 xpath_allocator_capture cr(stack.result); |
10054 | 10209 |
10055 return !eval_string(c, stack).empty(); | 10210 return !eval_string(c, stack).empty(); |
10056 } | 10211 } |
10057 | 10212 |
10058 case xpath_type_node_set: | 10213 case xpath_type_node_set: |
10059 { | 10214 { |
10060 xpath_allocator_capture cr(stack.result); | 10215 xpath_allocator_capture cr(stack.result); |
10061 | 10216 |
10062 return !eval_node_set(c, stack, nodeset_eval_any).empty(); | 10217 return !eval_node_set(c, stack, nodeset_eval_any).empty(); |
10063 } | 10218 } |
10064 | 10219 |
10065 default: | 10220 default: |
10066 assert(!"Wrong expression for return type boolean"); | 10221 assert(false && "Wrong expression for return type boolean"); |
10067 return false; | 10222 return false; |
10068 } | 10223 } |
10069 } | 10224 } |
10070 } | 10225 } |
10071 } | 10226 } |
10074 { | 10229 { |
10075 switch (_type) | 10230 switch (_type) |
10076 { | 10231 { |
10077 case ast_op_add: | 10232 case ast_op_add: |
10078 return _left->eval_number(c, stack) + _right->eval_number(c, stack); | 10233 return _left->eval_number(c, stack) + _right->eval_number(c, stack); |
10079 | 10234 |
10080 case ast_op_subtract: | 10235 case ast_op_subtract: |
10081 return _left->eval_number(c, stack) - _right->eval_number(c, stack); | 10236 return _left->eval_number(c, stack) - _right->eval_number(c, stack); |
10082 | 10237 |
10083 case ast_op_multiply: | 10238 case ast_op_multiply: |
10084 return _left->eval_number(c, stack) * _right->eval_number(c, stack); | 10239 return _left->eval_number(c, stack) * _right->eval_number(c, stack); |
10095 case ast_number_constant: | 10250 case ast_number_constant: |
10096 return _data.number; | 10251 return _data.number; |
10097 | 10252 |
10098 case ast_func_last: | 10253 case ast_func_last: |
10099 return static_cast<double>(c.size); | 10254 return static_cast<double>(c.size); |
10100 | 10255 |
10101 case ast_func_position: | 10256 case ast_func_position: |
10102 return static_cast<double>(c.position); | 10257 return static_cast<double>(c.position); |
10103 | 10258 |
10104 case ast_func_count: | 10259 case ast_func_count: |
10105 { | 10260 { |
10106 xpath_allocator_capture cr(stack.result); | 10261 xpath_allocator_capture cr(stack.result); |
10107 | 10262 |
10108 return static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size()); | 10263 return static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size()); |
10109 } | 10264 } |
10110 | 10265 |
10111 case ast_func_string_length_0: | 10266 case ast_func_string_length_0: |
10112 { | 10267 { |
10113 xpath_allocator_capture cr(stack.result); | 10268 xpath_allocator_capture cr(stack.result); |
10114 | 10269 |
10115 return static_cast<double>(string_value(c.n, stack.result).length()); | 10270 return static_cast<double>(string_value(c.n, stack.result).length()); |
10116 } | 10271 } |
10117 | 10272 |
10118 case ast_func_string_length_1: | 10273 case ast_func_string_length_1: |
10119 { | 10274 { |
10120 xpath_allocator_capture cr(stack.result); | 10275 xpath_allocator_capture cr(stack.result); |
10121 | 10276 |
10122 return static_cast<double>(_left->eval_string(c, stack).length()); | 10277 return static_cast<double>(_left->eval_string(c, stack).length()); |
10123 } | 10278 } |
10124 | 10279 |
10125 case ast_func_number_0: | 10280 case ast_func_number_0: |
10126 { | 10281 { |
10127 xpath_allocator_capture cr(stack.result); | 10282 xpath_allocator_capture cr(stack.result); |
10128 | 10283 |
10129 return convert_string_to_number(string_value(c.n, stack.result).c_str()); | 10284 return convert_string_to_number(string_value(c.n, stack.result).c_str()); |
10130 } | 10285 } |
10131 | 10286 |
10132 case ast_func_number_1: | 10287 case ast_func_number_1: |
10133 return _left->eval_number(c, stack); | 10288 return _left->eval_number(c, stack); |
10134 | 10289 |
10135 case ast_func_sum: | 10290 case ast_func_sum: |
10136 { | 10291 { |
10137 xpath_allocator_capture cr(stack.result); | 10292 xpath_allocator_capture cr(stack.result); |
10138 | 10293 |
10139 double r = 0; | 10294 double r = 0; |
10140 | 10295 |
10141 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); | 10296 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all); |
10142 | 10297 |
10143 for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) | 10298 for (const xpath_node* it = ns.begin(); it != ns.end(); ++it) |
10144 { | 10299 { |
10145 xpath_allocator_capture cri(stack.result); | 10300 xpath_allocator_capture cri(stack.result); |
10146 | 10301 |
10147 r += convert_string_to_number(string_value(*it, stack.result).c_str()); | 10302 r += convert_string_to_number(string_value(*it, stack.result).c_str()); |
10148 } | 10303 } |
10149 | 10304 |
10150 return r; | 10305 return r; |
10151 } | 10306 } |
10152 | 10307 |
10153 case ast_func_floor: | 10308 case ast_func_floor: |
10154 { | 10309 { |
10155 double r = _left->eval_number(c, stack); | 10310 double r = _left->eval_number(c, stack); |
10156 | 10311 |
10157 return r == r ? floor(r) : r; | 10312 return r == r ? floor(r) : r; |
10158 } | 10313 } |
10159 | 10314 |
10160 case ast_func_ceiling: | 10315 case ast_func_ceiling: |
10161 { | 10316 { |
10162 double r = _left->eval_number(c, stack); | 10317 double r = _left->eval_number(c, stack); |
10163 | 10318 |
10164 return r == r ? ceil(r) : r; | 10319 return r == r ? ceil(r) : r; |
10165 } | 10320 } |
10166 | 10321 |
10167 case ast_func_round: | 10322 case ast_func_round: |
10168 return round_nearest_nzero(_left->eval_number(c, stack)); | 10323 return round_nearest_nzero(_left->eval_number(c, stack)); |
10169 | 10324 |
10170 case ast_variable: | 10325 case ast_variable: |
10171 { | 10326 { |
10172 assert(_rettype == _data.variable->type()); | 10327 assert(_rettype == _data.variable->type()); |
10173 | 10328 |
10174 if (_rettype == xpath_type_number) | 10329 if (_rettype == xpath_type_number) |
10181 { | 10336 { |
10182 switch (_rettype) | 10337 switch (_rettype) |
10183 { | 10338 { |
10184 case xpath_type_boolean: | 10339 case xpath_type_boolean: |
10185 return eval_boolean(c, stack) ? 1 : 0; | 10340 return eval_boolean(c, stack) ? 1 : 0; |
10186 | 10341 |
10187 case xpath_type_string: | 10342 case xpath_type_string: |
10188 { | 10343 { |
10189 xpath_allocator_capture cr(stack.result); | 10344 xpath_allocator_capture cr(stack.result); |
10190 | 10345 |
10191 return convert_string_to_number(eval_string(c, stack).c_str()); | 10346 return convert_string_to_number(eval_string(c, stack).c_str()); |
10192 } | 10347 } |
10193 | 10348 |
10194 case xpath_type_node_set: | 10349 case xpath_type_node_set: |
10195 { | 10350 { |
10196 xpath_allocator_capture cr(stack.result); | 10351 xpath_allocator_capture cr(stack.result); |
10197 | 10352 |
10198 return convert_string_to_number(eval_string(c, stack).c_str()); | 10353 return convert_string_to_number(eval_string(c, stack).c_str()); |
10199 } | 10354 } |
10200 | 10355 |
10201 default: | 10356 default: |
10202 assert(!"Wrong expression for return type number"); | 10357 assert(false && "Wrong expression for return type number"); |
10203 return 0; | 10358 return 0; |
10204 } | 10359 } |
10205 | 10360 |
10206 } | 10361 } |
10207 } | 10362 } |
10208 } | 10363 } |
10209 | 10364 |
10210 xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) | 10365 xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack) |
10211 { | 10366 { |
10212 assert(_type == ast_func_concat); | 10367 assert(_type == ast_func_concat); |
10213 | 10368 |
10214 xpath_allocator_capture ct(stack.temp); | 10369 xpath_allocator_capture ct(stack.temp); |
10260 { | 10415 { |
10261 switch (_type) | 10416 switch (_type) |
10262 { | 10417 { |
10263 case ast_string_constant: | 10418 case ast_string_constant: |
10264 return xpath_string::from_const(_data.string); | 10419 return xpath_string::from_const(_data.string); |
10265 | 10420 |
10266 case ast_func_local_name_0: | 10421 case ast_func_local_name_0: |
10267 { | 10422 { |
10268 xpath_node na = c.n; | 10423 xpath_node na = c.n; |
10269 | 10424 |
10270 return xpath_string::from_const(local_name(na)); | 10425 return xpath_string::from_const(local_name(na)); |
10271 } | 10426 } |
10272 | 10427 |
10273 case ast_func_local_name_1: | 10428 case ast_func_local_name_1: |
10274 { | 10429 { |
10275 xpath_allocator_capture cr(stack.result); | 10430 xpath_allocator_capture cr(stack.result); |
10276 | 10431 |
10277 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); | 10432 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); |
10278 xpath_node na = ns.first(); | 10433 xpath_node na = ns.first(); |
10279 | 10434 |
10280 return xpath_string::from_const(local_name(na)); | 10435 return xpath_string::from_const(local_name(na)); |
10281 } | 10436 } |
10282 | 10437 |
10283 case ast_func_name_0: | 10438 case ast_func_name_0: |
10284 { | 10439 { |
10285 xpath_node na = c.n; | 10440 xpath_node na = c.n; |
10286 | 10441 |
10287 return xpath_string::from_const(qualified_name(na)); | 10442 return xpath_string::from_const(qualified_name(na)); |
10288 } | 10443 } |
10289 | 10444 |
10290 case ast_func_name_1: | 10445 case ast_func_name_1: |
10291 { | 10446 { |
10292 xpath_allocator_capture cr(stack.result); | 10447 xpath_allocator_capture cr(stack.result); |
10293 | 10448 |
10294 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); | 10449 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); |
10295 xpath_node na = ns.first(); | 10450 xpath_node na = ns.first(); |
10296 | 10451 |
10297 return xpath_string::from_const(qualified_name(na)); | 10452 return xpath_string::from_const(qualified_name(na)); |
10298 } | 10453 } |
10299 | 10454 |
10300 case ast_func_namespace_uri_0: | 10455 case ast_func_namespace_uri_0: |
10301 { | 10456 { |
10302 xpath_node na = c.n; | 10457 xpath_node na = c.n; |
10303 | 10458 |
10304 return xpath_string::from_const(namespace_uri(na)); | 10459 return xpath_string::from_const(namespace_uri(na)); |
10305 } | 10460 } |
10306 | 10461 |
10307 case ast_func_namespace_uri_1: | 10462 case ast_func_namespace_uri_1: |
10308 { | 10463 { |
10309 xpath_allocator_capture cr(stack.result); | 10464 xpath_allocator_capture cr(stack.result); |
10310 | 10465 |
10311 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); | 10466 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first); |
10312 xpath_node na = ns.first(); | 10467 xpath_node na = ns.first(); |
10313 | 10468 |
10314 return xpath_string::from_const(namespace_uri(na)); | 10469 return xpath_string::from_const(namespace_uri(na)); |
10315 } | 10470 } |
10316 | 10471 |
10317 case ast_func_string_0: | 10472 case ast_func_string_0: |
10318 return string_value(c.n, stack.result); | 10473 return string_value(c.n, stack.result); |
10331 | 10486 |
10332 xpath_string s = _left->eval_string(c, swapped_stack); | 10487 xpath_string s = _left->eval_string(c, swapped_stack); |
10333 xpath_string p = _right->eval_string(c, swapped_stack); | 10488 xpath_string p = _right->eval_string(c, swapped_stack); |
10334 | 10489 |
10335 const char_t* pos = find_substring(s.c_str(), p.c_str()); | 10490 const char_t* pos = find_substring(s.c_str(), p.c_str()); |
10336 | 10491 |
10337 return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); | 10492 return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string(); |
10338 } | 10493 } |
10339 | 10494 |
10340 case ast_func_substring_after: | 10495 case ast_func_substring_after: |
10341 { | 10496 { |
10342 xpath_allocator_capture cr(stack.temp); | 10497 xpath_allocator_capture cr(stack.temp); |
10343 | 10498 |
10344 xpath_stack swapped_stack = {stack.temp, stack.result}; | 10499 xpath_stack swapped_stack = {stack.temp, stack.result}; |
10345 | 10500 |
10346 xpath_string s = _left->eval_string(c, swapped_stack); | 10501 xpath_string s = _left->eval_string(c, swapped_stack); |
10347 xpath_string p = _right->eval_string(c, swapped_stack); | 10502 xpath_string p = _right->eval_string(c, swapped_stack); |
10348 | 10503 |
10349 const char_t* pos = find_substring(s.c_str(), p.c_str()); | 10504 const char_t* pos = find_substring(s.c_str(), p.c_str()); |
10350 if (!pos) return xpath_string(); | 10505 if (!pos) return xpath_string(); |
10351 | 10506 |
10352 const char_t* rbegin = pos + p.length(); | 10507 const char_t* rbegin = pos + p.length(); |
10353 const char_t* rend = s.c_str() + s.length(); | 10508 const char_t* rend = s.c_str() + s.length(); |
10363 | 10518 |
10364 xpath_string s = _left->eval_string(c, swapped_stack); | 10519 xpath_string s = _left->eval_string(c, swapped_stack); |
10365 size_t s_length = s.length(); | 10520 size_t s_length = s.length(); |
10366 | 10521 |
10367 double first = round_nearest(_right->eval_number(c, stack)); | 10522 double first = round_nearest(_right->eval_number(c, stack)); |
10368 | 10523 |
10369 if (is_nan(first)) return xpath_string(); // NaN | 10524 if (is_nan(first)) return xpath_string(); // NaN |
10370 else if (first >= s_length + 1) return xpath_string(); | 10525 else if (first >= s_length + 1) return xpath_string(); |
10371 | 10526 |
10372 size_t pos = first < 1 ? 1 : static_cast<size_t>(first); | 10527 size_t pos = first < 1 ? 1 : static_cast<size_t>(first); |
10373 assert(1 <= pos && pos <= s_length + 1); | 10528 assert(1 <= pos && pos <= s_length + 1); |
10374 | 10529 |
10375 const char_t* rbegin = s.c_str() + (pos - 1); | 10530 const char_t* rbegin = s.c_str() + (pos - 1); |
10376 const char_t* rend = s.c_str() + s.length(); | 10531 const char_t* rend = s.c_str() + s.length(); |
10377 | 10532 |
10378 return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); | 10533 return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin); |
10379 } | 10534 } |
10380 | 10535 |
10381 case ast_func_substring_3: | 10536 case ast_func_substring_3: |
10382 { | 10537 { |
10383 xpath_allocator_capture cr(stack.temp); | 10538 xpath_allocator_capture cr(stack.temp); |
10384 | 10539 |
10385 xpath_stack swapped_stack = {stack.temp, stack.result}; | 10540 xpath_stack swapped_stack = {stack.temp, stack.result}; |
10387 xpath_string s = _left->eval_string(c, swapped_stack); | 10542 xpath_string s = _left->eval_string(c, swapped_stack); |
10388 size_t s_length = s.length(); | 10543 size_t s_length = s.length(); |
10389 | 10544 |
10390 double first = round_nearest(_right->eval_number(c, stack)); | 10545 double first = round_nearest(_right->eval_number(c, stack)); |
10391 double last = first + round_nearest(_right->_next->eval_number(c, stack)); | 10546 double last = first + round_nearest(_right->_next->eval_number(c, stack)); |
10392 | 10547 |
10393 if (is_nan(first) || is_nan(last)) return xpath_string(); | 10548 if (is_nan(first) || is_nan(last)) return xpath_string(); |
10394 else if (first >= s_length + 1) return xpath_string(); | 10549 else if (first >= s_length + 1) return xpath_string(); |
10395 else if (first >= last) return xpath_string(); | 10550 else if (first >= last) return xpath_string(); |
10396 else if (last < 1) return xpath_string(); | 10551 else if (last < 1) return xpath_string(); |
10397 | 10552 |
10398 size_t pos = first < 1 ? 1 : static_cast<size_t>(first); | 10553 size_t pos = first < 1 ? 1 : static_cast<size_t>(first); |
10399 size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last); | 10554 size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last); |
10400 | 10555 |
10401 assert(1 <= pos && pos <= end && end <= s_length + 1); | 10556 assert(1 <= pos && pos <= end && end <= s_length + 1); |
10402 const char_t* rbegin = s.c_str() + (pos - 1); | 10557 const char_t* rbegin = s.c_str() + (pos - 1); |
10419 { | 10574 { |
10420 xpath_string s = _left->eval_string(c, stack); | 10575 xpath_string s = _left->eval_string(c, stack); |
10421 | 10576 |
10422 char_t* begin = s.data(stack.result); | 10577 char_t* begin = s.data(stack.result); |
10423 char_t* end = normalize_space(begin); | 10578 char_t* end = normalize_space(begin); |
10424 | 10579 |
10425 return xpath_string::from_heap_preallocated(begin, end); | 10580 return xpath_string::from_heap_preallocated(begin, end); |
10426 } | 10581 } |
10427 | 10582 |
10428 case ast_func_translate: | 10583 case ast_func_translate: |
10429 { | 10584 { |
10465 { | 10620 { |
10466 switch (_rettype) | 10621 switch (_rettype) |
10467 { | 10622 { |
10468 case xpath_type_boolean: | 10623 case xpath_type_boolean: |
10469 return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); | 10624 return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false")); |
10470 | 10625 |
10471 case xpath_type_number: | 10626 case xpath_type_number: |
10472 return convert_number_to_string(eval_number(c, stack), stack.result); | 10627 return convert_number_to_string(eval_number(c, stack), stack.result); |
10473 | 10628 |
10474 case xpath_type_node_set: | 10629 case xpath_type_node_set: |
10475 { | 10630 { |
10476 xpath_allocator_capture cr(stack.temp); | 10631 xpath_allocator_capture cr(stack.temp); |
10477 | 10632 |
10478 xpath_stack swapped_stack = {stack.temp, stack.result}; | 10633 xpath_stack swapped_stack = {stack.temp, stack.result}; |
10479 | 10634 |
10480 xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); | 10635 xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first); |
10481 return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); | 10636 return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result); |
10482 } | 10637 } |
10483 | 10638 |
10484 default: | 10639 default: |
10485 assert(!"Wrong expression for return type string"); | 10640 assert(false && "Wrong expression for return type string"); |
10486 return xpath_string(); | 10641 return xpath_string(); |
10487 } | 10642 } |
10488 } | 10643 } |
10489 } | 10644 } |
10490 } | 10645 } |
10519 if (_test != predicate_posinv) set.sort_do(); | 10674 if (_test != predicate_posinv) set.sort_do(); |
10520 | 10675 |
10521 bool once = eval_once(set.type(), eval); | 10676 bool once = eval_once(set.type(), eval); |
10522 | 10677 |
10523 apply_predicate(set, 0, stack, once); | 10678 apply_predicate(set, 0, stack, once); |
10524 | 10679 |
10525 return set; | 10680 return set; |
10526 } | 10681 } |
10527 | 10682 |
10528 case ast_func_id: | 10683 case ast_func_id: |
10529 return xpath_node_set_raw(); | 10684 return xpath_node_set_raw(); |
10530 | 10685 |
10531 case ast_step: | 10686 case ast_step: |
10532 { | 10687 { |
10533 switch (_axis) | 10688 switch (_axis) |
10534 { | 10689 { |
10535 case axis_ancestor: | 10690 case axis_ancestor: |
10536 return step_do(c, stack, eval, axis_to_type<axis_ancestor>()); | 10691 return step_do(c, stack, eval, axis_to_type<axis_ancestor>()); |
10537 | 10692 |
10538 case axis_ancestor_or_self: | 10693 case axis_ancestor_or_self: |
10539 return step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>()); | 10694 return step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>()); |
10540 | 10695 |
10541 case axis_attribute: | 10696 case axis_attribute: |
10542 return step_do(c, stack, eval, axis_to_type<axis_attribute>()); | 10697 return step_do(c, stack, eval, axis_to_type<axis_attribute>()); |
10543 | 10698 |
10544 case axis_child: | 10699 case axis_child: |
10545 return step_do(c, stack, eval, axis_to_type<axis_child>()); | 10700 return step_do(c, stack, eval, axis_to_type<axis_child>()); |
10546 | 10701 |
10547 case axis_descendant: | 10702 case axis_descendant: |
10548 return step_do(c, stack, eval, axis_to_type<axis_descendant>()); | 10703 return step_do(c, stack, eval, axis_to_type<axis_descendant>()); |
10549 | 10704 |
10550 case axis_descendant_or_self: | 10705 case axis_descendant_or_self: |
10551 return step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>()); | 10706 return step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>()); |
10552 | 10707 |
10553 case axis_following: | 10708 case axis_following: |
10554 return step_do(c, stack, eval, axis_to_type<axis_following>()); | 10709 return step_do(c, stack, eval, axis_to_type<axis_following>()); |
10555 | 10710 |
10556 case axis_following_sibling: | 10711 case axis_following_sibling: |
10557 return step_do(c, stack, eval, axis_to_type<axis_following_sibling>()); | 10712 return step_do(c, stack, eval, axis_to_type<axis_following_sibling>()); |
10558 | 10713 |
10559 case axis_namespace: | 10714 case axis_namespace: |
10560 // namespaced axis is not supported | 10715 // namespaced axis is not supported |
10561 return xpath_node_set_raw(); | 10716 return xpath_node_set_raw(); |
10562 | 10717 |
10563 case axis_parent: | 10718 case axis_parent: |
10564 return step_do(c, stack, eval, axis_to_type<axis_parent>()); | 10719 return step_do(c, stack, eval, axis_to_type<axis_parent>()); |
10565 | 10720 |
10566 case axis_preceding: | 10721 case axis_preceding: |
10567 return step_do(c, stack, eval, axis_to_type<axis_preceding>()); | 10722 return step_do(c, stack, eval, axis_to_type<axis_preceding>()); |
10568 | 10723 |
10569 case axis_preceding_sibling: | 10724 case axis_preceding_sibling: |
10570 return step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>()); | 10725 return step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>()); |
10571 | 10726 |
10572 case axis_self: | 10727 case axis_self: |
10573 return step_do(c, stack, eval, axis_to_type<axis_self>()); | 10728 return step_do(c, stack, eval, axis_to_type<axis_self>()); |
10574 | 10729 |
10575 default: | 10730 default: |
10576 assert(!"Unknown axis"); | 10731 assert(false && "Unknown axis"); |
10577 return xpath_node_set_raw(); | 10732 return xpath_node_set_raw(); |
10578 } | 10733 } |
10579 } | 10734 } |
10580 | 10735 |
10581 case ast_step_root: | 10736 case ast_step_root: |
10610 | 10765 |
10611 // fallthrough to type conversion | 10766 // fallthrough to type conversion |
10612 } | 10767 } |
10613 | 10768 |
10614 default: | 10769 default: |
10615 assert(!"Wrong expression for return type node set"); | 10770 assert(false && "Wrong expression for return type node set"); |
10616 return xpath_node_set_raw(); | 10771 return xpath_node_set_raw(); |
10617 } | 10772 } |
10618 } | 10773 } |
10619 | 10774 |
10620 void optimize(xpath_allocator* alloc) | 10775 void optimize(xpath_allocator* alloc) |
10621 { | 10776 { |
10622 if (_left) _left->optimize(alloc); | 10777 if (_left) |
10623 if (_right) _right->optimize(alloc); | 10778 _left->optimize(alloc); |
10624 if (_next) _next->optimize(alloc); | 10779 |
10780 if (_right) | |
10781 _right->optimize(alloc); | |
10782 | |
10783 if (_next) | |
10784 _next->optimize(alloc); | |
10625 | 10785 |
10626 optimize_self(alloc); | 10786 optimize_self(alloc); |
10627 } | 10787 } |
10628 | 10788 |
10629 void optimize_self(xpath_allocator* alloc) | 10789 void optimize_self(xpath_allocator* alloc) |
10683 (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string))) | 10843 (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string))) |
10684 { | 10844 { |
10685 _type = ast_opt_compare_attribute; | 10845 _type = ast_opt_compare_attribute; |
10686 } | 10846 } |
10687 } | 10847 } |
10688 | 10848 |
10689 bool is_posinv_expr() const | 10849 bool is_posinv_expr() const |
10690 { | 10850 { |
10691 switch (_type) | 10851 switch (_type) |
10692 { | 10852 { |
10693 case ast_func_position: | 10853 case ast_func_position: |
10707 case ast_filter: | 10867 case ast_filter: |
10708 return true; | 10868 return true; |
10709 | 10869 |
10710 default: | 10870 default: |
10711 if (_left && !_left->is_posinv_expr()) return false; | 10871 if (_left && !_left->is_posinv_expr()) return false; |
10712 | 10872 |
10713 for (xpath_ast_node* n = _right; n; n = n->_next) | 10873 for (xpath_ast_node* n = _right; n; n = n->_next) |
10714 if (!n->is_posinv_expr()) return false; | 10874 if (!n->is_posinv_expr()) return false; |
10715 | 10875 |
10716 return true; | 10876 return true; |
10717 } | 10877 } |
10718 } | 10878 } |
10719 | 10879 |
10720 bool is_posinv_step() const | 10880 bool is_posinv_step() const |
10804 | 10964 |
10805 xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) | 10965 xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2]) |
10806 { | 10966 { |
10807 assert(argc <= 1); | 10967 assert(argc <= 1); |
10808 | 10968 |
10809 if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); | 10969 if (argc == 1 && args[0]->rettype() != xpath_type_node_set) |
10970 throw_error("Function has to be applied to node set"); | |
10810 | 10971 |
10811 return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); | 10972 return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]); |
10812 } | 10973 } |
10813 | 10974 |
10814 xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) | 10975 xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2]) |
10816 switch (name.begin[0]) | 10977 switch (name.begin[0]) |
10817 { | 10978 { |
10818 case 'b': | 10979 case 'b': |
10819 if (name == PUGIXML_TEXT("boolean") && argc == 1) | 10980 if (name == PUGIXML_TEXT("boolean") && argc == 1) |
10820 return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); | 10981 return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]); |
10821 | 10982 |
10822 break; | 10983 break; |
10823 | 10984 |
10824 case 'c': | 10985 case 'c': |
10825 if (name == PUGIXML_TEXT("count") && argc == 1) | 10986 if (name == PUGIXML_TEXT("count") && argc == 1) |
10826 { | 10987 { |
10827 if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); | 10988 if (args[0]->rettype() != xpath_type_node_set) |
10989 throw_error("Function has to be applied to node set"); | |
10990 | |
10828 return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); | 10991 return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]); |
10829 } | 10992 } |
10830 else if (name == PUGIXML_TEXT("contains") && argc == 2) | 10993 else if (name == PUGIXML_TEXT("contains") && argc == 2) |
10831 return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); | 10994 return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]); |
10832 else if (name == PUGIXML_TEXT("concat") && argc >= 2) | 10995 else if (name == PUGIXML_TEXT("concat") && argc >= 2) |
10833 return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); | 10996 return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]); |
10834 else if (name == PUGIXML_TEXT("ceiling") && argc == 1) | 10997 else if (name == PUGIXML_TEXT("ceiling") && argc == 1) |
10835 return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); | 10998 return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]); |
10836 | 10999 |
10837 break; | 11000 break; |
10838 | 11001 |
10839 case 'f': | 11002 case 'f': |
10840 if (name == PUGIXML_TEXT("false") && argc == 0) | 11003 if (name == PUGIXML_TEXT("false") && argc == 0) |
10841 return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); | 11004 return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean); |
10842 else if (name == PUGIXML_TEXT("floor") && argc == 1) | 11005 else if (name == PUGIXML_TEXT("floor") && argc == 1) |
10843 return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); | 11006 return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]); |
10844 | 11007 |
10845 break; | 11008 break; |
10846 | 11009 |
10847 case 'i': | 11010 case 'i': |
10848 if (name == PUGIXML_TEXT("id") && argc == 1) | 11011 if (name == PUGIXML_TEXT("id") && argc == 1) |
10849 return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); | 11012 return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]); |
10850 | 11013 |
10851 break; | 11014 break; |
10852 | 11015 |
10853 case 'l': | 11016 case 'l': |
10854 if (name == PUGIXML_TEXT("last") && argc == 0) | 11017 if (name == PUGIXML_TEXT("last") && argc == 0) |
10855 return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); | 11018 return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number); |
10856 else if (name == PUGIXML_TEXT("lang") && argc == 1) | 11019 else if (name == PUGIXML_TEXT("lang") && argc == 1) |
10857 return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); | 11020 return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]); |
10858 else if (name == PUGIXML_TEXT("local-name") && argc <= 1) | 11021 else if (name == PUGIXML_TEXT("local-name") && argc <= 1) |
10859 return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); | 11022 return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args); |
10860 | 11023 |
10861 break; | 11024 break; |
10862 | 11025 |
10863 case 'n': | 11026 case 'n': |
10864 if (name == PUGIXML_TEXT("name") && argc <= 1) | 11027 if (name == PUGIXML_TEXT("name") && argc <= 1) |
10865 return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); | 11028 return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args); |
10866 else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) | 11029 else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1) |
10867 return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); | 11030 return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args); |
10869 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); | 11032 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]); |
10870 else if (name == PUGIXML_TEXT("not") && argc == 1) | 11033 else if (name == PUGIXML_TEXT("not") && argc == 1) |
10871 return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); | 11034 return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]); |
10872 else if (name == PUGIXML_TEXT("number") && argc <= 1) | 11035 else if (name == PUGIXML_TEXT("number") && argc <= 1) |
10873 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); | 11036 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]); |
10874 | 11037 |
10875 break; | 11038 break; |
10876 | 11039 |
10877 case 'p': | 11040 case 'p': |
10878 if (name == PUGIXML_TEXT("position") && argc == 0) | 11041 if (name == PUGIXML_TEXT("position") && argc == 0) |
10879 return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); | 11042 return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number); |
10880 | 11043 |
10881 break; | 11044 break; |
10882 | 11045 |
10883 case 'r': | 11046 case 'r': |
10884 if (name == PUGIXML_TEXT("round") && argc == 1) | 11047 if (name == PUGIXML_TEXT("round") && argc == 1) |
10885 return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); | 11048 return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]); |
10886 | 11049 |
10887 break; | 11050 break; |
10888 | 11051 |
10889 case 's': | 11052 case 's': |
10890 if (name == PUGIXML_TEXT("string") && argc <= 1) | 11053 if (name == PUGIXML_TEXT("string") && argc <= 1) |
10891 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); | 11054 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]); |
10892 else if (name == PUGIXML_TEXT("string-length") && argc <= 1) | 11055 else if (name == PUGIXML_TEXT("string-length") && argc <= 1) |
10893 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); | 11056 return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]); |
10904 if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); | 11067 if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set"); |
10905 return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); | 11068 return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]); |
10906 } | 11069 } |
10907 | 11070 |
10908 break; | 11071 break; |
10909 | 11072 |
10910 case 't': | 11073 case 't': |
10911 if (name == PUGIXML_TEXT("translate") && argc == 3) | 11074 if (name == PUGIXML_TEXT("translate") && argc == 3) |
10912 return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); | 11075 return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]); |
10913 else if (name == PUGIXML_TEXT("true") && argc == 0) | 11076 else if (name == PUGIXML_TEXT("true") && argc == 0) |
10914 return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); | 11077 return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean); |
10915 | 11078 |
10916 break; | 11079 break; |
10917 | 11080 |
10918 default: | 11081 default: |
10919 break; | 11082 break; |
10920 } | 11083 } |
10935 return axis_ancestor; | 11098 return axis_ancestor; |
10936 else if (name == PUGIXML_TEXT("ancestor-or-self")) | 11099 else if (name == PUGIXML_TEXT("ancestor-or-self")) |
10937 return axis_ancestor_or_self; | 11100 return axis_ancestor_or_self; |
10938 else if (name == PUGIXML_TEXT("attribute")) | 11101 else if (name == PUGIXML_TEXT("attribute")) |
10939 return axis_attribute; | 11102 return axis_attribute; |
10940 | 11103 |
10941 break; | 11104 break; |
10942 | 11105 |
10943 case 'c': | 11106 case 'c': |
10944 if (name == PUGIXML_TEXT("child")) | 11107 if (name == PUGIXML_TEXT("child")) |
10945 return axis_child; | 11108 return axis_child; |
10946 | 11109 |
10947 break; | 11110 break; |
10948 | 11111 |
10949 case 'd': | 11112 case 'd': |
10950 if (name == PUGIXML_TEXT("descendant")) | 11113 if (name == PUGIXML_TEXT("descendant")) |
10951 return axis_descendant; | 11114 return axis_descendant; |
10952 else if (name == PUGIXML_TEXT("descendant-or-self")) | 11115 else if (name == PUGIXML_TEXT("descendant-or-self")) |
10953 return axis_descendant_or_self; | 11116 return axis_descendant_or_self; |
10954 | 11117 |
10955 break; | 11118 break; |
10956 | 11119 |
10957 case 'f': | 11120 case 'f': |
10958 if (name == PUGIXML_TEXT("following")) | 11121 if (name == PUGIXML_TEXT("following")) |
10959 return axis_following; | 11122 return axis_following; |
10960 else if (name == PUGIXML_TEXT("following-sibling")) | 11123 else if (name == PUGIXML_TEXT("following-sibling")) |
10961 return axis_following_sibling; | 11124 return axis_following_sibling; |
10962 | 11125 |
10963 break; | 11126 break; |
10964 | 11127 |
10965 case 'n': | 11128 case 'n': |
10966 if (name == PUGIXML_TEXT("namespace")) | 11129 if (name == PUGIXML_TEXT("namespace")) |
10967 return axis_namespace; | 11130 return axis_namespace; |
10968 | 11131 |
10969 break; | 11132 break; |
10970 | 11133 |
10971 case 'p': | 11134 case 'p': |
10972 if (name == PUGIXML_TEXT("parent")) | 11135 if (name == PUGIXML_TEXT("parent")) |
10973 return axis_parent; | 11136 return axis_parent; |
10974 else if (name == PUGIXML_TEXT("preceding")) | 11137 else if (name == PUGIXML_TEXT("preceding")) |
10975 return axis_preceding; | 11138 return axis_preceding; |
10976 else if (name == PUGIXML_TEXT("preceding-sibling")) | 11139 else if (name == PUGIXML_TEXT("preceding-sibling")) |
10977 return axis_preceding_sibling; | 11140 return axis_preceding_sibling; |
10978 | 11141 |
10979 break; | 11142 break; |
10980 | 11143 |
10981 case 's': | 11144 case 's': |
10982 if (name == PUGIXML_TEXT("self")) | 11145 if (name == PUGIXML_TEXT("self")) |
10983 return axis_self; | 11146 return axis_self; |
10984 | 11147 |
10985 break; | 11148 break; |
10986 | 11149 |
10987 default: | 11150 default: |
10988 break; | 11151 break; |
10989 } | 11152 } |
11017 case 't': | 11180 case 't': |
11018 if (name == PUGIXML_TEXT("text")) | 11181 if (name == PUGIXML_TEXT("text")) |
11019 return nodetest_type_text; | 11182 return nodetest_type_text; |
11020 | 11183 |
11021 break; | 11184 break; |
11022 | 11185 |
11023 default: | 11186 default: |
11024 break; | 11187 break; |
11025 } | 11188 } |
11026 | 11189 |
11027 return nodetest_none; | 11190 return nodetest_none; |
11090 | 11253 |
11091 case lex_string: | 11254 case lex_string: |
11092 { | 11255 { |
11093 xpath_ast_node* args[2] = {0}; | 11256 xpath_ast_node* args[2] = {0}; |
11094 size_t argc = 0; | 11257 size_t argc = 0; |
11095 | 11258 |
11096 xpath_lexer_string function = _lexer.contents(); | 11259 xpath_lexer_string function = _lexer.contents(); |
11097 _lexer.next(); | 11260 _lexer.next(); |
11098 | 11261 |
11099 xpath_ast_node* last_arg = 0; | 11262 xpath_ast_node* last_arg = 0; |
11100 | 11263 |
11101 if (_lexer.current() != lex_open_brace) | 11264 if (_lexer.current() != lex_open_brace) |
11102 throw_error("Unrecognized function call"); | 11265 throw_error("Unrecognized function call"); |
11103 _lexer.next(); | 11266 _lexer.next(); |
11104 | 11267 |
11105 if (_lexer.current() != lex_close_brace) | 11268 if (_lexer.current() != lex_close_brace) |
11108 while (_lexer.current() != lex_close_brace) | 11271 while (_lexer.current() != lex_close_brace) |
11109 { | 11272 { |
11110 if (_lexer.current() != lex_comma) | 11273 if (_lexer.current() != lex_comma) |
11111 throw_error("No comma between function arguments"); | 11274 throw_error("No comma between function arguments"); |
11112 _lexer.next(); | 11275 _lexer.next(); |
11113 | 11276 |
11114 xpath_ast_node* n = parse_expression(); | 11277 xpath_ast_node* n = parse_expression(); |
11115 | 11278 |
11116 if (argc < 2) args[argc] = n; | 11279 if (argc < 2) args[argc] = n; |
11117 else last_arg->set_next(n); | 11280 else last_arg->set_next(n); |
11118 | 11281 |
11119 argc++; | 11282 argc++; |
11120 last_arg = n; | 11283 last_arg = n; |
11121 } | 11284 } |
11122 | 11285 |
11123 _lexer.next(); | 11286 _lexer.next(); |
11124 | 11287 |
11125 return parse_function(function, argc, args); | 11288 return parse_function(function, argc, args); |
11126 } | 11289 } |
11127 | 11290 |
11129 throw_error("Unrecognizable primary expression"); | 11292 throw_error("Unrecognizable primary expression"); |
11130 | 11293 |
11131 return 0; | 11294 return 0; |
11132 } | 11295 } |
11133 } | 11296 } |
11134 | 11297 |
11135 // FilterExpr ::= PrimaryExpr | FilterExpr Predicate | 11298 // FilterExpr ::= PrimaryExpr | FilterExpr Predicate |
11136 // Predicate ::= '[' PredicateExpr ']' | 11299 // Predicate ::= '[' PredicateExpr ']' |
11137 // PredicateExpr ::= Expr | 11300 // PredicateExpr ::= Expr |
11138 xpath_ast_node* parse_filter_expression() | 11301 xpath_ast_node* parse_filter_expression() |
11139 { | 11302 { |
11143 { | 11306 { |
11144 _lexer.next(); | 11307 _lexer.next(); |
11145 | 11308 |
11146 xpath_ast_node* expr = parse_expression(); | 11309 xpath_ast_node* expr = parse_expression(); |
11147 | 11310 |
11148 if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set"); | 11311 if (n->rettype() != xpath_type_node_set) |
11312 throw_error("Predicate has to be applied to node set"); | |
11149 | 11313 |
11150 n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default); | 11314 n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default); |
11151 | 11315 |
11152 if (_lexer.current() != lex_close_square_brace) | 11316 if (_lexer.current() != lex_close_square_brace) |
11153 throw_error("Unmatched square brace"); | 11317 throw_error("Unmatched square brace"); |
11154 | 11318 |
11155 _lexer.next(); | 11319 _lexer.next(); |
11156 } | 11320 } |
11157 | 11321 |
11158 return n; | 11322 return n; |
11159 } | 11323 } |
11160 | 11324 |
11161 // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep | 11325 // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep |
11162 // AxisSpecifier ::= AxisName '::' | '@'? | 11326 // AxisSpecifier ::= AxisName '::' | '@'? |
11163 // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' | 11327 // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')' |
11164 // NameTest ::= '*' | NCName ':' '*' | QName | 11328 // NameTest ::= '*' | NCName ':' '*' | QName |
11165 // AbbreviatedStep ::= '.' | '..' | 11329 // AbbreviatedStep ::= '.' | '..' |
11173 | 11337 |
11174 if (_lexer.current() == lex_axis_attribute) | 11338 if (_lexer.current() == lex_axis_attribute) |
11175 { | 11339 { |
11176 axis = axis_attribute; | 11340 axis = axis_attribute; |
11177 axis_specified = true; | 11341 axis_specified = true; |
11178 | 11342 |
11179 _lexer.next(); | 11343 _lexer.next(); |
11180 } | 11344 } |
11181 else if (_lexer.current() == lex_dot) | 11345 else if (_lexer.current() == lex_dot) |
11182 { | 11346 { |
11183 _lexer.next(); | 11347 _lexer.next(); |
11184 | 11348 |
11185 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); | 11349 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0); |
11186 } | 11350 } |
11187 else if (_lexer.current() == lex_double_dot) | 11351 else if (_lexer.current() == lex_double_dot) |
11188 { | 11352 { |
11189 _lexer.next(); | 11353 _lexer.next(); |
11190 | 11354 |
11191 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); | 11355 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0); |
11192 } | 11356 } |
11193 | 11357 |
11194 nodetest_t nt_type = nodetest_none; | 11358 nodetest_t nt_type = nodetest_none; |
11195 xpath_lexer_string nt_name; | 11359 xpath_lexer_string nt_name; |
11196 | 11360 |
11197 if (_lexer.current() == lex_string) | 11361 if (_lexer.current() == lex_string) |
11198 { | 11362 { |
11199 // node name test | 11363 // node name test |
11200 nt_name = _lexer.contents(); | 11364 nt_name = _lexer.contents(); |
11201 _lexer.next(); | 11365 _lexer.next(); |
11202 | 11366 |
11203 // was it an axis name? | 11367 // was it an axis name? |
11204 if (_lexer.current() == lex_double_colon) | 11368 if (_lexer.current() == lex_double_colon) |
11205 { | 11369 { |
11206 // parse axis name | 11370 // parse axis name |
11207 if (axis_specified) throw_error("Two axis specifiers in one step"); | 11371 if (axis_specified) |
11372 throw_error("Two axis specifiers in one step"); | |
11208 | 11373 |
11209 axis = parse_axis_name(nt_name, axis_specified); | 11374 axis = parse_axis_name(nt_name, axis_specified); |
11210 | 11375 |
11211 if (!axis_specified) throw_error("Unknown axis"); | 11376 if (!axis_specified) |
11377 throw_error("Unknown axis"); | |
11212 | 11378 |
11213 // read actual node test | 11379 // read actual node test |
11214 _lexer.next(); | 11380 _lexer.next(); |
11215 | 11381 |
11216 if (_lexer.current() == lex_multiply) | 11382 if (_lexer.current() == lex_multiply) |
11224 nt_name = _lexer.contents(); | 11390 nt_name = _lexer.contents(); |
11225 _lexer.next(); | 11391 _lexer.next(); |
11226 } | 11392 } |
11227 else throw_error("Unrecognized node test"); | 11393 else throw_error("Unrecognized node test"); |
11228 } | 11394 } |
11229 | 11395 |
11230 if (nt_type == nodetest_none) | 11396 if (nt_type == nodetest_none) |
11231 { | 11397 { |
11232 // node type test or processing-instruction | 11398 // node type test or processing-instruction |
11233 if (_lexer.current() == lex_open_brace) | 11399 if (_lexer.current() == lex_open_brace) |
11234 { | 11400 { |
11235 _lexer.next(); | 11401 _lexer.next(); |
11236 | 11402 |
11237 if (_lexer.current() == lex_close_brace) | 11403 if (_lexer.current() == lex_close_brace) |
11238 { | 11404 { |
11239 _lexer.next(); | 11405 _lexer.next(); |
11240 | 11406 |
11241 nt_type = parse_node_test_type(nt_name); | 11407 nt_type = parse_node_test_type(nt_name); |
11242 | 11408 |
11243 if (nt_type == nodetest_none) throw_error("Unrecognized node type"); | 11409 if (nt_type == nodetest_none) |
11244 | 11410 throw_error("Unrecognized node type"); |
11411 | |
11245 nt_name = xpath_lexer_string(); | 11412 nt_name = xpath_lexer_string(); |
11246 } | 11413 } |
11247 else if (nt_name == PUGIXML_TEXT("processing-instruction")) | 11414 else if (nt_name == PUGIXML_TEXT("processing-instruction")) |
11248 { | 11415 { |
11249 if (_lexer.current() != lex_quoted_string) | 11416 if (_lexer.current() != lex_quoted_string) |
11250 throw_error("Only literals are allowed as arguments to processing-instruction()"); | 11417 throw_error("Only literals are allowed as arguments to processing-instruction()"); |
11251 | 11418 |
11252 nt_type = nodetest_pi; | 11419 nt_type = nodetest_pi; |
11253 nt_name = _lexer.contents(); | 11420 nt_name = _lexer.contents(); |
11254 _lexer.next(); | 11421 _lexer.next(); |
11255 | 11422 |
11256 if (_lexer.current() != lex_close_brace) | 11423 if (_lexer.current() != lex_close_brace) |
11257 throw_error("Unmatched brace near processing-instruction()"); | 11424 throw_error("Unmatched brace near processing-instruction()"); |
11258 _lexer.next(); | 11425 _lexer.next(); |
11259 } | 11426 } |
11260 else | 11427 else |
11428 { | |
11261 throw_error("Unmatched brace near node type test"); | 11429 throw_error("Unmatched brace near node type test"); |
11262 | 11430 } |
11263 } | 11431 } |
11264 // QName or NCName:* | 11432 // QName or NCName:* |
11265 else | 11433 else |
11266 { | 11434 { |
11267 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* | 11435 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:* |
11268 { | 11436 { |
11269 nt_name.end--; // erase * | 11437 nt_name.end--; // erase * |
11270 | 11438 |
11271 nt_type = nodetest_all_in_namespace; | 11439 nt_type = nodetest_all_in_namespace; |
11272 } | 11440 } |
11273 else nt_type = nodetest_name; | 11441 else |
11442 { | |
11443 nt_type = nodetest_name; | |
11444 } | |
11274 } | 11445 } |
11275 } | 11446 } |
11276 } | 11447 } |
11277 else if (_lexer.current() == lex_multiply) | 11448 else if (_lexer.current() == lex_multiply) |
11278 { | 11449 { |
11279 nt_type = nodetest_all; | 11450 nt_type = nodetest_all; |
11280 _lexer.next(); | 11451 _lexer.next(); |
11281 } | 11452 } |
11282 else throw_error("Unrecognized node test"); | 11453 else |
11283 | 11454 { |
11284 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name)); | 11455 throw_error("Unrecognized node test"); |
11285 | 11456 } |
11457 | |
11458 const char_t* nt_name_copy = alloc_string(nt_name); | |
11459 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, nt_name_copy); | |
11460 | |
11286 xpath_ast_node* last = 0; | 11461 xpath_ast_node* last = 0; |
11287 | 11462 |
11288 while (_lexer.current() == lex_open_square_brace) | 11463 while (_lexer.current() == lex_open_square_brace) |
11289 { | 11464 { |
11290 _lexer.next(); | 11465 _lexer.next(); |
11291 | 11466 |
11292 xpath_ast_node* expr = parse_expression(); | 11467 xpath_ast_node* expr = parse_expression(); |
11293 | 11468 |
11294 xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default); | 11469 xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default); |
11295 | 11470 |
11296 if (_lexer.current() != lex_close_square_brace) | 11471 if (_lexer.current() != lex_close_square_brace) |
11297 throw_error("Unmatched square brace"); | 11472 throw_error("Unmatched square brace"); |
11298 _lexer.next(); | 11473 _lexer.next(); |
11299 | 11474 |
11300 if (last) last->set_next(pred); | 11475 if (last) last->set_next(pred); |
11301 else n->set_right(pred); | 11476 else n->set_right(pred); |
11302 | 11477 |
11303 last = pred; | 11478 last = pred; |
11304 } | 11479 } |
11305 | 11480 |
11306 return n; | 11481 return n; |
11307 } | 11482 } |
11308 | 11483 |
11309 // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step | 11484 // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step |
11310 xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) | 11485 xpath_ast_node* parse_relative_location_path(xpath_ast_node* set) |
11311 { | 11486 { |
11312 xpath_ast_node* n = parse_step(set); | 11487 xpath_ast_node* n = parse_step(set); |
11313 | 11488 |
11314 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) | 11489 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) |
11315 { | 11490 { |
11316 lexeme_t l = _lexer.current(); | 11491 lexeme_t l = _lexer.current(); |
11317 _lexer.next(); | 11492 _lexer.next(); |
11318 | 11493 |
11319 if (l == lex_double_slash) | 11494 if (l == lex_double_slash) |
11320 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); | 11495 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); |
11321 | 11496 |
11322 n = parse_step(n); | 11497 n = parse_step(n); |
11323 } | 11498 } |
11324 | 11499 |
11325 return n; | 11500 return n; |
11326 } | 11501 } |
11327 | 11502 |
11328 // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath | 11503 // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath |
11329 // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath | 11504 // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath |
11330 xpath_ast_node* parse_location_path() | 11505 xpath_ast_node* parse_location_path() |
11331 { | 11506 { |
11332 if (_lexer.current() == lex_slash) | 11507 if (_lexer.current() == lex_slash) |
11333 { | 11508 { |
11334 _lexer.next(); | 11509 _lexer.next(); |
11335 | 11510 |
11336 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); | 11511 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); |
11337 | 11512 |
11338 // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path | 11513 // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path |
11339 lexeme_t l = _lexer.current(); | 11514 lexeme_t l = _lexer.current(); |
11340 | 11515 |
11344 return n; | 11519 return n; |
11345 } | 11520 } |
11346 else if (_lexer.current() == lex_double_slash) | 11521 else if (_lexer.current() == lex_double_slash) |
11347 { | 11522 { |
11348 _lexer.next(); | 11523 _lexer.next(); |
11349 | 11524 |
11350 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); | 11525 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set); |
11351 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); | 11526 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); |
11352 | 11527 |
11353 return parse_relative_location_path(n); | 11528 return parse_relative_location_path(n); |
11354 } | 11529 } |
11355 | 11530 |
11356 // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 | 11531 // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1 |
11357 return parse_relative_location_path(0); | 11532 return parse_relative_location_path(0); |
11358 } | 11533 } |
11359 | 11534 |
11360 // PathExpr ::= LocationPath | 11535 // PathExpr ::= LocationPath |
11361 // | FilterExpr | 11536 // | FilterExpr |
11362 // | FilterExpr '/' RelativeLocationPath | 11537 // | FilterExpr '/' RelativeLocationPath |
11363 // | FilterExpr '//' RelativeLocationPath | 11538 // | FilterExpr '//' RelativeLocationPath |
11364 // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr | 11539 // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr |
11370 // FilterExpr begins with PrimaryExpr | 11545 // FilterExpr begins with PrimaryExpr |
11371 // PrimaryExpr begins with '$' in case of it being a variable reference, | 11546 // PrimaryExpr begins with '$' in case of it being a variable reference, |
11372 // '(' in case of it being an expression, string literal, number constant or | 11547 // '(' in case of it being an expression, string literal, number constant or |
11373 // function call. | 11548 // function call. |
11374 | 11549 |
11375 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || | 11550 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || |
11376 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || | 11551 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number || |
11377 _lexer.current() == lex_string) | 11552 _lexer.current() == lex_string) |
11378 { | 11553 { |
11379 if (_lexer.current() == lex_string) | 11554 if (_lexer.current() == lex_string) |
11380 { | 11555 { |
11381 // This is either a function call, or not - if not, we shall proceed with location path | 11556 // This is either a function call, or not - if not, we shall proceed with location path |
11382 const char_t* state = _lexer.state(); | 11557 const char_t* state = _lexer.state(); |
11383 | 11558 |
11384 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; | 11559 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state; |
11385 | 11560 |
11386 if (*state != '(') return parse_location_path(); | 11561 if (*state != '(') return parse_location_path(); |
11387 | 11562 |
11388 // This looks like a function call; however this still can be a node-test. Check it. | 11563 // This looks like a function call; however this still can be a node-test. Check it. |
11389 if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path(); | 11564 if (parse_node_test_type(_lexer.contents()) != nodetest_none) |
11390 } | 11565 return parse_location_path(); |
11391 | 11566 } |
11567 | |
11392 xpath_ast_node* n = parse_filter_expression(); | 11568 xpath_ast_node* n = parse_filter_expression(); |
11393 | 11569 |
11394 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) | 11570 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash) |
11395 { | 11571 { |
11396 lexeme_t l = _lexer.current(); | 11572 lexeme_t l = _lexer.current(); |
11397 _lexer.next(); | 11573 _lexer.next(); |
11398 | 11574 |
11399 if (l == lex_double_slash) | 11575 if (l == lex_double_slash) |
11400 { | 11576 { |
11401 if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set"); | 11577 if (n->rettype() != xpath_type_node_set) |
11578 throw_error("Step has to be applied to node set"); | |
11402 | 11579 |
11403 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); | 11580 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0); |
11404 } | 11581 } |
11405 | 11582 |
11406 // select from location path | 11583 // select from location path |
11407 return parse_relative_location_path(n); | 11584 return parse_relative_location_path(n); |
11408 } | 11585 } |
11409 | 11586 |
11410 return n; | 11587 return n; |
11417 xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7); | 11594 xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7); |
11418 | 11595 |
11419 return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); | 11596 return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr); |
11420 } | 11597 } |
11421 else | 11598 else |
11599 { | |
11422 return parse_location_path(); | 11600 return parse_location_path(); |
11601 } | |
11423 } | 11602 } |
11424 | 11603 |
11425 struct binary_op_t | 11604 struct binary_op_t |
11426 { | 11605 { |
11427 ast_type_t asttype; | 11606 ast_type_t asttype; |
11546 } | 11725 } |
11547 | 11726 |
11548 xpath_ast_node* parse() | 11727 xpath_ast_node* parse() |
11549 { | 11728 { |
11550 xpath_ast_node* result = parse_expression(); | 11729 xpath_ast_node* result = parse_expression(); |
11551 | 11730 |
11731 // check if there are unparsed tokens left | |
11552 if (_lexer.current() != lex_eof) | 11732 if (_lexer.current() != lex_eof) |
11553 { | |
11554 // there are still unparsed tokens left, error | |
11555 throw_error("Incorrect query"); | 11733 throw_error("Incorrect query"); |
11556 } | 11734 |
11557 | |
11558 return result; | 11735 return result; |
11559 } | 11736 } |
11560 | 11737 |
11561 static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) | 11738 static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result) |
11562 { | 11739 { |
11640 #ifndef PUGIXML_NO_EXCEPTIONS | 11817 #ifndef PUGIXML_NO_EXCEPTIONS |
11641 PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) | 11818 PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_) |
11642 { | 11819 { |
11643 assert(_result.error); | 11820 assert(_result.error); |
11644 } | 11821 } |
11645 | 11822 |
11646 PUGI__FN const char* xpath_exception::what() const throw() | 11823 PUGI__FN const char* xpath_exception::what() const throw() |
11647 { | 11824 { |
11648 return _result.error; | 11825 return _result.error; |
11649 } | 11826 } |
11650 | 11827 |
11651 PUGI__FN const xpath_parse_result& xpath_exception::result() const | 11828 PUGI__FN const xpath_parse_result& xpath_exception::result() const |
11652 { | 11829 { |
11653 return _result; | 11830 return _result; |
11654 } | 11831 } |
11655 #endif | 11832 #endif |
11656 | 11833 |
11657 PUGI__FN xpath_node::xpath_node() | 11834 PUGI__FN xpath_node::xpath_node() |
11658 { | 11835 { |
11659 } | 11836 } |
11660 | 11837 |
11661 PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) | 11838 PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_) |
11662 { | 11839 { |
11663 } | 11840 } |
11664 | 11841 |
11665 PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) | 11842 PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_) |
11666 { | 11843 { |
11667 } | 11844 } |
11668 | 11845 |
11669 PUGI__FN xml_node xpath_node::node() const | 11846 PUGI__FN xml_node xpath_node::node() const |
11670 { | 11847 { |
11671 return _attribute ? xml_node() : _node; | 11848 return _attribute ? xml_node() : _node; |
11672 } | 11849 } |
11673 | 11850 |
11674 PUGI__FN xml_attribute xpath_node::attribute() const | 11851 PUGI__FN xml_attribute xpath_node::attribute() const |
11675 { | 11852 { |
11676 return _attribute; | 11853 return _attribute; |
11677 } | 11854 } |
11678 | 11855 |
11679 PUGI__FN xml_node xpath_node::parent() const | 11856 PUGI__FN xml_node xpath_node::parent() const |
11680 { | 11857 { |
11681 return _attribute ? _node : _node.parent(); | 11858 return _attribute ? _node : _node.parent(); |
11682 } | 11859 } |
11683 | 11860 |
11687 | 11864 |
11688 PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const | 11865 PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const |
11689 { | 11866 { |
11690 return (_node || _attribute) ? unspecified_bool_xpath_node : 0; | 11867 return (_node || _attribute) ? unspecified_bool_xpath_node : 0; |
11691 } | 11868 } |
11692 | 11869 |
11693 PUGI__FN bool xpath_node::operator!() const | 11870 PUGI__FN bool xpath_node::operator!() const |
11694 { | 11871 { |
11695 return !(_node || _attribute); | 11872 return !(_node || _attribute); |
11696 } | 11873 } |
11697 | 11874 |
11698 PUGI__FN bool xpath_node::operator==(const xpath_node& n) const | 11875 PUGI__FN bool xpath_node::operator==(const xpath_node& n) const |
11699 { | 11876 { |
11700 return _node == n._node && _attribute == n._attribute; | 11877 return _node == n._node && _attribute == n._attribute; |
11701 } | 11878 } |
11702 | 11879 |
11703 PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const | 11880 PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const |
11704 { | 11881 { |
11705 return _node != n._node || _attribute != n._attribute; | 11882 return _node != n._node || _attribute != n._attribute; |
11706 } | 11883 } |
11707 | 11884 |
11748 throw std::bad_alloc(); | 11925 throw std::bad_alloc(); |
11749 #endif | 11926 #endif |
11750 } | 11927 } |
11751 | 11928 |
11752 memcpy(storage, begin_, size_ * sizeof(xpath_node)); | 11929 memcpy(storage, begin_, size_ * sizeof(xpath_node)); |
11753 | 11930 |
11754 // deallocate old buffer | 11931 // deallocate old buffer |
11755 if (_begin != &_storage) impl::xml_memory::deallocate(_begin); | 11932 if (_begin != &_storage) impl::xml_memory::deallocate(_begin); |
11756 | 11933 |
11757 // finalize | 11934 // finalize |
11758 _begin = storage; | 11935 _begin = storage; |
11759 _end = storage + size_; | 11936 _end = storage + size_; |
11760 _type = type_; | 11937 _type = type_; |
11761 } | 11938 } |
11762 } | 11939 } |
11763 | 11940 |
11764 #if __cplusplus >= 201103 | 11941 #ifdef PUGIXML_HAS_MOVE |
11765 PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) | 11942 PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) |
11766 { | 11943 { |
11767 _type = rhs._type; | 11944 _type = rhs._type; |
11768 _storage = rhs._storage; | 11945 _storage = rhs._storage; |
11769 _begin = (rhs._begin == &rhs._storage) ? &_storage : rhs._begin; | 11946 _begin = (rhs._begin == &rhs._storage) ? &_storage : rhs._begin; |
11787 PUGI__FN xpath_node_set::~xpath_node_set() | 11964 PUGI__FN xpath_node_set::~xpath_node_set() |
11788 { | 11965 { |
11789 if (_begin != &_storage) | 11966 if (_begin != &_storage) |
11790 impl::xml_memory::deallocate(_begin); | 11967 impl::xml_memory::deallocate(_begin); |
11791 } | 11968 } |
11792 | 11969 |
11793 PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage) | 11970 PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage) |
11794 { | 11971 { |
11795 _assign(ns._begin, ns._end, ns._type); | 11972 _assign(ns._begin, ns._end, ns._type); |
11796 } | 11973 } |
11797 | 11974 |
11798 PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) | 11975 PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns) |
11799 { | 11976 { |
11800 if (this == &ns) return *this; | 11977 if (this == &ns) return *this; |
11801 | 11978 |
11802 _assign(ns._begin, ns._end, ns._type); | 11979 _assign(ns._begin, ns._end, ns._type); |
11803 | 11980 |
11804 return *this; | 11981 return *this; |
11805 } | 11982 } |
11806 | 11983 |
11807 #if __cplusplus >= 201103 | 11984 #ifdef PUGIXML_HAS_MOVE |
11808 PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs): _type(type_unsorted), _begin(&_storage), _end(&_storage) | 11985 PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs): _type(type_unsorted), _begin(&_storage), _end(&_storage) |
11809 { | 11986 { |
11810 _move(rhs); | 11987 _move(rhs); |
11811 } | 11988 } |
11812 | 11989 |
11825 | 12002 |
11826 PUGI__FN xpath_node_set::type_t xpath_node_set::type() const | 12003 PUGI__FN xpath_node_set::type_t xpath_node_set::type() const |
11827 { | 12004 { |
11828 return _type; | 12005 return _type; |
11829 } | 12006 } |
11830 | 12007 |
11831 PUGI__FN size_t xpath_node_set::size() const | 12008 PUGI__FN size_t xpath_node_set::size() const |
11832 { | 12009 { |
11833 return _end - _begin; | 12010 return _end - _begin; |
11834 } | 12011 } |
11835 | 12012 |
11836 PUGI__FN bool xpath_node_set::empty() const | 12013 PUGI__FN bool xpath_node_set::empty() const |
11837 { | 12014 { |
11838 return _begin == _end; | 12015 return _begin == _end; |
11839 } | 12016 } |
11840 | 12017 |
11841 PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const | 12018 PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const |
11842 { | 12019 { |
11843 assert(index < size()); | 12020 assert(index < size()); |
11844 return _begin[index]; | 12021 return _begin[index]; |
11845 } | 12022 } |
11846 | 12023 |
11847 PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const | 12024 PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const |
11848 { | 12025 { |
11849 return _begin; | 12026 return _begin; |
11850 } | 12027 } |
11851 | 12028 |
11852 PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const | 12029 PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const |
11853 { | 12030 { |
11854 return _end; | 12031 return _end; |
11855 } | 12032 } |
11856 | 12033 |
11857 PUGI__FN void xpath_node_set::sort(bool reverse) | 12034 PUGI__FN void xpath_node_set::sort(bool reverse) |
11858 { | 12035 { |
11859 _type = impl::xpath_sort(_begin, _end, _type, reverse); | 12036 _type = impl::xpath_sort(_begin, _end, _type, reverse); |
11860 } | 12037 } |
11861 | 12038 |
11897 | 12074 |
11898 case xpath_type_boolean: | 12075 case xpath_type_boolean: |
11899 return static_cast<const impl::xpath_variable_boolean*>(this)->name; | 12076 return static_cast<const impl::xpath_variable_boolean*>(this)->name; |
11900 | 12077 |
11901 default: | 12078 default: |
11902 assert(!"Invalid variable type"); | 12079 assert(false && "Invalid variable type"); |
11903 return 0; | 12080 return 0; |
11904 } | 12081 } |
11905 } | 12082 } |
11906 | 12083 |
11907 PUGI__FN xpath_value_type xpath_variable::type() const | 12084 PUGI__FN xpath_value_type xpath_variable::type() const |
12002 _assign(rhs); | 12179 _assign(rhs); |
12003 | 12180 |
12004 return *this; | 12181 return *this; |
12005 } | 12182 } |
12006 | 12183 |
12007 #if __cplusplus >= 201103 | 12184 #ifdef PUGIXML_HAS_MOVE |
12008 PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) | 12185 PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) |
12009 { | 12186 { |
12010 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) | 12187 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) |
12011 { | 12188 { |
12012 _data[i] = rhs._data[i]; | 12189 _data[i] = rhs._data[i]; |
12196 { | 12373 { |
12197 if (_impl) | 12374 if (_impl) |
12198 impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl)); | 12375 impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl)); |
12199 } | 12376 } |
12200 | 12377 |
12201 #if __cplusplus >= 201103 | 12378 #ifdef PUGIXML_HAS_MOVE |
12202 PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) | 12379 PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) |
12203 { | 12380 { |
12204 _impl = rhs._impl; | 12381 _impl = rhs._impl; |
12205 _result = rhs._result; | 12382 _result = rhs._result; |
12206 rhs._impl = 0; | 12383 rhs._impl = 0; |
12231 } | 12408 } |
12232 | 12409 |
12233 PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const | 12410 PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const |
12234 { | 12411 { |
12235 if (!_impl) return false; | 12412 if (!_impl) return false; |
12236 | 12413 |
12237 impl::xpath_context c(n, 1, 1); | 12414 impl::xpath_context c(n, 1, 1); |
12238 impl::xpath_stack_data sd; | 12415 impl::xpath_stack_data sd; |
12239 | 12416 |
12240 #ifdef PUGIXML_NO_EXCEPTIONS | 12417 #ifdef PUGIXML_NO_EXCEPTIONS |
12241 if (setjmp(sd.error_handler)) return false; | 12418 if (setjmp(sd.error_handler)) return false; |
12242 #endif | 12419 #endif |
12243 | 12420 |
12244 return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack); | 12421 return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack); |
12245 } | 12422 } |
12246 | 12423 |
12247 PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const | 12424 PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const |
12248 { | 12425 { |
12249 if (!_impl) return impl::gen_nan(); | 12426 if (!_impl) return impl::gen_nan(); |
12250 | 12427 |
12251 impl::xpath_context c(n, 1, 1); | 12428 impl::xpath_context c(n, 1, 1); |
12252 impl::xpath_stack_data sd; | 12429 impl::xpath_stack_data sd; |
12253 | 12430 |
12254 #ifdef PUGIXML_NO_EXCEPTIONS | 12431 #ifdef PUGIXML_NO_EXCEPTIONS |
12255 if (setjmp(sd.error_handler)) return impl::gen_nan(); | 12432 if (setjmp(sd.error_handler)) return impl::gen_nan(); |
12274 impl::xpath_stack_data sd; | 12451 impl::xpath_stack_data sd; |
12275 | 12452 |
12276 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd); | 12453 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd); |
12277 | 12454 |
12278 size_t full_size = r.length() + 1; | 12455 size_t full_size = r.length() + 1; |
12279 | 12456 |
12280 if (capacity > 0) | 12457 if (capacity > 0) |
12281 { | 12458 { |
12282 size_t size = (full_size < capacity) ? full_size : capacity; | 12459 size_t size = (full_size < capacity) ? full_size : capacity; |
12283 assert(size > 0); | 12460 assert(size > 0); |
12284 | 12461 |
12285 memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); | 12462 memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t)); |
12286 buffer[size - 1] = 0; | 12463 buffer[size - 1] = 0; |
12287 } | 12464 } |
12288 | 12465 |
12289 return full_size; | 12466 return full_size; |
12290 } | 12467 } |
12291 | 12468 |
12292 PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const | 12469 PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const |
12293 { | 12470 { |
12396 #undef PUGI__MSVC_CRT_VERSION | 12573 #undef PUGI__MSVC_CRT_VERSION |
12397 #undef PUGI__NS_BEGIN | 12574 #undef PUGI__NS_BEGIN |
12398 #undef PUGI__NS_END | 12575 #undef PUGI__NS_END |
12399 #undef PUGI__FN | 12576 #undef PUGI__FN |
12400 #undef PUGI__FN_NO_INLINE | 12577 #undef PUGI__FN_NO_INLINE |
12578 #undef PUGI__GETHEADER_IMPL | |
12401 #undef PUGI__GETPAGE_IMPL | 12579 #undef PUGI__GETPAGE_IMPL |
12402 #undef PUGI__GETPAGE | 12580 #undef PUGI__GETPAGE |
12403 #undef PUGI__NODETYPE | 12581 #undef PUGI__NODETYPE |
12404 #undef PUGI__IS_CHARTYPE_IMPL | 12582 #undef PUGI__IS_CHARTYPE_IMPL |
12405 #undef PUGI__IS_CHARTYPE | 12583 #undef PUGI__IS_CHARTYPE |
12417 #undef PUGI__CHECK_ERROR | 12595 #undef PUGI__CHECK_ERROR |
12418 | 12596 |
12419 #endif | 12597 #endif |
12420 | 12598 |
12421 /** | 12599 /** |
12422 * Copyright (c) 2006-2015 Arseny Kapoulkine | 12600 * Copyright (c) 2006-2016 Arseny Kapoulkine |
12423 * | 12601 * |
12424 * Permission is hereby granted, free of charge, to any person | 12602 * Permission is hereby granted, free of charge, to any person |
12425 * obtaining a copy of this software and associated documentation | 12603 * obtaining a copy of this software and associated documentation |
12426 * files (the "Software"), to deal in the Software without | 12604 * files (the "Software"), to deal in the Software without |
12427 * restriction, including without limitation the rights to use, | 12605 * restriction, including without limitation the rights to use, |
12430 * Software is furnished to do so, subject to the following | 12608 * Software is furnished to do so, subject to the following |
12431 * conditions: | 12609 * conditions: |
12432 * | 12610 * |
12433 * The above copyright notice and this permission notice shall be | 12611 * The above copyright notice and this permission notice shall be |
12434 * included in all copies or substantial portions of the Software. | 12612 * included in all copies or substantial portions of the Software. |
12435 * | 12613 * |
12436 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | 12614 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
12437 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | 12615 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
12438 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | 12616 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
12439 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | 12617 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
12440 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | 12618 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |