00001
00014 #ifndef SOURCE_PUGIXML_CPP
00015 #define SOURCE_PUGIXML_CPP
00016
00017 #include "pugixml.hpp"
00018
00019 #include <stdlib.h>
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <assert.h>
00023 #include <limits.h>
00024
00025 #ifdef PUGIXML_WCHAR_MODE
00026 # include <wchar.h>
00027 #endif
00028
00029 #ifndef PUGIXML_NO_XPATH
00030 # include <math.h>
00031 # include <float.h>
00032 # ifdef PUGIXML_NO_EXCEPTIONS
00033 # include <setjmp.h>
00034 # endif
00035 #endif
00036
00037 #ifndef PUGIXML_NO_STL
00038 # include <istream>
00039 # include <ostream>
00040 # include <string>
00041 #endif
00042
00043
00044 #include <new>
00045
00046 #ifdef _MSC_VER
00047 # pragma warning(push)
00048 # pragma warning(disable: 4127) // conditional expression is constant
00049 # pragma warning(disable: 4324) // structure was padded due to __declspec(align())
00050 # pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
00051 # pragma warning(disable: 4702) // unreachable code
00052 # pragma warning(disable: 4996) // this function or variable may be unsafe
00053 # pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
00054 #endif
00055
00056 #ifdef __INTEL_COMPILER
00057 # pragma warning(disable: 177) // function was declared but never referenced
00058 # pragma warning(disable: 279) // controlling expression is constant
00059 # pragma warning(disable: 1478 1786) // function was declared "deprecated"
00060 # pragma warning(disable: 1684) // conversion from pointer to same-sized integral type
00061 #endif
00062
00063 #if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
00064 # pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away
00065 #endif
00066
00067 #ifdef __BORLANDC__
00068 # pragma option push
00069 # pragma warn -8008 // condition is always false
00070 # pragma warn -8066 // unreachable code
00071 #endif
00072
00073 #ifdef __SNC__
00074
00075 # pragma diag_suppress=178 // function was declared but never referenced
00076 # pragma diag_suppress=237 // controlling expression is constant
00077 #endif
00078
00079
00080 #if defined(_MSC_VER) && _MSC_VER >= 1300
00081 # define PUGI__NO_INLINE __declspec(noinline)
00082 #elif defined(__GNUC__)
00083 # define PUGI__NO_INLINE __attribute__((noinline))
00084 #else
00085 # define PUGI__NO_INLINE
00086 #endif
00087
00088
00089 #if defined(__GNUC__)
00090 # define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0)
00091 #else
00092 # define PUGI__UNLIKELY(cond) (cond)
00093 #endif
00094
00095
00096 #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
00097
00098
00099 #ifdef __DMC__
00100 # define PUGI__DMC_VOLATILE volatile
00101 #else
00102 # define PUGI__DMC_VOLATILE
00103 #endif
00104
00105
00106 #if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
00107 using std::memcpy;
00108 using std::memmove;
00109 using std::memset;
00110 #endif
00111
00112
00113 #if defined(_MSC_VER) && !defined(__S3E__)
00114 # define PUGI__MSVC_CRT_VERSION _MSC_VER
00115 #endif
00116
00117 #ifdef PUGIXML_HEADER_ONLY
00118 # define PUGI__NS_BEGIN namespace pugi { namespace impl {
00119 # define PUGI__NS_END } }
00120 # define PUGI__FN inline
00121 # define PUGI__FN_NO_INLINE inline
00122 #else
00123 # if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
00124 # define PUGI__NS_BEGIN namespace pugi { namespace impl {
00125 # define PUGI__NS_END } }
00126 # else
00127 # define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace {
00128 # define PUGI__NS_END } } }
00129 # endif
00130 # define PUGI__FN
00131 # define PUGI__FN_NO_INLINE PUGI__NO_INLINE
00132 #endif
00133
00134
00135 #if !defined(_MSC_VER) || _MSC_VER >= 1600
00136 # include <stdint.h>
00137 #else
00138 namespace pugi
00139 {
00140 # ifndef _UINTPTR_T_DEFINED
00141 typedef size_t uintptr_t;
00142 # endif
00143
00144 typedef unsigned __int8 uint8_t;
00145 typedef unsigned __int16 uint16_t;
00146 typedef unsigned __int32 uint32_t;
00147 }
00148 #endif
00149
00150
00151 PUGI__NS_BEGIN
00152 PUGI__FN void* default_allocate(size_t size)
00153 {
00154 return malloc(size);
00155 }
00156
00157 PUGI__FN void default_deallocate(void* ptr)
00158 {
00159 free(ptr);
00160 }
00161
00162 template <typename T>
00163 struct xml_memory_management_function_storage
00164 {
00165 static allocation_function allocate;
00166 static deallocation_function deallocate;
00167 };
00168
00169
00170
00171 template <typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate;
00172 template <typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;
00173
00174 typedef xml_memory_management_function_storage<int> xml_memory;
00175 PUGI__NS_END
00176
00177
00178 PUGI__NS_BEGIN
00179
00180 PUGI__FN size_t strlength(const char_t* s)
00181 {
00182 assert(s);
00183
00184 #ifdef PUGIXML_WCHAR_MODE
00185 return wcslen(s);
00186 #else
00187 return strlen(s);
00188 #endif
00189 }
00190
00191
00192 PUGI__FN bool strequal(const char_t* src, const char_t* dst)
00193 {
00194 assert(src && dst);
00195
00196 #ifdef PUGIXML_WCHAR_MODE
00197 return wcscmp(src, dst) == 0;
00198 #else
00199 return strcmp(src, dst) == 0;
00200 #endif
00201 }
00202
00203
00204 PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
00205 {
00206 for (size_t i = 0; i < count; ++i)
00207 if (lhs[i] != rhs[i])
00208 return false;
00209
00210 return lhs[count] == 0;
00211 }
00212
00213
00214 PUGI__FN size_t strlength_wide(const wchar_t* s)
00215 {
00216 assert(s);
00217
00218 #ifdef PUGIXML_WCHAR_MODE
00219 return wcslen(s);
00220 #else
00221 const wchar_t* end = s;
00222 while (*end) end++;
00223 return static_cast<size_t>(end - s);
00224 #endif
00225 }
00226 PUGI__NS_END
00227
00228
00229 PUGI__NS_BEGIN
00230 template <typename T, typename D = void(*)(T*)> struct auto_deleter
00231 {
00232 T* data;
00233 D deleter;
00234
00235 auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_)
00236 {
00237 }
00238
00239 ~auto_deleter()
00240 {
00241 if (data) deleter(data);
00242 }
00243
00244 T* release()
00245 {
00246 T* result = data;
00247 data = 0;
00248 return result;
00249 }
00250 };
00251 PUGI__NS_END
00252
00253 #ifdef PUGIXML_COMPACT
00254 PUGI__NS_BEGIN
00255 class compact_hash_table
00256 {
00257 public:
00258 compact_hash_table(): _items(0), _capacity(0), _count(0)
00259 {
00260 }
00261
00262 void clear()
00263 {
00264 if (_items)
00265 {
00266 xml_memory::deallocate(_items);
00267 _items = 0;
00268 _capacity = 0;
00269 _count = 0;
00270 }
00271 }
00272
00273 void** find(const void* key)
00274 {
00275 assert(key);
00276
00277 if (_capacity == 0) return 0;
00278
00279 size_t hashmod = _capacity - 1;
00280 size_t bucket = hash(key) & hashmod;
00281
00282 for (size_t probe = 0; probe <= hashmod; ++probe)
00283 {
00284 item_t& probe_item = _items[bucket];
00285
00286 if (probe_item.key == key)
00287 return &probe_item.value;
00288
00289 if (probe_item.key == 0)
00290 return 0;
00291
00292
00293 bucket = (bucket + probe + 1) & hashmod;
00294 }
00295
00296 assert(!"Hash table is full");
00297 return 0;
00298 }
00299
00300 void** insert(const void* key)
00301 {
00302 assert(key);
00303 assert(_capacity != 0 && _count < _capacity - _capacity / 4);
00304
00305 size_t hashmod = _capacity - 1;
00306 size_t bucket = hash(key) & hashmod;
00307
00308 for (size_t probe = 0; probe <= hashmod; ++probe)
00309 {
00310 item_t& probe_item = _items[bucket];
00311
00312 if (probe_item.key == 0)
00313 {
00314 probe_item.key = key;
00315 _count++;
00316 return &probe_item.value;
00317 }
00318
00319 if (probe_item.key == key)
00320 return &probe_item.value;
00321
00322
00323 bucket = (bucket + probe + 1) & hashmod;
00324 }
00325
00326 assert(!"Hash table is full");
00327 return 0;
00328 }
00329
00330 bool reserve()
00331 {
00332 if (_count + 16 >= _capacity - _capacity / 4)
00333 return rehash();
00334
00335 return true;
00336 }
00337
00338 private:
00339 struct item_t
00340 {
00341 const void* key;
00342 void* value;
00343 };
00344
00345 item_t* _items;
00346 size_t _capacity;
00347
00348 size_t _count;
00349
00350 bool rehash();
00351
00352 static unsigned int hash(const void* key)
00353 {
00354 unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key));
00355
00356
00357 h ^= h >> 16;
00358 h *= 0x85ebca6bu;
00359 h ^= h >> 13;
00360 h *= 0xc2b2ae35u;
00361 h ^= h >> 16;
00362
00363 return h;
00364 }
00365 };
00366
00367 PUGI__FN_NO_INLINE bool compact_hash_table::rehash()
00368 {
00369 compact_hash_table rt;
00370 rt._capacity = (_capacity == 0) ? 32 : _capacity * 2;
00371 rt._items = static_cast<item_t*>(xml_memory::allocate(sizeof(item_t) * rt._capacity));
00372
00373 if (!rt._items)
00374 return false;
00375
00376 memset(rt._items, 0, sizeof(item_t) * rt._capacity);
00377
00378 for (size_t i = 0; i < _capacity; ++i)
00379 if (_items[i].key)
00380 *rt.insert(_items[i].key) = _items[i].value;
00381
00382 if (_items)
00383 xml_memory::deallocate(_items);
00384
00385 _capacity = rt._capacity;
00386 _items = rt._items;
00387
00388 assert(_count == rt._count);
00389
00390 return true;
00391 }
00392
00393 PUGI__NS_END
00394 #endif
00395
00396 PUGI__NS_BEGIN
00397 static const size_t xml_memory_page_size =
00398 #ifdef PUGIXML_MEMORY_PAGE_SIZE
00399 PUGIXML_MEMORY_PAGE_SIZE
00400 #else
00401 32768
00402 #endif
00403 ;
00404
00405 #ifdef PUGIXML_COMPACT
00406 static const uintptr_t xml_memory_block_alignment = 4;
00407
00408 static const uintptr_t xml_memory_page_alignment = sizeof(void*);
00409 #else
00410 static const uintptr_t xml_memory_block_alignment = sizeof(void*);
00411
00412 static const uintptr_t xml_memory_page_alignment = 64;
00413 static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1);
00414 #endif
00415
00416
00417 static const uintptr_t xml_memory_page_contents_shared_mask = 32;
00418 static const uintptr_t xml_memory_page_name_allocated_mask = 16;
00419 static const uintptr_t xml_memory_page_value_allocated_mask = 8;
00420 static const uintptr_t xml_memory_page_type_mask = 7;
00421
00422
00423 static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask;
00424 static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask;
00425
00426 #ifdef PUGIXML_COMPACT
00427 #define PUGI__GETPAGE_IMPL(header) (header).get_page()
00428 #else
00429 #define PUGI__GETPAGE_IMPL(header) reinterpret_cast<impl::xml_memory_page*>((header) & impl::xml_memory_page_pointer_mask)
00430 #endif
00431
00432 #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header)
00433 #define PUGI__NODETYPE(n) static_cast<xml_node_type>(((n)->header & impl::xml_memory_page_type_mask) + 1)
00434
00435 struct xml_allocator;
00436
00437 struct xml_memory_page
00438 {
00439 static xml_memory_page* construct(void* memory)
00440 {
00441 xml_memory_page* result = static_cast<xml_memory_page*>(memory);
00442
00443 result->allocator = 0;
00444 result->prev = 0;
00445 result->next = 0;
00446 result->busy_size = 0;
00447 result->freed_size = 0;
00448
00449 #ifdef PUGIXML_COMPACT
00450 result->compact_string_base = 0;
00451 result->compact_shared_parent = 0;
00452 result->compact_page_marker = 0;
00453 #endif
00454
00455 return result;
00456 }
00457
00458 xml_allocator* allocator;
00459
00460 xml_memory_page* prev;
00461 xml_memory_page* next;
00462
00463 size_t busy_size;
00464 size_t freed_size;
00465
00466 #ifdef PUGIXML_COMPACT
00467 char_t* compact_string_base;
00468 void* compact_shared_parent;
00469 uint32_t* compact_page_marker;
00470 #endif
00471 };
00472
00473 struct xml_memory_string_header
00474 {
00475 uint16_t page_offset;
00476 uint16_t full_size;
00477 };
00478
00479 struct xml_allocator
00480 {
00481 xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
00482 {
00483 #ifdef PUGIXML_COMPACT
00484 _hash = 0;
00485 #endif
00486 }
00487
00488 xml_memory_page* allocate_page(size_t data_size)
00489 {
00490 size_t size = sizeof(xml_memory_page) + data_size;
00491
00492
00493 void* memory = xml_memory::allocate(size + xml_memory_page_alignment);
00494 if (!memory) return 0;
00495
00496
00497 char* page_memory = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1));
00498
00499
00500 xml_memory_page* page = xml_memory_page::construct(page_memory);
00501 assert(page);
00502
00503 page->allocator = _root->allocator;
00504
00505
00506 assert(page_memory > memory && page_memory - static_cast<char*>(memory) <= 127);
00507 page_memory[-1] = static_cast<char>(page_memory - static_cast<char*>(memory));
00508
00509 return page;
00510 }
00511
00512 static void deallocate_page(xml_memory_page* page)
00513 {
00514 char* page_memory = reinterpret_cast<char*>(page);
00515
00516 xml_memory::deallocate(page_memory - page_memory[-1]);
00517 }
00518
00519 void* allocate_memory_oob(size_t size, xml_memory_page*& out_page);
00520
00521 void* allocate_memory(size_t size, xml_memory_page*& out_page)
00522 {
00523 if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size))
00524 return allocate_memory_oob(size, out_page);
00525
00526 void* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size;
00527
00528 _busy_size += size;
00529
00530 out_page = _root;
00531
00532 return buf;
00533 }
00534
00535 #ifdef PUGIXML_COMPACT
00536 void* allocate_object(size_t size, xml_memory_page*& out_page)
00537 {
00538 void* result = allocate_memory(size + sizeof(uint32_t), out_page);
00539 if (!result) return 0;
00540
00541
00542 ptrdiff_t offset = static_cast<char*>(result) - reinterpret_cast<char*>(out_page->compact_page_marker);
00543
00544 if (PUGI__UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment))
00545 {
00546
00547 uint32_t* marker = static_cast<uint32_t*>(result);
00548
00549 *marker = static_cast<uint32_t>(reinterpret_cast<char*>(marker) - reinterpret_cast<char*>(out_page));
00550 out_page->compact_page_marker = marker;
00551
00552
00553
00554 out_page->freed_size += sizeof(uint32_t);
00555
00556 return marker + 1;
00557 }
00558 else
00559 {
00560
00561 _busy_size -= sizeof(uint32_t);
00562
00563 return result;
00564 }
00565 }
00566 #else
00567 void* allocate_object(size_t size, xml_memory_page*& out_page)
00568 {
00569 return allocate_memory(size, out_page);
00570 }
00571 #endif
00572
00573 void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
00574 {
00575 if (page == _root) page->busy_size = _busy_size;
00576
00577 assert(ptr >= reinterpret_cast<char*>(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast<char*>(page) + sizeof(xml_memory_page) + page->busy_size);
00578 (void)!ptr;
00579
00580 page->freed_size += size;
00581 assert(page->freed_size <= page->busy_size);
00582
00583 if (page->freed_size == page->busy_size)
00584 {
00585 if (page->next == 0)
00586 {
00587 assert(_root == page);
00588
00589
00590 page->busy_size = 0;
00591 page->freed_size = 0;
00592
00593 #ifdef PUGIXML_COMPACT
00594
00595 page->compact_string_base = 0;
00596 page->compact_shared_parent = 0;
00597 page->compact_page_marker = 0;
00598 #endif
00599
00600 _busy_size = 0;
00601 }
00602 else
00603 {
00604 assert(_root != page);
00605 assert(page->prev);
00606
00607
00608 page->prev->next = page->next;
00609 page->next->prev = page->prev;
00610
00611
00612 deallocate_page(page);
00613 }
00614 }
00615 }
00616
00617 char_t* allocate_string(size_t length)
00618 {
00619 static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment;
00620
00621 PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
00622
00623
00624 size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
00625
00626
00627 size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1);
00628
00629 xml_memory_page* page;
00630 xml_memory_string_header* header = static_cast<xml_memory_string_header*>(allocate_memory(full_size, page));
00631
00632 if (!header) return 0;
00633
00634
00635 ptrdiff_t page_offset = reinterpret_cast<char*>(header) - reinterpret_cast<char*>(page) - sizeof(xml_memory_page);
00636
00637 assert(page_offset % xml_memory_block_alignment == 0);
00638 assert(page_offset >= 0 && static_cast<size_t>(page_offset) < max_encoded_offset);
00639 header->page_offset = static_cast<uint16_t>(static_cast<size_t>(page_offset) / xml_memory_block_alignment);
00640
00641
00642 assert(full_size % xml_memory_block_alignment == 0);
00643 assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0));
00644 header->full_size = static_cast<uint16_t>(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0);
00645
00646
00647
00648 return static_cast<char_t*>(static_cast<void*>(header + 1));
00649 }
00650
00651 void deallocate_string(char_t* string)
00652 {
00653
00654
00655
00656
00657 xml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1;
00658 assert(header);
00659
00660
00661 size_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment;
00662 xml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset));
00663
00664
00665 size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment;
00666
00667 deallocate_memory(header, full_size, page);
00668 }
00669
00670 bool reserve()
00671 {
00672 #ifdef PUGIXML_COMPACT
00673 return _hash->reserve();
00674 #else
00675 return true;
00676 #endif
00677 }
00678
00679 xml_memory_page* _root;
00680 size_t _busy_size;
00681
00682 #ifdef PUGIXML_COMPACT
00683 compact_hash_table* _hash;
00684 #endif
00685 };
00686
00687 PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)
00688 {
00689 const size_t large_allocation_threshold = xml_memory_page_size / 4;
00690
00691 xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
00692 out_page = page;
00693
00694 if (!page) return 0;
00695
00696 if (size <= large_allocation_threshold)
00697 {
00698 _root->busy_size = _busy_size;
00699
00700
00701 page->prev = _root;
00702 _root->next = page;
00703 _root = page;
00704
00705 _busy_size = size;
00706 }
00707 else
00708 {
00709
00710
00711 assert(_root->prev);
00712
00713 page->prev = _root->prev;
00714 page->next = _root;
00715
00716 _root->prev->next = page;
00717 _root->prev = page;
00718
00719 page->busy_size = size;
00720 }
00721
00722 return reinterpret_cast<char*>(page) + sizeof(xml_memory_page);
00723 }
00724 PUGI__NS_END
00725
00726 #ifdef PUGIXML_COMPACT
00727 PUGI__NS_BEGIN
00728 static const uintptr_t compact_alignment_log2 = 2;
00729 static const uintptr_t compact_alignment = 1 << compact_alignment_log2;
00730
00731 class compact_header
00732 {
00733 public:
00734 compact_header(xml_memory_page* page, unsigned int flags)
00735 {
00736 PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
00737
00738 ptrdiff_t offset = (reinterpret_cast<char*>(this) - reinterpret_cast<char*>(page->compact_page_marker));
00739 assert(offset % compact_alignment == 0 && static_cast<uintptr_t>(offset) < 256 * compact_alignment);
00740
00741 _page = static_cast<unsigned char>(offset >> compact_alignment_log2);
00742 _flags = static_cast<unsigned char>(flags);
00743 }
00744
00745 void operator&=(uintptr_t mod)
00746 {
00747 _flags &= static_cast<unsigned char>(mod);
00748 }
00749
00750 void operator|=(uintptr_t mod)
00751 {
00752 _flags |= static_cast<unsigned char>(mod);
00753 }
00754
00755 uintptr_t operator&(uintptr_t mod) const
00756 {
00757 return _flags & mod;
00758 }
00759
00760 xml_memory_page* get_page() const
00761 {
00762
00763 const char* page_marker = reinterpret_cast<const char*>(this) - (_page << compact_alignment_log2);
00764 const char* page = page_marker - *reinterpret_cast<const uint32_t*>(static_cast<const void*>(page_marker));
00765
00766 return const_cast<xml_memory_page*>(reinterpret_cast<const xml_memory_page*>(static_cast<const void*>(page)));
00767 }
00768
00769 private:
00770 unsigned char _page;
00771 unsigned char _flags;
00772 };
00773
00774 PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset)
00775 {
00776 const compact_header* header = reinterpret_cast<const compact_header*>(static_cast<const char*>(object) - header_offset);
00777
00778 return header->get_page();
00779 }
00780
00781 template <int header_offset, typename T> PUGI__FN_NO_INLINE T* compact_get_value(const void* object)
00782 {
00783 return static_cast<T*>(*compact_get_page(object, header_offset)->allocator->_hash->find(object));
00784 }
00785
00786 template <int header_offset, typename T> PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value)
00787 {
00788 *compact_get_page(object, header_offset)->allocator->_hash->insert(object) = value;
00789 }
00790
00791 template <typename T, int header_offset, int start = -126> class compact_pointer
00792 {
00793 public:
00794 compact_pointer(): _data(0)
00795 {
00796 }
00797
00798 void operator=(const compact_pointer& rhs)
00799 {
00800 *this = rhs + 0;
00801 }
00802
00803 void operator=(T* value)
00804 {
00805 if (value)
00806 {
00807
00808
00809
00810
00811 ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
00812 ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start;
00813
00814 if (static_cast<uintptr_t>(offset) <= 253)
00815 _data = static_cast<unsigned char>(offset + 1);
00816 else
00817 {
00818 compact_set_value<header_offset>(this, value);
00819
00820 _data = 255;
00821 }
00822 }
00823 else
00824 _data = 0;
00825 }
00826
00827 operator T*() const
00828 {
00829 if (_data)
00830 {
00831 if (_data < 255)
00832 {
00833 uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
00834
00835 return reinterpret_cast<T*>(base + ((_data - 1 + start) << compact_alignment_log2));
00836 }
00837 else
00838 return compact_get_value<header_offset, T>(this);
00839 }
00840 else
00841 return 0;
00842 }
00843
00844 T* operator->() const
00845 {
00846 return *this;
00847 }
00848
00849 private:
00850 unsigned char _data;
00851 };
00852
00853 template <typename T, int header_offset> class compact_pointer_parent
00854 {
00855 public:
00856 compact_pointer_parent(): _data(0)
00857 {
00858 }
00859
00860 void operator=(const compact_pointer_parent& rhs)
00861 {
00862 *this = rhs + 0;
00863 }
00864
00865 void operator=(T* value)
00866 {
00867 if (value)
00868 {
00869
00870
00871
00872
00873 ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
00874 ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533;
00875
00876 if (static_cast<uintptr_t>(offset) <= 65533)
00877 {
00878 _data = static_cast<unsigned short>(offset + 1);
00879 }
00880 else
00881 {
00882 xml_memory_page* page = compact_get_page(this, header_offset);
00883
00884 if (PUGI__UNLIKELY(page->compact_shared_parent == 0))
00885 page->compact_shared_parent = value;
00886
00887 if (page->compact_shared_parent == value)
00888 {
00889 _data = 65534;
00890 }
00891 else
00892 {
00893 compact_set_value<header_offset>(this, value);
00894
00895 _data = 65535;
00896 }
00897 }
00898 }
00899 else
00900 {
00901 _data = 0;
00902 }
00903 }
00904
00905 operator T*() const
00906 {
00907 if (_data)
00908 {
00909 if (_data < 65534)
00910 {
00911 uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
00912
00913 return reinterpret_cast<T*>(base + ((_data - 1 - 65533) << compact_alignment_log2));
00914 }
00915 else if (_data == 65534)
00916 return static_cast<T*>(compact_get_page(this, header_offset)->compact_shared_parent);
00917 else
00918 return compact_get_value<header_offset, T>(this);
00919 }
00920 else
00921 return 0;
00922 }
00923
00924 T* operator->() const
00925 {
00926 return *this;
00927 }
00928
00929 private:
00930 uint16_t _data;
00931 };
00932
00933 template <int header_offset, int base_offset> class compact_string
00934 {
00935 public:
00936 compact_string(): _data(0)
00937 {
00938 }
00939
00940 void operator=(const compact_string& rhs)
00941 {
00942 *this = rhs + 0;
00943 }
00944
00945 void operator=(char_t* value)
00946 {
00947 if (value)
00948 {
00949 xml_memory_page* page = compact_get_page(this, header_offset);
00950
00951 if (PUGI__UNLIKELY(page->compact_string_base == 0))
00952 page->compact_string_base = value;
00953
00954 ptrdiff_t offset = value - page->compact_string_base;
00955
00956 if (static_cast<uintptr_t>(offset) < (65535 << 7))
00957 {
00958
00959 uint16_t* base = reinterpret_cast<uint16_t*>(static_cast<void*>(reinterpret_cast<char*>(this) - base_offset));
00960
00961 if (*base == 0)
00962 {
00963 *base = static_cast<uint16_t>((offset >> 7) + 1);
00964 _data = static_cast<unsigned char>((offset & 127) + 1);
00965 }
00966 else
00967 {
00968 ptrdiff_t remainder = offset - ((*base - 1) << 7);
00969
00970 if (static_cast<uintptr_t>(remainder) <= 253)
00971 {
00972 _data = static_cast<unsigned char>(remainder + 1);
00973 }
00974 else
00975 {
00976 compact_set_value<header_offset>(this, value);
00977
00978 _data = 255;
00979 }
00980 }
00981 }
00982 else
00983 {
00984 compact_set_value<header_offset>(this, value);
00985
00986 _data = 255;
00987 }
00988 }
00989 else
00990 {
00991 _data = 0;
00992 }
00993 }
00994
00995 operator char_t*() const
00996 {
00997 if (_data)
00998 {
00999 if (_data < 255)
01000 {
01001 xml_memory_page* page = compact_get_page(this, header_offset);
01002
01003
01004 const uint16_t* base = reinterpret_cast<const uint16_t*>(static_cast<const void*>(reinterpret_cast<const char*>(this) - base_offset));
01005 assert(*base);
01006
01007 ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);
01008
01009 return page->compact_string_base + offset;
01010 }
01011 else
01012 {
01013 return compact_get_value<header_offset, char_t>(this);
01014 }
01015 }
01016 else
01017 return 0;
01018 }
01019
01020 private:
01021 unsigned char _data;
01022 };
01023 PUGI__NS_END
01024 #endif
01025
01026 #ifdef PUGIXML_COMPACT
01027 namespace pugi
01028 {
01029 struct xml_attribute_struct
01030 {
01031 xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)
01032 {
01033 PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8);
01034 }
01035
01036 impl::compact_header header;
01037
01038 uint16_t namevalue_base;
01039
01040 impl::compact_string<4, 2> name;
01041 impl::compact_string<5, 3> value;
01042
01043 impl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c;
01044 impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute;
01045 };
01046
01047 struct xml_node_struct
01048 {
01049 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type - 1), namevalue_base(0)
01050 {
01051 PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12);
01052 }
01053
01054 impl::compact_header header;
01055
01056 uint16_t namevalue_base;
01057
01058 impl::compact_string<4, 2> name;
01059 impl::compact_string<5, 3> value;
01060
01061 impl::compact_pointer_parent<xml_node_struct, 6> parent;
01062
01063 impl::compact_pointer<xml_node_struct, 8, 0> first_child;
01064
01065 impl::compact_pointer<xml_node_struct, 9> prev_sibling_c;
01066 impl::compact_pointer<xml_node_struct, 10, 0> next_sibling;
01067
01068 impl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute;
01069 };
01070 }
01071 #else
01072 namespace pugi
01073 {
01074 struct xml_attribute_struct
01075 {
01076 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)
01077 {
01078 }
01079
01080 uintptr_t header;
01081
01082 char_t* name;
01083 char_t* value;
01084
01085 xml_attribute_struct* prev_attribute_c;
01086 xml_attribute_struct* next_attribute;
01087 };
01088
01089 struct xml_node_struct
01090 {
01091 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)
01092 {
01093 }
01094
01095 uintptr_t header;
01096
01097 char_t* name;
01098 char_t* value;
01099
01100 xml_node_struct* parent;
01101
01102 xml_node_struct* first_child;
01103
01104 xml_node_struct* prev_sibling_c;
01105 xml_node_struct* next_sibling;
01106
01107 xml_attribute_struct* first_attribute;
01108 };
01109 }
01110 #endif
01111
01112 PUGI__NS_BEGIN
01113 struct xml_extra_buffer
01114 {
01115 char_t* buffer;
01116 xml_extra_buffer* next;
01117 };
01118
01119 struct xml_document_struct: public xml_node_struct, public xml_allocator
01120 {
01121 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0)
01122 {
01123 #ifdef PUGIXML_COMPACT
01124 _hash = &hash;
01125 #endif
01126 }
01127
01128 const char_t* buffer;
01129
01130 xml_extra_buffer* extra_buffers;
01131
01132 #ifdef PUGIXML_COMPACT
01133 compact_hash_table hash;
01134 #endif
01135 };
01136
01137 template <typename Object> inline xml_allocator& get_allocator(const Object* object)
01138 {
01139 assert(object);
01140
01141 return *PUGI__GETPAGE(object)->allocator;
01142 }
01143
01144 template <typename Object> inline xml_document_struct& get_document(const Object* object)
01145 {
01146 assert(object);
01147
01148 return *static_cast<xml_document_struct*>(PUGI__GETPAGE(object)->allocator);
01149 }
01150 PUGI__NS_END
01151
01152
01153 PUGI__NS_BEGIN
01154 inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
01155 {
01156 xml_memory_page* page;
01157 void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page);
01158 if (!memory) return 0;
01159
01160 return new (memory) xml_attribute_struct(page);
01161 }
01162
01163 inline xml_node_struct* allocate_node(xml_allocator& alloc, xml_node_type type)
01164 {
01165 xml_memory_page* page;
01166 void* memory = alloc.allocate_object(sizeof(xml_node_struct), page);
01167 if (!memory) return 0;
01168
01169 return new (memory) xml_node_struct(page, type);
01170 }
01171
01172 inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
01173 {
01174 if (a->header & impl::xml_memory_page_name_allocated_mask)
01175 alloc.deallocate_string(a->name);
01176
01177 if (a->header & impl::xml_memory_page_value_allocated_mask)
01178 alloc.deallocate_string(a->value);
01179
01180 alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a));
01181 }
01182
01183 inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
01184 {
01185 if (n->header & impl::xml_memory_page_name_allocated_mask)
01186 alloc.deallocate_string(n->name);
01187
01188 if (n->header & impl::xml_memory_page_value_allocated_mask)
01189 alloc.deallocate_string(n->value);
01190
01191 for (xml_attribute_struct* attr = n->first_attribute; attr; )
01192 {
01193 xml_attribute_struct* next = attr->next_attribute;
01194
01195 destroy_attribute(attr, alloc);
01196
01197 attr = next;
01198 }
01199
01200 for (xml_node_struct* child = n->first_child; child; )
01201 {
01202 xml_node_struct* next = child->next_sibling;
01203
01204 destroy_node(child, alloc);
01205
01206 child = next;
01207 }
01208
01209 alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n));
01210 }
01211
01212 inline void append_node(xml_node_struct* child, xml_node_struct* node)
01213 {
01214 child->parent = node;
01215
01216 xml_node_struct* head = node->first_child;
01217
01218 if (head)
01219 {
01220 xml_node_struct* tail = head->prev_sibling_c;
01221
01222 tail->next_sibling = child;
01223 child->prev_sibling_c = tail;
01224 head->prev_sibling_c = child;
01225 }
01226 else
01227 {
01228 node->first_child = child;
01229 child->prev_sibling_c = child;
01230 }
01231 }
01232
01233 inline void prepend_node(xml_node_struct* child, xml_node_struct* node)
01234 {
01235 child->parent = node;
01236
01237 xml_node_struct* head = node->first_child;
01238
01239 if (head)
01240 {
01241 child->prev_sibling_c = head->prev_sibling_c;
01242 head->prev_sibling_c = child;
01243 }
01244 else
01245 child->prev_sibling_c = child;
01246
01247 child->next_sibling = head;
01248 node->first_child = child;
01249 }
01250
01251 inline void insert_node_after(xml_node_struct* child, xml_node_struct* node)
01252 {
01253 xml_node_struct* parent = node->parent;
01254
01255 child->parent = parent;
01256
01257 if (node->next_sibling)
01258 node->next_sibling->prev_sibling_c = child;
01259 else
01260 parent->first_child->prev_sibling_c = child;
01261
01262 child->next_sibling = node->next_sibling;
01263 child->prev_sibling_c = node;
01264
01265 node->next_sibling = child;
01266 }
01267
01268 inline void insert_node_before(xml_node_struct* child, xml_node_struct* node)
01269 {
01270 xml_node_struct* parent = node->parent;
01271
01272 child->parent = parent;
01273
01274 if (node->prev_sibling_c->next_sibling)
01275 node->prev_sibling_c->next_sibling = child;
01276 else
01277 parent->first_child = child;
01278
01279 child->prev_sibling_c = node->prev_sibling_c;
01280 child->next_sibling = node;
01281
01282 node->prev_sibling_c = child;
01283 }
01284
01285 inline void remove_node(xml_node_struct* node)
01286 {
01287 xml_node_struct* parent = node->parent;
01288
01289 if (node->next_sibling)
01290 node->next_sibling->prev_sibling_c = node->prev_sibling_c;
01291 else
01292 parent->first_child->prev_sibling_c = node->prev_sibling_c;
01293
01294 if (node->prev_sibling_c->next_sibling)
01295 node->prev_sibling_c->next_sibling = node->next_sibling;
01296 else
01297 parent->first_child = node->next_sibling;
01298
01299 node->parent = 0;
01300 node->prev_sibling_c = 0;
01301 node->next_sibling = 0;
01302 }
01303
01304 inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node)
01305 {
01306 xml_attribute_struct* head = node->first_attribute;
01307
01308 if (head)
01309 {
01310 xml_attribute_struct* tail = head->prev_attribute_c;
01311
01312 tail->next_attribute = attr;
01313 attr->prev_attribute_c = tail;
01314 head->prev_attribute_c = attr;
01315 }
01316 else
01317 {
01318 node->first_attribute = attr;
01319 attr->prev_attribute_c = attr;
01320 }
01321 }
01322
01323 inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node)
01324 {
01325 xml_attribute_struct* head = node->first_attribute;
01326
01327 if (head)
01328 {
01329 attr->prev_attribute_c = head->prev_attribute_c;
01330 head->prev_attribute_c = attr;
01331 }
01332 else
01333 attr->prev_attribute_c = attr;
01334
01335 attr->next_attribute = head;
01336 node->first_attribute = attr;
01337 }
01338
01339 inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
01340 {
01341 if (place->next_attribute)
01342 place->next_attribute->prev_attribute_c = attr;
01343 else
01344 node->first_attribute->prev_attribute_c = attr;
01345
01346 attr->next_attribute = place->next_attribute;
01347 attr->prev_attribute_c = place;
01348 place->next_attribute = attr;
01349 }
01350
01351 inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
01352 {
01353 if (place->prev_attribute_c->next_attribute)
01354 place->prev_attribute_c->next_attribute = attr;
01355 else
01356 node->first_attribute = attr;
01357
01358 attr->prev_attribute_c = place->prev_attribute_c;
01359 attr->next_attribute = place;
01360 place->prev_attribute_c = attr;
01361 }
01362
01363 inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node)
01364 {
01365 if (attr->next_attribute)
01366 attr->next_attribute->prev_attribute_c = attr->prev_attribute_c;
01367 else
01368 node->first_attribute->prev_attribute_c = attr->prev_attribute_c;
01369
01370 if (attr->prev_attribute_c->next_attribute)
01371 attr->prev_attribute_c->next_attribute = attr->next_attribute;
01372 else
01373 node->first_attribute = attr->next_attribute;
01374
01375 attr->prev_attribute_c = 0;
01376 attr->next_attribute = 0;
01377 }
01378
01379 PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
01380 {
01381 if (!alloc.reserve()) return 0;
01382
01383 xml_node_struct* child = allocate_node(alloc, type);
01384 if (!child) return 0;
01385
01386 append_node(child, node);
01387
01388 return child;
01389 }
01390
01391 PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)
01392 {
01393 if (!alloc.reserve()) return 0;
01394
01395 xml_attribute_struct* attr = allocate_attribute(alloc);
01396 if (!attr) return 0;
01397
01398 append_attribute(attr, node);
01399
01400 return attr;
01401 }
01402 PUGI__NS_END
01403
01404
01405 PUGI__NS_BEGIN
01406 struct opt_false
01407 {
01408 enum { value = 0 };
01409 };
01410
01411 struct opt_true
01412 {
01413 enum { value = 1 };
01414 };
01415 PUGI__NS_END
01416
01417
01418 PUGI__NS_BEGIN
01419 inline uint16_t endian_swap(uint16_t value)
01420 {
01421 return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
01422 }
01423
01424 inline uint32_t endian_swap(uint32_t value)
01425 {
01426 return ((value & 0xff) << 24) | ((value & 0xff00) << 8) | ((value & 0xff0000) >> 8) | (value >> 24);
01427 }
01428
01429 struct utf8_counter
01430 {
01431 typedef size_t value_type;
01432
01433 static value_type low(value_type result, uint32_t ch)
01434 {
01435
01436 if (ch < 0x80) return result + 1;
01437
01438 else if (ch < 0x800) return result + 2;
01439
01440 else return result + 3;
01441 }
01442
01443 static value_type high(value_type result, uint32_t)
01444 {
01445
01446 return result + 4;
01447 }
01448 };
01449
01450 struct utf8_writer
01451 {
01452 typedef uint8_t* value_type;
01453
01454 static value_type low(value_type result, uint32_t ch)
01455 {
01456
01457 if (ch < 0x80)
01458 {
01459 *result = static_cast<uint8_t>(ch);
01460 return result + 1;
01461 }
01462
01463 else if (ch < 0x800)
01464 {
01465 result[0] = static_cast<uint8_t>(0xC0 | (ch >> 6));
01466 result[1] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
01467 return result + 2;
01468 }
01469
01470 else
01471 {
01472 result[0] = static_cast<uint8_t>(0xE0 | (ch >> 12));
01473 result[1] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
01474 result[2] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
01475 return result + 3;
01476 }
01477 }
01478
01479 static value_type high(value_type result, uint32_t ch)
01480 {
01481
01482 result[0] = static_cast<uint8_t>(0xF0 | (ch >> 18));
01483 result[1] = static_cast<uint8_t>(0x80 | ((ch >> 12) & 0x3F));
01484 result[2] = static_cast<uint8_t>(0x80 | ((ch >> 6) & 0x3F));
01485 result[3] = static_cast<uint8_t>(0x80 | (ch & 0x3F));
01486 return result + 4;
01487 }
01488
01489 static value_type any(value_type result, uint32_t ch)
01490 {
01491 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
01492 }
01493 };
01494
01495 struct utf16_counter
01496 {
01497 typedef size_t value_type;
01498
01499 static value_type low(value_type result, uint32_t)
01500 {
01501 return result + 1;
01502 }
01503
01504 static value_type high(value_type result, uint32_t)
01505 {
01506 return result + 2;
01507 }
01508 };
01509
01510 struct utf16_writer
01511 {
01512 typedef uint16_t* value_type;
01513
01514 static value_type low(value_type result, uint32_t ch)
01515 {
01516 *result = static_cast<uint16_t>(ch);
01517
01518 return result + 1;
01519 }
01520
01521 static value_type high(value_type result, uint32_t ch)
01522 {
01523 uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10;
01524 uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff;
01525
01526 result[0] = static_cast<uint16_t>(0xD800 + msh);
01527 result[1] = static_cast<uint16_t>(0xDC00 + lsh);
01528
01529 return result + 2;
01530 }
01531
01532 static value_type any(value_type result, uint32_t ch)
01533 {
01534 return (ch < 0x10000) ? low(result, ch) : high(result, ch);
01535 }
01536 };
01537
01538 struct utf32_counter
01539 {
01540 typedef size_t value_type;
01541
01542 static value_type low(value_type result, uint32_t)
01543 {
01544 return result + 1;
01545 }
01546
01547 static value_type high(value_type result, uint32_t)
01548 {
01549 return result + 1;
01550 }
01551 };
01552
01553 struct utf32_writer
01554 {
01555 typedef uint32_t* value_type;
01556
01557 static value_type low(value_type result, uint32_t ch)
01558 {
01559 *result = ch;
01560
01561 return result + 1;
01562 }
01563
01564 static value_type high(value_type result, uint32_t ch)
01565 {
01566 *result = ch;
01567
01568 return result + 1;
01569 }
01570
01571 static value_type any(value_type result, uint32_t ch)
01572 {
01573 *result = ch;
01574
01575 return result + 1;
01576 }
01577 };
01578
01579 struct latin1_writer
01580 {
01581 typedef uint8_t* value_type;
01582
01583 static value_type low(value_type result, uint32_t ch)
01584 {
01585 *result = static_cast<uint8_t>(ch > 255 ? '?' : ch);
01586
01587 return result + 1;
01588 }
01589
01590 static value_type high(value_type result, uint32_t ch)
01591 {
01592 (void)ch;
01593
01594 *result = '?';
01595
01596 return result + 1;
01597 }
01598 };
01599
01600 struct utf8_decoder
01601 {
01602 typedef uint8_t type;
01603
01604 template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
01605 {
01606 const uint8_t utf8_byte_mask = 0x3f;
01607
01608 while (size)
01609 {
01610 uint8_t lead = *data;
01611
01612
01613 if (lead < 0x80)
01614 {
01615 result = Traits::low(result, lead);
01616 data += 1;
01617 size -= 1;
01618
01619
01620 if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
01621 {
01622
01623 while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)
01624 {
01625 result = Traits::low(result, data[0]);
01626 result = Traits::low(result, data[1]);
01627 result = Traits::low(result, data[2]);
01628 result = Traits::low(result, data[3]);
01629 data += 4;
01630 size -= 4;
01631 }
01632 }
01633 }
01634
01635 else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
01636 {
01637 result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
01638 data += 2;
01639 size -= 2;
01640 }
01641
01642 else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
01643 {
01644 result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
01645 data += 3;
01646 size -= 3;
01647 }
01648
01649 else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
01650 {
01651 result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
01652 data += 4;
01653 size -= 4;
01654 }
01655
01656 else
01657 {
01658 data += 1;
01659 size -= 1;
01660 }
01661 }
01662
01663 return result;
01664 }
01665 };
01666
01667 template <typename opt_swap> struct utf16_decoder
01668 {
01669 typedef uint16_t type;
01670
01671 template <typename Traits> static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits)
01672 {
01673 while (size)
01674 {
01675 uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
01676
01677
01678 if (lead < 0xD800)
01679 {
01680 result = Traits::low(result, lead);
01681 data += 1;
01682 size -= 1;
01683 }
01684
01685 else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
01686 {
01687 result = Traits::low(result, lead);
01688 data += 1;
01689 size -= 1;
01690 }
01691
01692 else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
01693 {
01694 uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
01695
01696 if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
01697 {
01698 result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
01699 data += 2;
01700 size -= 2;
01701 }
01702 else
01703 {
01704 data += 1;
01705 size -= 1;
01706 }
01707 }
01708 else
01709 {
01710 data += 1;
01711 size -= 1;
01712 }
01713 }
01714
01715 return result;
01716 }
01717 };
01718
01719 template <typename opt_swap> struct utf32_decoder
01720 {
01721 typedef uint32_t type;
01722
01723 template <typename Traits> static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits)
01724 {
01725 while (size)
01726 {
01727 uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
01728
01729
01730 if (lead < 0x10000)
01731 {
01732 result = Traits::low(result, lead);
01733 data += 1;
01734 size -= 1;
01735 }
01736
01737 else
01738 {
01739 result = Traits::high(result, lead);
01740 data += 1;
01741 size -= 1;
01742 }
01743 }
01744
01745 return result;
01746 }
01747 };
01748
01749 struct latin1_decoder
01750 {
01751 typedef uint8_t type;
01752
01753 template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
01754 {
01755 while (size)
01756 {
01757 result = Traits::low(result, *data);
01758 data += 1;
01759 size -= 1;
01760 }
01761
01762 return result;
01763 }
01764 };
01765
01766 template <size_t size> struct wchar_selector;
01767
01768 template <> struct wchar_selector<2>
01769 {
01770 typedef uint16_t type;
01771 typedef utf16_counter counter;
01772 typedef utf16_writer writer;
01773 typedef utf16_decoder<opt_false> decoder;
01774 };
01775
01776 template <> struct wchar_selector<4>
01777 {
01778 typedef uint32_t type;
01779 typedef utf32_counter counter;
01780 typedef utf32_writer writer;
01781 typedef utf32_decoder<opt_false> decoder;
01782 };
01783
01784 typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
01785 typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
01786
01787 struct wchar_decoder
01788 {
01789 typedef wchar_t type;
01790
01791 template <typename Traits> static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits)
01792 {
01793 typedef wchar_selector<sizeof(wchar_t)>::decoder decoder;
01794
01795 return decoder::process(reinterpret_cast<const typename decoder::type*>(data), size, result, traits);
01796 }
01797 };
01798
01799 #ifdef PUGIXML_WCHAR_MODE
01800 PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
01801 {
01802 for (size_t i = 0; i < length; ++i)
01803 result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
01804 }
01805 #endif
01806 PUGI__NS_END
01807
01808 PUGI__NS_BEGIN
01809 enum chartype_t
01810 {
01811 ct_parse_pcdata = 1,
01812 ct_parse_attr = 2,
01813 ct_parse_attr_ws = 4,
01814 ct_space = 8,
01815 ct_parse_cdata = 16,
01816 ct_parse_comment = 32,
01817 ct_symbol = 64,
01818 ct_start_symbol = 128
01819 };
01820
01821 static const unsigned char chartype_table[256] =
01822 {
01823 55, 0, 0, 0, 0, 0, 0, 0, 0, 12, 12, 0, 0, 63, 0, 0,
01824 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
01825 8, 0, 6, 0, 0, 0, 7, 6, 0, 0, 0, 0, 0, 96, 64, 0,
01826 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 192, 0, 1, 0, 48, 0,
01827 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01828 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 16, 0, 192,
01829 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01830 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 0,
01831
01832 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01833 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01834 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01835 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01836 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01837 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01838 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
01839 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192
01840 };
01841
01842 enum chartypex_t
01843 {
01844 ctx_special_pcdata = 1,
01845 ctx_special_attr = 2,
01846 ctx_start_symbol = 4,
01847 ctx_digit = 8,
01848 ctx_symbol = 16
01849 };
01850
01851 static const unsigned char chartypex_table[256] =
01852 {
01853 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 2, 3, 3, 2, 3, 3,
01854 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
01855 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 16, 16, 0,
01856 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 0, 0, 3, 0, 3, 0,
01857
01858 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01859 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 20,
01860 0, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01861 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 0, 0, 0, 0, 0,
01862
01863 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01864 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01865 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01866 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01867 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01868 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01869 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
01870 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
01871 };
01872
01873 #ifdef PUGIXML_WCHAR_MODE
01874 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
01875 #else
01876 #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
01877 #endif
01878
01879 #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
01880 #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
01881
01882 PUGI__FN bool is_little_endian()
01883 {
01884 unsigned int ui = 1;
01885
01886 return *reinterpret_cast<unsigned char*>(&ui) == 1;
01887 }
01888
01889 PUGI__FN xml_encoding get_wchar_encoding()
01890 {
01891 PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
01892
01893 if (sizeof(wchar_t) == 2)
01894 return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
01895 else
01896 return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
01897 }
01898
01899 PUGI__FN xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
01900 {
01901
01902 if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be;
01903 if (d0 == 0xff && d1 == 0xfe && d2 == 0 && d3 == 0) return encoding_utf32_le;
01904 if (d0 == 0xfe && d1 == 0xff) return encoding_utf16_be;
01905 if (d0 == 0xff && d1 == 0xfe) return encoding_utf16_le;
01906 if (d0 == 0xef && d1 == 0xbb && d2 == 0xbf) return encoding_utf8;
01907
01908
01909 if (d0 == 0 && d1 == 0 && d2 == 0 && d3 == 0x3c) return encoding_utf32_be;
01910 if (d0 == 0x3c && d1 == 0 && d2 == 0 && d3 == 0) return encoding_utf32_le;
01911 if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be;
01912 if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le;
01913 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8;
01914
01915
01916 if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be;
01917 if (d0 == 0x3c && d1 == 0) return encoding_utf16_le;
01918
01919
01920 return encoding_utf8;
01921 }
01922
01923 PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
01924 {
01925
01926 if (encoding == encoding_wchar) return get_wchar_encoding();
01927
01928
01929 if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
01930
01931
01932 if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
01933
01934
01935 if (encoding != encoding_auto) return encoding;
01936
01937
01938 if (size < 4) return encoding_utf8;
01939
01940
01941 const uint8_t* data = static_cast<const uint8_t*>(contents);
01942
01943 PUGI__DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
01944
01945 return guess_buffer_encoding(d0, d1, d2, d3);
01946 }
01947
01948 PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
01949 {
01950 size_t length = size / sizeof(char_t);
01951
01952 if (is_mutable)
01953 {
01954 out_buffer = static_cast<char_t*>(const_cast<void*>(contents));
01955 out_length = length;
01956 }
01957 else
01958 {
01959 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
01960 if (!buffer) return false;
01961
01962 if (contents)
01963 memcpy(buffer, contents, length * sizeof(char_t));
01964 else
01965 assert(length == 0);
01966
01967 buffer[length] = 0;
01968
01969 out_buffer = buffer;
01970 out_length = length + 1;
01971 }
01972
01973 return true;
01974 }
01975
01976 #ifdef PUGIXML_WCHAR_MODE
01977 PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
01978 {
01979 return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
01980 (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
01981 }
01982
01983 PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
01984 {
01985 const char_t* data = static_cast<const char_t*>(contents);
01986 size_t length = size / sizeof(char_t);
01987
01988 if (is_mutable)
01989 {
01990 char_t* buffer = const_cast<char_t*>(data);
01991
01992 convert_wchar_endian_swap(buffer, data, length);
01993
01994 out_buffer = buffer;
01995 out_length = length;
01996 }
01997 else
01998 {
01999 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
02000 if (!buffer) return false;
02001
02002 convert_wchar_endian_swap(buffer, data, length);
02003 buffer[length] = 0;
02004
02005 out_buffer = buffer;
02006 out_length = length + 1;
02007 }
02008
02009 return true;
02010 }
02011
02012 template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
02013 {
02014 const typename D::type* data = static_cast<const typename D::type*>(contents);
02015 size_t data_length = size / sizeof(typename D::type);
02016
02017
02018 size_t length = D::process(data, data_length, 0, wchar_counter());
02019
02020
02021 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
02022 if (!buffer) return false;
02023
02024
02025 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
02026 wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer());
02027
02028 assert(oend == obegin + length);
02029 *oend = 0;
02030
02031 out_buffer = buffer;
02032 out_length = length + 1;
02033
02034 return true;
02035 }
02036
02037 PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
02038 {
02039
02040 xml_encoding wchar_encoding = get_wchar_encoding();
02041
02042
02043 if (encoding == wchar_encoding)
02044 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
02045
02046
02047 if (need_endian_swap_utf(encoding, wchar_encoding))
02048 return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
02049
02050
02051 if (encoding == encoding_utf8)
02052 return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder());
02053
02054
02055 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
02056 {
02057 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
02058
02059 return (native_encoding == encoding) ?
02060 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
02061 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
02062 }
02063
02064
02065 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
02066 {
02067 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
02068
02069 return (native_encoding == encoding) ?
02070 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
02071 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
02072 }
02073
02074
02075 if (encoding == encoding_latin1)
02076 return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder());
02077
02078 assert(!"Invalid encoding");
02079 return false;
02080 }
02081 #else
02082 template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
02083 {
02084 const typename D::type* data = static_cast<const typename D::type*>(contents);
02085 size_t data_length = size / sizeof(typename D::type);
02086
02087
02088 size_t length = D::process(data, data_length, 0, utf8_counter());
02089
02090
02091 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
02092 if (!buffer) return false;
02093
02094
02095 uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
02096 uint8_t* oend = D::process(data, data_length, obegin, utf8_writer());
02097
02098 assert(oend == obegin + length);
02099 *oend = 0;
02100
02101 out_buffer = buffer;
02102 out_length = length + 1;
02103
02104 return true;
02105 }
02106
02107 PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
02108 {
02109 for (size_t i = 0; i < size; ++i)
02110 if (data[i] > 127)
02111 return i;
02112
02113 return size;
02114 }
02115
02116 PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
02117 {
02118 const uint8_t* data = static_cast<const uint8_t*>(contents);
02119 size_t data_length = size;
02120
02121
02122 size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
02123 assert(prefix_length <= data_length);
02124
02125 const uint8_t* postfix = data + prefix_length;
02126 size_t postfix_length = data_length - prefix_length;
02127
02128
02129 if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
02130
02131
02132 size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter());
02133
02134
02135 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
02136 if (!buffer) return false;
02137
02138
02139 memcpy(buffer, data, prefix_length);
02140
02141 uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
02142 uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer());
02143
02144 assert(oend == obegin + length);
02145 *oend = 0;
02146
02147 out_buffer = buffer;
02148 out_length = length + 1;
02149
02150 return true;
02151 }
02152
02153 PUGI__FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
02154 {
02155
02156 if (encoding == encoding_utf8)
02157 return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
02158
02159
02160 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
02161 {
02162 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
02163
02164 return (native_encoding == encoding) ?
02165 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
02166 convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
02167 }
02168
02169
02170 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
02171 {
02172 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
02173
02174 return (native_encoding == encoding) ?
02175 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
02176 convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
02177 }
02178
02179
02180 if (encoding == encoding_latin1)
02181 return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
02182
02183 assert(!"Invalid encoding");
02184 return false;
02185 }
02186 #endif
02187
02188 PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length)
02189 {
02190
02191 return wchar_decoder::process(str, length, 0, utf8_counter());
02192 }
02193
02194 PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
02195 {
02196
02197 uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
02198 uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer());
02199
02200 assert(begin + size == end);
02201 (void)!end;
02202 (void)!size;
02203 }
02204
02205 #ifndef PUGIXML_NO_STL
02206 PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length)
02207 {
02208
02209 size_t size = as_utf8_begin(str, length);
02210
02211
02212 std::string result;
02213 result.resize(size);
02214
02215
02216 if (size > 0) as_utf8_end(&result[0], size, str, length);
02217
02218 return result;
02219 }
02220
02221 PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)
02222 {
02223 const uint8_t* data = reinterpret_cast<const uint8_t*>(str);
02224
02225
02226 size_t length = utf8_decoder::process(data, size, 0, wchar_counter());
02227
02228
02229 std::basic_string<wchar_t> result;
02230 result.resize(length);
02231
02232
02233 if (length > 0)
02234 {
02235 wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
02236 wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer());
02237
02238 assert(begin + length == end);
02239 (void)!end;
02240 }
02241
02242 return result;
02243 }
02244 #endif
02245
02246 template <typename Header>
02247 inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target)
02248 {
02249
02250 if (header & xml_memory_page_contents_shared_mask) return false;
02251
02252 size_t target_length = strlength(target);
02253
02254
02255 if ((header & header_mask) == 0) return target_length >= length;
02256
02257
02258 const size_t reuse_threshold = 32;
02259
02260 return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2);
02261 }
02262
02263 template <typename String, typename Header>
02264 PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length)
02265 {
02266 if (source_length == 0)
02267 {
02268
02269 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
02270
02271 if (header & header_mask) alloc->deallocate_string(dest);
02272
02273
02274 dest = 0;
02275 header &= ~header_mask;
02276
02277 return true;
02278 }
02279 else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest))
02280 {
02281
02282 memcpy(dest, source, source_length * sizeof(char_t));
02283 dest[source_length] = 0;
02284
02285 return true;
02286 }
02287 else
02288 {
02289 xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
02290
02291 if (!alloc->reserve()) return false;
02292
02293
02294 char_t* buf = alloc->allocate_string(source_length + 1);
02295 if (!buf) return false;
02296
02297
02298 memcpy(buf, source, source_length * sizeof(char_t));
02299 buf[source_length] = 0;
02300
02301
02302 if (header & header_mask) alloc->deallocate_string(dest);
02303
02304
02305 dest = buf;
02306 header |= header_mask;
02307
02308 return true;
02309 }
02310 }
02311
02312 struct gap
02313 {
02314 char_t* end;
02315 size_t size;
02316
02317 gap(): end(0), size(0)
02318 {
02319 }
02320
02321
02322
02323 void push(char_t*& s, size_t count)
02324 {
02325 if (end)
02326 {
02327
02328 assert(s >= end);
02329 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
02330 }
02331
02332 s += count;
02333
02334
02335 end = s;
02336 size += count;
02337 }
02338
02339
02340 char_t* flush(char_t* s)
02341 {
02342 if (end)
02343 {
02344
02345 assert(s >= end);
02346 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
02347
02348 return s - size;
02349 }
02350 else return s;
02351 }
02352 };
02353
02354 PUGI__FN char_t* strconv_escape(char_t* s, gap& g)
02355 {
02356 char_t* stre = s + 1;
02357
02358 switch (*stre)
02359 {
02360 case '#':
02361 {
02362 unsigned int ucsc = 0;
02363
02364 if (stre[1] == 'x')
02365 {
02366 stre += 2;
02367
02368 char_t ch = *stre;
02369
02370 if (ch == ';') return stre;
02371
02372 for (;;)
02373 {
02374 if (static_cast<unsigned int>(ch - '0') <= 9)
02375 ucsc = 16 * ucsc + (ch - '0');
02376 else if (static_cast<unsigned int>((ch | ' ') - 'a') <= 5)
02377 ucsc = 16 * ucsc + ((ch | ' ') - 'a' + 10);
02378 else if (ch == ';')
02379 break;
02380 else
02381 return stre;
02382
02383 ch = *++stre;
02384 }
02385
02386 ++stre;
02387 }
02388 else
02389 {
02390 char_t ch = *++stre;
02391
02392 if (ch == ';') return stre;
02393
02394 for (;;)
02395 {
02396 if (static_cast<unsigned int>(static_cast<unsigned int>(ch) - '0') <= 9)
02397 ucsc = 10 * ucsc + (ch - '0');
02398 else if (ch == ';')
02399 break;
02400 else
02401 return stre;
02402
02403 ch = *++stre;
02404 }
02405
02406 ++stre;
02407 }
02408
02409 #ifdef PUGIXML_WCHAR_MODE
02410 s = reinterpret_cast<char_t*>(wchar_writer::any(reinterpret_cast<wchar_writer::value_type>(s), ucsc));
02411 #else
02412 s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));
02413 #endif
02414
02415 g.push(s, stre - s);
02416 return stre;
02417 }
02418
02419 case 'a':
02420 {
02421 ++stre;
02422
02423 if (*stre == 'm')
02424 {
02425 if (*++stre == 'p' && *++stre == ';')
02426 {
02427 *s++ = '&';
02428 ++stre;
02429
02430 g.push(s, stre - s);
02431 return stre;
02432 }
02433 }
02434 else if (*stre == 'p')
02435 {
02436 if (*++stre == 'o' && *++stre == 's' && *++stre == ';')
02437 {
02438 *s++ = '\'';
02439 ++stre;
02440
02441 g.push(s, stre - s);
02442 return stre;
02443 }
02444 }
02445 break;
02446 }
02447
02448 case 'g':
02449 {
02450 if (*++stre == 't' && *++stre == ';')
02451 {
02452 *s++ = '>';
02453 ++stre;
02454
02455 g.push(s, stre - s);
02456 return stre;
02457 }
02458 break;
02459 }
02460
02461 case 'l':
02462 {
02463 if (*++stre == 't' && *++stre == ';')
02464 {
02465 *s++ = '<';
02466 ++stre;
02467
02468 g.push(s, stre - s);
02469 return stre;
02470 }
02471 break;
02472 }
02473
02474 case 'q':
02475 {
02476 if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';')
02477 {
02478 *s++ = '"';
02479 ++stre;
02480
02481 g.push(s, stre - s);
02482 return stre;
02483 }
02484 break;
02485 }
02486
02487 default:
02488 break;
02489 }
02490
02491 return stre;
02492 }
02493
02494
02495 #define PUGI__ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
02496 #define PUGI__SKIPWS() { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
02497 #define PUGI__OPTSET(OPT) ( optmsk & (OPT) )
02498 #define PUGI__PUSHNODE(TYPE) { cursor = append_new_node(cursor, alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
02499 #define PUGI__POPNODE() { cursor = cursor->parent; }
02500 #define PUGI__SCANFOR(X) { while (*s != 0 && !(X)) ++s; }
02501 #define PUGI__SCANWHILE(X) { while (X) ++s; }
02502 #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; } }
02503 #define PUGI__ENDSEG() { ch = *s; *s = 0; ++s; }
02504 #define PUGI__THROW_ERROR(err, m) return error_offset = m, error_status = err, static_cast<char_t*>(0)
02505 #define PUGI__CHECK_ERROR(err, m) { if (*s == 0) PUGI__THROW_ERROR(err, m); }
02506
02507 PUGI__FN char_t* strconv_comment(char_t* s, char_t endch)
02508 {
02509 gap g;
02510
02511 while (true)
02512 {
02513 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment));
02514
02515 if (*s == '\r')
02516 {
02517 *s++ = '\n';
02518
02519 if (*s == '\n') g.push(s, 1);
02520 }
02521 else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>'))
02522 {
02523 *g.flush(s) = 0;
02524
02525 return s + (s[2] == '>' ? 3 : 2);
02526 }
02527 else if (*s == 0)
02528 {
02529 return 0;
02530 }
02531 else ++s;
02532 }
02533 }
02534
02535 PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch)
02536 {
02537 gap g;
02538
02539 while (true)
02540 {
02541 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata));
02542
02543 if (*s == '\r')
02544 {
02545 *s++ = '\n';
02546
02547 if (*s == '\n') g.push(s, 1);
02548 }
02549 else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'))
02550 {
02551 *g.flush(s) = 0;
02552
02553 return s + 1;
02554 }
02555 else if (*s == 0)
02556 {
02557 return 0;
02558 }
02559 else ++s;
02560 }
02561 }
02562
02563 typedef char_t* (*strconv_pcdata_t)(char_t*);
02564
02565 template <typename opt_trim, typename opt_eol, typename opt_escape> struct strconv_pcdata_impl
02566 {
02567 static char_t* parse(char_t* s)
02568 {
02569 gap g;
02570
02571 char_t* begin = s;
02572
02573 while (true)
02574 {
02575 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata));
02576
02577 if (*s == '<')
02578 {
02579 char_t* end = g.flush(s);
02580
02581 if (opt_trim::value)
02582 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
02583 --end;
02584
02585 *end = 0;
02586
02587 return s + 1;
02588 }
02589 else if (opt_eol::value && *s == '\r')
02590 {
02591 *s++ = '\n';
02592
02593 if (*s == '\n') g.push(s, 1);
02594 }
02595 else if (opt_escape::value && *s == '&')
02596 {
02597 s = strconv_escape(s, g);
02598 }
02599 else if (*s == 0)
02600 {
02601 char_t* end = g.flush(s);
02602
02603 if (opt_trim::value)
02604 while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
02605 --end;
02606
02607 *end = 0;
02608
02609 return s;
02610 }
02611 else ++s;
02612 }
02613 }
02614 };
02615
02616 PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
02617 {
02618 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
02619
02620 switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4))
02621 {
02622 case 0: return strconv_pcdata_impl<opt_false, opt_false, opt_false>::parse;
02623 case 1: return strconv_pcdata_impl<opt_false, opt_false, opt_true>::parse;
02624 case 2: return strconv_pcdata_impl<opt_false, opt_true, opt_false>::parse;
02625 case 3: return strconv_pcdata_impl<opt_false, opt_true, opt_true>::parse;
02626 case 4: return strconv_pcdata_impl<opt_true, opt_false, opt_false>::parse;
02627 case 5: return strconv_pcdata_impl<opt_true, opt_false, opt_true>::parse;
02628 case 6: return strconv_pcdata_impl<opt_true, opt_true, opt_false>::parse;
02629 case 7: return strconv_pcdata_impl<opt_true, opt_true, opt_true>::parse;
02630 default: assert(false); return 0;
02631 }
02632 }
02633
02634 typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
02635
02636 template <typename opt_escape> struct strconv_attribute_impl
02637 {
02638 static char_t* parse_wnorm(char_t* s, char_t end_quote)
02639 {
02640 gap g;
02641
02642
02643 if (PUGI__IS_CHARTYPE(*s, ct_space))
02644 {
02645 char_t* str = s;
02646
02647 do ++str;
02648 while (PUGI__IS_CHARTYPE(*str, ct_space));
02649
02650 g.push(s, str - s);
02651 }
02652
02653 while (true)
02654 {
02655 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space));
02656
02657 if (*s == end_quote)
02658 {
02659 char_t* str = g.flush(s);
02660
02661 do *str-- = 0;
02662 while (PUGI__IS_CHARTYPE(*str, ct_space));
02663
02664 return s + 1;
02665 }
02666 else if (PUGI__IS_CHARTYPE(*s, ct_space))
02667 {
02668 *s++ = ' ';
02669
02670 if (PUGI__IS_CHARTYPE(*s, ct_space))
02671 {
02672 char_t* str = s + 1;
02673 while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
02674
02675 g.push(s, str - s);
02676 }
02677 }
02678 else if (opt_escape::value && *s == '&')
02679 {
02680 s = strconv_escape(s, g);
02681 }
02682 else if (!*s)
02683 {
02684 return 0;
02685 }
02686 else ++s;
02687 }
02688 }
02689
02690 static char_t* parse_wconv(char_t* s, char_t end_quote)
02691 {
02692 gap g;
02693
02694 while (true)
02695 {
02696 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws));
02697
02698 if (*s == end_quote)
02699 {
02700 *g.flush(s) = 0;
02701
02702 return s + 1;
02703 }
02704 else if (PUGI__IS_CHARTYPE(*s, ct_space))
02705 {
02706 if (*s == '\r')
02707 {
02708 *s++ = ' ';
02709
02710 if (*s == '\n') g.push(s, 1);
02711 }
02712 else *s++ = ' ';
02713 }
02714 else if (opt_escape::value && *s == '&')
02715 {
02716 s = strconv_escape(s, g);
02717 }
02718 else if (!*s)
02719 {
02720 return 0;
02721 }
02722 else ++s;
02723 }
02724 }
02725
02726 static char_t* parse_eol(char_t* s, char_t end_quote)
02727 {
02728 gap g;
02729
02730 while (true)
02731 {
02732 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
02733
02734 if (*s == end_quote)
02735 {
02736 *g.flush(s) = 0;
02737
02738 return s + 1;
02739 }
02740 else if (*s == '\r')
02741 {
02742 *s++ = '\n';
02743
02744 if (*s == '\n') g.push(s, 1);
02745 }
02746 else if (opt_escape::value && *s == '&')
02747 {
02748 s = strconv_escape(s, g);
02749 }
02750 else if (!*s)
02751 {
02752 return 0;
02753 }
02754 else ++s;
02755 }
02756 }
02757
02758 static char_t* parse_simple(char_t* s, char_t end_quote)
02759 {
02760 gap g;
02761
02762 while (true)
02763 {
02764 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
02765
02766 if (*s == end_quote)
02767 {
02768 *g.flush(s) = 0;
02769
02770 return s + 1;
02771 }
02772 else if (opt_escape::value && *s == '&')
02773 {
02774 s = strconv_escape(s, g);
02775 }
02776 else if (!*s)
02777 {
02778 return 0;
02779 }
02780 else ++s;
02781 }
02782 }
02783 };
02784
02785 PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
02786 {
02787 PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
02788
02789 switch ((optmask >> 4) & 15)
02790 {
02791 case 0: return strconv_attribute_impl<opt_false>::parse_simple;
02792 case 1: return strconv_attribute_impl<opt_true>::parse_simple;
02793 case 2: return strconv_attribute_impl<opt_false>::parse_eol;
02794 case 3: return strconv_attribute_impl<opt_true>::parse_eol;
02795 case 4: return strconv_attribute_impl<opt_false>::parse_wconv;
02796 case 5: return strconv_attribute_impl<opt_true>::parse_wconv;
02797 case 6: return strconv_attribute_impl<opt_false>::parse_wconv;
02798 case 7: return strconv_attribute_impl<opt_true>::parse_wconv;
02799 case 8: return strconv_attribute_impl<opt_false>::parse_wnorm;
02800 case 9: return strconv_attribute_impl<opt_true>::parse_wnorm;
02801 case 10: return strconv_attribute_impl<opt_false>::parse_wnorm;
02802 case 11: return strconv_attribute_impl<opt_true>::parse_wnorm;
02803 case 12: return strconv_attribute_impl<opt_false>::parse_wnorm;
02804 case 13: return strconv_attribute_impl<opt_true>::parse_wnorm;
02805 case 14: return strconv_attribute_impl<opt_false>::parse_wnorm;
02806 case 15: return strconv_attribute_impl<opt_true>::parse_wnorm;
02807 default: assert(false); return 0;
02808 }
02809 }
02810
02811 inline xml_parse_result make_parse_result(xml_parse_status status, ptrdiff_t offset = 0)
02812 {
02813 xml_parse_result result;
02814 result.status = status;
02815 result.offset = offset;
02816
02817 return result;
02818 }
02819
02820 struct xml_parser
02821 {
02822 xml_allocator alloc;
02823 xml_allocator* alloc_state;
02824 char_t* error_offset;
02825 xml_parse_status error_status;
02826
02827 xml_parser(xml_allocator* alloc_): alloc(*alloc_), alloc_state(alloc_), error_offset(0), error_status(status_ok)
02828 {
02829 }
02830
02831 ~xml_parser()
02832 {
02833 *alloc_state = alloc;
02834 }
02835
02836
02837
02838
02839
02840
02841
02842
02843 char_t* parse_doctype_primitive(char_t* s)
02844 {
02845 if (*s == '"' || *s == '\'')
02846 {
02847
02848 char_t ch = *s++;
02849 PUGI__SCANFOR(*s == ch);
02850 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
02851
02852 s++;
02853 }
02854 else if (s[0] == '<' && s[1] == '?')
02855 {
02856
02857 s += 2;
02858 PUGI__SCANFOR(s[0] == '?' && s[1] == '>');
02859 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
02860
02861 s += 2;
02862 }
02863 else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')
02864 {
02865 s += 4;
02866 PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>');
02867 if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
02868
02869 s += 3;
02870 }
02871 else PUGI__THROW_ERROR(status_bad_doctype, s);
02872
02873 return s;
02874 }
02875
02876 char_t* parse_doctype_ignore(char_t* s)
02877 {
02878 size_t depth = 0;
02879
02880 assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
02881 s += 3;
02882
02883 while (*s)
02884 {
02885 if (s[0] == '<' && s[1] == '!' && s[2] == '[')
02886 {
02887
02888 s += 3;
02889 depth++;
02890 }
02891 else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
02892 {
02893
02894 s += 3;
02895
02896 if (depth == 0)
02897 return s;
02898
02899 depth--;
02900 }
02901 else s++;
02902 }
02903
02904 PUGI__THROW_ERROR(status_bad_doctype, s);
02905 }
02906
02907 char_t* parse_doctype_group(char_t* s, char_t endch)
02908 {
02909 size_t depth = 0;
02910
02911 assert((s[0] == '<' || s[0] == 0) && s[1] == '!');
02912 s += 2;
02913
02914 while (*s)
02915 {
02916 if (s[0] == '<' && s[1] == '!' && s[2] != '-')
02917 {
02918 if (s[2] == '[')
02919 {
02920
02921 s = parse_doctype_ignore(s);
02922 if (!s) return s;
02923 }
02924 else
02925 {
02926
02927 s += 2;
02928 depth++;
02929 }
02930 }
02931 else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
02932 {
02933
02934 s = parse_doctype_primitive(s);
02935 if (!s) return s;
02936 }
02937 else if (*s == '>')
02938 {
02939 if (depth == 0)
02940 return s;
02941
02942 depth--;
02943 s++;
02944 }
02945 else s++;
02946 }
02947
02948 if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
02949
02950 return s;
02951 }
02952
02953 char_t* parse_exclamation(char_t* s, xml_node_struct* cursor, unsigned int optmsk, char_t endch)
02954 {
02955
02956 ++s;
02957
02958 if (*s == '-')
02959 {
02960 ++s;
02961
02962 if (*s == '-')
02963 {
02964 ++s;
02965
02966 if (PUGI__OPTSET(parse_comments))
02967 {
02968 PUGI__PUSHNODE(node_comment);
02969 cursor->value = s;
02970 }
02971
02972 if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments))
02973 {
02974 s = strconv_comment(s, endch);
02975
02976 if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
02977 }
02978 else
02979 {
02980
02981 PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>'));
02982 PUGI__CHECK_ERROR(status_bad_comment, s);
02983
02984 if (PUGI__OPTSET(parse_comments))
02985 *s = 0;
02986
02987 s += (s[2] == '>' ? 3 : 2);
02988 }
02989 }
02990 else PUGI__THROW_ERROR(status_bad_comment, s);
02991 }
02992 else if (*s == '[')
02993 {
02994
02995 if (*++s=='C' && *++s=='D' && *++s=='A' && *++s=='T' && *++s=='A' && *++s == '[')
02996 {
02997 ++s;
02998
02999 if (PUGI__OPTSET(parse_cdata))
03000 {
03001 PUGI__PUSHNODE(node_cdata);
03002 cursor->value = s;
03003
03004 if (PUGI__OPTSET(parse_eol))
03005 {
03006 s = strconv_cdata(s, endch);
03007
03008 if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
03009 }
03010 else
03011 {
03012
03013 PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
03014 PUGI__CHECK_ERROR(status_bad_cdata, s);
03015
03016 *s++ = 0;
03017 }
03018 }
03019 else
03020 {
03021
03022 PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
03023 PUGI__CHECK_ERROR(status_bad_cdata, s);
03024
03025 ++s;
03026 }
03027
03028 s += (s[1] == '>' ? 2 : 1);
03029 }
03030 else PUGI__THROW_ERROR(status_bad_cdata, s);
03031 }
03032 else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI__ENDSWITH(s[6], 'E'))
03033 {
03034 s -= 2;
03035
03036 if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
03037
03038 char_t* mark = s + 9;
03039
03040 s = parse_doctype_group(s, endch);
03041 if (!s) return s;
03042
03043 assert((*s == 0 && endch == '>') || *s == '>');
03044 if (*s) *s++ = 0;
03045
03046 if (PUGI__OPTSET(parse_doctype))
03047 {
03048 while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
03049
03050 PUGI__PUSHNODE(node_doctype);
03051
03052 cursor->value = mark;
03053 }
03054 }
03055 else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s);
03056 else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s);
03057 else PUGI__THROW_ERROR(status_unrecognized_tag, s);
03058
03059 return s;
03060 }
03061
03062 char_t* parse_question(char_t* s, xml_node_struct*& ref_cursor, unsigned int optmsk, char_t endch)
03063 {
03064
03065 xml_node_struct* cursor = ref_cursor;
03066 char_t ch = 0;
03067
03068
03069 ++s;
03070
03071
03072 char_t* target = s;
03073
03074 if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s);
03075
03076 PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
03077 PUGI__CHECK_ERROR(status_bad_pi, s);
03078
03079
03080 bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
03081
03082 if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
03083 {
03084 if (declaration)
03085 {
03086
03087 if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
03088
03089 PUGI__PUSHNODE(node_declaration);
03090 }
03091 else
03092 {
03093 PUGI__PUSHNODE(node_pi);
03094 }
03095
03096 cursor->name = target;
03097
03098 PUGI__ENDSEG();
03099
03100
03101 if (ch == '?')
03102 {
03103
03104 if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s);
03105 s += (*s == '>');
03106
03107 PUGI__POPNODE();
03108 }
03109 else if (PUGI__IS_CHARTYPE(ch, ct_space))
03110 {
03111 PUGI__SKIPWS();
03112
03113
03114 char_t* value = s;
03115
03116 PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
03117 PUGI__CHECK_ERROR(status_bad_pi, s);
03118
03119 if (declaration)
03120 {
03121
03122 *s = '/';
03123
03124
03125 s = value;
03126 }
03127 else
03128 {
03129
03130 cursor->value = value;
03131
03132 PUGI__POPNODE();
03133
03134 PUGI__ENDSEG();
03135
03136 s += (*s == '>');
03137 }
03138 }
03139 else PUGI__THROW_ERROR(status_bad_pi, s);
03140 }
03141 else
03142 {
03143
03144 PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
03145 PUGI__CHECK_ERROR(status_bad_pi, s);
03146
03147 s += (s[1] == '>' ? 2 : 1);
03148 }
03149
03150
03151 ref_cursor = cursor;
03152
03153 return s;
03154 }
03155
03156 char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch)
03157 {
03158 strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
03159 strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
03160
03161 char_t ch = 0;
03162 xml_node_struct* cursor = root;
03163 char_t* mark = s;
03164
03165 while (*s != 0)
03166 {
03167 if (*s == '<')
03168 {
03169 ++s;
03170
03171 LOC_TAG:
03172 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
03173 {
03174 PUGI__PUSHNODE(node_element);
03175
03176 cursor->name = s;
03177
03178 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol));
03179 PUGI__ENDSEG();
03180
03181 if (ch == '>')
03182 {
03183
03184 }
03185 else if (PUGI__IS_CHARTYPE(ch, ct_space))
03186 {
03187 LOC_ATTRIBUTES:
03188 while (true)
03189 {
03190 PUGI__SKIPWS();
03191
03192 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol))
03193 {
03194 xml_attribute_struct* a = append_new_attribute(cursor, alloc);
03195 if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
03196
03197 a->name = s;
03198
03199 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol));
03200 PUGI__ENDSEG();
03201
03202 if (PUGI__IS_CHARTYPE(ch, ct_space))
03203 {
03204 PUGI__SKIPWS();
03205
03206 ch = *s;
03207 ++s;
03208 }
03209
03210 if (ch == '=')
03211 {
03212 PUGI__SKIPWS();
03213
03214 if (*s == '"' || *s == '\'')
03215 {
03216 ch = *s;
03217 ++s;
03218 a->value = s;
03219
03220 s = strconv_attribute(s, ch);
03221
03222 if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
03223
03224
03225
03226
03227 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s);
03228 }
03229 else PUGI__THROW_ERROR(status_bad_attribute, s);
03230 }
03231 else PUGI__THROW_ERROR(status_bad_attribute, s);
03232 }
03233 else if (*s == '/')
03234 {
03235 ++s;
03236
03237 if (*s == '>')
03238 {
03239 PUGI__POPNODE();
03240 s++;
03241 break;
03242 }
03243 else if (*s == 0 && endch == '>')
03244 {
03245 PUGI__POPNODE();
03246 break;
03247 }
03248 else PUGI__THROW_ERROR(status_bad_start_element, s);
03249 }
03250 else if (*s == '>')
03251 {
03252 ++s;
03253
03254 break;
03255 }
03256 else if (*s == 0 && endch == '>')
03257 {
03258 break;
03259 }
03260 else PUGI__THROW_ERROR(status_bad_start_element, s);
03261 }
03262
03263
03264 }
03265 else if (ch == '/')
03266 {
03267 if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s);
03268
03269 PUGI__POPNODE();
03270
03271 s += (*s == '>');
03272 }
03273 else if (ch == 0)
03274 {
03275
03276 --s;
03277
03278 if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s);
03279 }
03280 else PUGI__THROW_ERROR(status_bad_start_element, s);
03281 }
03282 else if (*s == '/')
03283 {
03284 ++s;
03285
03286 char_t* name = cursor->name;
03287 if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, s);
03288
03289 while (PUGI__IS_CHARTYPE(*s, ct_symbol))
03290 {
03291 if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, s);
03292 }
03293
03294 if (*name)
03295 {
03296 if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
03297 else PUGI__THROW_ERROR(status_end_element_mismatch, s);
03298 }
03299
03300 PUGI__POPNODE();
03301
03302 PUGI__SKIPWS();
03303
03304 if (*s == 0)
03305 {
03306 if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
03307 }
03308 else
03309 {
03310 if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
03311 ++s;
03312 }
03313 }
03314 else if (*s == '?')
03315 {
03316 s = parse_question(s, cursor, optmsk, endch);
03317 if (!s) return s;
03318
03319 assert(cursor);
03320 if (PUGI__NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES;
03321 }
03322 else if (*s == '!')
03323 {
03324 s = parse_exclamation(s, cursor, optmsk, endch);
03325 if (!s) return s;
03326 }
03327 else if (*s == 0 && endch == '?') PUGI__THROW_ERROR(status_bad_pi, s);
03328 else PUGI__THROW_ERROR(status_unrecognized_tag, s);
03329 }
03330 else
03331 {
03332 mark = s;
03333
03334 PUGI__SKIPWS();
03335
03336 if (*s == '<' || !*s)
03337 {
03338
03339 assert(mark != s);
03340
03341 if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI__OPTSET(parse_trim_pcdata))
03342 {
03343 continue;
03344 }
03345 else if (PUGI__OPTSET(parse_ws_pcdata_single))
03346 {
03347 if (s[0] != '<' || s[1] != '/' || cursor->first_child) continue;
03348 }
03349 }
03350
03351 if (!PUGI__OPTSET(parse_trim_pcdata))
03352 s = mark;
03353
03354 if (cursor->parent || PUGI__OPTSET(parse_fragment))
03355 {
03356 PUGI__PUSHNODE(node_pcdata);
03357 cursor->value = s;
03358
03359 s = strconv_pcdata(s);
03360
03361 PUGI__POPNODE();
03362
03363 if (!*s) break;
03364 }
03365 else
03366 {
03367 PUGI__SCANFOR(*s == '<');
03368 if (!*s) break;
03369
03370 ++s;
03371 }
03372
03373
03374 goto LOC_TAG;
03375 }
03376 }
03377
03378
03379 if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s);
03380
03381 return s;
03382 }
03383
03384 #ifdef PUGIXML_WCHAR_MODE
03385 static char_t* parse_skip_bom(char_t* s)
03386 {
03387 unsigned int bom = 0xfeff;
03388 return (s[0] == static_cast<wchar_t>(bom)) ? s + 1 : s;
03389 }
03390 #else
03391 static char_t* parse_skip_bom(char_t* s)
03392 {
03393 return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s;
03394 }
03395 #endif
03396
03397 static bool has_element_node_siblings(xml_node_struct* node)
03398 {
03399 while (node)
03400 {
03401 if (PUGI__NODETYPE(node) == node_element) return true;
03402
03403 node = node->next_sibling;
03404 }
03405
03406 return false;
03407 }
03408
03409 static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk)
03410 {
03411
03412 if (length == 0)
03413 return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element);
03414
03415
03416 xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
03417
03418
03419 xml_parser parser(static_cast<xml_allocator*>(xmldoc));
03420
03421
03422 char_t endch = buffer[length - 1];
03423 buffer[length - 1] = 0;
03424
03425
03426 char_t* buffer_data = parse_skip_bom(buffer);
03427
03428
03429 parser.parse_tree(buffer_data, root, optmsk, endch);
03430
03431 xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
03432 assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
03433
03434 if (result)
03435 {
03436
03437 if (endch == '<')
03438 return make_parse_result(status_unrecognized_tag, length - 1);
03439
03440
03441 xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0;
03442
03443 if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
03444 return make_parse_result(status_no_document_element, length - 1);
03445 }
03446 else
03447 {
03448
03449 if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0)
03450 result.offset--;
03451 }
03452
03453 return result;
03454 }
03455 };
03456
03457
03458 PUGI__FN xml_encoding get_write_native_encoding()
03459 {
03460 #ifdef PUGIXML_WCHAR_MODE
03461 return get_wchar_encoding();
03462 #else
03463 return encoding_utf8;
03464 #endif
03465 }
03466
03467 PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
03468 {
03469
03470 if (encoding == encoding_wchar) return get_wchar_encoding();
03471
03472
03473 if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
03474
03475
03476 if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
03477
03478
03479 if (encoding != encoding_auto) return encoding;
03480
03481
03482 return encoding_utf8;
03483 }
03484
03485 template <typename D, typename T> PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T)
03486 {
03487 PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
03488
03489 typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
03490
03491 return static_cast<size_t>(end - dest) * sizeof(*dest);
03492 }
03493
03494 template <typename D, typename T> PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap)
03495 {
03496 PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
03497
03498 typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
03499
03500 if (opt_swap)
03501 {
03502 for (typename T::value_type i = dest; i != end; ++i)
03503 *i = endian_swap(*i);
03504 }
03505
03506 return static_cast<size_t>(end - dest) * sizeof(*dest);
03507 }
03508
03509 #ifdef PUGIXML_WCHAR_MODE
03510 PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
03511 {
03512 if (length < 1) return 0;
03513
03514
03515 return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
03516 }
03517
03518 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)
03519 {
03520
03521 if (need_endian_swap_utf(encoding, get_wchar_encoding()))
03522 {
03523 convert_wchar_endian_swap(r_char, data, length);
03524
03525 return length * sizeof(char_t);
03526 }
03527
03528
03529 if (encoding == encoding_utf8)
03530 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer());
03531
03532
03533 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
03534 {
03535 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
03536
03537 return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding);
03538 }
03539
03540
03541 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
03542 {
03543 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
03544
03545 return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding);
03546 }
03547
03548
03549 if (encoding == encoding_latin1)
03550 return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer());
03551
03552 assert(!"Invalid encoding");
03553 return 0;
03554 }
03555 #else
03556 PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
03557 {
03558 if (length < 5) return 0;
03559
03560 for (size_t i = 1; i <= 4; ++i)
03561 {
03562 uint8_t ch = static_cast<uint8_t>(data[length - i]);
03563
03564
03565 if ((ch & 0xc0) != 0x80) return length - i;
03566 }
03567
03568
03569 return length;
03570 }
03571
03572 PUGI__FN size_t convert_buffer_output(char_t* , uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
03573 {
03574 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
03575 {
03576 xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
03577
03578 return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding);
03579 }
03580
03581 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
03582 {
03583 xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
03584
03585 return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding);
03586 }
03587
03588 if (encoding == encoding_latin1)
03589 return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer());
03590
03591 assert(!"Invalid encoding");
03592 return 0;
03593 }
03594 #endif
03595
03596 class xml_buffered_writer
03597 {
03598 xml_buffered_writer(const xml_buffered_writer&);
03599 xml_buffered_writer& operator=(const xml_buffered_writer&);
03600
03601 public:
03602 xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
03603 {
03604 PUGI__STATIC_ASSERT(bufcapacity >= 8);
03605 }
03606
03607 size_t flush()
03608 {
03609 flush(buffer, bufsize);
03610 bufsize = 0;
03611 return 0;
03612 }
03613
03614 void flush(const char_t* data, size_t size)
03615 {
03616 if (size == 0) return;
03617
03618
03619 if (encoding == get_write_native_encoding())
03620 writer.write(data, size * sizeof(char_t));
03621 else
03622 {
03623
03624 size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);
03625 assert(result <= sizeof(scratch));
03626
03627
03628 writer.write(scratch.data_u8, result);
03629 }
03630 }
03631
03632 void write_direct(const char_t* data, size_t length)
03633 {
03634
03635 flush();
03636
03637
03638 if (length > bufcapacity)
03639 {
03640 if (encoding == get_write_native_encoding())
03641 {
03642
03643 writer.write(data, length * sizeof(char_t));
03644 return;
03645 }
03646
03647
03648 while (length > bufcapacity)
03649 {
03650
03651
03652 size_t chunk_size = get_valid_length(data, bufcapacity);
03653 assert(chunk_size);
03654
03655
03656 flush(data, chunk_size);
03657
03658
03659 data += chunk_size;
03660 length -= chunk_size;
03661 }
03662
03663
03664 bufsize = 0;
03665 }
03666
03667 memcpy(buffer + bufsize, data, length * sizeof(char_t));
03668 bufsize += length;
03669 }
03670
03671 void write_buffer(const char_t* data, size_t length)
03672 {
03673 size_t offset = bufsize;
03674
03675 if (offset + length <= bufcapacity)
03676 {
03677 memcpy(buffer + offset, data, length * sizeof(char_t));
03678 bufsize = offset + length;
03679 }
03680 else
03681 {
03682 write_direct(data, length);
03683 }
03684 }
03685
03686 void write_string(const char_t* data)
03687 {
03688
03689 size_t offset = bufsize;
03690
03691 while (*data && offset < bufcapacity)
03692 buffer[offset++] = *data++;
03693
03694
03695 if (offset < bufcapacity)
03696 {
03697 bufsize = offset;
03698 }
03699 else
03700 {
03701
03702 size_t length = offset - bufsize;
03703 size_t extra = length - get_valid_length(data - length, length);
03704
03705 bufsize = offset - extra;
03706
03707 write_direct(data - extra, strlength(data) + extra);
03708 }
03709 }
03710
03711 void write(char_t d0)
03712 {
03713 size_t offset = bufsize;
03714 if (offset > bufcapacity - 1) offset = flush();
03715
03716 buffer[offset + 0] = d0;
03717 bufsize = offset + 1;
03718 }
03719
03720 void write(char_t d0, char_t d1)
03721 {
03722 size_t offset = bufsize;
03723 if (offset > bufcapacity - 2) offset = flush();
03724
03725 buffer[offset + 0] = d0;
03726 buffer[offset + 1] = d1;
03727 bufsize = offset + 2;
03728 }
03729
03730 void write(char_t d0, char_t d1, char_t d2)
03731 {
03732 size_t offset = bufsize;
03733 if (offset > bufcapacity - 3) offset = flush();
03734
03735 buffer[offset + 0] = d0;
03736 buffer[offset + 1] = d1;
03737 buffer[offset + 2] = d2;
03738 bufsize = offset + 3;
03739 }
03740
03741 void write(char_t d0, char_t d1, char_t d2, char_t d3)
03742 {
03743 size_t offset = bufsize;
03744 if (offset > bufcapacity - 4) offset = flush();
03745
03746 buffer[offset + 0] = d0;
03747 buffer[offset + 1] = d1;
03748 buffer[offset + 2] = d2;
03749 buffer[offset + 3] = d3;
03750 bufsize = offset + 4;
03751 }
03752
03753 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
03754 {
03755 size_t offset = bufsize;
03756 if (offset > bufcapacity - 5) offset = flush();
03757
03758 buffer[offset + 0] = d0;
03759 buffer[offset + 1] = d1;
03760 buffer[offset + 2] = d2;
03761 buffer[offset + 3] = d3;
03762 buffer[offset + 4] = d4;
03763 bufsize = offset + 5;
03764 }
03765
03766 void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
03767 {
03768 size_t offset = bufsize;
03769 if (offset > bufcapacity - 6) offset = flush();
03770
03771 buffer[offset + 0] = d0;
03772 buffer[offset + 1] = d1;
03773 buffer[offset + 2] = d2;
03774 buffer[offset + 3] = d3;
03775 buffer[offset + 4] = d4;
03776 buffer[offset + 5] = d5;
03777 bufsize = offset + 6;
03778 }
03779
03780
03781
03782
03783 enum
03784 {
03785 bufcapacitybytes =
03786 #ifdef PUGIXML_MEMORY_OUTPUT_STACK
03787 PUGIXML_MEMORY_OUTPUT_STACK
03788 #else
03789 10240
03790 #endif
03791 ,
03792 bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4)
03793 };
03794
03795 char_t buffer[bufcapacity];
03796
03797 union
03798 {
03799 uint8_t data_u8[4 * bufcapacity];
03800 uint16_t data_u16[2 * bufcapacity];
03801 uint32_t data_u32[bufcapacity];
03802 char_t data_char[bufcapacity];
03803 } scratch;
03804
03805 xml_writer& writer;
03806 size_t bufsize;
03807 xml_encoding encoding;
03808 };
03809
03810 PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type)
03811 {
03812 while (*s)
03813 {
03814 const char_t* prev = s;
03815
03816
03817 PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type));
03818
03819 writer.write_buffer(prev, static_cast<size_t>(s - prev));
03820
03821 switch (*s)
03822 {
03823 case 0: break;
03824 case '&':
03825 writer.write('&', 'a', 'm', 'p', ';');
03826 ++s;
03827 break;
03828 case '<':
03829 writer.write('&', 'l', 't', ';');
03830 ++s;
03831 break;
03832 case '>':
03833 writer.write('&', 'g', 't', ';');
03834 ++s;
03835 break;
03836 case '"':
03837 writer.write('&', 'q', 'u', 'o', 't', ';');
03838 ++s;
03839 break;
03840 default:
03841 {
03842 unsigned int ch = static_cast<unsigned int>(*s++);
03843 assert(ch < 32);
03844
03845 writer.write('&', '#', static_cast<char_t>((ch / 10) + '0'), static_cast<char_t>((ch % 10) + '0'), ';');
03846 }
03847 }
03848 }
03849 }
03850
03851 PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
03852 {
03853 if (flags & format_no_escapes)
03854 writer.write_string(s);
03855 else
03856 text_output_escaped(writer, s, type);
03857 }
03858
03859 PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s)
03860 {
03861 do
03862 {
03863 writer.write('<', '!', '[', 'C', 'D');
03864 writer.write('A', 'T', 'A', '[');
03865
03866 const char_t* prev = s;
03867
03868
03869 while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s;
03870
03871
03872 if (*s) s += 2;
03873
03874 writer.write_buffer(prev, static_cast<size_t>(s - prev));
03875
03876 writer.write(']', ']', '>');
03877 }
03878 while (*s);
03879 }
03880
03881 PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth)
03882 {
03883 switch (indent_length)
03884 {
03885 case 1:
03886 {
03887 for (unsigned int i = 0; i < depth; ++i)
03888 writer.write(indent[0]);
03889 break;
03890 }
03891
03892 case 2:
03893 {
03894 for (unsigned int i = 0; i < depth; ++i)
03895 writer.write(indent[0], indent[1]);
03896 break;
03897 }
03898
03899 case 3:
03900 {
03901 for (unsigned int i = 0; i < depth; ++i)
03902 writer.write(indent[0], indent[1], indent[2]);
03903 break;
03904 }
03905
03906 case 4:
03907 {
03908 for (unsigned int i = 0; i < depth; ++i)
03909 writer.write(indent[0], indent[1], indent[2], indent[3]);
03910 break;
03911 }
03912
03913 default:
03914 {
03915 for (unsigned int i = 0; i < depth; ++i)
03916 writer.write_buffer(indent, indent_length);
03917 }
03918 }
03919 }
03920
03921 PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s)
03922 {
03923 writer.write('<', '!', '-', '-');
03924
03925 while (*s)
03926 {
03927 const char_t* prev = s;
03928
03929
03930 while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s;
03931
03932 writer.write_buffer(prev, static_cast<size_t>(s - prev));
03933
03934 if (*s)
03935 {
03936 assert(*s == '-');
03937
03938 writer.write('-', ' ');
03939 ++s;
03940 }
03941 }
03942
03943 writer.write('-', '-', '>');
03944 }
03945
03946 PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s)
03947 {
03948 while (*s)
03949 {
03950 const char_t* prev = s;
03951
03952
03953 while (*s && !(s[0] == '?' && s[1] == '>')) ++s;
03954
03955 writer.write_buffer(prev, static_cast<size_t>(s - prev));
03956
03957 if (*s)
03958 {
03959 assert(s[0] == '?' && s[1] == '>');
03960
03961 writer.write('?', ' ', '>');
03962 s += 2;
03963 }
03964 }
03965 }
03966
03967 PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)
03968 {
03969 const char_t* default_name = PUGIXML_TEXT(":anonymous");
03970
03971 for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
03972 {
03973 if ((flags & (format_indent_attributes | format_raw)) == format_indent_attributes)
03974 {
03975 writer.write('\n');
03976
03977 text_output_indent(writer, indent, indent_length, depth + 1);
03978 }
03979 else
03980 {
03981 writer.write(' ');
03982 }
03983
03984 writer.write_string(a->name ? a->name + 0 : default_name);
03985 writer.write('=', '"');
03986
03987 if (a->value)
03988 text_output(writer, a->value, ctx_special_attr, flags);
03989
03990 writer.write('"');
03991 }
03992 }
03993
03994 PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)
03995 {
03996 const char_t* default_name = PUGIXML_TEXT(":anonymous");
03997 const char_t* name = node->name ? node->name + 0 : default_name;
03998
03999 writer.write('<');
04000 writer.write_string(name);
04001
04002 if (node->first_attribute)
04003 node_output_attributes(writer, node, indent, indent_length, flags, depth);
04004
04005 if (!node->first_child)
04006 {
04007 writer.write(' ', '/', '>');
04008
04009 return false;
04010 }
04011 else
04012 {
04013 writer.write('>');
04014
04015 return true;
04016 }
04017 }
04018
04019 PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node)
04020 {
04021 const char_t* default_name = PUGIXML_TEXT(":anonymous");
04022 const char_t* name = node->name ? node->name + 0 : default_name;
04023
04024 writer.write('<', '/');
04025 writer.write_string(name);
04026 writer.write('>');
04027 }
04028
04029 PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)
04030 {
04031 const char_t* default_name = PUGIXML_TEXT(":anonymous");
04032
04033 switch (PUGI__NODETYPE(node))
04034 {
04035 case node_pcdata:
04036 text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags);
04037 break;
04038
04039 case node_cdata:
04040 text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
04041 break;
04042
04043 case node_comment:
04044 node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
04045 break;
04046
04047 case node_pi:
04048 writer.write('<', '?');
04049 writer.write_string(node->name ? node->name + 0 : default_name);
04050
04051 if (node->value)
04052 {
04053 writer.write(' ');
04054 node_output_pi_value(writer, node->value);
04055 }
04056
04057 writer.write('?', '>');
04058 break;
04059
04060 case node_declaration:
04061 writer.write('<', '?');
04062 writer.write_string(node->name ? node->name + 0 : default_name);
04063 node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0);
04064 writer.write('?', '>');
04065 break;
04066
04067 case node_doctype:
04068 writer.write('<', '!', 'D', 'O', 'C');
04069 writer.write('T', 'Y', 'P', 'E');
04070
04071 if (node->value)
04072 {
04073 writer.write(' ');
04074 writer.write_string(node->value);
04075 }
04076
04077 writer.write('>');
04078 break;
04079
04080 default:
04081 assert(!"Invalid node type");
04082 }
04083 }
04084
04085 enum indent_flags_t
04086 {
04087 indent_newline = 1,
04088 indent_indent = 2
04089 };
04090
04091 PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth)
04092 {
04093 size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0;
04094 unsigned int indent_flags = indent_indent;
04095
04096 xml_node_struct* node = root;
04097
04098 do
04099 {
04100 assert(node);
04101
04102
04103 if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata)
04104 {
04105 node_output_simple(writer, node, flags);
04106
04107 indent_flags = 0;
04108 }
04109 else
04110 {
04111 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
04112 writer.write('\n');
04113
04114 if ((indent_flags & indent_indent) && indent_length)
04115 text_output_indent(writer, indent, indent_length, depth);
04116
04117 if (PUGI__NODETYPE(node) == node_element)
04118 {
04119 indent_flags = indent_newline | indent_indent;
04120
04121 if (node_output_start(writer, node, indent, indent_length, flags, depth))
04122 {
04123 node = node->first_child;
04124 depth++;
04125 continue;
04126 }
04127 }
04128 else if (PUGI__NODETYPE(node) == node_document)
04129 {
04130 indent_flags = indent_indent;
04131
04132 if (node->first_child)
04133 {
04134 node = node->first_child;
04135 continue;
04136 }
04137 }
04138 else
04139 {
04140 node_output_simple(writer, node, flags);
04141
04142 indent_flags = indent_newline | indent_indent;
04143 }
04144 }
04145
04146
04147 while (node != root)
04148 {
04149 if (node->next_sibling)
04150 {
04151 node = node->next_sibling;
04152 break;
04153 }
04154
04155 node = node->parent;
04156
04157
04158 if (PUGI__NODETYPE(node) == node_element)
04159 {
04160 depth--;
04161
04162 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
04163 writer.write('\n');
04164
04165 if ((indent_flags & indent_indent) && indent_length)
04166 text_output_indent(writer, indent, indent_length, depth);
04167
04168 node_output_end(writer, node);
04169
04170 indent_flags = indent_newline | indent_indent;
04171 }
04172 }
04173 }
04174 while (node != root);
04175
04176 if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
04177 writer.write('\n');
04178 }
04179
04180 PUGI__FN bool has_declaration(xml_node_struct* node)
04181 {
04182 for (xml_node_struct* child = node->first_child; child; child = child->next_sibling)
04183 {
04184 xml_node_type type = PUGI__NODETYPE(child);
04185
04186 if (type == node_declaration) return true;
04187 if (type == node_element) return false;
04188 }
04189
04190 return false;
04191 }
04192
04193 PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node)
04194 {
04195 for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
04196 if (a == attr)
04197 return true;
04198
04199 return false;
04200 }
04201
04202 PUGI__FN bool allow_insert_attribute(xml_node_type parent)
04203 {
04204 return parent == node_element || parent == node_declaration;
04205 }
04206
04207 PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child)
04208 {
04209 if (parent != node_document && parent != node_element) return false;
04210 if (child == node_document || child == node_null) return false;
04211 if (parent != node_document && (child == node_declaration || child == node_doctype)) return false;
04212
04213 return true;
04214 }
04215
04216 PUGI__FN bool allow_move(xml_node parent, xml_node child)
04217 {
04218
04219 if (!allow_insert_child(parent.type(), child.type()))
04220 return false;
04221
04222
04223 if (parent.root() != child.root())
04224 return false;
04225
04226
04227 xml_node cur = parent;
04228
04229 while (cur)
04230 {
04231 if (cur == child)
04232 return false;
04233
04234 cur = cur.parent();
04235 }
04236
04237 return true;
04238 }
04239
04240 template <typename String, typename Header>
04241 PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)
04242 {
04243 assert(!dest && (header & header_mask) == 0);
04244
04245 if (source)
04246 {
04247 if (alloc && (source_header & header_mask) == 0)
04248 {
04249 dest = source;
04250
04251
04252 header |= xml_memory_page_contents_shared_mask;
04253 source_header |= xml_memory_page_contents_shared_mask;
04254 }
04255 else
04256 strcpy_insitu(dest, header, header_mask, source, strlength(source));
04257 }
04258 }
04259
04260 PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc)
04261 {
04262 node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc);
04263 node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc);
04264
04265 for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute)
04266 {
04267 xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn));
04268
04269 if (da)
04270 {
04271 node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
04272 node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
04273 }
04274 }
04275 }
04276
04277 PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)
04278 {
04279 xml_allocator& alloc = get_allocator(dn);
04280 xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0;
04281
04282 node_copy_contents(dn, sn, shared_alloc);
04283
04284 xml_node_struct* dit = dn;
04285 xml_node_struct* sit = sn->first_child;
04286
04287 while (sit && sit != sn)
04288 {
04289 if (sit != dn)
04290 {
04291 xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit));
04292
04293 if (copy)
04294 {
04295 node_copy_contents(copy, sit, shared_alloc);
04296
04297 if (sit->first_child)
04298 {
04299 dit = copy;
04300 sit = sit->first_child;
04301 continue;
04302 }
04303 }
04304 }
04305
04306
04307 do
04308 {
04309 if (sit->next_sibling)
04310 {
04311 sit = sit->next_sibling;
04312 break;
04313 }
04314
04315 sit = sit->parent;
04316 dit = dit->parent;
04317 }
04318 while (sit != sn);
04319 }
04320 }
04321
04322 PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
04323 {
04324 xml_allocator& alloc = get_allocator(da);
04325 xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0;
04326
04327 node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
04328 node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
04329 }
04330
04331 inline bool is_text_node(xml_node_struct* node)
04332 {
04333 xml_node_type type = PUGI__NODETYPE(node);
04334
04335 return type == node_pcdata || type == node_cdata;
04336 }
04337
04338
04339 template <typename U> U string_to_integer(const char_t* value, U minneg, U maxpos)
04340 {
04341 U result = 0;
04342 const char_t* s = value;
04343
04344 while (PUGI__IS_CHARTYPE(*s, ct_space))
04345 s++;
04346
04347 bool negative = (*s == '-');
04348
04349 s += (*s == '+' || *s == '-');
04350
04351 bool overflow = false;
04352
04353 if (s[0] == '0' && (s[1] | ' ') == 'x')
04354 {
04355 s += 2;
04356
04357
04358 while (*s == '0')
04359 s++;
04360
04361 const char_t* start = s;
04362
04363 for (;;)
04364 {
04365 if (static_cast<unsigned>(*s - '0') < 10)
04366 result = result * 16 + (*s - '0');
04367 else if (static_cast<unsigned>((*s | ' ') - 'a') < 6)
04368 result = result * 16 + ((*s | ' ') - 'a' + 10);
04369 else
04370 break;
04371
04372 s++;
04373 }
04374
04375 size_t digits = static_cast<size_t>(s - start);
04376
04377 overflow = digits > sizeof(U) * 2;
04378 }
04379 else
04380 {
04381
04382 while (*s == '0')
04383 s++;
04384
04385 const char_t* start = s;
04386
04387 for (;;)
04388 {
04389 if (static_cast<unsigned>(*s - '0') < 10)
04390 result = result * 10 + (*s - '0');
04391 else
04392 break;
04393
04394 s++;
04395 }
04396
04397 size_t digits = static_cast<size_t>(s - start);
04398
04399 PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);
04400
04401 const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
04402 const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6';
04403 const size_t high_bit = sizeof(U) * 8 - 1;
04404
04405 overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit)));
04406 }
04407
04408 if (negative)
04409 return (overflow || result > minneg) ? 0 - minneg : 0 - result;
04410 else
04411 return (overflow || result > maxpos) ? maxpos : result;
04412 }
04413
04414 PUGI__FN int get_value_int(const char_t* value)
04415 {
04416 return string_to_integer<unsigned int>(value, 0 - static_cast<unsigned int>(INT_MIN), INT_MAX);
04417 }
04418
04419 PUGI__FN unsigned int get_value_uint(const char_t* value)
04420 {
04421 return string_to_integer<unsigned int>(value, 0, UINT_MAX);
04422 }
04423
04424 PUGI__FN double get_value_double(const char_t* value)
04425 {
04426 #ifdef PUGIXML_WCHAR_MODE
04427 return wcstod(value, 0);
04428 #else
04429 return strtod(value, 0);
04430 #endif
04431 }
04432
04433 PUGI__FN float get_value_float(const char_t* value)
04434 {
04435 #ifdef PUGIXML_WCHAR_MODE
04436 return static_cast<float>(wcstod(value, 0));
04437 #else
04438 return static_cast<float>(strtod(value, 0));
04439 #endif
04440 }
04441
04442 PUGI__FN bool get_value_bool(const char_t* value)
04443 {
04444
04445 char_t first = *value;
04446
04447
04448 return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
04449 }
04450
04451 #ifdef PUGIXML_HAS_LONG_LONG
04452 PUGI__FN long long get_value_llong(const char_t* value)
04453 {
04454 return string_to_integer<unsigned long long>(value, 0 - static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);
04455 }
04456
04457 PUGI__FN unsigned long long get_value_ullong(const char_t* value)
04458 {
04459 return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);
04460 }
04461 #endif
04462
04463 template <typename U>
04464 PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative)
04465 {
04466 char_t* result = end - 1;
04467 U rest = negative ? 0 - value : value;
04468
04469 do
04470 {
04471 *result-- = static_cast<char_t>('0' + (rest % 10));
04472 rest /= 10;
04473 }
04474 while (rest);
04475
04476 assert(result >= begin);
04477 (void)begin;
04478
04479 *result = '-';
04480
04481 return result + !negative;
04482 }
04483
04484
04485 template <typename String, typename Header>
04486 PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf)
04487 {
04488 #ifdef PUGIXML_WCHAR_MODE
04489 char_t wbuf[128];
04490 assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0]));
04491
04492 size_t offset = 0;
04493 for (; buf[offset]; ++offset) wbuf[offset] = buf[offset];
04494
04495 return strcpy_insitu(dest, header, header_mask, wbuf, offset);
04496 #else
04497 return strcpy_insitu(dest, header, header_mask, buf, strlen(buf));
04498 #endif
04499 }
04500
04501 template <typename String, typename Header>
04502 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, int value)
04503 {
04504 char_t buf[64];
04505 char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
04506 char_t* begin = integer_to_string<unsigned int>(buf, end, value, value < 0);
04507
04508 return strcpy_insitu(dest, header, header_mask, begin, end - begin);
04509 }
04510
04511 template <typename String, typename Header>
04512 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned int value)
04513 {
04514 char_t buf[64];
04515 char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
04516 char_t* begin = integer_to_string<unsigned int>(buf, end, value, false);
04517
04518 return strcpy_insitu(dest, header, header_mask, begin, end - begin);
04519 }
04520
04521 template <typename String, typename Header>
04522 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value)
04523 {
04524 char buf[128];
04525 sprintf(buf, "%.9g", value);
04526
04527 return set_value_ascii(dest, header, header_mask, buf);
04528 }
04529
04530 template <typename String, typename Header>
04531 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value)
04532 {
04533 char buf[128];
04534 sprintf(buf, "%.17g", value);
04535
04536 return set_value_ascii(dest, header, header_mask, buf);
04537 }
04538
04539 template <typename String, typename Header>
04540 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, bool value)
04541 {
04542 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5);
04543 }
04544
04545 #ifdef PUGIXML_HAS_LONG_LONG
04546 template <typename String, typename Header>
04547 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, long long value)
04548 {
04549 char_t buf[64];
04550 char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
04551 char_t* begin = integer_to_string<unsigned long long>(buf, end, value, value < 0);
04552
04553 return strcpy_insitu(dest, header, header_mask, begin, end - begin);
04554 }
04555
04556 template <typename String, typename Header>
04557 PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned long long value)
04558 {
04559 char_t buf[64];
04560 char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
04561 char_t* begin = integer_to_string<unsigned long long>(buf, end, value, false);
04562
04563 return strcpy_insitu(dest, header, header_mask, begin, end - begin);
04564 }
04565 #endif
04566
04567 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)
04568 {
04569
04570 if (!contents && size) return make_parse_result(status_io_error);
04571
04572
04573 xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
04574
04575
04576 char_t* buffer = 0;
04577 size_t length = 0;
04578
04579 if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
04580
04581
04582 if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
04583
04584
04585 if (own || buffer != contents) *out_buffer = buffer;
04586
04587
04588 doc->buffer = buffer;
04589
04590
04591 xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
04592
04593
04594 res.encoding = buffer_encoding;
04595
04596 return res;
04597 }
04598
04599
04600 PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
04601 {
04602 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
04603
04604 typedef __int64 length_type;
04605
04606 _fseeki64(file, 0, SEEK_END);
04607 length_type length = _ftelli64(file);
04608 _fseeki64(file, 0, SEEK_SET);
04609 #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))
04610
04611 typedef off64_t length_type;
04612
04613 fseeko64(file, 0, SEEK_END);
04614 length_type length = ftello64(file);
04615 fseeko64(file, 0, SEEK_SET);
04616 #else
04617
04618 typedef long length_type;
04619
04620 fseek(file, 0, SEEK_END);
04621 length_type length = ftell(file);
04622 fseek(file, 0, SEEK_SET);
04623 #endif
04624
04625
04626 if (length < 0) return status_io_error;
04627
04628
04629 size_t result = static_cast<size_t>(length);
04630
04631 if (static_cast<length_type>(result) != length) return status_out_of_memory;
04632
04633
04634 out_result = result;
04635
04636 return status_ok;
04637 }
04638
04639
04640 PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding)
04641 {
04642
04643 #ifdef PUGIXML_WCHAR_MODE
04644 xml_encoding wchar_encoding = get_wchar_encoding();
04645
04646 if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding))
04647 {
04648 size_t length = size / sizeof(char_t);
04649
04650 static_cast<char_t*>(buffer)[length] = 0;
04651 return (length + 1) * sizeof(char_t);
04652 }
04653 #else
04654 if (encoding == encoding_utf8)
04655 {
04656 static_cast<char*>(buffer)[size] = 0;
04657 return size + 1;
04658 }
04659 #endif
04660
04661 return size;
04662 }
04663
04664 PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer)
04665 {
04666 if (!file) return make_parse_result(status_file_not_found);
04667
04668
04669 size_t size = 0;
04670 xml_parse_status size_status = get_file_size(file, size);
04671 if (size_status != status_ok) return make_parse_result(size_status);
04672
04673 size_t max_suffix_size = sizeof(char_t);
04674
04675
04676 char* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size));
04677 if (!contents) return make_parse_result(status_out_of_memory);
04678
04679
04680 size_t read_size = fread(contents, 1, size, file);
04681
04682 if (read_size != size)
04683 {
04684 xml_memory::deallocate(contents);
04685 return make_parse_result(status_io_error);
04686 }
04687
04688 xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
04689
04690 return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer);
04691 }
04692
04693 #ifndef PUGIXML_NO_STL
04694 template <typename T> struct xml_stream_chunk
04695 {
04696 static xml_stream_chunk* create()
04697 {
04698 void* memory = xml_memory::allocate(sizeof(xml_stream_chunk));
04699 if (!memory) return 0;
04700
04701 return new (memory) xml_stream_chunk();
04702 }
04703
04704 static void destroy(xml_stream_chunk* chunk)
04705 {
04706
04707 while (chunk)
04708 {
04709 xml_stream_chunk* next_ = chunk->next;
04710
04711 xml_memory::deallocate(chunk);
04712
04713 chunk = next_;
04714 }
04715 }
04716
04717 xml_stream_chunk(): next(0), size(0)
04718 {
04719 }
04720
04721 xml_stream_chunk* next;
04722 size_t size;
04723
04724 T data[xml_memory_page_size / sizeof(T)];
04725 };
04726
04727 template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
04728 {
04729 auto_deleter<xml_stream_chunk<T> > chunks(0, xml_stream_chunk<T>::destroy);
04730
04731
04732 size_t total = 0;
04733 xml_stream_chunk<T>* last = 0;
04734
04735 while (!stream.eof())
04736 {
04737
04738 xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create();
04739 if (!chunk) return status_out_of_memory;
04740
04741
04742 if (last) last = last->next = chunk;
04743 else chunks.data = last = chunk;
04744
04745
04746 stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));
04747 chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);
04748
04749
04750 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
04751
04752
04753 if (total + chunk->size < total) return status_out_of_memory;
04754 total += chunk->size;
04755 }
04756
04757 size_t max_suffix_size = sizeof(char_t);
04758
04759
04760 char* buffer = static_cast<char*>(xml_memory::allocate(total + max_suffix_size));
04761 if (!buffer) return status_out_of_memory;
04762
04763 char* write = buffer;
04764
04765 for (xml_stream_chunk<T>* chunk = chunks.data; chunk; chunk = chunk->next)
04766 {
04767 assert(write + chunk->size <= buffer + total);
04768 memcpy(write, chunk->data, chunk->size);
04769 write += chunk->size;
04770 }
04771
04772 assert(write == buffer + total);
04773
04774
04775 *out_buffer = buffer;
04776 *out_size = total;
04777
04778 return status_ok;
04779 }
04780
04781 template <typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
04782 {
04783
04784 typename std::basic_istream<T>::pos_type pos = stream.tellg();
04785 stream.seekg(0, std::ios::end);
04786 std::streamoff length = stream.tellg() - pos;
04787 stream.seekg(pos);
04788
04789 if (stream.fail() || pos < 0) return status_io_error;
04790
04791
04792 size_t read_length = static_cast<size_t>(length);
04793
04794 if (static_cast<std::streamsize>(read_length) != length || length < 0) return status_out_of_memory;
04795
04796 size_t max_suffix_size = sizeof(char_t);
04797
04798
04799 auto_deleter<void> buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);
04800 if (!buffer.data) return status_out_of_memory;
04801
04802 stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
04803
04804
04805 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
04806
04807
04808 size_t actual_length = static_cast<size_t>(stream.gcount());
04809 assert(actual_length <= read_length);
04810
04811 *out_buffer = buffer.release();
04812 *out_size = actual_length * sizeof(T);
04813
04814 return status_ok;
04815 }
04816
04817 template <typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer)
04818 {
04819 void* buffer = 0;
04820 size_t size = 0;
04821 xml_parse_status status = status_ok;
04822
04823
04824 if (stream.fail()) return make_parse_result(status_io_error);
04825
04826
04827 if (stream.tellg() < 0)
04828 {
04829 stream.clear();
04830 status = load_stream_data_noseek(stream, &buffer, &size);
04831 }
04832 else
04833 status = load_stream_data_seek(stream, &buffer, &size);
04834
04835 if (status != status_ok) return make_parse_result(status);
04836
04837 xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
04838
04839 return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer);
04840 }
04841 #endif
04842
04843 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))
04844 PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
04845 {
04846 return _wfopen(path, mode);
04847 }
04848 #else
04849 PUGI__FN char* convert_path_heap(const wchar_t* str)
04850 {
04851 assert(str);
04852
04853
04854 size_t length = strlength_wide(str);
04855 size_t size = as_utf8_begin(str, length);
04856
04857
04858 char* result = static_cast<char*>(xml_memory::allocate(size + 1));
04859 if (!result) return 0;
04860
04861
04862 as_utf8_end(result, size, str, length);
04863
04864
04865 result[size] = 0;
04866
04867 return result;
04868 }
04869
04870 PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
04871 {
04872
04873 char* path_utf8 = convert_path_heap(path);
04874 if (!path_utf8) return 0;
04875
04876
04877 char mode_ascii[4] = {0};
04878 for (size_t i = 0; mode[i]; ++i) mode_ascii[i] = static_cast<char>(mode[i]);
04879
04880
04881 FILE* result = fopen(path_utf8, mode_ascii);
04882
04883
04884 xml_memory::deallocate(path_utf8);
04885
04886 return result;
04887 }
04888 #endif
04889
04890 PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)
04891 {
04892 if (!file) return false;
04893
04894 xml_writer_file writer(file);
04895 doc.save(writer, indent, flags, encoding);
04896
04897 return ferror(file) == 0;
04898 }
04899
04900 struct name_null_sentry
04901 {
04902 xml_node_struct* node;
04903 char_t* name;
04904
04905 name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name)
04906 {
04907 node->name = 0;
04908 }
04909
04910 ~name_null_sentry()
04911 {
04912 node->name = name;
04913 }
04914 };
04915 PUGI__NS_END
04916
04917 namespace pugi
04918 {
04919 PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_)
04920 {
04921 }
04922
04923 PUGI__FN void xml_writer_file::write(const void* data, size_t size)
04924 {
04925 size_t result = fwrite(data, 1, size, static_cast<FILE*>(file));
04926 (void)!result;
04927 }
04928
04929 #ifndef PUGIXML_NO_STL
04930 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
04931 {
04932 }
04933
04934 PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
04935 {
04936 }
04937
04938 PUGI__FN void xml_writer_stream::write(const void* data, size_t size)
04939 {
04940 if (narrow_stream)
04941 {
04942 assert(!wide_stream);
04943 narrow_stream->write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
04944 }
04945 else
04946 {
04947 assert(wide_stream);
04948 assert(size % sizeof(wchar_t) == 0);
04949
04950 wide_stream->write(reinterpret_cast<const wchar_t*>(data), static_cast<std::streamsize>(size / sizeof(wchar_t)));
04951 }
04952 }
04953 #endif
04954
04955 PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0)
04956 {
04957 }
04958
04959 PUGI__FN xml_tree_walker::~xml_tree_walker()
04960 {
04961 }
04962
04963 PUGI__FN int xml_tree_walker::depth() const
04964 {
04965 return _depth;
04966 }
04967
04968 PUGI__FN bool xml_tree_walker::begin(xml_node&)
04969 {
04970 return true;
04971 }
04972
04973 PUGI__FN bool xml_tree_walker::end(xml_node&)
04974 {
04975 return true;
04976 }
04977
04978 PUGI__FN xml_attribute::xml_attribute(): _attr(0)
04979 {
04980 }
04981
04982 PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
04983 {
04984 }
04985
04986 PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***)
04987 {
04988 }
04989
04990 PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
04991 {
04992 return _attr ? unspecified_bool_xml_attribute : 0;
04993 }
04994
04995 PUGI__FN bool xml_attribute::operator!() const
04996 {
04997 return !_attr;
04998 }
04999
05000 PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const
05001 {
05002 return (_attr == r._attr);
05003 }
05004
05005 PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const
05006 {
05007 return (_attr != r._attr);
05008 }
05009
05010 PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const
05011 {
05012 return (_attr < r._attr);
05013 }
05014
05015 PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const
05016 {
05017 return (_attr > r._attr);
05018 }
05019
05020 PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const
05021 {
05022 return (_attr <= r._attr);
05023 }
05024
05025 PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const
05026 {
05027 return (_attr >= r._attr);
05028 }
05029
05030 PUGI__FN xml_attribute xml_attribute::next_attribute() const
05031 {
05032 return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
05033 }
05034
05035 PUGI__FN xml_attribute xml_attribute::previous_attribute() const
05036 {
05037 return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
05038 }
05039
05040 PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const
05041 {
05042 return (_attr && _attr->value) ? _attr->value + 0 : def;
05043 }
05044
05045 PUGI__FN int xml_attribute::as_int(int def) const
05046 {
05047 return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def;
05048 }
05049
05050 PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
05051 {
05052 return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def;
05053 }
05054
05055 PUGI__FN double xml_attribute::as_double(double def) const
05056 {
05057 return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def;
05058 }
05059
05060 PUGI__FN float xml_attribute::as_float(float def) const
05061 {
05062 return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def;
05063 }
05064
05065 PUGI__FN bool xml_attribute::as_bool(bool def) const
05066 {
05067 return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def;
05068 }
05069
05070 #ifdef PUGIXML_HAS_LONG_LONG
05071 PUGI__FN long long xml_attribute::as_llong(long long def) const
05072 {
05073 return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def;
05074 }
05075
05076 PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
05077 {
05078 return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def;
05079 }
05080 #endif
05081
05082 PUGI__FN bool xml_attribute::empty() const
05083 {
05084 return !_attr;
05085 }
05086
05087 PUGI__FN const char_t* xml_attribute::name() const
05088 {
05089 return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT("");
05090 }
05091
05092 PUGI__FN const char_t* xml_attribute::value() const
05093 {
05094 return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT("");
05095 }
05096
05097 PUGI__FN size_t xml_attribute::hash_value() const
05098 {
05099 return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
05100 }
05101
05102 PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const
05103 {
05104 return _attr;
05105 }
05106
05107 PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs)
05108 {
05109 set_value(rhs);
05110 return *this;
05111 }
05112
05113 PUGI__FN xml_attribute& xml_attribute::operator=(int rhs)
05114 {
05115 set_value(rhs);
05116 return *this;
05117 }
05118
05119 PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs)
05120 {
05121 set_value(rhs);
05122 return *this;
05123 }
05124
05125 PUGI__FN xml_attribute& xml_attribute::operator=(double rhs)
05126 {
05127 set_value(rhs);
05128 return *this;
05129 }
05130
05131 PUGI__FN xml_attribute& xml_attribute::operator=(float rhs)
05132 {
05133 set_value(rhs);
05134 return *this;
05135 }
05136
05137 PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs)
05138 {
05139 set_value(rhs);
05140 return *this;
05141 }
05142
05143 #ifdef PUGIXML_HAS_LONG_LONG
05144 PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs)
05145 {
05146 set_value(rhs);
05147 return *this;
05148 }
05149
05150 PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs)
05151 {
05152 set_value(rhs);
05153 return *this;
05154 }
05155 #endif
05156
05157 PUGI__FN bool xml_attribute::set_name(const char_t* rhs)
05158 {
05159 if (!_attr) return false;
05160
05161 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
05162 }
05163
05164 PUGI__FN bool xml_attribute::set_value(const char_t* rhs)
05165 {
05166 if (!_attr) return false;
05167
05168 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
05169 }
05170
05171 PUGI__FN bool xml_attribute::set_value(int rhs)
05172 {
05173 if (!_attr) return false;
05174
05175 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
05176 }
05177
05178 PUGI__FN bool xml_attribute::set_value(unsigned int rhs)
05179 {
05180 if (!_attr) return false;
05181
05182 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
05183 }
05184
05185 PUGI__FN bool xml_attribute::set_value(double rhs)
05186 {
05187 if (!_attr) return false;
05188
05189 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
05190 }
05191
05192 PUGI__FN bool xml_attribute::set_value(float rhs)
05193 {
05194 if (!_attr) return false;
05195
05196 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
05197 }
05198
05199 PUGI__FN bool xml_attribute::set_value(bool rhs)
05200 {
05201 if (!_attr) return false;
05202
05203 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
05204 }
05205
05206 #ifdef PUGIXML_HAS_LONG_LONG
05207 PUGI__FN bool xml_attribute::set_value(long long rhs)
05208 {
05209 if (!_attr) return false;
05210
05211 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
05212 }
05213
05214 PUGI__FN bool xml_attribute::set_value(unsigned long long rhs)
05215 {
05216 if (!_attr) return false;
05217
05218 return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
05219 }
05220 #endif
05221
05222 #ifdef __BORLANDC__
05223 PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs)
05224 {
05225 return (bool)lhs && rhs;
05226 }
05227
05228 PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs)
05229 {
05230 return (bool)lhs || rhs;
05231 }
05232 #endif
05233
05234 PUGI__FN xml_node::xml_node(): _root(0)
05235 {
05236 }
05237
05238 PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p)
05239 {
05240 }
05241
05242 PUGI__FN static void unspecified_bool_xml_node(xml_node***)
05243 {
05244 }
05245
05246 PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const
05247 {
05248 return _root ? unspecified_bool_xml_node : 0;
05249 }
05250
05251 PUGI__FN bool xml_node::operator!() const
05252 {
05253 return !_root;
05254 }
05255
05256 PUGI__FN xml_node::iterator xml_node::begin() const
05257 {
05258 return iterator(_root ? _root->first_child + 0 : 0, _root);
05259 }
05260
05261 PUGI__FN xml_node::iterator xml_node::end() const
05262 {
05263 return iterator(0, _root);
05264 }
05265
05266 PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const
05267 {
05268 return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root);
05269 }
05270
05271 PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const
05272 {
05273 return attribute_iterator(0, _root);
05274 }
05275
05276 PUGI__FN xml_object_range<xml_node_iterator> xml_node::children() const
05277 {
05278 return xml_object_range<xml_node_iterator>(begin(), end());
05279 }
05280
05281 PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(const char_t* name_) const
05282 {
05283 return xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_));
05284 }
05285
05286 PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes() const
05287 {
05288 return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());
05289 }
05290
05291 PUGI__FN bool xml_node::operator==(const xml_node& r) const
05292 {
05293 return (_root == r._root);
05294 }
05295
05296 PUGI__FN bool xml_node::operator!=(const xml_node& r) const
05297 {
05298 return (_root != r._root);
05299 }
05300
05301 PUGI__FN bool xml_node::operator<(const xml_node& r) const
05302 {
05303 return (_root < r._root);
05304 }
05305
05306 PUGI__FN bool xml_node::operator>(const xml_node& r) const
05307 {
05308 return (_root > r._root);
05309 }
05310
05311 PUGI__FN bool xml_node::operator<=(const xml_node& r) const
05312 {
05313 return (_root <= r._root);
05314 }
05315
05316 PUGI__FN bool xml_node::operator>=(const xml_node& r) const
05317 {
05318 return (_root >= r._root);
05319 }
05320
05321 PUGI__FN bool xml_node::empty() const
05322 {
05323 return !_root;
05324 }
05325
05326 PUGI__FN const char_t* xml_node::name() const
05327 {
05328 return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT("");
05329 }
05330
05331 PUGI__FN xml_node_type xml_node::type() const
05332 {
05333 return _root ? PUGI__NODETYPE(_root) : node_null;
05334 }
05335
05336 PUGI__FN const char_t* xml_node::value() const
05337 {
05338 return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT("");
05339 }
05340
05341 PUGI__FN xml_node xml_node::child(const char_t* name_) const
05342 {
05343 if (!_root) return xml_node();
05344
05345 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
05346 if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
05347
05348 return xml_node();
05349 }
05350
05351 PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const
05352 {
05353 if (!_root) return xml_attribute();
05354
05355 for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
05356 if (i->name && impl::strequal(name_, i->name))
05357 return xml_attribute(i);
05358
05359 return xml_attribute();
05360 }
05361
05362 PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const
05363 {
05364 if (!_root) return xml_node();
05365
05366 for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
05367 if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
05368
05369 return xml_node();
05370 }
05371
05372 PUGI__FN xml_node xml_node::next_sibling() const
05373 {
05374 return _root ? xml_node(_root->next_sibling) : xml_node();
05375 }
05376
05377 PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const
05378 {
05379 if (!_root) return xml_node();
05380
05381 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
05382 if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
05383
05384 return xml_node();
05385 }
05386
05387 PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const
05388 {
05389 xml_attribute_struct* hint = hint_._attr;
05390
05391
05392 assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
05393
05394 if (!_root) return xml_attribute();
05395
05396
05397 for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
05398 if (i->name && impl::strequal(name_, i->name))
05399 {
05400
05401 hint_._attr = i->next_attribute;
05402
05403 return xml_attribute(i);
05404 }
05405
05406
05407
05408 for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)
05409 if (j->name && impl::strequal(name_, j->name))
05410 {
05411
05412 hint_._attr = j->next_attribute;
05413
05414 return xml_attribute(j);
05415 }
05416
05417 return xml_attribute();
05418 }
05419
05420 PUGI__FN xml_node xml_node::previous_sibling() const
05421 {
05422 if (!_root) return xml_node();
05423
05424 if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c);
05425 else return xml_node();
05426 }
05427
05428 PUGI__FN xml_node xml_node::parent() const
05429 {
05430 return _root ? xml_node(_root->parent) : xml_node();
05431 }
05432
05433 PUGI__FN xml_node xml_node::root() const
05434 {
05435 return _root ? xml_node(&impl::get_document(_root)) : xml_node();
05436 }
05437
05438 PUGI__FN xml_text xml_node::text() const
05439 {
05440 return xml_text(_root);
05441 }
05442
05443 PUGI__FN const char_t* xml_node::child_value() const
05444 {
05445 if (!_root) return PUGIXML_TEXT("");
05446
05447 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
05448 if (impl::is_text_node(i) && i->value)
05449 return i->value;
05450
05451 return PUGIXML_TEXT("");
05452 }
05453
05454 PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const
05455 {
05456 return child(name_).child_value();
05457 }
05458
05459 PUGI__FN xml_attribute xml_node::first_attribute() const
05460 {
05461 return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
05462 }
05463
05464 PUGI__FN xml_attribute xml_node::last_attribute() const
05465 {
05466 return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute();
05467 }
05468
05469 PUGI__FN xml_node xml_node::first_child() const
05470 {
05471 return _root ? xml_node(_root->first_child) : xml_node();
05472 }
05473
05474 PUGI__FN xml_node xml_node::last_child() const
05475 {
05476 return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
05477 }
05478
05479 PUGI__FN bool xml_node::set_name(const char_t* rhs)
05480 {
05481 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
05482
05483 if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
05484 return false;
05485
05486 return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
05487 }
05488
05489 PUGI__FN bool xml_node::set_value(const char_t* rhs)
05490 {
05491 xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
05492
05493 if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
05494 return false;
05495
05496 return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
05497 }
05498
05499 PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_)
05500 {
05501 if (!impl::allow_insert_attribute(type())) return xml_attribute();
05502
05503 impl::xml_allocator& alloc = impl::get_allocator(_root);
05504 if (!alloc.reserve()) return xml_attribute();
05505
05506 xml_attribute a(impl::allocate_attribute(alloc));
05507 if (!a) return xml_attribute();
05508
05509 impl::append_attribute(a._attr, _root);
05510
05511 a.set_name(name_);
05512
05513 return a;
05514 }
05515
05516 PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_)
05517 {
05518 if (!impl::allow_insert_attribute(type())) return xml_attribute();
05519
05520 impl::xml_allocator& alloc = impl::get_allocator(_root);
05521 if (!alloc.reserve()) return xml_attribute();
05522
05523 xml_attribute a(impl::allocate_attribute(alloc));
05524 if (!a) return xml_attribute();
05525
05526 impl::prepend_attribute(a._attr, _root);
05527
05528 a.set_name(name_);
05529
05530 return a;
05531 }
05532
05533 PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr)
05534 {
05535 if (!impl::allow_insert_attribute(type())) return xml_attribute();
05536 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
05537
05538 impl::xml_allocator& alloc = impl::get_allocator(_root);
05539 if (!alloc.reserve()) return xml_attribute();
05540
05541 xml_attribute a(impl::allocate_attribute(alloc));
05542 if (!a) return xml_attribute();
05543
05544 impl::insert_attribute_after(a._attr, attr._attr, _root);
05545
05546 a.set_name(name_);
05547
05548 return a;
05549 }
05550
05551 PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr)
05552 {
05553 if (!impl::allow_insert_attribute(type())) return xml_attribute();
05554 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
05555
05556 impl::xml_allocator& alloc = impl::get_allocator(_root);
05557 if (!alloc.reserve()) return xml_attribute();
05558
05559 xml_attribute a(impl::allocate_attribute(alloc));
05560 if (!a) return xml_attribute();
05561
05562 impl::insert_attribute_before(a._attr, attr._attr, _root);
05563
05564 a.set_name(name_);
05565
05566 return a;
05567 }
05568
05569 PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto)
05570 {
05571 if (!proto) return xml_attribute();
05572 if (!impl::allow_insert_attribute(type())) return xml_attribute();
05573
05574 impl::xml_allocator& alloc = impl::get_allocator(_root);
05575 if (!alloc.reserve()) return xml_attribute();
05576
05577 xml_attribute a(impl::allocate_attribute(alloc));
05578 if (!a) return xml_attribute();
05579
05580 impl::append_attribute(a._attr, _root);
05581 impl::node_copy_attribute(a._attr, proto._attr);
05582
05583 return a;
05584 }
05585
05586 PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto)
05587 {
05588 if (!proto) return xml_attribute();
05589 if (!impl::allow_insert_attribute(type())) return xml_attribute();
05590
05591 impl::xml_allocator& alloc = impl::get_allocator(_root);
05592 if (!alloc.reserve()) return xml_attribute();
05593
05594 xml_attribute a(impl::allocate_attribute(alloc));
05595 if (!a) return xml_attribute();
05596
05597 impl::prepend_attribute(a._attr, _root);
05598 impl::node_copy_attribute(a._attr, proto._attr);
05599
05600 return a;
05601 }
05602
05603 PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr)
05604 {
05605 if (!proto) return xml_attribute();
05606 if (!impl::allow_insert_attribute(type())) return xml_attribute();
05607 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
05608
05609 impl::xml_allocator& alloc = impl::get_allocator(_root);
05610 if (!alloc.reserve()) return xml_attribute();
05611
05612 xml_attribute a(impl::allocate_attribute(alloc));
05613 if (!a) return xml_attribute();
05614
05615 impl::insert_attribute_after(a._attr, attr._attr, _root);
05616 impl::node_copy_attribute(a._attr, proto._attr);
05617
05618 return a;
05619 }
05620
05621 PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr)
05622 {
05623 if (!proto) return xml_attribute();
05624 if (!impl::allow_insert_attribute(type())) return xml_attribute();
05625 if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
05626
05627 impl::xml_allocator& alloc = impl::get_allocator(_root);
05628 if (!alloc.reserve()) return xml_attribute();
05629
05630 xml_attribute a(impl::allocate_attribute(alloc));
05631 if (!a) return xml_attribute();
05632
05633 impl::insert_attribute_before(a._attr, attr._attr, _root);
05634 impl::node_copy_attribute(a._attr, proto._attr);
05635
05636 return a;
05637 }
05638
05639 PUGI__FN xml_node xml_node::append_child(xml_node_type type_)
05640 {
05641 if (!impl::allow_insert_child(type(), type_)) return xml_node();
05642
05643 impl::xml_allocator& alloc = impl::get_allocator(_root);
05644 if (!alloc.reserve()) return xml_node();
05645
05646 xml_node n(impl::allocate_node(alloc, type_));
05647 if (!n) return xml_node();
05648
05649 impl::append_node(n._root, _root);
05650
05651 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
05652
05653 return n;
05654 }
05655
05656 PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_)
05657 {
05658 if (!impl::allow_insert_child(type(), type_)) return xml_node();
05659
05660 impl::xml_allocator& alloc = impl::get_allocator(_root);
05661 if (!alloc.reserve()) return xml_node();
05662
05663 xml_node n(impl::allocate_node(alloc, type_));
05664 if (!n) return xml_node();
05665
05666 impl::prepend_node(n._root, _root);
05667
05668 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
05669
05670 return n;
05671 }
05672
05673 PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node)
05674 {
05675 if (!impl::allow_insert_child(type(), type_)) return xml_node();
05676 if (!node._root || node._root->parent != _root) return xml_node();
05677
05678 impl::xml_allocator& alloc = impl::get_allocator(_root);
05679 if (!alloc.reserve()) return xml_node();
05680
05681 xml_node n(impl::allocate_node(alloc, type_));
05682 if (!n) return xml_node();
05683
05684 impl::insert_node_before(n._root, node._root);
05685
05686 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
05687
05688 return n;
05689 }
05690
05691 PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node)
05692 {
05693 if (!impl::allow_insert_child(type(), type_)) return xml_node();
05694 if (!node._root || node._root->parent != _root) return xml_node();
05695
05696 impl::xml_allocator& alloc = impl::get_allocator(_root);
05697 if (!alloc.reserve()) return xml_node();
05698
05699 xml_node n(impl::allocate_node(alloc, type_));
05700 if (!n) return xml_node();
05701
05702 impl::insert_node_after(n._root, node._root);
05703
05704 if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
05705
05706 return n;
05707 }
05708
05709 PUGI__FN xml_node xml_node::append_child(const char_t* name_)
05710 {
05711 xml_node result = append_child(node_element);
05712
05713 result.set_name(name_);
05714
05715 return result;
05716 }
05717
05718 PUGI__FN xml_node xml_node::prepend_child(const char_t* name_)
05719 {
05720 xml_node result = prepend_child(node_element);
05721
05722 result.set_name(name_);
05723
05724 return result;
05725 }
05726
05727 PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node)
05728 {
05729 xml_node result = insert_child_after(node_element, node);
05730
05731 result.set_name(name_);
05732
05733 return result;
05734 }
05735
05736 PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node)
05737 {
05738 xml_node result = insert_child_before(node_element, node);
05739
05740 result.set_name(name_);
05741
05742 return result;
05743 }
05744
05745 PUGI__FN xml_node xml_node::append_copy(const xml_node& proto)
05746 {
05747 xml_node_type type_ = proto.type();
05748 if (!impl::allow_insert_child(type(), type_)) return xml_node();
05749
05750 impl::xml_allocator& alloc = impl::get_allocator(_root);
05751 if (!alloc.reserve()) return xml_node();
05752
05753 xml_node n(impl::allocate_node(alloc, type_));
05754 if (!n) return xml_node();
05755
05756 impl::append_node(n._root, _root);
05757 impl::node_copy_tree(n._root, proto._root);
05758
05759 return n;
05760 }
05761
05762 PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto)
05763 {
05764 xml_node_type type_ = proto.type();
05765 if (!impl::allow_insert_child(type(), type_)) return xml_node();
05766
05767 impl::xml_allocator& alloc = impl::get_allocator(_root);
05768 if (!alloc.reserve()) return xml_node();
05769
05770 xml_node n(impl::allocate_node(alloc, type_));
05771 if (!n) return xml_node();
05772
05773 impl::prepend_node(n._root, _root);
05774 impl::node_copy_tree(n._root, proto._root);
05775
05776 return n;
05777 }
05778
05779 PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)
05780 {
05781 xml_node_type type_ = proto.type();
05782 if (!impl::allow_insert_child(type(), type_)) return xml_node();
05783 if (!node._root || node._root->parent != _root) return xml_node();
05784
05785 impl::xml_allocator& alloc = impl::get_allocator(_root);
05786 if (!alloc.reserve()) return xml_node();
05787
05788 xml_node n(impl::allocate_node(alloc, type_));
05789 if (!n) return xml_node();
05790
05791 impl::insert_node_after(n._root, node._root);
05792 impl::node_copy_tree(n._root, proto._root);
05793
05794 return n;
05795 }
05796
05797 PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)
05798 {
05799 xml_node_type type_ = proto.type();
05800 if (!impl::allow_insert_child(type(), type_)) return xml_node();
05801 if (!node._root || node._root->parent != _root) return xml_node();
05802
05803 impl::xml_allocator& alloc = impl::get_allocator(_root);
05804 if (!alloc.reserve()) return xml_node();
05805
05806 xml_node n(impl::allocate_node(alloc, type_));
05807 if (!n) return xml_node();
05808
05809 impl::insert_node_before(n._root, node._root);
05810 impl::node_copy_tree(n._root, proto._root);
05811
05812 return n;
05813 }
05814
05815 PUGI__FN xml_node xml_node::append_move(const xml_node& moved)
05816 {
05817 if (!impl::allow_move(*this, moved)) return xml_node();
05818
05819 impl::xml_allocator& alloc = impl::get_allocator(_root);
05820 if (!alloc.reserve()) return xml_node();
05821
05822
05823 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
05824
05825 impl::remove_node(moved._root);
05826 impl::append_node(moved._root, _root);
05827
05828 return moved;
05829 }
05830
05831 PUGI__FN xml_node xml_node::prepend_move(const xml_node& moved)
05832 {
05833 if (!impl::allow_move(*this, moved)) return xml_node();
05834
05835 impl::xml_allocator& alloc = impl::get_allocator(_root);
05836 if (!alloc.reserve()) return xml_node();
05837
05838
05839 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
05840
05841 impl::remove_node(moved._root);
05842 impl::prepend_node(moved._root, _root);
05843
05844 return moved;
05845 }
05846
05847 PUGI__FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node)
05848 {
05849 if (!impl::allow_move(*this, moved)) return xml_node();
05850 if (!node._root || node._root->parent != _root) return xml_node();
05851 if (moved._root == node._root) return xml_node();
05852
05853 impl::xml_allocator& alloc = impl::get_allocator(_root);
05854 if (!alloc.reserve()) return xml_node();
05855
05856
05857 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
05858
05859 impl::remove_node(moved._root);
05860 impl::insert_node_after(moved._root, node._root);
05861
05862 return moved;
05863 }
05864
05865 PUGI__FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node)
05866 {
05867 if (!impl::allow_move(*this, moved)) return xml_node();
05868 if (!node._root || node._root->parent != _root) return xml_node();
05869 if (moved._root == node._root) return xml_node();
05870
05871 impl::xml_allocator& alloc = impl::get_allocator(_root);
05872 if (!alloc.reserve()) return xml_node();
05873
05874
05875 impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
05876
05877 impl::remove_node(moved._root);
05878 impl::insert_node_before(moved._root, node._root);
05879
05880 return moved;
05881 }
05882
05883 PUGI__FN bool xml_node::remove_attribute(const char_t* name_)
05884 {
05885 return remove_attribute(attribute(name_));
05886 }
05887
05888 PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a)
05889 {
05890 if (!_root || !a._attr) return false;
05891 if (!impl::is_attribute_of(a._attr, _root)) return false;
05892
05893 impl::xml_allocator& alloc = impl::get_allocator(_root);
05894 if (!alloc.reserve()) return false;
05895
05896 impl::remove_attribute(a._attr, _root);
05897 impl::destroy_attribute(a._attr, alloc);
05898
05899 return true;
05900 }
05901
05902 PUGI__FN bool xml_node::remove_child(const char_t* name_)
05903 {
05904 return remove_child(child(name_));
05905 }
05906
05907 PUGI__FN bool xml_node::remove_child(const xml_node& n)
05908 {
05909 if (!_root || !n._root || n._root->parent != _root) return false;
05910
05911 impl::xml_allocator& alloc = impl::get_allocator(_root);
05912 if (!alloc.reserve()) return false;
05913
05914 impl::remove_node(n._root);
05915 impl::destroy_node(n._root, alloc);
05916
05917 return true;
05918 }
05919
05920 PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
05921 {
05922
05923 if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root);
05924
05925
05926 impl::xml_document_struct* doc = &impl::get_document(_root);
05927
05928
05929 doc->header |= impl::xml_memory_page_contents_shared_mask;
05930
05931
05932 impl::xml_memory_page* page = 0;
05933 impl::xml_extra_buffer* extra = static_cast<impl::xml_extra_buffer*>(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page));
05934 (void)page;
05935
05936 if (!extra) return impl::make_parse_result(status_out_of_memory);
05937
05938
05939 extra->buffer = 0;
05940 extra->next = doc->extra_buffers;
05941 doc->extra_buffers = extra;
05942
05943
05944 impl::name_null_sentry sentry(_root);
05945
05946 return impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &extra->buffer);
05947 }
05948
05949 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
05950 {
05951 if (!_root) return xml_node();
05952
05953 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
05954 if (i->name && impl::strequal(name_, i->name))
05955 {
05956 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
05957 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
05958 return xml_node(i);
05959 }
05960
05961 return xml_node();
05962 }
05963
05964 PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
05965 {
05966 if (!_root) return xml_node();
05967
05968 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
05969 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
05970 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
05971 return xml_node(i);
05972
05973 return xml_node();
05974 }
05975
05976 #ifndef PUGIXML_NO_STL
05977 PUGI__FN string_t xml_node::path(char_t delimiter) const
05978 {
05979 if (!_root) return string_t();
05980
05981 size_t offset = 0;
05982
05983 for (xml_node_struct* i = _root; i; i = i->parent)
05984 {
05985 offset += (i != _root);
05986 offset += i->name ? impl::strlength(i->name) : 0;
05987 }
05988
05989 string_t result;
05990 result.resize(offset);
05991
05992 for (xml_node_struct* j = _root; j; j = j->parent)
05993 {
05994 if (j != _root)
05995 result[--offset] = delimiter;
05996
05997 if (j->name && *j->name)
05998 {
05999 size_t length = impl::strlength(j->name);
06000
06001 offset -= length;
06002 memcpy(&result[offset], j->name, length * sizeof(char_t));
06003 }
06004 }
06005
06006 assert(offset == 0);
06007
06008 return result;
06009 }
06010 #endif
06011
06012 PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const
06013 {
06014 xml_node found = *this;
06015
06016 if (!_root || !path_ || !path_[0]) return found;
06017
06018 if (path_[0] == delimiter)
06019 {
06020
06021 found = found.root();
06022 ++path_;
06023 }
06024
06025 const char_t* path_segment = path_;
06026
06027 while (*path_segment == delimiter) ++path_segment;
06028
06029 const char_t* path_segment_end = path_segment;
06030
06031 while (*path_segment_end && *path_segment_end != delimiter) ++path_segment_end;
06032
06033 if (path_segment == path_segment_end) return found;
06034
06035 const char_t* next_segment = path_segment_end;
06036
06037 while (*next_segment == delimiter) ++next_segment;
06038
06039 if (*path_segment == '.' && path_segment + 1 == path_segment_end)
06040 return found.first_element_by_path(next_segment, delimiter);
06041 else if (*path_segment == '.' && *(path_segment+1) == '.' && path_segment + 2 == path_segment_end)
06042 return found.parent().first_element_by_path(next_segment, delimiter);
06043 else
06044 {
06045 for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling)
06046 {
06047 if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
06048 {
06049 xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
06050
06051 if (subsearch) return subsearch;
06052 }
06053 }
06054
06055 return xml_node();
06056 }
06057 }
06058
06059 PUGI__FN bool xml_node::traverse(xml_tree_walker& walker)
06060 {
06061 walker._depth = -1;
06062
06063 xml_node arg_begin = *this;
06064 if (!walker.begin(arg_begin)) return false;
06065
06066 xml_node cur = first_child();
06067
06068 if (cur)
06069 {
06070 ++walker._depth;
06071
06072 do
06073 {
06074 xml_node arg_for_each = cur;
06075 if (!walker.for_each(arg_for_each))
06076 return false;
06077
06078 if (cur.first_child())
06079 {
06080 ++walker._depth;
06081 cur = cur.first_child();
06082 }
06083 else if (cur.next_sibling())
06084 cur = cur.next_sibling();
06085 else
06086 {
06087
06088 while (!cur.next_sibling() && cur != *this && !cur.parent().empty())
06089 {
06090 --walker._depth;
06091 cur = cur.parent();
06092 }
06093
06094 if (cur != *this)
06095 cur = cur.next_sibling();
06096 }
06097 }
06098 while (cur && cur != *this);
06099 }
06100
06101 assert(walker._depth == -1);
06102
06103 xml_node arg_end = *this;
06104 return walker.end(arg_end);
06105 }
06106
06107 PUGI__FN size_t xml_node::hash_value() const
06108 {
06109 return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
06110 }
06111
06112 PUGI__FN xml_node_struct* xml_node::internal_object() const
06113 {
06114 return _root;
06115 }
06116
06117 PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
06118 {
06119 if (!_root) return;
06120
06121 impl::xml_buffered_writer buffered_writer(writer, encoding);
06122
06123 impl::node_output(buffered_writer, _root, indent, flags, depth);
06124
06125 buffered_writer.flush();
06126 }
06127
06128 #ifndef PUGIXML_NO_STL
06129 PUGI__FN void xml_node::print(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
06130 {
06131 xml_writer_stream writer(stream);
06132
06133 print(writer, indent, flags, encoding, depth);
06134 }
06135
06136 PUGI__FN void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const
06137 {
06138 xml_writer_stream writer(stream);
06139
06140 print(writer, indent, flags, encoding_wchar, depth);
06141 }
06142 #endif
06143
06144 PUGI__FN ptrdiff_t xml_node::offset_debug() const
06145 {
06146 if (!_root) return -1;
06147
06148 impl::xml_document_struct& doc = impl::get_document(_root);
06149
06150
06151 if (!doc.buffer || doc.extra_buffers) return -1;
06152
06153 switch (type())
06154 {
06155 case node_document:
06156 return 0;
06157
06158 case node_element:
06159 case node_declaration:
06160 case node_pi:
06161 return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1;
06162
06163 case node_pcdata:
06164 case node_cdata:
06165 case node_comment:
06166 case node_doctype:
06167 return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1;
06168
06169 default:
06170 return -1;
06171 }
06172 }
06173
06174 #ifdef __BORLANDC__
06175 PUGI__FN bool operator&&(const xml_node& lhs, bool rhs)
06176 {
06177 return (bool)lhs && rhs;
06178 }
06179
06180 PUGI__FN bool operator||(const xml_node& lhs, bool rhs)
06181 {
06182 return (bool)lhs || rhs;
06183 }
06184 #endif
06185
06186 PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root)
06187 {
06188 }
06189
06190 PUGI__FN xml_node_struct* xml_text::_data() const
06191 {
06192 if (!_root || impl::is_text_node(_root)) return _root;
06193
06194 for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
06195 if (impl::is_text_node(node))
06196 return node;
06197
06198 return 0;
06199 }
06200
06201 PUGI__FN xml_node_struct* xml_text::_data_new()
06202 {
06203 xml_node_struct* d = _data();
06204 if (d) return d;
06205
06206 return xml_node(_root).append_child(node_pcdata).internal_object();
06207 }
06208
06209 PUGI__FN xml_text::xml_text(): _root(0)
06210 {
06211 }
06212
06213 PUGI__FN static void unspecified_bool_xml_text(xml_text***)
06214 {
06215 }
06216
06217 PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const
06218 {
06219 return _data() ? unspecified_bool_xml_text : 0;
06220 }
06221
06222 PUGI__FN bool xml_text::operator!() const
06223 {
06224 return !_data();
06225 }
06226
06227 PUGI__FN bool xml_text::empty() const
06228 {
06229 return _data() == 0;
06230 }
06231
06232 PUGI__FN const char_t* xml_text::get() const
06233 {
06234 xml_node_struct* d = _data();
06235
06236 return (d && d->value) ? d->value + 0 : PUGIXML_TEXT("");
06237 }
06238
06239 PUGI__FN const char_t* xml_text::as_string(const char_t* def) const
06240 {
06241 xml_node_struct* d = _data();
06242
06243 return (d && d->value) ? d->value + 0 : def;
06244 }
06245
06246 PUGI__FN int xml_text::as_int(int def) const
06247 {
06248 xml_node_struct* d = _data();
06249
06250 return (d && d->value) ? impl::get_value_int(d->value) : def;
06251 }
06252
06253 PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
06254 {
06255 xml_node_struct* d = _data();
06256
06257 return (d && d->value) ? impl::get_value_uint(d->value) : def;
06258 }
06259
06260 PUGI__FN double xml_text::as_double(double def) const
06261 {
06262 xml_node_struct* d = _data();
06263
06264 return (d && d->value) ? impl::get_value_double(d->value) : def;
06265 }
06266
06267 PUGI__FN float xml_text::as_float(float def) const
06268 {
06269 xml_node_struct* d = _data();
06270
06271 return (d && d->value) ? impl::get_value_float(d->value) : def;
06272 }
06273
06274 PUGI__FN bool xml_text::as_bool(bool def) const
06275 {
06276 xml_node_struct* d = _data();
06277
06278 return (d && d->value) ? impl::get_value_bool(d->value) : def;
06279 }
06280
06281 #ifdef PUGIXML_HAS_LONG_LONG
06282 PUGI__FN long long xml_text::as_llong(long long def) const
06283 {
06284 xml_node_struct* d = _data();
06285
06286 return (d && d->value) ? impl::get_value_llong(d->value) : def;
06287 }
06288
06289 PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const
06290 {
06291 xml_node_struct* d = _data();
06292
06293 return (d && d->value) ? impl::get_value_ullong(d->value) : def;
06294 }
06295 #endif
06296
06297 PUGI__FN bool xml_text::set(const char_t* rhs)
06298 {
06299 xml_node_struct* dn = _data_new();
06300
06301 return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false;
06302 }
06303
06304 PUGI__FN bool xml_text::set(int rhs)
06305 {
06306 xml_node_struct* dn = _data_new();
06307
06308 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
06309 }
06310
06311 PUGI__FN bool xml_text::set(unsigned int rhs)
06312 {
06313 xml_node_struct* dn = _data_new();
06314
06315 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
06316 }
06317
06318 PUGI__FN bool xml_text::set(float rhs)
06319 {
06320 xml_node_struct* dn = _data_new();
06321
06322 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
06323 }
06324
06325 PUGI__FN bool xml_text::set(double rhs)
06326 {
06327 xml_node_struct* dn = _data_new();
06328
06329 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
06330 }
06331
06332 PUGI__FN bool xml_text::set(bool rhs)
06333 {
06334 xml_node_struct* dn = _data_new();
06335
06336 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
06337 }
06338
06339 #ifdef PUGIXML_HAS_LONG_LONG
06340 PUGI__FN bool xml_text::set(long long rhs)
06341 {
06342 xml_node_struct* dn = _data_new();
06343
06344 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
06345 }
06346
06347 PUGI__FN bool xml_text::set(unsigned long long rhs)
06348 {
06349 xml_node_struct* dn = _data_new();
06350
06351 return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
06352 }
06353 #endif
06354
06355 PUGI__FN xml_text& xml_text::operator=(const char_t* rhs)
06356 {
06357 set(rhs);
06358 return *this;
06359 }
06360
06361 PUGI__FN xml_text& xml_text::operator=(int rhs)
06362 {
06363 set(rhs);
06364 return *this;
06365 }
06366
06367 PUGI__FN xml_text& xml_text::operator=(unsigned int rhs)
06368 {
06369 set(rhs);
06370 return *this;
06371 }
06372
06373 PUGI__FN xml_text& xml_text::operator=(double rhs)
06374 {
06375 set(rhs);
06376 return *this;
06377 }
06378
06379 PUGI__FN xml_text& xml_text::operator=(float rhs)
06380 {
06381 set(rhs);
06382 return *this;
06383 }
06384
06385 PUGI__FN xml_text& xml_text::operator=(bool rhs)
06386 {
06387 set(rhs);
06388 return *this;
06389 }
06390
06391 #ifdef PUGIXML_HAS_LONG_LONG
06392 PUGI__FN xml_text& xml_text::operator=(long long rhs)
06393 {
06394 set(rhs);
06395 return *this;
06396 }
06397
06398 PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs)
06399 {
06400 set(rhs);
06401 return *this;
06402 }
06403 #endif
06404
06405 PUGI__FN xml_node xml_text::data() const
06406 {
06407 return xml_node(_data());
06408 }
06409
06410 #ifdef __BORLANDC__
06411 PUGI__FN bool operator&&(const xml_text& lhs, bool rhs)
06412 {
06413 return (bool)lhs && rhs;
06414 }
06415
06416 PUGI__FN bool operator||(const xml_text& lhs, bool rhs)
06417 {
06418 return (bool)lhs || rhs;
06419 }
06420 #endif
06421
06422 PUGI__FN xml_node_iterator::xml_node_iterator()
06423 {
06424 }
06425
06426 PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
06427 {
06428 }
06429
06430 PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
06431 {
06432 }
06433
06434 PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const
06435 {
06436 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
06437 }
06438
06439 PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const
06440 {
06441 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
06442 }
06443
06444 PUGI__FN xml_node& xml_node_iterator::operator*() const
06445 {
06446 assert(_wrap._root);
06447 return _wrap;
06448 }
06449
06450 PUGI__FN xml_node* xml_node_iterator::operator->() const
06451 {
06452 assert(_wrap._root);
06453 return const_cast<xml_node*>(&_wrap);
06454 }
06455
06456 PUGI__FN const xml_node_iterator& xml_node_iterator::operator++()
06457 {
06458 assert(_wrap._root);
06459 _wrap._root = _wrap._root->next_sibling;
06460 return *this;
06461 }
06462
06463 PUGI__FN xml_node_iterator xml_node_iterator::operator++(int)
06464 {
06465 xml_node_iterator temp = *this;
06466 ++*this;
06467 return temp;
06468 }
06469
06470 PUGI__FN const xml_node_iterator& xml_node_iterator::operator--()
06471 {
06472 _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
06473 return *this;
06474 }
06475
06476 PUGI__FN xml_node_iterator xml_node_iterator::operator--(int)
06477 {
06478 xml_node_iterator temp = *this;
06479 --*this;
06480 return temp;
06481 }
06482
06483 PUGI__FN xml_attribute_iterator::xml_attribute_iterator()
06484 {
06485 }
06486
06487 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
06488 {
06489 }
06490
06491 PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
06492 {
06493 }
06494
06495 PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const
06496 {
06497 return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
06498 }
06499
06500 PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const
06501 {
06502 return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
06503 }
06504
06505 PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const
06506 {
06507 assert(_wrap._attr);
06508 return _wrap;
06509 }
06510
06511 PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const
06512 {
06513 assert(_wrap._attr);
06514 return const_cast<xml_attribute*>(&_wrap);
06515 }
06516
06517 PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++()
06518 {
06519 assert(_wrap._attr);
06520 _wrap._attr = _wrap._attr->next_attribute;
06521 return *this;
06522 }
06523
06524 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int)
06525 {
06526 xml_attribute_iterator temp = *this;
06527 ++*this;
06528 return temp;
06529 }
06530
06531 PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--()
06532 {
06533 _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
06534 return *this;
06535 }
06536
06537 PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int)
06538 {
06539 xml_attribute_iterator temp = *this;
06540 --*this;
06541 return temp;
06542 }
06543
06544 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0)
06545 {
06546 }
06547
06548 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name)
06549 {
06550 }
06551
06552 PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name)
06553 {
06554 }
06555
06556 PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const
06557 {
06558 return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
06559 }
06560
06561 PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const
06562 {
06563 return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
06564 }
06565
06566 PUGI__FN xml_node& xml_named_node_iterator::operator*() const
06567 {
06568 assert(_wrap._root);
06569 return _wrap;
06570 }
06571
06572 PUGI__FN xml_node* xml_named_node_iterator::operator->() const
06573 {
06574 assert(_wrap._root);
06575 return const_cast<xml_node*>(&_wrap);
06576 }
06577
06578 PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++()
06579 {
06580 assert(_wrap._root);
06581 _wrap = _wrap.next_sibling(_name);
06582 return *this;
06583 }
06584
06585 PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int)
06586 {
06587 xml_named_node_iterator temp = *this;
06588 ++*this;
06589 return temp;
06590 }
06591
06592 PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator--()
06593 {
06594 if (_wrap._root)
06595 _wrap = _wrap.previous_sibling(_name);
06596 else
06597 {
06598 _wrap = _parent.last_child();
06599
06600 if (!impl::strequal(_wrap.name(), _name))
06601 _wrap = _wrap.previous_sibling(_name);
06602 }
06603
06604 return *this;
06605 }
06606
06607 PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(int)
06608 {
06609 xml_named_node_iterator temp = *this;
06610 --*this;
06611 return temp;
06612 }
06613
06614 PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
06615 {
06616 }
06617
06618 PUGI__FN xml_parse_result::operator bool() const
06619 {
06620 return status == status_ok;
06621 }
06622
06623 PUGI__FN const char* xml_parse_result::description() const
06624 {
06625 switch (status)
06626 {
06627 case status_ok: return "No error";
06628
06629 case status_file_not_found: return "File was not found";
06630 case status_io_error: return "Error reading from file/stream";
06631 case status_out_of_memory: return "Could not allocate memory";
06632 case status_internal_error: return "Internal error occurred";
06633
06634 case status_unrecognized_tag: return "Could not determine tag type";
06635
06636 case status_bad_pi: return "Error parsing document declaration/processing instruction";
06637 case status_bad_comment: return "Error parsing comment";
06638 case status_bad_cdata: return "Error parsing CDATA section";
06639 case status_bad_doctype: return "Error parsing document type declaration";
06640 case status_bad_pcdata: return "Error parsing PCDATA section";
06641 case status_bad_start_element: return "Error parsing start element tag";
06642 case status_bad_attribute: return "Error parsing element attribute";
06643 case status_bad_end_element: return "Error parsing end element tag";
06644 case status_end_element_mismatch: return "Start-end tags mismatch";
06645
06646 case status_append_invalid_root: return "Unable to append nodes: root is not an element or document";
06647
06648 case status_no_document_element: return "No document element found";
06649
06650 default: return "Unknown error";
06651 }
06652 }
06653
06654 PUGI__FN xml_document::xml_document(): _buffer(0)
06655 {
06656 create();
06657 }
06658
06659 PUGI__FN xml_document::~xml_document()
06660 {
06661 destroy();
06662 }
06663
06664 PUGI__FN void xml_document::reset()
06665 {
06666 destroy();
06667 create();
06668 }
06669
06670 PUGI__FN void xml_document::reset(const xml_document& proto)
06671 {
06672 reset();
06673
06674 for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
06675 append_copy(cur);
06676 }
06677
06678 PUGI__FN void xml_document::create()
06679 {
06680 assert(!_root);
06681
06682 #ifdef PUGIXML_COMPACT
06683 const size_t page_offset = sizeof(uint32_t);
06684 #else
06685 const size_t page_offset = 0;
06686 #endif
06687
06688
06689 PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment - sizeof(void*) + page_offset <= sizeof(_memory));
06690
06691
06692 void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(_memory) + (impl::xml_memory_page_alignment - 1)) & ~(impl::xml_memory_page_alignment - 1));
06693
06694
06695 impl::xml_memory_page* page = impl::xml_memory_page::construct(page_memory);
06696 assert(page);
06697
06698 page->busy_size = impl::xml_memory_page_size;
06699
06700
06701 #ifdef PUGIXML_COMPACT
06702
06703 page->compact_page_marker = reinterpret_cast<uint32_t*>(static_cast<void*>(reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page)));
06704 *page->compact_page_marker = sizeof(impl::xml_memory_page);
06705 #endif
06706
06707
06708 _root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page);
06709 _root->prev_sibling_c = _root;
06710
06711
06712 page->allocator = static_cast<impl::xml_document_struct*>(_root);
06713
06714
06715 assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory));
06716 }
06717
06718 PUGI__FN void xml_document::destroy()
06719 {
06720 assert(_root);
06721
06722
06723 if (_buffer)
06724 {
06725 impl::xml_memory::deallocate(_buffer);
06726 _buffer = 0;
06727 }
06728
06729
06730 for (impl::xml_extra_buffer* extra = static_cast<impl::xml_document_struct*>(_root)->extra_buffers; extra; extra = extra->next)
06731 {
06732 if (extra->buffer) impl::xml_memory::deallocate(extra->buffer);
06733 }
06734
06735
06736 impl::xml_memory_page* root_page = PUGI__GETPAGE(_root);
06737 assert(root_page && !root_page->prev);
06738 assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));
06739
06740 for (impl::xml_memory_page* page = root_page->next; page; )
06741 {
06742 impl::xml_memory_page* next = page->next;
06743
06744 impl::xml_allocator::deallocate_page(page);
06745
06746 page = next;
06747 }
06748
06749 #ifdef PUGIXML_COMPACT
06750
06751 static_cast<impl::xml_document_struct*>(_root)->hash.clear();
06752 #endif
06753
06754 _root = 0;
06755 }
06756
06757 #ifndef PUGIXML_NO_STL
06758 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
06759 {
06760 reset();
06761
06762 return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding, &_buffer);
06763 }
06764
06765 PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
06766 {
06767 reset();
06768
06769 return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding_wchar, &_buffer);
06770 }
06771 #endif
06772
06773 PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options)
06774 {
06775
06776 #ifdef PUGIXML_WCHAR_MODE
06777 xml_encoding encoding = encoding_wchar;
06778 #else
06779 xml_encoding encoding = encoding_utf8;
06780 #endif
06781
06782 return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
06783 }
06784
06785 PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
06786 {
06787 return load_string(contents, options);
06788 }
06789
06790 PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
06791 {
06792 reset();
06793
06794 using impl::auto_deleter;
06795 auto_deleter<FILE, int(*)(FILE*)> file(fopen(path_, "rb"), fclose);
06796
06797 return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
06798 }
06799
06800 PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)
06801 {
06802 reset();
06803
06804 using impl::auto_deleter;
06805 auto_deleter<FILE, int(*)(FILE*)> file(impl::open_file_wide(path_, L"rb"), fclose);
06806
06807 return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
06808 }
06809
06810 PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
06811 {
06812 reset();
06813
06814 return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, const_cast<void*>(contents), size, options, encoding, false, false, &_buffer);
06815 }
06816
06817 PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
06818 {
06819 reset();
06820
06821 return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, false, &_buffer);
06822 }
06823
06824 PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
06825 {
06826 reset();
06827
06828 return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, true, &_buffer);
06829 }
06830
06831 PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
06832 {
06833 impl::xml_buffered_writer buffered_writer(writer, encoding);
06834
06835 if ((flags & format_write_bom) && encoding != encoding_latin1)
06836 {
06837
06838 #ifdef PUGIXML_WCHAR_MODE
06839 unsigned int bom = 0xfeff;
06840 buffered_writer.write(static_cast<wchar_t>(bom));
06841 #else
06842 buffered_writer.write('\xef', '\xbb', '\xbf');
06843 #endif
06844 }
06845
06846 if (!(flags & format_no_declaration) && !impl::has_declaration(_root))
06847 {
06848 buffered_writer.write_string(PUGIXML_TEXT("<?xml version=\"1.0\""));
06849 if (encoding == encoding_latin1) buffered_writer.write_string(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
06850 buffered_writer.write('?', '>');
06851 if (!(flags & format_raw)) buffered_writer.write('\n');
06852 }
06853
06854 impl::node_output(buffered_writer, _root, indent, flags, 0);
06855
06856 buffered_writer.flush();
06857 }
06858
06859 #ifndef PUGIXML_NO_STL
06860 PUGI__FN void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const
06861 {
06862 xml_writer_stream writer(stream);
06863
06864 save(writer, indent, flags, encoding);
06865 }
06866
06867 PUGI__FN void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const
06868 {
06869 xml_writer_stream writer(stream);
06870
06871 save(writer, indent, flags, encoding_wchar);
06872 }
06873 #endif
06874
06875 PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
06876 {
06877 using impl::auto_deleter;
06878 auto_deleter<FILE, int(*)(FILE*)> file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), fclose);
06879
06880 return impl::save_file_impl(*this, file.data, indent, flags, encoding);
06881 }
06882
06883 PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
06884 {
06885 using impl::auto_deleter;
06886 auto_deleter<FILE, int(*)(FILE*)> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), fclose);
06887
06888 return impl::save_file_impl(*this, file.data, indent, flags, encoding);
06889 }
06890
06891 PUGI__FN xml_node xml_document::document_element() const
06892 {
06893 assert(_root);
06894
06895 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
06896 if (PUGI__NODETYPE(i) == node_element)
06897 return xml_node(i);
06898
06899 return xml_node();
06900 }
06901
06902 #ifndef PUGIXML_NO_STL
06903 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
06904 {
06905 assert(str);
06906
06907 return impl::as_utf8_impl(str, impl::strlength_wide(str));
06908 }
06909
06910 PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str)
06911 {
06912 return impl::as_utf8_impl(str.c_str(), str.size());
06913 }
06914
06915 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str)
06916 {
06917 assert(str);
06918
06919 return impl::as_wide_impl(str, strlen(str));
06920 }
06921
06922 PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str)
06923 {
06924 return impl::as_wide_impl(str.c_str(), str.size());
06925 }
06926 #endif
06927
06928 PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
06929 {
06930 impl::xml_memory::allocate = allocate;
06931 impl::xml_memory::deallocate = deallocate;
06932 }
06933
06934 PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
06935 {
06936 return impl::xml_memory::allocate;
06937 }
06938
06939 PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
06940 {
06941 return impl::xml_memory::deallocate;
06942 }
06943 }
06944
06945 #if !defined(PUGIXML_NO_STL) && (defined(_MSC_VER) || defined(__ICC))
06946 namespace std
06947 {
06948
06949 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
06950 {
06951 return std::bidirectional_iterator_tag();
06952 }
06953
06954 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
06955 {
06956 return std::bidirectional_iterator_tag();
06957 }
06958
06959 PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)
06960 {
06961 return std::bidirectional_iterator_tag();
06962 }
06963 }
06964 #endif
06965
06966 #if !defined(PUGIXML_NO_STL) && defined(__SUNPRO_CC)
06967 namespace std
06968 {
06969
06970 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)
06971 {
06972 return std::bidirectional_iterator_tag();
06973 }
06974
06975 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)
06976 {
06977 return std::bidirectional_iterator_tag();
06978 }
06979
06980 PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)
06981 {
06982 return std::bidirectional_iterator_tag();
06983 }
06984 }
06985 #endif
06986
06987 #ifndef PUGIXML_NO_XPATH
06988
06989 PUGI__NS_BEGIN
06990 struct equal_to
06991 {
06992 template <typename T> bool operator()(const T& lhs, const T& rhs) const
06993 {
06994 return lhs == rhs;
06995 }
06996 };
06997
06998 struct not_equal_to
06999 {
07000 template <typename T> bool operator()(const T& lhs, const T& rhs) const
07001 {
07002 return lhs != rhs;
07003 }
07004 };
07005
07006 struct less
07007 {
07008 template <typename T> bool operator()(const T& lhs, const T& rhs) const
07009 {
07010 return lhs < rhs;
07011 }
07012 };
07013
07014 struct less_equal
07015 {
07016 template <typename T> bool operator()(const T& lhs, const T& rhs) const
07017 {
07018 return lhs <= rhs;
07019 }
07020 };
07021
07022 template <typename T> void swap(T& lhs, T& rhs)
07023 {
07024 T temp = lhs;
07025 lhs = rhs;
07026 rhs = temp;
07027 }
07028
07029 template <typename I, typename Pred> I min_element(I begin, I end, const Pred& pred)
07030 {
07031 I result = begin;
07032
07033 for (I it = begin + 1; it != end; ++it)
07034 if (pred(*it, *result))
07035 result = it;
07036
07037 return result;
07038 }
07039
07040 template <typename I> void reverse(I begin, I end)
07041 {
07042 while (end - begin > 1) swap(*begin++, *--end);
07043 }
07044
07045 template <typename I> I unique(I begin, I end)
07046 {
07047
07048 while (end - begin > 1 && *begin != *(begin + 1)) begin++;
07049
07050 if (begin == end) return begin;
07051
07052
07053 I write = begin++;
07054
07055
07056 while (begin != end)
07057 {
07058 if (*begin != *write)
07059 *++write = *begin++;
07060 else
07061 begin++;
07062 }
07063
07064
07065 return write + 1;
07066 }
07067
07068 template <typename I> void copy_backwards(I begin, I end, I target)
07069 {
07070 while (begin != end) *--target = *--end;
07071 }
07072
07073 template <typename I, typename Pred, typename T> void insertion_sort(I begin, I end, const Pred& pred, T*)
07074 {
07075 assert(begin != end);
07076
07077 for (I it = begin + 1; it != end; ++it)
07078 {
07079 T val = *it;
07080
07081 if (pred(val, *begin))
07082 {
07083
07084 copy_backwards(begin, it, it + 1);
07085 *begin = val;
07086 }
07087 else
07088 {
07089 I hole = it;
07090
07091
07092 while (pred(val, *(hole - 1)))
07093 {
07094 *hole = *(hole - 1);
07095 hole--;
07096 }
07097
07098
07099 *hole = val;
07100 }
07101 }
07102 }
07103
07104
07105 template <typename I, typename Pred> void partition(I begin, I middle, I end, const Pred& pred, I* out_eqbeg, I* out_eqend)
07106 {
07107 I eqbeg = middle, eqend = middle + 1;
07108
07109
07110 while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg;
07111 while (eqend != end && *eqend == *eqbeg) ++eqend;
07112
07113
07114 I ltend = eqbeg, gtbeg = eqend;
07115
07116 for (;;)
07117 {
07118
07119 for (; gtbeg != end; ++gtbeg)
07120 if (!pred(*eqbeg, *gtbeg))
07121 {
07122 if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++);
07123 else break;
07124 }
07125
07126
07127 for (; ltend != begin; --ltend)
07128 if (!pred(*(ltend - 1), *eqbeg))
07129 {
07130 if (*eqbeg == *(ltend - 1)) swap(*(ltend - 1), *--eqbeg);
07131 else break;
07132 }
07133
07134
07135 if (gtbeg == end && ltend == begin)
07136 {
07137 *out_eqbeg = eqbeg;
07138 *out_eqend = eqend;
07139 return;
07140 }
07141
07142
07143 if (gtbeg == end)
07144 {
07145 if (--ltend != --eqbeg) swap(*ltend, *eqbeg);
07146 swap(*eqbeg, *--eqend);
07147 }
07148 else if (ltend == begin)
07149 {
07150 if (eqend != gtbeg) swap(*eqbeg, *eqend);
07151 ++eqend;
07152 swap(*gtbeg++, *eqbeg++);
07153 }
07154 else swap(*gtbeg++, *--ltend);
07155 }
07156 }
07157
07158 template <typename I, typename Pred> void median3(I first, I middle, I last, const Pred& pred)
07159 {
07160 if (pred(*middle, *first)) swap(*middle, *first);
07161 if (pred(*last, *middle)) swap(*last, *middle);
07162 if (pred(*middle, *first)) swap(*middle, *first);
07163 }
07164
07165 template <typename I, typename Pred> void median(I first, I middle, I last, const Pred& pred)
07166 {
07167 if (last - first <= 40)
07168 {
07169
07170 median3(first, middle, last, pred);
07171 }
07172 else
07173 {
07174
07175 size_t step = (last - first + 1) / 8;
07176
07177 median3(first, first + step, first + 2 * step, pred);
07178 median3(middle - step, middle, middle + step, pred);
07179 median3(last - 2 * step, last - step, last, pred);
07180 median3(first + step, middle, last - step, pred);
07181 }
07182 }
07183
07184 template <typename I, typename Pred> void sort(I begin, I end, const Pred& pred)
07185 {
07186
07187 while (end - begin > 32)
07188 {
07189
07190 I middle = begin + (end - begin) / 2;
07191 median(begin, middle, end - 1, pred);
07192
07193
07194 I eqbeg, eqend;
07195 partition(begin, middle, end, pred, &eqbeg, &eqend);
07196
07197
07198 if (eqbeg - begin > end - eqend)
07199 {
07200 sort(eqend, end, pred);
07201 end = eqbeg;
07202 }
07203 else
07204 {
07205 sort(begin, eqbeg, pred);
07206 begin = eqend;
07207 }
07208 }
07209
07210
07211 if (begin != end) insertion_sort(begin, end, pred, &*begin);
07212 }
07213 PUGI__NS_END
07214
07215
07216 PUGI__NS_BEGIN
07217 static const size_t xpath_memory_page_size =
07218 #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
07219 PUGIXML_MEMORY_XPATH_PAGE_SIZE
07220 #else
07221 4096
07222 #endif
07223 ;
07224
07225 static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*);
07226
07227 struct xpath_memory_block
07228 {
07229 xpath_memory_block* next;
07230 size_t capacity;
07231
07232 union
07233 {
07234 char data[xpath_memory_page_size];
07235 double alignment;
07236 };
07237 };
07238
07239 class xpath_allocator
07240 {
07241 xpath_memory_block* _root;
07242 size_t _root_size;
07243
07244 public:
07245 #ifdef PUGIXML_NO_EXCEPTIONS
07246 jmp_buf* error_handler;
07247 #endif
07248
07249 xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size)
07250 {
07251 #ifdef PUGIXML_NO_EXCEPTIONS
07252 error_handler = 0;
07253 #endif
07254 }
07255
07256 void* allocate_nothrow(size_t size)
07257 {
07258
07259 size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
07260
07261 if (_root_size + size <= _root->capacity)
07262 {
07263 void* buf = &_root->data[0] + _root_size;
07264 _root_size += size;
07265 return buf;
07266 }
07267 else
07268 {
07269
07270 size_t block_capacity_base = sizeof(_root->data);
07271 size_t block_capacity_req = size + block_capacity_base / 4;
07272 size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req;
07273
07274 size_t block_size = block_capacity + offsetof(xpath_memory_block, data);
07275
07276 xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));
07277 if (!block) return 0;
07278
07279 block->next = _root;
07280 block->capacity = block_capacity;
07281
07282 _root = block;
07283 _root_size = size;
07284
07285 return block->data;
07286 }
07287 }
07288
07289 void* allocate(size_t size)
07290 {
07291 void* result = allocate_nothrow(size);
07292
07293 if (!result)
07294 {
07295 #ifdef PUGIXML_NO_EXCEPTIONS
07296 assert(error_handler);
07297 longjmp(*error_handler, 1);
07298 #else
07299 throw std::bad_alloc();
07300 #endif
07301 }
07302
07303 return result;
07304 }
07305
07306 void* reallocate(void* ptr, size_t old_size, size_t new_size)
07307 {
07308
07309 old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
07310 new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
07311
07312
07313 assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);
07314
07315
07316 bool only_object = (_root_size == old_size);
07317
07318 if (ptr) _root_size -= old_size;
07319
07320
07321 void* result = allocate(new_size);
07322 assert(result);
07323
07324
07325 if (result != ptr && ptr)
07326 {
07327
07328 assert(new_size >= old_size);
07329 memcpy(result, ptr, old_size);
07330
07331
07332 if (only_object)
07333 {
07334 assert(_root->data == result);
07335 assert(_root->next);
07336
07337 xpath_memory_block* next = _root->next->next;
07338
07339 if (next)
07340 {
07341
07342 xml_memory::deallocate(_root->next);
07343 _root->next = next;
07344 }
07345 }
07346 }
07347
07348 return result;
07349 }
07350
07351 void revert(const xpath_allocator& state)
07352 {
07353
07354 xpath_memory_block* cur = _root;
07355
07356 while (cur != state._root)
07357 {
07358 xpath_memory_block* next = cur->next;
07359
07360 xml_memory::deallocate(cur);
07361
07362 cur = next;
07363 }
07364
07365
07366 _root = state._root;
07367 _root_size = state._root_size;
07368 }
07369
07370 void release()
07371 {
07372 xpath_memory_block* cur = _root;
07373 assert(cur);
07374
07375 while (cur->next)
07376 {
07377 xpath_memory_block* next = cur->next;
07378
07379 xml_memory::deallocate(cur);
07380
07381 cur = next;
07382 }
07383 }
07384 };
07385
07386 struct xpath_allocator_capture
07387 {
07388 xpath_allocator_capture(xpath_allocator* alloc): _target(alloc), _state(*alloc)
07389 {
07390 }
07391
07392 ~xpath_allocator_capture()
07393 {
07394 _target->revert(_state);
07395 }
07396
07397 xpath_allocator* _target;
07398 xpath_allocator _state;
07399 };
07400
07401 struct xpath_stack
07402 {
07403 xpath_allocator* result;
07404 xpath_allocator* temp;
07405 };
07406
07407 struct xpath_stack_data
07408 {
07409 xpath_memory_block blocks[2];
07410 xpath_allocator result;
07411 xpath_allocator temp;
07412 xpath_stack stack;
07413
07414 #ifdef PUGIXML_NO_EXCEPTIONS
07415 jmp_buf error_handler;
07416 #endif
07417
07418 xpath_stack_data(): result(blocks + 0), temp(blocks + 1)
07419 {
07420 blocks[0].next = blocks[1].next = 0;
07421 blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data);
07422
07423 stack.result = &result;
07424 stack.temp = &temp;
07425
07426 #ifdef PUGIXML_NO_EXCEPTIONS
07427 result.error_handler = temp.error_handler = &error_handler;
07428 #endif
07429 }
07430
07431 ~xpath_stack_data()
07432 {
07433 result.release();
07434 temp.release();
07435 }
07436 };
07437 PUGI__NS_END
07438
07439
07440 PUGI__NS_BEGIN
07441 class xpath_string
07442 {
07443 const char_t* _buffer;
07444 bool _uses_heap;
07445 size_t _length_heap;
07446
07447 static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc)
07448 {
07449 char_t* result = static_cast<char_t*>(alloc->allocate((length + 1) * sizeof(char_t)));
07450 assert(result);
07451
07452 memcpy(result, string, length * sizeof(char_t));
07453 result[length] = 0;
07454
07455 return result;
07456 }
07457
07458 xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap)
07459 {
07460 }
07461
07462 public:
07463 static xpath_string from_const(const char_t* str)
07464 {
07465 return xpath_string(str, false, 0);
07466 }
07467
07468 static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end)
07469 {
07470 assert(begin <= end && *end == 0);
07471
07472 return xpath_string(begin, true, static_cast<size_t>(end - begin));
07473 }
07474
07475 static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc)
07476 {
07477 assert(begin <= end);
07478
07479 size_t length = static_cast<size_t>(end - begin);
07480
07481 return length == 0 ? xpath_string() : xpath_string(duplicate_string(begin, length, alloc), true, length);
07482 }
07483
07484 xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0)
07485 {
07486 }
07487
07488 void append(const xpath_string& o, xpath_allocator* alloc)
07489 {
07490
07491 if (!*o._buffer) return;
07492
07493
07494 if (!*_buffer && !_uses_heap && !o._uses_heap)
07495 {
07496 _buffer = o._buffer;
07497 }
07498 else
07499 {
07500
07501 size_t target_length = length();
07502 size_t source_length = o.length();
07503 size_t result_length = target_length + source_length;
07504
07505
07506 char_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t)));
07507 assert(result);
07508
07509
07510 if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t));
07511
07512
07513 memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
07514 result[result_length] = 0;
07515
07516
07517 _buffer = result;
07518 _uses_heap = true;
07519 _length_heap = result_length;
07520 }
07521 }
07522
07523 const char_t* c_str() const
07524 {
07525 return _buffer;
07526 }
07527
07528 size_t length() const
07529 {
07530 return _uses_heap ? _length_heap : strlength(_buffer);
07531 }
07532
07533 char_t* data(xpath_allocator* alloc)
07534 {
07535
07536 if (!_uses_heap)
07537 {
07538 size_t length_ = strlength(_buffer);
07539
07540 _buffer = duplicate_string(_buffer, length_, alloc);
07541 _uses_heap = true;
07542 _length_heap = length_;
07543 }
07544
07545 return const_cast<char_t*>(_buffer);
07546 }
07547
07548 bool empty() const
07549 {
07550 return *_buffer == 0;
07551 }
07552
07553 bool operator==(const xpath_string& o) const
07554 {
07555 return strequal(_buffer, o._buffer);
07556 }
07557
07558 bool operator!=(const xpath_string& o) const
07559 {
07560 return !strequal(_buffer, o._buffer);
07561 }
07562
07563 bool uses_heap() const
07564 {
07565 return _uses_heap;
07566 }
07567 };
07568 PUGI__NS_END
07569
07570 PUGI__NS_BEGIN
07571 PUGI__FN bool starts_with(const char_t* string, const char_t* pattern)
07572 {
07573 while (*pattern && *string == *pattern)
07574 {
07575 string++;
07576 pattern++;
07577 }
07578
07579 return *pattern == 0;
07580 }
07581
07582 PUGI__FN const char_t* find_char(const char_t* s, char_t c)
07583 {
07584 #ifdef PUGIXML_WCHAR_MODE
07585 return wcschr(s, c);
07586 #else
07587 return strchr(s, c);
07588 #endif
07589 }
07590
07591 PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p)
07592 {
07593 #ifdef PUGIXML_WCHAR_MODE
07594
07595 return (*p == 0) ? s : wcsstr(s, p);
07596 #else
07597 return strstr(s, p);
07598 #endif
07599 }
07600
07601
07602 PUGI__FN char_t tolower_ascii(char_t ch)
07603 {
07604 return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
07605 }
07606
07607 PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
07608 {
07609 if (na.attribute())
07610 return xpath_string::from_const(na.attribute().value());
07611 else
07612 {
07613 xml_node n = na.node();
07614
07615 switch (n.type())
07616 {
07617 case node_pcdata:
07618 case node_cdata:
07619 case node_comment:
07620 case node_pi:
07621 return xpath_string::from_const(n.value());
07622
07623 case node_document:
07624 case node_element:
07625 {
07626 xpath_string result;
07627
07628 xml_node cur = n.first_child();
07629
07630 while (cur && cur != n)
07631 {
07632 if (cur.type() == node_pcdata || cur.type() == node_cdata)
07633 result.append(xpath_string::from_const(cur.value()), alloc);
07634
07635 if (cur.first_child())
07636 cur = cur.first_child();
07637 else if (cur.next_sibling())
07638 cur = cur.next_sibling();
07639 else
07640 {
07641 while (!cur.next_sibling() && cur != n)
07642 cur = cur.parent();
07643
07644 if (cur != n) cur = cur.next_sibling();
07645 }
07646 }
07647
07648 return result;
07649 }
07650
07651 default:
07652 return xpath_string();
07653 }
07654 }
07655 }
07656
07657 PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)
07658 {
07659 assert(ln->parent == rn->parent);
07660
07661
07662 if (!ln->parent) return ln < rn;
07663
07664
07665 xml_node_struct* ls = ln;
07666 xml_node_struct* rs = rn;
07667
07668 while (ls && rs)
07669 {
07670 if (ls == rn) return true;
07671 if (rs == ln) return false;
07672
07673 ls = ls->next_sibling;
07674 rs = rs->next_sibling;
07675 }
07676
07677
07678 return !rs;
07679 }
07680
07681 PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
07682 {
07683
07684 xml_node_struct* lp = ln;
07685 xml_node_struct* rp = rn;
07686
07687 while (lp && rp && lp->parent != rp->parent)
07688 {
07689 lp = lp->parent;
07690 rp = rp->parent;
07691 }
07692
07693
07694 if (lp && rp) return node_is_before_sibling(lp, rp);
07695
07696
07697 bool left_higher = !lp;
07698
07699 while (lp)
07700 {
07701 lp = lp->parent;
07702 ln = ln->parent;
07703 }
07704
07705 while (rp)
07706 {
07707 rp = rp->parent;
07708 rn = rn->parent;
07709 }
07710
07711
07712 if (ln == rn) return left_higher;
07713
07714
07715 while (ln->parent != rn->parent)
07716 {
07717 ln = ln->parent;
07718 rn = rn->parent;
07719 }
07720
07721 return node_is_before_sibling(ln, rn);
07722 }
07723
07724 PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)
07725 {
07726 while (node && node != parent) node = node->parent;
07727
07728 return parent && node == parent;
07729 }
07730
07731 PUGI__FN const void* document_buffer_order(const xpath_node& xnode)
07732 {
07733 xml_node_struct* node = xnode.node().internal_object();
07734
07735 if (node)
07736 {
07737 if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0)
07738 {
07739 if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name;
07740 if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value;
07741 }
07742
07743 return 0;
07744 }
07745
07746 xml_attribute_struct* attr = xnode.attribute().internal_object();
07747
07748 if (attr)
07749 {
07750 if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0)
07751 {
07752 if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name;
07753 if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value;
07754 }
07755
07756 return 0;
07757 }
07758
07759 return 0;
07760 }
07761
07762 struct document_order_comparator
07763 {
07764 bool operator()(const xpath_node& lhs, const xpath_node& rhs) const
07765 {
07766
07767 const void* lo = document_buffer_order(lhs);
07768 const void* ro = document_buffer_order(rhs);
07769
07770 if (lo && ro) return lo < ro;
07771
07772
07773 xml_node ln = lhs.node(), rn = rhs.node();
07774
07775
07776 if (lhs.attribute() && rhs.attribute())
07777 {
07778
07779 if (lhs.parent() == rhs.parent())
07780 {
07781
07782 for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
07783 if (a == rhs.attribute())
07784 return true;
07785
07786 return false;
07787 }
07788
07789
07790 ln = lhs.parent();
07791 rn = rhs.parent();
07792 }
07793 else if (lhs.attribute())
07794 {
07795
07796 if (lhs.parent() == rhs.node()) return false;
07797
07798 ln = lhs.parent();
07799 }
07800 else if (rhs.attribute())
07801 {
07802
07803 if (rhs.parent() == lhs.node()) return true;
07804
07805 rn = rhs.parent();
07806 }
07807
07808 if (ln == rn) return false;
07809
07810 if (!ln || !rn) return ln < rn;
07811
07812 return node_is_before(ln.internal_object(), rn.internal_object());
07813 }
07814 };
07815
07816 struct duplicate_comparator
07817 {
07818 bool operator()(const xpath_node& lhs, const xpath_node& rhs) const
07819 {
07820 if (lhs.attribute()) return rhs.attribute() ? lhs.attribute() < rhs.attribute() : true;
07821 else return rhs.attribute() ? false : lhs.node() < rhs.node();
07822 }
07823 };
07824
07825 PUGI__FN double gen_nan()
07826 {
07827 #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
07828 union { float f; uint32_t i; } u[sizeof(float) == sizeof(uint32_t) ? 1 : -1];
07829 u[0].i = 0x7fc00000;
07830 return u[0].f;
07831 #else
07832
07833 const volatile double zero = 0.0;
07834 return zero / zero;
07835 #endif
07836 }
07837
07838 PUGI__FN bool is_nan(double value)
07839 {
07840 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
07841 return !!_isnan(value);
07842 #elif defined(fpclassify) && defined(FP_NAN)
07843 return fpclassify(value) == FP_NAN;
07844 #else
07845
07846 const volatile double v = value;
07847 return v != v;
07848 #endif
07849 }
07850
07851 PUGI__FN const char_t* convert_number_to_string_special(double value)
07852 {
07853 #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
07854 if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0;
07855 if (_isnan(value)) return PUGIXML_TEXT("NaN");
07856 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
07857 #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
07858 switch (fpclassify(value))
07859 {
07860 case FP_NAN:
07861 return PUGIXML_TEXT("NaN");
07862
07863 case FP_INFINITE:
07864 return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
07865
07866 case FP_ZERO:
07867 return PUGIXML_TEXT("0");
07868
07869 default:
07870 return 0;
07871 }
07872 #else
07873
07874 const volatile double v = value;
07875
07876 if (v == 0) return PUGIXML_TEXT("0");
07877 if (v != v) return PUGIXML_TEXT("NaN");
07878 if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
07879 return 0;
07880 #endif
07881 }
07882
07883 PUGI__FN bool convert_number_to_boolean(double value)
07884 {
07885 return (value != 0 && !is_nan(value));
07886 }
07887
07888 PUGI__FN void truncate_zeros(char* begin, char* end)
07889 {
07890 while (begin != end && end[-1] == '0') end--;
07891
07892 *end = 0;
07893 }
07894
07895
07896 #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
07897 PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
07898 {
07899
07900 int sign, exponent;
07901 _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign);
07902
07903
07904 truncate_zeros(buffer, buffer + strlen(buffer));
07905
07906
07907 *out_mantissa = buffer;
07908 *out_exponent = exponent;
07909 }
07910 #else
07911 PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
07912 {
07913
07914 sprintf(buffer, "%.*e", DBL_DIG, value);
07915 assert(strlen(buffer) < buffer_size);
07916 (void)!buffer_size;
07917
07918
07919 char* exponent_string = strchr(buffer, 'e');
07920 assert(exponent_string);
07921
07922 int exponent = atoi(exponent_string + 1);
07923
07924
07925 char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
07926 assert(mantissa[0] != '0' && mantissa[1] == '.');
07927
07928
07929 mantissa[1] = mantissa[0];
07930 mantissa++;
07931 exponent++;
07932
07933
07934 truncate_zeros(mantissa, exponent_string);
07935
07936
07937 *out_mantissa = mantissa;
07938 *out_exponent = exponent;
07939 }
07940 #endif
07941
07942 PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc)
07943 {
07944
07945 const char_t* special = convert_number_to_string_special(value);
07946 if (special) return xpath_string::from_const(special);
07947
07948
07949 char mantissa_buffer[32];
07950
07951 char* mantissa;
07952 int exponent;
07953 convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent);
07954
07955
07956 size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
07957 char_t* result = static_cast<char_t*>(alloc->allocate(sizeof(char_t) * result_size));
07958 assert(result);
07959
07960
07961 char_t* s = result;
07962
07963
07964 if (value < 0) *s++ = '-';
07965
07966
07967 if (exponent <= 0)
07968 {
07969 *s++ = '0';
07970 }
07971 else
07972 {
07973 while (exponent > 0)
07974 {
07975 assert(*mantissa == 0 || static_cast<unsigned int>(static_cast<unsigned int>(*mantissa) - '0') <= 9);
07976 *s++ = *mantissa ? *mantissa++ : '0';
07977 exponent--;
07978 }
07979 }
07980
07981
07982 if (*mantissa)
07983 {
07984
07985 *s++ = '.';
07986
07987
07988 while (exponent < 0)
07989 {
07990 *s++ = '0';
07991 exponent++;
07992 }
07993
07994
07995 while (*mantissa)
07996 {
07997 assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
07998 *s++ = *mantissa++;
07999 }
08000 }
08001
08002
08003 assert(s < result + result_size);
08004 *s = 0;
08005
08006 return xpath_string::from_heap_preallocated(result, s);
08007 }
08008
08009 PUGI__FN bool check_string_to_number_format(const char_t* string)
08010 {
08011
08012 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
08013
08014
08015 if (*string == '-') ++string;
08016
08017 if (!*string) return false;
08018
08019
08020 if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false;
08021
08022
08023 while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
08024
08025
08026 if (*string == '.')
08027 {
08028 ++string;
08029
08030 while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
08031 }
08032
08033
08034 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
08035
08036 return *string == 0;
08037 }
08038
08039 PUGI__FN double convert_string_to_number(const char_t* string)
08040 {
08041
08042 if (!check_string_to_number_format(string)) return gen_nan();
08043
08044
08045 #ifdef PUGIXML_WCHAR_MODE
08046 return wcstod(string, 0);
08047 #else
08048 return strtod(string, 0);
08049 #endif
08050 }
08051
08052 PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result)
08053 {
08054 size_t length = static_cast<size_t>(end - begin);
08055 char_t* scratch = buffer;
08056
08057 if (length >= sizeof(buffer) / sizeof(buffer[0]))
08058 {
08059
08060 scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
08061 if (!scratch) return false;
08062 }
08063
08064
08065 memcpy(scratch, begin, length * sizeof(char_t));
08066 scratch[length] = 0;
08067
08068 *out_result = convert_string_to_number(scratch);
08069
08070
08071 if (scratch != buffer) xml_memory::deallocate(scratch);
08072
08073 return true;
08074 }
08075
08076 PUGI__FN double round_nearest(double value)
08077 {
08078 return floor(value + 0.5);
08079 }
08080
08081 PUGI__FN double round_nearest_nzero(double value)
08082 {
08083
08084
08085 return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
08086 }
08087
08088 PUGI__FN const char_t* qualified_name(const xpath_node& node)
08089 {
08090 return node.attribute() ? node.attribute().name() : node.node().name();
08091 }
08092
08093 PUGI__FN const char_t* local_name(const xpath_node& node)
08094 {
08095 const char_t* name = qualified_name(node);
08096 const char_t* p = find_char(name, ':');
08097
08098 return p ? p + 1 : name;
08099 }
08100
08101 struct namespace_uri_predicate
08102 {
08103 const char_t* prefix;
08104 size_t prefix_length;
08105
08106 namespace_uri_predicate(const char_t* name)
08107 {
08108 const char_t* pos = find_char(name, ':');
08109
08110 prefix = pos ? name : 0;
08111 prefix_length = pos ? static_cast<size_t>(pos - name) : 0;
08112 }
08113
08114 bool operator()(xml_attribute a) const
08115 {
08116 const char_t* name = a.name();
08117
08118 if (!starts_with(name, PUGIXML_TEXT("xmlns"))) return false;
08119
08120 return prefix ? name[5] == ':' && strequalrange(name + 6, prefix, prefix_length) : name[5] == 0;
08121 }
08122 };
08123
08124 PUGI__FN const char_t* namespace_uri(xml_node node)
08125 {
08126 namespace_uri_predicate pred = node.name();
08127
08128 xml_node p = node;
08129
08130 while (p)
08131 {
08132 xml_attribute a = p.find_attribute(pred);
08133
08134 if (a) return a.value();
08135
08136 p = p.parent();
08137 }
08138
08139 return PUGIXML_TEXT("");
08140 }
08141
08142 PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent)
08143 {
08144 namespace_uri_predicate pred = attr.name();
08145
08146
08147 if (!pred.prefix) return PUGIXML_TEXT("");
08148
08149 xml_node p = parent;
08150
08151 while (p)
08152 {
08153 xml_attribute a = p.find_attribute(pred);
08154
08155 if (a) return a.value();
08156
08157 p = p.parent();
08158 }
08159
08160 return PUGIXML_TEXT("");
08161 }
08162
08163 PUGI__FN const char_t* namespace_uri(const xpath_node& node)
08164 {
08165 return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
08166 }
08167
08168 PUGI__FN char_t* normalize_space(char_t* buffer)
08169 {
08170 char_t* write = buffer;
08171
08172 for (char_t* it = buffer; *it; )
08173 {
08174 char_t ch = *it++;
08175
08176 if (PUGI__IS_CHARTYPE(ch, ct_space))
08177 {
08178
08179 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
08180
08181
08182 if (write != buffer) *write++ = ' ';
08183 }
08184 else *write++ = ch;
08185 }
08186
08187
08188 if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
08189
08190
08191 *write = 0;
08192
08193 return write;
08194 }
08195
08196 PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)
08197 {
08198 char_t* write = buffer;
08199
08200 while (*buffer)
08201 {
08202 PUGI__DMC_VOLATILE char_t ch = *buffer++;
08203
08204 const char_t* pos = find_char(from, ch);
08205
08206 if (!pos)
08207 *write++ = ch;
08208 else if (static_cast<size_t>(pos - from) < to_length)
08209 *write++ = to[pos - from];
08210 }
08211
08212
08213 *write = 0;
08214
08215 return write;
08216 }
08217
08218 PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to)
08219 {
08220 unsigned char table[128] = {0};
08221
08222 while (*from)
08223 {
08224 unsigned int fc = static_cast<unsigned int>(*from);
08225 unsigned int tc = static_cast<unsigned int>(*to);
08226
08227 if (fc >= 128 || tc >= 128)
08228 return 0;
08229
08230
08231 if (!table[fc])
08232 table[fc] = static_cast<unsigned char>(tc ? tc : 128);
08233
08234 from++;
08235 if (tc) to++;
08236 }
08237
08238 for (int i = 0; i < 128; ++i)
08239 if (!table[i])
08240 table[i] = static_cast<unsigned char>(i);
08241
08242 void* result = alloc->allocate_nothrow(sizeof(table));
08243
08244 if (result)
08245 {
08246 memcpy(result, table, sizeof(table));
08247 }
08248
08249 return static_cast<unsigned char*>(result);
08250 }
08251
08252 PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table)
08253 {
08254 char_t* write = buffer;
08255
08256 while (*buffer)
08257 {
08258 char_t ch = *buffer++;
08259 unsigned int index = static_cast<unsigned int>(ch);
08260
08261 if (index < 128)
08262 {
08263 unsigned char code = table[index];
08264
08265
08266
08267 *write = static_cast<char_t>(code);
08268 write += 1 - (code >> 7);
08269 }
08270 else
08271 {
08272 *write++ = ch;
08273 }
08274 }
08275
08276
08277 *write = 0;
08278
08279 return write;
08280 }
08281
08282 inline bool is_xpath_attribute(const char_t* name)
08283 {
08284 return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':'));
08285 }
08286
08287 struct xpath_variable_boolean: xpath_variable
08288 {
08289 xpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false)
08290 {
08291 }
08292
08293 bool value;
08294 char_t name[1];
08295 };
08296
08297 struct xpath_variable_number: xpath_variable
08298 {
08299 xpath_variable_number(): xpath_variable(xpath_type_number), value(0)
08300 {
08301 }
08302
08303 double value;
08304 char_t name[1];
08305 };
08306
08307 struct xpath_variable_string: xpath_variable
08308 {
08309 xpath_variable_string(): xpath_variable(xpath_type_string), value(0)
08310 {
08311 }
08312
08313 ~xpath_variable_string()
08314 {
08315 if (value) xml_memory::deallocate(value);
08316 }
08317
08318 char_t* value;
08319 char_t name[1];
08320 };
08321
08322 struct xpath_variable_node_set: xpath_variable
08323 {
08324 xpath_variable_node_set(): xpath_variable(xpath_type_node_set)
08325 {
08326 }
08327
08328 xpath_node_set value;
08329 char_t name[1];
08330 };
08331
08332 static const xpath_node_set dummy_node_set;
08333
08334 PUGI__FN unsigned int hash_string(const char_t* str)
08335 {
08336
08337 unsigned int result = 0;
08338
08339 while (*str)
08340 {
08341 result += static_cast<unsigned int>(*str++);
08342 result += result << 10;
08343 result ^= result >> 6;
08344 }
08345
08346 result += result << 3;
08347 result ^= result >> 11;
08348 result += result << 15;
08349
08350 return result;
08351 }
08352
08353 template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name)
08354 {
08355 size_t length = strlength(name);
08356 if (length == 0) return 0;
08357
08358
08359 void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));
08360 if (!memory) return 0;
08361
08362 T* result = new (memory) T();
08363
08364 memcpy(result->name, name, (length + 1) * sizeof(char_t));
08365
08366 return result;
08367 }
08368
08369 PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
08370 {
08371 switch (type)
08372 {
08373 case xpath_type_node_set:
08374 return new_xpath_variable<xpath_variable_node_set>(name);
08375
08376 case xpath_type_number:
08377 return new_xpath_variable<xpath_variable_number>(name);
08378
08379 case xpath_type_string:
08380 return new_xpath_variable<xpath_variable_string>(name);
08381
08382 case xpath_type_boolean:
08383 return new_xpath_variable<xpath_variable_boolean>(name);
08384
08385 default:
08386 return 0;
08387 }
08388 }
08389
08390 template <typename T> PUGI__FN void delete_xpath_variable(T* var)
08391 {
08392 var->~T();
08393 xml_memory::deallocate(var);
08394 }
08395
08396 PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
08397 {
08398 switch (type)
08399 {
08400 case xpath_type_node_set:
08401 delete_xpath_variable(static_cast<xpath_variable_node_set*>(var));
08402 break;
08403
08404 case xpath_type_number:
08405 delete_xpath_variable(static_cast<xpath_variable_number*>(var));
08406 break;
08407
08408 case xpath_type_string:
08409 delete_xpath_variable(static_cast<xpath_variable_string*>(var));
08410 break;
08411
08412 case xpath_type_boolean:
08413 delete_xpath_variable(static_cast<xpath_variable_boolean*>(var));
08414 break;
08415
08416 default:
08417 assert(!"Invalid variable type");
08418 }
08419 }
08420
08421 PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs)
08422 {
08423 switch (rhs->type())
08424 {
08425 case xpath_type_node_set:
08426 return lhs->set(static_cast<const xpath_variable_node_set*>(rhs)->value);
08427
08428 case xpath_type_number:
08429 return lhs->set(static_cast<const xpath_variable_number*>(rhs)->value);
08430
08431 case xpath_type_string:
08432 return lhs->set(static_cast<const xpath_variable_string*>(rhs)->value);
08433
08434 case xpath_type_boolean:
08435 return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value);
08436
08437 default:
08438 assert(!"Invalid variable type");
08439 return false;
08440 }
08441 }
08442
08443 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)
08444 {
08445 size_t length = static_cast<size_t>(end - begin);
08446 char_t* scratch = buffer;
08447
08448 if (length >= sizeof(buffer) / sizeof(buffer[0]))
08449 {
08450
08451 scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
08452 if (!scratch) return false;
08453 }
08454
08455
08456 memcpy(scratch, begin, length * sizeof(char_t));
08457 scratch[length] = 0;
08458
08459 *out_result = set->get(scratch);
08460
08461
08462 if (scratch != buffer) xml_memory::deallocate(scratch);
08463
08464 return true;
08465 }
08466 PUGI__NS_END
08467
08468
08469 PUGI__NS_BEGIN
08470 PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end)
08471 {
08472 if (end - begin < 2)
08473 return xpath_node_set::type_sorted;
08474
08475 document_order_comparator cmp;
08476
08477 bool first = cmp(begin[0], begin[1]);
08478
08479 for (const xpath_node* it = begin + 1; it + 1 < end; ++it)
08480 if (cmp(it[0], it[1]) != first)
08481 return xpath_node_set::type_unsorted;
08482
08483 return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse;
08484 }
08485
08486 PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
08487 {
08488 xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
08489
08490 if (type == xpath_node_set::type_unsorted)
08491 {
08492 xpath_node_set::type_t sorted = xpath_get_order(begin, end);
08493
08494 if (sorted == xpath_node_set::type_unsorted)
08495 {
08496 sort(begin, end, document_order_comparator());
08497
08498 type = xpath_node_set::type_sorted;
08499 }
08500 else
08501 type = sorted;
08502 }
08503
08504 if (type != order) reverse(begin, end);
08505
08506 return order;
08507 }
08508
08509 PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
08510 {
08511 if (begin == end) return xpath_node();
08512
08513 switch (type)
08514 {
08515 case xpath_node_set::type_sorted:
08516 return *begin;
08517
08518 case xpath_node_set::type_sorted_reverse:
08519 return *(end - 1);
08520
08521 case xpath_node_set::type_unsorted:
08522 return *min_element(begin, end, document_order_comparator());
08523
08524 default:
08525 assert(!"Invalid node set type");
08526 return xpath_node();
08527 }
08528 }
08529
08530 class xpath_node_set_raw
08531 {
08532 xpath_node_set::type_t _type;
08533
08534 xpath_node* _begin;
08535 xpath_node* _end;
08536 xpath_node* _eos;
08537
08538 public:
08539 xpath_node_set_raw(): _type(xpath_node_set::type_unsorted), _begin(0), _end(0), _eos(0)
08540 {
08541 }
08542
08543 xpath_node* begin() const
08544 {
08545 return _begin;
08546 }
08547
08548 xpath_node* end() const
08549 {
08550 return _end;
08551 }
08552
08553 bool empty() const
08554 {
08555 return _begin == _end;
08556 }
08557
08558 size_t size() const
08559 {
08560 return static_cast<size_t>(_end - _begin);
08561 }
08562
08563 xpath_node first() const
08564 {
08565 return xpath_first(_begin, _end, _type);
08566 }
08567
08568 void push_back_grow(const xpath_node& node, xpath_allocator* alloc);
08569
08570 void push_back(const xpath_node& node, xpath_allocator* alloc)
08571 {
08572 if (_end != _eos)
08573 *_end++ = node;
08574 else
08575 push_back_grow(node, alloc);
08576 }
08577
08578 void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)
08579 {
08580 if (begin_ == end_) return;
08581
08582 size_t size_ = static_cast<size_t>(_end - _begin);
08583 size_t capacity = static_cast<size_t>(_eos - _begin);
08584 size_t count = static_cast<size_t>(end_ - begin_);
08585
08586 if (size_ + count > capacity)
08587 {
08588
08589 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
08590 assert(data);
08591
08592
08593 _begin = data;
08594 _end = data + size_;
08595 _eos = data + size_ + count;
08596 }
08597
08598 memcpy(_end, begin_, count * sizeof(xpath_node));
08599 _end += count;
08600 }
08601
08602 void sort_do()
08603 {
08604 _type = xpath_sort(_begin, _end, _type, false);
08605 }
08606
08607 void truncate(xpath_node* pos)
08608 {
08609 assert(_begin <= pos && pos <= _end);
08610
08611 _end = pos;
08612 }
08613
08614 void remove_duplicates()
08615 {
08616 if (_type == xpath_node_set::type_unsorted)
08617 sort(_begin, _end, duplicate_comparator());
08618
08619 _end = unique(_begin, _end);
08620 }
08621
08622 xpath_node_set::type_t type() const
08623 {
08624 return _type;
08625 }
08626
08627 void set_type(xpath_node_set::type_t value)
08628 {
08629 _type = value;
08630 }
08631 };
08632
08633 PUGI__FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc)
08634 {
08635 size_t capacity = static_cast<size_t>(_eos - _begin);
08636
08637
08638 size_t new_capacity = capacity + capacity / 2 + 1;
08639
08640
08641 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
08642 assert(data);
08643
08644
08645 _begin = data;
08646 _end = data + capacity;
08647 _eos = data + new_capacity;
08648
08649
08650 *_end++ = node;
08651 }
08652 PUGI__NS_END
08653
08654 PUGI__NS_BEGIN
08655 struct xpath_context
08656 {
08657 xpath_node n;
08658 size_t position, size;
08659
08660 xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_)
08661 {
08662 }
08663 };
08664
08665 enum lexeme_t
08666 {
08667 lex_none = 0,
08668 lex_equal,
08669 lex_not_equal,
08670 lex_less,
08671 lex_greater,
08672 lex_less_or_equal,
08673 lex_greater_or_equal,
08674 lex_plus,
08675 lex_minus,
08676 lex_multiply,
08677 lex_union,
08678 lex_var_ref,
08679 lex_open_brace,
08680 lex_close_brace,
08681 lex_quoted_string,
08682 lex_number,
08683 lex_slash,
08684 lex_double_slash,
08685 lex_open_square_brace,
08686 lex_close_square_brace,
08687 lex_string,
08688 lex_comma,
08689 lex_axis_attribute,
08690 lex_dot,
08691 lex_double_dot,
08692 lex_double_colon,
08693 lex_eof
08694 };
08695
08696 struct xpath_lexer_string
08697 {
08698 const char_t* begin;
08699 const char_t* end;
08700
08701 xpath_lexer_string(): begin(0), end(0)
08702 {
08703 }
08704
08705 bool operator==(const char_t* other) const
08706 {
08707 size_t length = static_cast<size_t>(end - begin);
08708
08709 return strequalrange(other, begin, length);
08710 }
08711 };
08712
08713 class xpath_lexer
08714 {
08715 const char_t* _cur;
08716 const char_t* _cur_lexeme_pos;
08717 xpath_lexer_string _cur_lexeme_contents;
08718
08719 lexeme_t _cur_lexeme;
08720
08721 public:
08722 explicit xpath_lexer(const char_t* query): _cur(query)
08723 {
08724 next();
08725 }
08726
08727 const char_t* state() const
08728 {
08729 return _cur;
08730 }
08731
08732 void next()
08733 {
08734 const char_t* cur = _cur;
08735
08736 while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
08737
08738
08739 _cur_lexeme_pos = cur;
08740
08741 switch (*cur)
08742 {
08743 case 0:
08744 _cur_lexeme = lex_eof;
08745 break;
08746
08747 case '>':
08748 if (*(cur+1) == '=')
08749 {
08750 cur += 2;
08751 _cur_lexeme = lex_greater_or_equal;
08752 }
08753 else
08754 {
08755 cur += 1;
08756 _cur_lexeme = lex_greater;
08757 }
08758 break;
08759
08760 case '<':
08761 if (*(cur+1) == '=')
08762 {
08763 cur += 2;
08764 _cur_lexeme = lex_less_or_equal;
08765 }
08766 else
08767 {
08768 cur += 1;
08769 _cur_lexeme = lex_less;
08770 }
08771 break;
08772
08773 case '!':
08774 if (*(cur+1) == '=')
08775 {
08776 cur += 2;
08777 _cur_lexeme = lex_not_equal;
08778 }
08779 else
08780 {
08781 _cur_lexeme = lex_none;
08782 }
08783 break;
08784
08785 case '=':
08786 cur += 1;
08787 _cur_lexeme = lex_equal;
08788
08789 break;
08790
08791 case '+':
08792 cur += 1;
08793 _cur_lexeme = lex_plus;
08794
08795 break;
08796
08797 case '-':
08798 cur += 1;
08799 _cur_lexeme = lex_minus;
08800
08801 break;
08802
08803 case '*':
08804 cur += 1;
08805 _cur_lexeme = lex_multiply;
08806
08807 break;
08808
08809 case '|':
08810 cur += 1;
08811 _cur_lexeme = lex_union;
08812
08813 break;
08814
08815 case '$':
08816 cur += 1;
08817
08818 if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
08819 {
08820 _cur_lexeme_contents.begin = cur;
08821
08822 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
08823
08824 if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
08825 {
08826 cur++;
08827
08828 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
08829 }
08830
08831 _cur_lexeme_contents.end = cur;
08832
08833 _cur_lexeme = lex_var_ref;
08834 }
08835 else
08836 {
08837 _cur_lexeme = lex_none;
08838 }
08839
08840 break;
08841
08842 case '(':
08843 cur += 1;
08844 _cur_lexeme = lex_open_brace;
08845
08846 break;
08847
08848 case ')':
08849 cur += 1;
08850 _cur_lexeme = lex_close_brace;
08851
08852 break;
08853
08854 case '[':
08855 cur += 1;
08856 _cur_lexeme = lex_open_square_brace;
08857
08858 break;
08859
08860 case ']':
08861 cur += 1;
08862 _cur_lexeme = lex_close_square_brace;
08863
08864 break;
08865
08866 case ',':
08867 cur += 1;
08868 _cur_lexeme = lex_comma;
08869
08870 break;
08871
08872 case '/':
08873 if (*(cur+1) == '/')
08874 {
08875 cur += 2;
08876 _cur_lexeme = lex_double_slash;
08877 }
08878 else
08879 {
08880 cur += 1;
08881 _cur_lexeme = lex_slash;
08882 }
08883 break;
08884
08885 case '.':
08886 if (*(cur+1) == '.')
08887 {
08888 cur += 2;
08889 _cur_lexeme = lex_double_dot;
08890 }
08891 else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
08892 {
08893 _cur_lexeme_contents.begin = cur;
08894
08895 ++cur;
08896
08897 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
08898
08899 _cur_lexeme_contents.end = cur;
08900
08901 _cur_lexeme = lex_number;
08902 }
08903 else
08904 {
08905 cur += 1;
08906 _cur_lexeme = lex_dot;
08907 }
08908 break;
08909
08910 case '@':
08911 cur += 1;
08912 _cur_lexeme = lex_axis_attribute;
08913
08914 break;
08915
08916 case '"':
08917 case '\'':
08918 {
08919 char_t terminator = *cur;
08920
08921 ++cur;
08922
08923 _cur_lexeme_contents.begin = cur;
08924 while (*cur && *cur != terminator) cur++;
08925 _cur_lexeme_contents.end = cur;
08926
08927 if (!*cur)
08928 _cur_lexeme = lex_none;
08929 else
08930 {
08931 cur += 1;
08932 _cur_lexeme = lex_quoted_string;
08933 }
08934
08935 break;
08936 }
08937
08938 case ':':
08939 if (*(cur+1) == ':')
08940 {
08941 cur += 2;
08942 _cur_lexeme = lex_double_colon;
08943 }
08944 else
08945 {
08946 _cur_lexeme = lex_none;
08947 }
08948 break;
08949
08950 default:
08951 if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
08952 {
08953 _cur_lexeme_contents.begin = cur;
08954
08955 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
08956
08957 if (*cur == '.')
08958 {
08959 cur++;
08960
08961 while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
08962 }
08963
08964 _cur_lexeme_contents.end = cur;
08965
08966 _cur_lexeme = lex_number;
08967 }
08968 else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
08969 {
08970 _cur_lexeme_contents.begin = cur;
08971
08972 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
08973
08974 if (cur[0] == ':')
08975 {
08976 if (cur[1] == '*')
08977 {
08978 cur += 2;
08979 }
08980 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol))
08981 {
08982 cur++;
08983
08984 while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
08985 }
08986 }
08987
08988 _cur_lexeme_contents.end = cur;
08989
08990 _cur_lexeme = lex_string;
08991 }
08992 else
08993 {
08994 _cur_lexeme = lex_none;
08995 }
08996 }
08997
08998 _cur = cur;
08999 }
09000
09001 lexeme_t current() const
09002 {
09003 return _cur_lexeme;
09004 }
09005
09006 const char_t* current_pos() const
09007 {
09008 return _cur_lexeme_pos;
09009 }
09010
09011 const xpath_lexer_string& contents() const
09012 {
09013 assert(_cur_lexeme == lex_var_ref || _cur_lexeme == lex_number || _cur_lexeme == lex_string || _cur_lexeme == lex_quoted_string);
09014
09015 return _cur_lexeme_contents;
09016 }
09017 };
09018
09019 enum ast_type_t
09020 {
09021 ast_unknown,
09022 ast_op_or,
09023 ast_op_and,
09024 ast_op_equal,
09025 ast_op_not_equal,
09026 ast_op_less,
09027 ast_op_greater,
09028 ast_op_less_or_equal,
09029 ast_op_greater_or_equal,
09030 ast_op_add,
09031 ast_op_subtract,
09032 ast_op_multiply,
09033 ast_op_divide,
09034 ast_op_mod,
09035 ast_op_negate,
09036 ast_op_union,
09037 ast_predicate,
09038 ast_filter,
09039 ast_string_constant,
09040 ast_number_constant,
09041 ast_variable,
09042 ast_func_last,
09043 ast_func_position,
09044 ast_func_count,
09045 ast_func_id,
09046 ast_func_local_name_0,
09047 ast_func_local_name_1,
09048 ast_func_namespace_uri_0,
09049 ast_func_namespace_uri_1,
09050 ast_func_name_0,
09051 ast_func_name_1,
09052 ast_func_string_0,
09053 ast_func_string_1,
09054 ast_func_concat,
09055 ast_func_starts_with,
09056 ast_func_contains,
09057 ast_func_substring_before,
09058 ast_func_substring_after,
09059 ast_func_substring_2,
09060 ast_func_substring_3,
09061 ast_func_string_length_0,
09062 ast_func_string_length_1,
09063 ast_func_normalize_space_0,
09064 ast_func_normalize_space_1,
09065 ast_func_translate,
09066 ast_func_boolean,
09067 ast_func_not,
09068 ast_func_true,
09069 ast_func_false,
09070 ast_func_lang,
09071 ast_func_number_0,
09072 ast_func_number_1,
09073 ast_func_sum,
09074 ast_func_floor,
09075 ast_func_ceiling,
09076 ast_func_round,
09077 ast_step,
09078 ast_step_root,
09079
09080 ast_opt_translate_table,
09081 ast_opt_compare_attribute
09082 };
09083
09084 enum axis_t
09085 {
09086 axis_ancestor,
09087 axis_ancestor_or_self,
09088 axis_attribute,
09089 axis_child,
09090 axis_descendant,
09091 axis_descendant_or_self,
09092 axis_following,
09093 axis_following_sibling,
09094 axis_namespace,
09095 axis_parent,
09096 axis_preceding,
09097 axis_preceding_sibling,
09098 axis_self
09099 };
09100
09101 enum nodetest_t
09102 {
09103 nodetest_none,
09104 nodetest_name,
09105 nodetest_type_node,
09106 nodetest_type_comment,
09107 nodetest_type_pi,
09108 nodetest_type_text,
09109 nodetest_pi,
09110 nodetest_all,
09111 nodetest_all_in_namespace
09112 };
09113
09114 enum predicate_t
09115 {
09116 predicate_default,
09117 predicate_posinv,
09118 predicate_constant,
09119 predicate_constant_one
09120 };
09121
09122 enum nodeset_eval_t
09123 {
09124 nodeset_eval_all,
09125 nodeset_eval_any,
09126 nodeset_eval_first
09127 };
09128
09129 template <axis_t N> struct axis_to_type
09130 {
09131 static const axis_t axis;
09132 };
09133
09134 template <axis_t N> const axis_t axis_to_type<N>::axis = N;
09135
09136 class xpath_ast_node
09137 {
09138 private:
09139
09140 char _type;
09141 char _rettype;
09142
09143
09144 char _axis;
09145
09146
09147 char _test;
09148
09149
09150 xpath_ast_node* _left;
09151 xpath_ast_node* _right;
09152 xpath_ast_node* _next;
09153
09154 union
09155 {
09156
09157 const char_t* string;
09158
09159 double number;
09160
09161 xpath_variable* variable;
09162
09163 const char_t* nodetest;
09164
09165 const unsigned char* table;
09166 } _data;
09167
09168 xpath_ast_node(const xpath_ast_node&);
09169 xpath_ast_node& operator=(const xpath_ast_node&);
09170
09171 template <class Comp> static bool compare_eq(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
09172 {
09173 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
09174
09175 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
09176 {
09177 if (lt == xpath_type_boolean || rt == xpath_type_boolean)
09178 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
09179 else if (lt == xpath_type_number || rt == xpath_type_number)
09180 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
09181 else if (lt == xpath_type_string || rt == xpath_type_string)
09182 {
09183 xpath_allocator_capture cr(stack.result);
09184
09185 xpath_string ls = lhs->eval_string(c, stack);
09186 xpath_string rs = rhs->eval_string(c, stack);
09187
09188 return comp(ls, rs);
09189 }
09190 }
09191 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
09192 {
09193 xpath_allocator_capture cr(stack.result);
09194
09195 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
09196 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
09197
09198 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
09199 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
09200 {
09201 xpath_allocator_capture cri(stack.result);
09202
09203 if (comp(string_value(*li, stack.result), string_value(*ri, stack.result)))
09204 return true;
09205 }
09206
09207 return false;
09208 }
09209 else
09210 {
09211 if (lt == xpath_type_node_set)
09212 {
09213 swap(lhs, rhs);
09214 swap(lt, rt);
09215 }
09216
09217 if (lt == xpath_type_boolean)
09218 return comp(lhs->eval_boolean(c, stack), rhs->eval_boolean(c, stack));
09219 else if (lt == xpath_type_number)
09220 {
09221 xpath_allocator_capture cr(stack.result);
09222
09223 double l = lhs->eval_number(c, stack);
09224 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
09225
09226 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
09227 {
09228 xpath_allocator_capture cri(stack.result);
09229
09230 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
09231 return true;
09232 }
09233
09234 return false;
09235 }
09236 else if (lt == xpath_type_string)
09237 {
09238 xpath_allocator_capture cr(stack.result);
09239
09240 xpath_string l = lhs->eval_string(c, stack);
09241 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
09242
09243 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
09244 {
09245 xpath_allocator_capture cri(stack.result);
09246
09247 if (comp(l, string_value(*ri, stack.result)))
09248 return true;
09249 }
09250
09251 return false;
09252 }
09253 }
09254
09255 assert(!"Wrong types");
09256 return false;
09257 }
09258
09259 static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval)
09260 {
09261 return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any;
09262 }
09263
09264 template <class Comp> static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
09265 {
09266 xpath_value_type lt = lhs->rettype(), rt = rhs->rettype();
09267
09268 if (lt != xpath_type_node_set && rt != xpath_type_node_set)
09269 return comp(lhs->eval_number(c, stack), rhs->eval_number(c, stack));
09270 else if (lt == xpath_type_node_set && rt == xpath_type_node_set)
09271 {
09272 xpath_allocator_capture cr(stack.result);
09273
09274 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
09275 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
09276
09277 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
09278 {
09279 xpath_allocator_capture cri(stack.result);
09280
09281 double l = convert_string_to_number(string_value(*li, stack.result).c_str());
09282
09283 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
09284 {
09285 xpath_allocator_capture crii(stack.result);
09286
09287 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
09288 return true;
09289 }
09290 }
09291
09292 return false;
09293 }
09294 else if (lt != xpath_type_node_set && rt == xpath_type_node_set)
09295 {
09296 xpath_allocator_capture cr(stack.result);
09297
09298 double l = lhs->eval_number(c, stack);
09299 xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
09300
09301 for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
09302 {
09303 xpath_allocator_capture cri(stack.result);
09304
09305 if (comp(l, convert_string_to_number(string_value(*ri, stack.result).c_str())))
09306 return true;
09307 }
09308
09309 return false;
09310 }
09311 else if (lt == xpath_type_node_set && rt != xpath_type_node_set)
09312 {
09313 xpath_allocator_capture cr(stack.result);
09314
09315 xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
09316 double r = rhs->eval_number(c, stack);
09317
09318 for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
09319 {
09320 xpath_allocator_capture cri(stack.result);
09321
09322 if (comp(convert_string_to_number(string_value(*li, stack.result).c_str()), r))
09323 return true;
09324 }
09325
09326 return false;
09327 }
09328 else
09329 {
09330 assert(!"Wrong types");
09331 return false;
09332 }
09333 }
09334
09335 static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)
09336 {
09337 assert(ns.size() >= first);
09338 assert(expr->rettype() != xpath_type_number);
09339
09340 size_t i = 1;
09341 size_t size = ns.size() - first;
09342
09343 xpath_node* last = ns.begin() + first;
09344
09345
09346 for (xpath_node* it = last; it != ns.end(); ++it, ++i)
09347 {
09348 xpath_context c(*it, i, size);
09349
09350 if (expr->eval_boolean(c, stack))
09351 {
09352 *last++ = *it;
09353
09354 if (once) break;
09355 }
09356 }
09357
09358 ns.truncate(last);
09359 }
09360
09361 static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)
09362 {
09363 assert(ns.size() >= first);
09364 assert(expr->rettype() == xpath_type_number);
09365
09366 size_t i = 1;
09367 size_t size = ns.size() - first;
09368
09369 xpath_node* last = ns.begin() + first;
09370
09371
09372 for (xpath_node* it = last; it != ns.end(); ++it, ++i)
09373 {
09374 xpath_context c(*it, i, size);
09375
09376 if (expr->eval_number(c, stack) == i)
09377 {
09378 *last++ = *it;
09379
09380 if (once) break;
09381 }
09382 }
09383
09384 ns.truncate(last);
09385 }
09386
09387 static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)
09388 {
09389 assert(ns.size() >= first);
09390 assert(expr->rettype() == xpath_type_number);
09391
09392 size_t size = ns.size() - first;
09393
09394 xpath_node* last = ns.begin() + first;
09395
09396 xpath_context c(xpath_node(), 1, size);
09397
09398 double er = expr->eval_number(c, stack);
09399
09400 if (er >= 1.0 && er <= size)
09401 {
09402 size_t eri = static_cast<size_t>(er);
09403
09404 if (er == eri)
09405 {
09406 xpath_node r = last[eri - 1];
09407
09408 *last++ = r;
09409 }
09410 }
09411
09412 ns.truncate(last);
09413 }
09414
09415 void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once)
09416 {
09417 if (ns.size() == first) return;
09418
09419 assert(_type == ast_filter || _type == ast_predicate);
09420
09421 if (_test == predicate_constant || _test == predicate_constant_one)
09422 apply_predicate_number_const(ns, first, _right, stack);
09423 else if (_right->rettype() == xpath_type_number)
09424 apply_predicate_number(ns, first, _right, stack, once);
09425 else
09426 apply_predicate_boolean(ns, first, _right, stack, once);
09427 }
09428
09429 void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval)
09430 {
09431 if (ns.size() == first) return;
09432
09433 bool last_once = eval_once(ns.type(), eval);
09434
09435 for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
09436 pred->apply_predicate(ns, first, stack, !pred->_next && last_once);
09437 }
09438
09439 bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc)
09440 {
09441 assert(a);
09442
09443 const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT("");
09444
09445 switch (_test)
09446 {
09447 case nodetest_name:
09448 if (strequal(name, _data.nodetest) && is_xpath_attribute(name))
09449 {
09450 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
09451 return true;
09452 }
09453 break;
09454
09455 case nodetest_type_node:
09456 case nodetest_all:
09457 if (is_xpath_attribute(name))
09458 {
09459 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
09460 return true;
09461 }
09462 break;
09463
09464 case nodetest_all_in_namespace:
09465 if (starts_with(name, _data.nodetest) && is_xpath_attribute(name))
09466 {
09467 ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
09468 return true;
09469 }
09470 break;
09471
09472 default:
09473 ;
09474 }
09475
09476 return false;
09477 }
09478
09479 bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc)
09480 {
09481 assert(n);
09482
09483 xml_node_type type = PUGI__NODETYPE(n);
09484
09485 switch (_test)
09486 {
09487 case nodetest_name:
09488 if (type == node_element && n->name && strequal(n->name, _data.nodetest))
09489 {
09490 ns.push_back(xml_node(n), alloc);
09491 return true;
09492 }
09493 break;
09494
09495 case nodetest_type_node:
09496 ns.push_back(xml_node(n), alloc);
09497 return true;
09498
09499 case nodetest_type_comment:
09500 if (type == node_comment)
09501 {
09502 ns.push_back(xml_node(n), alloc);
09503 return true;
09504 }
09505 break;
09506
09507 case nodetest_type_text:
09508 if (type == node_pcdata || type == node_cdata)
09509 {
09510 ns.push_back(xml_node(n), alloc);
09511 return true;
09512 }
09513 break;
09514
09515 case nodetest_type_pi:
09516 if (type == node_pi)
09517 {
09518 ns.push_back(xml_node(n), alloc);
09519 return true;
09520 }
09521 break;
09522
09523 case nodetest_pi:
09524 if (type == node_pi && n->name && strequal(n->name, _data.nodetest))
09525 {
09526 ns.push_back(xml_node(n), alloc);
09527 return true;
09528 }
09529 break;
09530
09531 case nodetest_all:
09532 if (type == node_element)
09533 {
09534 ns.push_back(xml_node(n), alloc);
09535 return true;
09536 }
09537 break;
09538
09539 case nodetest_all_in_namespace:
09540 if (type == node_element && n->name && starts_with(n->name, _data.nodetest))
09541 {
09542 ns.push_back(xml_node(n), alloc);
09543 return true;
09544 }
09545 break;
09546
09547 default:
09548 assert(!"Unknown axis");
09549 }
09550
09551 return false;
09552 }
09553
09554 template <class T> void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T)
09555 {
09556 const axis_t axis = T::axis;
09557
09558 switch (axis)
09559 {
09560 case axis_attribute:
09561 {
09562 for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute)
09563 if (step_push(ns, a, n, alloc) & once)
09564 return;
09565
09566 break;
09567 }
09568
09569 case axis_child:
09570 {
09571 for (xml_node_struct* c = n->first_child; c; c = c->next_sibling)
09572 if (step_push(ns, c, alloc) & once)
09573 return;
09574
09575 break;
09576 }
09577
09578 case axis_descendant:
09579 case axis_descendant_or_self:
09580 {
09581 if (axis == axis_descendant_or_self)
09582 if (step_push(ns, n, alloc) & once)
09583 return;
09584
09585 xml_node_struct* cur = n->first_child;
09586
09587 while (cur)
09588 {
09589 if (step_push(ns, cur, alloc) & once)
09590 return;
09591
09592 if (cur->first_child)
09593 cur = cur->first_child;
09594 else
09595 {
09596 while (!cur->next_sibling)
09597 {
09598 cur = cur->parent;
09599
09600 if (cur == n) return;
09601 }
09602
09603 cur = cur->next_sibling;
09604 }
09605 }
09606
09607 break;
09608 }
09609
09610 case axis_following_sibling:
09611 {
09612 for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling)
09613 if (step_push(ns, c, alloc) & once)
09614 return;
09615
09616 break;
09617 }
09618
09619 case axis_preceding_sibling:
09620 {
09621 for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c)
09622 if (step_push(ns, c, alloc) & once)
09623 return;
09624
09625 break;
09626 }
09627
09628 case axis_following:
09629 {
09630 xml_node_struct* cur = n;
09631
09632
09633 while (!cur->next_sibling)
09634 {
09635 cur = cur->parent;
09636
09637 if (!cur) return;
09638 }
09639
09640 cur = cur->next_sibling;
09641
09642 while (cur)
09643 {
09644 if (step_push(ns, cur, alloc) & once)
09645 return;
09646
09647 if (cur->first_child)
09648 cur = cur->first_child;
09649 else
09650 {
09651 while (!cur->next_sibling)
09652 {
09653 cur = cur->parent;
09654
09655 if (!cur) return;
09656 }
09657
09658 cur = cur->next_sibling;
09659 }
09660 }
09661
09662 break;
09663 }
09664
09665 case axis_preceding:
09666 {
09667 xml_node_struct* cur = n;
09668
09669
09670 while (!cur->prev_sibling_c->next_sibling)
09671 {
09672 cur = cur->parent;
09673
09674 if (!cur) return;
09675 }
09676
09677 cur = cur->prev_sibling_c;
09678
09679 while (cur)
09680 {
09681 if (cur->first_child)
09682 cur = cur->first_child->prev_sibling_c;
09683 else
09684 {
09685
09686 if (step_push(ns, cur, alloc) & once)
09687 return;
09688
09689 while (!cur->prev_sibling_c->next_sibling)
09690 {
09691 cur = cur->parent;
09692
09693 if (!cur) return;
09694
09695 if (!node_is_ancestor(cur, n))
09696 if (step_push(ns, cur, alloc) & once)
09697 return;
09698 }
09699
09700 cur = cur->prev_sibling_c;
09701 }
09702 }
09703
09704 break;
09705 }
09706
09707 case axis_ancestor:
09708 case axis_ancestor_or_self:
09709 {
09710 if (axis == axis_ancestor_or_self)
09711 if (step_push(ns, n, alloc) & once)
09712 return;
09713
09714 xml_node_struct* cur = n->parent;
09715
09716 while (cur)
09717 {
09718 if (step_push(ns, cur, alloc) & once)
09719 return;
09720
09721 cur = cur->parent;
09722 }
09723
09724 break;
09725 }
09726
09727 case axis_self:
09728 {
09729 step_push(ns, n, alloc);
09730
09731 break;
09732 }
09733
09734 case axis_parent:
09735 {
09736 if (n->parent)
09737 step_push(ns, n->parent, alloc);
09738
09739 break;
09740 }
09741
09742 default:
09743 assert(!"Unimplemented axis");
09744 }
09745 }
09746
09747 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)
09748 {
09749 const axis_t axis = T::axis;
09750
09751 switch (axis)
09752 {
09753 case axis_ancestor:
09754 case axis_ancestor_or_self:
09755 {
09756 if (axis == axis_ancestor_or_self && _test == nodetest_type_node)
09757 if (step_push(ns, a, p, alloc) & once)
09758 return;
09759
09760 xml_node_struct* cur = p;
09761
09762 while (cur)
09763 {
09764 if (step_push(ns, cur, alloc) & once)
09765 return;
09766
09767 cur = cur->parent;
09768 }
09769
09770 break;
09771 }
09772
09773 case axis_descendant_or_self:
09774 case axis_self:
09775 {
09776 if (_test == nodetest_type_node)
09777 step_push(ns, a, p, alloc);
09778
09779 break;
09780 }
09781
09782 case axis_following:
09783 {
09784 xml_node_struct* cur = p;
09785
09786 while (cur)
09787 {
09788 if (cur->first_child)
09789 cur = cur->first_child;
09790 else
09791 {
09792 while (!cur->next_sibling)
09793 {
09794 cur = cur->parent;
09795
09796 if (!cur) return;
09797 }
09798
09799 cur = cur->next_sibling;
09800 }
09801
09802 if (step_push(ns, cur, alloc) & once)
09803 return;
09804 }
09805
09806 break;
09807 }
09808
09809 case axis_parent:
09810 {
09811 step_push(ns, p, alloc);
09812
09813 break;
09814 }
09815
09816 case axis_preceding:
09817 {
09818
09819 step_fill(ns, p, alloc, once, v);
09820 break;
09821 }
09822
09823 default:
09824 assert(!"Unimplemented axis");
09825 }
09826 }
09827
09828 template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v)
09829 {
09830 const axis_t axis = T::axis;
09831 const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
09832
09833 if (xn.node())
09834 step_fill(ns, xn.node().internal_object(), alloc, once, v);
09835 else if (axis_has_attributes && xn.attribute() && xn.parent())
09836 step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v);
09837 }
09838
09839 template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v)
09840 {
09841 const axis_t axis = T::axis;
09842 const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);
09843 const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
09844
09845 bool once =
09846 (axis == axis_attribute && _test == nodetest_name) ||
09847 (!_right && eval_once(axis_type, eval)) ||
09848 (_right && !_right->_next && _right->_test == predicate_constant_one);
09849
09850 xpath_node_set_raw ns;
09851 ns.set_type(axis_type);
09852
09853 if (_left)
09854 {
09855 xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all);
09856
09857
09858 if (axis == axis_self) ns.set_type(s.type());
09859
09860 for (const xpath_node* it = s.begin(); it != s.end(); ++it)
09861 {
09862 size_t size = ns.size();
09863
09864
09865 if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
09866
09867 step_fill(ns, *it, stack.result, once, v);
09868 if (_right) apply_predicates(ns, size, stack, eval);
09869 }
09870 }
09871 else
09872 {
09873 step_fill(ns, c.n, stack.result, once, v);
09874 if (_right) apply_predicates(ns, 0, stack, eval);
09875 }
09876
09877
09878
09879 if (axis != axis_child && axis != axis_attribute && axis != axis_self && ns.type() == xpath_node_set::type_unsorted)
09880 ns.remove_duplicates();
09881
09882 return ns;
09883 }
09884
09885 public:
09886 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value):
09887 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
09888 {
09889 assert(type == ast_string_constant);
09890 _data.string = value;
09891 }
09892
09893 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value):
09894 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
09895 {
09896 assert(type == ast_number_constant);
09897 _data.number = value;
09898 }
09899
09900 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):
09901 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
09902 {
09903 assert(type == ast_variable);
09904 _data.variable = value;
09905 }
09906
09907 xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0):
09908 _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
09909 {
09910 }
09911
09912 xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents):
09913 _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(static_cast<char>(axis)), _test(static_cast<char>(test)), _left(left), _right(0), _next(0)
09914 {
09915 assert(type == ast_step);
09916 _data.nodetest = contents;
09917 }
09918
09919 xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test):
09920 _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast<char>(test)), _left(left), _right(right), _next(0)
09921 {
09922 assert(type == ast_filter || type == ast_predicate);
09923 }
09924
09925 void set_next(xpath_ast_node* value)
09926 {
09927 _next = value;
09928 }
09929
09930 void set_right(xpath_ast_node* value)
09931 {
09932 _right = value;
09933 }
09934
09935 bool eval_boolean(const xpath_context& c, const xpath_stack& stack)
09936 {
09937 switch (_type)
09938 {
09939 case ast_op_or:
09940 return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
09941
09942 case ast_op_and:
09943 return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
09944
09945 case ast_op_equal:
09946 return compare_eq(_left, _right, c, stack, equal_to());
09947
09948 case ast_op_not_equal:
09949 return compare_eq(_left, _right, c, stack, not_equal_to());
09950
09951 case ast_op_less:
09952 return compare_rel(_left, _right, c, stack, less());
09953
09954 case ast_op_greater:
09955 return compare_rel(_right, _left, c, stack, less());
09956
09957 case ast_op_less_or_equal:
09958 return compare_rel(_left, _right, c, stack, less_equal());
09959
09960 case ast_op_greater_or_equal:
09961 return compare_rel(_right, _left, c, stack, less_equal());
09962
09963 case ast_func_starts_with:
09964 {
09965 xpath_allocator_capture cr(stack.result);
09966
09967 xpath_string lr = _left->eval_string(c, stack);
09968 xpath_string rr = _right->eval_string(c, stack);
09969
09970 return starts_with(lr.c_str(), rr.c_str());
09971 }
09972
09973 case ast_func_contains:
09974 {
09975 xpath_allocator_capture cr(stack.result);
09976
09977 xpath_string lr = _left->eval_string(c, stack);
09978 xpath_string rr = _right->eval_string(c, stack);
09979
09980 return find_substring(lr.c_str(), rr.c_str()) != 0;
09981 }
09982
09983 case ast_func_boolean:
09984 return _left->eval_boolean(c, stack);
09985
09986 case ast_func_not:
09987 return !_left->eval_boolean(c, stack);
09988
09989 case ast_func_true:
09990 return true;
09991
09992 case ast_func_false:
09993 return false;
09994
09995 case ast_func_lang:
09996 {
09997 if (c.n.attribute()) return false;
09998
09999 xpath_allocator_capture cr(stack.result);
10000
10001 xpath_string lang = _left->eval_string(c, stack);
10002
10003 for (xml_node n = c.n.node(); n; n = n.parent())
10004 {
10005 xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
10006
10007 if (a)
10008 {
10009 const char_t* value = a.value();
10010
10011
10012 for (const char_t* lit = lang.c_str(); *lit; ++lit)
10013 {
10014 if (tolower_ascii(*lit) != tolower_ascii(*value)) return false;
10015 ++value;
10016 }
10017
10018 return *value == 0 || *value == '-';
10019 }
10020 }
10021
10022 return false;
10023 }
10024
10025 case ast_opt_compare_attribute:
10026 {
10027 const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string();
10028
10029 xml_attribute attr = c.n.node().attribute(_left->_data.nodetest);
10030
10031 return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name());
10032 }
10033
10034 case ast_variable:
10035 {
10036 assert(_rettype == _data.variable->type());
10037
10038 if (_rettype == xpath_type_boolean)
10039 return _data.variable->get_boolean();
10040
10041
10042 }
10043
10044 default:
10045 {
10046 switch (_rettype)
10047 {
10048 case xpath_type_number:
10049 return convert_number_to_boolean(eval_number(c, stack));
10050
10051 case xpath_type_string:
10052 {
10053 xpath_allocator_capture cr(stack.result);
10054
10055 return !eval_string(c, stack).empty();
10056 }
10057
10058 case xpath_type_node_set:
10059 {
10060 xpath_allocator_capture cr(stack.result);
10061
10062 return !eval_node_set(c, stack, nodeset_eval_any).empty();
10063 }
10064
10065 default:
10066 assert(!"Wrong expression for return type boolean");
10067 return false;
10068 }
10069 }
10070 }
10071 }
10072
10073 double eval_number(const xpath_context& c, const xpath_stack& stack)
10074 {
10075 switch (_type)
10076 {
10077 case ast_op_add:
10078 return _left->eval_number(c, stack) + _right->eval_number(c, stack);
10079
10080 case ast_op_subtract:
10081 return _left->eval_number(c, stack) - _right->eval_number(c, stack);
10082
10083 case ast_op_multiply:
10084 return _left->eval_number(c, stack) * _right->eval_number(c, stack);
10085
10086 case ast_op_divide:
10087 return _left->eval_number(c, stack) / _right->eval_number(c, stack);
10088
10089 case ast_op_mod:
10090 return fmod(_left->eval_number(c, stack), _right->eval_number(c, stack));
10091
10092 case ast_op_negate:
10093 return -_left->eval_number(c, stack);
10094
10095 case ast_number_constant:
10096 return _data.number;
10097
10098 case ast_func_last:
10099 return static_cast<double>(c.size);
10100
10101 case ast_func_position:
10102 return static_cast<double>(c.position);
10103
10104 case ast_func_count:
10105 {
10106 xpath_allocator_capture cr(stack.result);
10107
10108 return static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size());
10109 }
10110
10111 case ast_func_string_length_0:
10112 {
10113 xpath_allocator_capture cr(stack.result);
10114
10115 return static_cast<double>(string_value(c.n, stack.result).length());
10116 }
10117
10118 case ast_func_string_length_1:
10119 {
10120 xpath_allocator_capture cr(stack.result);
10121
10122 return static_cast<double>(_left->eval_string(c, stack).length());
10123 }
10124
10125 case ast_func_number_0:
10126 {
10127 xpath_allocator_capture cr(stack.result);
10128
10129 return convert_string_to_number(string_value(c.n, stack.result).c_str());
10130 }
10131
10132 case ast_func_number_1:
10133 return _left->eval_number(c, stack);
10134
10135 case ast_func_sum:
10136 {
10137 xpath_allocator_capture cr(stack.result);
10138
10139 double r = 0;
10140
10141 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all);
10142
10143 for (const xpath_node* it = ns.begin(); it != ns.end(); ++it)
10144 {
10145 xpath_allocator_capture cri(stack.result);
10146
10147 r += convert_string_to_number(string_value(*it, stack.result).c_str());
10148 }
10149
10150 return r;
10151 }
10152
10153 case ast_func_floor:
10154 {
10155 double r = _left->eval_number(c, stack);
10156
10157 return r == r ? floor(r) : r;
10158 }
10159
10160 case ast_func_ceiling:
10161 {
10162 double r = _left->eval_number(c, stack);
10163
10164 return r == r ? ceil(r) : r;
10165 }
10166
10167 case ast_func_round:
10168 return round_nearest_nzero(_left->eval_number(c, stack));
10169
10170 case ast_variable:
10171 {
10172 assert(_rettype == _data.variable->type());
10173
10174 if (_rettype == xpath_type_number)
10175 return _data.variable->get_number();
10176
10177
10178 }
10179
10180 default:
10181 {
10182 switch (_rettype)
10183 {
10184 case xpath_type_boolean:
10185 return eval_boolean(c, stack) ? 1 : 0;
10186
10187 case xpath_type_string:
10188 {
10189 xpath_allocator_capture cr(stack.result);
10190
10191 return convert_string_to_number(eval_string(c, stack).c_str());
10192 }
10193
10194 case xpath_type_node_set:
10195 {
10196 xpath_allocator_capture cr(stack.result);
10197
10198 return convert_string_to_number(eval_string(c, stack).c_str());
10199 }
10200
10201 default:
10202 assert(!"Wrong expression for return type number");
10203 return 0;
10204 }
10205
10206 }
10207 }
10208 }
10209
10210 xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack)
10211 {
10212 assert(_type == ast_func_concat);
10213
10214 xpath_allocator_capture ct(stack.temp);
10215
10216
10217 size_t count = 1;
10218 for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
10219
10220
10221 xpath_string static_buffer[4];
10222 xpath_string* buffer = static_buffer;
10223
10224
10225 if (count > sizeof(static_buffer) / sizeof(static_buffer[0]))
10226 {
10227 buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string)));
10228 assert(buffer);
10229 }
10230
10231
10232 xpath_stack swapped_stack = {stack.temp, stack.result};
10233
10234 buffer[0] = _left->eval_string(c, swapped_stack);
10235
10236 size_t pos = 1;
10237 for (xpath_ast_node* n = _right; n; n = n->_next, ++pos) buffer[pos] = n->eval_string(c, swapped_stack);
10238 assert(pos == count);
10239
10240
10241 size_t length = 0;
10242 for (size_t i = 0; i < count; ++i) length += buffer[i].length();
10243
10244
10245 char_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t)));
10246 assert(result);
10247
10248 char_t* ri = result;
10249
10250 for (size_t j = 0; j < count; ++j)
10251 for (const char_t* bi = buffer[j].c_str(); *bi; ++bi)
10252 *ri++ = *bi;
10253
10254 *ri = 0;
10255
10256 return xpath_string::from_heap_preallocated(result, ri);
10257 }
10258
10259 xpath_string eval_string(const xpath_context& c, const xpath_stack& stack)
10260 {
10261 switch (_type)
10262 {
10263 case ast_string_constant:
10264 return xpath_string::from_const(_data.string);
10265
10266 case ast_func_local_name_0:
10267 {
10268 xpath_node na = c.n;
10269
10270 return xpath_string::from_const(local_name(na));
10271 }
10272
10273 case ast_func_local_name_1:
10274 {
10275 xpath_allocator_capture cr(stack.result);
10276
10277 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10278 xpath_node na = ns.first();
10279
10280 return xpath_string::from_const(local_name(na));
10281 }
10282
10283 case ast_func_name_0:
10284 {
10285 xpath_node na = c.n;
10286
10287 return xpath_string::from_const(qualified_name(na));
10288 }
10289
10290 case ast_func_name_1:
10291 {
10292 xpath_allocator_capture cr(stack.result);
10293
10294 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10295 xpath_node na = ns.first();
10296
10297 return xpath_string::from_const(qualified_name(na));
10298 }
10299
10300 case ast_func_namespace_uri_0:
10301 {
10302 xpath_node na = c.n;
10303
10304 return xpath_string::from_const(namespace_uri(na));
10305 }
10306
10307 case ast_func_namespace_uri_1:
10308 {
10309 xpath_allocator_capture cr(stack.result);
10310
10311 xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
10312 xpath_node na = ns.first();
10313
10314 return xpath_string::from_const(namespace_uri(na));
10315 }
10316
10317 case ast_func_string_0:
10318 return string_value(c.n, stack.result);
10319
10320 case ast_func_string_1:
10321 return _left->eval_string(c, stack);
10322
10323 case ast_func_concat:
10324 return eval_string_concat(c, stack);
10325
10326 case ast_func_substring_before:
10327 {
10328 xpath_allocator_capture cr(stack.temp);
10329
10330 xpath_stack swapped_stack = {stack.temp, stack.result};
10331
10332 xpath_string s = _left->eval_string(c, swapped_stack);
10333 xpath_string p = _right->eval_string(c, swapped_stack);
10334
10335 const char_t* pos = find_substring(s.c_str(), p.c_str());
10336
10337 return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string();
10338 }
10339
10340 case ast_func_substring_after:
10341 {
10342 xpath_allocator_capture cr(stack.temp);
10343
10344 xpath_stack swapped_stack = {stack.temp, stack.result};
10345
10346 xpath_string s = _left->eval_string(c, swapped_stack);
10347 xpath_string p = _right->eval_string(c, swapped_stack);
10348
10349 const char_t* pos = find_substring(s.c_str(), p.c_str());
10350 if (!pos) return xpath_string();
10351
10352 const char_t* rbegin = pos + p.length();
10353 const char_t* rend = s.c_str() + s.length();
10354
10355 return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
10356 }
10357
10358 case ast_func_substring_2:
10359 {
10360 xpath_allocator_capture cr(stack.temp);
10361
10362 xpath_stack swapped_stack = {stack.temp, stack.result};
10363
10364 xpath_string s = _left->eval_string(c, swapped_stack);
10365 size_t s_length = s.length();
10366
10367 double first = round_nearest(_right->eval_number(c, stack));
10368
10369 if (is_nan(first)) return xpath_string();
10370 else if (first >= s_length + 1) return xpath_string();
10371
10372 size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
10373 assert(1 <= pos && pos <= s_length + 1);
10374
10375 const char_t* rbegin = s.c_str() + (pos - 1);
10376 const char_t* rend = s.c_str() + s.length();
10377
10378 return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
10379 }
10380
10381 case ast_func_substring_3:
10382 {
10383 xpath_allocator_capture cr(stack.temp);
10384
10385 xpath_stack swapped_stack = {stack.temp, stack.result};
10386
10387 xpath_string s = _left->eval_string(c, swapped_stack);
10388 size_t s_length = s.length();
10389
10390 double first = round_nearest(_right->eval_number(c, stack));
10391 double last = first + round_nearest(_right->_next->eval_number(c, stack));
10392
10393 if (is_nan(first) || is_nan(last)) return xpath_string();
10394 else if (first >= s_length + 1) return xpath_string();
10395 else if (first >= last) return xpath_string();
10396 else if (last < 1) return xpath_string();
10397
10398 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);
10400
10401 assert(1 <= pos && pos <= end && end <= s_length + 1);
10402 const char_t* rbegin = s.c_str() + (pos - 1);
10403 const char_t* rend = s.c_str() + (end - 1);
10404
10405 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result);
10406 }
10407
10408 case ast_func_normalize_space_0:
10409 {
10410 xpath_string s = string_value(c.n, stack.result);
10411
10412 char_t* begin = s.data(stack.result);
10413 char_t* end = normalize_space(begin);
10414
10415 return xpath_string::from_heap_preallocated(begin, end);
10416 }
10417
10418 case ast_func_normalize_space_1:
10419 {
10420 xpath_string s = _left->eval_string(c, stack);
10421
10422 char_t* begin = s.data(stack.result);
10423 char_t* end = normalize_space(begin);
10424
10425 return xpath_string::from_heap_preallocated(begin, end);
10426 }
10427
10428 case ast_func_translate:
10429 {
10430 xpath_allocator_capture cr(stack.temp);
10431
10432 xpath_stack swapped_stack = {stack.temp, stack.result};
10433
10434 xpath_string s = _left->eval_string(c, stack);
10435 xpath_string from = _right->eval_string(c, swapped_stack);
10436 xpath_string to = _right->_next->eval_string(c, swapped_stack);
10437
10438 char_t* begin = s.data(stack.result);
10439 char_t* end = translate(begin, from.c_str(), to.c_str(), to.length());
10440
10441 return xpath_string::from_heap_preallocated(begin, end);
10442 }
10443
10444 case ast_opt_translate_table:
10445 {
10446 xpath_string s = _left->eval_string(c, stack);
10447
10448 char_t* begin = s.data(stack.result);
10449 char_t* end = translate_table(begin, _data.table);
10450
10451 return xpath_string::from_heap_preallocated(begin, end);
10452 }
10453
10454 case ast_variable:
10455 {
10456 assert(_rettype == _data.variable->type());
10457
10458 if (_rettype == xpath_type_string)
10459 return xpath_string::from_const(_data.variable->get_string());
10460
10461
10462 }
10463
10464 default:
10465 {
10466 switch (_rettype)
10467 {
10468 case xpath_type_boolean:
10469 return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
10470
10471 case xpath_type_number:
10472 return convert_number_to_string(eval_number(c, stack), stack.result);
10473
10474 case xpath_type_node_set:
10475 {
10476 xpath_allocator_capture cr(stack.temp);
10477
10478 xpath_stack swapped_stack = {stack.temp, stack.result};
10479
10480 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);
10482 }
10483
10484 default:
10485 assert(!"Wrong expression for return type string");
10486 return xpath_string();
10487 }
10488 }
10489 }
10490 }
10491
10492 xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval)
10493 {
10494 switch (_type)
10495 {
10496 case ast_op_union:
10497 {
10498 xpath_allocator_capture cr(stack.temp);
10499
10500 xpath_stack swapped_stack = {stack.temp, stack.result};
10501
10502 xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack, eval);
10503 xpath_node_set_raw rs = _right->eval_node_set(c, stack, eval);
10504
10505
10506 rs.set_type(xpath_node_set::type_unsorted);
10507
10508 rs.append(ls.begin(), ls.end(), stack.result);
10509 rs.remove_duplicates();
10510
10511 return rs;
10512 }
10513
10514 case ast_filter:
10515 {
10516 xpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all);
10517
10518
10519 if (_test != predicate_posinv) set.sort_do();
10520
10521 bool once = eval_once(set.type(), eval);
10522
10523 apply_predicate(set, 0, stack, once);
10524
10525 return set;
10526 }
10527
10528 case ast_func_id:
10529 return xpath_node_set_raw();
10530
10531 case ast_step:
10532 {
10533 switch (_axis)
10534 {
10535 case axis_ancestor:
10536 return step_do(c, stack, eval, axis_to_type<axis_ancestor>());
10537
10538 case axis_ancestor_or_self:
10539 return step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>());
10540
10541 case axis_attribute:
10542 return step_do(c, stack, eval, axis_to_type<axis_attribute>());
10543
10544 case axis_child:
10545 return step_do(c, stack, eval, axis_to_type<axis_child>());
10546
10547 case axis_descendant:
10548 return step_do(c, stack, eval, axis_to_type<axis_descendant>());
10549
10550 case axis_descendant_or_self:
10551 return step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>());
10552
10553 case axis_following:
10554 return step_do(c, stack, eval, axis_to_type<axis_following>());
10555
10556 case axis_following_sibling:
10557 return step_do(c, stack, eval, axis_to_type<axis_following_sibling>());
10558
10559 case axis_namespace:
10560
10561 return xpath_node_set_raw();
10562
10563 case axis_parent:
10564 return step_do(c, stack, eval, axis_to_type<axis_parent>());
10565
10566 case axis_preceding:
10567 return step_do(c, stack, eval, axis_to_type<axis_preceding>());
10568
10569 case axis_preceding_sibling:
10570 return step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>());
10571
10572 case axis_self:
10573 return step_do(c, stack, eval, axis_to_type<axis_self>());
10574
10575 default:
10576 assert(!"Unknown axis");
10577 return xpath_node_set_raw();
10578 }
10579 }
10580
10581 case ast_step_root:
10582 {
10583 assert(!_right);
10584
10585 xpath_node_set_raw ns;
10586
10587 ns.set_type(xpath_node_set::type_sorted);
10588
10589 if (c.n.node()) ns.push_back(c.n.node().root(), stack.result);
10590 else if (c.n.attribute()) ns.push_back(c.n.parent().root(), stack.result);
10591
10592 return ns;
10593 }
10594
10595 case ast_variable:
10596 {
10597 assert(_rettype == _data.variable->type());
10598
10599 if (_rettype == xpath_type_node_set)
10600 {
10601 const xpath_node_set& s = _data.variable->get_node_set();
10602
10603 xpath_node_set_raw ns;
10604
10605 ns.set_type(s.type());
10606 ns.append(s.begin(), s.end(), stack.result);
10607
10608 return ns;
10609 }
10610
10611
10612 }
10613
10614 default:
10615 assert(!"Wrong expression for return type node set");
10616 return xpath_node_set_raw();
10617 }
10618 }
10619
10620 void optimize(xpath_allocator* alloc)
10621 {
10622 if (_left) _left->optimize(alloc);
10623 if (_right) _right->optimize(alloc);
10624 if (_next) _next->optimize(alloc);
10625
10626 optimize_self(alloc);
10627 }
10628
10629 void optimize_self(xpath_allocator* alloc)
10630 {
10631
10632
10633 if ((_type == ast_filter || _type == ast_predicate) &&
10634 _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number)
10635 {
10636 _right = _right->_right;
10637 }
10638
10639
10640 if (_type == ast_filter || _type == ast_predicate)
10641 {
10642 assert(_test == predicate_default);
10643
10644 if (_right->_type == ast_number_constant && _right->_data.number == 1.0)
10645 _test = predicate_constant_one;
10646 else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last))
10647 _test = predicate_constant;
10648 else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr())
10649 _test = predicate_posinv;
10650 }
10651
10652
10653
10654
10655
10656 if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) && _left &&
10657 _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right &&
10658 is_posinv_step())
10659 {
10660 if (_axis == axis_child || _axis == axis_descendant)
10661 _axis = axis_descendant;
10662 else
10663 _axis = axis_descendant_or_self;
10664
10665 _left = _left->_left;
10666 }
10667
10668
10669 if (_type == ast_func_translate && _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant)
10670 {
10671 unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string);
10672
10673 if (table)
10674 {
10675 _type = ast_opt_translate_table;
10676 _data.table = table;
10677 }
10678 }
10679
10680
10681 if (_type == ast_op_equal &&
10682 _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right &&
10683 (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string)))
10684 {
10685 _type = ast_opt_compare_attribute;
10686 }
10687 }
10688
10689 bool is_posinv_expr() const
10690 {
10691 switch (_type)
10692 {
10693 case ast_func_position:
10694 case ast_func_last:
10695 return false;
10696
10697 case ast_string_constant:
10698 case ast_number_constant:
10699 case ast_variable:
10700 return true;
10701
10702 case ast_step:
10703 case ast_step_root:
10704 return true;
10705
10706 case ast_predicate:
10707 case ast_filter:
10708 return true;
10709
10710 default:
10711 if (_left && !_left->is_posinv_expr()) return false;
10712
10713 for (xpath_ast_node* n = _right; n; n = n->_next)
10714 if (!n->is_posinv_expr()) return false;
10715
10716 return true;
10717 }
10718 }
10719
10720 bool is_posinv_step() const
10721 {
10722 assert(_type == ast_step);
10723
10724 for (xpath_ast_node* n = _right; n; n = n->_next)
10725 {
10726 assert(n->_type == ast_predicate);
10727
10728 if (n->_test != predicate_posinv)
10729 return false;
10730 }
10731
10732 return true;
10733 }
10734
10735 xpath_value_type rettype() const
10736 {
10737 return static_cast<xpath_value_type>(_rettype);
10738 }
10739 };
10740
10741 struct xpath_parser
10742 {
10743 xpath_allocator* _alloc;
10744 xpath_lexer _lexer;
10745
10746 const char_t* _query;
10747 xpath_variable_set* _variables;
10748
10749 xpath_parse_result* _result;
10750
10751 char_t _scratch[32];
10752
10753 #ifdef PUGIXML_NO_EXCEPTIONS
10754 jmp_buf _error_handler;
10755 #endif
10756
10757 void throw_error(const char* message)
10758 {
10759 _result->error = message;
10760 _result->offset = _lexer.current_pos() - _query;
10761
10762 #ifdef PUGIXML_NO_EXCEPTIONS
10763 longjmp(_error_handler, 1);
10764 #else
10765 throw xpath_exception(*_result);
10766 #endif
10767 }
10768
10769 void throw_error_oom()
10770 {
10771 #ifdef PUGIXML_NO_EXCEPTIONS
10772 throw_error("Out of memory");
10773 #else
10774 throw std::bad_alloc();
10775 #endif
10776 }
10777
10778 void* alloc_node()
10779 {
10780 void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node));
10781
10782 if (!result) throw_error_oom();
10783
10784 return result;
10785 }
10786
10787 const char_t* alloc_string(const xpath_lexer_string& value)
10788 {
10789 if (value.begin)
10790 {
10791 size_t length = static_cast<size_t>(value.end - value.begin);
10792
10793 char_t* c = static_cast<char_t*>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t)));
10794 if (!c) throw_error_oom();
10795 assert(c);
10796
10797 memcpy(c, value.begin, length * sizeof(char_t));
10798 c[length] = 0;
10799
10800 return c;
10801 }
10802 else return 0;
10803 }
10804
10805 xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2])
10806 {
10807 assert(argc <= 1);
10808
10809 if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
10810
10811 return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
10812 }
10813
10814 xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2])
10815 {
10816 switch (name.begin[0])
10817 {
10818 case 'b':
10819 if (name == PUGIXML_TEXT("boolean") && argc == 1)
10820 return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]);
10821
10822 break;
10823
10824 case 'c':
10825 if (name == PUGIXML_TEXT("count") && argc == 1)
10826 {
10827 if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
10828 return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]);
10829 }
10830 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]);
10832 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]);
10834 else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
10835 return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]);
10836
10837 break;
10838
10839 case 'f':
10840 if (name == PUGIXML_TEXT("false") && argc == 0)
10841 return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean);
10842 else if (name == PUGIXML_TEXT("floor") && argc == 1)
10843 return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]);
10844
10845 break;
10846
10847 case 'i':
10848 if (name == PUGIXML_TEXT("id") && argc == 1)
10849 return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]);
10850
10851 break;
10852
10853 case 'l':
10854 if (name == PUGIXML_TEXT("last") && argc == 0)
10855 return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number);
10856 else if (name == PUGIXML_TEXT("lang") && argc == 1)
10857 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)
10859 return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args);
10860
10861 break;
10862
10863 case 'n':
10864 if (name == PUGIXML_TEXT("name") && argc <= 1)
10865 return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args);
10866 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);
10868 else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
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]);
10870 else if (name == PUGIXML_TEXT("not") && argc == 1)
10871 return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]);
10872 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]);
10874
10875 break;
10876
10877 case 'p':
10878 if (name == PUGIXML_TEXT("position") && argc == 0)
10879 return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number);
10880
10881 break;
10882
10883 case 'r':
10884 if (name == PUGIXML_TEXT("round") && argc == 1)
10885 return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]);
10886
10887 break;
10888
10889 case 's':
10890 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]);
10892 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]);
10894 else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
10895 return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
10896 else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
10897 return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
10898 else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
10899 return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
10900 else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
10901 return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
10902 else if (name == PUGIXML_TEXT("sum") && argc == 1)
10903 {
10904 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]);
10906 }
10907
10908 break;
10909
10910 case 't':
10911 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]);
10913 else if (name == PUGIXML_TEXT("true") && argc == 0)
10914 return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean);
10915
10916 break;
10917
10918 default:
10919 break;
10920 }
10921
10922 throw_error("Unrecognized function or wrong parameter count");
10923
10924 return 0;
10925 }
10926
10927 axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified)
10928 {
10929 specified = true;
10930
10931 switch (name.begin[0])
10932 {
10933 case 'a':
10934 if (name == PUGIXML_TEXT("ancestor"))
10935 return axis_ancestor;
10936 else if (name == PUGIXML_TEXT("ancestor-or-self"))
10937 return axis_ancestor_or_self;
10938 else if (name == PUGIXML_TEXT("attribute"))
10939 return axis_attribute;
10940
10941 break;
10942
10943 case 'c':
10944 if (name == PUGIXML_TEXT("child"))
10945 return axis_child;
10946
10947 break;
10948
10949 case 'd':
10950 if (name == PUGIXML_TEXT("descendant"))
10951 return axis_descendant;
10952 else if (name == PUGIXML_TEXT("descendant-or-self"))
10953 return axis_descendant_or_self;
10954
10955 break;
10956
10957 case 'f':
10958 if (name == PUGIXML_TEXT("following"))
10959 return axis_following;
10960 else if (name == PUGIXML_TEXT("following-sibling"))
10961 return axis_following_sibling;
10962
10963 break;
10964
10965 case 'n':
10966 if (name == PUGIXML_TEXT("namespace"))
10967 return axis_namespace;
10968
10969 break;
10970
10971 case 'p':
10972 if (name == PUGIXML_TEXT("parent"))
10973 return axis_parent;
10974 else if (name == PUGIXML_TEXT("preceding"))
10975 return axis_preceding;
10976 else if (name == PUGIXML_TEXT("preceding-sibling"))
10977 return axis_preceding_sibling;
10978
10979 break;
10980
10981 case 's':
10982 if (name == PUGIXML_TEXT("self"))
10983 return axis_self;
10984
10985 break;
10986
10987 default:
10988 break;
10989 }
10990
10991 specified = false;
10992 return axis_child;
10993 }
10994
10995 nodetest_t parse_node_test_type(const xpath_lexer_string& name)
10996 {
10997 switch (name.begin[0])
10998 {
10999 case 'c':
11000 if (name == PUGIXML_TEXT("comment"))
11001 return nodetest_type_comment;
11002
11003 break;
11004
11005 case 'n':
11006 if (name == PUGIXML_TEXT("node"))
11007 return nodetest_type_node;
11008
11009 break;
11010
11011 case 'p':
11012 if (name == PUGIXML_TEXT("processing-instruction"))
11013 return nodetest_type_pi;
11014
11015 break;
11016
11017 case 't':
11018 if (name == PUGIXML_TEXT("text"))
11019 return nodetest_type_text;
11020
11021 break;
11022
11023 default:
11024 break;
11025 }
11026
11027 return nodetest_none;
11028 }
11029
11030
11031 xpath_ast_node* parse_primary_expression()
11032 {
11033 switch (_lexer.current())
11034 {
11035 case lex_var_ref:
11036 {
11037 xpath_lexer_string name = _lexer.contents();
11038
11039 if (!_variables)
11040 throw_error("Unknown variable: variable set is not provided");
11041
11042 xpath_variable* var = 0;
11043 if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var))
11044 throw_error_oom();
11045
11046 if (!var)
11047 throw_error("Unknown variable: variable set does not contain the given name");
11048
11049 _lexer.next();
11050
11051 return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
11052 }
11053
11054 case lex_open_brace:
11055 {
11056 _lexer.next();
11057
11058 xpath_ast_node* n = parse_expression();
11059
11060 if (_lexer.current() != lex_close_brace)
11061 throw_error("Unmatched braces");
11062
11063 _lexer.next();
11064
11065 return n;
11066 }
11067
11068 case lex_quoted_string:
11069 {
11070 const char_t* value = alloc_string(_lexer.contents());
11071
11072 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value);
11073 _lexer.next();
11074
11075 return n;
11076 }
11077
11078 case lex_number:
11079 {
11080 double value = 0;
11081
11082 if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value))
11083 throw_error_oom();
11084
11085 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value);
11086 _lexer.next();
11087
11088 return n;
11089 }
11090
11091 case lex_string:
11092 {
11093 xpath_ast_node* args[2] = {0};
11094 size_t argc = 0;
11095
11096 xpath_lexer_string function = _lexer.contents();
11097 _lexer.next();
11098
11099 xpath_ast_node* last_arg = 0;
11100
11101 if (_lexer.current() != lex_open_brace)
11102 throw_error("Unrecognized function call");
11103 _lexer.next();
11104
11105 if (_lexer.current() != lex_close_brace)
11106 args[argc++] = parse_expression();
11107
11108 while (_lexer.current() != lex_close_brace)
11109 {
11110 if (_lexer.current() != lex_comma)
11111 throw_error("No comma between function arguments");
11112 _lexer.next();
11113
11114 xpath_ast_node* n = parse_expression();
11115
11116 if (argc < 2) args[argc] = n;
11117 else last_arg->set_next(n);
11118
11119 argc++;
11120 last_arg = n;
11121 }
11122
11123 _lexer.next();
11124
11125 return parse_function(function, argc, args);
11126 }
11127
11128 default:
11129 throw_error("Unrecognizable primary expression");
11130
11131 return 0;
11132 }
11133 }
11134
11135
11136
11137
11138 xpath_ast_node* parse_filter_expression()
11139 {
11140 xpath_ast_node* n = parse_primary_expression();
11141
11142 while (_lexer.current() == lex_open_square_brace)
11143 {
11144 _lexer.next();
11145
11146 xpath_ast_node* expr = parse_expression();
11147
11148 if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set");
11149
11150 n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default);
11151
11152 if (_lexer.current() != lex_close_square_brace)
11153 throw_error("Unmatched square brace");
11154
11155 _lexer.next();
11156 }
11157
11158 return n;
11159 }
11160
11161
11162
11163
11164
11165
11166 xpath_ast_node* parse_step(xpath_ast_node* set)
11167 {
11168 if (set && set->rettype() != xpath_type_node_set)
11169 throw_error("Step has to be applied to node set");
11170
11171 bool axis_specified = false;
11172 axis_t axis = axis_child;
11173
11174 if (_lexer.current() == lex_axis_attribute)
11175 {
11176 axis = axis_attribute;
11177 axis_specified = true;
11178
11179 _lexer.next();
11180 }
11181 else if (_lexer.current() == lex_dot)
11182 {
11183 _lexer.next();
11184
11185 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0);
11186 }
11187 else if (_lexer.current() == lex_double_dot)
11188 {
11189 _lexer.next();
11190
11191 return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0);
11192 }
11193
11194 nodetest_t nt_type = nodetest_none;
11195 xpath_lexer_string nt_name;
11196
11197 if (_lexer.current() == lex_string)
11198 {
11199
11200 nt_name = _lexer.contents();
11201 _lexer.next();
11202
11203
11204 if (_lexer.current() == lex_double_colon)
11205 {
11206
11207 if (axis_specified) throw_error("Two axis specifiers in one step");
11208
11209 axis = parse_axis_name(nt_name, axis_specified);
11210
11211 if (!axis_specified) throw_error("Unknown axis");
11212
11213
11214 _lexer.next();
11215
11216 if (_lexer.current() == lex_multiply)
11217 {
11218 nt_type = nodetest_all;
11219 nt_name = xpath_lexer_string();
11220 _lexer.next();
11221 }
11222 else if (_lexer.current() == lex_string)
11223 {
11224 nt_name = _lexer.contents();
11225 _lexer.next();
11226 }
11227 else throw_error("Unrecognized node test");
11228 }
11229
11230 if (nt_type == nodetest_none)
11231 {
11232
11233 if (_lexer.current() == lex_open_brace)
11234 {
11235 _lexer.next();
11236
11237 if (_lexer.current() == lex_close_brace)
11238 {
11239 _lexer.next();
11240
11241 nt_type = parse_node_test_type(nt_name);
11242
11243 if (nt_type == nodetest_none) throw_error("Unrecognized node type");
11244
11245 nt_name = xpath_lexer_string();
11246 }
11247 else if (nt_name == PUGIXML_TEXT("processing-instruction"))
11248 {
11249 if (_lexer.current() != lex_quoted_string)
11250 throw_error("Only literals are allowed as arguments to processing-instruction()");
11251
11252 nt_type = nodetest_pi;
11253 nt_name = _lexer.contents();
11254 _lexer.next();
11255
11256 if (_lexer.current() != lex_close_brace)
11257 throw_error("Unmatched brace near processing-instruction()");
11258 _lexer.next();
11259 }
11260 else
11261 throw_error("Unmatched brace near node type test");
11262
11263 }
11264
11265 else
11266 {
11267 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*')
11268 {
11269 nt_name.end--;
11270
11271 nt_type = nodetest_all_in_namespace;
11272 }
11273 else nt_type = nodetest_name;
11274 }
11275 }
11276 }
11277 else if (_lexer.current() == lex_multiply)
11278 {
11279 nt_type = nodetest_all;
11280 _lexer.next();
11281 }
11282 else throw_error("Unrecognized node test");
11283
11284 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name));
11285
11286 xpath_ast_node* last = 0;
11287
11288 while (_lexer.current() == lex_open_square_brace)
11289 {
11290 _lexer.next();
11291
11292 xpath_ast_node* expr = parse_expression();
11293
11294 xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default);
11295
11296 if (_lexer.current() != lex_close_square_brace)
11297 throw_error("Unmatched square brace");
11298 _lexer.next();
11299
11300 if (last) last->set_next(pred);
11301 else n->set_right(pred);
11302
11303 last = pred;
11304 }
11305
11306 return n;
11307 }
11308
11309
11310 xpath_ast_node* parse_relative_location_path(xpath_ast_node* set)
11311 {
11312 xpath_ast_node* n = parse_step(set);
11313
11314 while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
11315 {
11316 lexeme_t l = _lexer.current();
11317 _lexer.next();
11318
11319 if (l == lex_double_slash)
11320 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
11321
11322 n = parse_step(n);
11323 }
11324
11325 return n;
11326 }
11327
11328
11329
11330 xpath_ast_node* parse_location_path()
11331 {
11332 if (_lexer.current() == lex_slash)
11333 {
11334 _lexer.next();
11335
11336 xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
11337
11338
11339 lexeme_t l = _lexer.current();
11340
11341 if (l == lex_string || l == lex_axis_attribute || l == lex_dot || l == lex_double_dot || l == lex_multiply)
11342 return parse_relative_location_path(n);
11343 else
11344 return n;
11345 }
11346 else if (_lexer.current() == lex_double_slash)
11347 {
11348 _lexer.next();
11349
11350 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);
11352
11353 return parse_relative_location_path(n);
11354 }
11355
11356
11357 return parse_relative_location_path(0);
11358 }
11359
11360
11361
11362
11363
11364
11365
11366 xpath_ast_node* parse_path_or_unary_expression()
11367 {
11368
11369
11370
11371
11372
11373
11374
11375 if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
11376 _lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
11377 _lexer.current() == lex_string)
11378 {
11379 if (_lexer.current() == lex_string)
11380 {
11381
11382 const char_t* state = _lexer.state();
11383
11384 while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
11385
11386 if (*state != '(') return parse_location_path();
11387
11388
11389 if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path();
11390 }
11391
11392 xpath_ast_node* n = parse_filter_expression();
11393
11394 if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
11395 {
11396 lexeme_t l = _lexer.current();
11397 _lexer.next();
11398
11399 if (l == lex_double_slash)
11400 {
11401 if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set");
11402
11403 n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
11404 }
11405
11406
11407 return parse_relative_location_path(n);
11408 }
11409
11410 return n;
11411 }
11412 else if (_lexer.current() == lex_minus)
11413 {
11414 _lexer.next();
11415
11416
11417 xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7);
11418
11419 return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr);
11420 }
11421 else
11422 return parse_location_path();
11423 }
11424
11425 struct binary_op_t
11426 {
11427 ast_type_t asttype;
11428 xpath_value_type rettype;
11429 int precedence;
11430
11431 binary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0)
11432 {
11433 }
11434
11435 binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_)
11436 {
11437 }
11438
11439 static binary_op_t parse(xpath_lexer& lexer)
11440 {
11441 switch (lexer.current())
11442 {
11443 case lex_string:
11444 if (lexer.contents() == PUGIXML_TEXT("or"))
11445 return binary_op_t(ast_op_or, xpath_type_boolean, 1);
11446 else if (lexer.contents() == PUGIXML_TEXT("and"))
11447 return binary_op_t(ast_op_and, xpath_type_boolean, 2);
11448 else if (lexer.contents() == PUGIXML_TEXT("div"))
11449 return binary_op_t(ast_op_divide, xpath_type_number, 6);
11450 else if (lexer.contents() == PUGIXML_TEXT("mod"))
11451 return binary_op_t(ast_op_mod, xpath_type_number, 6);
11452 else
11453 return binary_op_t();
11454
11455 case lex_equal:
11456 return binary_op_t(ast_op_equal, xpath_type_boolean, 3);
11457
11458 case lex_not_equal:
11459 return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3);
11460
11461 case lex_less:
11462 return binary_op_t(ast_op_less, xpath_type_boolean, 4);
11463
11464 case lex_greater:
11465 return binary_op_t(ast_op_greater, xpath_type_boolean, 4);
11466
11467 case lex_less_or_equal:
11468 return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4);
11469
11470 case lex_greater_or_equal:
11471 return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4);
11472
11473 case lex_plus:
11474 return binary_op_t(ast_op_add, xpath_type_number, 5);
11475
11476 case lex_minus:
11477 return binary_op_t(ast_op_subtract, xpath_type_number, 5);
11478
11479 case lex_multiply:
11480 return binary_op_t(ast_op_multiply, xpath_type_number, 6);
11481
11482 case lex_union:
11483 return binary_op_t(ast_op_union, xpath_type_node_set, 7);
11484
11485 default:
11486 return binary_op_t();
11487 }
11488 }
11489 };
11490
11491 xpath_ast_node* parse_expression_rec(xpath_ast_node* lhs, int limit)
11492 {
11493 binary_op_t op = binary_op_t::parse(_lexer);
11494
11495 while (op.asttype != ast_unknown && op.precedence >= limit)
11496 {
11497 _lexer.next();
11498
11499 xpath_ast_node* rhs = parse_path_or_unary_expression();
11500
11501 binary_op_t nextop = binary_op_t::parse(_lexer);
11502
11503 while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)
11504 {
11505 rhs = parse_expression_rec(rhs, nextop.precedence);
11506
11507 nextop = binary_op_t::parse(_lexer);
11508 }
11509
11510 if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))
11511 throw_error("Union operator has to be applied to node sets");
11512
11513 lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs);
11514
11515 op = binary_op_t::parse(_lexer);
11516 }
11517
11518 return lhs;
11519 }
11520
11521
11522
11523
11524
11525
11526
11527
11528
11529
11530
11531
11532
11533
11534
11535
11536
11537
11538
11539 xpath_ast_node* parse_expression()
11540 {
11541 return parse_expression_rec(parse_path_or_unary_expression(), 0);
11542 }
11543
11544 xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result)
11545 {
11546 }
11547
11548 xpath_ast_node* parse()
11549 {
11550 xpath_ast_node* result = parse_expression();
11551
11552 if (_lexer.current() != lex_eof)
11553 {
11554
11555 throw_error("Incorrect query");
11556 }
11557
11558 return result;
11559 }
11560
11561 static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)
11562 {
11563 xpath_parser parser(query, variables, alloc, result);
11564
11565 #ifdef PUGIXML_NO_EXCEPTIONS
11566 int error = setjmp(parser._error_handler);
11567
11568 return (error == 0) ? parser.parse() : 0;
11569 #else
11570 return parser.parse();
11571 #endif
11572 }
11573 };
11574
11575 struct xpath_query_impl
11576 {
11577 static xpath_query_impl* create()
11578 {
11579 void* memory = xml_memory::allocate(sizeof(xpath_query_impl));
11580 if (!memory) return 0;
11581
11582 return new (memory) xpath_query_impl();
11583 }
11584
11585 static void destroy(xpath_query_impl* impl)
11586 {
11587
11588 impl->alloc.release();
11589
11590
11591 xml_memory::deallocate(impl);
11592 }
11593
11594 xpath_query_impl(): root(0), alloc(&block)
11595 {
11596 block.next = 0;
11597 block.capacity = sizeof(block.data);
11598 }
11599
11600 xpath_ast_node* root;
11601 xpath_allocator alloc;
11602 xpath_memory_block block;
11603 };
11604
11605 PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd)
11606 {
11607 if (!impl) return xpath_string();
11608
11609 #ifdef PUGIXML_NO_EXCEPTIONS
11610 if (setjmp(sd.error_handler)) return xpath_string();
11611 #endif
11612
11613 xpath_context c(n, 1, 1);
11614
11615 return impl->root->eval_string(c, sd.stack);
11616 }
11617
11618 PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)
11619 {
11620 if (!impl) return 0;
11621
11622 if (impl->root->rettype() != xpath_type_node_set)
11623 {
11624 #ifdef PUGIXML_NO_EXCEPTIONS
11625 return 0;
11626 #else
11627 xpath_parse_result res;
11628 res.error = "Expression does not evaluate to node set";
11629
11630 throw xpath_exception(res);
11631 #endif
11632 }
11633
11634 return impl->root;
11635 }
11636 PUGI__NS_END
11637
11638 namespace pugi
11639 {
11640 #ifndef PUGIXML_NO_EXCEPTIONS
11641 PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_)
11642 {
11643 assert(_result.error);
11644 }
11645
11646 PUGI__FN const char* xpath_exception::what() const throw()
11647 {
11648 return _result.error;
11649 }
11650
11651 PUGI__FN const xpath_parse_result& xpath_exception::result() const
11652 {
11653 return _result;
11654 }
11655 #endif
11656
11657 PUGI__FN xpath_node::xpath_node()
11658 {
11659 }
11660
11661 PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_)
11662 {
11663 }
11664
11665 PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
11666 {
11667 }
11668
11669 PUGI__FN xml_node xpath_node::node() const
11670 {
11671 return _attribute ? xml_node() : _node;
11672 }
11673
11674 PUGI__FN xml_attribute xpath_node::attribute() const
11675 {
11676 return _attribute;
11677 }
11678
11679 PUGI__FN xml_node xpath_node::parent() const
11680 {
11681 return _attribute ? _node : _node.parent();
11682 }
11683
11684 PUGI__FN static void unspecified_bool_xpath_node(xpath_node***)
11685 {
11686 }
11687
11688 PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const
11689 {
11690 return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
11691 }
11692
11693 PUGI__FN bool xpath_node::operator!() const
11694 {
11695 return !(_node || _attribute);
11696 }
11697
11698 PUGI__FN bool xpath_node::operator==(const xpath_node& n) const
11699 {
11700 return _node == n._node && _attribute == n._attribute;
11701 }
11702
11703 PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const
11704 {
11705 return _node != n._node || _attribute != n._attribute;
11706 }
11707
11708 #ifdef __BORLANDC__
11709 PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs)
11710 {
11711 return (bool)lhs && rhs;
11712 }
11713
11714 PUGI__FN bool operator||(const xpath_node& lhs, bool rhs)
11715 {
11716 return (bool)lhs || rhs;
11717 }
11718 #endif
11719
11720 PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)
11721 {
11722 assert(begin_ <= end_);
11723
11724 size_t size_ = static_cast<size_t>(end_ - begin_);
11725
11726 if (size_ <= 1)
11727 {
11728
11729 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
11730
11731
11732 if (begin_ != end_) _storage = *begin_;
11733
11734 _begin = &_storage;
11735 _end = &_storage + size_;
11736 _type = type_;
11737 }
11738 else
11739 {
11740
11741 xpath_node* storage = static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
11742
11743 if (!storage)
11744 {
11745 #ifdef PUGIXML_NO_EXCEPTIONS
11746 return;
11747 #else
11748 throw std::bad_alloc();
11749 #endif
11750 }
11751
11752 memcpy(storage, begin_, size_ * sizeof(xpath_node));
11753
11754
11755 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
11756
11757
11758 _begin = storage;
11759 _end = storage + size_;
11760 _type = type_;
11761 }
11762 }
11763
11764 #if __cplusplus >= 201103
11765 PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs)
11766 {
11767 _type = rhs._type;
11768 _storage = rhs._storage;
11769 _begin = (rhs._begin == &rhs._storage) ? &_storage : rhs._begin;
11770 _end = _begin + (rhs._end - rhs._begin);
11771
11772 rhs._type = type_unsorted;
11773 rhs._begin = &rhs._storage;
11774 rhs._end = rhs._begin;
11775 }
11776 #endif
11777
11778 PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage)
11779 {
11780 }
11781
11782 PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(&_storage), _end(&_storage)
11783 {
11784 _assign(begin_, end_, type_);
11785 }
11786
11787 PUGI__FN xpath_node_set::~xpath_node_set()
11788 {
11789 if (_begin != &_storage)
11790 impl::xml_memory::deallocate(_begin);
11791 }
11792
11793 PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage)
11794 {
11795 _assign(ns._begin, ns._end, ns._type);
11796 }
11797
11798 PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
11799 {
11800 if (this == &ns) return *this;
11801
11802 _assign(ns._begin, ns._end, ns._type);
11803
11804 return *this;
11805 }
11806
11807 #if __cplusplus >= 201103
11808 PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs): _type(type_unsorted), _begin(&_storage), _end(&_storage)
11809 {
11810 _move(rhs);
11811 }
11812
11813 PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs)
11814 {
11815 if (this == &rhs) return *this;
11816
11817 if (_begin != &_storage)
11818 impl::xml_memory::deallocate(_begin);
11819
11820 _move(rhs);
11821
11822 return *this;
11823 }
11824 #endif
11825
11826 PUGI__FN xpath_node_set::type_t xpath_node_set::type() const
11827 {
11828 return _type;
11829 }
11830
11831 PUGI__FN size_t xpath_node_set::size() const
11832 {
11833 return _end - _begin;
11834 }
11835
11836 PUGI__FN bool xpath_node_set::empty() const
11837 {
11838 return _begin == _end;
11839 }
11840
11841 PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const
11842 {
11843 assert(index < size());
11844 return _begin[index];
11845 }
11846
11847 PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const
11848 {
11849 return _begin;
11850 }
11851
11852 PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const
11853 {
11854 return _end;
11855 }
11856
11857 PUGI__FN void xpath_node_set::sort(bool reverse)
11858 {
11859 _type = impl::xpath_sort(_begin, _end, _type, reverse);
11860 }
11861
11862 PUGI__FN xpath_node xpath_node_set::first() const
11863 {
11864 return impl::xpath_first(_begin, _end, _type);
11865 }
11866
11867 PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
11868 {
11869 }
11870
11871 PUGI__FN xpath_parse_result::operator bool() const
11872 {
11873 return error == 0;
11874 }
11875
11876 PUGI__FN const char* xpath_parse_result::description() const
11877 {
11878 return error ? error : "No error";
11879 }
11880
11881 PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0)
11882 {
11883 }
11884
11885 PUGI__FN const char_t* xpath_variable::name() const
11886 {
11887 switch (_type)
11888 {
11889 case xpath_type_node_set:
11890 return static_cast<const impl::xpath_variable_node_set*>(this)->name;
11891
11892 case xpath_type_number:
11893 return static_cast<const impl::xpath_variable_number*>(this)->name;
11894
11895 case xpath_type_string:
11896 return static_cast<const impl::xpath_variable_string*>(this)->name;
11897
11898 case xpath_type_boolean:
11899 return static_cast<const impl::xpath_variable_boolean*>(this)->name;
11900
11901 default:
11902 assert(!"Invalid variable type");
11903 return 0;
11904 }
11905 }
11906
11907 PUGI__FN xpath_value_type xpath_variable::type() const
11908 {
11909 return _type;
11910 }
11911
11912 PUGI__FN bool xpath_variable::get_boolean() const
11913 {
11914 return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
11915 }
11916
11917 PUGI__FN double xpath_variable::get_number() const
11918 {
11919 return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();
11920 }
11921
11922 PUGI__FN const char_t* xpath_variable::get_string() const
11923 {
11924 const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0;
11925 return value ? value : PUGIXML_TEXT("");
11926 }
11927
11928 PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const
11929 {
11930 return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
11931 }
11932
11933 PUGI__FN bool xpath_variable::set(bool value)
11934 {
11935 if (_type != xpath_type_boolean) return false;
11936
11937 static_cast<impl::xpath_variable_boolean*>(this)->value = value;
11938 return true;
11939 }
11940
11941 PUGI__FN bool xpath_variable::set(double value)
11942 {
11943 if (_type != xpath_type_number) return false;
11944
11945 static_cast<impl::xpath_variable_number*>(this)->value = value;
11946 return true;
11947 }
11948
11949 PUGI__FN bool xpath_variable::set(const char_t* value)
11950 {
11951 if (_type != xpath_type_string) return false;
11952
11953 impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);
11954
11955
11956 size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
11957
11958 char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));
11959 if (!copy) return false;
11960
11961 memcpy(copy, value, size);
11962
11963
11964 if (var->value) impl::xml_memory::deallocate(var->value);
11965 var->value = copy;
11966
11967 return true;
11968 }
11969
11970 PUGI__FN bool xpath_variable::set(const xpath_node_set& value)
11971 {
11972 if (_type != xpath_type_node_set) return false;
11973
11974 static_cast<impl::xpath_variable_node_set*>(this)->value = value;
11975 return true;
11976 }
11977
11978 PUGI__FN xpath_variable_set::xpath_variable_set()
11979 {
11980 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
11981 _data[i] = 0;
11982 }
11983
11984 PUGI__FN xpath_variable_set::~xpath_variable_set()
11985 {
11986 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
11987 _destroy(_data[i]);
11988 }
11989
11990 PUGI__FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs)
11991 {
11992 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
11993 _data[i] = 0;
11994
11995 _assign(rhs);
11996 }
11997
11998 PUGI__FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs)
11999 {
12000 if (this == &rhs) return *this;
12001
12002 _assign(rhs);
12003
12004 return *this;
12005 }
12006
12007 #if __cplusplus >= 201103
12008 PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs)
12009 {
12010 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12011 {
12012 _data[i] = rhs._data[i];
12013 rhs._data[i] = 0;
12014 }
12015 }
12016
12017 PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs)
12018 {
12019 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12020 {
12021 _destroy(_data[i]);
12022
12023 _data[i] = rhs._data[i];
12024 rhs._data[i] = 0;
12025 }
12026
12027 return *this;
12028 }
12029 #endif
12030
12031 PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs)
12032 {
12033 xpath_variable_set temp;
12034
12035 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12036 if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))
12037 return;
12038
12039 _swap(temp);
12040 }
12041
12042 PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs)
12043 {
12044 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12045 {
12046 xpath_variable* chain = _data[i];
12047
12048 _data[i] = rhs._data[i];
12049 rhs._data[i] = chain;
12050 }
12051 }
12052
12053 PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const
12054 {
12055 const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
12056 size_t hash = impl::hash_string(name) % hash_size;
12057
12058
12059 for (xpath_variable* var = _data[hash]; var; var = var->_next)
12060 if (impl::strequal(var->name(), name))
12061 return var;
12062
12063 return 0;
12064 }
12065
12066 PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)
12067 {
12068 xpath_variable* last = 0;
12069
12070 while (var)
12071 {
12072
12073 xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
12074 if (!nvar) return false;
12075
12076
12077 if (last)
12078 last->_next = nvar;
12079 else
12080 *out_result = nvar;
12081
12082 last = nvar;
12083
12084
12085 if (!impl::copy_xpath_variable(nvar, var)) return false;
12086
12087 var = var->_next;
12088 }
12089
12090 return true;
12091 }
12092
12093 PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var)
12094 {
12095 while (var)
12096 {
12097 xpath_variable* next = var->_next;
12098
12099 impl::delete_xpath_variable(var->_type, var);
12100
12101 var = next;
12102 }
12103 }
12104
12105 PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
12106 {
12107 const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
12108 size_t hash = impl::hash_string(name) % hash_size;
12109
12110
12111 for (xpath_variable* var = _data[hash]; var; var = var->_next)
12112 if (impl::strequal(var->name(), name))
12113 return var->type() == type ? var : 0;
12114
12115
12116 xpath_variable* result = impl::new_xpath_variable(type, name);
12117
12118 if (result)
12119 {
12120 result->_next = _data[hash];
12121
12122 _data[hash] = result;
12123 }
12124
12125 return result;
12126 }
12127
12128 PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value)
12129 {
12130 xpath_variable* var = add(name, xpath_type_boolean);
12131 return var ? var->set(value) : false;
12132 }
12133
12134 PUGI__FN bool xpath_variable_set::set(const char_t* name, double value)
12135 {
12136 xpath_variable* var = add(name, xpath_type_number);
12137 return var ? var->set(value) : false;
12138 }
12139
12140 PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value)
12141 {
12142 xpath_variable* var = add(name, xpath_type_string);
12143 return var ? var->set(value) : false;
12144 }
12145
12146 PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
12147 {
12148 xpath_variable* var = add(name, xpath_type_node_set);
12149 return var ? var->set(value) : false;
12150 }
12151
12152 PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name)
12153 {
12154 return _find(name);
12155 }
12156
12157 PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
12158 {
12159 return _find(name);
12160 }
12161
12162 PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
12163 {
12164 impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
12165
12166 if (!qimpl)
12167 {
12168 #ifdef PUGIXML_NO_EXCEPTIONS
12169 _result.error = "Out of memory";
12170 #else
12171 throw std::bad_alloc();
12172 #endif
12173 }
12174 else
12175 {
12176 using impl::auto_deleter;
12177 auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);
12178
12179 qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
12180
12181 if (qimpl->root)
12182 {
12183 qimpl->root->optimize(&qimpl->alloc);
12184
12185 _impl = impl.release();
12186 _result.error = 0;
12187 }
12188 }
12189 }
12190
12191 PUGI__FN xpath_query::xpath_query(): _impl(0)
12192 {
12193 }
12194
12195 PUGI__FN xpath_query::~xpath_query()
12196 {
12197 if (_impl)
12198 impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
12199 }
12200
12201 #if __cplusplus >= 201103
12202 PUGI__FN xpath_query::xpath_query(xpath_query&& rhs)
12203 {
12204 _impl = rhs._impl;
12205 _result = rhs._result;
12206 rhs._impl = 0;
12207 rhs._result = xpath_parse_result();
12208 }
12209
12210 PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs)
12211 {
12212 if (this == &rhs) return *this;
12213
12214 if (_impl)
12215 impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
12216
12217 _impl = rhs._impl;
12218 _result = rhs._result;
12219 rhs._impl = 0;
12220 rhs._result = xpath_parse_result();
12221
12222 return *this;
12223 }
12224 #endif
12225
12226 PUGI__FN xpath_value_type xpath_query::return_type() const
12227 {
12228 if (!_impl) return xpath_type_none;
12229
12230 return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();
12231 }
12232
12233 PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const
12234 {
12235 if (!_impl) return false;
12236
12237 impl::xpath_context c(n, 1, 1);
12238 impl::xpath_stack_data sd;
12239
12240 #ifdef PUGIXML_NO_EXCEPTIONS
12241 if (setjmp(sd.error_handler)) return false;
12242 #endif
12243
12244 return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
12245 }
12246
12247 PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
12248 {
12249 if (!_impl) return impl::gen_nan();
12250
12251 impl::xpath_context c(n, 1, 1);
12252 impl::xpath_stack_data sd;
12253
12254 #ifdef PUGIXML_NO_EXCEPTIONS
12255 if (setjmp(sd.error_handler)) return impl::gen_nan();
12256 #endif
12257
12258 return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
12259 }
12260
12261 #ifndef PUGIXML_NO_STL
12262 PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const
12263 {
12264 impl::xpath_stack_data sd;
12265
12266 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd);
12267
12268 return string_t(r.c_str(), r.length());
12269 }
12270 #endif
12271
12272 PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
12273 {
12274 impl::xpath_stack_data sd;
12275
12276 impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd);
12277
12278 size_t full_size = r.length() + 1;
12279
12280 if (capacity > 0)
12281 {
12282 size_t size = (full_size < capacity) ? full_size : capacity;
12283 assert(size > 0);
12284
12285 memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
12286 buffer[size - 1] = 0;
12287 }
12288
12289 return full_size;
12290 }
12291
12292 PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const
12293 {
12294 impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
12295 if (!root) return xpath_node_set();
12296
12297 impl::xpath_context c(n, 1, 1);
12298 impl::xpath_stack_data sd;
12299
12300 #ifdef PUGIXML_NO_EXCEPTIONS
12301 if (setjmp(sd.error_handler)) return xpath_node_set();
12302 #endif
12303
12304 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
12305
12306 return xpath_node_set(r.begin(), r.end(), r.type());
12307 }
12308
12309 PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const
12310 {
12311 impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
12312 if (!root) return xpath_node();
12313
12314 impl::xpath_context c(n, 1, 1);
12315 impl::xpath_stack_data sd;
12316
12317 #ifdef PUGIXML_NO_EXCEPTIONS
12318 if (setjmp(sd.error_handler)) return xpath_node();
12319 #endif
12320
12321 impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);
12322
12323 return r.first();
12324 }
12325
12326 PUGI__FN const xpath_parse_result& xpath_query::result() const
12327 {
12328 return _result;
12329 }
12330
12331 PUGI__FN static void unspecified_bool_xpath_query(xpath_query***)
12332 {
12333 }
12334
12335 PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
12336 {
12337 return _impl ? unspecified_bool_xpath_query : 0;
12338 }
12339
12340 PUGI__FN bool xpath_query::operator!() const
12341 {
12342 return !_impl;
12343 }
12344
12345 PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const
12346 {
12347 xpath_query q(query, variables);
12348 return select_node(q);
12349 }
12350
12351 PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const
12352 {
12353 return query.evaluate_node(*this);
12354 }
12355
12356 PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const
12357 {
12358 xpath_query q(query, variables);
12359 return select_nodes(q);
12360 }
12361
12362 PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const
12363 {
12364 return query.evaluate_node_set(*this);
12365 }
12366
12367 PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const
12368 {
12369 xpath_query q(query, variables);
12370 return select_single_node(q);
12371 }
12372
12373 PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const
12374 {
12375 return query.evaluate_node(*this);
12376 }
12377 }
12378
12379 #endif
12380
12381 #ifdef __BORLANDC__
12382 # pragma option pop
12383 #endif
12384
12385
12386
12387 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
12388 # pragma warning(pop)
12389 #endif
12390
12391
12392 #undef PUGI__NO_INLINE
12393 #undef PUGI__UNLIKELY
12394 #undef PUGI__STATIC_ASSERT
12395 #undef PUGI__DMC_VOLATILE
12396 #undef PUGI__MSVC_CRT_VERSION
12397 #undef PUGI__NS_BEGIN
12398 #undef PUGI__NS_END
12399 #undef PUGI__FN
12400 #undef PUGI__FN_NO_INLINE
12401 #undef PUGI__GETPAGE_IMPL
12402 #undef PUGI__GETPAGE
12403 #undef PUGI__NODETYPE
12404 #undef PUGI__IS_CHARTYPE_IMPL
12405 #undef PUGI__IS_CHARTYPE
12406 #undef PUGI__IS_CHARTYPEX
12407 #undef PUGI__ENDSWITH
12408 #undef PUGI__SKIPWS
12409 #undef PUGI__OPTSET
12410 #undef PUGI__PUSHNODE
12411 #undef PUGI__POPNODE
12412 #undef PUGI__SCANFOR
12413 #undef PUGI__SCANWHILE
12414 #undef PUGI__SCANWHILE_UNROLL
12415 #undef PUGI__ENDSEG
12416 #undef PUGI__THROW_ERROR
12417 #undef PUGI__CHECK_ERROR
12418
12419 #endif
12420