pugixml.cpp
Go to the documentation of this file.
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 // For placement new
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 // Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug
00075 #       pragma diag_suppress=178 // function was declared but never referenced
00076 #       pragma diag_suppress=237 // controlling expression is constant
00077 #endif
00078 
00079 // Inlining controls
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 // Branch weight controls
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 // Simple static assertion
00096 #define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
00097 
00098 // Digital Mars C++ bug workaround for passing char loaded from memory via stack
00099 #ifdef __DMC__
00100 #       define PUGI__DMC_VOLATILE volatile
00101 #else
00102 #       define PUGI__DMC_VOLATILE
00103 #endif
00104 
00105 // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all)
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 // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features
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 // uintptr_t
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 // Memory allocation
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         // Global allocation functions are stored in class statics so that in header mode linker deduplicates them
00170         // Without a template<> we'll get multiple definitions of the same static
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 // String utilities
00178 PUGI__NS_BEGIN
00179         // Get string length
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         // Compare two strings
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         // Compare lhs with [rhs_begin, rhs_end)
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         // Get length of wide string, even if CRT lacks wide character support
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 // auto_ptr-like object for exception recovery
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                                 // hash collision, quadratic probing
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                                 // hash collision, quadratic probing
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                         // MurmurHash3 32-bit finalizer
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         // extra metadata bits
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         // combined masks for string uniqueness
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; // offset from page->data
00476                 uint16_t full_size; // 0 if string occupies whole page
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                         // allocate block with some alignment, leaving memory for worst-case padding
00493                         void* memory = xml_memory::allocate(size + xml_memory_page_alignment);
00494                         if (!memory) return 0;
00495 
00496                         // align to next page boundary (note: this guarantees at least 1 usable byte before the page)
00497                         char* page_memory = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1));
00498 
00499                         // prepare page structure
00500                         xml_memory_page* page = xml_memory_page::construct(page_memory);
00501                         assert(page);
00502 
00503                         page->allocator = _root->allocator;
00504 
00505                         // record the offset for freeing the memory block
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                         // adjust for marker
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                                 // insert new marker
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                                 // since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block
00553                                 // this will make sure deallocate_memory correctly tracks the size
00554                                 out_page->freed_size += sizeof(uint32_t);
00555 
00556                                 return marker + 1;
00557                         }
00558                         else
00559                         {
00560                                 // roll back uint32_t part
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                                         // top page freed, just reset sizes
00590                                         page->busy_size = 0;
00591                                         page->freed_size = 0;
00592 
00593                                 #ifdef PUGIXML_COMPACT
00594                                         // reset compact state to maximize efficiency
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                                         // remove from the list
00608                                         page->prev->next = page->next;
00609                                         page->next->prev = page->prev;
00610 
00611                                         // deallocate
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                         // allocate memory for string and header block
00624                         size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
00625                         
00626                         // round size up to block alignment boundary
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                         // setup header
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                         // full_size == 0 for large strings that occupy the whole page
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                         // round-trip through void* to avoid 'cast increases required alignment of target type' warning
00647                         // header is guaranteed a pointer-sized alignment, which should be enough for char_t
00648                         return static_cast<char_t*>(static_cast<void*>(header + 1));
00649                 }
00650 
00651                 void deallocate_string(char_t* string)
00652                 {
00653                         // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
00654                         // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string
00655 
00656                         // get header
00657                         xml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1;
00658                         assert(header);
00659 
00660                         // deallocate
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                         // if full_size == 0 then this string occupies the whole page
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                         // insert page at the end of linked list
00701                         page->prev = _root;
00702                         _root->next = page;
00703                         _root = page;
00704 
00705                         _busy_size = size;
00706                 }
00707                 else
00708                 {
00709                         // insert page before the end of linked list, so that it is deleted as soon as possible
00710                         // the last page is not deleted even if it's empty (see deallocate_memory)
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                         // round-trip through void* to silence 'cast increases required alignment of target type' warnings
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                                 // value is guaranteed to be compact-aligned; 'this' is not
00808                                 // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
00809                                 // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
00810                                 // compensate for arithmetic shift rounding for negative values
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                                 // value is guaranteed to be compact-aligned; 'this' is not
00870                                 // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
00871                                 // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
00872                                 // compensate for arithmetic shift behavior for negative values
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                                         // round-trip through void* to silence 'cast increases required alignment of target type' warnings
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                                         // round-trip through void* to silence 'cast increases required alignment of target type' warnings
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 // Low-level DOM operations
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 // Helper classes for code generation
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 // Unicode utilities
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                         // U+0000..U+007F
01436                         if (ch < 0x80) return result + 1;
01437                         // U+0080..U+07FF
01438                         else if (ch < 0x800) return result + 2;
01439                         // U+0800..U+FFFF
01440                         else return result + 3;
01441                 }
01442 
01443                 static value_type high(value_type result, uint32_t)
01444                 {
01445                         // U+10000..U+10FFFF
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                         // U+0000..U+007F
01457                         if (ch < 0x80)
01458                         {
01459                                 *result = static_cast<uint8_t>(ch);
01460                                 return result + 1;
01461                         }
01462                         // U+0080..U+07FF
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                         // U+0800..U+FFFF
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                         // U+10000..U+10FFFF
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                                 // 0xxxxxxx -> U+0000..U+007F
01613                                 if (lead < 0x80)
01614                                 {
01615                                         result = Traits::low(result, lead);
01616                                         data += 1;
01617                                         size -= 1;
01618 
01619                                         // process aligned single-byte (ascii) blocks
01620                                         if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
01621                                         {
01622                                                 // round-trip through void* to silence 'cast increases required alignment of target type' warnings
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                                 // 110xxxxx -> U+0080..U+07FF
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                                 // 1110xxxx -> U+0800-U+FFFF
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                                 // 11110xxx -> U+10000..U+10FFFF
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                                 // 10xxxxxx or 11111xxx -> invalid
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                                 // U+0000..U+D7FF
01678                                 if (lead < 0xD800)
01679                                 {
01680                                         result = Traits::low(result, lead);
01681                                         data += 1;
01682                                         size -= 1;
01683                                 }
01684                                 // U+E000..U+FFFF
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                                 // surrogate pair lead
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                                 // U+0000..U+FFFF
01730                                 if (lead < 0x10000)
01731                                 {
01732                                         result = Traits::low(result, lead);
01733                                         data += 1;
01734                                         size -= 1;
01735                                 }
01736                                 // U+10000..U+10FFFF
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,    // \0, &, \r, <
01812                 ct_parse_attr = 2,              // \0, &, \r, ', "
01813                 ct_parse_attr_ws = 4,   // \0, &, \r, ', ", \n, tab
01814                 ct_space = 8,                   // \r, \n, space, tab
01815                 ct_parse_cdata = 16,    // \0, ], >, \r
01816                 ct_parse_comment = 32,  // \0, -, >, \r
01817                 ct_symbol = 64,                 // Any symbol > 127, a-z, A-Z, 0-9, _, :, -, .
01818                 ct_start_symbol = 128   // Any symbol > 127, a-z, A-Z, _, :
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,   // 0-15
01824                 0,   0,   0,   0,   0,   0,   0,   0,      0,   0,   0,   0,   0,   0,   0,   0,   // 16-31
01825                 8,   0,   6,   0,   0,   0,   7,   6,      0,   0,   0,   0,   0,   96,  64,  0,   // 32-47
01826                 64,  64,  64,  64,  64,  64,  64,  64,     64,  64,  192, 0,   1,   0,   48,  0,   // 48-63
01827                 0,   192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 64-79
01828                 192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 0,   0,   16,  0,   192, // 80-95
01829                 0,   192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 96-111
01830                 192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 0, 0, 0, 0, 0,           // 112-127
01831 
01832                 192, 192, 192, 192, 192, 192, 192, 192,    192, 192, 192, 192, 192, 192, 192, 192, // 128+
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,   // Any symbol >= 0 and < 32 (except \t, \r, \n), &, <, >
01845                 ctx_special_attr = 2,     // Any symbol >= 0 and < 32 (except \t), &, <, >, "
01846                 ctx_start_symbol = 4,     // Any symbol > 127, a-z, A-Z, _
01847                 ctx_digit = 8,                    // 0-9
01848                 ctx_symbol = 16                   // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
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,     // 0-15
01854                 3,  3,  3,  3,  3,  3,  3,  3,     3,  3,  3,  3,  3,  3,  3,  3,     // 16-31
01855                 0,  0,  2,  0,  0,  0,  3,  0,     0,  0,  0,  0,  0, 16, 16,  0,     // 32-47
01856                 24, 24, 24, 24, 24, 24, 24, 24,    24, 24, 0,  0,  3,  0,  3,  0,     // 48-63
01857 
01858                 0,  20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 64-79
01859                 20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 0,  0,  0,  0,  20,    // 80-95
01860                 0,  20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 96-111
01861                 20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 0,  0,  0,  0,  0,     // 112-127
01862 
01863                 20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20,    // 128+
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                 // look for BOM in first few bytes
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                 // look for <, <? or <?xm in various encodings
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                 // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)
01916                 if (d0 == 0 && d1 == 0x3c) return encoding_utf16_be;
01917                 if (d0 == 0x3c && d1 == 0) return encoding_utf16_le;
01918 
01919                 // no known BOM detected, assume utf8
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                 // replace wchar encoding with utf implementation
01926                 if (encoding == encoding_wchar) return get_wchar_encoding();
01927 
01928                 // replace utf16 encoding with utf16 with specific endianness
01929                 if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
01930 
01931                 // replace utf32 encoding with utf32 with specific endianness
01932                 if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
01933 
01934                 // only do autodetection if no explicit encoding is requested
01935                 if (encoding != encoding_auto) return encoding;
01936 
01937                 // skip encoding autodetection if input buffer is too small
01938                 if (size < 4) return encoding_utf8;
01939 
01940                 // try to guess encoding (based on XML specification, Appendix F.1)
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                 // first pass: get length in wchar_t units
02018                 size_t length = D::process(data, data_length, 0, wchar_counter());
02019 
02020                 // allocate buffer of suitable length
02021                 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
02022                 if (!buffer) return false;
02023 
02024                 // second pass: convert utf16 input to wchar_t
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                 // get native encoding
02040                 xml_encoding wchar_encoding = get_wchar_encoding();
02041 
02042                 // fast path: no conversion required
02043                 if (encoding == wchar_encoding)
02044                         return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
02045 
02046                 // only endian-swapping is required
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                 // source encoding is utf8
02051                 if (encoding == encoding_utf8)
02052                         return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder());
02053 
02054                 // source encoding is utf16
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                 // source encoding is utf32
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                 // source encoding is latin1
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                 // first pass: get length in utf8 units
02088                 size_t length = D::process(data, data_length, 0, utf8_counter());
02089 
02090                 // allocate buffer of suitable length
02091                 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
02092                 if (!buffer) return false;
02093 
02094                 // second pass: convert utf16 input to utf8
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                 // get size of prefix that does not need utf8 conversion
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                 // if no conversion is needed, just return the original buffer
02129                 if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
02130 
02131                 // first pass: get length in utf8 units
02132                 size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter());
02133 
02134                 // allocate buffer of suitable length
02135                 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
02136                 if (!buffer) return false;
02137 
02138                 // second pass: convert latin1 input to utf8
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                 // fast path: no conversion required
02156                 if (encoding == encoding_utf8)
02157                         return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
02158 
02159                 // source encoding is utf16
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                 // source encoding is utf32
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                 // source encoding is latin1
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                 // get length in utf8 characters
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                 // convert to utf8
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                 // first pass: get length in utf8 characters
02209                 size_t size = as_utf8_begin(str, length);
02210 
02211                 // allocate resulting string
02212                 std::string result;
02213                 result.resize(size);
02214 
02215                 // second pass: convert to utf8
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                 // first pass: get length in wchar_t units
02226                 size_t length = utf8_decoder::process(data, size, 0, wchar_counter());
02227 
02228                 // allocate resulting string
02229                 std::basic_string<wchar_t> result;
02230                 result.resize(length);
02231 
02232                 // second pass: convert to wchar_t
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                 // never reuse shared memory
02250                 if (header & xml_memory_page_contents_shared_mask) return false;
02251 
02252                 size_t target_length = strlength(target);
02253 
02254                 // always reuse document buffer memory if possible
02255                 if ((header & header_mask) == 0) return target_length >= length;
02256 
02257                 // reuse heap memory if waste is not too great
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                         // empty string and null pointer are equivalent, so just deallocate old memory
02269                         xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
02270 
02271                         if (header & header_mask) alloc->deallocate_string(dest);
02272                         
02273                         // mark the string as not allocated
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                         // we can reuse old buffer, so just copy the new data (including zero terminator)
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                         // allocate new buffer
02294                         char_t* buf = alloc->allocate_string(source_length + 1);
02295                         if (!buf) return false;
02296 
02297                         // copy the string (including zero terminator)
02298                         memcpy(buf, source, source_length * sizeof(char_t));
02299                         buf[source_length] = 0;
02300 
02301                         // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
02302                         if (header & header_mask) alloc->deallocate_string(dest);
02303                         
02304                         // the string is now allocated, so set the flag
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                 // Push new gap, move s count bytes further (skipping the gap).
02322                 // Collapse previous gap.
02323                 void push(char_t*& s, size_t count)
02324                 {
02325                         if (end) // there was a gap already; collapse it
02326                         {
02327                                 // Move [old_gap_end, new_gap_start) to [old_gap_start, ...)
02328                                 assert(s >= end);
02329                                 memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
02330                         }
02331                                 
02332                         s += count; // end of current gap
02333                                 
02334                         // "merge" two gaps
02335                         end = s;
02336                         size += count;
02337                 }
02338                         
02339                 // Collapse all gaps, return past-the-end pointer
02340                 char_t* flush(char_t* s)
02341                 {
02342                         if (end)
02343                         {
02344                                 // Move [old_gap_end, current_pos) to [old_gap_start, ...)
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') // &#x... (hex code)
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 // cancel
02381                                                         return stre;
02382 
02383                                                 ch = *++stre;
02384                                         }
02385                                         
02386                                         ++stre;
02387                                 }
02388                                 else    // &#... (dec code)
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 // cancel
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':       // &a
02420                         {
02421                                 ++stre;
02422 
02423                                 if (*stre == 'm') // &am
02424                                 {
02425                                         if (*++stre == 'p' && *++stre == ';') // &amp;
02426                                         {
02427                                                 *s++ = '&';
02428                                                 ++stre;
02429                                                         
02430                                                 g.push(s, stre - s);
02431                                                 return stre;
02432                                         }
02433                                 }
02434                                 else if (*stre == 'p') // &ap
02435                                 {
02436                                         if (*++stre == 'o' && *++stre == 's' && *++stre == ';') // &apos;
02437                                         {
02438                                                 *s++ = '\'';
02439                                                 ++stre;
02440 
02441                                                 g.push(s, stre - s);
02442                                                 return stre;
02443                                         }
02444                                 }
02445                                 break;
02446                         }
02447 
02448                         case 'g': // &g
02449                         {
02450                                 if (*++stre == 't' && *++stre == ';') // &gt;
02451                                 {
02452                                         *s++ = '>';
02453                                         ++stre;
02454                                         
02455                                         g.push(s, stre - s);
02456                                         return stre;
02457                                 }
02458                                 break;
02459                         }
02460 
02461                         case 'l': // &l
02462                         {
02463                                 if (*++stre == 't' && *++stre == ';') // &lt;
02464                                 {
02465                                         *s++ = '<';
02466                                         ++stre;
02467                                                 
02468                                         g.push(s, stre - s);
02469                                         return stre;
02470                                 }
02471                                 break;
02472                         }
02473 
02474                         case 'q': // &q
02475                         {
02476                                 if (*++stre == 'u' && *++stre == 'o' && *++stre == 't' && *++stre == ';') // &quot;
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         // Parser utilities
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') // Either a single 0x0d or 0x0d 0x0a pair
02516                         {
02517                                 *s++ = '\n'; // replace first one with 0x0a
02518                                 
02519                                 if (*s == '\n') g.push(s, 1);
02520                         }
02521                         else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here
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') // Either a single 0x0d or 0x0d 0x0a pair
02544                         {
02545                                 *s++ = '\n'; // replace first one with 0x0a
02546                                 
02547                                 if (*s == '\n') g.push(s, 1);
02548                         }
02549                         else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here
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 == '<') // PCDATA ends here
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') // Either a single 0x0d or 0x0d 0x0a pair
02590                                 {
02591                                         *s++ = '\n'; // replace first one with 0x0a
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)) // get bitmask for flags (eol escapes trim)
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; // should not get here
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                         // trim leading whitespaces
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) // get bitmask for flags (wconv wnorm eol escapes)
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; // should not get here
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                 // DOCTYPE consists of nested sections of the following possible types:
02837                 // <!-- ... -->, <? ... ?>, "...", '...'
02838                 // <![...]]>
02839                 // <!...>
02840                 // First group can not contain nested groups
02841                 // Second group can contain nested groups of the same type
02842                 // Third group can contain all other groups
02843                 char_t* parse_doctype_primitive(char_t* s)
02844                 {
02845                         if (*s == '"' || *s == '\'')
02846                         {
02847                                 // quoted string
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] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
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] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
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                                         // nested ignore section
02888                                         s += 3;
02889                                         depth++;
02890                                 }
02891                                 else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
02892                                 {
02893                                         // ignore section end
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                                                 // ignore
02921                                                 s = parse_doctype_ignore(s);
02922                                                 if (!s) return s;
02923                                         }
02924                                         else
02925                                         {
02926                                                 // some control group
02927                                                 s += 2;
02928                                                 depth++;
02929                                         }
02930                                 }
02931                                 else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
02932                                 {
02933                                         // unknown tag (forbidden), or some primitive group
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                         // parse node contents, starting with exclamation mark
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); // Append a new node on the tree.
02969                                                 cursor->value = s; // Save the offset.
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                                                 // Scan for terminating '-->'.
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; // Zero-terminate this segment at the first terminating '-'.
02986 
02987                                                 s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
02988                                         }
02989                                 }
02990                                 else PUGI__THROW_ERROR(status_bad_comment, s);
02991                         }
02992                         else if (*s == '[')
02993                         {
02994                                 // '<![CDATA[...'
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); // Append a new node on the tree.
03002                                                 cursor->value = s; // Save the offset.
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                                                         // Scan for terminating ']]>'.
03013                                                         PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
03014                                                         PUGI__CHECK_ERROR(status_bad_cdata, s);
03015 
03016                                                         *s++ = 0; // Zero-terminate this segment.
03017                                                 }
03018                                         }
03019                                         else // Flagged for discard, but we still have to scan for the terminator.
03020                                         {
03021                                                 // Scan for terminating ']]>'.
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); // Step over the last ']>'.
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                         // load into registers
03065                         xml_node_struct* cursor = ref_cursor;
03066                         char_t ch = 0;
03067 
03068                         // parse node contents, starting with question mark
03069                         ++s;
03070 
03071                         // read PI target
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                         // determine node type; stricmp / strcasecmp is not portable
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                                         // disallow non top-level declarations
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                                 // parse value/attributes
03101                                 if (ch == '?')
03102                                 {
03103                                         // empty node
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                                         // scan for tag end
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                                                 // replace ending ? with / so that 'element' terminates properly
03122                                                 *s = '/';
03123 
03124                                                 // we exit from this function with cursor at node_declaration, which is a signal to parse() to go to LOC_ATTRIBUTES
03125                                                 s = value;
03126                                         }
03127                                         else
03128                                         {
03129                                                 // store value and step over >
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                                 // scan for tag end
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                         // store from registers
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); // Append a new node to the tree.
03175 
03176                                                 cursor->name = s;
03177 
03178                                                 PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
03179                                                 PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
03180 
03181                                                 if (ch == '>')
03182                                                 {
03183                                                         // end of tag
03184                                                 }
03185                                                 else if (PUGI__IS_CHARTYPE(ch, ct_space))
03186                                                 {
03187                                                 LOC_ATTRIBUTES:
03188                                                         while (true)
03189                                                         {
03190                                                                 PUGI__SKIPWS(); // Eat any whitespace.
03191                                                 
03192                                                                 if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
03193                                                                 {
03194                                                                         xml_attribute_struct* a = append_new_attribute(cursor, alloc); // Make space for this attribute.
03195                                                                         if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
03196 
03197                                                                         a->name = s; // Save the offset.
03198 
03199                                                                         PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
03200                                                                         PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
03201 
03202                                                                         if (PUGI__IS_CHARTYPE(ch, ct_space))
03203                                                                         {
03204                                                                                 PUGI__SKIPWS(); // Eat any whitespace.
03205 
03206                                                                                 ch = *s;
03207                                                                                 ++s;
03208                                                                         }
03209                                                                         
03210                                                                         if (ch == '=') // '<... #=...'
03211                                                                         {
03212                                                                                 PUGI__SKIPWS(); // Eat any whitespace.
03213 
03214                                                                                 if (*s == '"' || *s == '\'') // '<... #="...'
03215                                                                                 {
03216                                                                                         ch = *s; // Save quote char to avoid breaking on "''" -or- '""'.
03217                                                                                         ++s; // Step over the quote.
03218                                                                                         a->value = s; // Save the offset.
03219 
03220                                                                                         s = strconv_attribute(s, ch);
03221                                                                                 
03222                                                                                         if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
03223 
03224                                                                                         // After this line the loop continues from the start;
03225                                                                                         // Whitespaces, / and > are ok, symbols and EOF are wrong,
03226                                                                                         // everything else will be detected
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(); // Pop.
03270 
03271                                                         s += (*s == '>');
03272                                                 }
03273                                                 else if (ch == 0)
03274                                                 {
03275                                                         // we stepped over null terminator, backtrack & handle closing tag
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(); // Pop.
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; // Save this offset while searching for a terminator.
03333 
03334                                         PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
03335 
03336                                         if (*s == '<' || !*s)
03337                                         {
03338                                                 // We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one
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); // Append a new node on the tree.
03357                                                 cursor->value = s; // Save the offset.
03358 
03359                                                 s = strconv_pcdata(s);
03360                                                                 
03361                                                 PUGI__POPNODE(); // Pop since this is a standalone.
03362                                                 
03363                                                 if (!*s) break;
03364                                         }
03365                                         else
03366                                         {
03367                                                 PUGI__SCANFOR(*s == '<'); // '...<'
03368                                                 if (!*s) break;
03369                                                 
03370                                                 ++s;
03371                                         }
03372 
03373                                         // We're after '<'
03374                                         goto LOC_TAG;
03375                                 }
03376                         }
03377 
03378                         // check that last tag is closed
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                         // early-out for empty documents
03412                         if (length == 0)
03413                                 return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element);
03414 
03415                         // get last child of the root before parsing
03416                         xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
03417         
03418                         // create parser on stack
03419                         xml_parser parser(static_cast<xml_allocator*>(xmldoc));
03420 
03421                         // save last character and make buffer zero-terminated (speeds up parsing)
03422                         char_t endch = buffer[length - 1];
03423                         buffer[length - 1] = 0;
03424                         
03425                         // skip BOM to make sure it does not end up as part of parse output
03426                         char_t* buffer_data = parse_skip_bom(buffer);
03427 
03428                         // perform actual parsing
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                                 // since we removed last character, we have to handle the only possible false positive (stray <)
03437                                 if (endch == '<')
03438                                         return make_parse_result(status_unrecognized_tag, length - 1);
03439 
03440                                 // check if there are any element nodes parsed
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                                 // roll back offset if it occurs on a null terminator in the source buffer
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         // Output facilities
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                 // replace wchar encoding with utf implementation
03470                 if (encoding == encoding_wchar) return get_wchar_encoding();
03471 
03472                 // replace utf16 encoding with utf16 with specific endianness
03473                 if (encoding == encoding_utf16) return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
03474 
03475                 // replace utf32 encoding with utf32 with specific endianness
03476                 if (encoding == encoding_utf32) return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
03477 
03478                 // only do autodetection if no explicit encoding is requested
03479                 if (encoding != encoding_auto) return encoding;
03480 
03481                 // assume utf8 encoding
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                 // discard last character if it's the lead of a surrogate pair 
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                 // only endian-swapping is required
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                 // convert to utf8
03529                 if (encoding == encoding_utf8)
03530                         return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer());
03531 
03532                 // convert to utf16
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                 // convert to utf32
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                 // convert to latin1
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                         // either a standalone character or a leading one
03565                         if ((ch & 0xc0) != 0x80) return length - i;
03566                 }
03567 
03568                 // there are four non-leading characters at the end, sequence tail is broken so might as well process the whole chunk
03569                 return length;
03570         }
03571 
03572         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)
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                         // fast path, just write data
03619                         if (encoding == get_write_native_encoding())
03620                                 writer.write(data, size * sizeof(char_t));
03621                         else
03622                         {
03623                                 // convert chunk
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                                 // write data
03628                                 writer.write(scratch.data_u8, result);
03629                         }
03630                 }
03631 
03632                 void write_direct(const char_t* data, size_t length)
03633                 {
03634                         // flush the remaining buffer contents
03635                         flush();
03636 
03637                         // handle large chunks
03638                         if (length > bufcapacity)
03639                         {
03640                                 if (encoding == get_write_native_encoding())
03641                                 {
03642                                         // fast path, can just write data chunk
03643                                         writer.write(data, length * sizeof(char_t));
03644                                         return;
03645                                 }
03646 
03647                                 // need to convert in suitable chunks
03648                                 while (length > bufcapacity)
03649                                 {
03650                                         // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer
03651                                         // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
03652                                         size_t chunk_size = get_valid_length(data, bufcapacity);
03653                                         assert(chunk_size);
03654 
03655                                         // convert chunk and write
03656                                         flush(data, chunk_size);
03657 
03658                                         // iterate
03659                                         data += chunk_size;
03660                                         length -= chunk_size;
03661                                 }
03662 
03663                                 // small tail is copied below
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                         // write the part of the string that fits in the buffer
03689                         size_t offset = bufsize;
03690 
03691                         while (*data && offset < bufcapacity)
03692                                 buffer[offset++] = *data++;
03693 
03694                         // write the rest
03695                         if (offset < bufcapacity)
03696                         {
03697                                 bufsize = offset;
03698                         }
03699                         else
03700                         {
03701                                 // backtrack a bit if we have split the codepoint
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                 // utf8 maximum expansion: x4 (-> utf32)
03781                 // utf16 maximum expansion: x2 (-> utf32)
03782                 // utf32 maximum expansion: x1
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                         // While *s is a usual symbol
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: // s is not a usual symbol
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                         // look for ]]> sequence - we can't output it as is since it terminates CDATA
03869                         while (*s && !(s[0] == ']' && s[1] == ']' && s[2] == '>')) ++s;
03870 
03871                         // skip ]] if we stopped at ]]>, > will go to the next CDATA section
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                         // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body
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                         // look for ?> sequence - we can't output it since ?> terminates PI
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                         // begin writing current node
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                         // continue to the next node
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                                 // write closing node
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                 // check that child can be a child of parent
04219                 if (!allow_insert_child(parent.type(), child.type()))
04220                         return false;
04221 
04222                 // check that node is not moved between documents
04223                 if (parent.root() != child.root())
04224                         return false;
04225 
04226                 // check that new parent is not in the child subtree
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                                 // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared
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                         // continue to the next node
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         // get value with conversion functions
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                         // since overflow detection relies on length of the sequence skip leading zeros
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                         // since overflow detection relies on length of the sequence skip leading zeros
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                 // only look at first char
04445                 char_t first = *value;
04446 
04447                 // 1*, t* (true), T* (True), y* (yes), Y* (YES)
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         // set value with conversion functions
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                 // check input buffer
04570                 if (!contents && size) return make_parse_result(status_io_error);
04571 
04572                 // get actual encoding
04573                 xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
04574 
04575                 // get private buffer
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                 // delete original buffer if we performed a conversion
04582                 if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
04583 
04584                 // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
04585                 if (own || buffer != contents) *out_buffer = buffer;
04586 
04587                 // store buffer for offset_debug
04588                 doc->buffer = buffer;
04589 
04590                 // parse
04591                 xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
04592 
04593                 // remember encoding
04594                 res.encoding = buffer_encoding;
04595 
04596                 return res;
04597         }
04598 
04599         // we need to get length of entire file to load it in memory; the only (relatively) sane way to do it is via seek/tell trick
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                 // there are 64-bit versions of fseek/ftell, let's use them
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                 // there are 64-bit versions of fseek/ftell, let's use them
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                 // if this is a 32-bit OS, long is enough; if this is a unix system, long is 64-bit, which is enough; otherwise we can't do anything anyway.
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                 // check for I/O errors
04626                 if (length < 0) return status_io_error;
04627                 
04628                 // check for overflow
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                 // finalize
04634                 out_result = result;
04635 
04636                 return status_ok;
04637         }
04638 
04639         // This function assumes that buffer has extra sizeof(char_t) writable bytes after size
04640         PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding) 
04641         {
04642                 // We only need to zero-terminate if encoding conversion does not do it for us
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                 // get file size (can result in I/O errors)
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                 // allocate buffer for the whole file
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                 // read file in memory
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                         // free chunk chain
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                 // read file to a chunk list
04732                 size_t total = 0;
04733                 xml_stream_chunk<T>* last = 0;
04734 
04735                 while (!stream.eof())
04736                 {
04737                         // allocate new chunk
04738                         xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create();
04739                         if (!chunk) return status_out_of_memory;
04740 
04741                         // append chunk to list
04742                         if (last) last = last->next = chunk;
04743                         else chunks.data = last = chunk;
04744 
04745                         // read data to chunk
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                         // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors
04750                         if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
04751 
04752                         // guard against huge files (chunk size is small enough to make this overflow check work)
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                 // copy chunk list to a contiguous buffer
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                 // return buffer
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                 // get length of remaining data in stream
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                 // guard against huge files
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                 // read stream data into memory (guard against stream exceptions with buffer holder)
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                 // read may set failbit | eofbit in case gcount() is less than read_length (i.e. line ending conversion), so check for other I/O errors
04805                 if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
04806 
04807                 // return buffer
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                 // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits)
04824                 if (stream.fail()) return make_parse_result(status_io_error);
04825 
04826                 // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)
04827                 if (stream.tellg() < 0)
04828                 {
04829                         stream.clear(); // clear error flags that could be set by a failing tellg
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                 // first pass: get length in utf8 characters
04854                 size_t length = strlength_wide(str);
04855                 size_t size = as_utf8_begin(str, length);
04856 
04857                 // allocate resulting string
04858                 char* result = static_cast<char*>(xml_memory::allocate(size + 1));
04859                 if (!result) return 0;
04860 
04861                 // second pass: convert to utf8
04862                 as_utf8_end(result, size, str, length);
04863 
04864                 // zero-terminate
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                 // there is no standard function to open wide paths, so our best bet is to try utf8 path
04873                 char* path_utf8 = convert_path_heap(path);
04874                 if (!path_utf8) return 0;
04875 
04876                 // convert mode to ASCII (we mirror _wfopen interface)
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                 // try to open the utf8 path
04881                 FILE* result = fopen(path_utf8, mode_ascii);
04882 
04883                 // free dummy buffer
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; // unfortunately we can't do proper error handling here
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                 // if hint is not an attribute of node, behavior is not defined
05392                 assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
05393 
05394                 if (!_root) return xml_attribute();
05395 
05396                 // optimistically search from hint up until the end
05397                 for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
05398                         if (i->name && impl::strequal(name_, i->name))
05399                         {
05400                                 // update hint to maximize efficiency of searching for consecutive attributes
05401                                 hint_._attr = i->next_attribute;
05402 
05403                                 return xml_attribute(i);
05404                         }
05405 
05406                 // wrap around and search from the first attribute until the hint
05407                 // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails
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                                 // update hint to maximize efficiency of searching for consecutive attributes
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                 // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
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                 // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
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                 // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
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                 // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
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                 // append_buffer is only valid for elements/documents
05923                 if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root);
05924 
05925                 // get document node
05926                 impl::xml_document_struct* doc = &impl::get_document(_root);
05927 
05928                 // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense
05929                 doc->header |= impl::xml_memory_page_contents_shared_mask;
05930                 
05931                 // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later)
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                 // add extra buffer to the list
05939                 extra->buffer = 0;
05940                 extra->next = doc->extra_buffers;
05941                 doc->extra_buffers = extra;
05942 
05943                 // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level
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; // Current search context.
06015 
06016                 if (!_root || !path_ || !path_[0]) return found;
06017 
06018                 if (path_[0] == delimiter)
06019                 {
06020                         // Absolute path; e.g. '/foo/bar'
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                                         // Borland C++ workaround
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                 // we can determine the offset reliably only if there is exactly once parse buffer
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); // BCC32 workaround
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); // BCC32 workaround
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); // BCC32 workaround
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                 // initialize sentinel page
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                 // align upwards to page boundary
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                 // prepare page structure
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                 // setup first page marker
06701         #ifdef PUGIXML_COMPACT
06702                 // round-trip through void* to avoid 'cast increases required alignment of target type' warning
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                 // allocate new root
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                 // setup sentinel page
06712                 page->allocator = static_cast<impl::xml_document_struct*>(_root);
06713 
06714                 // verify the document allocation
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                 // destroy static storage
06723                 if (_buffer)
06724                 {
06725                         impl::xml_memory::deallocate(_buffer);
06726                         _buffer = 0;
06727                 }
06728 
06729                 // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator)
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                 // destroy dynamic storage, leave sentinel page (it's in static memory)
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                 // destroy hash table
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                 // Force native encoding (skip autodetection)
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; // MSVC7 workaround
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; // MSVC7 workaround
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                         // BOM always represents the codepoint U+FEFF, so just write it in native encoding
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; // MSVC7 workaround
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; // MSVC7 workaround
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         // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
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         // Workarounds for (non-standard) iterator category detection
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 // STL replacements
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                 // fast skip head
07048                 while (end - begin > 1 && *begin != *(begin + 1)) begin++;
07049 
07050                 if (begin == end) return begin;
07051 
07052                 // last written element
07053                 I write = begin++; 
07054 
07055                 // merge unique elements
07056                 while (begin != end)
07057                 {
07058                         if (*begin != *write)
07059                                 *++write = *begin++;
07060                         else
07061                                 begin++;
07062                 }
07063 
07064                 // past-the-end (write points to live element)
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                                 // move to front
07084                                 copy_backwards(begin, it, it + 1);
07085                                 *begin = val;
07086                         }
07087                         else
07088                         {
07089                                 I hole = it;
07090 
07091                                 // move hole backwards
07092                                 while (pred(val, *(hole - 1)))
07093                                 {
07094                                         *hole = *(hole - 1);
07095                                         hole--;
07096                                 }
07097 
07098                                 // fill hole with element
07099                                 *hole = val;
07100                         }
07101                 }
07102         }
07103 
07104         // std variant for elements with ==
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                 // expand equal range
07110                 while (eqbeg != begin && *(eqbeg - 1) == *eqbeg) --eqbeg;
07111                 while (eqend != end && *eqend == *eqbeg) ++eqend;
07112 
07113                 // process outer elements
07114                 I ltend = eqbeg, gtbeg = eqend;
07115 
07116                 for (;;)
07117                 {
07118                         // find the element from the right side that belongs to the left one
07119                         for (; gtbeg != end; ++gtbeg)
07120                                 if (!pred(*eqbeg, *gtbeg))
07121                                 {
07122                                         if (*gtbeg == *eqbeg) swap(*gtbeg, *eqend++);
07123                                         else break;
07124                                 }
07125 
07126                         // find the element from the left side that belongs to the right one
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                         // scanned all elements
07135                         if (gtbeg == end && ltend == begin)
07136                         {
07137                                 *out_eqbeg = eqbeg;
07138                                 *out_eqend = eqend;
07139                                 return;
07140                         }
07141 
07142                         // make room for elements by moving equal area
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                         // median of three for small chunks
07170                         median3(first, middle, last, pred);
07171                 }
07172                 else
07173                 {
07174                         // median of nine
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                 // sort large chunks
07187                 while (end - begin > 32)
07188                 {
07189                         // find median element
07190                         I middle = begin + (end - begin) / 2;
07191                         median(begin, middle, end - 1, pred);
07192 
07193                         // partition in three chunks (< = >)
07194                         I eqbeg, eqend;
07195                         partition(begin, middle, end, pred, &eqbeg, &eqend);
07196 
07197                         // loop on larger half
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                 // insertion sort small chunk
07211                 if (begin != end) insertion_sort(begin, end, pred, &*begin);
07212         }
07213 PUGI__NS_END
07214 
07215 // Allocator used for AST and evaluation stacks
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                         // round size up to block alignment boundary
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                                 // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests
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                         // round size up to block alignment boundary
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                         // we can only reallocate the last object
07313                         assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);
07314 
07315                         // adjust root size so that we have not allocated the object at all
07316                         bool only_object = (_root_size == old_size);
07317 
07318                         if (ptr) _root_size -= old_size;
07319 
07320                         // allocate a new version (this will obviously reuse the memory if possible)
07321                         void* result = allocate(new_size);
07322                         assert(result);
07323 
07324                         // we have a new block
07325                         if (result != ptr && ptr)
07326                         {
07327                                 // copy old data
07328                                 assert(new_size >= old_size);
07329                                 memcpy(result, ptr, old_size);
07330 
07331                                 // free the previous page if it had no other objects
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                                                 // deallocate the whole page, unless it was the first one
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                         // free all new pages
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                         // restore state
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 // String class
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                         // skip empty sources
07491                         if (!*o._buffer) return;
07492 
07493                         // fast append for constant empty target and constant source
07494                         if (!*_buffer && !_uses_heap && !o._uses_heap)
07495                         {
07496                                 _buffer = o._buffer;
07497                         }
07498                         else
07499                         {
07500                                 // need to make heap copy
07501                                 size_t target_length = length();
07502                                 size_t source_length = o.length();
07503                                 size_t result_length = target_length + source_length;
07504 
07505                                 // allocate new buffer
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                                 // append first string to the new buffer in case there was no reallocation
07510                                 if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t));
07511 
07512                                 // append second string to the new buffer
07513                                 memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
07514                                 result[result_length] = 0;
07515 
07516                                 // finalize
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                         // make private heap copy
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                 // MSVC6 wcsstr bug workaround (if s is empty it always returns 0)
07595                 return (*p == 0) ? s : wcsstr(s, p);
07596         #else
07597                 return strstr(s, p);
07598         #endif
07599         }
07600 
07601         // Converts symbol to lower case, if it is an ASCII one
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                 // there is no common ancestor (the shared parent is null), nodes are from different documents
07662                 if (!ln->parent) return ln < rn;
07663 
07664                 // determine sibling order
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                 // if rn sibling chain ended ln must be before rn
07678                 return !rs;
07679         }
07680         
07681         PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
07682         {
07683                 // find common ancestor at the same depth, if any
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                 // parents are the same!
07694                 if (lp && rp) return node_is_before_sibling(lp, rp);
07695 
07696                 // nodes are at different depths, need to normalize heights
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                 // one node is the ancestor of the other
07712                 if (ln == rn) return left_higher;
07713 
07714                 // find common ancestor... again
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                         // optimized document order based check
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                         // slow comparison
07773                         xml_node ln = lhs.node(), rn = rhs.node();
07774 
07775                         // compare attributes
07776                         if (lhs.attribute() && rhs.attribute())
07777                         {
07778                                 // shared parent
07779                                 if (lhs.parent() == rhs.parent())
07780                                 {
07781                                         // determine sibling order
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                                 // compare attribute parents
07790                                 ln = lhs.parent();
07791                                 rn = rhs.parent();
07792                         }
07793                         else if (lhs.attribute())
07794                         {
07795                                 // attributes go after the parent element
07796                                 if (lhs.parent() == rhs.node()) return false;
07797                                 
07798                                 ln = lhs.parent();
07799                         }
07800                         else if (rhs.attribute())
07801                         {
07802                                 // attributes go after the parent element
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                 // fallback
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                 // fallback
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                 // fallback
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         // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
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                 // get base values
07900                 int sign, exponent;
07901                 _ecvt_s(buffer, buffer_size, value, DBL_DIG + 1, &exponent, &sign);
07902 
07903                 // truncate redundant zeros
07904                 truncate_zeros(buffer, buffer + strlen(buffer));
07905 
07906                 // fill results
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                 // get a scientific notation value with IEEE DBL_DIG decimals
07914                 sprintf(buffer, "%.*e", DBL_DIG, value);
07915                 assert(strlen(buffer) < buffer_size);
07916                 (void)!buffer_size;
07917 
07918                 // get the exponent (possibly negative)
07919                 char* exponent_string = strchr(buffer, 'e');
07920                 assert(exponent_string);
07921 
07922                 int exponent = atoi(exponent_string + 1);
07923 
07924                 // extract mantissa string: skip sign
07925                 char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
07926                 assert(mantissa[0] != '0' && mantissa[1] == '.');
07927 
07928                 // divide mantissa by 10 to eliminate integer part
07929                 mantissa[1] = mantissa[0];
07930                 mantissa++;
07931                 exponent++;
07932 
07933                 // remove extra mantissa digits and zero-terminate mantissa
07934                 truncate_zeros(mantissa, exponent_string);
07935 
07936                 // fill results
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                 // try special number conversion
07945                 const char_t* special = convert_number_to_string_special(value);
07946                 if (special) return xpath_string::from_const(special);
07947 
07948                 // get mantissa + exponent form
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                 // allocate a buffer of suitable length for the number
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                 // make the number!
07961                 char_t* s = result;
07962 
07963                 // sign
07964                 if (value < 0) *s++ = '-';
07965 
07966                 // integer part
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                 // fractional part
07982                 if (*mantissa)
07983                 {
07984                         // decimal point
07985                         *s++ = '.';
07986 
07987                         // extra zeroes from negative exponent
07988                         while (exponent < 0)
07989                         {
07990                                 *s++ = '0';
07991                                 exponent++;
07992                         }
07993 
07994                         // extra mantissa digits
07995                         while (*mantissa)
07996                         {
07997                                 assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
07998                                 *s++ = *mantissa++;
07999                         }
08000                 }
08001 
08002                 // zero-terminate
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                 // parse leading whitespace
08012                 while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
08013 
08014                 // parse sign
08015                 if (*string == '-') ++string;
08016 
08017                 if (!*string) return false;
08018 
08019                 // if there is no integer part, there should be a decimal part with at least one digit
08020                 if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false;
08021 
08022                 // parse integer part
08023                 while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
08024 
08025                 // parse decimal part
08026                 if (*string == '.')
08027                 {
08028                         ++string;
08029 
08030                         while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
08031                 }
08032 
08033                 // parse trailing whitespace
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                 // check string format
08042                 if (!check_string_to_number_format(string)) return gen_nan();
08043 
08044                 // parse string
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                         // need to make dummy on-heap copy
08060                         scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
08061                         if (!scratch) return false;
08062                 }
08063 
08064                 // copy string to zero-terminated buffer and perform conversion
08065                 memcpy(scratch, begin, length * sizeof(char_t));
08066                 scratch[length] = 0;
08067 
08068                 *out_result = convert_string_to_number(scratch);
08069 
08070                 // free dummy buffer
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                 // same as round_nearest, but returns -0 for [-0.5, -0]
08084                 // ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)
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                 // Default namespace does not apply to attributes
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                                 // replace whitespace sequence with single space
08179                                 while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
08180 
08181                                 // avoid leading spaces
08182                                 if (write != buffer) *write++ = ' ';
08183                         }
08184                         else *write++ = ch;
08185                 }
08186 
08187                 // remove trailing space
08188                 if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
08189 
08190                 // zero-terminate
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; // do not process
08208                         else if (static_cast<size_t>(pos - from) < to_length)
08209                                 *write++ = to[pos - from]; // replace
08210                 }
08211 
08212                 // zero-terminate
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                         // code=128 means "skip character"
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                                 // code=128 means "skip character" (table size is 128 so 128 can be a special value)
08266                                 // this code skips these characters without extra branches
08267                                 *write = static_cast<char_t>(code);
08268                                 write += 1 - (code >> 7);
08269                         }
08270                         else
08271                         {
08272                                 *write++ = ch;
08273                         }
08274                 }
08275 
08276                 // zero-terminate
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                 // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
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; // empty variable names are invalid
08357 
08358                 // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
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                         // need to make dummy on-heap copy
08451                         scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
08452                         if (!scratch) return false;
08453                 }
08454 
08455                 // copy string to zero-terminated buffer and perform lookup
08456                 memcpy(scratch, begin, length * sizeof(char_t));
08457                 scratch[length] = 0;
08458 
08459                 *out_result = set->get(scratch);
08460 
08461                 // free dummy buffer
08462                 if (scratch != buffer) xml_memory::deallocate(scratch);
08463 
08464                 return true;
08465         }
08466 PUGI__NS_END
08467 
08468 // Internal node set class
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                                 // reallocate the old array or allocate a new one
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                                 // finalize
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                 // get new capacity (1.5x rule)
08638                 size_t new_capacity = capacity + capacity / 2 + 1;
08639 
08640                 // reallocate the old array or allocate a new one
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                 // finalize
08645                 _begin = data;
08646                 _end = data + capacity;
08647                 _eos = data + new_capacity;
08648 
08649                 // push
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                         // save lexeme position for error reporting
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)) // qname
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] == '*') // namespace test ncname:*
08977                                                 {
08978                                                         cur += 2; // :*
08979                                                 }
08980                                                 else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
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,                                              // left or right
09023                 ast_op_and,                                             // left and right
09024                 ast_op_equal,                                   // left = right
09025                 ast_op_not_equal,                               // left != right
09026                 ast_op_less,                                    // left < right
09027                 ast_op_greater,                                 // left > right
09028                 ast_op_less_or_equal,                   // left <= right
09029                 ast_op_greater_or_equal,                // left >= right
09030                 ast_op_add,                                             // left + right
09031                 ast_op_subtract,                                // left - right
09032                 ast_op_multiply,                                // left * right
09033                 ast_op_divide,                                  // left / right
09034                 ast_op_mod,                                             // left % right
09035                 ast_op_negate,                                  // left - right
09036                 ast_op_union,                                   // left | right
09037                 ast_predicate,                                  // apply predicate to set; next points to next predicate
09038                 ast_filter,                                             // select * from left where right
09039                 ast_string_constant,                    // string constant
09040                 ast_number_constant,                    // number constant
09041                 ast_variable,                                   // variable
09042                 ast_func_last,                                  // last()
09043                 ast_func_position,                              // position()
09044                 ast_func_count,                                 // count(left)
09045                 ast_func_id,                                    // id(left)
09046                 ast_func_local_name_0,                  // local-name()
09047                 ast_func_local_name_1,                  // local-name(left)
09048                 ast_func_namespace_uri_0,               // namespace-uri()
09049                 ast_func_namespace_uri_1,               // namespace-uri(left)
09050                 ast_func_name_0,                                // name()
09051                 ast_func_name_1,                                // name(left)
09052                 ast_func_string_0,                              // string()
09053                 ast_func_string_1,                              // string(left)
09054                 ast_func_concat,                                // concat(left, right, siblings)
09055                 ast_func_starts_with,                   // starts_with(left, right)
09056                 ast_func_contains,                              // contains(left, right)
09057                 ast_func_substring_before,              // substring-before(left, right)
09058                 ast_func_substring_after,               // substring-after(left, right)
09059                 ast_func_substring_2,                   // substring(left, right)
09060                 ast_func_substring_3,                   // substring(left, right, third)
09061                 ast_func_string_length_0,               // string-length()
09062                 ast_func_string_length_1,               // string-length(left)
09063                 ast_func_normalize_space_0,             // normalize-space()
09064                 ast_func_normalize_space_1,             // normalize-space(left)
09065                 ast_func_translate,                             // translate(left, right, third)
09066                 ast_func_boolean,                               // boolean(left)
09067                 ast_func_not,                                   // not(left)
09068                 ast_func_true,                                  // true()
09069                 ast_func_false,                                 // false()
09070                 ast_func_lang,                                  // lang(left)
09071                 ast_func_number_0,                              // number()
09072                 ast_func_number_1,                              // number(left)
09073                 ast_func_sum,                                   // sum(left)
09074                 ast_func_floor,                                 // floor(left)
09075                 ast_func_ceiling,                               // ceiling(left)
09076                 ast_func_round,                                 // round(left)
09077                 ast_step,                                               // process set left with step
09078                 ast_step_root,                                  // select root node
09079 
09080                 ast_opt_translate_table,                // translate(left, right, third) where right/third are constants
09081                 ast_opt_compare_attribute               // @name = 'string'
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                 // node type
09140                 char _type;
09141                 char _rettype;
09142 
09143                 // for ast_step
09144                 char _axis;
09145 
09146                 // for ast_step/ast_predicate/ast_filter
09147                 char _test;
09148 
09149                 // tree node structure
09150                 xpath_ast_node* _left;
09151                 xpath_ast_node* _right;
09152                 xpath_ast_node* _next;
09153 
09154                 union
09155                 {
09156                         // value for ast_string_constant
09157                         const char_t* string;
09158                         // value for ast_number_constant
09159                         double number;
09160                         // variable for ast_variable
09161                         xpath_variable* variable;
09162                         // node test for ast_step (node name/namespace/node type/pi target)
09163                         const char_t* nodetest;
09164                         // table for ast_opt_translate_table
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                         // remove_if... or well, sort of
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                         // remove_if... or well, sort of
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                                 // exit from this node so that we don't include descendants
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                                 // exit from this node so that we don't include descendants
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                                                 // leaf node, can't be ancestor
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) // reject attributes based on principal node type test
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) // reject attributes based on principal node type test
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                                 // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding
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                                 // self axis preserves the original order
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                                         // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes
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                         // child, attribute and self axes always generate unique set of nodes
09878                         // for other axis, if the set stayed sorted, it stayed unique because the traversal algorithms do not visit the same node twice
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                                                 // strnicmp / strncasecmp is not portable
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                                 // fallthrough to type conversion
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                                 // fallthrough to type conversion
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                         // count the string number
10217                         size_t count = 1;
10218                         for (xpath_ast_node* nc = _right; nc; nc = nc->_next) count++;
10219 
10220                         // gather all strings
10221                         xpath_string static_buffer[4];
10222                         xpath_string* buffer = static_buffer;
10223 
10224                         // allocate on-heap for large concats
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                         // evaluate all strings to temporary stack
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                         // get total length
10241                         size_t length = 0;
10242                         for (size_t i = 0; i < count; ++i) length += buffer[i].length();
10243 
10244                         // create final string
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(); // NaN
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                                 // fallthrough to type conversion
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                                 // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
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                                 // either expression is a number or it contains position() call; sort by document order
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                                         // namespaced axis is not supported
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); // root step can't have any predicates
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                                 // fallthrough to type conversion
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                         // Rewrite [position()=expr] with [expr]
10632                         // Note that this step has to go before classification to recognize [position()=1]
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                         // Classify filter/predicate ops to perform various optimizations during evaluation
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                         // Rewrite descendant-or-self::node()/child::foo with descendant::foo
10653                         // The former is a full form of //foo, the latter is much faster since it executes the node test immediately
10654                         // Do a similar kind of rewrite for self/descendant/descendant-or-self axes
10655                         // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1])
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                         // Use optimized lookup table implementation for translate() with constant arguments
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                         // Use optimized path for @attr = 'value' or @attr = $value
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); // workaround for clang static analysis
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                 // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
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                 // FilterExpr ::= PrimaryExpr | FilterExpr Predicate
11136                 // Predicate ::= '[' PredicateExpr ']'
11137                 // PredicateExpr ::= Expr
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                 // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
11162                 // AxisSpecifier ::= AxisName '::' | '@'?
11163                 // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
11164                 // NameTest ::= '*' | NCName ':' '*' | QName
11165                 // AbbreviatedStep ::= '.' | '..'
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; // implied child axis
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                                 // node name test
11200                                 nt_name = _lexer.contents();
11201                                 _lexer.next();
11202 
11203                                 // was it an axis name?
11204                                 if (_lexer.current() == lex_double_colon)
11205                                 {
11206                                         // parse axis name
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                                         // read actual node test
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                                         // node type test or processing-instruction
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                                         // QName or NCName:*
11265                                         else
11266                                         {
11267                                                 if (nt_name.end - nt_name.begin > 2 && nt_name.end[-2] == ':' && nt_name.end[-1] == '*') // NCName:*
11268                                                 {
11269                                                         nt_name.end--; // erase *
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                 // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
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                 // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
11329                 // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
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                                 // relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path
11339                                 lexeme_t l = _lexer.current();
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                         // else clause moved outside of if because of bogus warning 'control may reach end of non-void function being inlined' in gcc 4.0.1
11357                         return parse_relative_location_path(0);
11358                 }
11359                 
11360                 // PathExpr ::= LocationPath
11361                 //                              | FilterExpr
11362                 //                              | FilterExpr '/' RelativeLocationPath
11363                 //                              | FilterExpr '//' RelativeLocationPath
11364                 // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
11365                 // UnaryExpr ::= UnionExpr | '-' UnaryExpr
11366                 xpath_ast_node* parse_path_or_unary_expression()
11367                 {
11368                         // Clarification.
11369                         // PathExpr begins with either LocationPath or FilterExpr.
11370                         // FilterExpr begins with PrimaryExpr
11371                         // PrimaryExpr begins with '$' in case of it being a variable reference,
11372                         // '(' in case of it being an expression, string literal, number constant or
11373                         // function call.
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                                         // This is either a function call, or not - if not, we shall proceed with location path
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                                         // This looks like a function call; however this still can be a node-test. Check it.
11389                                         if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path();
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                                         // select from location path
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                                 // precedence 7+ - only parses union expressions
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                 // Expr ::= OrExpr
11522                 // OrExpr ::= AndExpr | OrExpr 'or' AndExpr
11523                 // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
11524                 // EqualityExpr ::= RelationalExpr
11525                 //                                      | EqualityExpr '=' RelationalExpr
11526                 //                                      | EqualityExpr '!=' RelationalExpr
11527                 // RelationalExpr ::= AdditiveExpr
11528                 //                                        | RelationalExpr '<' AdditiveExpr
11529                 //                                        | RelationalExpr '>' AdditiveExpr
11530                 //                                        | RelationalExpr '<=' AdditiveExpr
11531                 //                                        | RelationalExpr '>=' AdditiveExpr
11532                 // AdditiveExpr ::= MultiplicativeExpr
11533                 //                                      | AdditiveExpr '+' MultiplicativeExpr
11534                 //                                      | AdditiveExpr '-' MultiplicativeExpr
11535                 // MultiplicativeExpr ::= UnaryExpr
11536                 //                                                | MultiplicativeExpr '*' UnaryExpr
11537                 //                                                | MultiplicativeExpr 'div' UnaryExpr
11538                 //                                                | MultiplicativeExpr 'mod' UnaryExpr
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                                 // there are still unparsed tokens left, error
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                         // free all allocated pages
11588                         impl->alloc.release();
11589 
11590                         // free allocator memory (with the first page)
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                         // deallocate old buffer
11729                         if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
11730 
11731                         // use internal buffer
11732                         if (begin_ != end_) _storage = *begin_;
11733 
11734                         _begin = &_storage;
11735                         _end = &_storage + size_;
11736                         _type = type_;
11737                 }
11738                 else
11739                 {
11740                         // make heap copy
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                         // deallocate old buffer
11755                         if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
11756 
11757                         // finalize
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                 // duplicate string
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                 // replace old string
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                 // look for existing variable
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                         // allocate storage for new variable
12073                         xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
12074                         if (!nvar) return false;
12075 
12076                         // link the variable to the result immediately to handle failures gracefully
12077                         if (last)
12078                                 last->_next = nvar;
12079                         else
12080                                 *out_result = nvar;
12081 
12082                         last = nvar;
12083 
12084                         // copy the value; this can fail due to out-of-memory conditions
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                 // look for existing variable
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                 // add new variable
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; // MSVC7 workaround
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 // Intel C++ does not properly keep warning state for function templates,
12386 // so popping warning state at the end of translation unit leads to warnings in the middle.
12387 #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
12388 #       pragma warning(pop)
12389 #endif
12390 
12391 // Undefine all local macros (makes sure we're not leaking macros in header-only mode)
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 


pugixml
Author(s): Jose Luis Sanchez-Lopez
autogenerated on Thu Jun 6 2019 21:00:00