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

Generated on Mon Sep 15 2014 01:23:54 for QuickFIX by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2001