Ignore:
Timestamp:
May 5, 2017, 2:17:23 PM (8 years ago)
Author:
Frederik Heber <frederik.heber@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_StructOpt_integration_tests, AutomationFragmentation_failures, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph_documentation, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, Fix_ChronosMutex, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, GeometryObjects, Gui_displays_atomic_force_velocity, IndependentFragmentGrids_IntegrationTest, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, RotateToPrincipalAxisSystem_UndoRedo, StoppableMakroAction, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, Ubuntu_1604_changes
Children:
dde50d
Parents:
6798a5
git-author:
Frederik Heber <heber@…> (04/05/17 17:17:45)
git-committer:
Frederik Heber <frederik.heber@…> (05/05/17 14:17:23)
Message:

Updated pugixml in ThirdParty/vmg and src from 1.0 to 1.8.

  • this solved compilation issues with 1.0 seemingly from too recent gcc and c++11/14/.. changes.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • ThirdParty/vmg/src/thirdparty/pugixml/pugixml.cpp

    r6798a5 r33a694  
    11/**
    2  * pugixml parser - version 1.0
     2 * pugixml parser - version 1.8
    33 * --------------------------------------------------------
    4  * Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
     4 * Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
    55 * Report bugs and download new versions at http://pugixml.org/
    66 *
     
    1212 */
    1313
     14#ifndef SOURCE_PUGIXML_CPP
     15#define SOURCE_PUGIXML_CPP
     16
    1417#include "pugixml.hpp"
    1518
     
    1821#include <string.h>
    1922#include <assert.h>
    20 #include <setjmp.h>
    21 #include <wchar.h>
     23#include <limits.h>
     24
     25#ifdef PUGIXML_WCHAR_MODE
     26#       include <wchar.h>
     27#endif
    2228
    2329#ifndef PUGIXML_NO_XPATH
    2430#       include <math.h>
    2531#       include <float.h>
     32#       ifdef PUGIXML_NO_EXCEPTIONS
     33#               include <setjmp.h>
     34#       endif
    2635#endif
    2736
     
    3645
    3746#ifdef _MSC_VER
     47#       pragma warning(push)
    3848#       pragma warning(disable: 4127) // conditional expression is constant
    3949#       pragma warning(disable: 4324) // structure was padded due to __declspec(align())
     
    4151#       pragma warning(disable: 4702) // unreachable code
    4252#       pragma warning(disable: 4996) // this function or variable may be unsafe
     53#       pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
    4354#endif
    4455
    4556#ifdef __INTEL_COMPILER
    46 #       pragma warning(disable: 177) // function was declared but never referenced 
     57#       pragma warning(disable: 177) // function was declared but never referenced
    4758#       pragma warning(disable: 279) // controlling expression is constant
    4859#       pragma warning(disable: 1478 1786) // function was declared "deprecated"
     60#       pragma warning(disable: 1684) // conversion from pointer to same-sized integral type
    4961#endif
    5062
     63#if defined(__BORLANDC__) && defined(PUGIXML_HEADER_ONLY)
     64#       pragma warn -8080 // symbol is declared but never used; disabling this inside push/pop bracket does not make the warning go away
     65#endif
     66
    5167#ifdef __BORLANDC__
     68#       pragma option push
    5269#       pragma warn -8008 // condition is always false
    5370#       pragma warn -8066 // unreachable code
     
    5572
    5673#ifdef __SNC__
     74// Using diag_push/diag_pop does not disable the warnings inside templates due to a compiler bug
    5775#       pragma diag_suppress=178 // function was declared but never referenced
    5876#       pragma diag_suppress=237 // controlling expression is constant
    5977#endif
    6078
    61 // uintptr_t
    62 #if !defined(_MSC_VER) || _MSC_VER >= 1600
    63 #       include <stdint.h>
    64 #else
    65 #       if _MSC_VER < 1300
    66 // No native uintptr_t in MSVC6
    67 typedef size_t uintptr_t;
    68 #       endif
    69 typedef unsigned __int8 uint8_t;
    70 typedef unsigned __int16 uint16_t;
    71 typedef unsigned __int32 uint32_t;
    72 typedef __int32 int32_t;
    73 #endif
    74 
    7579// Inlining controls
    7680#if defined(_MSC_VER) && _MSC_VER >= 1300
    77 #       define PUGIXML_NO_INLINE __declspec(noinline)
     81#       define PUGI__NO_INLINE __declspec(noinline)
    7882#elif defined(__GNUC__)
    79 #       define PUGIXML_NO_INLINE __attribute__((noinline))
     83#       define PUGI__NO_INLINE __attribute__((noinline))
    8084#else
    81 #       define PUGIXML_NO_INLINE
     85#       define PUGI__NO_INLINE
    8286#endif
    8387
     88// Branch weight controls
     89#if defined(__GNUC__)
     90#       define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0)
     91#else
     92#       define PUGI__UNLIKELY(cond) (cond)
     93#endif
     94
    8495// Simple static assertion
    85 #define STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
     96#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
    8697
    8798// Digital Mars C++ bug workaround for passing char loaded from memory via stack
    8899#ifdef __DMC__
    89 #       define DMC_VOLATILE volatile
     100#       define PUGI__DMC_VOLATILE volatile
    90101#else
    91 #       define DMC_VOLATILE
     102#       define PUGI__DMC_VOLATILE
    92103#endif
    93104
    94 using namespace pugi;
     105// Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all)
     106#if defined(__BORLANDC__) && !defined(__MEM_H_USING_LIST)
     107using std::memcpy;
     108using std::memmove;
     109using std::memset;
     110#endif
     111
     112// Some MinGW versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions in strict ANSI mode
     113#if defined(PUGIXML_HAS_LONG_LONG) && defined(__MINGW32__) && defined(__STRICT_ANSI__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX)
     114#       define LLONG_MAX 9223372036854775807LL
     115#       define LLONG_MIN (-LLONG_MAX-1)
     116#       define ULLONG_MAX (2ULL*LLONG_MAX+1)
     117#endif
     118
     119// In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features
     120#if defined(_MSC_VER) && !defined(__S3E__)
     121#       define PUGI__MSVC_CRT_VERSION _MSC_VER
     122#endif
     123
     124#ifdef PUGIXML_HEADER_ONLY
     125#       define PUGI__NS_BEGIN namespace pugi { namespace impl {
     126#       define PUGI__NS_END } }
     127#       define PUGI__FN inline
     128#       define PUGI__FN_NO_INLINE inline
     129#else
     130#       if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
     131#               define PUGI__NS_BEGIN namespace pugi { namespace impl {
     132#               define PUGI__NS_END } }
     133#       else
     134#               define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace {
     135#               define PUGI__NS_END } } }
     136#       endif
     137#       define PUGI__FN
     138#       define PUGI__FN_NO_INLINE PUGI__NO_INLINE
     139#endif
     140
     141// uintptr_t
     142#if (defined(_MSC_VER) && _MSC_VER < 1600) || (defined(__BORLANDC__) && __BORLANDC__ < 0x561)
     143namespace pugi
     144{
     145#       ifndef _UINTPTR_T_DEFINED
     146        typedef size_t uintptr_t;
     147#       endif
     148
     149        typedef unsigned __int8 uint8_t;
     150        typedef unsigned __int16 uint16_t;
     151        typedef unsigned __int32 uint32_t;
     152}
     153#else
     154#       include <stdint.h>
     155#endif
    95156
    96157// Memory allocation
    97 namespace
    98 {
    99         void* default_allocate(size_t size)
     158PUGI__NS_BEGIN
     159        PUGI__FN void* default_allocate(size_t size)
    100160        {
    101161                return malloc(size);
    102162        }
    103163
    104         void default_deallocate(void* ptr)
     164        PUGI__FN void default_deallocate(void* ptr)
    105165        {
    106166                free(ptr);
    107167        }
    108168
    109         allocation_function global_allocate = default_allocate;
    110         deallocation_function global_deallocate = default_deallocate;
    111 }
     169        template <typename T>
     170        struct xml_memory_management_function_storage
     171        {
     172                static allocation_function allocate;
     173                static deallocation_function deallocate;
     174        };
     175
     176        // Global allocation functions are stored in class statics so that in header mode linker deduplicates them
     177        // Without a template<> we'll get multiple definitions of the same static
     178        template <typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate;
     179        template <typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;
     180
     181        typedef xml_memory_management_function_storage<int> xml_memory;
     182PUGI__NS_END
    112183
    113184// String utilities
    114 namespace
    115 {
     185PUGI__NS_BEGIN
    116186        // Get string length
    117         size_t strlength(const char_t* s)
     187        PUGI__FN size_t strlength(const char_t* s)
    118188        {
    119189                assert(s);
     
    127197
    128198        // Compare two strings
    129         bool strequal(const char_t* src, const char_t* dst)
     199        PUGI__FN bool strequal(const char_t* src, const char_t* dst)
    130200        {
    131201                assert(src && dst);
     
    139209
    140210        // Compare lhs with [rhs_begin, rhs_end)
    141         bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
     211        PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
    142212        {
    143213                for (size_t i = 0; i < count; ++i)
    144214                        if (lhs[i] != rhs[i])
    145215                                return false;
    146        
     216
    147217                return lhs[count] == 0;
    148218        }
    149        
    150 #ifdef PUGIXML_WCHAR_MODE
    151         // Convert string to wide string, assuming all symbols are ASCII
    152         void widen_ascii(wchar_t* dest, const char* source)
    153         {
    154                 for (const char* i = source; *i; ++i) *dest++ = *i;
    155                 *dest = 0;
    156         }
    157 #endif
    158 }
    159 
    160 #if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH)
    161 // auto_ptr-like buffer holder for exception recovery
    162 namespace
    163 {
    164         struct buffer_holder
    165         {
    166                 void* data;
    167                 void (*deleter)(void*);
    168 
    169                 buffer_holder(void* data, void (*deleter)(void*)): data(data), deleter(deleter)
    170                 {
    171                 }
    172 
    173                 ~buffer_holder()
     219
     220        // Get length of wide string, even if CRT lacks wide character support
     221        PUGI__FN size_t strlength_wide(const wchar_t* s)
     222        {
     223                assert(s);
     224
     225        #ifdef PUGIXML_WCHAR_MODE
     226                return wcslen(s);
     227        #else
     228                const wchar_t* end = s;
     229                while (*end) end++;
     230                return static_cast<size_t>(end - s);
     231        #endif
     232        }
     233PUGI__NS_END
     234
     235// auto_ptr-like object for exception recovery
     236PUGI__NS_BEGIN
     237        template <typename T> struct auto_deleter
     238        {
     239                typedef void (*D)(T*);
     240
     241                T* data;
     242                D deleter;
     243
     244                auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_)
     245                {
     246                }
     247
     248                ~auto_deleter()
    174249                {
    175250                        if (data) deleter(data);
    176251                }
    177252
    178                 void* release()
    179                 {
    180                         void* result = data;
     253                T* release()
     254                {
     255                        T* result = data;
    181256                        data = 0;
    182257                        return result;
    183258                }
    184259        };
    185 }
     260PUGI__NS_END
     261
     262#ifdef PUGIXML_COMPACT
     263PUGI__NS_BEGIN
     264        class compact_hash_table
     265        {
     266        public:
     267                compact_hash_table(): _items(0), _capacity(0), _count(0)
     268                {
     269                }
     270
     271                void clear()
     272                {
     273                        if (_items)
     274                        {
     275                                xml_memory::deallocate(_items);
     276                                _items = 0;
     277                                _capacity = 0;
     278                                _count = 0;
     279                        }
     280                }
     281
     282                void** find(const void* key)
     283                {
     284                        assert(key);
     285
     286                        if (_capacity == 0) return 0;
     287
     288                        size_t hashmod = _capacity - 1;
     289                        size_t bucket = hash(key) & hashmod;
     290
     291                        for (size_t probe = 0; probe <= hashmod; ++probe)
     292                        {
     293                                item_t& probe_item = _items[bucket];
     294
     295                                if (probe_item.key == key)
     296                                        return &probe_item.value;
     297
     298                                if (probe_item.key == 0)
     299                                        return 0;
     300
     301                                // hash collision, quadratic probing
     302                                bucket = (bucket + probe + 1) & hashmod;
     303                        }
     304
     305                        assert(false && "Hash table is full");
     306                        return 0;
     307                }
     308
     309                void** insert(const void* key)
     310                {
     311                        assert(key);
     312                        assert(_capacity != 0 && _count < _capacity - _capacity / 4);
     313
     314                        size_t hashmod = _capacity - 1;
     315                        size_t bucket = hash(key) & hashmod;
     316
     317                        for (size_t probe = 0; probe <= hashmod; ++probe)
     318                        {
     319                                item_t& probe_item = _items[bucket];
     320
     321                                if (probe_item.key == 0)
     322                                {
     323                                        probe_item.key = key;
     324                                        _count++;
     325                                        return &probe_item.value;
     326                                }
     327
     328                                if (probe_item.key == key)
     329                                        return &probe_item.value;
     330
     331                                // hash collision, quadratic probing
     332                                bucket = (bucket + probe + 1) & hashmod;
     333                        }
     334
     335                        assert(false && "Hash table is full");
     336                        return 0;
     337                }
     338
     339                bool reserve()
     340                {
     341                        if (_count + 16 >= _capacity - _capacity / 4)
     342                                return rehash();
     343
     344                        return true;
     345                }
     346
     347        private:
     348                struct item_t
     349                {
     350                        const void* key;
     351                        void* value;
     352                };
     353
     354                item_t* _items;
     355                size_t _capacity;
     356
     357                size_t _count;
     358
     359                bool rehash();
     360
     361                static unsigned int hash(const void* key)
     362                {
     363                        unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key));
     364
     365                        // MurmurHash3 32-bit finalizer
     366                        h ^= h >> 16;
     367                        h *= 0x85ebca6bu;
     368                        h ^= h >> 13;
     369                        h *= 0xc2b2ae35u;
     370                        h ^= h >> 16;
     371
     372                        return h;
     373                }
     374        };
     375
     376        PUGI__FN_NO_INLINE bool compact_hash_table::rehash()
     377        {
     378                compact_hash_table rt;
     379                rt._capacity = (_capacity == 0) ? 32 : _capacity * 2;
     380                rt._items = static_cast<item_t*>(xml_memory::allocate(sizeof(item_t) * rt._capacity));
     381
     382                if (!rt._items)
     383                        return false;
     384
     385                memset(rt._items, 0, sizeof(item_t) * rt._capacity);
     386
     387                for (size_t i = 0; i < _capacity; ++i)
     388                        if (_items[i].key)
     389                                *rt.insert(_items[i].key) = _items[i].value;
     390
     391                if (_items)
     392                        xml_memory::deallocate(_items);
     393
     394                _capacity = rt._capacity;
     395                _items = rt._items;
     396
     397                assert(_count == rt._count);
     398
     399                return true;
     400        }
     401
     402PUGI__NS_END
    186403#endif
    187404
    188 namespace
    189 {
    190         static const size_t xml_memory_page_size = 32768;
    191 
    192         static const uintptr_t xml_memory_page_alignment = 32;
    193         static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1);
    194         static const uintptr_t xml_memory_page_name_allocated_mask = 16;
    195         static const uintptr_t xml_memory_page_value_allocated_mask = 8;
    196         static const uintptr_t xml_memory_page_type_mask = 7;
     405PUGI__NS_BEGIN
     406#ifdef PUGIXML_COMPACT
     407        static const uintptr_t xml_memory_block_alignment = 4;
     408#else
     409        static const uintptr_t xml_memory_block_alignment = sizeof(void*);
     410#endif
     411
     412        // extra metadata bits
     413        static const uintptr_t xml_memory_page_contents_shared_mask = 64;
     414        static const uintptr_t xml_memory_page_name_allocated_mask = 32;
     415        static const uintptr_t xml_memory_page_value_allocated_mask = 16;
     416        static const uintptr_t xml_memory_page_type_mask = 15;
     417
     418        // combined masks for string uniqueness
     419        static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask;
     420        static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask;
     421
     422#ifdef PUGIXML_COMPACT
     423        #define PUGI__GETHEADER_IMPL(object, page, flags) // unused
     424        #define PUGI__GETPAGE_IMPL(header) (header).get_page()
     425#else
     426        #define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))
     427        // this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
     428        #define PUGI__GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8))))
     429#endif
     430
     431        #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header)
     432        #define PUGI__NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
    197433
    198434        struct xml_allocator;
     
    202438                static xml_memory_page* construct(void* memory)
    203439                {
    204                         if (!memory) return 0; //$ redundant, left for performance
    205 
    206440                        xml_memory_page* result = static_cast<xml_memory_page*>(memory);
    207441
    208442                        result->allocator = 0;
    209                         result->memory = 0;
    210443                        result->prev = 0;
    211444                        result->next = 0;
     
    213446                        result->freed_size = 0;
    214447
     448                #ifdef PUGIXML_COMPACT
     449                        result->compact_string_base = 0;
     450                        result->compact_shared_parent = 0;
     451                        result->compact_page_marker = 0;
     452                #endif
     453
    215454                        return result;
    216455                }
    217456
    218457                xml_allocator* allocator;
    219 
    220                 void* memory;
    221458
    222459                xml_memory_page* prev;
     
    226463                size_t freed_size;
    227464
    228                 char data[1];
     465        #ifdef PUGIXML_COMPACT
     466                char_t* compact_string_base;
     467                void* compact_shared_parent;
     468                uint32_t* compact_page_marker;
     469        #endif
    229470        };
     471
     472        static const size_t xml_memory_page_size =
     473        #ifdef PUGIXML_MEMORY_PAGE_SIZE
     474                (PUGIXML_MEMORY_PAGE_SIZE)
     475        #else
     476                32768
     477        #endif
     478                - sizeof(xml_memory_page);
    230479
    231480        struct xml_memory_string_header
     
    239488                xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
    240489                {
     490                #ifdef PUGIXML_COMPACT
     491                        _hash = 0;
     492                #endif
    241493                }
    242494
    243495                xml_memory_page* allocate_page(size_t data_size)
    244496                {
    245                         size_t size = offsetof(xml_memory_page, data) + data_size;
     497                        size_t size = sizeof(xml_memory_page) + data_size;
    246498
    247499                        // allocate block with some alignment, leaving memory for worst-case padding
    248                         void* memory = global_allocate(size + xml_memory_page_alignment);
     500                        void* memory = xml_memory::allocate(size);
    249501                        if (!memory) return 0;
    250502
    251                         // align upwards to page boundary
    252                         void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1));
    253 
    254503                        // prepare page structure
    255                         xml_memory_page* page = xml_memory_page::construct(page_memory);
    256 
    257                         page->memory = memory;
     504                        xml_memory_page* page = xml_memory_page::construct(memory);
     505                        assert(page);
     506
    258507                        page->allocator = _root->allocator;
    259508
     
    263512                static void deallocate_page(xml_memory_page* page)
    264513                {
    265                         global_deallocate(page->memory);
     514                        xml_memory::deallocate(page);
    266515                }
    267516
     
    270519                void* allocate_memory(size_t size, xml_memory_page*& out_page)
    271520                {
    272                         if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page);
    273 
    274                         void* buf = _root->data + _busy_size;
     521                        if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size))
     522                                return allocate_memory_oob(size, out_page);
     523
     524                        void* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size;
    275525
    276526                        _busy_size += size;
     
    281531                }
    282532
     533        #ifdef PUGIXML_COMPACT
     534                void* allocate_object(size_t size, xml_memory_page*& out_page)
     535                {
     536                        void* result = allocate_memory(size + sizeof(uint32_t), out_page);
     537                        if (!result) return 0;
     538
     539                        // adjust for marker
     540                        ptrdiff_t offset = static_cast<char*>(result) - reinterpret_cast<char*>(out_page->compact_page_marker);
     541
     542                        if (PUGI__UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment))
     543                        {
     544                                // insert new marker
     545                                uint32_t* marker = static_cast<uint32_t*>(result);
     546
     547                                *marker = static_cast<uint32_t>(reinterpret_cast<char*>(marker) - reinterpret_cast<char*>(out_page));
     548                                out_page->compact_page_marker = marker;
     549
     550                                // since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block
     551                                // this will make sure deallocate_memory correctly tracks the size
     552                                out_page->freed_size += sizeof(uint32_t);
     553
     554                                return marker + 1;
     555                        }
     556                        else
     557                        {
     558                                // roll back uint32_t part
     559                                _busy_size -= sizeof(uint32_t);
     560
     561                                return result;
     562                        }
     563                }
     564        #else
     565                void* allocate_object(size_t size, xml_memory_page*& out_page)
     566                {
     567                        return allocate_memory(size, out_page);
     568                }
     569        #endif
     570
    283571                void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
    284572                {
    285573                        if (page == _root) page->busy_size = _busy_size;
    286574
    287                         assert(ptr >= page->data && ptr < page->data + page->busy_size);
     575                        assert(ptr >= reinterpret_cast<char*>(page) + sizeof(xml_memory_page) && ptr < reinterpret_cast<char*>(page) + sizeof(xml_memory_page) + page->busy_size);
    288576                        (void)!ptr;
    289577
     
    298586
    299587                                        // top page freed, just reset sizes
    300                                         page->busy_size = page->freed_size = 0;
     588                                        page->busy_size = 0;
     589                                        page->freed_size = 0;
     590
     591                                #ifdef PUGIXML_COMPACT
     592                                        // reset compact state to maximize efficiency
     593                                        page->compact_string_base = 0;
     594                                        page->compact_shared_parent = 0;
     595                                        page->compact_page_marker = 0;
     596                                #endif
     597
    301598                                        _busy_size = 0;
    302599                                }
     
    318615                char_t* allocate_string(size_t length)
    319616                {
     617                        static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment;
     618
     619                        PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
     620
    320621                        // allocate memory for string and header block
    321622                        size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
    322                        
    323                         // round size up to pointer alignment boundary
    324                         size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1);
     623
     624                        // round size up to block alignment boundary
     625                        size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1);
    325626
    326627                        xml_memory_page* page;
     
    330631
    331632                        // setup header
    332                         ptrdiff_t page_offset = reinterpret_cast<char*>(header) - page->data;
    333 
    334                         assert(page_offset >= 0 && page_offset < (1 << 16));
    335                         header->page_offset = static_cast<uint16_t>(page_offset);
     633                        ptrdiff_t page_offset = reinterpret_cast<char*>(header) - reinterpret_cast<char*>(page) - sizeof(xml_memory_page);
     634
     635                        assert(page_offset % xml_memory_block_alignment == 0);
     636                        assert(page_offset >= 0 && static_cast<size_t>(page_offset) < max_encoded_offset);
     637                        header->page_offset = static_cast<uint16_t>(static_cast<size_t>(page_offset) / xml_memory_block_alignment);
    336638
    337639                        // full_size == 0 for large strings that occupy the whole page
    338                         assert(full_size < (1 << 16) || (page->busy_size == full_size && page_offset == 0));
    339                         header->full_size = static_cast<uint16_t>(full_size < (1 << 16) ? full_size : 0);
    340 
    341                         return reinterpret_cast<char_t*>(header + 1);
     640                        assert(full_size % xml_memory_block_alignment == 0);
     641                        assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0));
     642                        header->full_size = static_cast<uint16_t>(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0);
     643
     644                        // round-trip through void* to avoid 'cast increases required alignment of target type' warning
     645                        // header is guaranteed a pointer-sized alignment, which should be enough for char_t
     646                        return static_cast<char_t*>(static_cast<void*>(header + 1));
    342647                }
    343648
    344649                void deallocate_string(char_t* string)
    345650                {
     651                        // this function casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
     652                        // we're guaranteed the proper (pointer-sized) alignment on the input string if it was allocated via allocate_string
     653
    346654                        // get header
    347                         xml_memory_string_header* header = reinterpret_cast<xml_memory_string_header*>(string) - 1;
     655                        xml_memory_string_header* header = static_cast<xml_memory_string_header*>(static_cast<void*>(string)) - 1;
     656                        assert(header);
    348657
    349658                        // deallocate
    350                         size_t page_offset = offsetof(xml_memory_page, data) + header->page_offset;
    351                         xml_memory_page* page = reinterpret_cast<xml_memory_page*>(reinterpret_cast<char*>(header) - page_offset);
     659                        size_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment;
     660                        xml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset));
    352661
    353662                        // if full_size == 0 then this string occupies the whole page
    354                         size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size;
     663                        size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment;
    355664
    356665                        deallocate_memory(header, full_size, page);
     666                }
     667
     668                bool reserve()
     669                {
     670                #ifdef PUGIXML_COMPACT
     671                        return _hash->reserve();
     672                #else
     673                        return true;
     674                #endif
    357675                }
    358676
    359677                xml_memory_page* _root;
    360678                size_t _busy_size;
     679
     680        #ifdef PUGIXML_COMPACT
     681                compact_hash_table* _hash;
     682        #endif
    361683        };
    362684
    363         PUGIXML_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)
     685        PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)
    364686        {
    365687                const size_t large_allocation_threshold = xml_memory_page_size / 4;
    366688
    367689                xml_memory_page* page = allocate_page(size <= large_allocation_threshold ? xml_memory_page_size : size);
     690                out_page = page;
     691
    368692                if (!page) return 0;
    369693
     
    390714                        _root->prev->next = page;
    391715                        _root->prev = page;
    392                 }
    393 
    394                 // allocate inside page
    395                 page->busy_size = size;
    396 
    397                 out_page = page;
    398                 return page->data;
    399         }
    400 }
    401 
     716
     717                        page->busy_size = size;
     718                }
     719
     720                return reinterpret_cast<char*>(page) + sizeof(xml_memory_page);
     721        }
     722PUGI__NS_END
     723
     724#ifdef PUGIXML_COMPACT
     725PUGI__NS_BEGIN
     726        static const uintptr_t compact_alignment_log2 = 2;
     727        static const uintptr_t compact_alignment = 1 << compact_alignment_log2;
     728
     729        class compact_header
     730        {
     731        public:
     732                compact_header(xml_memory_page* page, unsigned int flags)
     733                {
     734                        PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
     735
     736                        ptrdiff_t offset = (reinterpret_cast<char*>(this) - reinterpret_cast<char*>(page->compact_page_marker));
     737                        assert(offset % compact_alignment == 0 && static_cast<uintptr_t>(offset) < 256 * compact_alignment);
     738
     739                        _page = static_cast<unsigned char>(offset >> compact_alignment_log2);
     740                        _flags = static_cast<unsigned char>(flags);
     741                }
     742
     743                void operator&=(uintptr_t mod)
     744                {
     745                        _flags &= static_cast<unsigned char>(mod);
     746                }
     747
     748                void operator|=(uintptr_t mod)
     749                {
     750                        _flags |= static_cast<unsigned char>(mod);
     751                }
     752
     753                uintptr_t operator&(uintptr_t mod) const
     754                {
     755                        return _flags & mod;
     756                }
     757
     758                xml_memory_page* get_page() const
     759                {
     760                        // round-trip through void* to silence 'cast increases required alignment of target type' warnings
     761                        const char* page_marker = reinterpret_cast<const char*>(this) - (_page << compact_alignment_log2);
     762                        const char* page = page_marker - *reinterpret_cast<const uint32_t*>(static_cast<const void*>(page_marker));
     763
     764                        return const_cast<xml_memory_page*>(reinterpret_cast<const xml_memory_page*>(static_cast<const void*>(page)));
     765                }
     766
     767        private:
     768                unsigned char _page;
     769                unsigned char _flags;
     770        };
     771
     772        PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset)
     773        {
     774                const compact_header* header = reinterpret_cast<const compact_header*>(static_cast<const char*>(object) - header_offset);
     775
     776                return header->get_page();
     777        }
     778
     779        template <int header_offset, typename T> PUGI__FN_NO_INLINE T* compact_get_value(const void* object)
     780        {
     781                return static_cast<T*>(*compact_get_page(object, header_offset)->allocator->_hash->find(object));
     782        }
     783
     784        template <int header_offset, typename T> PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value)
     785        {
     786                *compact_get_page(object, header_offset)->allocator->_hash->insert(object) = value;
     787        }
     788
     789        template <typename T, int header_offset, int start = -126> class compact_pointer
     790        {
     791        public:
     792                compact_pointer(): _data(0)
     793                {
     794                }
     795
     796                void operator=(const compact_pointer& rhs)
     797                {
     798                        *this = rhs + 0;
     799                }
     800
     801                void operator=(T* value)
     802                {
     803                        if (value)
     804                        {
     805                                // value is guaranteed to be compact-aligned; 'this' is not
     806                                // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
     807                                // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
     808                                // compensate for arithmetic shift rounding for negative values
     809                                ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
     810                                ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start;
     811
     812                                if (static_cast<uintptr_t>(offset) <= 253)
     813                                        _data = static_cast<unsigned char>(offset + 1);
     814                                else
     815                                {
     816                                        compact_set_value<header_offset>(this, value);
     817
     818                                        _data = 255;
     819                                }
     820                        }
     821                        else
     822                                _data = 0;
     823                }
     824
     825                operator T*() const
     826                {
     827                        if (_data)
     828                        {
     829                                if (_data < 255)
     830                                {
     831                                        uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
     832
     833                                        return reinterpret_cast<T*>(base + ((_data - 1 + start) << compact_alignment_log2));
     834                                }
     835                                else
     836                                        return compact_get_value<header_offset, T>(this);
     837                        }
     838                        else
     839                                return 0;
     840                }
     841
     842                T* operator->() const
     843                {
     844                        return *this;
     845                }
     846
     847        private:
     848                unsigned char _data;
     849        };
     850
     851        template <typename T, int header_offset> class compact_pointer_parent
     852        {
     853        public:
     854                compact_pointer_parent(): _data(0)
     855                {
     856                }
     857
     858                void operator=(const compact_pointer_parent& rhs)
     859                {
     860                        *this = rhs + 0;
     861                }
     862
     863                void operator=(T* value)
     864                {
     865                        if (value)
     866                        {
     867                                // value is guaranteed to be compact-aligned; 'this' is not
     868                                // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
     869                                // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
     870                                // compensate for arithmetic shift behavior for negative values
     871                                ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
     872                                ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533;
     873
     874                                if (static_cast<uintptr_t>(offset) <= 65533)
     875                                {
     876                                        _data = static_cast<unsigned short>(offset + 1);
     877                                }
     878                                else
     879                                {
     880                                        xml_memory_page* page = compact_get_page(this, header_offset);
     881
     882                                        if (PUGI__UNLIKELY(page->compact_shared_parent == 0))
     883                                                page->compact_shared_parent = value;
     884
     885                                        if (page->compact_shared_parent == value)
     886                                        {
     887                                                _data = 65534;
     888                                        }
     889                                        else
     890                                        {
     891                                                compact_set_value<header_offset>(this, value);
     892
     893                                                _data = 65535;
     894                                        }
     895                                }
     896                        }
     897                        else
     898                        {
     899                                _data = 0;
     900                        }
     901                }
     902
     903                operator T*() const
     904                {
     905                        if (_data)
     906                        {
     907                                if (_data < 65534)
     908                                {
     909                                        uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
     910
     911                                        return reinterpret_cast<T*>(base + ((_data - 1 - 65533) << compact_alignment_log2));
     912                                }
     913                                else if (_data == 65534)
     914                                        return static_cast<T*>(compact_get_page(this, header_offset)->compact_shared_parent);
     915                                else
     916                                        return compact_get_value<header_offset, T>(this);
     917                        }
     918                        else
     919                                return 0;
     920                }
     921
     922                T* operator->() const
     923                {
     924                        return *this;
     925                }
     926
     927        private:
     928                uint16_t _data;
     929        };
     930
     931        template <int header_offset, int base_offset> class compact_string
     932        {
     933        public:
     934                compact_string(): _data(0)
     935                {
     936                }
     937
     938                void operator=(const compact_string& rhs)
     939                {
     940                        *this = rhs + 0;
     941                }
     942
     943                void operator=(char_t* value)
     944                {
     945                        if (value)
     946                        {
     947                                xml_memory_page* page = compact_get_page(this, header_offset);
     948
     949                                if (PUGI__UNLIKELY(page->compact_string_base == 0))
     950                                        page->compact_string_base = value;
     951
     952                                ptrdiff_t offset = value - page->compact_string_base;
     953
     954                                if (static_cast<uintptr_t>(offset) < (65535 << 7))
     955                                {
     956                                        // round-trip through void* to silence 'cast increases required alignment of target type' warnings
     957                                        uint16_t* base = reinterpret_cast<uint16_t*>(static_cast<void*>(reinterpret_cast<char*>(this) - base_offset));
     958
     959                                        if (*base == 0)
     960                                        {
     961                                                *base = static_cast<uint16_t>((offset >> 7) + 1);
     962                                                _data = static_cast<unsigned char>((offset & 127) + 1);
     963                                        }
     964                                        else
     965                                        {
     966                                                ptrdiff_t remainder = offset - ((*base - 1) << 7);
     967
     968                                                if (static_cast<uintptr_t>(remainder) <= 253)
     969                                                {
     970                                                        _data = static_cast<unsigned char>(remainder + 1);
     971                                                }
     972                                                else
     973                                                {
     974                                                        compact_set_value<header_offset>(this, value);
     975
     976                                                        _data = 255;
     977                                                }
     978                                        }
     979                                }
     980                                else
     981                                {
     982                                        compact_set_value<header_offset>(this, value);
     983
     984                                        _data = 255;
     985                                }
     986                        }
     987                        else
     988                        {
     989                                _data = 0;
     990                        }
     991                }
     992
     993                operator char_t*() const
     994                {
     995                        if (_data)
     996                        {
     997                                if (_data < 255)
     998                                {
     999                                        xml_memory_page* page = compact_get_page(this, header_offset);
     1000
     1001                                        // round-trip through void* to silence 'cast increases required alignment of target type' warnings
     1002                                        const uint16_t* base = reinterpret_cast<const uint16_t*>(static_cast<const void*>(reinterpret_cast<const char*>(this) - base_offset));
     1003                                        assert(*base);
     1004
     1005                                        ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);
     1006
     1007                                        return page->compact_string_base + offset;
     1008                                }
     1009                                else
     1010                                {
     1011                                        return compact_get_value<header_offset, char_t>(this);
     1012                                }
     1013                        }
     1014                        else
     1015                                return 0;
     1016                }
     1017
     1018        private:
     1019                unsigned char _data;
     1020        };
     1021PUGI__NS_END
     1022#endif
     1023
     1024#ifdef PUGIXML_COMPACT
    4021025namespace pugi
    4031026{
    404         /// A 'name=value' XML attribute structure.
    4051027        struct xml_attribute_struct
    4061028        {
    407                 /// Default ctor
    408                 xml_attribute_struct(xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0)
    409                 {
    410                 }
    411 
    412                 uintptr_t header;
    413 
    414                 char_t* name;   ///< Pointer to attribute name.
    415                 char_t* value;  ///< Pointer to attribute value.
    416 
    417                 xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list)
    418                 xml_attribute_struct* next_attribute;   ///< Next attribute
     1029                xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)
     1030                {
     1031                        PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8);
     1032                }
     1033
     1034                impl::compact_header header;
     1035
     1036                uint16_t namevalue_base;
     1037
     1038                impl::compact_string<4, 2> name;
     1039                impl::compact_string<5, 3> value;
     1040
     1041                impl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c;
     1042                impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute;
    4191043        };
    4201044
    421         /// An XML document tree node.
    4221045        struct xml_node_struct
    4231046        {
    424                 /// Default ctor
    425                 /// \param type - node type
    426                 xml_node_struct(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)
    427                 {
    428                 }
    429 
    430                 uintptr_t header;
    431 
    432                 xml_node_struct*                parent;                                 ///< Pointer to parent
    433 
    434                 char_t*                                 name;                                   ///< Pointer to element name.
    435                 char_t*                                 value;                                  ///< Pointer to any associated string data.
    436 
    437                 xml_node_struct*                first_child;                    ///< First child
    438                
    439                 xml_node_struct*                prev_sibling_c;                 ///< Left brother (cyclic list)
    440                 xml_node_struct*                next_sibling;                   ///< Right brother
    441                
    442                 xml_attribute_struct*   first_attribute;                ///< First attribute
     1047                xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0)
     1048                {
     1049                        PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12);
     1050                }
     1051
     1052                impl::compact_header header;
     1053
     1054                uint16_t namevalue_base;
     1055
     1056                impl::compact_string<4, 2> name;
     1057                impl::compact_string<5, 3> value;
     1058
     1059                impl::compact_pointer_parent<xml_node_struct, 6> parent;
     1060
     1061                impl::compact_pointer<xml_node_struct, 8, 0> first_child;
     1062
     1063                impl::compact_pointer<xml_node_struct,  9>    prev_sibling_c;
     1064                impl::compact_pointer<xml_node_struct, 10, 0> next_sibling;
     1065
     1066                impl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute;
    4431067        };
    4441068}
    445 
    446 namespace
     1069#else
     1070namespace pugi
    4471071{
     1072        struct xml_attribute_struct
     1073        {
     1074                xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0)
     1075                {
     1076                        header = PUGI__GETHEADER_IMPL(this, page, 0);
     1077                }
     1078
     1079                uintptr_t header;
     1080
     1081                char_t* name;
     1082                char_t* value;
     1083
     1084                xml_attribute_struct* prev_attribute_c;
     1085                xml_attribute_struct* next_attribute;
     1086        };
     1087
     1088        struct xml_node_struct
     1089        {
     1090                xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
     1091                {
     1092                        header = PUGI__GETHEADER_IMPL(this, page, type);
     1093                }
     1094
     1095                uintptr_t header;
     1096
     1097                char_t* name;
     1098                char_t* value;
     1099
     1100                xml_node_struct* parent;
     1101
     1102                xml_node_struct* first_child;
     1103
     1104                xml_node_struct* prev_sibling_c;
     1105                xml_node_struct* next_sibling;
     1106
     1107                xml_attribute_struct* first_attribute;
     1108        };
     1109}
     1110#endif
     1111
     1112PUGI__NS_BEGIN
     1113        struct xml_extra_buffer
     1114        {
     1115                char_t* buffer;
     1116                xml_extra_buffer* next;
     1117        };
     1118
    4481119        struct xml_document_struct: public xml_node_struct, public xml_allocator
    4491120        {
    450                 xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0)
     1121                xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0)
    4511122                {
    4521123                }
    4531124
    4541125                const char_t* buffer;
     1126
     1127                xml_extra_buffer* extra_buffers;
     1128
     1129        #ifdef PUGIXML_COMPACT
     1130                compact_hash_table hash;
     1131        #endif
    4551132        };
    4561133
    457         static inline xml_allocator& get_allocator(const xml_node_struct* node)
    458         {
    459                 assert(node);
    460 
    461                 return *reinterpret_cast<xml_memory_page*>(node->header & xml_memory_page_pointer_mask)->allocator;
    462         }
    463 }
     1134        template <typename Object> inline xml_allocator& get_allocator(const Object* object)
     1135        {
     1136                assert(object);
     1137
     1138                return *PUGI__GETPAGE(object)->allocator;
     1139        }
     1140
     1141        template <typename Object> inline xml_document_struct& get_document(const Object* object)
     1142        {
     1143                assert(object);
     1144
     1145                return *static_cast<xml_document_struct*>(PUGI__GETPAGE(object)->allocator);
     1146        }
     1147PUGI__NS_END
    4641148
    4651149// Low-level DOM operations
    466 namespace
    467 {
     1150PUGI__NS_BEGIN
    4681151        inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
    4691152        {
    4701153                xml_memory_page* page;
    471                 void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page);
     1154                void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page);
     1155                if (!memory) return 0;
    4721156
    4731157                return new (memory) xml_attribute_struct(page);
     
    4771161        {
    4781162                xml_memory_page* page;
    479                 void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page);
     1163                void* memory = alloc.allocate_object(sizeof(xml_node_struct), page);
     1164                if (!memory) return 0;
    4801165
    4811166                return new (memory) xml_node_struct(page, type);
     
    4841169        inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
    4851170        {
    486                 uintptr_t header = a->header;
    487 
    488                 if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name);
    489                 if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value);
    490 
    491                 alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
     1171                if (a->header & impl::xml_memory_page_name_allocated_mask)
     1172                        alloc.deallocate_string(a->name);
     1173
     1174                if (a->header & impl::xml_memory_page_value_allocated_mask)
     1175                        alloc.deallocate_string(a->value);
     1176
     1177                alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a));
    4921178        }
    4931179
    4941180        inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
    4951181        {
    496                 uintptr_t header = n->header;
    497 
    498                 if (header & xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name);
    499                 if (header & xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value);
     1182                if (n->header & impl::xml_memory_page_name_allocated_mask)
     1183                        alloc.deallocate_string(n->name);
     1184
     1185                if (n->header & impl::xml_memory_page_value_allocated_mask)
     1186                        alloc.deallocate_string(n->value);
    5001187
    5011188                for (xml_attribute_struct* attr = n->first_attribute; attr; )
     
    5171204                }
    5181205
    519                 alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
    520         }
    521 
    522         PUGIXML_NO_INLINE xml_node_struct* append_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
    523         {
     1206                alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n));
     1207        }
     1208
     1209        inline void append_node(xml_node_struct* child, xml_node_struct* node)
     1210        {
     1211                child->parent = node;
     1212
     1213                xml_node_struct* head = node->first_child;
     1214
     1215                if (head)
     1216                {
     1217                        xml_node_struct* tail = head->prev_sibling_c;
     1218
     1219                        tail->next_sibling = child;
     1220                        child->prev_sibling_c = tail;
     1221                        head->prev_sibling_c = child;
     1222                }
     1223                else
     1224                {
     1225                        node->first_child = child;
     1226                        child->prev_sibling_c = child;
     1227                }
     1228        }
     1229
     1230        inline void prepend_node(xml_node_struct* child, xml_node_struct* node)
     1231        {
     1232                child->parent = node;
     1233
     1234                xml_node_struct* head = node->first_child;
     1235
     1236                if (head)
     1237                {
     1238                        child->prev_sibling_c = head->prev_sibling_c;
     1239                        head->prev_sibling_c = child;
     1240                }
     1241                else
     1242                        child->prev_sibling_c = child;
     1243
     1244                child->next_sibling = head;
     1245                node->first_child = child;
     1246        }
     1247
     1248        inline void insert_node_after(xml_node_struct* child, xml_node_struct* node)
     1249        {
     1250                xml_node_struct* parent = node->parent;
     1251
     1252                child->parent = parent;
     1253
     1254                if (node->next_sibling)
     1255                        node->next_sibling->prev_sibling_c = child;
     1256                else
     1257                        parent->first_child->prev_sibling_c = child;
     1258
     1259                child->next_sibling = node->next_sibling;
     1260                child->prev_sibling_c = node;
     1261
     1262                node->next_sibling = child;
     1263        }
     1264
     1265        inline void insert_node_before(xml_node_struct* child, xml_node_struct* node)
     1266        {
     1267                xml_node_struct* parent = node->parent;
     1268
     1269                child->parent = parent;
     1270
     1271                if (node->prev_sibling_c->next_sibling)
     1272                        node->prev_sibling_c->next_sibling = child;
     1273                else
     1274                        parent->first_child = child;
     1275
     1276                child->prev_sibling_c = node->prev_sibling_c;
     1277                child->next_sibling = node;
     1278
     1279                node->prev_sibling_c = child;
     1280        }
     1281
     1282        inline void remove_node(xml_node_struct* node)
     1283        {
     1284                xml_node_struct* parent = node->parent;
     1285
     1286                if (node->next_sibling)
     1287                        node->next_sibling->prev_sibling_c = node->prev_sibling_c;
     1288                else
     1289                        parent->first_child->prev_sibling_c = node->prev_sibling_c;
     1290
     1291                if (node->prev_sibling_c->next_sibling)
     1292                        node->prev_sibling_c->next_sibling = node->next_sibling;
     1293                else
     1294                        parent->first_child = node->next_sibling;
     1295
     1296                node->parent = 0;
     1297                node->prev_sibling_c = 0;
     1298                node->next_sibling = 0;
     1299        }
     1300
     1301        inline void append_attribute(xml_attribute_struct* attr, xml_node_struct* node)
     1302        {
     1303                xml_attribute_struct* head = node->first_attribute;
     1304
     1305                if (head)
     1306                {
     1307                        xml_attribute_struct* tail = head->prev_attribute_c;
     1308
     1309                        tail->next_attribute = attr;
     1310                        attr->prev_attribute_c = tail;
     1311                        head->prev_attribute_c = attr;
     1312                }
     1313                else
     1314                {
     1315                        node->first_attribute = attr;
     1316                        attr->prev_attribute_c = attr;
     1317                }
     1318        }
     1319
     1320        inline void prepend_attribute(xml_attribute_struct* attr, xml_node_struct* node)
     1321        {
     1322                xml_attribute_struct* head = node->first_attribute;
     1323
     1324                if (head)
     1325                {
     1326                        attr->prev_attribute_c = head->prev_attribute_c;
     1327                        head->prev_attribute_c = attr;
     1328                }
     1329                else
     1330                        attr->prev_attribute_c = attr;
     1331
     1332                attr->next_attribute = head;
     1333                node->first_attribute = attr;
     1334        }
     1335
     1336        inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
     1337        {
     1338                if (place->next_attribute)
     1339                        place->next_attribute->prev_attribute_c = attr;
     1340                else
     1341                        node->first_attribute->prev_attribute_c = attr;
     1342
     1343                attr->next_attribute = place->next_attribute;
     1344                attr->prev_attribute_c = place;
     1345                place->next_attribute = attr;
     1346        }
     1347
     1348        inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node)
     1349        {
     1350                if (place->prev_attribute_c->next_attribute)
     1351                        place->prev_attribute_c->next_attribute = attr;
     1352                else
     1353                        node->first_attribute = attr;
     1354
     1355                attr->prev_attribute_c = place->prev_attribute_c;
     1356                attr->next_attribute = place;
     1357                place->prev_attribute_c = attr;
     1358        }
     1359
     1360        inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node)
     1361        {
     1362                if (attr->next_attribute)
     1363                        attr->next_attribute->prev_attribute_c = attr->prev_attribute_c;
     1364                else
     1365                        node->first_attribute->prev_attribute_c = attr->prev_attribute_c;
     1366
     1367                if (attr->prev_attribute_c->next_attribute)
     1368                        attr->prev_attribute_c->next_attribute = attr->next_attribute;
     1369                else
     1370                        node->first_attribute = attr->next_attribute;
     1371
     1372                attr->prev_attribute_c = 0;
     1373                attr->next_attribute = 0;
     1374        }
     1375
     1376        PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
     1377        {
     1378                if (!alloc.reserve()) return 0;
     1379
    5241380                xml_node_struct* child = allocate_node(alloc, type);
    5251381                if (!child) return 0;
    5261382
    527                 child->parent = node;
    528 
    529                 xml_node_struct* first_child = node->first_child;
    530                        
    531                 if (first_child)
    532                 {
    533                         xml_node_struct* last_child = first_child->prev_sibling_c;
    534 
    535                         last_child->next_sibling = child;
    536                         child->prev_sibling_c = last_child;
    537                         first_child->prev_sibling_c = child;
    538                 }
    539                 else
    540                 {
    541                         node->first_child = child;
    542                         child->prev_sibling_c = child;
    543                 }
    544                        
     1383                append_node(child, node);
     1384
    5451385                return child;
    5461386        }
    5471387
    548         PUGIXML_NO_INLINE xml_attribute_struct* append_attribute_ll(xml_node_struct* node, xml_allocator& alloc)
    549         {
    550                 xml_attribute_struct* a = allocate_attribute(alloc);
    551                 if (!a) return 0;
    552 
    553                 xml_attribute_struct* first_attribute = node->first_attribute;
    554 
    555                 if (first_attribute)
    556                 {
    557                         xml_attribute_struct* last_attribute = first_attribute->prev_attribute_c;
    558 
    559                         last_attribute->next_attribute = a;
    560                         a->prev_attribute_c = last_attribute;
    561                         first_attribute->prev_attribute_c = a;
    562                 }
    563                 else
    564                 {
    565                         node->first_attribute = a;
    566                         a->prev_attribute_c = a;
    567                 }
    568                        
    569                 return a;
    570         }
    571 }
     1388        PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)
     1389        {
     1390                if (!alloc.reserve()) return 0;
     1391
     1392                xml_attribute_struct* attr = allocate_attribute(alloc);
     1393                if (!attr) return 0;
     1394
     1395                append_attribute(attr, node);
     1396
     1397                return attr;
     1398        }
     1399PUGI__NS_END
    5721400
    5731401// Helper classes for code generation
    574 namespace
    575 {
     1402PUGI__NS_BEGIN
    5761403        struct opt_false
    5771404        {
     
    5831410                enum { value = 1 };
    5841411        };
    585 }
     1412PUGI__NS_END
    5861413
    5871414// Unicode utilities
    588 namespace
    589 {
     1415PUGI__NS_BEGIN
    5901416        inline uint16_t endian_swap(uint16_t value)
    5911417        {
     
    6921518                static value_type high(value_type result, uint32_t ch)
    6931519                {
    694                         uint32_t msh = (uint32_t)(ch - 0x10000) >> 10;
    695                         uint32_t lsh = (uint32_t)(ch - 0x10000) & 0x3ff;
     1520                        uint32_t msh = static_cast<uint32_t>(ch - 0x10000) >> 10;
     1521                        uint32_t lsh = static_cast<uint32_t>(ch - 0x10000) & 0x3ff;
    6961522
    6971523                        result[0] = static_cast<uint16_t>(0xD800 + msh);
     
    7481574        };
    7491575
    750         template <size_t size> struct wchar_selector;
    751 
    752         template <> struct wchar_selector<2>
    753         {
    754                 typedef uint16_t type;
    755                 typedef utf16_counter counter;
    756                 typedef utf16_writer writer;
     1576        struct latin1_writer
     1577        {
     1578                typedef uint8_t* value_type;
     1579
     1580                static value_type low(value_type result, uint32_t ch)
     1581                {
     1582                        *result = static_cast<uint8_t>(ch > 255 ? '?' : ch);
     1583
     1584                        return result + 1;
     1585                }
     1586
     1587                static value_type high(value_type result, uint32_t ch)
     1588                {
     1589                        (void)ch;
     1590
     1591                        *result = '?';
     1592
     1593                        return result + 1;
     1594                }
    7571595        };
    7581596
    759         template <> struct wchar_selector<4>
    760         {
    761                 typedef uint32_t type;
    762                 typedef utf32_counter counter;
    763                 typedef utf32_writer writer;
    764         };
    765 
    766         typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
    767         typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
    768 
    769         template <typename Traits, typename opt_swap = opt_false> struct utf_decoder
    770         {
    771                 static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result)
     1597        struct utf8_decoder
     1598        {
     1599                typedef uint8_t type;
     1600
     1601                template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
    7721602                {
    7731603                        const uint8_t utf8_byte_mask = 0x3f;
     
    7871617                                        if ((reinterpret_cast<uintptr_t>(data) & 3) == 0)
    7881618                                        {
    789                                                 while (size >= 4 && (*reinterpret_cast<const uint32_t*>(data) & 0x80808080) == 0)
     1619                                                // round-trip through void* to silence 'cast increases required alignment of target type' warnings
     1620                                                while (size >= 4 && (*static_cast<const uint32_t*>(static_cast<const void*>(data)) & 0x80808080) == 0)
    7901621                                                {
    7911622                                                        result = Traits::low(result, data[0]);
     
    7991630                                }
    8001631                                // 110xxxxx -> U+0080..U+07FF
    801                                 else if ((unsigned)(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
     1632                                else if (static_cast<unsigned int>(lead - 0xC0) < 0x20 && size >= 2 && (data[1] & 0xc0) == 0x80)
    8021633                                {
    8031634                                        result = Traits::low(result, ((lead & ~0xC0) << 6) | (data[1] & utf8_byte_mask));
     
    8061637                                }
    8071638                                // 1110xxxx -> U+0800-U+FFFF
    808                                 else if ((unsigned)(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
     1639                                else if (static_cast<unsigned int>(lead - 0xE0) < 0x10 && size >= 3 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80)
    8091640                                {
    8101641                                        result = Traits::low(result, ((lead & ~0xE0) << 12) | ((data[1] & utf8_byte_mask) << 6) | (data[2] & utf8_byte_mask));
     
    8131644                                }
    8141645                                // 11110xxx -> U+10000..U+10FFFF
    815                                 else if ((unsigned)(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
     1646                                else if (static_cast<unsigned int>(lead - 0xF0) < 0x08 && size >= 4 && (data[1] & 0xc0) == 0x80 && (data[2] & 0xc0) == 0x80 && (data[3] & 0xc0) == 0x80)
    8161647                                {
    8171648                                        result = Traits::high(result, ((lead & ~0xF0) << 18) | ((data[1] & utf8_byte_mask) << 12) | ((data[2] & utf8_byte_mask) << 6) | (data[3] & utf8_byte_mask));
     
    8291660                        return result;
    8301661                }
    831 
    832                 static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result)
    833                 {
    834                         const uint16_t* end = data + size;
    835 
    836                         while (data < end)
     1662        };
     1663
     1664        template <typename opt_swap> struct utf16_decoder
     1665        {
     1666                typedef uint16_t type;
     1667
     1668                template <typename Traits> static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits)
     1669                {
     1670                        while (size)
    8371671                        {
    8381672                                uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
     
    8431677                                        result = Traits::low(result, lead);
    8441678                                        data += 1;
     1679                                        size -= 1;
    8451680                                }
    8461681                                // U+E000..U+FFFF
    847                                 else if ((unsigned)(lead - 0xE000) < 0x2000)
     1682                                else if (static_cast<unsigned int>(lead - 0xE000) < 0x2000)
    8481683                                {
    8491684                                        result = Traits::low(result, lead);
    8501685                                        data += 1;
     1686                                        size -= 1;
    8511687                                }
    8521688                                // surrogate pair lead
    853                                 else if ((unsigned)(lead - 0xD800) < 0x400 && data + 1 < end)
     1689                                else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
    8541690                                {
    8551691                                        uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
    8561692
    857                                         if ((unsigned)(next - 0xDC00) < 0x400)
     1693                                        if (static_cast<unsigned int>(next - 0xDC00) < 0x400)
    8581694                                        {
    8591695                                                result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
    8601696                                                data += 2;
     1697                                                size -= 2;
    8611698                                        }
    8621699                                        else
    8631700                                        {
    8641701                                                data += 1;
     1702                                                size -= 1;
    8651703                                        }
    8661704                                }
     
    8681706                                {
    8691707                                        data += 1;
     1708                                        size -= 1;
    8701709                                }
    8711710                        }
     
    8731712                        return result;
    8741713                }
    875 
    876                 static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result)
    877                 {
    878                         const uint32_t* end = data + size;
    879 
    880                         while (data < end)
     1714        };
     1715
     1716        template <typename opt_swap> struct utf32_decoder
     1717        {
     1718                typedef uint32_t type;
     1719
     1720                template <typename Traits> static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits)
     1721                {
     1722                        while (size)
    8811723                        {
    8821724                                uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
     
    8871729                                        result = Traits::low(result, lead);
    8881730                                        data += 1;
     1731                                        size -= 1;
    8891732                                }
    8901733                                // U+10000..U+10FFFF
     
    8931736                                        result = Traits::high(result, lead);
    8941737                                        data += 1;
     1738                                        size -= 1;
    8951739                                }
    8961740                        }
     
    9001744        };
    9011745
    902         template <typename T> inline void convert_utf_endian_swap(T* result, const T* data, size_t length)
    903         {
    904                 for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]);
    905         }
    906 
    907         inline void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
    908         {
    909                 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])));
    910         }
    911 }
    912 
    913 namespace
    914 {       
     1746        struct latin1_decoder
     1747        {
     1748                typedef uint8_t type;
     1749
     1750                template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
     1751                {
     1752                        while (size)
     1753                        {
     1754                                result = Traits::low(result, *data);
     1755                                data += 1;
     1756                                size -= 1;
     1757                        }
     1758
     1759                        return result;
     1760                }
     1761        };
     1762
     1763        template <size_t size> struct wchar_selector;
     1764
     1765        template <> struct wchar_selector<2>
     1766        {
     1767                typedef uint16_t type;
     1768                typedef utf16_counter counter;
     1769                typedef utf16_writer writer;
     1770                typedef utf16_decoder<opt_false> decoder;
     1771        };
     1772
     1773        template <> struct wchar_selector<4>
     1774        {
     1775                typedef uint32_t type;
     1776                typedef utf32_counter counter;
     1777                typedef utf32_writer writer;
     1778                typedef utf32_decoder<opt_false> decoder;
     1779        };
     1780
     1781        typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
     1782        typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
     1783
     1784        struct wchar_decoder
     1785        {
     1786                typedef wchar_t type;
     1787
     1788                template <typename Traits> static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits)
     1789                {
     1790                        typedef wchar_selector<sizeof(wchar_t)>::decoder decoder;
     1791
     1792                        return decoder::process(reinterpret_cast<const typename decoder::type*>(data), size, result, traits);
     1793                }
     1794        };
     1795
     1796#ifdef PUGIXML_WCHAR_MODE
     1797        PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
     1798        {
     1799                for (size_t i = 0; i < length; ++i)
     1800                        result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
     1801        }
     1802#endif
     1803PUGI__NS_END
     1804
     1805PUGI__NS_BEGIN
    9151806        enum chartype_t
    9161807        {
     
    9251816        };
    9261817
    927         const unsigned char chartype_table[256] =
     1818        static const unsigned char chartype_table[256] =
    9281819        {
    9291820                55,  0,   0,   0,   0,   0,   0,   0,      0,   12,  12,  0,   0,   63,  0,   0,   // 0-15
     
    9541845                ctx_symbol = 16                   // Any symbol > 127, a-z, A-Z, 0-9, _, -, .
    9551846        };
    956        
    957         const unsigned char chartypex_table[256] =
     1847
     1848        static const unsigned char chartypex_table[256] =
    9581849        {
    9591850                3,  3,  3,  3,  3,  3,  3,  3,     3,  0,  2,  3,  3,  2,  3,  3,     // 0-15
     
    9761867                20, 20, 20, 20, 20, 20, 20, 20,    20, 20, 20, 20, 20, 20, 20, 20
    9771868        };
    978        
     1869
    9791870#ifdef PUGIXML_WCHAR_MODE
    980         #define IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
     1871        #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
    9811872#else
    982         #define IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
     1873        #define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
    9831874#endif
    9841875
    985         #define IS_CHARTYPE(c, ct) IS_CHARTYPE_IMPL(c, ct, chartype_table)
    986         #define IS_CHARTYPEX(c, ct) IS_CHARTYPE_IMPL(c, ct, chartypex_table)
    987 
    988         bool is_little_endian()
     1876        #define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
     1877        #define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
     1878
     1879        PUGI__FN bool is_little_endian()
    9891880        {
    9901881                unsigned int ui = 1;
     
    9931884        }
    9941885
    995         xml_encoding get_wchar_encoding()
    996         {
    997                 STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
     1886        PUGI__FN xml_encoding get_wchar_encoding()
     1887        {
     1888                PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
    9981889
    9991890                if (sizeof(wchar_t) == 2)
    10001891                        return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
    1001                 else 
     1892                else
    10021893                        return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
    10031894        }
    10041895
    1005         xml_encoding guess_buffer_encoding(uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
    1006         {
     1896        PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length)
     1897        {
     1898        #define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
     1899        #define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; }
     1900
     1901                // check if we have a non-empty XML declaration
     1902                if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space)))
     1903                        return false;
     1904
     1905                // scan XML declaration until the encoding field
     1906                for (size_t i = 6; i + 1 < size; ++i)
     1907                {
     1908                        // declaration can not contain ? in quoted values
     1909                        if (data[i] == '?')
     1910                                return false;
     1911
     1912                        if (data[i] == 'e' && data[i + 1] == 'n')
     1913                        {
     1914                                size_t offset = i;
     1915
     1916                                // encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed
     1917                                PUGI__SCANCHAR('e'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('c'); PUGI__SCANCHAR('o');
     1918                                PUGI__SCANCHAR('d'); PUGI__SCANCHAR('i'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('g');
     1919
     1920                                // S? = S?
     1921                                PUGI__SCANCHARTYPE(ct_space);
     1922                                PUGI__SCANCHAR('=');
     1923                                PUGI__SCANCHARTYPE(ct_space);
     1924
     1925                                // the only two valid delimiters are ' and "
     1926                                uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\'';
     1927
     1928                                PUGI__SCANCHAR(delimiter);
     1929
     1930                                size_t start = offset;
     1931
     1932                                out_encoding = data + offset;
     1933
     1934                                PUGI__SCANCHARTYPE(ct_symbol);
     1935
     1936                                out_length = offset - start;
     1937
     1938                                PUGI__SCANCHAR(delimiter);
     1939
     1940                                return true;
     1941                        }
     1942                }
     1943
     1944                return false;
     1945
     1946        #undef PUGI__SCANCHAR
     1947        #undef PUGI__SCANCHARTYPE
     1948        }
     1949
     1950        PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size)
     1951        {
     1952                // skip encoding autodetection if input buffer is too small
     1953                if (size < 4) return encoding_utf8;
     1954
     1955                uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
     1956
    10071957                // look for BOM in first few bytes
    10081958                if (d0 == 0 && d1 == 0 && d2 == 0xfe && d3 == 0xff) return encoding_utf32_be;
     
    10171967                if (d0 == 0 && d1 == 0x3c && d2 == 0 && d3 == 0x3f) return encoding_utf16_be;
    10181968                if (d0 == 0x3c && d1 == 0 && d2 == 0x3f && d3 == 0) return encoding_utf16_le;
    1019                 if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d) return encoding_utf8;
    10201969
    10211970                // look for utf16 < followed by node name (this may fail, but is better than utf8 since it's zero terminated so early)
     
    10231972                if (d0 == 0x3c && d1 == 0) return encoding_utf16_le;
    10241973
    1025                 // no known BOM detected, assume utf8
     1974                // no known BOM detected; parse declaration
     1975                const uint8_t* enc = 0;
     1976                size_t enc_length = 0;
     1977
     1978                if (d0 == 0x3c && d1 == 0x3f && d2 == 0x78 && d3 == 0x6d && parse_declaration_encoding(data, size, enc, enc_length))
     1979                {
     1980                        // iso-8859-1 (case-insensitive)
     1981                        if (enc_length == 10
     1982                                && (enc[0] | ' ') == 'i' && (enc[1] | ' ') == 's' && (enc[2] | ' ') == 'o'
     1983                                && enc[3] == '-' && enc[4] == '8' && enc[5] == '8' && enc[6] == '5' && enc[7] == '9'
     1984                                && enc[8] == '-' && enc[9] == '1')
     1985                                return encoding_latin1;
     1986
     1987                        // latin1 (case-insensitive)
     1988                        if (enc_length == 6
     1989                                && (enc[0] | ' ') == 'l' && (enc[1] | ' ') == 'a' && (enc[2] | ' ') == 't'
     1990                                && (enc[3] | ' ') == 'i' && (enc[4] | ' ') == 'n'
     1991                                && enc[5] == '1')
     1992                                return encoding_latin1;
     1993                }
     1994
    10261995                return encoding_utf8;
    10271996        }
    10281997
    1029         xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
     1998        PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
    10301999        {
    10312000                // replace wchar encoding with utf implementation
     
    10412010                if (encoding != encoding_auto) return encoding;
    10422011
    1043                 // skip encoding autodetection if input buffer is too small
    1044                 if (size < 4) return encoding_utf8;
    1045 
    10462012                // try to guess encoding (based on XML specification, Appendix F.1)
    10472013                const uint8_t* data = static_cast<const uint8_t*>(contents);
    10482014
    1049                 DMC_VOLATILE uint8_t d0 = data[0], d1 = data[1], d2 = data[2], d3 = data[3];
    1050 
    1051                 return guess_buffer_encoding(d0, d1, d2, d3);
    1052         }
    1053 
    1054         bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
    1055         {
     2015                return guess_buffer_encoding(data, size);
     2016        }
     2017
     2018        PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
     2019        {
     2020                size_t length = size / sizeof(char_t);
     2021
    10562022                if (is_mutable)
    10572023                {
    10582024                        out_buffer = static_cast<char_t*>(const_cast<void*>(contents));
     2025                        out_length = length;
    10592026                }
    10602027                else
    10612028                {
    1062                         void* buffer = global_allocate(size > 0 ? size : 1);
     2029                        char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
    10632030                        if (!buffer) return false;
    10642031
    1065                         memcpy(buffer, contents, size);
    1066 
    1067                         out_buffer = static_cast<char_t*>(buffer);
    1068                 }
    1069 
    1070                 out_length = size / sizeof(char_t);
     2032                        if (contents)
     2033                                memcpy(buffer, contents, length * sizeof(char_t));
     2034                        else
     2035                                assert(length == 0);
     2036
     2037                        buffer[length] = 0;
     2038
     2039                        out_buffer = buffer;
     2040                        out_length = length + 1;
     2041                }
    10712042
    10722043                return true;
     
    10742045
    10752046#ifdef PUGIXML_WCHAR_MODE
    1076         inline bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
     2047        PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
    10772048        {
    10782049                return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
    1079                        (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
    1080         }
    1081 
    1082         bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
     2050                           (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
     2051        }
     2052
     2053        PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
    10832054        {
    10842055                const char_t* data = static_cast<const char_t*>(contents);
    1085        
     2056                size_t length = size / sizeof(char_t);
     2057
    10862058                if (is_mutable)
    10872059                {
    1088                         out_buffer = const_cast<char_t*>(data);
     2060                        char_t* buffer = const_cast<char_t*>(data);
     2061
     2062                        convert_wchar_endian_swap(buffer, data, length);
     2063
     2064                        out_buffer = buffer;
     2065                        out_length = length;
    10892066                }
    10902067                else
    10912068                {
    1092                         out_buffer = static_cast<char_t*>(global_allocate(size > 0 ? size : 1));
    1093                         if (!out_buffer) return false;
    1094                 }
    1095 
    1096                 out_length = size / sizeof(char_t);
    1097 
    1098                 convert_wchar_endian_swap(out_buffer, data, out_length);
     2069                        char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
     2070                        if (!buffer) return false;
     2071
     2072                        convert_wchar_endian_swap(buffer, data, length);
     2073                        buffer[length] = 0;
     2074
     2075                        out_buffer = buffer;
     2076                        out_length = length + 1;
     2077                }
    10992078
    11002079                return true;
    11012080        }
    11022081
    1103         bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size)
    1104         {
    1105                 const uint8_t* data = static_cast<const uint8_t*>(contents);
     2082        template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
     2083        {
     2084                const typename D::type* data = static_cast<const typename D::type*>(contents);
     2085                size_t data_length = size / sizeof(typename D::type);
    11062086
    11072087                // first pass: get length in wchar_t units
    1108                 out_length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
     2088                size_t length = D::process(data, data_length, 0, wchar_counter());
    11092089
    11102090                // allocate buffer of suitable length
    1111                 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
    1112                 if (!out_buffer) return false;
    1113 
    1114                 // second pass: convert utf8 input to wchar_t
    1115                 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
    1116                 wchar_writer::value_type out_end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, out_begin);
    1117 
    1118                 assert(out_end == out_begin + out_length);
    1119                 (void)!out_end;
     2091                char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
     2092                if (!buffer) return false;
     2093
     2094                // second pass: convert utf16 input to wchar_t
     2095                wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
     2096                wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer());
     2097
     2098                assert(oend == obegin + length);
     2099                *oend = 0;
     2100
     2101                out_buffer = buffer;
     2102                out_length = length + 1;
    11202103
    11212104                return true;
    11222105        }
    11232106
    1124         template <typename opt_swap> bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
    1125         {
    1126                 const uint16_t* data = static_cast<const uint16_t*>(contents);
    1127                 size_t length = size / sizeof(uint16_t);
    1128 
    1129                 // first pass: get length in wchar_t units
    1130                 out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf16_block(data, length, 0);
    1131 
    1132                 // allocate buffer of suitable length
    1133                 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
    1134                 if (!out_buffer) return false;
    1135 
    1136                 // second pass: convert utf16 input to wchar_t
    1137                 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
    1138                 wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, length, out_begin);
    1139 
    1140                 assert(out_end == out_begin + out_length);
    1141                 (void)!out_end;
    1142 
    1143                 return true;
    1144         }
    1145 
    1146         template <typename opt_swap> bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
    1147         {
    1148                 const uint32_t* data = static_cast<const uint32_t*>(contents);
    1149                 size_t length = size / sizeof(uint32_t);
    1150 
    1151                 // first pass: get length in wchar_t units
    1152                 out_length = utf_decoder<wchar_counter, opt_swap>::decode_utf32_block(data, length, 0);
    1153 
    1154                 // allocate buffer of suitable length
    1155                 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
    1156                 if (!out_buffer) return false;
    1157 
    1158                 // second pass: convert utf32 input to wchar_t
    1159                 wchar_writer::value_type out_begin = reinterpret_cast<wchar_writer::value_type>(out_buffer);
    1160                 wchar_writer::value_type out_end = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, length, out_begin);
    1161 
    1162                 assert(out_end == out_begin + out_length);
    1163                 (void)!out_end;
    1164 
    1165                 return true;
    1166         }
    1167 
    1168         bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
     2107        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)
    11692108        {
    11702109                // get native encoding
     
    11722111
    11732112                // fast path: no conversion required
    1174                 if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
     2113                if (encoding == wchar_encoding)
     2114                        return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
    11752115
    11762116                // only endian-swapping is required
    1177                 if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
     2117                if (need_endian_swap_utf(encoding, wchar_encoding))
     2118                        return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
    11782119
    11792120                // source encoding is utf8
    1180                 if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size);
     2121                if (encoding == encoding_utf8)
     2122                        return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder());
    11812123
    11822124                // source encoding is utf16
     
    11862128
    11872129                        return (native_encoding == encoding) ?
    1188                                 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
    1189                                 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
     2130                                convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
     2131                                convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
    11902132                }
    11912133
     
    11962138
    11972139                        return (native_encoding == encoding) ?
    1198                                 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
    1199                                 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
    1200                 }
    1201 
    1202                 assert(!"Invalid encoding");
     2140                                convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
     2141                                convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
     2142                }
     2143
     2144                // source encoding is latin1
     2145                if (encoding == encoding_latin1)
     2146                        return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder());
     2147
     2148                assert(false && "Invalid encoding");
    12032149                return false;
    12042150        }
    12052151#else
    1206         template <typename opt_swap> bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
    1207         {
    1208                 const uint16_t* data = static_cast<const uint16_t*>(contents);
    1209                 size_t length = size / sizeof(uint16_t);
     2152        template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
     2153        {
     2154                const typename D::type* data = static_cast<const typename D::type*>(contents);
     2155                size_t data_length = size / sizeof(typename D::type);
    12102156
    12112157                // first pass: get length in utf8 units
    1212                 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, length, 0);
     2158                size_t length = D::process(data, data_length, 0, utf8_counter());
    12132159
    12142160                // allocate buffer of suitable length
    1215                 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
    1216                 if (!out_buffer) return false;
     2161                char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
     2162                if (!buffer) return false;
    12172163
    12182164                // second pass: convert utf16 input to utf8
    1219                 uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer);
    1220                 uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, length, out_begin);
    1221 
    1222                 assert(out_end == out_begin + out_length);
    1223                 (void)!out_end;
     2165                uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
     2166                uint8_t* oend = D::process(data, data_length, obegin, utf8_writer());
     2167
     2168                assert(oend == obegin + length);
     2169                *oend = 0;
     2170
     2171                out_buffer = buffer;
     2172                out_length = length + 1;
    12242173
    12252174                return true;
    12262175        }
    12272176
    1228         template <typename opt_swap> bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
    1229         {
    1230                 const uint32_t* data = static_cast<const uint32_t*>(contents);
    1231                 size_t length = size / sizeof(uint32_t);
     2177        PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
     2178        {
     2179                for (size_t i = 0; i < size; ++i)
     2180                        if (data[i] > 127)
     2181                                return i;
     2182
     2183                return size;
     2184        }
     2185
     2186        PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
     2187        {
     2188                const uint8_t* data = static_cast<const uint8_t*>(contents);
     2189                size_t data_length = size;
     2190
     2191                // get size of prefix that does not need utf8 conversion
     2192                size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
     2193                assert(prefix_length <= data_length);
     2194
     2195                const uint8_t* postfix = data + prefix_length;
     2196                size_t postfix_length = data_length - prefix_length;
     2197
     2198                // if no conversion is needed, just return the original buffer
     2199                if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
    12322200
    12332201                // first pass: get length in utf8 units
    1234                 out_length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, length, 0);
     2202                size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter());
    12352203
    12362204                // allocate buffer of suitable length
    1237                 out_buffer = static_cast<char_t*>(global_allocate((out_length > 0 ? out_length : 1) * sizeof(char_t)));
    1238                 if (!out_buffer) return false;
    1239 
    1240                 // second pass: convert utf32 input to utf8
    1241                 uint8_t* out_begin = reinterpret_cast<uint8_t*>(out_buffer);
    1242                 uint8_t* out_end = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, length, out_begin);
    1243 
    1244                 assert(out_end == out_begin + out_length);
    1245                 (void)!out_end;
     2205                char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
     2206                if (!buffer) return false;
     2207
     2208                // second pass: convert latin1 input to utf8
     2209                memcpy(buffer, data, prefix_length);
     2210
     2211                uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
     2212                uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer());
     2213
     2214                assert(oend == obegin + length);
     2215                *oend = 0;
     2216
     2217                out_buffer = buffer;
     2218                out_length = length + 1;
    12462219
    12472220                return true;
    12482221        }
    12492222
    1250         bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
     2223        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)
    12512224        {
    12522225                // fast path: no conversion required
    1253                 if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
     2226                if (encoding == encoding_utf8)
     2227                        return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
    12542228
    12552229                // source encoding is utf16
     
    12592233
    12602234                        return (native_encoding == encoding) ?
    1261                                 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
    1262                                 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
     2235                                convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
     2236                                convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
    12632237                }
    12642238
     
    12692243
    12702244                        return (native_encoding == encoding) ?
    1271                                 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
    1272                                 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
    1273                 }
    1274 
    1275                 assert(!"Invalid encoding");
     2245                                convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
     2246                                convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
     2247                }
     2248
     2249                // source encoding is latin1
     2250                if (encoding == encoding_latin1)
     2251                        return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
     2252
     2253                assert(false && "Invalid encoding");
    12762254                return false;
    12772255        }
    12782256#endif
    12792257
    1280         size_t as_utf8_begin(const wchar_t* str, size_t length)
    1281         {
    1282                 STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
    1283 
     2258        PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length)
     2259        {
    12842260                // get length in utf8 characters
    1285                 return sizeof(wchar_t) == 2 ?
    1286                         utf_decoder<utf8_counter>::decode_utf16_block(reinterpret_cast<const uint16_t*>(str), length, 0) :
    1287                         utf_decoder<utf8_counter>::decode_utf32_block(reinterpret_cast<const uint32_t*>(str), length, 0);
    1288     }
    1289 
    1290     void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
    1291     {
    1292                 STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
    1293 
    1294         // convert to utf8
    1295         uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
    1296         uint8_t* end = sizeof(wchar_t) == 2 ?
    1297             utf_decoder<utf8_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(str), length, begin) :
    1298             utf_decoder<utf8_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(str), length, begin);
    1299    
    1300         assert(begin + size == end);
    1301         (void)!end;
    1302 
    1303                 // zero-terminate
    1304                 buffer[size] = 0;
    1305         }
    1306    
     2261                return wchar_decoder::process(str, length, 0, utf8_counter());
     2262        }
     2263
     2264        PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
     2265        {
     2266                // convert to utf8
     2267                uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
     2268                uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer());
     2269
     2270                assert(begin + size == end);
     2271                (void)!end;
     2272                (void)!size;
     2273        }
     2274
    13072275#ifndef PUGIXML_NO_STL
    1308     std::string as_utf8_impl(const wchar_t* str, size_t length)
    1309     {
     2276        PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length)
     2277        {
    13102278                // first pass: get length in utf8 characters
    1311         size_t size = as_utf8_begin(str, length);
     2279                size_t size = as_utf8_begin(str, length);
    13122280
    13132281                // allocate resulting string
     
    13182286                if (size > 0) as_utf8_end(&result[0], size, str, length);
    13192287
    1320                 return result;
    1321     }
    1322 
    1323         std::wstring as_wide_impl(const char* str, size_t size)
     2288                return result;
     2289        }
     2290
     2291        PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)
    13242292        {
    13252293                const uint8_t* data = reinterpret_cast<const uint8_t*>(str);
    13262294
    13272295                // first pass: get length in wchar_t units
    1328                 size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
     2296                size_t length = utf8_decoder::process(data, size, 0, wchar_counter());
    13292297
    13302298                // allocate resulting string
    1331                 std::wstring result;
     2299                std::basic_string<wchar_t> result;
    13322300                result.resize(length);
    13332301
     
    13362304                {
    13372305                        wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
    1338                         wchar_writer::value_type end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, begin);
     2306                        wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer());
    13392307
    13402308                        assert(begin + length == end);
     
    13462314#endif
    13472315
    1348         inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target)
    1349         {
    1350                 assert(target);
     2316        template <typename Header>
     2317        inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target)
     2318        {
     2319                // never reuse shared memory
     2320                if (header & xml_memory_page_contents_shared_mask) return false;
     2321
    13512322                size_t target_length = strlength(target);
    13522323
    13532324                // always reuse document buffer memory if possible
    1354                 if (!allocated) return target_length >= length;
     2325                if ((header & header_mask) == 0) return target_length >= length;
    13552326
    13562327                // reuse heap memory if waste is not too great
     
    13602331        }
    13612332
    1362         bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source)
    1363         {
    1364                 size_t source_length = strlength(source);
    1365 
     2333        template <typename String, typename Header>
     2334        PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length)
     2335        {
    13662336                if (source_length == 0)
    13672337                {
    13682338                        // empty string and null pointer are equivalent, so just deallocate old memory
    1369                         xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
     2339                        xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
    13702340
    13712341                        if (header & header_mask) alloc->deallocate_string(dest);
    1372                        
     2342
    13732343                        // mark the string as not allocated
    13742344                        dest = 0;
     
    13772347                        return true;
    13782348                }
    1379                 else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest))
     2349                else if (dest && strcpy_insitu_allow(source_length, header, header_mask, dest))
    13802350                {
    13812351                        // we can reuse old buffer, so just copy the new data (including zero terminator)
    1382                         memcpy(dest, source, (source_length + 1) * sizeof(char_t));
    1383                        
     2352                        memcpy(dest, source, source_length * sizeof(char_t));
     2353                        dest[source_length] = 0;
     2354
    13842355                        return true;
    13852356                }
    13862357                else
    13872358                {
    1388                         xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
     2359                        xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
     2360
     2361                        if (!alloc->reserve()) return false;
    13892362
    13902363                        // allocate new buffer
     
    13932366
    13942367                        // copy the string (including zero terminator)
    1395                         memcpy(buf, source, (source_length + 1) * sizeof(char_t));
     2368                        memcpy(buf, source, source_length * sizeof(char_t));
     2369                        buf[source_length] = 0;
    13962370
    13972371                        // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
    13982372                        if (header & header_mask) alloc->deallocate_string(dest);
    1399                        
     2373
    14002374                        // the string is now allocated, so set the flag
    14012375                        dest = buf;
     
    14102384                char_t* end;
    14112385                size_t size;
    1412                        
     2386
    14132387                gap(): end(0), size(0)
    14142388                {
    14152389                }
    1416                        
     2390
    14172391                // Push new gap, move s count bytes further (skipping the gap).
    14182392                // Collapse previous gap.
     
    14252399                                memmove(end - size, end, reinterpret_cast<char*>(s) - reinterpret_cast<char*>(end));
    14262400                        }
    1427                                
     2401
    14282402                        s += count; // end of current gap
    1429                                
     2403
    14302404                        // "merge" two gaps
    14312405                        end = s;
    14322406                        size += count;
    14332407                }
    1434                        
     2408
    14352409                // Collapse all gaps, return past-the-end pointer
    14362410                char_t* flush(char_t* s)
     
    14472421                }
    14482422        };
    1449        
    1450         char_t* strconv_escape(char_t* s, gap& g)
     2423
     2424        PUGI__FN char_t* strconv_escape(char_t* s, gap& g)
    14512425        {
    14522426                char_t* stre = s + 1;
     
    14792453                                                ch = *++stre;
    14802454                                        }
    1481                                        
     2455
    14822456                                        ++stre;
    14832457                                }
     
    14902464                                        for (;;)
    14912465                                        {
    1492                                                 if (static_cast<unsigned int>(ch - '0') <= 9)
     2466                                                if (static_cast<unsigned int>(static_cast<unsigned int>(ch) - '0') <= 9)
    14932467                                                        ucsc = 10 * ucsc + (ch - '0');
    14942468                                                else if (ch == ';')
     
    14992473                                                ch = *++stre;
    15002474                                        }
    1501                                        
     2475
    15022476                                        ++stre;
    15032477                                }
     
    15082482                                s = reinterpret_cast<char_t*>(utf8_writer::any(reinterpret_cast<uint8_t*>(s), ucsc));
    15092483                        #endif
    1510                                        
     2484
    15112485                                g.push(s, stre - s);
    15122486                                return stre;
    15132487                        }
     2488
    15142489                        case 'a':       // &a
    15152490                        {
     
    15222497                                                *s++ = '&';
    15232498                                                ++stre;
    1524                                                        
     2499
    15252500                                                g.push(s, stre - s);
    15262501                                                return stre;
     
    15402515                                break;
    15412516                        }
     2517
    15422518                        case 'g': // &g
    15432519                        {
     
    15462522                                        *s++ = '>';
    15472523                                        ++stre;
    1548                                        
     2524
    15492525                                        g.push(s, stre - s);
    15502526                                        return stre;
     
    15522528                                break;
    15532529                        }
     2530
    15542531                        case 'l': // &l
    15552532                        {
     
    15582535                                        *s++ = '<';
    15592536                                        ++stre;
    1560                                                
     2537
    15612538                                        g.push(s, stre - s);
    15622539                                        return stre;
     
    15642541                                break;
    15652542                        }
     2543
    15662544                        case 'q': // &q
    15672545                        {
     
    15702548                                        *s++ = '"';
    15712549                                        ++stre;
    1572                                        
     2550
    15732551                                        g.push(s, stre - s);
    15742552                                        return stre;
     
    15762554                                break;
    15772555                        }
    1578                 }
    1579                
     2556
     2557                        default:
     2558                                break;
     2559                }
     2560
    15802561                return stre;
    15812562        }
    15822563
    1583         // Utility macro for last character handling
    1584         #define ENDSWITH(c, e) ((c) == (e) || ((c) == 0 && endch == (e)))
    1585 
    1586         char_t* strconv_comment(char_t* s, char_t endch)
     2564        // Parser utilities
     2565        #define PUGI__ENDSWITH(c, e)        ((c) == (e) || ((c) == 0 && endch == (e)))
     2566        #define PUGI__SKIPWS()              { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
     2567        #define PUGI__OPTSET(OPT)           ( optmsk & (OPT) )
     2568        #define PUGI__PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
     2569        #define PUGI__POPNODE()             { cursor = cursor->parent; }
     2570        #define PUGI__SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
     2571        #define PUGI__SCANWHILE(X)          { while (X) ++s; }
     2572        #define PUGI__SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
     2573        #define PUGI__ENDSEG()              { ch = *s; *s = 0; ++s; }
     2574        #define PUGI__THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(0)
     2575        #define PUGI__CHECK_ERROR(err, m)   { if (*s == 0) PUGI__THROW_ERROR(err, m); }
     2576
     2577        PUGI__FN char_t* strconv_comment(char_t* s, char_t endch)
    15872578        {
    15882579                gap g;
    1589                
     2580
    15902581                while (true)
    15912582                {
    1592                         while (!IS_CHARTYPE(*s, ct_parse_comment)) ++s;
    1593                
     2583                        PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment));
     2584
    15942585                        if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
    15952586                        {
    15962587                                *s++ = '\n'; // replace first one with 0x0a
    1597                                
     2588
    15982589                                if (*s == '\n') g.push(s, 1);
    15992590                        }
    1600                         else if (s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>')) // comment ends here
     2591                        else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here
    16012592                        {
    16022593                                *g.flush(s) = 0;
    1603                                
     2594
    16042595                                return s + (s[2] == '>' ? 3 : 2);
    16052596                        }
     
    16122603        }
    16132604
    1614         char_t* strconv_cdata(char_t* s, char_t endch)
     2605        PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch)
    16152606        {
    16162607                gap g;
    1617                        
     2608
    16182609                while (true)
    16192610                {
    1620                         while (!IS_CHARTYPE(*s, ct_parse_cdata)) ++s;
    1621                        
     2611                        PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata));
     2612
    16222613                        if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
    16232614                        {
    16242615                                *s++ = '\n'; // replace first one with 0x0a
    1625                                
     2616
    16262617                                if (*s == '\n') g.push(s, 1);
    16272618                        }
    1628                         else if (s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>')) // CDATA ends here
     2619                        else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here
    16292620                        {
    16302621                                *g.flush(s) = 0;
    1631                                
     2622
    16322623                                return s + 1;
    16332624                        }
     
    16392630                }
    16402631        }
    1641        
     2632
    16422633        typedef char_t* (*strconv_pcdata_t)(char_t*);
    1643                
    1644         template <typename opt_eol, typename opt_escape> struct strconv_pcdata_impl
     2634
     2635        template <typename opt_trim, typename opt_eol, typename opt_escape> struct strconv_pcdata_impl
    16452636        {
    16462637                static char_t* parse(char_t* s)
    16472638                {
    16482639                        gap g;
    1649                        
     2640
     2641                        char_t* begin = s;
     2642
    16502643                        while (true)
    16512644                        {
    1652                                 while (!IS_CHARTYPE(*s, ct_parse_pcdata)) ++s;
    1653                                        
     2645                                PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata));
     2646
    16542647                                if (*s == '<') // PCDATA ends here
    16552648                                {
    1656                                         *g.flush(s) = 0;
    1657                                        
     2649                                        char_t* end = g.flush(s);
     2650
     2651                                        if (opt_trim::value)
     2652                                                while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
     2653                                                        --end;
     2654
     2655                                        *end = 0;
     2656
    16582657                                        return s + 1;
    16592658                                }
     
    16612660                                {
    16622661                                        *s++ = '\n'; // replace first one with 0x0a
    1663                                        
     2662
    16642663                                        if (*s == '\n') g.push(s, 1);
    16652664                                }
     
    16702669                                else if (*s == 0)
    16712670                                {
     2671                                        char_t* end = g.flush(s);
     2672
     2673                                        if (opt_trim::value)
     2674                                                while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
     2675                                                        --end;
     2676
     2677                                        *end = 0;
     2678
    16722679                                        return s;
    16732680                                }
     
    16762683                }
    16772684        };
    1678        
    1679         strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
    1680         {
    1681                 STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20);
    1682 
    1683                 switch ((optmask >> 4) & 3) // get bitmask for flags (eol escapes)
    1684                 {
    1685                 case 0: return strconv_pcdata_impl<opt_false, opt_false>::parse;
    1686                 case 1: return strconv_pcdata_impl<opt_false, opt_true>::parse;
    1687                 case 2: return strconv_pcdata_impl<opt_true, opt_false>::parse;
    1688                 case 3: return strconv_pcdata_impl<opt_true, opt_true>::parse;
    1689                 default: return 0; // should not get here
     2685
     2686        PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
     2687        {
     2688                PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
     2689
     2690                switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (eol escapes trim)
     2691                {
     2692                case 0: return strconv_pcdata_impl<opt_false, opt_false, opt_false>::parse;
     2693                case 1: return strconv_pcdata_impl<opt_false, opt_false, opt_true>::parse;
     2694                case 2: return strconv_pcdata_impl<opt_false, opt_true, opt_false>::parse;
     2695                case 3: return strconv_pcdata_impl<opt_false, opt_true, opt_true>::parse;
     2696                case 4: return strconv_pcdata_impl<opt_true, opt_false, opt_false>::parse;
     2697                case 5: return strconv_pcdata_impl<opt_true, opt_false, opt_true>::parse;
     2698                case 6: return strconv_pcdata_impl<opt_true, opt_true, opt_false>::parse;
     2699                case 7: return strconv_pcdata_impl<opt_true, opt_true, opt_true>::parse;
     2700                default: assert(false); return 0; // should not get here
    16902701                }
    16912702        }
    16922703
    16932704        typedef char_t* (*strconv_attribute_t)(char_t*, char_t);
    1694        
     2705
    16952706        template <typename opt_escape> struct strconv_attribute_impl
    16962707        {
     
    17002711
    17012712                        // trim leading whitespaces
    1702                         if (IS_CHARTYPE(*s, ct_space))
     2713                        if (PUGI__IS_CHARTYPE(*s, ct_space))
    17032714                        {
    17042715                                char_t* str = s;
    1705                                
     2716
    17062717                                do ++str;
    1707                                 while (IS_CHARTYPE(*str, ct_space));
    1708                                
     2718                                while (PUGI__IS_CHARTYPE(*str, ct_space));
     2719
    17092720                                g.push(s, str - s);
    17102721                        }
     
    17122723                        while (true)
    17132724                        {
    1714                                 while (!IS_CHARTYPE(*s, ct_parse_attr_ws | ct_space)) ++s;
    1715                                
     2725                                PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space));
     2726
    17162727                                if (*s == end_quote)
    17172728                                {
    17182729                                        char_t* str = g.flush(s);
    1719                                        
     2730
    17202731                                        do *str-- = 0;
    1721                                         while (IS_CHARTYPE(*str, ct_space));
    1722                                
     2732                                        while (PUGI__IS_CHARTYPE(*str, ct_space));
     2733
    17232734                                        return s + 1;
    17242735                                }
    1725                                 else if (IS_CHARTYPE(*s, ct_space))
     2736                                else if (PUGI__IS_CHARTYPE(*s, ct_space))
    17262737                                {
    17272738                                        *s++ = ' ';
    1728                
    1729                                         if (IS_CHARTYPE(*s, ct_space))
     2739
     2740                                        if (PUGI__IS_CHARTYPE(*s, ct_space))
    17302741                                        {
    17312742                                                char_t* str = s + 1;
    1732                                                 while (IS_CHARTYPE(*str, ct_space)) ++str;
    1733                                                
     2743                                                while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
     2744
    17342745                                                g.push(s, str - s);
    17352746                                        }
     
    17532764                        while (true)
    17542765                        {
    1755                                 while (!IS_CHARTYPE(*s, ct_parse_attr_ws)) ++s;
    1756                                
     2766                                PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws));
     2767
    17572768                                if (*s == end_quote)
    17582769                                {
    17592770                                        *g.flush(s) = 0;
    1760                                
     2771
    17612772                                        return s + 1;
    17622773                                }
    1763                                 else if (IS_CHARTYPE(*s, ct_space))
     2774                                else if (PUGI__IS_CHARTYPE(*s, ct_space))
    17642775                                {
    17652776                                        if (*s == '\r')
    17662777                                        {
    17672778                                                *s++ = ' ';
    1768                                
     2779
    17692780                                                if (*s == '\n') g.push(s, 1);
    17702781                                        }
     
    17892800                        while (true)
    17902801                        {
    1791                                 while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s;
    1792                                
     2802                                PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
     2803
    17932804                                if (*s == end_quote)
    17942805                                {
    17952806                                        *g.flush(s) = 0;
    1796                                
     2807
    17972808                                        return s + 1;
    17982809                                }
     
    18002811                                {
    18012812                                        *s++ = '\n';
    1802                                        
     2813
    18032814                                        if (*s == '\n') g.push(s, 1);
    18042815                                }
     
    18212832                        while (true)
    18222833                        {
    1823                                 while (!IS_CHARTYPE(*s, ct_parse_attr)) ++s;
    1824                                
     2834                                PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
     2835
    18252836                                if (*s == end_quote)
    18262837                                {
    18272838                                        *g.flush(s) = 0;
    1828                                
     2839
    18292840                                        return s + 1;
    18302841                                }
     
    18422853        };
    18432854
    1844         strconv_attribute_t get_strconv_attribute(unsigned int optmask)
    1845         {
    1846                 STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
    1847                
     2855        PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
     2856        {
     2857                PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
     2858
    18482859                switch ((optmask >> 4) & 15) // get bitmask for flags (wconv wnorm eol escapes)
    18492860                {
     
    18642875                case 14: return strconv_attribute_impl<opt_false>::parse_wnorm;
    18652876                case 15: return strconv_attribute_impl<opt_true>::parse_wnorm;
    1866                 default: return 0; // should not get here
     2877                default: assert(false); return 0; // should not get here
    18672878                }
    18682879        }
     
    18792890        struct xml_parser
    18802891        {
    1881                 xml_allocator alloc;
     2892                xml_allocator* alloc;
    18822893                char_t* error_offset;
    1883                 jmp_buf error_handler;
    1884                
    1885                 // Parser utilities.
    1886                 #define SKIPWS()                        { while (IS_CHARTYPE(*s, ct_space)) ++s; }
    1887                 #define OPTSET(OPT)                     ( optmsk & OPT )
    1888                 #define PUSHNODE(TYPE)          { cursor = append_node(cursor, alloc, TYPE); if (!cursor) THROW_ERROR(status_out_of_memory, s); }
    1889                 #define POPNODE()                       { cursor = cursor->parent; }
    1890                 #define SCANFOR(X)                      { while (*s != 0 && !(X)) ++s; }
    1891                 #define SCANWHILE(X)            { while ((X)) ++s; }
    1892                 #define ENDSEG()                        { ch = *s; *s = 0; ++s; }
    1893                 #define THROW_ERROR(err, m)     error_offset = m, longjmp(error_handler, err)
    1894                 #define CHECK_ERROR(err, m)     { if (*s == 0) THROW_ERROR(err, m); }
    1895                
    1896                 xml_parser(const xml_allocator& alloc): alloc(alloc), error_offset(0)
     2894                xml_parse_status error_status;
     2895
     2896                xml_parser(xml_allocator* alloc_): alloc(alloc_), error_offset(0), error_status(status_ok)
    18972897                {
    18982898                }
     
    19112911                                // quoted string
    19122912                                char_t ch = *s++;
    1913                                 SCANFOR(*s == ch);
    1914                                 if (!*s) THROW_ERROR(status_bad_doctype, s);
     2913                                PUGI__SCANFOR(*s == ch);
     2914                                if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
    19152915
    19162916                                s++;
     
    19202920                                // <? ... ?>
    19212921                                s += 2;
    1922                                 SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
    1923                                 if (!*s) THROW_ERROR(status_bad_doctype, s);
     2922                                PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
     2923                                if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
    19242924
    19252925                                s += 2;
     
    19282928                        {
    19292929                                s += 4;
    1930                                 SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
    1931                                 if (!*s) THROW_ERROR(status_bad_doctype, s);
    1932 
    1933                                 s += 4;
    1934                         }
    1935                         else THROW_ERROR(status_bad_doctype, s);
     2930                                PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
     2931                                if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
     2932
     2933                                s += 3;
     2934                        }
     2935                        else PUGI__THROW_ERROR(status_bad_doctype, s);
    19362936
    19372937                        return s;
     
    19402940                char_t* parse_doctype_ignore(char_t* s)
    19412941                {
     2942                        size_t depth = 0;
     2943
    19422944                        assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
    1943                         s++;
     2945                        s += 3;
    19442946
    19452947                        while (*s)
     
    19482950                                {
    19492951                                        // nested ignore section
    1950                                         s = parse_doctype_ignore(s);
     2952                                        s += 3;
     2953                                        depth++;
    19512954                                }
    19522955                                else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
     
    19552958                                        s += 3;
    19562959
    1957                                         return s;
     2960                                        if (depth == 0)
     2961                                                return s;
     2962
     2963                                        depth--;
    19582964                                }
    19592965                                else s++;
    19602966                        }
    19612967
    1962                         THROW_ERROR(status_bad_doctype, s);
    1963 
    1964                         return s;
    1965                 }
    1966 
    1967                 char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel)
    1968                 {
    1969                         assert(s[0] == '<' && s[1] == '!');
    1970                         s++;
     2968                        PUGI__THROW_ERROR(status_bad_doctype, s);
     2969                }
     2970
     2971                char_t* parse_doctype_group(char_t* s, char_t endch)
     2972                {
     2973                        size_t depth = 0;
     2974
     2975                        assert((s[0] == '<' || s[0] == 0) && s[1] == '!');
     2976                        s += 2;
    19712977
    19722978                        while (*s)
     
    19782984                                                // ignore
    19792985                                                s = parse_doctype_ignore(s);
     2986                                                if (!s) return s;
    19802987                                        }
    19812988                                        else
    19822989                                        {
    19832990                                                // some control group
    1984                                                 s = parse_doctype_group(s, endch, false);
     2991                                                s += 2;
     2992                                                depth++;
    19852993                                        }
    19862994                                }
     
    19892997                                        // unknown tag (forbidden), or some primitive group
    19902998                                        s = parse_doctype_primitive(s);
     2999                                        if (!s) return s;
    19913000                                }
    19923001                                else if (*s == '>')
    19933002                                {
     3003                                        if (depth == 0)
     3004                                                return s;
     3005
     3006                                        depth--;
    19943007                                        s++;
    1995 
    1996                                         return s;
    19973008                                }
    19983009                                else s++;
    19993010                        }
    20003011
    2001                         if (!toplevel || endch != '>') THROW_ERROR(status_bad_doctype, s);
     3012                        if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
    20023013
    20033014                        return s;
     
    20173028                                        ++s;
    20183029
    2019                                         if (OPTSET(parse_comments))
     3030                                        if (PUGI__OPTSET(parse_comments))
    20203031                                        {
    2021                                                 PUSHNODE(node_comment); // Append a new node on the tree.
     3032                                                PUGI__PUSHNODE(node_comment); // Append a new node on the tree.
    20223033                                                cursor->value = s; // Save the offset.
    20233034                                        }
    20243035
    2025                                         if (OPTSET(parse_eol) && OPTSET(parse_comments))
     3036                                        if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments))
    20263037                                        {
    20273038                                                s = strconv_comment(s, endch);
    20283039
    2029                                                 if (!s) THROW_ERROR(status_bad_comment, cursor->value);
     3040                                                if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
    20303041                                        }
    20313042                                        else
    20323043                                        {
    20333044                                                // Scan for terminating '-->'.
    2034                                                 SCANFOR(s[0] == '-' && s[1] == '-' && ENDSWITH(s[2], '>'));
    2035                                                 CHECK_ERROR(status_bad_comment, s);
    2036 
    2037                                                 if (OPTSET(parse_comments))
     3045                                                PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>'));
     3046                                                PUGI__CHECK_ERROR(status_bad_comment, s);
     3047
     3048                                                if (PUGI__OPTSET(parse_comments))
    20383049                                                        *s = 0; // Zero-terminate this segment at the first terminating '-'.
    20393050
     
    20413052                                        }
    20423053                                }
    2043                                 else THROW_ERROR(status_bad_comment, s);
     3054                                else PUGI__THROW_ERROR(status_bad_comment, s);
    20443055                        }
    20453056                        else if (*s == '[')
     
    20503061                                        ++s;
    20513062
    2052                                         if (OPTSET(parse_cdata))
     3063                                        if (PUGI__OPTSET(parse_cdata))
    20533064                                        {
    2054                                                 PUSHNODE(node_cdata); // Append a new node on the tree.
     3065                                                PUGI__PUSHNODE(node_cdata); // Append a new node on the tree.
    20553066                                                cursor->value = s; // Save the offset.
    20563067
    2057                                                 if (OPTSET(parse_eol))
     3068                                                if (PUGI__OPTSET(parse_eol))
    20583069                                                {
    20593070                                                        s = strconv_cdata(s, endch);
    20603071
    2061                                                         if (!s) THROW_ERROR(status_bad_cdata, cursor->value);
     3072                                                        if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
    20623073                                                }
    20633074                                                else
    20643075                                                {
    20653076                                                        // Scan for terminating ']]>'.
    2066                                                         SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
    2067                                                         CHECK_ERROR(status_bad_cdata, s);
     3077                                                        PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
     3078                                                        PUGI__CHECK_ERROR(status_bad_cdata, s);
    20683079
    20693080                                                        *s++ = 0; // Zero-terminate this segment.
     
    20733084                                        {
    20743085                                                // Scan for terminating ']]>'.
    2075                                                 SCANFOR(s[0] == ']' && s[1] == ']' && ENDSWITH(s[2], '>'));
    2076                                                 CHECK_ERROR(status_bad_cdata, s);
     3086                                                PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
     3087                                                PUGI__CHECK_ERROR(status_bad_cdata, s);
    20773088
    20783089                                                ++s;
     
    20813092                                        s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
    20823093                                }
    2083                                 else THROW_ERROR(status_bad_cdata, s);
    2084                         }
    2085                         else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && ENDSWITH(s[6], 'E'))
     3094                                else PUGI__THROW_ERROR(status_bad_cdata, s);
     3095                        }
     3096                        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'))
    20863097                        {
    20873098                                s -= 2;
    20883099
    2089                 if (cursor->parent) THROW_ERROR(status_bad_doctype, s);
    2090 
    2091                 char_t* mark = s + 9;
    2092 
    2093                                 s = parse_doctype_group(s, endch, true);
    2094 
    2095                 if (OPTSET(parse_doctype))
    2096                 {
    2097                     while (IS_CHARTYPE(*mark, ct_space)) ++mark;
    2098 
    2099                     PUSHNODE(node_doctype);
    2100 
    2101                     cursor->value = mark;
    2102 
    2103                     assert((s[0] == 0 && endch == '>') || s[-1] == '>');
    2104                     s[*s == 0 ? 0 : -1] = 0;
    2105 
    2106                     POPNODE();
    2107                 }
    2108                         }
    2109                         else if (*s == 0 && endch == '-') THROW_ERROR(status_bad_comment, s);
    2110                         else if (*s == 0 && endch == '[') THROW_ERROR(status_bad_cdata, s);
    2111                         else THROW_ERROR(status_unrecognized_tag, s);
     3100                                if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
     3101
     3102                                char_t* mark = s + 9;
     3103
     3104                                s = parse_doctype_group(s, endch);
     3105                                if (!s) return s;
     3106
     3107                                assert((*s == 0 && endch == '>') || *s == '>');
     3108                                if (*s) *s++ = 0;
     3109
     3110                                if (PUGI__OPTSET(parse_doctype))
     3111                                {
     3112                                        while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
     3113
     3114                                        PUGI__PUSHNODE(node_doctype);
     3115
     3116                                        cursor->value = mark;
     3117                                }
     3118                        }
     3119                        else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s);
     3120                        else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s);
     3121                        else PUGI__THROW_ERROR(status_unrecognized_tag, s);
    21123122
    21133123                        return s;
     
    21263136                        char_t* target = s;
    21273137
    2128                         if (!IS_CHARTYPE(*s, ct_start_symbol)) THROW_ERROR(status_bad_pi, s);
    2129 
    2130                         SCANWHILE(IS_CHARTYPE(*s, ct_symbol));
    2131                         CHECK_ERROR(status_bad_pi, s);
     3138                        if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s);
     3139
     3140                        PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
     3141                        PUGI__CHECK_ERROR(status_bad_pi, s);
    21323142
    21333143                        // determine node type; stricmp / strcasecmp is not portable
    21343144                        bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
    21353145
    2136                         if (declaration ? OPTSET(parse_declaration) : OPTSET(parse_pi))
     3146                        if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
    21373147                        {
    21383148                                if (declaration)
    21393149                                {
    21403150                                        // disallow non top-level declarations
    2141                                         if (cursor->parent) THROW_ERROR(status_bad_pi, s);
    2142 
    2143                                         PUSHNODE(node_declaration);
     3151                                        if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
     3152
     3153                                        PUGI__PUSHNODE(node_declaration);
    21443154                                }
    21453155                                else
    21463156                                {
    2147                                         PUSHNODE(node_pi);
     3157                                        PUGI__PUSHNODE(node_pi);
    21483158                                }
    21493159
    21503160                                cursor->name = target;
    21513161
    2152                                 ENDSEG();
     3162                                PUGI__ENDSEG();
    21533163
    21543164                                // parse value/attributes
     
    21563166                                {
    21573167                                        // empty node
    2158                                         if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_pi, s);
     3168                                        if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s);
    21593169                                        s += (*s == '>');
    21603170
    2161                                         POPNODE();
    2162                                 }
    2163                                 else if (IS_CHARTYPE(ch, ct_space))
    2164                                 {
    2165                                         SKIPWS();
     3171                                        PUGI__POPNODE();
     3172                                }
     3173                                else if (PUGI__IS_CHARTYPE(ch, ct_space))
     3174                                {
     3175                                        PUGI__SKIPWS();
    21663176
    21673177                                        // scan for tag end
    21683178                                        char_t* value = s;
    21693179
    2170                                         SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
    2171                                         CHECK_ERROR(status_bad_pi, s);
     3180                                        PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
     3181                                        PUGI__CHECK_ERROR(status_bad_pi, s);
    21723182
    21733183                                        if (declaration)
     
    21833193                                                // store value and step over >
    21843194                                                cursor->value = value;
    2185                                                 POPNODE();
    2186 
    2187                                                 ENDSEG();
     3195
     3196                                                PUGI__POPNODE();
     3197
     3198                                                PUGI__ENDSEG();
    21883199
    21893200                                                s += (*s == '>');
    21903201                                        }
    21913202                                }
    2192                                 else THROW_ERROR(status_bad_pi, s);
     3203                                else PUGI__THROW_ERROR(status_bad_pi, s);
    21933204                        }
    21943205                        else
    21953206                        {
    21963207                                // scan for tag end
    2197                                 SCANFOR(s[0] == '?' && ENDSWITH(s[1], '>'));
    2198                                 CHECK_ERROR(status_bad_pi, s);
     3208                                PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
     3209                                PUGI__CHECK_ERROR(status_bad_pi, s);
    21993210
    22003211                                s += (s[1] == '>' ? 2 : 1);
     
    22073218                }
    22083219
    2209                 void parse(char_t* s, xml_node_struct* xmldoc, unsigned int optmsk, char_t endch)
     3220                char_t* parse_tree(char_t* s, xml_node_struct* root, unsigned int optmsk, char_t endch)
    22103221                {
    22113222                        strconv_attribute_t strconv_attribute = get_strconv_attribute(optmsk);
    22123223                        strconv_pcdata_t strconv_pcdata = get_strconv_pcdata(optmsk);
    2213                        
     3224
    22143225                        char_t ch = 0;
    2215                         xml_node_struct* cursor = xmldoc;
     3226                        xml_node_struct* cursor = root;
    22163227                        char_t* mark = s;
    22173228
     
    22233234
    22243235                                LOC_TAG:
    2225                                         if (IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
     3236                                        if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
    22263237                                        {
    2227                                                 PUSHNODE(node_element); // Append a new node to the tree.
     3238                                                PUGI__PUSHNODE(node_element); // Append a new node to the tree.
    22283239
    22293240                                                cursor->name = s;
    22303241
    2231                                                 SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
    2232                                                 ENDSEG(); // Save char in 'ch', terminate & step over.
     3242                                                PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
     3243                                                PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
    22333244
    22343245                                                if (ch == '>')
     
    22363247                                                        // end of tag
    22373248                                                }
    2238                                                 else if (IS_CHARTYPE(ch, ct_space))
     3249                                                else if (PUGI__IS_CHARTYPE(ch, ct_space))
    22393250                                                {
    22403251                                                LOC_ATTRIBUTES:
    2241                                                     while (true)
    2242                                                     {
    2243                                                                 SKIPWS(); // Eat any whitespace.
    2244                                                
    2245                                                                 if (IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
     3252                                                        while (true)
     3253                                                        {
     3254                                                                PUGI__SKIPWS(); // Eat any whitespace.
     3255
     3256                                                                if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
    22463257                                                                {
    2247                                                                         xml_attribute_struct* a = append_attribute_ll(cursor, alloc); // Make space for this attribute.
    2248                                                                         if (!a) THROW_ERROR(status_out_of_memory, s);
     3258                                                                        xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute.
     3259                                                                        if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
    22493260
    22503261                                                                        a->name = s; // Save the offset.
    22513262
    2252                                                                         SCANWHILE(IS_CHARTYPE(*s, ct_symbol)); // Scan for a terminator.
    2253                                                                         CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
    2254 
    2255                                                                         ENDSEG(); // Save char in 'ch', terminate & step over.
    2256                                                                         CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
    2257 
    2258                                                                         if (IS_CHARTYPE(ch, ct_space))
     3263                                                                        PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
     3264                                                                        PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
     3265
     3266                                                                        if (PUGI__IS_CHARTYPE(ch, ct_space))
    22593267                                                                        {
    2260                                                                                 SKIPWS(); // Eat any whitespace.
    2261                                                                                 CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
     3268                                                                                PUGI__SKIPWS(); // Eat any whitespace.
    22623269
    22633270                                                                                ch = *s;
    22643271                                                                                ++s;
    22653272                                                                        }
    2266                                                                        
     3273
    22673274                                                                        if (ch == '=') // '<... #=...'
    22683275                                                                        {
    2269                                                                                 SKIPWS(); // Eat any whitespace.
     3276                                                                                PUGI__SKIPWS(); // Eat any whitespace.
    22703277
    22713278                                                                                if (*s == '"' || *s == '\'') // '<... #="...'
     
    22763283
    22773284                                                                                        s = strconv_attribute(s, ch);
    2278                                                                                
    2279                                                                                         if (!s) THROW_ERROR(status_bad_attribute, a->value);
     3285
     3286                                                                                        if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
    22803287
    22813288                                                                                        // After this line the loop continues from the start;
    22823289                                                                                        // Whitespaces, / and > are ok, symbols and EOF are wrong,
    22833290                                                                                        // everything else will be detected
    2284                                                                                         if (IS_CHARTYPE(*s, ct_start_symbol)) THROW_ERROR(status_bad_attribute, s);
     3291                                                                                        if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s);
    22853292                                                                                }
    2286                                                                                 else THROW_ERROR(status_bad_attribute, s);
     3293                                                                                else PUGI__THROW_ERROR(status_bad_attribute, s);
    22873294                                                                        }
    2288                                                                         else THROW_ERROR(status_bad_attribute, s);
     3295                                                                        else PUGI__THROW_ERROR(status_bad_attribute, s);
    22893296                                                                }
    22903297                                                                else if (*s == '/')
    22913298                                                                {
    22923299                                                                        ++s;
    2293                                                                        
     3300
    22943301                                                                        if (*s == '>')
    22953302                                                                        {
    2296                                                                                 POPNODE();
     3303                                                                                PUGI__POPNODE();
    22973304                                                                                s++;
    22983305                                                                                break;
     
    23003307                                                                        else if (*s == 0 && endch == '>')
    23013308                                                                        {
    2302                                                                                 POPNODE();
     3309                                                                                PUGI__POPNODE();
    23033310                                                                                break;
    23043311                                                                        }
    2305                                                                         else THROW_ERROR(status_bad_start_element, s);
     3312                                                                        else PUGI__THROW_ERROR(status_bad_start_element, s);
    23063313                                                                }
    23073314                                                                else if (*s == '>')
     
    23153322                                                                        break;
    23163323                                                                }
    2317                                                                 else THROW_ERROR(status_bad_start_element, s);
     3324                                                                else PUGI__THROW_ERROR(status_bad_start_element, s);
    23183325                                                        }
    23193326
     
    23223329                                                else if (ch == '/') // '<#.../'
    23233330                                                {
    2324                                                         if (!ENDSWITH(*s, '>')) THROW_ERROR(status_bad_start_element, s);
    2325 
    2326                                                         POPNODE(); // Pop.
     3331                                                        if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s);
     3332
     3333                                                        PUGI__POPNODE(); // Pop.
    23273334
    23283335                                                        s += (*s == '>');
     
    23323339                                                        // we stepped over null terminator, backtrack & handle closing tag
    23333340                                                        --s;
    2334                                                        
    2335                                                         if (endch != '>') THROW_ERROR(status_bad_start_element, s);
     3341
     3342                                                        if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s);
    23363343                                                }
    2337                                                 else THROW_ERROR(status_bad_start_element, s);
     3344                                                else PUGI__THROW_ERROR(status_bad_start_element, s);
    23383345                                        }
    23393346                                        else if (*s == '/')
     
    23413348                                                ++s;
    23423349
     3350                                                mark = s;
     3351
    23433352                                                char_t* name = cursor->name;
    2344                                                 if (!name) THROW_ERROR(status_end_element_mismatch, s);
    2345                                                
    2346                                                 while (IS_CHARTYPE(*s, ct_symbol))
     3353                                                if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
     3354
     3355                                                while (PUGI__IS_CHARTYPE(*s, ct_symbol))
    23473356                                                {
    2348                                                         if (*s++ != *name++) THROW_ERROR(status_end_element_mismatch, s);
     3357                                                        if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
    23493358                                                }
    23503359
    23513360                                                if (*name)
    23523361                                                {
    2353                                                         if (*s == 0 && name[0] == endch && name[1] == 0) THROW_ERROR(status_bad_end_element, s);
    2354                                                         else THROW_ERROR(status_end_element_mismatch, s);
     3362                                                        if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
     3363                                                        else PUGI__THROW_ERROR(status_end_element_mismatch, mark);
    23553364                                                }
    2356                                                        
    2357                                                 POPNODE(); // Pop.
    2358 
    2359                                                 SKIPWS();
     3365
     3366                                                PUGI__POPNODE(); // Pop.
     3367
     3368                                                PUGI__SKIPWS();
    23603369
    23613370                                                if (*s == 0)
    23623371                                                {
    2363                                                         if (endch != '>') THROW_ERROR(status_bad_end_element, s);
     3372                                                        if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
    23643373                                                }
    23653374                                                else
    23663375                                                {
    2367                                                         if (*s != '>') THROW_ERROR(status_bad_end_element, s);
     3376                                                        if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
    23683377                                                        ++s;
    23693378                                                }
     
    23723381                                        {
    23733382                                                s = parse_question(s, cursor, optmsk, endch);
     3383                                                if (!s) return s;
    23743384
    23753385                                                assert(cursor);
    2376                                                 if ((cursor->header & xml_memory_page_type_mask) + 1 == node_declaration) goto LOC_ATTRIBUTES;
     3386                                                if (PUGI__NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES;
    23773387                                        }
    23783388                                        else if (*s == '!') // '<!...'
    23793389                                        {
    23803390                                                s = parse_exclamation(s, cursor, optmsk, endch);
     3391                                                if (!s) return s;
    23813392                                        }
    2382                                         else if (*s == 0 && endch == '?') THROW_ERROR(status_bad_pi, s);
    2383                                         else THROW_ERROR(status_unrecognized_tag, s);
     3393                                        else if (*s == 0 && endch == '?') PUGI__THROW_ERROR(status_bad_pi, s);
     3394                                        else PUGI__THROW_ERROR(status_unrecognized_tag, s);
    23843395                                }
    23853396                                else
     
    23873398                                        mark = s; // Save this offset while searching for a terminator.
    23883399
    2389                                         SKIPWS(); // Eat whitespace if no genuine PCDATA here.
    2390 
    2391                                         if ((!OPTSET(parse_ws_pcdata) || mark == s) && (*s == '<' || !*s))
     3400                                        PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
     3401
     3402                                        if (*s == '<' || !*s)
    23923403                                        {
    2393                                                 continue;
     3404                                                // We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one
     3405                                                assert(mark != s);
     3406
     3407                                                if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI__OPTSET(parse_trim_pcdata))
     3408                                                {
     3409                                                        continue;
     3410                                                }
     3411                                                else if (PUGI__OPTSET(parse_ws_pcdata_single))
     3412                                                {
     3413                                                        if (s[0] != '<' || s[1] != '/' || cursor->first_child) continue;
     3414                                                }
    23943415                                        }
    23953416
    2396                                         s = mark;
    2397                                                        
    2398                                         if (cursor->parent)
     3417                                        if (!PUGI__OPTSET(parse_trim_pcdata))
     3418                                                s = mark;
     3419
     3420                                        if (cursor->parent || PUGI__OPTSET(parse_fragment))
    23993421                                        {
    2400                                                 PUSHNODE(node_pcdata); // Append a new node on the tree.
    2401                                                 cursor->value = s; // Save the offset.
     3422                                                if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value)
     3423                                                {
     3424                                                        cursor->value = s; // Save the offset.
     3425                                                }
     3426                                                else
     3427                                                {
     3428                                                        PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree.
     3429
     3430                                                        cursor->value = s; // Save the offset.
     3431
     3432                                                        PUGI__POPNODE(); // Pop since this is a standalone.
     3433                                                }
    24023434
    24033435                                                s = strconv_pcdata(s);
    2404                                                                
    2405                                                 POPNODE(); // Pop since this is a standalone.
    2406                                                
     3436
    24073437                                                if (!*s) break;
    24083438                                        }
    24093439                                        else
    24103440                                        {
    2411                                                 SCANFOR(*s == '<'); // '...<'
     3441                                                PUGI__SCANFOR(*s == '<'); // '...<'
    24123442                                                if (!*s) break;
    2413                                                
     3443
    24143444                                                ++s;
    24153445                                        }
     
    24213451
    24223452                        // check that last tag is closed
    2423                         if (cursor != xmldoc) THROW_ERROR(status_end_element_mismatch, s);
    2424                 }
    2425 
    2426                 static xml_parse_result parse(char_t* buffer, size_t length, xml_node_struct* root, unsigned int optmsk)
    2427                 {
    2428                         xml_document_struct* xmldoc = static_cast<xml_document_struct*>(root);
    2429 
    2430                         // store buffer for offset_debug
    2431                         xmldoc->buffer = buffer;
    2432 
     3453                        if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s);
     3454
     3455                        return s;
     3456                }
     3457
     3458        #ifdef PUGIXML_WCHAR_MODE
     3459                static char_t* parse_skip_bom(char_t* s)
     3460                {
     3461                        unsigned int bom = 0xfeff;
     3462                        return (s[0] == static_cast<wchar_t>(bom)) ? s + 1 : s;
     3463                }
     3464        #else
     3465                static char_t* parse_skip_bom(char_t* s)
     3466                {
     3467                        return (s[0] == '\xef' && s[1] == '\xbb' && s[2] == '\xbf') ? s + 3 : s;
     3468                }
     3469        #endif
     3470
     3471                static bool has_element_node_siblings(xml_node_struct* node)
     3472                {
     3473                        while (node)
     3474                        {
     3475                                if (PUGI__NODETYPE(node) == node_element) return true;
     3476
     3477                                node = node->next_sibling;
     3478                        }
     3479
     3480                        return false;
     3481                }
     3482
     3483                static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk)
     3484                {
    24333485                        // early-out for empty documents
    2434                         if (length == 0) return make_parse_result(status_ok);
     3486                        if (length == 0)
     3487                                return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element);
     3488
     3489                        // get last child of the root before parsing
     3490                        xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
    24353491
    24363492                        // create parser on stack
    2437                         xml_parser parser(*xmldoc);
     3493                        xml_parser parser(static_cast<xml_allocator*>(xmldoc));
    24383494
    24393495                        // save last character and make buffer zero-terminated (speeds up parsing)
    24403496                        char_t endch = buffer[length - 1];
    24413497                        buffer[length - 1] = 0;
    2442                        
     3498
     3499                        // skip BOM to make sure it does not end up as part of parse output
     3500                        char_t* buffer_data = parse_skip_bom(buffer);
     3501
    24433502                        // perform actual parsing
    2444                         int error = setjmp(parser.error_handler);
    2445 
    2446                         if (error == 0)
    2447                         {
    2448                                 parser.parse(buffer, xmldoc, optmsk, endch);
    2449                         }
    2450 
    2451                         xml_parse_result result = make_parse_result(static_cast<xml_parse_status>(error), parser.error_offset ? parser.error_offset - buffer : 0);
     3503                        parser.parse_tree(buffer_data, root, optmsk, endch);
     3504
     3505                        xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
    24523506                        assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
    24533507
    2454                         // update allocator state
    2455                         *static_cast<xml_allocator*>(xmldoc) = parser.alloc;
    2456 
    2457                         // since we removed last character, we have to handle the only possible false positive
    2458                         if (result && endch == '<')
    2459                         {
    2460                                 // there's no possible well-formed document with < at the end
    2461                                 return make_parse_result(status_unrecognized_tag, length);
     3508                        if (result)
     3509                        {
     3510                                // since we removed last character, we have to handle the only possible false positive (stray <)
     3511                                if (endch == '<')
     3512                                        return make_parse_result(status_unrecognized_tag, length - 1);
     3513
     3514                                // check if there are any element nodes parsed
     3515                                xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0;
     3516
     3517                                if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
     3518                                        return make_parse_result(status_no_document_element, length - 1);
     3519                        }
     3520                        else
     3521                        {
     3522                                // roll back offset if it occurs on a null terminator in the source buffer
     3523                                if (result.offset > 0 && static_cast<size_t>(result.offset) == length - 1 && endch == 0)
     3524                                        result.offset--;
    24623525                        }
    24633526
     
    24673530
    24683531        // Output facilities
    2469         xml_encoding get_write_native_encoding()
     3532        PUGI__FN xml_encoding get_write_native_encoding()
    24703533        {
    24713534        #ifdef PUGIXML_WCHAR_MODE
     
    24763539        }
    24773540
    2478         xml_encoding get_write_encoding(xml_encoding encoding)
     3541        PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
    24793542        {
    24803543                // replace wchar encoding with utf implementation
     
    24943557        }
    24953558
     3559        template <typename D, typename T> PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T)
     3560        {
     3561                PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
     3562
     3563                typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
     3564
     3565                return static_cast<size_t>(end - dest) * sizeof(*dest);
     3566        }
     3567
     3568        template <typename D, typename T> PUGI__FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap)
     3569        {
     3570                PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
     3571
     3572                typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
     3573
     3574                if (opt_swap)
     3575                {
     3576                        for (typename T::value_type i = dest; i != end; ++i)
     3577                                *i = endian_swap(*i);
     3578                }
     3579
     3580                return static_cast<size_t>(end - dest) * sizeof(*dest);
     3581        }
     3582
    24963583#ifdef PUGIXML_WCHAR_MODE
    2497         size_t get_valid_length(const char_t* data, size_t length)
    2498         {
    2499                 assert(length > 0);
    2500 
    2501                 // discard last character if it's the lead of a surrogate pair 
    2502                 return (sizeof(wchar_t) == 2 && (unsigned)(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
    2503         }
    2504 
    2505         size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding)
     3584        PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
     3585        {
     3586                if (length < 1) return 0;
     3587
     3588                // discard last character if it's the lead of a surrogate pair
     3589                return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
     3590        }
     3591
     3592        PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
    25063593        {
    25073594                // only endian-swapping is required
    25083595                if (need_endian_swap_utf(encoding, get_wchar_encoding()))
    25093596                {
    2510                         convert_wchar_endian_swap(reinterpret_cast<char_t*>(result), data, length);
     3597                        convert_wchar_endian_swap(r_char, data, length);
    25113598
    25123599                        return length * sizeof(char_t);
    25133600                }
    2514        
     3601
    25153602                // convert to utf8
    25163603                if (encoding == encoding_utf8)
    2517                 {
    2518                         uint8_t* dest = reinterpret_cast<uint8_t*>(result);
    2519 
    2520                         uint8_t* end = sizeof(wchar_t) == 2 ?
    2521                                 utf_decoder<utf8_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(data), length, dest) :
    2522                                 utf_decoder<utf8_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(data), length, dest);
    2523 
    2524                         return static_cast<size_t>(end - dest);
    2525                 }
     3604                        return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer());
    25263605
    25273606                // convert to utf16
    25283607                if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
    25293608                {
    2530                         uint16_t* dest = reinterpret_cast<uint16_t*>(result);
    2531 
    2532                         // convert to native utf16
    2533                         uint16_t* end = utf_decoder<utf16_writer>::decode_utf32_block(reinterpret_cast<const uint32_t*>(data), length, dest);
    2534 
    2535                         // swap if necessary
    25363609                        xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
    25373610
    2538                         if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
    2539 
    2540                         return static_cast<size_t>(end - dest) * sizeof(uint16_t);
     3611                        return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding);
    25413612                }
    25423613
     
    25443615                if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
    25453616                {
    2546                         uint32_t* dest = reinterpret_cast<uint32_t*>(result);
    2547 
    2548                         // convert to native utf32
    2549                         uint32_t* end = utf_decoder<utf32_writer>::decode_utf16_block(reinterpret_cast<const uint16_t*>(data), length, dest);
    2550 
    2551                         // swap if necessary
    25523617                        xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
    25533618
    2554                         if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
    2555 
    2556                         return static_cast<size_t>(end - dest) * sizeof(uint32_t);
    2557                 }
    2558 
    2559                 assert(!"Invalid encoding");
     3619                        return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding);
     3620                }
     3621
     3622                // convert to latin1
     3623                if (encoding == encoding_latin1)
     3624                        return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer());
     3625
     3626                assert(false && "Invalid encoding");
    25603627                return 0;
    25613628        }
    25623629#else
    2563         size_t get_valid_length(const char_t* data, size_t length)
    2564         {
    2565                 assert(length > 4);
     3630        PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
     3631        {
     3632                if (length < 5) return 0;
    25663633
    25673634                for (size_t i = 1; i <= 4; ++i)
     
    25773644        }
    25783645
    2579         size_t convert_buffer(char* result, const char_t* data, size_t length, xml_encoding encoding)
     3646        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)
    25803647        {
    25813648                if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
    25823649                {
    2583                         uint16_t* dest = reinterpret_cast<uint16_t*>(result);
    2584 
    2585                         // convert to native utf16
    2586                         uint16_t* end = utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
    2587 
    2588                         // swap if necessary
    25893650                        xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
    25903651
    2591                         if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
    2592 
    2593                         return static_cast<size_t>(end - dest) * sizeof(uint16_t);
     3652                        return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding);
    25943653                }
    25953654
    25963655                if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
    25973656                {
    2598                         uint32_t* dest = reinterpret_cast<uint32_t*>(result);
    2599 
    2600                         // convert to native utf32
    2601                         uint32_t* end = utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
    2602 
    2603                         // swap if necessary
    26043657                        xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
    26053658
    2606                         if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
    2607 
    2608                         return static_cast<size_t>(end - dest) * sizeof(uint32_t);
    2609                 }
    2610 
    2611                 assert(!"Invalid encoding");
     3659                        return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding);
     3660                }
     3661
     3662                if (encoding == encoding_latin1)
     3663                        return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer());
     3664
     3665                assert(false && "Invalid encoding");
    26123666                return 0;
    26133667        }
     
    26203674
    26213675        public:
    2622                 xml_buffered_writer(xml_writer& writer, xml_encoding user_encoding): writer(writer), bufsize(0), encoding(get_write_encoding(user_encoding))
    2623                 {
    2624                 }
    2625 
    2626                 ~xml_buffered_writer()
    2627                 {
    2628                         flush();
    2629                 }
    2630 
    2631                 void flush()
     3676                xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
     3677                {
     3678                        PUGI__STATIC_ASSERT(bufcapacity >= 8);
     3679                }
     3680
     3681                size_t flush()
    26323682                {
    26333683                        flush(buffer, bufsize);
    26343684                        bufsize = 0;
     3685                        return 0;
    26353686                }
    26363687
     
    26453696                        {
    26463697                                // convert chunk
    2647                                 size_t result = convert_buffer(scratch, data, size, encoding);
     3698                                size_t result = convert_buffer_output(scratch.data_char, scratch.data_u8, scratch.data_u16, scratch.data_u32, data, size, encoding);
    26483699                                assert(result <= sizeof(scratch));
    26493700
    26503701                                // write data
    2651                                 writer.write(scratch, result);
    2652                         }
    2653                 }
    2654 
    2655                 void write(const char_t* data, size_t length)
    2656                 {
    2657                         if (bufsize + length > bufcapacity)
    2658                         {
    2659                                 // flush the remaining buffer contents
    2660                                 flush();
    2661 
    2662                                 // handle large chunks
    2663                                 if (length > bufcapacity)
    2664                                 {
    2665                                         if (encoding == get_write_native_encoding())
    2666                                         {
    2667                                                 // fast path, can just write data chunk
    2668                                                 writer.write(data, length * sizeof(char_t));
    2669                                                 return;
    2670                                         }
    2671 
    2672                                         // need to convert in suitable chunks
    2673                                         while (length > bufcapacity)
    2674                                         {
    2675                                                 // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer
    2676                                                 // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
    2677                                                 size_t chunk_size = get_valid_length(data, bufcapacity);
    2678 
    2679                                                 // convert chunk and write
    2680                                                 flush(data, chunk_size);
    2681 
    2682                                                 // iterate
    2683                                                 data += chunk_size;
    2684                                                 length -= chunk_size;
    2685                                         }
    2686 
    2687                                         // small tail is copied below
    2688                                         bufsize = 0;
    2689                                 }
     3702                                writer.write(scratch.data_u8, result);
     3703                        }
     3704                }
     3705
     3706                void write_direct(const char_t* data, size_t length)
     3707                {
     3708                        // flush the remaining buffer contents
     3709                        flush();
     3710
     3711                        // handle large chunks
     3712                        if (length > bufcapacity)
     3713                        {
     3714                                if (encoding == get_write_native_encoding())
     3715                                {
     3716                                        // fast path, can just write data chunk
     3717                                        writer.write(data, length * sizeof(char_t));
     3718                                        return;
     3719                                }
     3720
     3721                                // need to convert in suitable chunks
     3722                                while (length > bufcapacity)
     3723                                {
     3724                                        // get chunk size by selecting such number of characters that are guaranteed to fit into scratch buffer
     3725                                        // and form a complete codepoint sequence (i.e. discard start of last codepoint if necessary)
     3726                                        size_t chunk_size = get_valid_length(data, bufcapacity);
     3727                                        assert(chunk_size);
     3728
     3729                                        // convert chunk and write
     3730                                        flush(data, chunk_size);
     3731
     3732                                        // iterate
     3733                                        data += chunk_size;
     3734                                        length -= chunk_size;
     3735                                }
     3736
     3737                                // small tail is copied below
     3738                                bufsize = 0;
    26903739                        }
    26913740
     
    26943743                }
    26953744
    2696                 void write(const char_t* data)
    2697                 {
    2698                         write(data, strlength(data));
     3745                void write_buffer(const char_t* data, size_t length)
     3746                {
     3747                        size_t offset = bufsize;
     3748
     3749                        if (offset + length <= bufcapacity)
     3750                        {
     3751                                memcpy(buffer + offset, data, length * sizeof(char_t));
     3752                                bufsize = offset + length;
     3753                        }
     3754                        else
     3755                        {
     3756                                write_direct(data, length);
     3757                        }
     3758                }
     3759
     3760                void write_string(const char_t* data)
     3761                {
     3762                        // write the part of the string that fits in the buffer
     3763                        size_t offset = bufsize;
     3764
     3765                        while (*data && offset < bufcapacity)
     3766                                buffer[offset++] = *data++;
     3767
     3768                        // write the rest
     3769                        if (offset < bufcapacity)
     3770                        {
     3771                                bufsize = offset;
     3772                        }
     3773                        else
     3774                        {
     3775                                // backtrack a bit if we have split the codepoint
     3776                                size_t length = offset - bufsize;
     3777                                size_t extra = length - get_valid_length(data - length, length);
     3778
     3779                                bufsize = offset - extra;
     3780
     3781                                write_direct(data - extra, strlength(data) + extra);
     3782                        }
    26993783                }
    27003784
    27013785                void write(char_t d0)
    27023786                {
    2703                         if (bufsize + 1 > bufcapacity) flush();
    2704 
    2705                         buffer[bufsize + 0] = d0;
    2706                         bufsize += 1;
     3787                        size_t offset = bufsize;
     3788                        if (offset > bufcapacity - 1) offset = flush();
     3789
     3790                        buffer[offset + 0] = d0;
     3791                        bufsize = offset + 1;
    27073792                }
    27083793
    27093794                void write(char_t d0, char_t d1)
    27103795                {
    2711                         if (bufsize + 2 > bufcapacity) flush();
    2712 
    2713                         buffer[bufsize + 0] = d0;
    2714                         buffer[bufsize + 1] = d1;
    2715                         bufsize += 2;
     3796                        size_t offset = bufsize;
     3797                        if (offset > bufcapacity - 2) offset = flush();
     3798
     3799                        buffer[offset + 0] = d0;
     3800                        buffer[offset + 1] = d1;
     3801                        bufsize = offset + 2;
    27163802                }
    27173803
    27183804                void write(char_t d0, char_t d1, char_t d2)
    27193805                {
    2720                         if (bufsize + 3 > bufcapacity) flush();
    2721 
    2722                         buffer[bufsize + 0] = d0;
    2723                         buffer[bufsize + 1] = d1;
    2724                         buffer[bufsize + 2] = d2;
    2725                         bufsize += 3;
     3806                        size_t offset = bufsize;
     3807                        if (offset > bufcapacity - 3) offset = flush();
     3808
     3809                        buffer[offset + 0] = d0;
     3810                        buffer[offset + 1] = d1;
     3811                        buffer[offset + 2] = d2;
     3812                        bufsize = offset + 3;
    27263813                }
    27273814
    27283815                void write(char_t d0, char_t d1, char_t d2, char_t d3)
    27293816                {
    2730                         if (bufsize + 4 > bufcapacity) flush();
    2731 
    2732                         buffer[bufsize + 0] = d0;
    2733                         buffer[bufsize + 1] = d1;
    2734                         buffer[bufsize + 2] = d2;
    2735                         buffer[bufsize + 3] = d3;
    2736                         bufsize += 4;
     3817                        size_t offset = bufsize;
     3818                        if (offset > bufcapacity - 4) offset = flush();
     3819
     3820                        buffer[offset + 0] = d0;
     3821                        buffer[offset + 1] = d1;
     3822                        buffer[offset + 2] = d2;
     3823                        buffer[offset + 3] = d3;
     3824                        bufsize = offset + 4;
    27373825                }
    27383826
    27393827                void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4)
    27403828                {
    2741                         if (bufsize + 5 > bufcapacity) flush();
    2742 
    2743                         buffer[bufsize + 0] = d0;
    2744                         buffer[bufsize + 1] = d1;
    2745                         buffer[bufsize + 2] = d2;
    2746                         buffer[bufsize + 3] = d3;
    2747                         buffer[bufsize + 4] = d4;
    2748                         bufsize += 5;
     3829                        size_t offset = bufsize;
     3830                        if (offset > bufcapacity - 5) offset = flush();
     3831
     3832                        buffer[offset + 0] = d0;
     3833                        buffer[offset + 1] = d1;
     3834                        buffer[offset + 2] = d2;
     3835                        buffer[offset + 3] = d3;
     3836                        buffer[offset + 4] = d4;
     3837                        bufsize = offset + 5;
    27493838                }
    27503839
    27513840                void write(char_t d0, char_t d1, char_t d2, char_t d3, char_t d4, char_t d5)
    27523841                {
    2753                         if (bufsize + 6 > bufcapacity) flush();
    2754 
    2755                         buffer[bufsize + 0] = d0;
    2756                         buffer[bufsize + 1] = d1;
    2757                         buffer[bufsize + 2] = d2;
    2758                         buffer[bufsize + 3] = d3;
    2759                         buffer[bufsize + 4] = d4;
    2760                         buffer[bufsize + 5] = d5;
    2761                         bufsize += 6;
     3842                        size_t offset = bufsize;
     3843                        if (offset > bufcapacity - 6) offset = flush();
     3844
     3845                        buffer[offset + 0] = d0;
     3846                        buffer[offset + 1] = d1;
     3847                        buffer[offset + 2] = d2;
     3848                        buffer[offset + 3] = d3;
     3849                        buffer[offset + 4] = d4;
     3850                        buffer[offset + 5] = d5;
     3851                        bufsize = offset + 6;
    27623852                }
    27633853
     
    27653855                // utf16 maximum expansion: x2 (-> utf32)
    27663856                // utf32 maximum expansion: x1
    2767                 enum { bufcapacity = 2048 };
     3857                enum
     3858                {
     3859                        bufcapacitybytes =
     3860                        #ifdef PUGIXML_MEMORY_OUTPUT_STACK
     3861                                PUGIXML_MEMORY_OUTPUT_STACK
     3862                        #else
     3863                                10240
     3864                        #endif
     3865                        ,
     3866                        bufcapacity = bufcapacitybytes / (sizeof(char_t) + 4)
     3867                };
    27683868
    27693869                char_t buffer[bufcapacity];
    2770                 char scratch[4 * bufcapacity];
     3870
     3871                union
     3872                {
     3873                        uint8_t data_u8[4 * bufcapacity];
     3874                        uint16_t data_u16[2 * bufcapacity];
     3875                        uint32_t data_u32[bufcapacity];
     3876                        char_t data_char[bufcapacity];
     3877                } scratch;
    27713878
    27723879                xml_writer& writer;
     
    27753882        };
    27763883
    2777         void write_bom(xml_writer& writer, xml_encoding encoding)
    2778         {
    2779                 switch (encoding)
    2780                 {
    2781                 case encoding_utf8:
    2782                         writer.write("\xef\xbb\xbf", 3);
    2783                         break;
    2784 
    2785                 case encoding_utf16_be:
    2786                         writer.write("\xfe\xff", 2);
    2787                         break;
    2788 
    2789                 case encoding_utf16_le:
    2790                         writer.write("\xff\xfe", 2);
    2791                         break;
    2792 
    2793                 case encoding_utf32_be:
    2794                         writer.write("\x00\x00\xfe\xff", 4);
    2795                         break;
    2796 
    2797                 case encoding_utf32_le:
    2798                         writer.write("\xff\xfe\x00\x00", 4);
    2799                         break;
    2800 
    2801                 default:
    2802                         assert(!"Invalid encoding");
    2803                 }
    2804         }
    2805 
    2806         void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type)
     3884        PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type)
    28073885        {
    28083886                while (*s)
    28093887                {
    28103888                        const char_t* prev = s;
    2811                        
     3889
    28123890                        // While *s is a usual symbol
    2813                         while (!IS_CHARTYPEX(*s, type)) ++s;
    2814                
    2815                         writer.write(prev, static_cast<size_t>(s - prev));
     3891                        PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type));
     3892
     3893                        writer.write_buffer(prev, static_cast<size_t>(s - prev));
    28163894
    28173895                        switch (*s)
     
    28453923        }
    28463924
    2847         void text_output_cdata(xml_buffered_writer& writer, const char_t* s)
     3925        PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
     3926        {
     3927                if (flags & format_no_escapes)
     3928                        writer.write_string(s);
     3929                else
     3930                        text_output_escaped(writer, s, type);
     3931        }
     3932
     3933        PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s)
    28483934        {
    28493935                do
     
    28603946                        if (*s) s += 2;
    28613947
    2862                         writer.write(prev, static_cast<size_t>(s - prev));
     3948                        writer.write_buffer(prev, static_cast<size_t>(s - prev));
    28633949
    28643950                        writer.write(']', ']', '>');
     
    28673953        }
    28683954
    2869         void node_output_attributes(xml_buffered_writer& writer, const xml_node& node)
     3955        PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth)
     3956        {
     3957                switch (indent_length)
     3958                {
     3959                case 1:
     3960                {
     3961                        for (unsigned int i = 0; i < depth; ++i)
     3962                                writer.write(indent[0]);
     3963                        break;
     3964                }
     3965
     3966                case 2:
     3967                {
     3968                        for (unsigned int i = 0; i < depth; ++i)
     3969                                writer.write(indent[0], indent[1]);
     3970                        break;
     3971                }
     3972
     3973                case 3:
     3974                {
     3975                        for (unsigned int i = 0; i < depth; ++i)
     3976                                writer.write(indent[0], indent[1], indent[2]);
     3977                        break;
     3978                }
     3979
     3980                case 4:
     3981                {
     3982                        for (unsigned int i = 0; i < depth; ++i)
     3983                                writer.write(indent[0], indent[1], indent[2], indent[3]);
     3984                        break;
     3985                }
     3986
     3987                default:
     3988                {
     3989                        for (unsigned int i = 0; i < depth; ++i)
     3990                                writer.write_buffer(indent, indent_length);
     3991                }
     3992                }
     3993        }
     3994
     3995        PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s)
     3996        {
     3997                writer.write('<', '!', '-', '-');
     3998
     3999                while (*s)
     4000                {
     4001                        const char_t* prev = s;
     4002
     4003                        // look for -\0 or -- sequence - we can't output it since -- is illegal in comment body
     4004                        while (*s && !(s[0] == '-' && (s[1] == '-' || s[1] == 0))) ++s;
     4005
     4006                        writer.write_buffer(prev, static_cast<size_t>(s - prev));
     4007
     4008                        if (*s)
     4009                        {
     4010                                assert(*s == '-');
     4011
     4012                                writer.write('-', ' ');
     4013                                ++s;
     4014                        }
     4015                }
     4016
     4017                writer.write('-', '-', '>');
     4018        }
     4019
     4020        PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s)
     4021        {
     4022                while (*s)
     4023                {
     4024                        const char_t* prev = s;
     4025
     4026                        // look for ?> sequence - we can't output it since ?> terminates PI
     4027                        while (*s && !(s[0] == '?' && s[1] == '>')) ++s;
     4028
     4029                        writer.write_buffer(prev, static_cast<size_t>(s - prev));
     4030
     4031                        if (*s)
     4032                        {
     4033                                assert(s[0] == '?' && s[1] == '>');
     4034
     4035                                writer.write('?', ' ', '>');
     4036                                s += 2;
     4037                        }
     4038                }
     4039        }
     4040
     4041        PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)
    28704042        {
    28714043                const char_t* default_name = PUGIXML_TEXT(":anonymous");
    28724044
    2873                 for (xml_attribute a = node.first_attribute(); a; a = a.next_attribute())
    2874                 {
    2875                         writer.write(' ');
    2876                         writer.write(a.name()[0] ? a.name() : default_name);
     4045                for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
     4046                {
     4047                        if ((flags & (format_indent_attributes | format_raw)) == format_indent_attributes)
     4048                        {
     4049                                writer.write('\n');
     4050
     4051                                text_output_indent(writer, indent, indent_length, depth + 1);
     4052                        }
     4053                        else
     4054                        {
     4055                                writer.write(' ');
     4056                        }
     4057
     4058                        writer.write_string(a->name ? a->name + 0 : default_name);
    28774059                        writer.write('=', '"');
    28784060
    2879                         text_output_escaped(writer, a.value(), ctx_special_attr);
     4061                        if (a->value)
     4062                                text_output(writer, a->value, ctx_special_attr, flags);
    28804063
    28814064                        writer.write('"');
     
    28834066        }
    28844067
    2885         void node_output(xml_buffered_writer& writer, const xml_node& node, const char_t* indent, unsigned int flags, unsigned int depth)
     4068        PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, const char_t* indent, size_t indent_length, unsigned int flags, unsigned int depth)
    28864069        {
    28874070                const char_t* default_name = PUGIXML_TEXT(":anonymous");
    2888 
    2889                 if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
    2890                         for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
    2891 
    2892                 switch (node.type())
    2893                 {
    2894                 case node_document:
    2895                 {
    2896                         for (xml_node n = node.first_child(); n; n = n.next_sibling())
    2897                                 node_output(writer, n, indent, flags, depth);
    2898                         break;
    2899                 }
    2900                        
    2901                 case node_element:
    2902                 {
    2903                         const char_t* name = node.name()[0] ? node.name() : default_name;
    2904 
    2905                         writer.write('<');
    2906                         writer.write(name);
    2907 
    2908                         node_output_attributes(writer, node);
    2909 
    2910                         if (flags & format_raw)
    2911                         {
    2912                                 if (!node.first_child())
    2913                                         writer.write(' ', '/', '>');
     4071                const char_t* name = node->name ? node->name + 0 : default_name;
     4072
     4073                writer.write('<');
     4074                writer.write_string(name);
     4075
     4076                if (node->first_attribute)
     4077                        node_output_attributes(writer, node, indent, indent_length, flags, depth);
     4078
     4079                // element nodes can have value if parse_embed_pcdata was used
     4080                if (!node->value)
     4081                {
     4082                        if (!node->first_child)
     4083                        {
     4084                                if (flags & format_no_empty_element_tags)
     4085                                {
     4086                                        writer.write('>', '<', '/');
     4087                                        writer.write_string(name);
     4088                                        writer.write('>');
     4089
     4090                                        return false;
     4091                                }
    29144092                                else
    29154093                                {
    2916                                         writer.write('>');
    2917 
    2918                                         for (xml_node n = node.first_child(); n; n = n.next_sibling())
    2919                                                 node_output(writer, n, indent, flags, depth + 1);
    2920 
    2921                                         writer.write('<', '/');
    2922                                         writer.write(name);
    2923                                         writer.write('>');
    2924                                 }
    2925                         }
    2926                         else if (!node.first_child())
    2927                                 writer.write(' ', '/', '>', '\n');
    2928                         else if (node.first_child() == node.last_child() && (node.first_child().type() == node_pcdata || node.first_child().type() == node_cdata))
     4094                                        if ((flags & format_raw) == 0)
     4095                                                writer.write(' ');
     4096
     4097                                        writer.write('/', '>');
     4098
     4099                                        return false;
     4100                                }
     4101                        }
     4102                        else
    29294103                        {
    29304104                                writer.write('>');
    29314105
    2932                 if (node.first_child().type() == node_pcdata)
    2933                     text_output_escaped(writer, node.first_child().value(), ctx_special_pcdata);
    2934                 else
    2935                     text_output_cdata(writer, node.first_child().value());
    2936 
     4106                                return true;
     4107                        }
     4108                }
     4109                else
     4110                {
     4111                        writer.write('>');
     4112
     4113                        text_output(writer, node->value, ctx_special_pcdata, flags);
     4114
     4115                        if (!node->first_child)
     4116                        {
    29374117                                writer.write('<', '/');
    2938                                 writer.write(name);
    2939                                 writer.write('>', '\n');
     4118                                writer.write_string(name);
     4119                                writer.write('>');
     4120
     4121                                return false;
    29404122                        }
    29414123                        else
    29424124                        {
    2943                                 writer.write('>', '\n');
    2944                                
    2945                                 for (xml_node n = node.first_child(); n; n = n.next_sibling())
    2946                                         node_output(writer, n, indent, flags, depth + 1);
    2947 
    2948                                 if ((flags & format_indent) != 0 && (flags & format_raw) == 0)
    2949                                         for (unsigned int i = 0; i < depth; ++i) writer.write(indent);
    2950                                
    2951                                 writer.write('<', '/');
    2952                                 writer.write(name);
    2953                                 writer.write('>', '\n');
    2954                         }
    2955 
    2956                         break;
    2957                 }
    2958                
    2959                 case node_pcdata:
    2960                         text_output_escaped(writer, node.value(), ctx_special_pcdata);
    2961                         if ((flags & format_raw) == 0) writer.write('\n');
    2962                         break;
    2963 
    2964                 case node_cdata:
    2965                         text_output_cdata(writer, node.value());
    2966                         if ((flags & format_raw) == 0) writer.write('\n');
    2967                         break;
    2968 
    2969                 case node_comment:
    2970                         writer.write('<', '!', '-', '-');
    2971                         writer.write(node.value());
    2972                         writer.write('-', '-', '>');
    2973                         if ((flags & format_raw) == 0) writer.write('\n');
    2974                         break;
    2975 
    2976                 case node_pi:
    2977                 case node_declaration:
    2978                         writer.write('<', '?');
    2979                         writer.write(node.name()[0] ? node.name() : default_name);
    2980 
    2981                         if (node.type() == node_declaration)
    2982                         {
    2983                                 node_output_attributes(writer, node);
    2984                         }
    2985                         else if (node.value()[0])
    2986                         {
    2987                                 writer.write(' ');
    2988                                 writer.write(node.value());
    2989                         }
    2990 
    2991                         writer.write('?', '>');
    2992                         if ((flags & format_raw) == 0) writer.write('\n');
    2993                         break;
    2994 
    2995                 case node_doctype:
    2996                         writer.write('<', '!', 'D', 'O', 'C');
    2997                         writer.write('T', 'Y', 'P', 'E');
    2998 
    2999             if (node.value()[0])
    3000             {
    3001                 writer.write(' ');
    3002                 writer.write(node.value());
    3003             }
    3004 
    3005             writer.write('>');
    3006                         if ((flags & format_raw) == 0) writer.write('\n');
    3007                         break;
    3008 
    3009                 default:
    3010                         assert(!"Invalid node type");
    3011                 }
    3012         }
    3013 
    3014         inline bool has_declaration(const xml_node& node)
    3015         {
    3016                 for (xml_node child = node.first_child(); child; child = child.next_sibling())
    3017                 {
    3018                         xml_node_type type = child.type();
     4125                                return true;
     4126                        }
     4127                }
     4128        }
     4129
     4130        PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node)
     4131        {
     4132                const char_t* default_name = PUGIXML_TEXT(":anonymous");
     4133                const char_t* name = node->name ? node->name + 0 : default_name;
     4134
     4135                writer.write('<', '/');
     4136                writer.write_string(name);
     4137                writer.write('>');
     4138        }
     4139
     4140        PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)
     4141        {
     4142                const char_t* default_name = PUGIXML_TEXT(":anonymous");
     4143
     4144                switch (PUGI__NODETYPE(node))
     4145                {
     4146                        case node_pcdata:
     4147                                text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags);
     4148                                break;
     4149
     4150                        case node_cdata:
     4151                                text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
     4152                                break;
     4153
     4154                        case node_comment:
     4155                                node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
     4156                                break;
     4157
     4158                        case node_pi:
     4159                                writer.write('<', '?');
     4160                                writer.write_string(node->name ? node->name + 0 : default_name);
     4161
     4162                                if (node->value)
     4163                                {
     4164                                        writer.write(' ');
     4165                                        node_output_pi_value(writer, node->value);
     4166                                }
     4167
     4168                                writer.write('?', '>');
     4169                                break;
     4170
     4171                        case node_declaration:
     4172                                writer.write('<', '?');
     4173                                writer.write_string(node->name ? node->name + 0 : default_name);
     4174                                node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0);
     4175                                writer.write('?', '>');
     4176                                break;
     4177
     4178                        case node_doctype:
     4179                                writer.write('<', '!', 'D', 'O', 'C');
     4180                                writer.write('T', 'Y', 'P', 'E');
     4181
     4182                                if (node->value)
     4183                                {
     4184                                        writer.write(' ');
     4185                                        writer.write_string(node->value);
     4186                                }
     4187
     4188                                writer.write('>');
     4189                                break;
     4190
     4191                        default:
     4192                                assert(false && "Invalid node type");
     4193                }
     4194        }
     4195
     4196        enum indent_flags_t
     4197        {
     4198                indent_newline = 1,
     4199                indent_indent = 2
     4200        };
     4201
     4202        PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth)
     4203        {
     4204                size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0;
     4205                unsigned int indent_flags = indent_indent;
     4206
     4207                xml_node_struct* node = root;
     4208
     4209                do
     4210                {
     4211                        assert(node);
     4212
     4213                        // begin writing current node
     4214                        if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata)
     4215                        {
     4216                                node_output_simple(writer, node, flags);
     4217
     4218                                indent_flags = 0;
     4219                        }
     4220                        else
     4221                        {
     4222                                if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
     4223                                        writer.write('\n');
     4224
     4225                                if ((indent_flags & indent_indent) && indent_length)
     4226                                        text_output_indent(writer, indent, indent_length, depth);
     4227
     4228                                if (PUGI__NODETYPE(node) == node_element)
     4229                                {
     4230                                        indent_flags = indent_newline | indent_indent;
     4231
     4232                                        if (node_output_start(writer, node, indent, indent_length, flags, depth))
     4233                                        {
     4234                                                // element nodes can have value if parse_embed_pcdata was used
     4235                                                if (node->value)
     4236                                                        indent_flags = 0;
     4237
     4238                                                node = node->first_child;
     4239                                                depth++;
     4240                                                continue;
     4241                                        }
     4242                                }
     4243                                else if (PUGI__NODETYPE(node) == node_document)
     4244                                {
     4245                                        indent_flags = indent_indent;
     4246
     4247                                        if (node->first_child)
     4248                                        {
     4249                                                node = node->first_child;
     4250                                                continue;
     4251                                        }
     4252                                }
     4253                                else
     4254                                {
     4255                                        node_output_simple(writer, node, flags);
     4256
     4257                                        indent_flags = indent_newline | indent_indent;
     4258                                }
     4259                        }
     4260
     4261                        // continue to the next node
     4262                        while (node != root)
     4263                        {
     4264                                if (node->next_sibling)
     4265                                {
     4266                                        node = node->next_sibling;
     4267                                        break;
     4268                                }
     4269
     4270                                node = node->parent;
     4271
     4272                                // write closing node
     4273                                if (PUGI__NODETYPE(node) == node_element)
     4274                                {
     4275                                        depth--;
     4276
     4277                                        if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
     4278                                                writer.write('\n');
     4279
     4280                                        if ((indent_flags & indent_indent) && indent_length)
     4281                                                text_output_indent(writer, indent, indent_length, depth);
     4282
     4283                                        node_output_end(writer, node);
     4284
     4285                                        indent_flags = indent_newline | indent_indent;
     4286                                }
     4287                        }
     4288                }
     4289                while (node != root);
     4290
     4291                if ((indent_flags & indent_newline) && (flags & format_raw) == 0)
     4292                        writer.write('\n');
     4293        }
     4294
     4295        PUGI__FN bool has_declaration(xml_node_struct* node)
     4296        {
     4297                for (xml_node_struct* child = node->first_child; child; child = child->next_sibling)
     4298                {
     4299                        xml_node_type type = PUGI__NODETYPE(child);
    30194300
    30204301                        if (type == node_declaration) return true;
     
    30254306        }
    30264307
    3027         inline bool allow_insert_child(xml_node_type parent, xml_node_type child)
     4308        PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node)
     4309        {
     4310                for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
     4311                        if (a == attr)
     4312                                return true;
     4313
     4314                return false;
     4315        }
     4316
     4317        PUGI__FN bool allow_insert_attribute(xml_node_type parent)
     4318        {
     4319                return parent == node_element || parent == node_declaration;
     4320        }
     4321
     4322        PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child)
    30284323        {
    30294324                if (parent != node_document && parent != node_element) return false;
     
    30344329        }
    30354330
    3036         void recursive_copy_skip(xml_node& dest, const xml_node& source, const xml_node& skip)
    3037         {
    3038                 assert(dest.type() == source.type());
    3039 
    3040                 switch (source.type())
    3041                 {
    3042                 case node_element:
    3043                 {
    3044                         dest.set_name(source.name());
    3045 
    3046                         for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
    3047                                 dest.append_attribute(a.name()).set_value(a.value());
    3048 
    3049                         for (xml_node c = source.first_child(); c; c = c.next_sibling())
    3050                         {
    3051                                 if (c == skip) continue;
    3052 
    3053                                 xml_node cc = dest.append_child(c.type());
    3054                                 assert(cc);
    3055 
    3056                                 recursive_copy_skip(cc, c, skip);
    3057                         }
    3058 
    3059                         break;
    3060                 }
    3061 
    3062                 case node_pcdata:
    3063                 case node_cdata:
    3064                 case node_comment:
    3065         case node_doctype:
    3066                         dest.set_value(source.value());
    3067                         break;
    3068 
    3069                 case node_pi:
    3070                         dest.set_name(source.name());
    3071                         dest.set_value(source.value());
    3072                         break;
    3073 
    3074                 case node_declaration:
    3075                 {
    3076                         dest.set_name(source.name());
    3077 
    3078                         for (xml_attribute a = source.first_attribute(); a; a = a.next_attribute())
    3079                                 dest.append_attribute(a.name()).set_value(a.value());
    3080 
    3081                         break;
    3082                 }
    3083 
    3084                 default:
    3085                         assert(!"Invalid node type");
    3086                 }
     4331        PUGI__FN bool allow_move(xml_node parent, xml_node child)
     4332        {
     4333                // check that child can be a child of parent
     4334                if (!allow_insert_child(parent.type(), child.type()))
     4335                        return false;
     4336
     4337                // check that node is not moved between documents
     4338                if (parent.root() != child.root())
     4339                        return false;
     4340
     4341                // check that new parent is not in the child subtree
     4342                xml_node cur = parent;
     4343
     4344                while (cur)
     4345                {
     4346                        if (cur == child)
     4347                                return false;
     4348
     4349                        cur = cur.parent();
     4350                }
     4351
     4352                return true;
     4353        }
     4354
     4355        template <typename String, typename Header>
     4356        PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)
     4357        {
     4358                assert(!dest && (header & header_mask) == 0);
     4359
     4360                if (source)
     4361                {
     4362                        if (alloc && (source_header & header_mask) == 0)
     4363                        {
     4364                                dest = source;
     4365
     4366                                // since strcpy_insitu can reuse document buffer memory we need to mark both source and dest as shared
     4367                                header |= xml_memory_page_contents_shared_mask;
     4368                                source_header |= xml_memory_page_contents_shared_mask;
     4369                        }
     4370                        else
     4371                                strcpy_insitu(dest, header, header_mask, source, strlength(source));
     4372                }
     4373        }
     4374
     4375        PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc)
     4376        {
     4377                node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc);
     4378                node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc);
     4379
     4380                for (xml_attribute_struct* sa = sn->first_attribute; sa; sa = sa->next_attribute)
     4381                {
     4382                        xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn));
     4383
     4384                        if (da)
     4385                        {
     4386                                node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
     4387                                node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
     4388                        }
     4389                }
     4390        }
     4391
     4392        PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)
     4393        {
     4394                xml_allocator& alloc = get_allocator(dn);
     4395                xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0;
     4396
     4397                node_copy_contents(dn, sn, shared_alloc);
     4398
     4399                xml_node_struct* dit = dn;
     4400                xml_node_struct* sit = sn->first_child;
     4401
     4402                while (sit && sit != sn)
     4403                {
     4404                        if (sit != dn)
     4405                        {
     4406                                xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit));
     4407
     4408                                if (copy)
     4409                                {
     4410                                        node_copy_contents(copy, sit, shared_alloc);
     4411
     4412                                        if (sit->first_child)
     4413                                        {
     4414                                                dit = copy;
     4415                                                sit = sit->first_child;
     4416                                                continue;
     4417                                        }
     4418                                }
     4419                        }
     4420
     4421                        // continue to the next node
     4422                        do
     4423                        {
     4424                                if (sit->next_sibling)
     4425                                {
     4426                                        sit = sit->next_sibling;
     4427                                        break;
     4428                                }
     4429
     4430                                sit = sit->parent;
     4431                                dit = dit->parent;
     4432                        }
     4433                        while (sit != sn);
     4434                }
     4435        }
     4436
     4437        PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
     4438        {
     4439                xml_allocator& alloc = get_allocator(da);
     4440                xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0;
     4441
     4442                node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
     4443                node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
     4444        }
     4445
     4446        inline bool is_text_node(xml_node_struct* node)
     4447        {
     4448                xml_node_type type = PUGI__NODETYPE(node);
     4449
     4450                return type == node_pcdata || type == node_cdata;
     4451        }
     4452
     4453        // get value with conversion functions
     4454        template <typename U> U string_to_integer(const char_t* value, U minneg, U maxpos)
     4455        {
     4456                U result = 0;
     4457                const char_t* s = value;
     4458
     4459                while (PUGI__IS_CHARTYPE(*s, ct_space))
     4460                        s++;
     4461
     4462                bool negative = (*s == '-');
     4463
     4464                s += (*s == '+' || *s == '-');
     4465
     4466                bool overflow = false;
     4467
     4468                if (s[0] == '0' && (s[1] | ' ') == 'x')
     4469                {
     4470                        s += 2;
     4471
     4472                        // since overflow detection relies on length of the sequence skip leading zeros
     4473                        while (*s == '0')
     4474                                s++;
     4475
     4476                        const char_t* start = s;
     4477
     4478                        for (;;)
     4479                        {
     4480                                if (static_cast<unsigned>(*s - '0') < 10)
     4481                                        result = result * 16 + (*s - '0');
     4482                                else if (static_cast<unsigned>((*s | ' ') - 'a') < 6)
     4483                                        result = result * 16 + ((*s | ' ') - 'a' + 10);
     4484                                else
     4485                                        break;
     4486
     4487                                s++;
     4488                        }
     4489
     4490                        size_t digits = static_cast<size_t>(s - start);
     4491
     4492                        overflow = digits > sizeof(U) * 2;
     4493                }
     4494                else
     4495                {
     4496                        // since overflow detection relies on length of the sequence skip leading zeros
     4497                        while (*s == '0')
     4498                                s++;
     4499
     4500                        const char_t* start = s;
     4501
     4502                        for (;;)
     4503                        {
     4504                                if (static_cast<unsigned>(*s - '0') < 10)
     4505                                        result = result * 10 + (*s - '0');
     4506                                else
     4507                                        break;
     4508
     4509                                s++;
     4510                        }
     4511
     4512                        size_t digits = static_cast<size_t>(s - start);
     4513
     4514                        PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);
     4515
     4516                        const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
     4517                        const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6';
     4518                        const size_t high_bit = sizeof(U) * 8 - 1;
     4519
     4520                        overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit)));
     4521                }
     4522
     4523                if (negative)
     4524                        return (overflow || result > minneg) ? 0 - minneg : 0 - result;
     4525                else
     4526                        return (overflow || result > maxpos) ? maxpos : result;
     4527        }
     4528
     4529        PUGI__FN int get_value_int(const char_t* value)
     4530        {
     4531                return string_to_integer<unsigned int>(value, 0 - static_cast<unsigned int>(INT_MIN), INT_MAX);
     4532        }
     4533
     4534        PUGI__FN unsigned int get_value_uint(const char_t* value)
     4535        {
     4536                return string_to_integer<unsigned int>(value, 0, UINT_MAX);
     4537        }
     4538
     4539        PUGI__FN double get_value_double(const char_t* value)
     4540        {
     4541        #ifdef PUGIXML_WCHAR_MODE
     4542                return wcstod(value, 0);
     4543        #else
     4544                return strtod(value, 0);
     4545        #endif
     4546        }
     4547
     4548        PUGI__FN float get_value_float(const char_t* value)
     4549        {
     4550        #ifdef PUGIXML_WCHAR_MODE
     4551                return static_cast<float>(wcstod(value, 0));
     4552        #else
     4553                return static_cast<float>(strtod(value, 0));
     4554        #endif
     4555        }
     4556
     4557        PUGI__FN bool get_value_bool(const char_t* value)
     4558        {
     4559                // only look at first char
     4560                char_t first = *value;
     4561
     4562                // 1*, t* (true), T* (True), y* (yes), Y* (YES)
     4563                return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
     4564        }
     4565
     4566#ifdef PUGIXML_HAS_LONG_LONG
     4567        PUGI__FN long long get_value_llong(const char_t* value)
     4568        {
     4569                return string_to_integer<unsigned long long>(value, 0 - static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);
     4570        }
     4571
     4572        PUGI__FN unsigned long long get_value_ullong(const char_t* value)
     4573        {
     4574                return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);
     4575        }
     4576#endif
     4577
     4578        template <typename U> PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative)
     4579        {
     4580                char_t* result = end - 1;
     4581                U rest = negative ? 0 - value : value;
     4582
     4583                do
     4584                {
     4585                        *result-- = static_cast<char_t>('0' + (rest % 10));
     4586                        rest /= 10;
     4587                }
     4588                while (rest);
     4589
     4590                assert(result >= begin);
     4591                (void)begin;
     4592
     4593                *result = '-';
     4594
     4595                return result + !negative;
     4596        }
     4597
     4598        // set value with conversion functions
     4599        template <typename String, typename Header>
     4600        PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf)
     4601        {
     4602        #ifdef PUGIXML_WCHAR_MODE
     4603                char_t wbuf[128];
     4604                assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0]));
     4605
     4606                size_t offset = 0;
     4607                for (; buf[offset]; ++offset) wbuf[offset] = buf[offset];
     4608
     4609                return strcpy_insitu(dest, header, header_mask, wbuf, offset);
     4610        #else
     4611                return strcpy_insitu(dest, header, header_mask, buf, strlen(buf));
     4612        #endif
     4613        }
     4614
     4615        template <typename U, typename String, typename Header>
     4616        PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative)
     4617        {
     4618                char_t buf[64];
     4619                char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
     4620                char_t* begin = integer_to_string(buf, end, value, negative);
     4621
     4622                return strcpy_insitu(dest, header, header_mask, begin, end - begin);
     4623        }
     4624
     4625        template <typename String, typename Header>
     4626        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value)
     4627        {
     4628                char buf[128];
     4629                sprintf(buf, "%.9g", value);
     4630
     4631                return set_value_ascii(dest, header, header_mask, buf);
     4632        }
     4633
     4634        template <typename String, typename Header>
     4635        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value)
     4636        {
     4637                char buf[128];
     4638                sprintf(buf, "%.17g", value);
     4639
     4640                return set_value_ascii(dest, header, header_mask, buf);
     4641        }
     4642
     4643        template <typename String, typename Header>
     4644        PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value)
     4645        {
     4646                return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5);
     4647        }
     4648
     4649        PUGI__FN xml_parse_result load_buffer_impl(xml_document_struct* doc, xml_node_struct* root, void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own, char_t** out_buffer)
     4650        {
     4651                // check input buffer
     4652                if (!contents && size) return make_parse_result(status_io_error);
     4653
     4654                // get actual encoding
     4655                xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
     4656
     4657                // get private buffer
     4658                char_t* buffer = 0;
     4659                size_t length = 0;
     4660
     4661                if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
     4662
     4663                // delete original buffer if we performed a conversion
     4664                if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
     4665
     4666                // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
     4667                if (own || buffer != contents) *out_buffer = buffer;
     4668
     4669                // store buffer for offset_debug
     4670                doc->buffer = buffer;
     4671
     4672                // parse
     4673                xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
     4674
     4675                // remember encoding
     4676                res.encoding = buffer_encoding;
     4677
     4678                return res;
    30874679        }
    30884680
    30894681        // 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
    3090         xml_parse_status get_file_size(FILE* file, size_t& out_result)
    3091         {
    3092         #if defined(_MSC_VER) && _MSC_VER >= 1400
     4682        PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
     4683        {
     4684        #if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
    30934685                // there are 64-bit versions of fseek/ftell, let's use them
    30944686                typedef __int64 length_type;
     
    30974689                length_type length = _ftelli64(file);
    30984690                _fseeki64(file, 0, SEEK_SET);
    3099         #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__)
     4691        #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))
    31004692                // there are 64-bit versions of fseek/ftell, let's use them
    31014693                typedef off64_t length_type;
     
    31154707                // check for I/O errors
    31164708                if (length < 0) return status_io_error;
    3117                
     4709
    31184710                // check for overflow
    31194711                size_t result = static_cast<size_t>(length);
     
    31274719        }
    31284720
    3129         xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding)
     4721        // This function assumes that buffer has extra sizeof(char_t) writable bytes after size
     4722        PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding)
     4723        {
     4724                // We only need to zero-terminate if encoding conversion does not do it for us
     4725        #ifdef PUGIXML_WCHAR_MODE
     4726                xml_encoding wchar_encoding = get_wchar_encoding();
     4727
     4728                if (encoding == wchar_encoding || need_endian_swap_utf(encoding, wchar_encoding))
     4729                {
     4730                        size_t length = size / sizeof(char_t);
     4731
     4732                        static_cast<char_t*>(buffer)[length] = 0;
     4733                        return (length + 1) * sizeof(char_t);
     4734                }
     4735        #else
     4736                if (encoding == encoding_utf8)
     4737                {
     4738                        static_cast<char*>(buffer)[size] = 0;
     4739                        return size + 1;
     4740                }
     4741        #endif
     4742
     4743                return size;
     4744        }
     4745
     4746        PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer)
    31304747        {
    31314748                if (!file) return make_parse_result(status_file_not_found);
     
    31344751                size_t size = 0;
    31354752                xml_parse_status size_status = get_file_size(file, size);
    3136 
    3137                 if (size_status != status_ok)
    3138                 {
    3139                         fclose(file);
    3140                         return make_parse_result(size_status);
    3141                 }
    3142                
     4753                if (size_status != status_ok) return make_parse_result(size_status);
     4754
     4755                size_t max_suffix_size = sizeof(char_t);
     4756
    31434757                // allocate buffer for the whole file
    3144                 char* contents = static_cast<char*>(global_allocate(size > 0 ? size : 1));
    3145 
    3146                 if (!contents)
    3147                 {
    3148                         fclose(file);
    3149                         return make_parse_result(status_out_of_memory);
    3150                 }
     4758                char* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size));
     4759                if (!contents) return make_parse_result(status_out_of_memory);
    31514760
    31524761                // read file in memory
    31534762                size_t read_size = fread(contents, 1, size, file);
     4763
     4764                if (read_size != size)
     4765                {
     4766                        xml_memory::deallocate(contents);
     4767                        return make_parse_result(status_io_error);
     4768                }
     4769
     4770                xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
     4771
     4772                return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer);
     4773        }
     4774
     4775        PUGI__FN void close_file(FILE* file)
     4776        {
    31544777                fclose(file);
    3155 
    3156                 if (read_size != size)
    3157                 {
    3158                         global_deallocate(contents);
    3159                         return make_parse_result(status_io_error);
    3160                 }
    3161                
    3162                 return doc.load_buffer_inplace_own(contents, size, options, encoding);
    31634778        }
    31644779
    31654780#ifndef PUGIXML_NO_STL
    3166         template <typename T> xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding)
     4781        template <typename T> struct xml_stream_chunk
     4782        {
     4783                static xml_stream_chunk* create()
     4784                {
     4785                        void* memory = xml_memory::allocate(sizeof(xml_stream_chunk));
     4786                        if (!memory) return 0;
     4787
     4788                        return new (memory) xml_stream_chunk();
     4789                }
     4790
     4791                static void destroy(xml_stream_chunk* chunk)
     4792                {
     4793                        // free chunk chain
     4794                        while (chunk)
     4795                        {
     4796                                xml_stream_chunk* next_ = chunk->next;
     4797
     4798                                xml_memory::deallocate(chunk);
     4799
     4800                                chunk = next_;
     4801                        }
     4802                }
     4803
     4804                xml_stream_chunk(): next(0), size(0)
     4805                {
     4806                }
     4807
     4808                xml_stream_chunk* next;
     4809                size_t size;
     4810
     4811                T data[xml_memory_page_size / sizeof(T)];
     4812        };
     4813
     4814        template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
     4815        {
     4816                auto_deleter<xml_stream_chunk<T> > chunks(0, xml_stream_chunk<T>::destroy);
     4817
     4818                // read file to a chunk list
     4819                size_t total = 0;
     4820                xml_stream_chunk<T>* last = 0;
     4821
     4822                while (!stream.eof())
     4823                {
     4824                        // allocate new chunk
     4825                        xml_stream_chunk<T>* chunk = xml_stream_chunk<T>::create();
     4826                        if (!chunk) return status_out_of_memory;
     4827
     4828                        // append chunk to list
     4829                        if (last) last = last->next = chunk;
     4830                        else chunks.data = last = chunk;
     4831
     4832                        // read data to chunk
     4833                        stream.read(chunk->data, static_cast<std::streamsize>(sizeof(chunk->data) / sizeof(T)));
     4834                        chunk->size = static_cast<size_t>(stream.gcount()) * sizeof(T);
     4835
     4836                        // read may set failbit | eofbit in case gcount() is less than read length, so check for other I/O errors
     4837                        if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
     4838
     4839                        // guard against huge files (chunk size is small enough to make this overflow check work)
     4840                        if (total + chunk->size < total) return status_out_of_memory;
     4841                        total += chunk->size;
     4842                }
     4843
     4844                size_t max_suffix_size = sizeof(char_t);
     4845
     4846                // copy chunk list to a contiguous buffer
     4847                char* buffer = static_cast<char*>(xml_memory::allocate(total + max_suffix_size));
     4848                if (!buffer) return status_out_of_memory;
     4849
     4850                char* write = buffer;
     4851
     4852                for (xml_stream_chunk<T>* chunk = chunks.data; chunk; chunk = chunk->next)
     4853                {
     4854                        assert(write + chunk->size <= buffer + total);
     4855                        memcpy(write, chunk->data, chunk->size);
     4856                        write += chunk->size;
     4857                }
     4858
     4859                assert(write == buffer + total);
     4860
     4861                // return buffer
     4862                *out_buffer = buffer;
     4863                *out_size = total;
     4864
     4865                return status_ok;
     4866        }
     4867
     4868        template <typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
    31674869        {
    31684870                // get length of remaining data in stream
     
    31724874                stream.seekg(pos);
    31734875
    3174                 if (stream.fail() || pos < 0) return make_parse_result(status_io_error);
     4876                if (stream.fail() || pos < 0) return status_io_error;
    31754877
    31764878                // guard against huge files
    31774879                size_t read_length = static_cast<size_t>(length);
    31784880
    3179                 if (static_cast<std::streamsize>(read_length) != length || length < 0) return make_parse_result(status_out_of_memory);
     4881                if (static_cast<std::streamsize>(read_length) != length || length < 0) return status_out_of_memory;
     4882
     4883                size_t max_suffix_size = sizeof(char_t);
    31804884
    31814885                // read stream data into memory (guard against stream exceptions with buffer holder)
    3182                 buffer_holder buffer(global_allocate((read_length > 0 ? read_length : 1) * sizeof(T)), global_deallocate);
    3183                 if (!buffer.data) return make_parse_result(status_out_of_memory);
     4886                auto_deleter<void> buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);
     4887                if (!buffer.data) return status_out_of_memory;
    31844888
    31854889                stream.read(static_cast<T*>(buffer.data), static_cast<std::streamsize>(read_length));
    31864890
    31874891                // 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
    3188                 if (stream.bad()) return make_parse_result(status_io_error);
    3189 
    3190                 // load data from buffer
     4892                if (stream.bad() || (!stream.eof() && stream.fail())) return status_io_error;
     4893
     4894                // return buffer
    31914895                size_t actual_length = static_cast<size_t>(stream.gcount());
    31924896                assert(actual_length <= read_length);
    31934897
    3194                 return doc.load_buffer_inplace_own(buffer.release(), actual_length * sizeof(T), options, encoding);
     4898                *out_buffer = buffer.release();
     4899                *out_size = actual_length * sizeof(T);
     4900
     4901                return status_ok;
     4902        }
     4903
     4904        template <typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document_struct* doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding, char_t** out_buffer)
     4905        {
     4906                void* buffer = 0;
     4907                size_t size = 0;
     4908                xml_parse_status status = status_ok;
     4909
     4910                // if stream has an error bit set, bail out (otherwise tellg() can fail and we'll clear error bits)
     4911                if (stream.fail()) return make_parse_result(status_io_error);
     4912
     4913                // load stream to memory (using seek-based implementation if possible, since it's faster and takes less memory)
     4914                if (stream.tellg() < 0)
     4915                {
     4916                        stream.clear(); // clear error flags that could be set by a failing tellg
     4917                        status = load_stream_data_noseek(stream, &buffer, &size);
     4918                }
     4919                else
     4920                        status = load_stream_data_seek(stream, &buffer, &size);
     4921
     4922                if (status != status_ok) return make_parse_result(status);
     4923
     4924                xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
     4925
     4926                return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer);
    31954927        }
    31964928#endif
    31974929
    3198 #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__MINGW32__)
    3199         FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
     4930#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))
     4931        PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
    32004932        {
    32014933                return _wfopen(path, mode);
    32024934        }
    32034935#else
    3204         char* convert_path_heap(const wchar_t* str)
     4936        PUGI__FN char* convert_path_heap(const wchar_t* str)
    32054937        {
    32064938                assert(str);
    32074939
    32084940                // first pass: get length in utf8 characters
    3209                 size_t length = wcslen(str);
    3210         size_t size = as_utf8_begin(str, length);
     4941                size_t length = strlength_wide(str);
     4942                size_t size = as_utf8_begin(str, length);
    32114943
    32124944                // allocate resulting string
    3213                 char* result = static_cast<char*>(global_allocate(size + 1));
     4945                char* result = static_cast<char*>(xml_memory::allocate(size + 1));
    32144946                if (!result) return 0;
    32154947
    32164948                // second pass: convert to utf8
    3217         as_utf8_end(result, size, str, length);
    3218 
    3219                 return result;
    3220         }
    3221 
    3222         FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
     4949                as_utf8_end(result, size, str, length);
     4950
     4951                // zero-terminate
     4952                result[size] = 0;
     4953
     4954                return result;
     4955        }
     4956
     4957        PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
    32234958        {
    32244959                // there is no standard function to open wide paths, so our best bet is to try utf8 path
     
    32344969
    32354970                // free dummy buffer
    3236                 global_deallocate(path_utf8);
     4971                xml_memory::deallocate(path_utf8);
    32374972
    32384973                return result;
    32394974        }
    32404975#endif
    3241 }
     4976
     4977        PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)
     4978        {
     4979                if (!file) return false;
     4980
     4981                xml_writer_file writer(file);
     4982                doc.save(writer, indent, flags, encoding);
     4983
     4984                return ferror(file) == 0;
     4985        }
     4986
     4987        struct name_null_sentry
     4988        {
     4989                xml_node_struct* node;
     4990                char_t* name;
     4991
     4992                name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name)
     4993                {
     4994                        node->name = 0;
     4995                }
     4996
     4997                ~name_null_sentry()
     4998                {
     4999                        node->name = name;
     5000                }
     5001        };
     5002PUGI__NS_END
    32425003
    32435004namespace pugi
    32445005{
    3245         xml_writer_file::xml_writer_file(void* file): file(file)
    3246         {
    3247         }
    3248 
    3249         void xml_writer_file::write(const void* data, size_t size)
    3250         {
    3251                 fwrite(data, size, 1, static_cast<FILE*>(file));
     5006        PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_)
     5007        {
     5008        }
     5009
     5010        PUGI__FN void xml_writer_file::write(const void* data, size_t size)
     5011        {
     5012                size_t result = fwrite(data, 1, size, static_cast<FILE*>(file));
     5013                (void)!result; // unfortunately we can't do proper error handling here
    32525014        }
    32535015
    32545016#ifndef PUGIXML_NO_STL
    3255         xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
    3256         {
    3257         }
    3258 
    3259         xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
    3260         {
    3261         }
    3262 
    3263         void xml_writer_stream::write(const void* data, size_t size)
     5017        PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
     5018        {
     5019        }
     5020
     5021        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)
     5022        {
     5023        }
     5024
     5025        PUGI__FN void xml_writer_stream::write(const void* data, size_t size)
    32645026        {
    32655027                if (narrow_stream)
     
    32785040#endif
    32795041
    3280         xml_tree_walker::xml_tree_walker(): _depth(0)
    3281         {
    3282         }
    3283        
    3284         xml_tree_walker::~xml_tree_walker()
    3285         {
    3286         }
    3287 
    3288         int xml_tree_walker::depth() const
     5042        PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0)
     5043        {
     5044        }
     5045
     5046        PUGI__FN xml_tree_walker::~xml_tree_walker()
     5047        {
     5048        }
     5049
     5050        PUGI__FN int xml_tree_walker::depth() const
    32895051        {
    32905052                return _depth;
    32915053        }
    32925054
    3293         bool xml_tree_walker::begin(xml_node&)
     5055        PUGI__FN bool xml_tree_walker::begin(xml_node&)
    32945056        {
    32955057                return true;
    32965058        }
    32975059
    3298         bool xml_tree_walker::end(xml_node&)
     5060        PUGI__FN bool xml_tree_walker::end(xml_node&)
    32995061        {
    33005062                return true;
    33015063        }
    33025064
    3303         xml_attribute::xml_attribute(): _attr(0)
    3304         {
    3305         }
    3306 
    3307         xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
    3308         {
    3309         }
    3310 
    3311         xml_attribute::operator xml_attribute::unspecified_bool_type() const
    3312         {
    3313         return _attr ? &xml_attribute::_attr : 0;
    3314         }
    3315 
    3316         bool xml_attribute::operator!() const
    3317         {
    3318                 return !_attr;
    3319         }
    3320 
    3321         bool xml_attribute::operator==(const xml_attribute& r) const
     5065        PUGI__FN xml_attribute::xml_attribute(): _attr(0)
     5066        {
     5067        }
     5068
     5069        PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
     5070        {
     5071        }
     5072
     5073        PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***)
     5074        {
     5075        }
     5076
     5077        PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
     5078        {
     5079                return _attr ? unspecified_bool_xml_attribute : 0;
     5080        }
     5081
     5082        PUGI__FN bool xml_attribute::operator!() const
     5083        {
     5084                return !_attr;
     5085        }
     5086
     5087        PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const
    33225088        {
    33235089                return (_attr == r._attr);
    33245090        }
    3325        
    3326         bool xml_attribute::operator!=(const xml_attribute& r) const
     5091
     5092        PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const
    33275093        {
    33285094                return (_attr != r._attr);
    33295095        }
    33305096
    3331         bool xml_attribute::operator<(const xml_attribute& r) const
     5097        PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const
    33325098        {
    33335099                return (_attr < r._attr);
    33345100        }
    3335        
    3336         bool xml_attribute::operator>(const xml_attribute& r) const
     5101
     5102        PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const
    33375103        {
    33385104                return (_attr > r._attr);
    33395105        }
    3340        
    3341         bool xml_attribute::operator<=(const xml_attribute& r) const
     5106
     5107        PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const
    33425108        {
    33435109                return (_attr <= r._attr);
    33445110        }
    3345        
    3346         bool xml_attribute::operator>=(const xml_attribute& r) const
     5111
     5112        PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const
    33475113        {
    33485114                return (_attr >= r._attr);
    33495115        }
    33505116
    3351         xml_attribute xml_attribute::next_attribute() const
    3352         {
    3353         return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
    3354         }
    3355 
    3356     xml_attribute xml_attribute::previous_attribute() const
    3357     {
    3358         return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
    3359     }
    3360 
    3361         int xml_attribute::as_int() const
    3362         {
    3363                 if (!_attr || !_attr->value) return 0;
    3364 
    3365         #ifdef PUGIXML_WCHAR_MODE
    3366                 return (int)wcstol(_attr->value, 0, 10);
    3367         #else
    3368                 return (int)strtol(_attr->value, 0, 10);
    3369         #endif
    3370         }
    3371 
    3372         unsigned int xml_attribute::as_uint() const
    3373         {
    3374                 if (!_attr || !_attr->value) return 0;
    3375 
    3376         #ifdef PUGIXML_WCHAR_MODE
    3377                 return (unsigned int)wcstoul(_attr->value, 0, 10);
    3378         #else
    3379                 return (unsigned int)strtoul(_attr->value, 0, 10);
    3380         #endif
    3381         }
    3382 
    3383         double xml_attribute::as_double() const
    3384         {
    3385                 if (!_attr || !_attr->value) return 0;
    3386 
    3387         #ifdef PUGIXML_WCHAR_MODE
    3388                 return wcstod(_attr->value, 0);
    3389         #else
    3390                 return strtod(_attr->value, 0);
    3391         #endif
    3392         }
    3393 
    3394         float xml_attribute::as_float() const
    3395         {
    3396                 if (!_attr || !_attr->value) return 0;
    3397 
    3398         #ifdef PUGIXML_WCHAR_MODE
    3399                 return (float)wcstod(_attr->value, 0);
    3400         #else
    3401                 return (float)strtod(_attr->value, 0);
    3402         #endif
    3403         }
    3404 
    3405         bool xml_attribute::as_bool() const
    3406         {
    3407                 if (!_attr || !_attr->value) return false;
    3408 
    3409                 // only look at first char
    3410                 char_t first = *_attr->value;
    3411 
    3412                 // 1*, t* (true), T* (True), y* (yes), Y* (YES)
    3413                 return (first == '1' || first == 't' || first == 'T' || first == 'y' || first == 'Y');
    3414         }
    3415 
    3416         bool xml_attribute::empty() const
     5117        PUGI__FN xml_attribute xml_attribute::next_attribute() const
     5118        {
     5119                return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute();
     5120        }
     5121
     5122        PUGI__FN xml_attribute xml_attribute::previous_attribute() const
     5123        {
     5124                return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute();
     5125        }
     5126
     5127        PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const
     5128        {
     5129                return (_attr && _attr->value) ? _attr->value + 0 : def;
     5130        }
     5131
     5132        PUGI__FN int xml_attribute::as_int(int def) const
     5133        {
     5134                return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def;
     5135        }
     5136
     5137        PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
     5138        {
     5139                return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def;
     5140        }
     5141
     5142        PUGI__FN double xml_attribute::as_double(double def) const
     5143        {
     5144                return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def;
     5145        }
     5146
     5147        PUGI__FN float xml_attribute::as_float(float def) const
     5148        {
     5149                return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def;
     5150        }
     5151
     5152        PUGI__FN bool xml_attribute::as_bool(bool def) const
     5153        {
     5154                return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def;
     5155        }
     5156
     5157#ifdef PUGIXML_HAS_LONG_LONG
     5158        PUGI__FN long long xml_attribute::as_llong(long long def) const
     5159        {
     5160                return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def;
     5161        }
     5162
     5163        PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
     5164        {
     5165                return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def;
     5166        }
     5167#endif
     5168
     5169        PUGI__FN bool xml_attribute::empty() const
    34175170        {
    34185171                return !_attr;
    34195172        }
    34205173
    3421         const char_t* xml_attribute::name() const
    3422         {
    3423                 return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT("");
    3424         }
    3425 
    3426         const char_t* xml_attribute::value() const
    3427         {
    3428                 return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");
    3429         }
    3430 
    3431     size_t xml_attribute::hash_value() const
    3432     {
    3433         return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
    3434     }
    3435 
    3436         xml_attribute_struct* xml_attribute::internal_object() const
    3437         {
    3438         return _attr;
    3439         }
    3440 
    3441         xml_attribute& xml_attribute::operator=(const char_t* rhs)
     5174        PUGI__FN const char_t* xml_attribute::name() const
     5175        {
     5176                return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT("");
     5177        }
     5178
     5179        PUGI__FN const char_t* xml_attribute::value() const
     5180        {
     5181                return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT("");
     5182        }
     5183
     5184        PUGI__FN size_t xml_attribute::hash_value() const
     5185        {
     5186                return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
     5187        }
     5188
     5189        PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const
     5190        {
     5191                return _attr;
     5192        }
     5193
     5194        PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs)
    34425195        {
    34435196                set_value(rhs);
    34445197                return *this;
    34455198        }
    3446        
    3447         xml_attribute& xml_attribute::operator=(int rhs)
     5199
     5200        PUGI__FN xml_attribute& xml_attribute::operator=(int rhs)
    34485201        {
    34495202                set_value(rhs);
     
    34515204        }
    34525205
    3453         xml_attribute& xml_attribute::operator=(unsigned int rhs)
     5206        PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs)
    34545207        {
    34555208                set_value(rhs);
     
    34575210        }
    34585211
    3459         xml_attribute& xml_attribute::operator=(double rhs)
     5212        PUGI__FN xml_attribute& xml_attribute::operator=(long rhs)
    34605213        {
    34615214                set_value(rhs);
    34625215                return *this;
    34635216        }
    3464        
    3465         xml_attribute& xml_attribute::operator=(bool rhs)
     5217
     5218        PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs)
    34665219        {
    34675220                set_value(rhs);
     
    34695222        }
    34705223
    3471         bool xml_attribute::set_name(const char_t* rhs)
     5224        PUGI__FN xml_attribute& xml_attribute::operator=(double rhs)
     5225        {
     5226                set_value(rhs);
     5227                return *this;
     5228        }
     5229
     5230        PUGI__FN xml_attribute& xml_attribute::operator=(float rhs)
     5231        {
     5232                set_value(rhs);
     5233                return *this;
     5234        }
     5235
     5236        PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs)
     5237        {
     5238                set_value(rhs);
     5239                return *this;
     5240        }
     5241
     5242#ifdef PUGIXML_HAS_LONG_LONG
     5243        PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs)
     5244        {
     5245                set_value(rhs);
     5246                return *this;
     5247        }
     5248
     5249        PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs)
     5250        {
     5251                set_value(rhs);
     5252                return *this;
     5253        }
     5254#endif
     5255
     5256        PUGI__FN bool xml_attribute::set_name(const char_t* rhs)
    34725257        {
    34735258                if (!_attr) return false;
    3474                
    3475                 return strcpy_insitu(_attr->name, _attr->header, xml_memory_page_name_allocated_mask, rhs);
    3476         }
    3477                
    3478         bool xml_attribute::set_value(const char_t* rhs)
     5259
     5260                return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
     5261        }
     5262
     5263        PUGI__FN bool xml_attribute::set_value(const char_t* rhs)
    34795264        {
    34805265                if (!_attr) return false;
    34815266
    3482                 return strcpy_insitu(_attr->value, _attr->header, xml_memory_page_value_allocated_mask, rhs);
    3483         }
    3484 
    3485         bool xml_attribute::set_value(int rhs)
    3486         {
    3487                 char buf[128];
    3488                 sprintf(buf, "%d", rhs);
    3489        
    3490         #ifdef PUGIXML_WCHAR_MODE
    3491                 char_t wbuf[128];
    3492                 widen_ascii(wbuf, buf);
    3493 
    3494                 return set_value(wbuf);
    3495         #else
    3496                 return set_value(buf);
    3497         #endif
    3498         }
    3499 
    3500         bool xml_attribute::set_value(unsigned int rhs)
    3501         {
    3502                 char buf[128];
    3503                 sprintf(buf, "%u", rhs);
    3504 
    3505         #ifdef PUGIXML_WCHAR_MODE
    3506                 char_t wbuf[128];
    3507                 widen_ascii(wbuf, buf);
    3508 
    3509                 return set_value(wbuf);
    3510         #else
    3511                 return set_value(buf);
    3512         #endif
    3513         }
    3514 
    3515         bool xml_attribute::set_value(double rhs)
    3516         {
    3517                 char buf[128];
    3518                 sprintf(buf, "%g", rhs);
    3519 
    3520         #ifdef PUGIXML_WCHAR_MODE
    3521                 char_t wbuf[128];
    3522                 widen_ascii(wbuf, buf);
    3523 
    3524                 return set_value(wbuf);
    3525         #else
    3526                 return set_value(buf);
    3527         #endif
    3528         }
    3529        
    3530         bool xml_attribute::set_value(bool rhs)
    3531         {
    3532                 return set_value(rhs ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
    3533         }
     5267                return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
     5268        }
     5269
     5270        PUGI__FN bool xml_attribute::set_value(int rhs)
     5271        {
     5272                if (!_attr) return false;
     5273
     5274                return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
     5275        }
     5276
     5277        PUGI__FN bool xml_attribute::set_value(unsigned int rhs)
     5278        {
     5279                if (!_attr) return false;
     5280
     5281                return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
     5282        }
     5283
     5284        PUGI__FN bool xml_attribute::set_value(long rhs)
     5285        {
     5286                if (!_attr) return false;
     5287
     5288                return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
     5289        }
     5290
     5291        PUGI__FN bool xml_attribute::set_value(unsigned long rhs)
     5292        {
     5293                if (!_attr) return false;
     5294
     5295                return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
     5296        }
     5297
     5298        PUGI__FN bool xml_attribute::set_value(double rhs)
     5299        {
     5300                if (!_attr) return false;
     5301
     5302                return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
     5303        }
     5304
     5305        PUGI__FN bool xml_attribute::set_value(float rhs)
     5306        {
     5307                if (!_attr) return false;
     5308
     5309                return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
     5310        }
     5311
     5312        PUGI__FN bool xml_attribute::set_value(bool rhs)
     5313        {
     5314                if (!_attr) return false;
     5315
     5316                return impl::set_value_bool(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
     5317        }
     5318
     5319#ifdef PUGIXML_HAS_LONG_LONG
     5320        PUGI__FN bool xml_attribute::set_value(long long rhs)
     5321        {
     5322                if (!_attr) return false;
     5323
     5324                return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
     5325        }
     5326
     5327        PUGI__FN bool xml_attribute::set_value(unsigned long long rhs)
     5328        {
     5329                if (!_attr) return false;
     5330
     5331                return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
     5332        }
     5333#endif
    35345334
    35355335#ifdef __BORLANDC__
    3536         bool operator&&(const xml_attribute& lhs, bool rhs)
     5336        PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs)
    35375337        {
    35385338                return (bool)lhs && rhs;
    35395339        }
    35405340
    3541         bool operator||(const xml_attribute& lhs, bool rhs)
     5341        PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs)
    35425342        {
    35435343                return (bool)lhs || rhs;
     
    35455345#endif
    35465346
    3547         xml_node::xml_node(): _root(0)
    3548         {
    3549         }
    3550 
    3551         xml_node::xml_node(xml_node_struct* p): _root(p)
    3552         {
    3553         }
    3554        
    3555         xml_node::operator xml_node::unspecified_bool_type() const
    3556         {
    3557         return _root ? &xml_node::_root : 0;
    3558         }
    3559 
    3560         bool xml_node::operator!() const
    3561         {
    3562                 return !_root;
    3563         }
    3564 
    3565         xml_node::iterator xml_node::begin() const
    3566         {
    3567                 return iterator(_root ? _root->first_child : 0, _root);
    3568         }
    3569 
    3570         xml_node::iterator xml_node::end() const
     5347        PUGI__FN xml_node::xml_node(): _root(0)
     5348        {
     5349        }
     5350
     5351        PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p)
     5352        {
     5353        }
     5354
     5355        PUGI__FN static void unspecified_bool_xml_node(xml_node***)
     5356        {
     5357        }
     5358
     5359        PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const
     5360        {
     5361                return _root ? unspecified_bool_xml_node : 0;
     5362        }
     5363
     5364        PUGI__FN bool xml_node::operator!() const
     5365        {
     5366                return !_root;
     5367        }
     5368
     5369        PUGI__FN xml_node::iterator xml_node::begin() const
     5370        {
     5371                return iterator(_root ? _root->first_child + 0 : 0, _root);
     5372        }
     5373
     5374        PUGI__FN xml_node::iterator xml_node::end() const
    35715375        {
    35725376                return iterator(0, _root);
    35735377        }
    3574        
    3575         xml_node::attribute_iterator xml_node::attributes_begin() const
    3576         {
    3577                 return attribute_iterator(_root ? _root->first_attribute : 0, _root);
    3578         }
    3579 
    3580         xml_node::attribute_iterator xml_node::attributes_end() const
     5378
     5379        PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const
     5380        {
     5381                return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root);
     5382        }
     5383
     5384        PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const
    35815385        {
    35825386                return attribute_iterator(0, _root);
    35835387        }
    35845388
    3585         bool xml_node::operator==(const xml_node& r) const
     5389        PUGI__FN xml_object_range<xml_node_iterator> xml_node::children() const
     5390        {
     5391                return xml_object_range<xml_node_iterator>(begin(), end());
     5392        }
     5393
     5394        PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(const char_t* name_) const
     5395        {
     5396                return xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_));
     5397        }
     5398
     5399        PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes() const
     5400        {
     5401                return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());
     5402        }
     5403
     5404        PUGI__FN bool xml_node::operator==(const xml_node& r) const
    35865405        {
    35875406                return (_root == r._root);
    35885407        }
    35895408
    3590         bool xml_node::operator!=(const xml_node& r) const
     5409        PUGI__FN bool xml_node::operator!=(const xml_node& r) const
    35915410        {
    35925411                return (_root != r._root);
    35935412        }
    35945413
    3595         bool xml_node::operator<(const xml_node& r) const
     5414        PUGI__FN bool xml_node::operator<(const xml_node& r) const
    35965415        {
    35975416                return (_root < r._root);
    35985417        }
    3599        
    3600         bool xml_node::operator>(const xml_node& r) const
     5418
     5419        PUGI__FN bool xml_node::operator>(const xml_node& r) const
    36015420        {
    36025421                return (_root > r._root);
    36035422        }
    3604        
    3605         bool xml_node::operator<=(const xml_node& r) const
     5423
     5424        PUGI__FN bool xml_node::operator<=(const xml_node& r) const
    36065425        {
    36075426                return (_root <= r._root);
    36085427        }
    3609        
    3610         bool xml_node::operator>=(const xml_node& r) const
     5428
     5429        PUGI__FN bool xml_node::operator>=(const xml_node& r) const
    36115430        {
    36125431                return (_root >= r._root);
    36135432        }
    36145433
    3615         bool xml_node::empty() const
     5434        PUGI__FN bool xml_node::empty() const
    36165435        {
    36175436                return !_root;
    36185437        }
    3619        
    3620         const char_t* xml_node::name() const
    3621         {
    3622                 return (_root && _root->name) ? _root->name : PUGIXML_TEXT("");
    3623         }
    3624 
    3625         xml_node_type xml_node::type() const
    3626         {
    3627                 return _root ? static_cast<xml_node_type>((_root->header & xml_memory_page_type_mask) + 1) : node_null;
    3628         }
    3629        
    3630         const char_t* xml_node::value() const
    3631         {
    3632                 return (_root && _root->value) ? _root->value : PUGIXML_TEXT("");
    3633         }
    3634        
    3635         xml_node xml_node::child(const char_t* name) const
     5438
     5439        PUGI__FN const char_t* xml_node::name() const
     5440        {
     5441                return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT("");
     5442        }
     5443
     5444        PUGI__FN xml_node_type xml_node::type() const
     5445        {
     5446                return _root ? PUGI__NODETYPE(_root) : node_null;
     5447        }
     5448
     5449        PUGI__FN const char_t* xml_node::value() const
     5450        {
     5451                return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT("");
     5452        }
     5453
     5454        PUGI__FN xml_node xml_node::child(const char_t* name_) const
    36365455        {
    36375456                if (!_root) return xml_node();
    36385457
    36395458                for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
    3640                         if (i->name && strequal(name, i->name)) return xml_node(i);
     5459                        if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
    36415460
    36425461                return xml_node();
    36435462        }
    36445463
    3645         xml_attribute xml_node::attribute(const char_t* name) const
     5464        PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const
    36465465        {
    36475466                if (!_root) return xml_attribute();
    36485467
    36495468                for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute)
    3650                         if (i->name && strequal(name, i->name))
     5469                        if (i->name && impl::strequal(name_, i->name))
    36515470                                return xml_attribute(i);
    3652                
     5471
    36535472                return xml_attribute();
    36545473        }
    3655        
    3656         xml_node xml_node::next_sibling(const char_t* name) const
     5474
     5475        PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const
    36575476        {
    36585477                if (!_root) return xml_node();
    3659                
     5478
    36605479                for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling)
    3661                         if (i->name && strequal(name, i->name)) return xml_node(i);
     5480                        if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
    36625481
    36635482                return xml_node();
    36645483        }
    36655484
    3666         xml_node xml_node::next_sibling() const
     5485        PUGI__FN xml_node xml_node::next_sibling() const
     5486        {
     5487                return _root ? xml_node(_root->next_sibling) : xml_node();
     5488        }
     5489
     5490        PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const
    36675491        {
    36685492                if (!_root) return xml_node();
    3669                
    3670                 if (_root->next_sibling) return xml_node(_root->next_sibling);
    3671                 else return xml_node();
    3672         }
    3673 
    3674         xml_node xml_node::previous_sibling(const char_t* name) const
     5493
     5494                for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
     5495                        if (i->name && impl::strequal(name_, i->name)) return xml_node(i);
     5496
     5497                return xml_node();
     5498        }
     5499
     5500        PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const
     5501        {
     5502                xml_attribute_struct* hint = hint_._attr;
     5503
     5504                // if hint is not an attribute of node, behavior is not defined
     5505                assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
     5506
     5507                if (!_root) return xml_attribute();
     5508
     5509                // optimistically search from hint up until the end
     5510                for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
     5511                        if (i->name && impl::strequal(name_, i->name))
     5512                        {
     5513                                // update hint to maximize efficiency of searching for consecutive attributes
     5514                                hint_._attr = i->next_attribute;
     5515
     5516                                return xml_attribute(i);
     5517                        }
     5518
     5519                // wrap around and search from the first attribute until the hint
     5520                // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails
     5521                for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)
     5522                        if (j->name && impl::strequal(name_, j->name))
     5523                        {
     5524                                // update hint to maximize efficiency of searching for consecutive attributes
     5525                                hint_._attr = j->next_attribute;
     5526
     5527                                return xml_attribute(j);
     5528                        }
     5529
     5530                return xml_attribute();
     5531        }
     5532
     5533        PUGI__FN xml_node xml_node::previous_sibling() const
    36755534        {
    36765535                if (!_root) return xml_node();
    3677                
    3678                 for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c)
    3679                         if (i->name && strequal(name, i->name)) return xml_node(i);
    3680 
    3681                 return xml_node();
    3682         }
    3683 
    3684         xml_node xml_node::previous_sibling() const
    3685         {
    3686                 if (!_root) return xml_node();
    3687                
     5536
    36885537                if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c);
    36895538                else return xml_node();
    36905539        }
    36915540
    3692         xml_node xml_node::parent() const
     5541        PUGI__FN xml_node xml_node::parent() const
    36935542        {
    36945543                return _root ? xml_node(_root->parent) : xml_node();
    36955544        }
    36965545
    3697         xml_node xml_node::root() const
     5546        PUGI__FN xml_node xml_node::root() const
     5547        {
     5548                return _root ? xml_node(&impl::get_document(_root)) : xml_node();
     5549        }
     5550
     5551        PUGI__FN xml_text xml_node::text() const
     5552        {
     5553                return xml_text(_root);
     5554        }
     5555
     5556        PUGI__FN const char_t* xml_node::child_value() const
     5557        {
     5558                if (!_root) return PUGIXML_TEXT("");
     5559
     5560                // element nodes can have value if parse_embed_pcdata was used
     5561                if (PUGI__NODETYPE(_root) == node_element && _root->value)
     5562                        return _root->value;
     5563
     5564                for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
     5565                        if (impl::is_text_node(i) && i->value)
     5566                                return i->value;
     5567
     5568                return PUGIXML_TEXT("");
     5569        }
     5570
     5571        PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const
     5572        {
     5573                return child(name_).child_value();
     5574        }
     5575
     5576        PUGI__FN xml_attribute xml_node::first_attribute() const
     5577        {
     5578                return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
     5579        }
     5580
     5581        PUGI__FN xml_attribute xml_node::last_attribute() const
     5582        {
     5583                return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute();
     5584        }
     5585
     5586        PUGI__FN xml_node xml_node::first_child() const
     5587        {
     5588                return _root ? xml_node(_root->first_child) : xml_node();
     5589        }
     5590
     5591        PUGI__FN xml_node xml_node::last_child() const
     5592        {
     5593                return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
     5594        }
     5595
     5596        PUGI__FN bool xml_node::set_name(const char_t* rhs)
     5597        {
     5598                xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
     5599
     5600                if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
     5601                        return false;
     5602
     5603                return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
     5604        }
     5605
     5606        PUGI__FN bool xml_node::set_value(const char_t* rhs)
     5607        {
     5608                xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
     5609
     5610                if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
     5611                        return false;
     5612
     5613                return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
     5614        }
     5615
     5616        PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_)
     5617        {
     5618                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5619
     5620                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5621                if (!alloc.reserve()) return xml_attribute();
     5622
     5623                xml_attribute a(impl::allocate_attribute(alloc));
     5624                if (!a) return xml_attribute();
     5625
     5626                impl::append_attribute(a._attr, _root);
     5627
     5628                a.set_name(name_);
     5629
     5630                return a;
     5631        }
     5632
     5633        PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_)
     5634        {
     5635                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5636
     5637                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5638                if (!alloc.reserve()) return xml_attribute();
     5639
     5640                xml_attribute a(impl::allocate_attribute(alloc));
     5641                if (!a) return xml_attribute();
     5642
     5643                impl::prepend_attribute(a._attr, _root);
     5644
     5645                a.set_name(name_);
     5646
     5647                return a;
     5648        }
     5649
     5650        PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr)
     5651        {
     5652                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5653                if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
     5654
     5655                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5656                if (!alloc.reserve()) return xml_attribute();
     5657
     5658                xml_attribute a(impl::allocate_attribute(alloc));
     5659                if (!a) return xml_attribute();
     5660
     5661                impl::insert_attribute_after(a._attr, attr._attr, _root);
     5662
     5663                a.set_name(name_);
     5664
     5665                return a;
     5666        }
     5667
     5668        PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr)
     5669        {
     5670                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5671                if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
     5672
     5673                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5674                if (!alloc.reserve()) return xml_attribute();
     5675
     5676                xml_attribute a(impl::allocate_attribute(alloc));
     5677                if (!a) return xml_attribute();
     5678
     5679                impl::insert_attribute_before(a._attr, attr._attr, _root);
     5680
     5681                a.set_name(name_);
     5682
     5683                return a;
     5684        }
     5685
     5686        PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto)
     5687        {
     5688                if (!proto) return xml_attribute();
     5689                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5690
     5691                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5692                if (!alloc.reserve()) return xml_attribute();
     5693
     5694                xml_attribute a(impl::allocate_attribute(alloc));
     5695                if (!a) return xml_attribute();
     5696
     5697                impl::append_attribute(a._attr, _root);
     5698                impl::node_copy_attribute(a._attr, proto._attr);
     5699
     5700                return a;
     5701        }
     5702
     5703        PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto)
     5704        {
     5705                if (!proto) return xml_attribute();
     5706                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5707
     5708                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5709                if (!alloc.reserve()) return xml_attribute();
     5710
     5711                xml_attribute a(impl::allocate_attribute(alloc));
     5712                if (!a) return xml_attribute();
     5713
     5714                impl::prepend_attribute(a._attr, _root);
     5715                impl::node_copy_attribute(a._attr, proto._attr);
     5716
     5717                return a;
     5718        }
     5719
     5720        PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr)
     5721        {
     5722                if (!proto) return xml_attribute();
     5723                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5724                if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
     5725
     5726                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5727                if (!alloc.reserve()) return xml_attribute();
     5728
     5729                xml_attribute a(impl::allocate_attribute(alloc));
     5730                if (!a) return xml_attribute();
     5731
     5732                impl::insert_attribute_after(a._attr, attr._attr, _root);
     5733                impl::node_copy_attribute(a._attr, proto._attr);
     5734
     5735                return a;
     5736        }
     5737
     5738        PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr)
     5739        {
     5740                if (!proto) return xml_attribute();
     5741                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5742                if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
     5743
     5744                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5745                if (!alloc.reserve()) return xml_attribute();
     5746
     5747                xml_attribute a(impl::allocate_attribute(alloc));
     5748                if (!a) return xml_attribute();
     5749
     5750                impl::insert_attribute_before(a._attr, attr._attr, _root);
     5751                impl::node_copy_attribute(a._attr, proto._attr);
     5752
     5753                return a;
     5754        }
     5755
     5756        PUGI__FN xml_node xml_node::append_child(xml_node_type type_)
     5757        {
     5758                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5759
     5760                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5761                if (!alloc.reserve()) return xml_node();
     5762
     5763                xml_node n(impl::allocate_node(alloc, type_));
     5764                if (!n) return xml_node();
     5765
     5766                impl::append_node(n._root, _root);
     5767
     5768                if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
     5769
     5770                return n;
     5771        }
     5772
     5773        PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_)
     5774        {
     5775                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5776
     5777                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5778                if (!alloc.reserve()) return xml_node();
     5779
     5780                xml_node n(impl::allocate_node(alloc, type_));
     5781                if (!n) return xml_node();
     5782
     5783                impl::prepend_node(n._root, _root);
     5784
     5785                if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
     5786
     5787                return n;
     5788        }
     5789
     5790        PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node)
     5791        {
     5792                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5793                if (!node._root || node._root->parent != _root) return xml_node();
     5794
     5795                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5796                if (!alloc.reserve()) return xml_node();
     5797
     5798                xml_node n(impl::allocate_node(alloc, type_));
     5799                if (!n) return xml_node();
     5800
     5801                impl::insert_node_before(n._root, node._root);
     5802
     5803                if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
     5804
     5805                return n;
     5806        }
     5807
     5808        PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node)
     5809        {
     5810                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5811                if (!node._root || node._root->parent != _root) return xml_node();
     5812
     5813                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5814                if (!alloc.reserve()) return xml_node();
     5815
     5816                xml_node n(impl::allocate_node(alloc, type_));
     5817                if (!n) return xml_node();
     5818
     5819                impl::insert_node_after(n._root, node._root);
     5820
     5821                if (type_ == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
     5822
     5823                return n;
     5824        }
     5825
     5826        PUGI__FN xml_node xml_node::append_child(const char_t* name_)
     5827        {
     5828                xml_node result = append_child(node_element);
     5829
     5830                result.set_name(name_);
     5831
     5832                return result;
     5833        }
     5834
     5835        PUGI__FN xml_node xml_node::prepend_child(const char_t* name_)
     5836        {
     5837                xml_node result = prepend_child(node_element);
     5838
     5839                result.set_name(name_);
     5840
     5841                return result;
     5842        }
     5843
     5844        PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node)
     5845        {
     5846                xml_node result = insert_child_after(node_element, node);
     5847
     5848                result.set_name(name_);
     5849
     5850                return result;
     5851        }
     5852
     5853        PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node)
     5854        {
     5855                xml_node result = insert_child_before(node_element, node);
     5856
     5857                result.set_name(name_);
     5858
     5859                return result;
     5860        }
     5861
     5862        PUGI__FN xml_node xml_node::append_copy(const xml_node& proto)
     5863        {
     5864                xml_node_type type_ = proto.type();
     5865                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5866
     5867                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5868                if (!alloc.reserve()) return xml_node();
     5869
     5870                xml_node n(impl::allocate_node(alloc, type_));
     5871                if (!n) return xml_node();
     5872
     5873                impl::append_node(n._root, _root);
     5874                impl::node_copy_tree(n._root, proto._root);
     5875
     5876                return n;
     5877        }
     5878
     5879        PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto)
     5880        {
     5881                xml_node_type type_ = proto.type();
     5882                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5883
     5884                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5885                if (!alloc.reserve()) return xml_node();
     5886
     5887                xml_node n(impl::allocate_node(alloc, type_));
     5888                if (!n) return xml_node();
     5889
     5890                impl::prepend_node(n._root, _root);
     5891                impl::node_copy_tree(n._root, proto._root);
     5892
     5893                return n;
     5894        }
     5895
     5896        PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)
     5897        {
     5898                xml_node_type type_ = proto.type();
     5899                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5900                if (!node._root || node._root->parent != _root) return xml_node();
     5901
     5902                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5903                if (!alloc.reserve()) return xml_node();
     5904
     5905                xml_node n(impl::allocate_node(alloc, type_));
     5906                if (!n) return xml_node();
     5907
     5908                impl::insert_node_after(n._root, node._root);
     5909                impl::node_copy_tree(n._root, proto._root);
     5910
     5911                return n;
     5912        }
     5913
     5914        PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)
     5915        {
     5916                xml_node_type type_ = proto.type();
     5917                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5918                if (!node._root || node._root->parent != _root) return xml_node();
     5919
     5920                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5921                if (!alloc.reserve()) return xml_node();
     5922
     5923                xml_node n(impl::allocate_node(alloc, type_));
     5924                if (!n) return xml_node();
     5925
     5926                impl::insert_node_before(n._root, node._root);
     5927                impl::node_copy_tree(n._root, proto._root);
     5928
     5929                return n;
     5930        }
     5931
     5932        PUGI__FN xml_node xml_node::append_move(const xml_node& moved)
     5933        {
     5934                if (!impl::allow_move(*this, moved)) return xml_node();
     5935
     5936                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5937                if (!alloc.reserve()) return xml_node();
     5938
     5939                // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
     5940                impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
     5941
     5942                impl::remove_node(moved._root);
     5943                impl::append_node(moved._root, _root);
     5944
     5945                return moved;
     5946        }
     5947
     5948        PUGI__FN xml_node xml_node::prepend_move(const xml_node& moved)
     5949        {
     5950                if (!impl::allow_move(*this, moved)) return xml_node();
     5951
     5952                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5953                if (!alloc.reserve()) return xml_node();
     5954
     5955                // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
     5956                impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
     5957
     5958                impl::remove_node(moved._root);
     5959                impl::prepend_node(moved._root, _root);
     5960
     5961                return moved;
     5962        }
     5963
     5964        PUGI__FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node)
     5965        {
     5966                if (!impl::allow_move(*this, moved)) return xml_node();
     5967                if (!node._root || node._root->parent != _root) return xml_node();
     5968                if (moved._root == node._root) return xml_node();
     5969
     5970                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5971                if (!alloc.reserve()) return xml_node();
     5972
     5973                // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
     5974                impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
     5975
     5976                impl::remove_node(moved._root);
     5977                impl::insert_node_after(moved._root, node._root);
     5978
     5979                return moved;
     5980        }
     5981
     5982        PUGI__FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node)
     5983        {
     5984                if (!impl::allow_move(*this, moved)) return xml_node();
     5985                if (!node._root || node._root->parent != _root) return xml_node();
     5986                if (moved._root == node._root) return xml_node();
     5987
     5988                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5989                if (!alloc.reserve()) return xml_node();
     5990
     5991                // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
     5992                impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
     5993
     5994                impl::remove_node(moved._root);
     5995                impl::insert_node_before(moved._root, node._root);
     5996
     5997                return moved;
     5998        }
     5999
     6000        PUGI__FN bool xml_node::remove_attribute(const char_t* name_)
     6001        {
     6002                return remove_attribute(attribute(name_));
     6003        }
     6004
     6005        PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a)
     6006        {
     6007                if (!_root || !a._attr) return false;
     6008                if (!impl::is_attribute_of(a._attr, _root)) return false;
     6009
     6010                impl::xml_allocator& alloc = impl::get_allocator(_root);
     6011                if (!alloc.reserve()) return false;
     6012
     6013                impl::remove_attribute(a._attr, _root);
     6014                impl::destroy_attribute(a._attr, alloc);
     6015
     6016                return true;
     6017        }
     6018
     6019        PUGI__FN bool xml_node::remove_child(const char_t* name_)
     6020        {
     6021                return remove_child(child(name_));
     6022        }
     6023
     6024        PUGI__FN bool xml_node::remove_child(const xml_node& n)
     6025        {
     6026                if (!_root || !n._root || n._root->parent != _root) return false;
     6027
     6028                impl::xml_allocator& alloc = impl::get_allocator(_root);
     6029                if (!alloc.reserve()) return false;
     6030
     6031                impl::remove_node(n._root);
     6032                impl::destroy_node(n._root, alloc);
     6033
     6034                return true;
     6035        }
     6036
     6037        PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
     6038        {
     6039                // append_buffer is only valid for elements/documents
     6040                if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root);
     6041
     6042                // get document node
     6043                impl::xml_document_struct* doc = &impl::get_document(_root);
     6044
     6045                // disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense
     6046                doc->header |= impl::xml_memory_page_contents_shared_mask;
     6047
     6048                // get extra buffer element (we'll store the document fragment buffer there so that we can deallocate it later)
     6049                impl::xml_memory_page* page = 0;
     6050                impl::xml_extra_buffer* extra = static_cast<impl::xml_extra_buffer*>(doc->allocate_memory(sizeof(impl::xml_extra_buffer), page));
     6051                (void)page;
     6052
     6053                if (!extra) return impl::make_parse_result(status_out_of_memory);
     6054
     6055                // add extra buffer to the list
     6056                extra->buffer = 0;
     6057                extra->next = doc->extra_buffers;
     6058                doc->extra_buffers = extra;
     6059
     6060                // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level
     6061                impl::name_null_sentry sentry(_root);
     6062
     6063                return impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &extra->buffer);
     6064        }
     6065
     6066        PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const
    36986067        {
    36996068                if (!_root) return xml_node();
    37006069
    3701                 xml_memory_page* page = reinterpret_cast<xml_memory_page*>(_root->header & xml_memory_page_pointer_mask);
    3702 
    3703                 return xml_node(static_cast<xml_document_struct*>(page->allocator));
    3704         }
    3705 
    3706         const char_t* xml_node::child_value() const
    3707         {
    3708                 if (!_root) return PUGIXML_TEXT("");
    3709                
    37106070                for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
    3711                 {
    3712                         xml_node_type type = static_cast<xml_node_type>((i->header & xml_memory_page_type_mask) + 1);
    3713 
    3714                         if (i->value && (type == node_pcdata || type == node_cdata))
    3715                                 return i->value;
    3716                 }
    3717 
    3718                 return PUGIXML_TEXT("");
    3719         }
    3720 
    3721         const char_t* xml_node::child_value(const char_t* name) const
    3722         {
    3723                 return child(name).child_value();
    3724         }
    3725 
    3726         xml_attribute xml_node::first_attribute() const
    3727         {
    3728                 return _root ? xml_attribute(_root->first_attribute) : xml_attribute();
    3729         }
    3730 
    3731         xml_attribute xml_node::last_attribute() const
    3732         {
    3733                 return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute();
    3734         }
    3735 
    3736         xml_node xml_node::first_child() const
    3737         {
    3738                 return _root ? xml_node(_root->first_child) : xml_node();
    3739         }
    3740 
    3741         xml_node xml_node::last_child() const
    3742         {
    3743                 return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node();
    3744         }
    3745 
    3746         bool xml_node::set_name(const char_t* rhs)
    3747         {
    3748                 switch (type())
    3749                 {
    3750                 case node_pi:
    3751                 case node_declaration:
    3752                 case node_element:
    3753                         return strcpy_insitu(_root->name, _root->header, xml_memory_page_name_allocated_mask, rhs);
    3754 
    3755                 default:
    3756                         return false;
    3757                 }
    3758         }
    3759                
    3760         bool xml_node::set_value(const char_t* rhs)
    3761         {
    3762                 switch (type())
    3763                 {
    3764                 case node_pi:
    3765                 case node_cdata:
    3766                 case node_pcdata:
    3767                 case node_comment:
    3768         case node_doctype:
    3769                         return strcpy_insitu(_root->value, _root->header, xml_memory_page_value_allocated_mask, rhs);
    3770 
    3771                 default:
    3772                         return false;
    3773                 }
    3774         }
    3775 
    3776         xml_attribute xml_node::append_attribute(const char_t* name)
    3777         {
    3778                 if (type() != node_element && type() != node_declaration) return xml_attribute();
    3779                
    3780                 xml_attribute a(append_attribute_ll(_root, get_allocator(_root)));
    3781                 a.set_name(name);
    3782                
    3783                 return a;
    3784         }
    3785 
    3786         xml_attribute xml_node::prepend_attribute(const char_t* name)
    3787         {
    3788                 if (type() != node_element && type() != node_declaration) return xml_attribute();
    3789                
    3790                 xml_attribute a(allocate_attribute(get_allocator(_root)));
    3791                 if (!a) return xml_attribute();
    3792 
    3793                 a.set_name(name);
    3794                
    3795         xml_attribute_struct* head = _root->first_attribute;
    3796 
    3797                 if (head)
    3798         {
    3799             a._attr->prev_attribute_c = head->prev_attribute_c;
    3800             head->prev_attribute_c = a._attr;
    3801         }
    3802         else
    3803             a._attr->prev_attribute_c = a._attr;
    3804                
    3805                 a._attr->next_attribute = head;
    3806         _root->first_attribute = a._attr;
    3807                                
    3808                 return a;
    3809         }
    3810 
    3811         xml_attribute xml_node::insert_attribute_before(const char_t* name, const xml_attribute& attr)
    3812         {
    3813                 if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute();
    3814                
    3815                 // check that attribute belongs to *this
    3816                 xml_attribute_struct* cur = attr._attr;
    3817 
    3818                 while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c;
    3819 
    3820                 if (cur != _root->first_attribute) return xml_attribute();
    3821 
    3822                 xml_attribute a(allocate_attribute(get_allocator(_root)));
    3823                 if (!a) return xml_attribute();
    3824 
    3825                 a.set_name(name);
    3826 
    3827                 if (attr._attr->prev_attribute_c->next_attribute)
    3828                         attr._attr->prev_attribute_c->next_attribute = a._attr;
    3829                 else
    3830                         _root->first_attribute = a._attr;
    3831                
    3832                 a._attr->prev_attribute_c = attr._attr->prev_attribute_c;
    3833                 a._attr->next_attribute = attr._attr;
    3834                 attr._attr->prev_attribute_c = a._attr;
    3835                                
    3836                 return a;
    3837         }
    3838 
    3839         xml_attribute xml_node::insert_attribute_after(const char_t* name, const xml_attribute& attr)
    3840         {
    3841                 if ((type() != node_element && type() != node_declaration) || attr.empty()) return xml_attribute();
    3842                
    3843                 // check that attribute belongs to *this
    3844                 xml_attribute_struct* cur = attr._attr;
    3845 
    3846                 while (cur->prev_attribute_c->next_attribute) cur = cur->prev_attribute_c;
    3847 
    3848                 if (cur != _root->first_attribute) return xml_attribute();
    3849 
    3850                 xml_attribute a(allocate_attribute(get_allocator(_root)));
    3851                 if (!a) return xml_attribute();
    3852 
    3853                 a.set_name(name);
    3854 
    3855                 if (attr._attr->next_attribute)
    3856                         attr._attr->next_attribute->prev_attribute_c = a._attr;
    3857                 else
    3858                         _root->first_attribute->prev_attribute_c = a._attr;
    3859                
    3860                 a._attr->next_attribute = attr._attr->next_attribute;
    3861                 a._attr->prev_attribute_c = attr._attr;
    3862                 attr._attr->next_attribute = a._attr;
    3863 
    3864                 return a;
    3865         }
    3866 
    3867         xml_attribute xml_node::append_copy(const xml_attribute& proto)
    3868         {
    3869                 if (!proto) return xml_attribute();
    3870 
    3871                 xml_attribute result = append_attribute(proto.name());
    3872                 result.set_value(proto.value());
    3873 
    3874                 return result;
    3875         }
    3876 
    3877         xml_attribute xml_node::prepend_copy(const xml_attribute& proto)
    3878         {
    3879                 if (!proto) return xml_attribute();
    3880 
    3881                 xml_attribute result = prepend_attribute(proto.name());
    3882                 result.set_value(proto.value());
    3883 
    3884                 return result;
    3885         }
    3886 
    3887         xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr)
    3888         {
    3889                 if (!proto) return xml_attribute();
    3890 
    3891                 xml_attribute result = insert_attribute_after(proto.name(), attr);
    3892                 result.set_value(proto.value());
    3893 
    3894                 return result;
    3895         }
    3896 
    3897         xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr)
    3898         {
    3899                 if (!proto) return xml_attribute();
    3900 
    3901                 xml_attribute result = insert_attribute_before(proto.name(), attr);
    3902                 result.set_value(proto.value());
    3903 
    3904                 return result;
    3905         }
    3906 
    3907         xml_node xml_node::append_child(xml_node_type type)
    3908         {
    3909                 if (!allow_insert_child(this->type(), type)) return xml_node();
    3910                
    3911                 xml_node n(append_node(_root, get_allocator(_root), type));
    3912 
    3913                 if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
    3914 
    3915                 return n;
    3916         }
    3917 
    3918         xml_node xml_node::prepend_child(xml_node_type type)
    3919         {
    3920                 if (!allow_insert_child(this->type(), type)) return xml_node();
    3921                
    3922                 xml_node n(allocate_node(get_allocator(_root), type));
    3923                 if (!n) return xml_node();
    3924 
    3925         n._root->parent = _root;
    3926 
    3927         xml_node_struct* head = _root->first_child;
    3928 
    3929                 if (head)
    3930         {
    3931             n._root->prev_sibling_c = head->prev_sibling_c;
    3932             head->prev_sibling_c = n._root;
    3933         }
    3934         else
    3935             n._root->prev_sibling_c = n._root;
    3936                
    3937                 n._root->next_sibling = head;
    3938         _root->first_child = n._root;
    3939                                
    3940                 if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
    3941 
    3942                 return n;
    3943         }
    3944 
    3945         xml_node xml_node::insert_child_before(xml_node_type type, const xml_node& node)
    3946         {
    3947                 if (!allow_insert_child(this->type(), type)) return xml_node();
    3948                 if (!node._root || node._root->parent != _root) return xml_node();
    3949        
    3950                 xml_node n(allocate_node(get_allocator(_root), type));
    3951                 if (!n) return xml_node();
    3952 
    3953                 n._root->parent = _root;
    3954                
    3955                 if (node._root->prev_sibling_c->next_sibling)
    3956                         node._root->prev_sibling_c->next_sibling = n._root;
    3957                 else
    3958                         _root->first_child = n._root;
    3959                
    3960                 n._root->prev_sibling_c = node._root->prev_sibling_c;
    3961                 n._root->next_sibling = node._root;
    3962                 node._root->prev_sibling_c = n._root;
    3963 
    3964                 if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
    3965 
    3966                 return n;
    3967         }
    3968 
    3969         xml_node xml_node::insert_child_after(xml_node_type type, const xml_node& node)
    3970         {
    3971                 if (!allow_insert_child(this->type(), type)) return xml_node();
    3972                 if (!node._root || node._root->parent != _root) return xml_node();
    3973        
    3974                 xml_node n(allocate_node(get_allocator(_root), type));
    3975                 if (!n) return xml_node();
    3976 
    3977                 n._root->parent = _root;
    3978        
    3979                 if (node._root->next_sibling)
    3980                         node._root->next_sibling->prev_sibling_c = n._root;
    3981                 else
    3982                         _root->first_child->prev_sibling_c = n._root;
    3983                
    3984                 n._root->next_sibling = node._root->next_sibling;
    3985                 n._root->prev_sibling_c = node._root;
    3986                 node._root->next_sibling = n._root;
    3987 
    3988                 if (type == node_declaration) n.set_name(PUGIXML_TEXT("xml"));
    3989 
    3990                 return n;
    3991         }
    3992 
    3993     xml_node xml_node::append_child(const char_t* name)
    3994     {
    3995         xml_node result = append_child(node_element);
    3996 
    3997         result.set_name(name);
    3998 
    3999         return result;
    4000     }
    4001 
    4002     xml_node xml_node::prepend_child(const char_t* name)
    4003     {
    4004         xml_node result = prepend_child(node_element);
    4005 
    4006         result.set_name(name);
    4007 
    4008         return result;
    4009     }
    4010 
    4011     xml_node xml_node::insert_child_after(const char_t* name, const xml_node& node)
    4012     {
    4013         xml_node result = insert_child_after(node_element, node);
    4014 
    4015         result.set_name(name);
    4016 
    4017         return result;
    4018     }
    4019 
    4020     xml_node xml_node::insert_child_before(const char_t* name, const xml_node& node)
    4021     {
    4022         xml_node result = insert_child_before(node_element, node);
    4023 
    4024         result.set_name(name);
    4025 
    4026         return result;
    4027     }
    4028 
    4029         xml_node xml_node::append_copy(const xml_node& proto)
    4030         {
    4031                 xml_node result = append_child(proto.type());
    4032 
    4033                 if (result) recursive_copy_skip(result, proto, result);
    4034 
    4035                 return result;
    4036         }
    4037 
    4038         xml_node xml_node::prepend_copy(const xml_node& proto)
    4039         {
    4040                 xml_node result = prepend_child(proto.type());
    4041 
    4042                 if (result) recursive_copy_skip(result, proto, result);
    4043 
    4044                 return result;
    4045         }
    4046 
    4047         xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)
    4048         {
    4049                 xml_node result = insert_child_after(proto.type(), node);
    4050 
    4051                 if (result) recursive_copy_skip(result, proto, result);
    4052 
    4053                 return result;
    4054         }
    4055 
    4056         xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)
    4057         {
    4058                 xml_node result = insert_child_before(proto.type(), node);
    4059 
    4060                 if (result) recursive_copy_skip(result, proto, result);
    4061 
    4062                 return result;
    4063         }
    4064 
    4065         bool xml_node::remove_attribute(const char_t* name)
    4066         {
    4067                 return remove_attribute(attribute(name));
    4068         }
    4069 
    4070         bool xml_node::remove_attribute(const xml_attribute& a)
    4071         {
    4072                 if (!_root || !a._attr) return false;
    4073 
    4074                 // check that attribute belongs to *this
    4075                 xml_attribute_struct* attr = a._attr;
    4076 
    4077                 while (attr->prev_attribute_c->next_attribute) attr = attr->prev_attribute_c;
    4078 
    4079                 if (attr != _root->first_attribute) return false;
    4080 
    4081                 if (a._attr->next_attribute) a._attr->next_attribute->prev_attribute_c = a._attr->prev_attribute_c;
    4082                 else if (_root->first_attribute) _root->first_attribute->prev_attribute_c = a._attr->prev_attribute_c;
    4083                
    4084                 if (a._attr->prev_attribute_c->next_attribute) a._attr->prev_attribute_c->next_attribute = a._attr->next_attribute;
    4085                 else _root->first_attribute = a._attr->next_attribute;
    4086 
    4087                 destroy_attribute(a._attr, get_allocator(_root));
    4088 
    4089                 return true;
    4090         }
    4091 
    4092         bool xml_node::remove_child(const char_t* name)
    4093         {
    4094                 return remove_child(child(name));
    4095         }
    4096 
    4097         bool xml_node::remove_child(const xml_node& n)
    4098         {
    4099                 if (!_root || !n._root || n._root->parent != _root) return false;
    4100 
    4101                 if (n._root->next_sibling) n._root->next_sibling->prev_sibling_c = n._root->prev_sibling_c;
    4102                 else if (_root->first_child) _root->first_child->prev_sibling_c = n._root->prev_sibling_c;
    4103                
    4104                 if (n._root->prev_sibling_c->next_sibling) n._root->prev_sibling_c->next_sibling = n._root->next_sibling;
    4105                 else _root->first_child = n._root->next_sibling;
    4106        
    4107         destroy_node(n._root, get_allocator(_root));
    4108 
    4109                 return true;
    4110         }
    4111 
    4112         xml_node xml_node::find_child_by_attribute(const char_t* name, const char_t* attr_name, const char_t* attr_value) const
     6071                        if (i->name && impl::strequal(name_, i->name))
     6072                        {
     6073                                for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
     6074                                        if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
     6075                                                return xml_node(i);
     6076                        }
     6077
     6078                return xml_node();
     6079        }
     6080
     6081        PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
    41136082        {
    41146083                if (!_root) return xml_node();
    4115                
    4116                 for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
    4117                         if (i->name && strequal(name, i->name))
    4118                         {
    4119                                 for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
    4120                                         if (strequal(attr_name, a->name) && strequal(attr_value, a->value))
    4121                                                 return xml_node(i);
    4122                         }
    4123 
    4124                 return xml_node();
    4125         }
    4126 
    4127         xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
    4128         {
    4129                 if (!_root) return xml_node();
    4130                
     6084
    41316085                for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
    41326086                        for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
    4133                                 if (strequal(attr_name, a->name) && strequal(attr_value, a->value))
     6087                                if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
    41346088                                        return xml_node(i);
    41356089
     
    41386092
    41396093#ifndef PUGIXML_NO_STL
    4140         string_t xml_node::path(char_t delimiter) const
    4141         {
    4142                 string_t path;
    4143 
    4144                 xml_node cursor = *this; // Make a copy.
    4145                
    4146                 path = cursor.name();
    4147 
    4148                 while (cursor.parent())
    4149                 {
    4150                         cursor = cursor.parent();
    4151                        
    4152                         string_t temp = cursor.name();
    4153                         temp += delimiter;
    4154                         temp += path;
    4155                         path.swap(temp);
    4156                 }
    4157 
    4158                 return path;
     6094        PUGI__FN string_t xml_node::path(char_t delimiter) const
     6095        {
     6096                if (!_root) return string_t();
     6097
     6098                size_t offset = 0;
     6099
     6100                for (xml_node_struct* i = _root; i; i = i->parent)
     6101                {
     6102                        offset += (i != _root);
     6103                        offset += i->name ? impl::strlength(i->name) : 0;
     6104                }
     6105
     6106                string_t result;
     6107                result.resize(offset);
     6108
     6109                for (xml_node_struct* j = _root; j; j = j->parent)
     6110                {
     6111                        if (j != _root)
     6112                                result[--offset] = delimiter;
     6113
     6114                        if (j->name && *j->name)
     6115                        {
     6116                                size_t length = impl::strlength(j->name);
     6117
     6118                                offset -= length;
     6119                                memcpy(&result[offset], j->name, length * sizeof(char_t));
     6120                        }
     6121                }
     6122
     6123                assert(offset == 0);
     6124
     6125                return result;
    41596126        }
    41606127#endif
    41616128
    4162         xml_node xml_node::first_element_by_path(const char_t* path, char_t delimiter) const
     6129        PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const
    41636130        {
    41646131                xml_node found = *this; // Current search context.
    41656132
    4166                 if (!_root || !path || !path[0]) return found;
    4167 
    4168                 if (path[0] == delimiter)
     6133                if (!_root || !path_ || !path_[0]) return found;
     6134
     6135                if (path_[0] == delimiter)
    41696136                {
    41706137                        // Absolute path; e.g. '/foo/bar'
    41716138                        found = found.root();
    4172                         ++path;
    4173                 }
    4174 
    4175                 const char_t* path_segment = path;
     6139                        ++path_;
     6140                }
     6141
     6142                const char_t* path_segment = path_;
    41766143
    41776144                while (*path_segment == delimiter) ++path_segment;
     
    41956162                        for (xml_node_struct* j = found._root->first_child; j; j = j->next_sibling)
    41966163                        {
    4197                                 if (j->name && strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
     6164                                if (j->name && impl::strequalrange(j->name, path_segment, static_cast<size_t>(path_segment_end - path_segment)))
    41986165                                {
    41996166                                        xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter);
     
    42076174        }
    42086175
    4209         bool xml_node::traverse(xml_tree_walker& walker)
     6176        PUGI__FN bool xml_node::traverse(xml_tree_walker& walker)
    42106177        {
    42116178                walker._depth = -1;
    4212                
     6179
    42136180                xml_node arg_begin = *this;
    42146181                if (!walker.begin(arg_begin)) return false;
    42156182
    42166183                xml_node cur = first_child();
    4217                                
     6184
    42186185                if (cur)
    42196186                {
    42206187                        ++walker._depth;
    42216188
    4222                         do 
     6189                        do
    42236190                        {
    42246191                                xml_node arg_for_each = cur;
    42256192                                if (!walker.for_each(arg_for_each))
    42266193                                        return false;
    4227                                                
     6194
    42286195                                if (cur.first_child())
    42296196                                {
     
    42366203                                {
    42376204                                        // Borland C++ workaround
    4238                                         while (!cur.next_sibling() && cur != *this && (bool)cur.parent())
     6205                                        while (!cur.next_sibling() && cur != *this && !cur.parent().empty())
    42396206                                        {
    42406207                                                --walker._depth;
    42416208                                                cur = cur.parent();
    42426209                                        }
    4243                                                
     6210
    42446211                                        if (cur != *this)
    42456212                                                cur = cur.next_sibling();
     
    42556222        }
    42566223
    4257     size_t xml_node::hash_value() const
    4258     {
    4259         return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
    4260     }
    4261 
    4262         xml_node_struct* xml_node::internal_object() const
    4263         {
    4264         return _root;
    4265         }
    4266 
    4267         void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
     6224        PUGI__FN size_t xml_node::hash_value() const
     6225        {
     6226                return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
     6227        }
     6228
     6229        PUGI__FN xml_node_struct* xml_node::internal_object() const
     6230        {
     6231                return _root;
     6232        }
     6233
     6234        PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
    42686235        {
    42696236                if (!_root) return;
    42706237
    4271                 xml_buffered_writer buffered_writer(writer, encoding);
    4272 
    4273                 node_output(buffered_writer, *this, indent, flags, depth);
     6238                impl::xml_buffered_writer buffered_writer(writer, encoding);
     6239
     6240                impl::node_output(buffered_writer, _root, indent, flags, depth);
     6241
     6242                buffered_writer.flush();
    42746243        }
    42756244
    42766245#ifndef PUGIXML_NO_STL
    4277         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
     6246        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
    42786247        {
    42796248                xml_writer_stream writer(stream);
     
    42826251        }
    42836252
    4284         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
     6253        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
    42856254        {
    42866255                xml_writer_stream writer(stream);
     
    42906259#endif
    42916260
    4292         ptrdiff_t xml_node::offset_debug() const
    4293         {
    4294                 xml_node_struct* r = root()._root;
    4295 
    4296                 if (!r) return -1;
    4297 
    4298                 const char_t* buffer = static_cast<xml_document_struct*>(r)->buffer;
    4299 
    4300                 if (!buffer) return -1;
     6261        PUGI__FN ptrdiff_t xml_node::offset_debug() const
     6262        {
     6263                if (!_root) return -1;
     6264
     6265                impl::xml_document_struct& doc = impl::get_document(_root);
     6266
     6267                // we can determine the offset reliably only if there is exactly once parse buffer
     6268                if (!doc.buffer || doc.extra_buffers) return -1;
    43016269
    43026270                switch (type())
     
    43086276                case node_declaration:
    43096277                case node_pi:
    4310                         return (_root->header & xml_memory_page_name_allocated_mask) ? -1 : _root->name - buffer;
     6278                        return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1;
    43116279
    43126280                case node_pcdata:
     
    43146282                case node_comment:
    43156283                case node_doctype:
    4316                         return (_root->header & xml_memory_page_value_allocated_mask) ? -1 : _root->value - buffer;
     6284                        return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1;
    43176285
    43186286                default:
     
    43226290
    43236291#ifdef __BORLANDC__
    4324         bool operator&&(const xml_node& lhs, bool rhs)
     6292        PUGI__FN bool operator&&(const xml_node& lhs, bool rhs)
    43256293        {
    43266294                return (bool)lhs && rhs;
    43276295        }
    43286296
    4329         bool operator||(const xml_node& lhs, bool rhs)
     6297        PUGI__FN bool operator||(const xml_node& lhs, bool rhs)
    43306298        {
    43316299                return (bool)lhs || rhs;
     
    43336301#endif
    43346302
    4335         xml_node_iterator::xml_node_iterator()
    4336         {
    4337         }
    4338 
    4339         xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
    4340         {
    4341         }
    4342 
    4343         xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
    4344         {
    4345         }
    4346 
    4347         bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const
     6303        PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root)
     6304        {
     6305        }
     6306
     6307        PUGI__FN xml_node_struct* xml_text::_data() const
     6308        {
     6309                if (!_root || impl::is_text_node(_root)) return _root;
     6310
     6311                // element nodes can have value if parse_embed_pcdata was used
     6312                if (PUGI__NODETYPE(_root) == node_element && _root->value)
     6313                        return _root;
     6314
     6315                for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
     6316                        if (impl::is_text_node(node))
     6317                                return node;
     6318
     6319                return 0;
     6320        }
     6321
     6322        PUGI__FN xml_node_struct* xml_text::_data_new()
     6323        {
     6324                xml_node_struct* d = _data();
     6325                if (d) return d;
     6326
     6327                return xml_node(_root).append_child(node_pcdata).internal_object();
     6328        }
     6329
     6330        PUGI__FN xml_text::xml_text(): _root(0)
     6331        {
     6332        }
     6333
     6334        PUGI__FN static void unspecified_bool_xml_text(xml_text***)
     6335        {
     6336        }
     6337
     6338        PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const
     6339        {
     6340                return _data() ? unspecified_bool_xml_text : 0;
     6341        }
     6342
     6343        PUGI__FN bool xml_text::operator!() const
     6344        {
     6345                return !_data();
     6346        }
     6347
     6348        PUGI__FN bool xml_text::empty() const
     6349        {
     6350                return _data() == 0;
     6351        }
     6352
     6353        PUGI__FN const char_t* xml_text::get() const
     6354        {
     6355                xml_node_struct* d = _data();
     6356
     6357                return (d && d->value) ? d->value + 0 : PUGIXML_TEXT("");
     6358        }
     6359
     6360        PUGI__FN const char_t* xml_text::as_string(const char_t* def) const
     6361        {
     6362                xml_node_struct* d = _data();
     6363
     6364                return (d && d->value) ? d->value + 0 : def;
     6365        }
     6366
     6367        PUGI__FN int xml_text::as_int(int def) const
     6368        {
     6369                xml_node_struct* d = _data();
     6370
     6371                return (d && d->value) ? impl::get_value_int(d->value) : def;
     6372        }
     6373
     6374        PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
     6375        {
     6376                xml_node_struct* d = _data();
     6377
     6378                return (d && d->value) ? impl::get_value_uint(d->value) : def;
     6379        }
     6380
     6381        PUGI__FN double xml_text::as_double(double def) const
     6382        {
     6383                xml_node_struct* d = _data();
     6384
     6385                return (d && d->value) ? impl::get_value_double(d->value) : def;
     6386        }
     6387
     6388        PUGI__FN float xml_text::as_float(float def) const
     6389        {
     6390                xml_node_struct* d = _data();
     6391
     6392                return (d && d->value) ? impl::get_value_float(d->value) : def;
     6393        }
     6394
     6395        PUGI__FN bool xml_text::as_bool(bool def) const
     6396        {
     6397                xml_node_struct* d = _data();
     6398
     6399                return (d && d->value) ? impl::get_value_bool(d->value) : def;
     6400        }
     6401
     6402#ifdef PUGIXML_HAS_LONG_LONG
     6403        PUGI__FN long long xml_text::as_llong(long long def) const
     6404        {
     6405                xml_node_struct* d = _data();
     6406
     6407                return (d && d->value) ? impl::get_value_llong(d->value) : def;
     6408        }
     6409
     6410        PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const
     6411        {
     6412                xml_node_struct* d = _data();
     6413
     6414                return (d && d->value) ? impl::get_value_ullong(d->value) : def;
     6415        }
     6416#endif
     6417
     6418        PUGI__FN bool xml_text::set(const char_t* rhs)
     6419        {
     6420                xml_node_struct* dn = _data_new();
     6421
     6422                return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false;
     6423        }
     6424
     6425        PUGI__FN bool xml_text::set(int rhs)
     6426        {
     6427                xml_node_struct* dn = _data_new();
     6428
     6429                return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
     6430        }
     6431
     6432        PUGI__FN bool xml_text::set(unsigned int rhs)
     6433        {
     6434                xml_node_struct* dn = _data_new();
     6435
     6436                return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
     6437        }
     6438
     6439        PUGI__FN bool xml_text::set(long rhs)
     6440        {
     6441                xml_node_struct* dn = _data_new();
     6442
     6443                return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
     6444        }
     6445
     6446        PUGI__FN bool xml_text::set(unsigned long rhs)
     6447        {
     6448                xml_node_struct* dn = _data_new();
     6449
     6450                return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
     6451        }
     6452
     6453        PUGI__FN bool xml_text::set(float rhs)
     6454        {
     6455                xml_node_struct* dn = _data_new();
     6456
     6457                return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
     6458        }
     6459
     6460        PUGI__FN bool xml_text::set(double rhs)
     6461        {
     6462                xml_node_struct* dn = _data_new();
     6463
     6464                return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
     6465        }
     6466
     6467        PUGI__FN bool xml_text::set(bool rhs)
     6468        {
     6469                xml_node_struct* dn = _data_new();
     6470
     6471                return dn ? impl::set_value_bool(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
     6472        }
     6473
     6474#ifdef PUGIXML_HAS_LONG_LONG
     6475        PUGI__FN bool xml_text::set(long long rhs)
     6476        {
     6477                xml_node_struct* dn = _data_new();
     6478
     6479                return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
     6480        }
     6481
     6482        PUGI__FN bool xml_text::set(unsigned long long rhs)
     6483        {
     6484                xml_node_struct* dn = _data_new();
     6485
     6486                return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
     6487        }
     6488#endif
     6489
     6490        PUGI__FN xml_text& xml_text::operator=(const char_t* rhs)
     6491        {
     6492                set(rhs);
     6493                return *this;
     6494        }
     6495
     6496        PUGI__FN xml_text& xml_text::operator=(int rhs)
     6497        {
     6498                set(rhs);
     6499                return *this;
     6500        }
     6501
     6502        PUGI__FN xml_text& xml_text::operator=(unsigned int rhs)
     6503        {
     6504                set(rhs);
     6505                return *this;
     6506        }
     6507
     6508        PUGI__FN xml_text& xml_text::operator=(long rhs)
     6509        {
     6510                set(rhs);
     6511                return *this;
     6512        }
     6513
     6514        PUGI__FN xml_text& xml_text::operator=(unsigned long rhs)
     6515        {
     6516                set(rhs);
     6517                return *this;
     6518        }
     6519
     6520        PUGI__FN xml_text& xml_text::operator=(double rhs)
     6521        {
     6522                set(rhs);
     6523                return *this;
     6524        }
     6525
     6526        PUGI__FN xml_text& xml_text::operator=(float rhs)
     6527        {
     6528                set(rhs);
     6529                return *this;
     6530        }
     6531
     6532        PUGI__FN xml_text& xml_text::operator=(bool rhs)
     6533        {
     6534                set(rhs);
     6535                return *this;
     6536        }
     6537
     6538#ifdef PUGIXML_HAS_LONG_LONG
     6539        PUGI__FN xml_text& xml_text::operator=(long long rhs)
     6540        {
     6541                set(rhs);
     6542                return *this;
     6543        }
     6544
     6545        PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs)
     6546        {
     6547                set(rhs);
     6548                return *this;
     6549        }
     6550#endif
     6551
     6552        PUGI__FN xml_node xml_text::data() const
     6553        {
     6554                return xml_node(_data());
     6555        }
     6556
     6557#ifdef __BORLANDC__
     6558        PUGI__FN bool operator&&(const xml_text& lhs, bool rhs)
     6559        {
     6560                return (bool)lhs && rhs;
     6561        }
     6562
     6563        PUGI__FN bool operator||(const xml_text& lhs, bool rhs)
     6564        {
     6565                return (bool)lhs || rhs;
     6566        }
     6567#endif
     6568
     6569        PUGI__FN xml_node_iterator::xml_node_iterator()
     6570        {
     6571        }
     6572
     6573        PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
     6574        {
     6575        }
     6576
     6577        PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
     6578        {
     6579        }
     6580
     6581        PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const
    43486582        {
    43496583                return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
    43506584        }
    4351        
    4352         bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const
     6585
     6586        PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const
    43536587        {
    43546588                return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
    43556589        }
    43566590
    4357         xml_node& xml_node_iterator::operator*()
     6591        PUGI__FN xml_node& xml_node_iterator::operator*() const
    43586592        {
    43596593                assert(_wrap._root);
     
    43616595        }
    43626596
    4363         xml_node* xml_node_iterator::operator->()
     6597        PUGI__FN xml_node* xml_node_iterator::operator->() const
    43646598        {
    43656599                assert(_wrap._root);
    4366                 return &_wrap;
    4367         }
    4368 
    4369         const xml_node_iterator& xml_node_iterator::operator++()
     6600                return const_cast<xml_node*>(&_wrap); // BCC5 workaround
     6601        }
     6602
     6603        PUGI__FN const xml_node_iterator& xml_node_iterator::operator++()
    43706604        {
    43716605                assert(_wrap._root);
     
    43746608        }
    43756609
    4376         xml_node_iterator xml_node_iterator::operator++(int)
     6610        PUGI__FN xml_node_iterator xml_node_iterator::operator++(int)
    43776611        {
    43786612                xml_node_iterator temp = *this;
     
    43816615        }
    43826616
    4383         const xml_node_iterator& xml_node_iterator::operator--()
     6617        PUGI__FN const xml_node_iterator& xml_node_iterator::operator--()
    43846618        {
    43856619                _wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
     
    43876621        }
    43886622
    4389         xml_node_iterator xml_node_iterator::operator--(int)
     6623        PUGI__FN xml_node_iterator xml_node_iterator::operator--(int)
    43906624        {
    43916625                xml_node_iterator temp = *this;
     
    43946628        }
    43956629
    4396         xml_attribute_iterator::xml_attribute_iterator()
    4397         {
    4398         }
    4399 
    4400         xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
    4401         {
    4402         }
    4403 
    4404         xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
    4405         {
    4406         }
    4407 
    4408         bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const
     6630        PUGI__FN xml_attribute_iterator::xml_attribute_iterator()
     6631        {
     6632        }
     6633
     6634        PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
     6635        {
     6636        }
     6637
     6638        PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
     6639        {
     6640        }
     6641
     6642        PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const
    44096643        {
    44106644                return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
    44116645        }
    4412        
    4413         bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const
     6646
     6647        PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const
    44146648        {
    44156649                return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
    44166650        }
    44176651
    4418         xml_attribute& xml_attribute_iterator::operator*()
     6652        PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const
    44196653        {
    44206654                assert(_wrap._attr);
     
    44226656        }
    44236657
    4424         xml_attribute* xml_attribute_iterator::operator->()
     6658        PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const
    44256659        {
    44266660                assert(_wrap._attr);
    4427                 return &_wrap;
    4428         }
    4429 
    4430         const xml_attribute_iterator& xml_attribute_iterator::operator++()
     6661                return const_cast<xml_attribute*>(&_wrap); // BCC5 workaround
     6662        }
     6663
     6664        PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator++()
    44316665        {
    44326666                assert(_wrap._attr);
     
    44356669        }
    44366670
    4437         xml_attribute_iterator xml_attribute_iterator::operator++(int)
     6671        PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int)
    44386672        {
    44396673                xml_attribute_iterator temp = *this;
     
    44426676        }
    44436677
    4444         const xml_attribute_iterator& xml_attribute_iterator::operator--()
     6678        PUGI__FN const xml_attribute_iterator& xml_attribute_iterator::operator--()
    44456679        {
    44466680                _wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
     
    44486682        }
    44496683
    4450         xml_attribute_iterator xml_attribute_iterator::operator--(int)
     6684        PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int)
    44516685        {
    44526686                xml_attribute_iterator temp = *this;
     
    44556689        }
    44566690
    4457     xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
    4458     {
    4459     }
    4460 
    4461     xml_parse_result::operator bool() const
    4462     {
    4463         return status == status_ok;
    4464     }
    4465 
    4466         const char* xml_parse_result::description() const
     6691        PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0)
     6692        {
     6693        }
     6694
     6695        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)
     6696        {
     6697        }
     6698
     6699        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)
     6700        {
     6701        }
     6702
     6703        PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const
     6704        {
     6705                return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
     6706        }
     6707
     6708        PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const
     6709        {
     6710                return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
     6711        }
     6712
     6713        PUGI__FN xml_node& xml_named_node_iterator::operator*() const
     6714        {
     6715                assert(_wrap._root);
     6716                return _wrap;
     6717        }
     6718
     6719        PUGI__FN xml_node* xml_named_node_iterator::operator->() const
     6720        {
     6721                assert(_wrap._root);
     6722                return const_cast<xml_node*>(&_wrap); // BCC5 workaround
     6723        }
     6724
     6725        PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator++()
     6726        {
     6727                assert(_wrap._root);
     6728                _wrap = _wrap.next_sibling(_name);
     6729                return *this;
     6730        }
     6731
     6732        PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int)
     6733        {
     6734                xml_named_node_iterator temp = *this;
     6735                ++*this;
     6736                return temp;
     6737        }
     6738
     6739        PUGI__FN const xml_named_node_iterator& xml_named_node_iterator::operator--()
     6740        {
     6741                if (_wrap._root)
     6742                        _wrap = _wrap.previous_sibling(_name);
     6743                else
     6744                {
     6745                        _wrap = _parent.last_child();
     6746
     6747                        if (!impl::strequal(_wrap.name(), _name))
     6748                                _wrap = _wrap.previous_sibling(_name);
     6749                }
     6750
     6751                return *this;
     6752        }
     6753
     6754        PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(int)
     6755        {
     6756                xml_named_node_iterator temp = *this;
     6757                --*this;
     6758                return temp;
     6759        }
     6760
     6761        PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
     6762        {
     6763        }
     6764
     6765        PUGI__FN xml_parse_result::operator bool() const
     6766        {
     6767                return status == status_ok;
     6768        }
     6769
     6770        PUGI__FN const char* xml_parse_result::description() const
    44676771        {
    44686772                switch (status)
     
    44876791                case status_end_element_mismatch: return "Start-end tags mismatch";
    44886792
     6793                case status_append_invalid_root: return "Unable to append nodes: root is not an element or document";
     6794
     6795                case status_no_document_element: return "No document element found";
     6796
    44896797                default: return "Unknown error";
    44906798                }
    44916799        }
    44926800
    4493         xml_document::xml_document(): _buffer(0)
    4494         {
    4495                 create();
    4496         }
    4497 
    4498         xml_document::~xml_document()
    4499         {
    4500                 destroy();
    4501         }
    4502 
    4503         void xml_document::reset()
    4504         {
    4505                 destroy();
    4506                 create();
    4507         }
    4508 
    4509     void xml_document::reset(const xml_document& proto)
    4510     {
    4511         reset();
    4512 
    4513         for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
    4514             append_copy(cur);
    4515     }
    4516 
    4517         void xml_document::create()
    4518         {
     6801        PUGI__FN xml_document::xml_document(): _buffer(0)
     6802        {
     6803                _create();
     6804        }
     6805
     6806        PUGI__FN xml_document::~xml_document()
     6807        {
     6808                _destroy();
     6809        }
     6810
     6811        PUGI__FN void xml_document::reset()
     6812        {
     6813                _destroy();
     6814                _create();
     6815        }
     6816
     6817        PUGI__FN void xml_document::reset(const xml_document& proto)
     6818        {
     6819                reset();
     6820
     6821                for (xml_node cur = proto.first_child(); cur; cur = cur.next_sibling())
     6822                        append_copy(cur);
     6823        }
     6824
     6825        PUGI__FN void xml_document::_create()
     6826        {
     6827                assert(!_root);
     6828
     6829        #ifdef PUGIXML_COMPACT
     6830                const size_t page_offset = sizeof(uint32_t);
     6831        #else
     6832                const size_t page_offset = 0;
     6833        #endif
     6834
    45196835                // initialize sentinel page
    4520                 STATIC_ASSERT(offsetof(xml_memory_page, data) + sizeof(xml_document_struct) + xml_memory_page_alignment <= sizeof(_memory));
    4521 
    4522                 // align upwards to page boundary
    4523                 void* page_memory = reinterpret_cast<void*>((reinterpret_cast<uintptr_t>(_memory) + (xml_memory_page_alignment - 1)) & ~(xml_memory_page_alignment - 1));
     6836                PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory));
    45246837
    45256838                // prepare page structure
    4526                 xml_memory_page* page = xml_memory_page::construct(page_memory);
    4527 
    4528                 page->busy_size = xml_memory_page_size;
     6839                impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory);
     6840                assert(page);
     6841
     6842                page->busy_size = impl::xml_memory_page_size;
     6843
     6844                // setup first page marker
     6845        #ifdef PUGIXML_COMPACT
     6846                // round-trip through void* to avoid 'cast increases required alignment of target type' warning
     6847                page->compact_page_marker = reinterpret_cast<uint32_t*>(static_cast<void*>(reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page)));
     6848                *page->compact_page_marker = sizeof(impl::xml_memory_page);
     6849        #endif
    45296850
    45306851                // allocate new root
    4531                 _root = new (page->data) xml_document_struct(page);
     6852                _root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page);
    45326853                _root->prev_sibling_c = _root;
    45336854
    45346855                // setup sentinel page
    4535                 page->allocator = static_cast<xml_document_struct*>(_root);
    4536         }
    4537 
    4538         void xml_document::destroy()
    4539         {
     6856                page->allocator = static_cast<impl::xml_document_struct*>(_root);
     6857
     6858                // setup hash table pointer in allocator
     6859        #ifdef PUGIXML_COMPACT
     6860                page->allocator->_hash = &static_cast<impl::xml_document_struct*>(_root)->hash;
     6861        #endif
     6862
     6863                // verify the document allocation
     6864                assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory));
     6865        }
     6866
     6867        PUGI__FN void xml_document::_destroy()
     6868        {
     6869                assert(_root);
     6870
    45406871                // destroy static storage
    45416872                if (_buffer)
    45426873                {
    4543                         global_deallocate(_buffer);
     6874                        impl::xml_memory::deallocate(_buffer);
    45446875                        _buffer = 0;
    45456876                }
    45466877
     6878                // destroy extra buffers (note: no need to destroy linked list nodes, they're allocated using document allocator)
     6879                for (impl::xml_extra_buffer* extra = static_cast<impl::xml_document_struct*>(_root)->extra_buffers; extra; extra = extra->next)
     6880                {
     6881                        if (extra->buffer) impl::xml_memory::deallocate(extra->buffer);
     6882                }
     6883
    45476884                // destroy dynamic storage, leave sentinel page (it's in static memory)
    4548                 if (_root)
    4549                 {
    4550                         xml_memory_page* root_page = reinterpret_cast<xml_memory_page*>(_root->header & xml_memory_page_pointer_mask);
    4551                         assert(root_page && !root_page->prev && !root_page->memory);
    4552 
    4553                         // destroy all pages
    4554                         for (xml_memory_page* page = root_page->next; page; )
    4555                         {
    4556                                 xml_memory_page* next = page->next;
    4557 
    4558                                 xml_allocator::deallocate_page(page);
    4559 
    4560                                 page = next;
    4561                         }
    4562 
    4563                         // cleanup root page
    4564                         root_page->allocator = 0;
    4565                         root_page->next = 0;
    4566                         root_page->busy_size = root_page->freed_size = 0;
    4567 
    4568                         _root = 0;
    4569                 }
     6885                impl::xml_memory_page* root_page = PUGI__GETPAGE(_root);
     6886                assert(root_page && !root_page->prev);
     6887                assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));
     6888
     6889                for (impl::xml_memory_page* page = root_page->next; page; )
     6890                {
     6891                        impl::xml_memory_page* next = page->next;
     6892
     6893                        impl::xml_allocator::deallocate_page(page);
     6894
     6895                        page = next;
     6896                }
     6897
     6898        #ifdef PUGIXML_COMPACT
     6899                // destroy hash table
     6900                static_cast<impl::xml_document_struct*>(_root)->hash.clear();
     6901        #endif
     6902
     6903                _root = 0;
    45706904        }
    45716905
    45726906#ifndef PUGIXML_NO_STL
    4573         xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
     6907        PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
    45746908        {
    45756909                reset();
    45766910
    4577                 return load_stream_impl(*this, stream, options, encoding);
    4578         }
    4579 
    4580         xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
     6911                return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding, &_buffer);
     6912        }
     6913
     6914        PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
    45816915        {
    45826916                reset();
    45836917
    4584                 return load_stream_impl(*this, stream, options, encoding_wchar);
     6918                return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding_wchar, &_buffer);
    45856919        }
    45866920#endif
    45876921
    4588         xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
     6922        PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options)
    45896923        {
    45906924                // Force native encoding (skip autodetection)
     
    45956929        #endif
    45966930
    4597                 return load_buffer(contents, strlength(contents) * sizeof(char_t), options, encoding);
    4598         }
    4599 
    4600         xml_parse_result xml_document::load_file(const char* path, unsigned int options, xml_encoding encoding)
     6931                return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
     6932        }
     6933
     6934        PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
     6935        {
     6936                return load_string(contents, options);
     6937        }
     6938
     6939        PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
    46016940        {
    46026941                reset();
    46036942
    4604                 FILE* file = fopen(path, "rb");
    4605 
    4606                 return load_file_impl(*this, file, options, encoding);
    4607         }
    4608 
    4609         xml_parse_result xml_document::load_file(const wchar_t* path, unsigned int options, xml_encoding encoding)
     6943                using impl::auto_deleter; // MSVC7 workaround
     6944                auto_deleter<FILE> file(fopen(path_, "rb"), impl::close_file);
     6945
     6946                return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
     6947        }
     6948
     6949        PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)
    46106950        {
    46116951                reset();
    46126952
    4613                 FILE* file = open_file_wide(path, L"rb");
    4614 
    4615                 return load_file_impl(*this, file, options, encoding);
    4616         }
    4617 
    4618         xml_parse_result xml_document::load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own)
     6953                using impl::auto_deleter; // MSVC7 workaround
     6954                auto_deleter<FILE> file(impl::open_file_wide(path_, L"rb"), impl::close_file);
     6955
     6956                return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
     6957        }
     6958
     6959        PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
    46196960        {
    46206961                reset();
    46216962
    4622                 // check input buffer
    4623                 assert(contents || size == 0);
    4624 
    4625                 // get actual encoding
    4626                 xml_encoding buffer_encoding = get_buffer_encoding(encoding, contents, size);
    4627 
    4628                 // get private buffer
    4629                 char_t* buffer = 0;
    4630                 size_t length = 0;
    4631 
    4632                 if (!convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return make_parse_result(status_out_of_memory);
    4633                
    4634                 // delete original buffer if we performed a conversion
    4635                 if (own && buffer != contents && contents) global_deallocate(contents);
    4636 
    4637                 // parse
    4638                 xml_parse_result res = xml_parser::parse(buffer, length, _root, options);
    4639 
    4640                 // remember encoding
    4641                 res.encoding = buffer_encoding;
    4642 
    4643                 // grab onto buffer if it's our buffer, user is responsible for deallocating contens himself
    4644                 if (own || buffer != contents) _buffer = buffer;
    4645 
    4646                 return res;
    4647         }
    4648 
    4649         xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
    4650         {
    4651                 return load_buffer_impl(const_cast<void*>(contents), size, options, encoding, false, false);
    4652         }
    4653 
    4654         xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
    4655         {
    4656                 return load_buffer_impl(contents, size, options, encoding, true, false);
    4657         }
    4658                
    4659         xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
    4660         {
    4661                 return load_buffer_impl(contents, size, options, encoding, true, true);
    4662         }
    4663 
    4664         void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
    4665         {
    4666                 if (flags & format_write_bom) write_bom(writer, get_write_encoding(encoding));
    4667 
    4668                 xml_buffered_writer buffered_writer(writer, encoding);
    4669 
    4670                 if (!(flags & format_no_declaration) && !has_declaration(*this))
    4671                 {
    4672                         buffered_writer.write(PUGIXML_TEXT("<?xml version=\"1.0\"?>"));
     6963                return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, const_cast<void*>(contents), size, options, encoding, false, false, &_buffer);
     6964        }
     6965
     6966        PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
     6967        {
     6968                reset();
     6969
     6970                return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, false, &_buffer);
     6971        }
     6972
     6973        PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
     6974        {
     6975                reset();
     6976
     6977                return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, true, &_buffer);
     6978        }
     6979
     6980        PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
     6981        {
     6982                impl::xml_buffered_writer buffered_writer(writer, encoding);
     6983
     6984                if ((flags & format_write_bom) && encoding != encoding_latin1)
     6985                {
     6986                        // BOM always represents the codepoint U+FEFF, so just write it in native encoding
     6987                #ifdef PUGIXML_WCHAR_MODE
     6988                        unsigned int bom = 0xfeff;
     6989                        buffered_writer.write(static_cast<wchar_t>(bom));
     6990                #else
     6991                        buffered_writer.write('\xef', '\xbb', '\xbf');
     6992                #endif
     6993                }
     6994
     6995                if (!(flags & format_no_declaration) && !impl::has_declaration(_root))
     6996                {
     6997                        buffered_writer.write_string(PUGIXML_TEXT("<?xml version=\"1.0\""));
     6998                        if (encoding == encoding_latin1) buffered_writer.write_string(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
     6999                        buffered_writer.write('?', '>');
    46737000                        if (!(flags & format_raw)) buffered_writer.write('\n');
    46747001                }
    46757002
    4676                 node_output(buffered_writer, *this, indent, flags, 0);
     7003                impl::node_output(buffered_writer, _root, indent, flags, 0);
     7004
     7005                buffered_writer.flush();
    46777006        }
    46787007
    46797008#ifndef PUGIXML_NO_STL
    4680         void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const
     7009        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
    46817010        {
    46827011                xml_writer_stream writer(stream);
     
    46857014        }
    46867015
    4687         void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const
     7016        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
    46887017        {
    46897018                xml_writer_stream writer(stream);
     
    46937022#endif
    46947023
    4695         bool xml_document::save_file(const char* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const
    4696         {
    4697                 FILE* file = fopen(path, "wb");
    4698                 if (!file) return false;
    4699 
    4700                 xml_writer_file writer(file);
    4701                 save(writer, indent, flags, encoding);
    4702 
    4703                 fclose(file);
    4704 
    4705                 return true;
    4706         }
    4707 
    4708         bool xml_document::save_file(const wchar_t* path, const char_t* indent, unsigned int flags, xml_encoding encoding) const
    4709         {
    4710                 FILE* file = open_file_wide(path, L"wb");
    4711                 if (!file) return false;
    4712 
    4713                 xml_writer_file writer(file);
    4714                 save(writer, indent, flags, encoding);
    4715 
    4716                 fclose(file);
    4717 
    4718                 return true;
    4719         }
    4720 
    4721     xml_node xml_document::document_element() const
    4722     {
     7024        PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
     7025        {
     7026                using impl::auto_deleter; // MSVC7 workaround
     7027                auto_deleter<FILE> file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file);
     7028
     7029                return impl::save_file_impl(*this, file.data, indent, flags, encoding);
     7030        }
     7031
     7032        PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
     7033        {
     7034                using impl::auto_deleter; // MSVC7 workaround
     7035                auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file);
     7036
     7037                return impl::save_file_impl(*this, file.data, indent, flags, encoding);
     7038        }
     7039
     7040        PUGI__FN xml_node xml_document::document_element() const
     7041        {
     7042                assert(_root);
     7043
    47237044                for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
    4724                         if ((i->header & xml_memory_page_type_mask) + 1 == node_element)
    4725                 return xml_node(i);
    4726 
    4727         return xml_node();
    4728     }
     7045                        if (PUGI__NODETYPE(i) == node_element)
     7046                                return xml_node(i);
     7047
     7048                return xml_node();
     7049        }
    47297050
    47307051#ifndef PUGIXML_NO_STL
    4731         std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
     7052        PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
    47327053        {
    47337054                assert(str);
    47347055
    4735         return as_utf8_impl(str, wcslen(str));
    4736         }
    4737 
    4738         std::string PUGIXML_FUNCTION as_utf8(const std::wstring& str)
    4739         {
    4740         return as_utf8_impl(str.c_str(), str.size());
    4741         }
    4742        
    4743         std::wstring PUGIXML_FUNCTION as_wide(const char* str)
     7056                return impl::as_utf8_impl(str, impl::strlength_wide(str));
     7057        }
     7058
     7059        PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str)
     7060        {
     7061                return impl::as_utf8_impl(str.c_str(), str.size());
     7062        }
     7063
     7064        PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str)
    47447065        {
    47457066                assert(str);
    47467067
    4747         return as_wide_impl(str, strlen(str));
    4748         }
    4749        
    4750         std::wstring PUGIXML_FUNCTION as_wide(const std::string& str)
    4751         {
    4752         return as_wide_impl(str.c_str(), str.size());
     7068                return impl::as_wide_impl(str, strlen(str));
     7069        }
     7070
     7071        PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str)
     7072        {
     7073                return impl::as_wide_impl(str.c_str(), str.size());
    47537074        }
    47547075#endif
    47557076
    4756     void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
    4757     {
    4758         global_allocate = allocate;
    4759         global_deallocate = deallocate;
    4760     }
    4761 
    4762     allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
    4763     {
    4764         return global_allocate;
    4765     }
    4766 
    4767     deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
    4768     {
    4769         return global_deallocate;
    4770     }
     7077        PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
     7078        {
     7079                impl::xml_memory::allocate = allocate;
     7080                impl::xml_memory::deallocate = deallocate;
     7081        }
     7082
     7083        PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
     7084        {
     7085                return impl::xml_memory::allocate;
     7086        }
     7087
     7088        PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
     7089        {
     7090                return impl::xml_memory::deallocate;
     7091        }
    47717092}
    47727093
     
    47757096{
    47767097        // Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
    4777         std::bidirectional_iterator_tag _Iter_cat(const xml_node_iterator&)
     7098        PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
    47787099        {
    47797100                return std::bidirectional_iterator_tag();
    47807101        }
    47817102
    4782         std::bidirectional_iterator_tag _Iter_cat(const xml_attribute_iterator&)
     7103        PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
     7104        {
     7105                return std::bidirectional_iterator_tag();
     7106        }
     7107
     7108        PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)
    47837109        {
    47847110                return std::bidirectional_iterator_tag();
     
    47917117{
    47927118        // Workarounds for (non-standard) iterator category detection
    4793         std::bidirectional_iterator_tag __iterator_category(const xml_node_iterator&)
     7119        PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)
    47947120        {
    47957121                return std::bidirectional_iterator_tag();
    47967122        }
    47977123
    4798         std::bidirectional_iterator_tag __iterator_category(const xml_attribute_iterator&)
     7124        PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)
     7125        {
     7126                return std::bidirectional_iterator_tag();
     7127        }
     7128
     7129        PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)
    47997130        {
    48007131                return std::bidirectional_iterator_tag();
     
    48047135
    48057136#ifndef PUGIXML_NO_XPATH
    4806 
    48077137// STL replacements
    4808 namespace
    4809 {
     7138PUGI__NS_BEGIN
    48107139        struct equal_to
    48117140        {
     
    48607189        template <typename I> void reverse(I begin, I end)
    48617190        {
    4862                 while (begin + 1 < end) swap(*begin++, *--end);
     7191                while (end - begin > 1) swap(*begin++, *--end);
    48637192        }
    48647193
     
    48667195        {
    48677196                // fast skip head
    4868                 while (begin + 1 < end && *begin != *(begin + 1)) begin++;
     7197                while (end - begin > 1 && *begin != *(begin + 1)) begin++;
    48697198
    48707199                if (begin == end) return begin;
    48717200
    48727201                // last written element
    4873                 I write = begin++; 
     7202                I write = begin++;
    48747203
    48757204                // merge unique elements
     
    50317360                if (begin != end) insertion_sort(begin, end, pred, &*begin);
    50327361        }
    5033 }
     7362PUGI__NS_END
    50347363
    50357364// Allocator used for AST and evaluation stacks
    5036 namespace
    5037 {
     7365PUGI__NS_BEGIN
     7366        static const size_t xpath_memory_page_size =
     7367        #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
     7368                PUGIXML_MEMORY_XPATH_PAGE_SIZE
     7369        #else
     7370                4096
     7371        #endif
     7372                ;
     7373
     7374        static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*);
     7375
    50387376        struct xpath_memory_block
    5039         {       
     7377        {
    50407378                xpath_memory_block* next;
    5041 
    5042                 char data[4096];
     7379                size_t capacity;
     7380
     7381                union
     7382                {
     7383                        char data[xpath_memory_page_size];
     7384                        double alignment;
     7385                };
    50437386        };
    5044                
     7387
    50457388        class xpath_allocator
    50467389        {
     
    50597402                #endif
    50607403                }
    5061                
     7404
    50627405                void* allocate_nothrow(size_t size)
    50637406                {
    5064                         const size_t block_capacity = sizeof(_root->data);
    5065 
    5066                         // align size so that we're able to store pointers in subsequent blocks
    5067                         size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
    5068 
    5069                         if (_root_size + size <= block_capacity)
    5070                         {
    5071                                 void* buf = _root->data + _root_size;
     7407                        // round size up to block alignment boundary
     7408                        size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
     7409
     7410                        if (_root_size + size <= _root->capacity)
     7411                        {
     7412                                void* buf = &_root->data[0] + _root_size;
    50727413                                _root_size += size;
    50737414                                return buf;
     
    50757416                        else
    50767417                        {
    5077                                 size_t block_data_size = (size > block_capacity) ? size : block_capacity;
    5078                                 size_t block_size = block_data_size + offsetof(xpath_memory_block, data);
    5079 
    5080                                 xpath_memory_block* block = static_cast<xpath_memory_block*>(global_allocate(block_size));
     7418                                // make sure we have at least 1/4th of the page free after allocation to satisfy subsequent allocation requests
     7419                                size_t block_capacity_base = sizeof(_root->data);
     7420                                size_t block_capacity_req = size + block_capacity_base / 4;
     7421                                size_t block_capacity = (block_capacity_base > block_capacity_req) ? block_capacity_base : block_capacity_req;
     7422
     7423                                size_t block_size = block_capacity + offsetof(xpath_memory_block, data);
     7424
     7425                                xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));
    50817426                                if (!block) return 0;
    5082                                
     7427
    50837428                                block->next = _root;
    5084                                
     7429                                block->capacity = block_capacity;
     7430
    50857431                                _root = block;
    50867432                                _root_size = size;
    5087                                
     7433
    50887434                                return block->data;
    50897435                        }
     
    51097455                void* reallocate(void* ptr, size_t old_size, size_t new_size)
    51107456                {
    5111                         // align size so that we're able to store pointers in subsequent blocks
    5112                         old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
    5113                         new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
     7457                        // round size up to block alignment boundary
     7458                        old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
     7459                        new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
    51147460
    51157461                        // we can only reallocate the last object
    5116                         assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _root->data + _root_size);
     7462                        assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);
    51177463
    51187464                        // adjust root size so that we have not allocated the object at all
     
    51297475                        {
    51307476                                // copy old data
    5131                                 assert(new_size > old_size);
     7477                                assert(new_size >= old_size);
    51327478                                memcpy(result, ptr, old_size);
    51337479
     
    51437489                                        {
    51447490                                                // deallocate the whole page, unless it was the first one
    5145                                                 global_deallocate(_root->next);
     7491                                                xml_memory::deallocate(_root->next);
    51467492                                                _root->next = next;
    51477493                                        }
     
    51617507                                xpath_memory_block* next = cur->next;
    51627508
    5163                                 global_deallocate(cur);
     7509                                xml_memory::deallocate(cur);
    51647510
    51657511                                cur = next;
     
    51807526                                xpath_memory_block* next = cur->next;
    51817527
    5182                                 global_deallocate(cur);
     7528                                xml_memory::deallocate(cur);
    51837529
    51847530                                cur = next;
     
    52227568                {
    52237569                        blocks[0].next = blocks[1].next = 0;
     7570                        blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data);
    52247571
    52257572                        stack.result = &result;
     
    52377584                }
    52387585        };
    5239 }
     7586PUGI__NS_END
    52407587
    52417588// String class
    5242 namespace
    5243 {
     7589PUGI__NS_BEGIN
    52447590        class xpath_string
    52457591        {
    52467592                const char_t* _buffer;
    52477593                bool _uses_heap;
     7594                size_t _length_heap;
    52487595
    52497596                static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc)
     
    52587605                }
    52597606
    5260                 static char_t* duplicate_string(const char_t* string, xpath_allocator* alloc)
    5261                 {
    5262                         return duplicate_string(string, strlength(string), alloc);
     7607                xpath_string(const char_t* buffer, bool uses_heap_, size_t length_heap): _buffer(buffer), _uses_heap(uses_heap_), _length_heap(length_heap)
     7608                {
    52637609                }
    52647610
    52657611        public:
    5266                 xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false)
    5267                 {
    5268                 }
    5269 
    5270                 explicit xpath_string(const char_t* str, xpath_allocator* alloc)
    5271                 {
    5272                         bool empty = (*str == 0);
    5273 
    5274                         _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(str, alloc);
    5275                         _uses_heap = !empty;
    5276                 }
    5277 
    5278                 explicit xpath_string(const char_t* str, bool use_heap): _buffer(str), _uses_heap(use_heap)
    5279                 {
    5280                 }
    5281 
    5282                 xpath_string(const char_t* begin, const char_t* end, xpath_allocator* alloc)
     7612                static xpath_string from_const(const char_t* str)
     7613                {
     7614                        return xpath_string(str, false, 0);
     7615                }
     7616
     7617                static xpath_string from_heap_preallocated(const char_t* begin, const char_t* end)
     7618                {
     7619                        assert(begin <= end && *end == 0);
     7620
     7621                        return xpath_string(begin, true, static_cast<size_t>(end - begin));
     7622                }
     7623
     7624                static xpath_string from_heap(const char_t* begin, const char_t* end, xpath_allocator* alloc)
    52837625                {
    52847626                        assert(begin <= end);
    52857627
    5286                         bool empty = (begin == end);
    5287 
    5288                         _buffer = empty ? PUGIXML_TEXT("") : duplicate_string(begin, static_cast<size_t>(end - begin), alloc);
    5289                         _uses_heap = !empty;
     7628                        size_t length = static_cast<size_t>(end - begin);
     7629
     7630                        return length == 0 ? xpath_string() : xpath_string(duplicate_string(begin, length, alloc), true, length);
     7631                }
     7632
     7633                xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0)
     7634                {
    52907635                }
    52917636
     
    53037648                        {
    53047649                                // need to make heap copy
    5305                                 size_t target_length = strlength(_buffer);
    5306                                 size_t source_length = strlength(o._buffer);
    5307                                 size_t length = target_length + source_length;
     7650                                size_t target_length = length();
     7651                                size_t source_length = o.length();
     7652                                size_t result_length = target_length + source_length;
    53087653
    53097654                                // allocate new buffer
    5310                                 char_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) * sizeof(char_t), (length + 1) * sizeof(char_t)));
     7655                                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)));
    53117656                                assert(result);
    53127657
     
    53167661                                // append second string to the new buffer
    53177662                                memcpy(result + target_length, o._buffer, source_length * sizeof(char_t));
    5318                                 result[length] = 0;
     7663                                result[result_length] = 0;
    53197664
    53207665                                // finalize
    53217666                                _buffer = result;
    53227667                                _uses_heap = true;
     7668                                _length_heap = result_length;
    53237669                        }
    53247670                }
     
    53317677                size_t length() const
    53327678                {
    5333                         return strlength(_buffer);
    5334                 }
    5335                
     7679                        return _uses_heap ? _length_heap : strlength(_buffer);
     7680                }
     7681
    53367682                char_t* data(xpath_allocator* alloc)
    53377683                {
     
    53397685                        if (!_uses_heap)
    53407686                        {
    5341                                 _buffer = duplicate_string(_buffer, alloc);
     7687                                size_t length_ = strlength(_buffer);
     7688
     7689                                _buffer = duplicate_string(_buffer, length_, alloc);
    53427690                                _uses_heap = true;
     7691                                _length_heap = length_;
    53437692                        }
    53447693
     
    53667715                }
    53677716        };
    5368 
    5369         xpath_string xpath_string_const(const char_t* str)
    5370         {
    5371                 return xpath_string(str, false);
    5372         }
    5373 }
    5374 
    5375 namespace
    5376 {
    5377         bool starts_with(const char_t* string, const char_t* pattern)
     7717PUGI__NS_END
     7718
     7719PUGI__NS_BEGIN
     7720        PUGI__FN bool starts_with(const char_t* string, const char_t* pattern)
    53787721        {
    53797722                while (*pattern && *string == *pattern)
     
    53867729        }
    53877730
    5388         const char_t* find_char(const char_t* s, char_t c)
     7731        PUGI__FN const char_t* find_char(const char_t* s, char_t c)
    53897732        {
    53907733        #ifdef PUGIXML_WCHAR_MODE
     
    53957738        }
    53967739
    5397         const char_t* find_substring(const char_t* s, const char_t* p)
     7740        PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p)
    53987741        {
    53997742        #ifdef PUGIXML_WCHAR_MODE
     
    54067749
    54077750        // Converts symbol to lower case, if it is an ASCII one
    5408         char_t tolower_ascii(char_t ch)
     7751        PUGI__FN char_t tolower_ascii(char_t ch)
    54097752        {
    54107753                return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
    54117754        }
    54127755
    5413         xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
     7756        PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
    54147757        {
    54157758                if (na.attribute())
    5416                         return xpath_string_const(na.attribute().value());
     7759                        return xpath_string::from_const(na.attribute().value());
    54177760                else
    54187761                {
    5419                         const xml_node& n = na.node();
     7762                        xml_node n = na.node();
    54207763
    54217764                        switch (n.type())
     
    54257768                        case node_comment:
    54267769                        case node_pi:
    5427                                 return xpath_string_const(n.value());
    5428                        
     7770                                return xpath_string::from_const(n.value());
     7771
    54297772                        case node_document:
    54307773                        case node_element:
     
    54327775                                xpath_string result;
    54337776
     7777                                // element nodes can have value if parse_embed_pcdata was used
     7778                                if (n.value()[0])
     7779                                        result.append(xpath_string::from_const(n.value()), alloc);
     7780
    54347781                                xml_node cur = n.first_child();
    5435                                
     7782
    54367783                                while (cur && cur != n)
    54377784                                {
    54387785                                        if (cur.type() == node_pcdata || cur.type() == node_cdata)
    5439                                                 result.append(xpath_string_const(cur.value()), alloc);
     7786                                                result.append(xpath_string::from_const(cur.value()), alloc);
    54407787
    54417788                                        if (cur.first_child())
     
    54517798                                        }
    54527799                                }
    5453                                
     7800
    54547801                                return result;
    54557802                        }
    5456                        
     7803
    54577804                        default:
    54587805                                return xpath_string();
     
    54607807                }
    54617808        }
    5462        
    5463         unsigned int node_height(xml_node n)
    5464         {
    5465             unsigned int result = 0;
    5466            
    5467             while (n)
    5468             {
    5469                 ++result;
    5470                 n = n.parent();
    5471             }
    5472            
    5473             return result;
    5474         }
    5475        
    5476         bool node_is_before(xml_node ln, unsigned int lh, xml_node rn, unsigned int rh)
    5477         {
    5478                 // normalize heights
    5479                 for (unsigned int i = rh; i < lh; i++) ln = ln.parent();
    5480                 for (unsigned int j = lh; j < rh; j++) rn = rn.parent();
    5481            
     7809
     7810        PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)
     7811        {
     7812                assert(ln->parent == rn->parent);
     7813
     7814                // there is no common ancestor (the shared parent is null), nodes are from different documents
     7815                if (!ln->parent) return ln < rn;
     7816
     7817                // determine sibling order
     7818                xml_node_struct* ls = ln;
     7819                xml_node_struct* rs = rn;
     7820
     7821                while (ls && rs)
     7822                {
     7823                        if (ls == rn) return true;
     7824                        if (rs == ln) return false;
     7825
     7826                        ls = ls->next_sibling;
     7827                        rs = rs->next_sibling;
     7828                }
     7829
     7830                // if rn sibling chain ended ln must be before rn
     7831                return !rs;
     7832        }
     7833
     7834        PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
     7835        {
     7836                // find common ancestor at the same depth, if any
     7837                xml_node_struct* lp = ln;
     7838                xml_node_struct* rp = rn;
     7839
     7840                while (lp && rp && lp->parent != rp->parent)
     7841                {
     7842                        lp = lp->parent;
     7843                        rp = rp->parent;
     7844                }
     7845
     7846                // parents are the same!
     7847                if (lp && rp) return node_is_before_sibling(lp, rp);
     7848
     7849                // nodes are at different depths, need to normalize heights
     7850                bool left_higher = !lp;
     7851
     7852                while (lp)
     7853                {
     7854                        lp = lp->parent;
     7855                        ln = ln->parent;
     7856                }
     7857
     7858                while (rp)
     7859                {
     7860                        rp = rp->parent;
     7861                        rn = rn->parent;
     7862                }
     7863
    54827864                // one node is the ancestor of the other
    5483             if (ln == rn) return lh < rh;
    5484            
    5485                 // find common ancestor
    5486             while (ln.parent() != rn.parent())
    5487             {
    5488                 ln = ln.parent();
    5489                 rn = rn.parent();
    5490             }
    5491 
    5492                 // there is no common ancestor (the shared parent is null), nodes are from different documents
    5493                 if (!ln.parent()) return ln < rn;
    5494 
    5495                 // determine sibling order
    5496         for (; ln; ln = ln.next_sibling())
    5497             if (ln == rn)
    5498                 return true;
    5499                
    5500         return false;
    5501     }
    5502 
    5503     bool node_is_ancestor(xml_node parent, xml_node node)
    5504     {
    5505         while (node && node != parent) node = node.parent();
    5506 
    5507         return parent && node == parent;
    5508     }
    5509 
    5510     const void* document_order(const xpath_node& xnode)
    5511     {
    5512         xml_node_struct* node = xnode.node().internal_object();
    5513 
    5514         if (node)
    5515         {
    5516             if (node->name && (node->header & xml_memory_page_name_allocated_mask) == 0) return node->name;
    5517             if (node->value && (node->header & xml_memory_page_value_allocated_mask) == 0) return node->value;
    5518             return 0;
    5519         }
    5520 
    5521         xml_attribute_struct* attr = xnode.attribute().internal_object();
    5522 
    5523         if (attr)
    5524         {
    5525             if ((attr->header & xml_memory_page_name_allocated_mask) == 0) return attr->name;
    5526             if ((attr->header & xml_memory_page_value_allocated_mask) == 0) return attr->value;
    5527             return 0;
    5528         }
     7865                if (ln == rn) return left_higher;
     7866
     7867                // find common ancestor... again
     7868                while (ln->parent != rn->parent)
     7869                {
     7870                        ln = ln->parent;
     7871                        rn = rn->parent;
     7872                }
     7873
     7874                return node_is_before_sibling(ln, rn);
     7875        }
     7876
     7877        PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)
     7878        {
     7879                while (node && node != parent) node = node->parent;
     7880
     7881                return parent && node == parent;
     7882        }
     7883
     7884        PUGI__FN const void* document_buffer_order(const xpath_node& xnode)
     7885        {
     7886                xml_node_struct* node = xnode.node().internal_object();
     7887
     7888                if (node)
     7889                {
     7890                        if ((get_document(node).header & xml_memory_page_contents_shared_mask) == 0)
     7891                        {
     7892                                if (node->name && (node->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return node->name;
     7893                                if (node->value && (node->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return node->value;
     7894                        }
     7895
     7896                        return 0;
     7897                }
     7898
     7899                xml_attribute_struct* attr = xnode.attribute().internal_object();
     7900
     7901                if (attr)
     7902                {
     7903                        if ((get_document(attr).header & xml_memory_page_contents_shared_mask) == 0)
     7904                        {
     7905                                if ((attr->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0) return attr->name;
     7906                                if ((attr->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0) return attr->value;
     7907                        }
     7908
     7909                        return 0;
     7910                }
    55297911
    55307912                return 0;
    5531     }
    5532    
     7913        }
     7914
    55337915        struct document_order_comparator
    55347916        {
     
    55367918                {
    55377919                        // optimized document order based check
    5538                         const void* lo = document_order(lhs);
    5539                         const void* ro = document_order(rhs);
     7920                        const void* lo = document_buffer_order(lhs);
     7921                        const void* ro = document_buffer_order(rhs);
    55407922
    55417923                        if (lo && ro) return lo < ro;
    55427924
    5543             // slow comparison
     7925                        // slow comparison
    55447926                        xml_node ln = lhs.node(), rn = rhs.node();
    55457927
     
    55517933                                {
    55527934                                        // determine sibling order
    5553                                     for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
    5554                                         if (a == rhs.attribute())
    5555                                             return true;
    5556                                    
    5557                                     return false;
    5558                                 }
    5559                                
     7935                                        for (xml_attribute a = lhs.attribute(); a; a = a.next_attribute())
     7936                                                if (a == rhs.attribute())
     7937                                                        return true;
     7938
     7939                                        return false;
     7940                                }
     7941
    55607942                                // compare attribute parents
    55617943                                ln = lhs.parent();
     
    55667948                                // attributes go after the parent element
    55677949                                if (lhs.parent() == rhs.node()) return false;
    5568                                
     7950
    55697951                                ln = lhs.parent();
    55707952                        }
     
    55737955                                // attributes go after the parent element
    55747956                                if (rhs.parent() == lhs.node()) return true;
    5575                                
     7957
    55767958                                rn = rhs.parent();
    55777959                        }
    55787960
    55797961                        if (ln == rn) return false;
    5580                        
    5581                         unsigned int lh = node_height(ln);
    5582                         unsigned int rh = node_height(rn);
    5583                        
    5584                         return node_is_before(ln, lh, rn, rh);
     7962
     7963                        if (!ln || !rn) return ln < rn;
     7964
     7965                        return node_is_before(ln.internal_object(), rn.internal_object());
    55857966                }
    55867967        };
     
    55947975                }
    55957976        };
    5596        
    5597         double gen_nan()
     7977
     7978        PUGI__FN double gen_nan()
    55987979        {
    55997980        #if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
    5600                 union { float f; int32_t i; } u[sizeof(float) == sizeof(int32_t) ? 1 : -1];
    5601                 u[0].i = 0x7fc00000;
    5602                 return u[0].f;
     7981                PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t));
     7982                typedef uint32_t UI; // BCC5 workaround
     7983                union { float f; UI i; } u;
     7984                u.i = 0x7fc00000;
     7985                return u.f;
    56037986        #else
    56047987                // fallback
     
    56077990        #endif
    56087991        }
    5609        
    5610         bool is_nan(double value)
    5611         {
    5612         #if defined(_MSC_VER) || defined(__BORLANDC__)
     7992
     7993        PUGI__FN bool is_nan(double value)
     7994        {
     7995        #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
    56137996                return !!_isnan(value);
    56147997        #elif defined(fpclassify) && defined(FP_NAN)
     
    56208003        #endif
    56218004        }
    5622        
    5623         const char_t* convert_number_to_string_special(double value)
    5624         {
    5625         #if defined(_MSC_VER) || defined(__BORLANDC__)
     8005
     8006        PUGI__FN const char_t* convert_number_to_string_special(double value)
     8007        {
     8008        #if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
    56268009                if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0;
    56278010                if (_isnan(value)) return PUGIXML_TEXT("NaN");
    5628                 return PUGIXML_TEXT("-Infinity") + (value > 0);
     8011                return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
    56298012        #elif defined(fpclassify) && defined(FP_NAN) && defined(FP_INFINITE) && defined(FP_ZERO)
    56308013                switch (fpclassify(value))
     
    56348017
    56358018                case FP_INFINITE:
    5636                         return PUGIXML_TEXT("-Infinity") + (value > 0);
     8019                        return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
    56378020
    56388021                case FP_ZERO:
     
    56488031                if (v == 0) return PUGIXML_TEXT("0");
    56498032                if (v != v) return PUGIXML_TEXT("NaN");
    5650                 if (v * 2 == v) return PUGIXML_TEXT("-Infinity") + (value > 0);
     8033                if (v * 2 == v) return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
    56518034                return 0;
    56528035        #endif
    56538036        }
    5654        
    5655         bool convert_number_to_boolean(double value)
     8037
     8038        PUGI__FN bool convert_number_to_boolean(double value)
    56568039        {
    56578040                return (value != 0 && !is_nan(value));
    56588041        }
    5659        
    5660         void truncate_zeros(char* begin, char* end)
     8042
     8043        PUGI__FN void truncate_zeros(char* begin, char* end)
    56618044        {
    56628045                while (begin != end && end[-1] == '0') end--;
     
    56668049
    56678050        // gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
    5668 #if defined(_MSC_VER) && _MSC_VER >= 1400
    5669         void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
     8051#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400 && !defined(_WIN32_WCE)
     8052        PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
    56708053        {
    56718054                // get base values
     
    56818064        }
    56828065#else
    5683         void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
     8066        PUGI__FN void convert_number_to_mantissa_exponent(double value, char* buffer, size_t buffer_size, char** out_mantissa, int* out_exponent)
    56848067        {
    56858068                // get a scientific notation value with IEEE DBL_DIG decimals
     
    57128095#endif
    57138096
    5714         xpath_string convert_number_to_string(double value, xpath_allocator* alloc)
     8097        PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc)
    57158098        {
    57168099                // try special number conversion
    57178100                const char_t* special = convert_number_to_string_special(value);
    5718                 if (special) return xpath_string_const(special);
     8101                if (special) return xpath_string::from_const(special);
    57198102
    57208103                // get mantissa + exponent form
    5721                 char mantissa_buffer[64];
     8104                char mantissa_buffer[32];
    57228105
    57238106                char* mantissa;
     
    57258108                convert_number_to_mantissa_exponent(value, mantissa_buffer, sizeof(mantissa_buffer), &mantissa, &exponent);
    57268109
     8110                // allocate a buffer of suitable length for the number
     8111                size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
     8112                char_t* result = static_cast<char_t*>(alloc->allocate(sizeof(char_t) * result_size));
     8113                assert(result);
     8114
    57278115                // make the number!
    5728                 char_t result[512];
    57298116                char_t* s = result;
    57308117
     
    57418128                        while (exponent > 0)
    57428129                        {
    5743                                 assert(*mantissa == 0 || (unsigned)(*mantissa - '0') <= 9);
     8130                                assert(*mantissa == 0 || static_cast<unsigned int>(static_cast<unsigned int>(*mantissa) - '0') <= 9);
    57448131                                *s++ = *mantissa ? *mantissa++ : '0';
    57458132                                exponent--;
     
    57638150                        while (*mantissa)
    57648151                        {
    5765                                 assert((unsigned)(*mantissa - '0') <= 9);
     8152                                assert(static_cast<unsigned int>(*mantissa - '0') <= 9);
    57668153                                *s++ = *mantissa++;
    57678154                        }
     
    57698156
    57708157                // zero-terminate
    5771                 assert(s < result + sizeof(result) / sizeof(result[0]));
     8158                assert(s < result + result_size);
    57728159                *s = 0;
    57738160
    5774                 return xpath_string(result, alloc);
    5775         }
    5776        
    5777         bool check_string_to_number_format(const char_t* string)
     8161                return xpath_string::from_heap_preallocated(result, s);
     8162        }
     8163
     8164        PUGI__FN bool check_string_to_number_format(const char_t* string)
    57788165        {
    57798166                // parse leading whitespace
    5780                 while (IS_CHARTYPE(*string, ct_space)) ++string;
     8167                while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
    57818168
    57828169                // parse sign
     
    57868173
    57878174                // if there is no integer part, there should be a decimal part with at least one digit
    5788                 if (!IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !IS_CHARTYPEX(string[1], ctx_digit))) return false;
     8175                if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false;
    57898176
    57908177                // parse integer part
    5791                 while (IS_CHARTYPEX(*string, ctx_digit)) ++string;
     8178                while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
    57928179
    57938180                // parse decimal part
     
    57968183                        ++string;
    57978184
    5798                         while (IS_CHARTYPEX(*string, ctx_digit)) ++string;
     8185                        while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
    57998186                }
    58008187
    58018188                // parse trailing whitespace
    5802                 while (IS_CHARTYPE(*string, ct_space)) ++string;
     8189                while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
    58038190
    58048191                return *string == 0;
    58058192        }
    58068193
    5807         double convert_string_to_number(const char_t* string)
     8194        PUGI__FN double convert_string_to_number(const char_t* string)
    58088195        {
    58098196                // check string format
     
    58148201                return wcstod(string, 0);
    58158202        #else
    5816                 return atof(string);
     8203                return strtod(string, 0);
    58178204        #endif
    58188205        }
    58198206
    5820         bool convert_string_to_number(const char_t* begin, const char_t* end, double* out_result)
    5821         {
    5822                 char_t buffer[32];
    5823 
     8207        PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result)
     8208        {
    58248209                size_t length = static_cast<size_t>(end - begin);
    58258210                char_t* scratch = buffer;
     
    58288213                {
    58298214                        // need to make dummy on-heap copy
    5830                         scratch = static_cast<char_t*>(global_allocate((length + 1) * sizeof(char_t)));
     8215                        scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
    58318216                        if (!scratch) return false;
    58328217                }
     
    58398224
    58408225                // free dummy buffer
    5841                 if (scratch != buffer) global_deallocate(scratch);
     8226                if (scratch != buffer) xml_memory::deallocate(scratch);
    58428227
    58438228                return true;
    58448229        }
    5845        
    5846         double round_nearest(double value)
     8230
     8231        PUGI__FN double round_nearest(double value)
    58478232        {
    58488233                return floor(value + 0.5);
    58498234        }
    58508235
    5851         double round_nearest_nzero(double value)
     8236        PUGI__FN double round_nearest_nzero(double value)
    58528237        {
    58538238                // same as round_nearest, but returns -0 for [-0.5, -0]
     
    58558240                return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
    58568241        }
    5857        
    5858         const char_t* qualified_name(const xpath_node& node)
     8242
     8243        PUGI__FN const char_t* qualified_name(const xpath_node& node)
    58598244        {
    58608245                return node.attribute() ? node.attribute().name() : node.node().name();
    58618246        }
    5862        
    5863         const char_t* local_name(const xpath_node& node)
     8247
     8248        PUGI__FN const char_t* local_name(const xpath_node& node)
    58648249        {
    58658250                const char_t* name = qualified_name(node);
    58668251                const char_t* p = find_char(name, ':');
    5867                
     8252
    58688253                return p ? p + 1 : name;
    58698254        }
     
    58828267                }
    58838268
    5884                 bool operator()(const xml_attribute& a) const
     8269                bool operator()(xml_attribute a) const
    58858270                {
    58868271                        const char_t* name = a.name();
     
    58928277        };
    58938278
    5894         const char_t* namespace_uri(const xml_node& node)
     8279        PUGI__FN const char_t* namespace_uri(xml_node node)
    58958280        {
    58968281                namespace_uri_predicate pred = node.name();
    5897                
     8282
    58988283                xml_node p = node;
    5899                
     8284
    59008285                while (p)
    59018286                {
    59028287                        xml_attribute a = p.find_attribute(pred);
    5903                        
     8288
    59048289                        if (a) return a.value();
    5905                        
     8290
    59068291                        p = p.parent();
    59078292                }
    5908                
     8293
    59098294                return PUGIXML_TEXT("");
    59108295        }
    59118296
    5912         const char_t* namespace_uri(const xml_attribute& attr, const xml_node& parent)
     8297        PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent)
    59138298        {
    59148299                namespace_uri_predicate pred = attr.name();
    5915                
     8300
    59168301                // Default namespace does not apply to attributes
    59178302                if (!pred.prefix) return PUGIXML_TEXT("");
    5918                
     8303
    59198304                xml_node p = parent;
    5920                
     8305
    59218306                while (p)
    59228307                {
    59238308                        xml_attribute a = p.find_attribute(pred);
    5924                        
     8309
    59258310                        if (a) return a.value();
    5926                        
     8311
    59278312                        p = p.parent();
    59288313                }
    5929                
     8314
    59308315                return PUGIXML_TEXT("");
    59318316        }
    59328317
    5933         const char_t* namespace_uri(const xpath_node& node)
     8318        PUGI__FN const char_t* namespace_uri(const xpath_node& node)
    59348319        {
    59358320                return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
    59368321        }
    59378322
    5938         void normalize_space(char_t* buffer)
     8323        PUGI__FN char_t* normalize_space(char_t* buffer)
    59398324        {
    59408325                char_t* write = buffer;
     
    59448329                        char_t ch = *it++;
    59458330
    5946                         if (IS_CHARTYPE(ch, ct_space))
     8331                        if (PUGI__IS_CHARTYPE(ch, ct_space))
    59478332                        {
    59488333                                // replace whitespace sequence with single space
    5949                                 while (IS_CHARTYPE(*it, ct_space)) it++;
     8334                                while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
    59508335
    59518336                                // avoid leading spaces
     
    59568341
    59578342                // remove trailing space
    5958                 if (write != buffer && IS_CHARTYPE(write[-1], ct_space)) write--;
     8343                if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
    59598344
    59608345                // zero-terminate
    59618346                *write = 0;
    5962         }
    5963 
    5964         void translate(char_t* buffer, const char_t* from, const char_t* to)
    5965         {
    5966                 size_t to_length = strlength(to);
    5967 
     8347
     8348                return write;
     8349        }
     8350
     8351        PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)
     8352        {
    59688353                char_t* write = buffer;
    59698354
    59708355                while (*buffer)
    59718356                {
    5972                         DMC_VOLATILE char_t ch = *buffer++;
     8357                        PUGI__DMC_VOLATILE char_t ch = *buffer++;
    59738358
    59748359                        const char_t* pos = find_char(from, ch);
     
    59828367                // zero-terminate
    59838368                *write = 0;
     8369
     8370                return write;
     8371        }
     8372
     8373        PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to)
     8374        {
     8375                unsigned char table[128] = {0};
     8376
     8377                while (*from)
     8378                {
     8379                        unsigned int fc = static_cast<unsigned int>(*from);
     8380                        unsigned int tc = static_cast<unsigned int>(*to);
     8381
     8382                        if (fc >= 128 || tc >= 128)
     8383                                return 0;
     8384
     8385                        // code=128 means "skip character"
     8386                        if (!table[fc])
     8387                                table[fc] = static_cast<unsigned char>(tc ? tc : 128);
     8388
     8389                        from++;
     8390                        if (tc) to++;
     8391                }
     8392
     8393                for (int i = 0; i < 128; ++i)
     8394                        if (!table[i])
     8395                                table[i] = static_cast<unsigned char>(i);
     8396
     8397                void* result = alloc->allocate_nothrow(sizeof(table));
     8398
     8399                if (result)
     8400                {
     8401                        memcpy(result, table, sizeof(table));
     8402                }
     8403
     8404                return static_cast<unsigned char*>(result);
     8405        }
     8406
     8407        PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table)
     8408        {
     8409                char_t* write = buffer;
     8410
     8411                while (*buffer)
     8412                {
     8413                        char_t ch = *buffer++;
     8414                        unsigned int index = static_cast<unsigned int>(ch);
     8415
     8416                        if (index < 128)
     8417                        {
     8418                                unsigned char code = table[index];
     8419
     8420                                // code=128 means "skip character" (table size is 128 so 128 can be a special value)
     8421                                // this code skips these characters without extra branches
     8422                                *write = static_cast<char_t>(code);
     8423                                write += 1 - (code >> 7);
     8424                        }
     8425                        else
     8426                        {
     8427                                *write++ = ch;
     8428                        }
     8429                }
     8430
     8431                // zero-terminate
     8432                *write = 0;
     8433
     8434                return write;
     8435        }
     8436
     8437        inline bool is_xpath_attribute(const char_t* name)
     8438        {
     8439                return !(starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':'));
    59848440        }
    59858441
    59868442        struct xpath_variable_boolean: xpath_variable
    59878443        {
    5988                 xpath_variable_boolean(): value(false)
     8444                xpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false)
    59898445                {
    59908446                }
     
    59968452        struct xpath_variable_number: xpath_variable
    59978453        {
    5998                 xpath_variable_number(): value(0)
     8454                xpath_variable_number(): xpath_variable(xpath_type_number), value(0)
    59998455                {
    60008456                }
     
    60068462        struct xpath_variable_string: xpath_variable
    60078463        {
    6008                 xpath_variable_string(): value(0)
     8464                xpath_variable_string(): xpath_variable(xpath_type_string), value(0)
    60098465                {
    60108466                }
     
    60128468                ~xpath_variable_string()
    60138469                {
    6014                         if (value) global_deallocate(value);
     8470                        if (value) xml_memory::deallocate(value);
    60158471                }
    60168472
     
    60218477        struct xpath_variable_node_set: xpath_variable
    60228478        {
     8479                xpath_variable_node_set(): xpath_variable(xpath_type_node_set)
     8480                {
     8481                }
     8482
    60238483                xpath_node_set value;
    60248484                char_t name[1];
    60258485        };
    60268486
    6027         const xpath_node_set dummy_node_set;
    6028 
    6029         unsigned int hash_string(const char_t* str)
     8487        static const xpath_node_set dummy_node_set;
     8488
     8489        PUGI__FN unsigned int hash_string(const char_t* str)
    60308490        {
    60318491                // Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
     
    60388498                        result ^= result >> 6;
    60398499                }
    6040        
     8500
    60418501                result += result << 3;
    60428502                result ^= result >> 11;
    60438503                result += result << 15;
    6044        
     8504
    60458505                return result;
    60468506        }
    60478507
    6048         template <typename T> T* new_xpath_variable(const char_t* name)
     8508        template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name)
    60498509        {
    60508510                size_t length = strlength(name);
     
    60528512
    60538513                // $$ we can't use offsetof(T, name) because T is non-POD, so we just allocate additional length characters
    6054                 void* memory = global_allocate(sizeof(T) + length * sizeof(char_t));
     8514                void* memory = xml_memory::allocate(sizeof(T) + length * sizeof(char_t));
    60558515                if (!memory) return 0;
    60568516
     
    60628522        }
    60638523
    6064         xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
     8524        PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
    60658525        {
    60668526                switch (type)
     
    60838543        }
    60848544
    6085         template <typename T> void delete_xpath_variable(T* var)
     8545        template <typename T> PUGI__FN void delete_xpath_variable(T* var)
    60868546        {
    60878547                var->~T();
    6088                 global_deallocate(var);
    6089         }
    6090 
    6091         void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
     8548                xml_memory::deallocate(var);
     8549        }
     8550
     8551        PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
    60928552        {
    60938553                switch (type)
     
    61108570
    61118571                default:
    6112                         assert(!"Invalid variable type");
    6113                 }
    6114         }
    6115 
    6116         xpath_variable* get_variable(xpath_variable_set* set, const char_t* begin, const char_t* end)
    6117         {
    6118                 char_t buffer[32];
    6119 
     8572                        assert(false && "Invalid variable type");
     8573                }
     8574        }
     8575
     8576        PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs)
     8577        {
     8578                switch (rhs->type())
     8579                {
     8580                case xpath_type_node_set:
     8581                        return lhs->set(static_cast<const xpath_variable_node_set*>(rhs)->value);
     8582
     8583                case xpath_type_number:
     8584                        return lhs->set(static_cast<const xpath_variable_number*>(rhs)->value);
     8585
     8586                case xpath_type_string:
     8587                        return lhs->set(static_cast<const xpath_variable_string*>(rhs)->value);
     8588
     8589                case xpath_type_boolean:
     8590                        return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value);
     8591
     8592                default:
     8593                        assert(false && "Invalid variable type");
     8594                        return false;
     8595                }
     8596        }
     8597
     8598        PUGI__FN bool get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end, xpath_variable** out_result)
     8599        {
    61208600                size_t length = static_cast<size_t>(end - begin);
    61218601                char_t* scratch = buffer;
     
    61248604                {
    61258605                        // need to make dummy on-heap copy
    6126                         scratch = static_cast<char_t*>(global_allocate((length + 1) * sizeof(char_t)));
    6127                         if (!scratch) return 0;
     8606                        scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
     8607                        if (!scratch) return false;
    61288608                }
    61298609
     
    61328612                scratch[length] = 0;
    61338613
    6134                 xpath_variable* result = set->get(scratch);
     8614                *out_result = set->get(scratch);
    61358615
    61368616                // free dummy buffer
    6137                 if (scratch != buffer) global_deallocate(scratch);
    6138 
    6139                 return result;
    6140         }
    6141 }
     8617                if (scratch != buffer) xml_memory::deallocate(scratch);
     8618
     8619                return true;
     8620        }
     8621PUGI__NS_END
    61428622
    61438623// Internal node set class
    6144 namespace
    6145 {
    6146         xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
     8624PUGI__NS_BEGIN
     8625        PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end)
     8626        {
     8627                if (end - begin < 2)
     8628                        return xpath_node_set::type_sorted;
     8629
     8630                document_order_comparator cmp;
     8631
     8632                bool first = cmp(begin[0], begin[1]);
     8633
     8634                for (const xpath_node* it = begin + 1; it + 1 < end; ++it)
     8635                        if (cmp(it[0], it[1]) != first)
     8636                                return xpath_node_set::type_unsorted;
     8637
     8638                return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse;
     8639        }
     8640
     8641        PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
    61478642        {
    61488643                xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
     
    61508645                if (type == xpath_node_set::type_unsorted)
    61518646                {
    6152                         sort(begin, end, document_order_comparator());
    6153 
    6154                         type = xpath_node_set::type_sorted;
    6155                 }
    6156                
     8647                        xpath_node_set::type_t sorted = xpath_get_order(begin, end);
     8648
     8649                        if (sorted == xpath_node_set::type_unsorted)
     8650                        {
     8651                                sort(begin, end, document_order_comparator());
     8652
     8653                                type = xpath_node_set::type_sorted;
     8654                        }
     8655                        else
     8656                                type = sorted;
     8657                }
     8658
    61578659                if (type != order) reverse(begin, end);
    6158                        
     8660
    61598661                return order;
    61608662        }
    61618663
    6162         xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
     8664        PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
    61638665        {
    61648666                if (begin == end) return xpath_node();
     
    61768678
    61778679                default:
    6178                         assert(!"Invalid node set type");
     8680                        assert(false && "Invalid node set type");
    61798681                        return xpath_node();
    61808682                }
    61818683        }
     8684
    61828685        class xpath_node_set_raw
    61838686        {
     
    62188721                }
    62198722
     8723                void push_back_grow(const xpath_node& node, xpath_allocator* alloc);
     8724
    62208725                void push_back(const xpath_node& node, xpath_allocator* alloc)
    62218726                {
    6222                         if (_end == _eos)
    6223                         {
    6224                                 size_t capacity = static_cast<size_t>(_eos - _begin);
    6225 
    6226                                 // get new capacity (1.5x rule)
    6227                                 size_t new_capacity = capacity + capacity / 2 + 1;
    6228 
     8727                        if (_end != _eos)
     8728                                *_end++ = node;
     8729                        else
     8730                                push_back_grow(node, alloc);
     8731                }
     8732
     8733                void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)
     8734                {
     8735                        if (begin_ == end_) return;
     8736
     8737                        size_t size_ = static_cast<size_t>(_end - _begin);
     8738                        size_t capacity = static_cast<size_t>(_eos - _begin);
     8739                        size_t count = static_cast<size_t>(end_ - begin_);
     8740
     8741                        if (size_ + count > capacity)
     8742                        {
    62298743                                // reallocate the old array or allocate a new one
    6230                                 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
     8744                                xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
    62318745                                assert(data);
    62328746
    62338747                                // finalize
    62348748                                _begin = data;
    6235                                 _end = data + capacity;
    6236                                 _eos = data + new_capacity;
    6237                         }
    6238 
    6239                         *_end++ = node;
    6240                 }
    6241 
    6242                 void append(const xpath_node* begin, const xpath_node* end, xpath_allocator* alloc)
    6243                 {
    6244                         size_t size = static_cast<size_t>(_end - _begin);
    6245                         size_t capacity = static_cast<size_t>(_eos - _begin);
    6246                         size_t count = static_cast<size_t>(end - begin);
    6247 
    6248                         if (size + count > capacity)
    6249                         {
    6250                                 // reallocate the old array or allocate a new one
    6251                                 xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size + count) * sizeof(xpath_node)));
    6252                                 assert(data);
    6253 
    6254                                 // finalize
    6255                                 _begin = data;
    6256                                 _end = data + size;
    6257                                 _eos = data + size + count;
    6258                         }
    6259 
    6260                         memcpy(_end, begin, count * sizeof(xpath_node));
     8749                                _end = data + size_;
     8750                                _eos = data + size_ + count;
     8751                        }
     8752
     8753                        memcpy(_end, begin_, count * sizeof(xpath_node));
    62618754                        _end += count;
    62628755                }
     
    62788771                        if (_type == xpath_node_set::type_unsorted)
    62798772                                sort(_begin, _end, duplicate_comparator());
    6280                
     8773
    62818774                        _end = unique(_begin, _end);
    62828775                }
     
    62878780                }
    62888781
    6289                 void set_type(xpath_node_set::type_t type)
    6290                 {
    6291                         _type = type;
     8782                void set_type(xpath_node_set::type_t value)
     8783                {
     8784                        _type = value;
    62928785                }
    62938786        };
    6294 }
    6295 
    6296 namespace
    6297 {
     8787
     8788        PUGI__FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc)
     8789        {
     8790                size_t capacity = static_cast<size_t>(_eos - _begin);
     8791
     8792                // get new capacity (1.5x rule)
     8793                size_t new_capacity = capacity + capacity / 2 + 1;
     8794
     8795                // reallocate the old array or allocate a new one
     8796                xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
     8797                assert(data);
     8798
     8799                // finalize
     8800                _begin = data;
     8801                _end = data + capacity;
     8802                _eos = data + new_capacity;
     8803
     8804                // push
     8805                *_end++ = node;
     8806        }
     8807PUGI__NS_END
     8808
     8809PUGI__NS_BEGIN
    62988810        struct xpath_context
    62998811        {
     
    63018813                size_t position, size;
    63028814
    6303                 xpath_context(const xpath_node& n, size_t position, size_t size): n(n), position(position), size(size)
     8815                xpath_context(const xpath_node& n_, size_t position_, size_t size_): n(n_), position(position_), size(size_)
    63048816                {
    63058817                }
     
    63678879                        next();
    63688880                }
    6369                
     8881
    63708882                const char_t* state() const
    63718883                {
    63728884                        return _cur;
    63738885                }
    6374                
     8886
    63758887                void next()
    63768888                {
    63778889                        const char_t* cur = _cur;
    63788890
    6379                         while (IS_CHARTYPE(*cur, ct_space)) ++cur;
     8891                        while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
    63808892
    63818893                        // save lexeme position for error reporting
     
    63878899                                _cur_lexeme = lex_eof;
    63888900                                break;
    6389                        
     8901
    63908902                        case '>':
    63918903                                if (*(cur+1) == '=')
     
    64318943
    64328944                                break;
    6433                        
     8945
    64348946                        case '+':
    64358947                                cur += 1;
     
    64558967
    64568968                                break;
    6457                        
     8969
    64588970                        case '$':
    64598971                                cur += 1;
    64608972
    6461                                 if (IS_CHARTYPEX(*cur, ctx_start_symbol))
     8973                                if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
    64628974                                {
    64638975                                        _cur_lexeme_contents.begin = cur;
    64648976
    6465                                         while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
    6466 
    6467                                         if (cur[0] == ':' && IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
     8977                                        while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
     8978
     8979                                        if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
    64688980                                        {
    64698981                                                cur++; // :
    64708982
    6471                                                 while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
     8983                                                while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
    64728984                                        }
    64738985
    64748986                                        _cur_lexeme_contents.end = cur;
    6475                                
     8987
    64768988                                        _cur_lexeme = lex_var_ref;
    64778989                                }
     
    64949006
    64959007                                break;
    6496                        
     9008
    64979009                        case '[':
    64989010                                cur += 1;
     
    65259037                                }
    65269038                                break;
    6527                
     9039
    65289040                        case '.':
    65299041                                if (*(cur+1) == '.')
     
    65329044                                        _cur_lexeme = lex_double_dot;
    65339045                                }
    6534                                 else if (IS_CHARTYPEX(*(cur+1), ctx_digit))
     9046                                else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
    65359047                                {
    65369048                                        _cur_lexeme_contents.begin = cur; // .
     
    65389050                                        ++cur;
    65399051
    6540                                         while (IS_CHARTYPEX(*cur, ctx_digit)) cur++;
     9052                                        while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
    65419053
    65429054                                        _cur_lexeme_contents.end = cur;
    6543                                        
     9055
    65449056                                        _cur_lexeme = lex_number;
    65459057                                }
     
    65679079                                while (*cur && *cur != terminator) cur++;
    65689080                                _cur_lexeme_contents.end = cur;
    6569                                
     9081
    65709082                                if (!*cur)
    65719083                                        _cur_lexeme = lex_none;
     
    65929104
    65939105                        default:
    6594                                 if (IS_CHARTYPEX(*cur, ctx_digit))
     9106                                if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
    65959107                                {
    65969108                                        _cur_lexeme_contents.begin = cur;
    65979109
    6598                                         while (IS_CHARTYPEX(*cur, ctx_digit)) cur++;
    6599                                
     9110                                        while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
     9111
    66009112                                        if (*cur == '.')
    66019113                                        {
    66029114                                                cur++;
    66039115
    6604                                                 while (IS_CHARTYPEX(*cur, ctx_digit)) cur++;
     9116                                                while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
    66059117                                        }
    66069118
     
    66099121                                        _cur_lexeme = lex_number;
    66109122                                }
    6611                                 else if (IS_CHARTYPEX(*cur, ctx_start_symbol))
     9123                                else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
    66129124                                {
    66139125                                        _cur_lexeme_contents.begin = cur;
    66149126
    6615                                         while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
     9127                                        while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
    66169128
    66179129                                        if (cur[0] == ':')
     
    66219133                                                        cur += 2; // :*
    66229134                                                }
    6623                                                 else if (IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
     9135                                                else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
    66249136                                                {
    66259137                                                        cur++; // :
    66269138
    6627                                                         while (IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
     9139                                                        while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
    66289140                                                }
    66299141                                        }
    66309142
    66319143                                        _cur_lexeme_contents.end = cur;
    6632                                
     9144
    66339145                                        _cur_lexeme = lex_string;
    66349146                                }
     
    66629174        enum ast_type_t
    66639175        {
     9176                ast_unknown,
    66649177                ast_op_or,                                              // left or right
    66659178                ast_op_and,                                             // left and right
    66669179                ast_op_equal,                                   // left = right
    6667                 ast_op_not_equal,                               // left != right
     9180                ast_op_not_equal,                               // left != right
    66689181                ast_op_less,                                    // left < right
    66699182                ast_op_greater,                                 // left > right
     
    66799192                ast_predicate,                                  // apply predicate to set; next points to next predicate
    66809193                ast_filter,                                             // select * from left where right
    6681                 ast_filter_posinv,                              // select * from left where right; proximity position invariant
    66829194                ast_string_constant,                    // string constant
    66839195                ast_number_constant,                    // number constant
     
    67199231                ast_func_round,                                 // round(left)
    67209232                ast_step,                                               // process set left with step
    6721                 ast_step_root                                   // select root node
     9233                ast_step_root,                                  // select root node
     9234
     9235                ast_opt_translate_table,                // translate(left, right, third) where right/third are constants
     9236                ast_opt_compare_attribute               // @name = 'string'
    67229237        };
    67239238
     
    67389253                axis_self
    67399254        };
    6740        
     9255
    67419256        enum nodetest_t
    67429257        {
     
    67529267        };
    67539268
     9269        enum predicate_t
     9270        {
     9271                predicate_default,
     9272                predicate_posinv,
     9273                predicate_constant,
     9274                predicate_constant_one
     9275        };
     9276
     9277        enum nodeset_eval_t
     9278        {
     9279                nodeset_eval_all,
     9280                nodeset_eval_any,
     9281                nodeset_eval_first
     9282        };
     9283
    67549284        template <axis_t N> struct axis_to_type
    67559285        {
     
    67589288
    67599289        template <axis_t N> const axis_t axis_to_type<N>::axis = N;
    6760                
     9290
    67619291        class xpath_ast_node
    67629292        {
     
    67669296                char _rettype;
    67679297
    6768                 // for ast_step / ast_predicate
     9298                // for ast_step
    67699299                char _axis;
     9300
     9301                // for ast_step/ast_predicate/ast_filter
    67709302                char _test;
    67719303
     
    67859317                        // node test for ast_step (node name/namespace/node type/pi target)
    67869318                        const char_t* nodetest;
     9319                        // table for ast_opt_translate_table
     9320                        const unsigned char* table;
    67879321                } _data;
    67889322
     
    68149348                                xpath_allocator_capture cr(stack.result);
    68159349
    6816                                 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
    6817                                 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
     9350                                xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
     9351                                xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
    68189352
    68199353                                for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
     
    68439377
    68449378                                        double l = lhs->eval_number(c, stack);
    6845                                         xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
     9379                                        xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
    68469380
    68479381                                        for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
     
    68609394
    68619395                                        xpath_string l = lhs->eval_string(c, stack);
    6862                                         xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
     9396                                        xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
    68639397
    68649398                                        for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
     
    68749408                        }
    68759409
    6876                         assert(!"Wrong types");
     9410                        assert(false && "Wrong types");
    68779411                        return false;
     9412                }
     9413
     9414                static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval)
     9415                {
     9416                        return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any;
    68789417                }
    68799418
     
    68889427                                xpath_allocator_capture cr(stack.result);
    68899428
    6890                                 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
    6891                                 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
     9429                                xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
     9430                                xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
    68929431
    68939432                                for (const xpath_node* li = ls.begin(); li != ls.end(); ++li)
     
    69139452
    69149453                                double l = lhs->eval_number(c, stack);
    6915                                 xpath_node_set_raw rs = rhs->eval_node_set(c, stack);
     9454                                xpath_node_set_raw rs = rhs->eval_node_set(c, stack, nodeset_eval_all);
    69169455
    69179456                                for (const xpath_node* ri = rs.begin(); ri != rs.end(); ++ri)
     
    69299468                                xpath_allocator_capture cr(stack.result);
    69309469
    6931                                 xpath_node_set_raw ls = lhs->eval_node_set(c, stack);
     9470                                xpath_node_set_raw ls = lhs->eval_node_set(c, stack, nodeset_eval_all);
    69329471                                double r = rhs->eval_number(c, stack);
    69339472
     
    69449483                        else
    69459484                        {
    6946                                 assert(!"Wrong types");
     9485                                assert(false && "Wrong types");
    69479486                                return false;
    69489487                        }
    69499488                }
    69509489
    6951                 void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)
     9490                static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)
    69529491                {
    69539492                        assert(ns.size() >= first);
     9493                        assert(expr->rettype() != xpath_type_number);
    69549494
    69559495                        size_t i = 1;
    69569496                        size_t size = ns.size() - first;
    6957                                
     9497
    69589498                        xpath_node* last = ns.begin() + first;
    6959                                
     9499
    69609500                        // remove_if... or well, sort of
    69619501                        for (xpath_node* it = last; it != ns.end(); ++it, ++i)
    69629502                        {
    69639503                                xpath_context c(*it, i, size);
    6964                        
    6965                                 if (expr->rettype() == xpath_type_number)
    6966                                 {
    6967                                         if (expr->eval_number(c, stack) == i)
    6968                                                 *last++ = *it;
    6969                                 }
    6970                                 else if (expr->eval_boolean(c, stack))
     9504
     9505                                if (expr->eval_boolean(c, stack))
     9506                                {
    69719507                                        *last++ = *it;
    6972                         }
    6973                        
     9508
     9509                                        if (once) break;
     9510                                }
     9511                        }
     9512
    69749513                        ns.truncate(last);
    69759514                }
    69769515
    6977                 void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack)
     9516                static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)
     9517                {
     9518                        assert(ns.size() >= first);
     9519                        assert(expr->rettype() == xpath_type_number);
     9520
     9521                        size_t i = 1;
     9522                        size_t size = ns.size() - first;
     9523
     9524                        xpath_node* last = ns.begin() + first;
     9525
     9526                        // remove_if... or well, sort of
     9527                        for (xpath_node* it = last; it != ns.end(); ++it, ++i)
     9528                        {
     9529                                xpath_context c(*it, i, size);
     9530
     9531                                if (expr->eval_number(c, stack) == i)
     9532                                {
     9533                                        *last++ = *it;
     9534
     9535                                        if (once) break;
     9536                                }
     9537                        }
     9538
     9539                        ns.truncate(last);
     9540                }
     9541
     9542                static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)
     9543                {
     9544                        assert(ns.size() >= first);
     9545                        assert(expr->rettype() == xpath_type_number);
     9546
     9547                        size_t size = ns.size() - first;
     9548
     9549                        xpath_node* last = ns.begin() + first;
     9550
     9551                        xpath_context c(xpath_node(), 1, size);
     9552
     9553                        double er = expr->eval_number(c, stack);
     9554
     9555                        if (er >= 1.0 && er <= size)
     9556                        {
     9557                                size_t eri = static_cast<size_t>(er);
     9558
     9559                                if (er == eri)
     9560                                {
     9561                                        xpath_node r = last[eri - 1];
     9562
     9563                                        *last++ = r;
     9564                                }
     9565                        }
     9566
     9567                        ns.truncate(last);
     9568                }
     9569
     9570                void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once)
    69789571                {
    69799572                        if (ns.size() == first) return;
    6980                        
     9573
     9574                        assert(_type == ast_filter || _type == ast_predicate);
     9575
     9576                        if (_test == predicate_constant || _test == predicate_constant_one)
     9577                                apply_predicate_number_const(ns, first, _right, stack);
     9578                        else if (_right->rettype() == xpath_type_number)
     9579                                apply_predicate_number(ns, first, _right, stack, once);
     9580                        else
     9581                                apply_predicate_boolean(ns, first, _right, stack, once);
     9582                }
     9583
     9584                void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval)
     9585                {
     9586                        if (ns.size() == first) return;
     9587
     9588                        bool last_once = eval_once(ns.type(), eval);
     9589
    69819590                        for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
    6982                         {
    6983                                 apply_predicate(ns, first, pred->_left, stack);
    6984                         }
    6985                 }
    6986 
    6987                 void step_push(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& parent, xpath_allocator* alloc)
    6988                 {
    6989                         if (!a) return;
    6990 
    6991                         const char_t* name = a.name();
    6992 
    6993                         // There are no attribute nodes corresponding to attributes that declare namespaces
    6994                         // That is, "xmlns:..." or "xmlns"
    6995                         if (starts_with(name, PUGIXML_TEXT("xmlns")) && (name[5] == 0 || name[5] == ':')) return;
    6996                        
     9591                                pred->apply_predicate(ns, first, stack, !pred->_next && last_once);
     9592                }
     9593
     9594                bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc)
     9595                {
     9596                        assert(a);
     9597
     9598                        const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT("");
     9599
    69979600                        switch (_test)
    69989601                        {
    69999602                        case nodetest_name:
    7000                                 if (strequal(name, _data.nodetest)) ns.push_back(xpath_node(a, parent), alloc);
     9603                                if (strequal(name, _data.nodetest) && is_xpath_attribute(name))
     9604                                {
     9605                                        ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
     9606                                        return true;
     9607                                }
    70019608                                break;
    7002                                
     9609
    70039610                        case nodetest_type_node:
    70049611                        case nodetest_all:
    7005                                 ns.push_back(xpath_node(a, parent), alloc);
     9612                                if (is_xpath_attribute(name))
     9613                                {
     9614                                        ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
     9615                                        return true;
     9616                                }
    70069617                                break;
    7007                                
     9618
    70089619                        case nodetest_all_in_namespace:
    7009                                 if (starts_with(name, _data.nodetest))
    7010                                         ns.push_back(xpath_node(a, parent), alloc);
     9620                                if (starts_with(name, _data.nodetest) && is_xpath_attribute(name))
     9621                                {
     9622                                        ns.push_back(xpath_node(xml_attribute(a), xml_node(parent)), alloc);
     9623                                        return true;
     9624                                }
    70119625                                break;
    7012                        
     9626
    70139627                        default:
    70149628                                ;
    70159629                        }
    7016                 }
    7017                
    7018                 void step_push(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc)
    7019                 {
    7020                         if (!n) return;
     9630
     9631                        return false;
     9632                }
     9633
     9634                bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc)
     9635                {
     9636                        assert(n);
     9637
     9638                        xml_node_type type = PUGI__NODETYPE(n);
    70219639
    70229640                        switch (_test)
    70239641                        {
    70249642                        case nodetest_name:
    7025                                 if (n.type() == node_element && strequal(n.name(), _data.nodetest)) ns.push_back(n, alloc);
     9643                                if (type == node_element && n->name && strequal(n->name, _data.nodetest))
     9644                                {
     9645                                        ns.push_back(xml_node(n), alloc);
     9646                                        return true;
     9647                                }
    70269648                                break;
    7027                                
     9649
    70289650                        case nodetest_type_node:
    7029                                 ns.push_back(n, alloc);
     9651                                ns.push_back(xml_node(n), alloc);
     9652                                return true;
     9653
     9654                        case nodetest_type_comment:
     9655                                if (type == node_comment)
     9656                                {
     9657                                        ns.push_back(xml_node(n), alloc);
     9658                                        return true;
     9659                                }
    70309660                                break;
    7031                                
    7032                         case nodetest_type_comment:
    7033                                 if (n.type() == node_comment)
    7034                                         ns.push_back(n, alloc);
     9661
     9662                        case nodetest_type_text:
     9663                                if (type == node_pcdata || type == node_cdata)
     9664                                {
     9665                                        ns.push_back(xml_node(n), alloc);
     9666                                        return true;
     9667                                }
    70359668                                break;
    7036                                
    7037                         case nodetest_type_text:
    7038                                 if (n.type() == node_pcdata || n.type() == node_cdata)
    7039                                         ns.push_back(n, alloc);
     9669
     9670                        case nodetest_type_pi:
     9671                                if (type == node_pi)
     9672                                {
     9673                                        ns.push_back(xml_node(n), alloc);
     9674                                        return true;
     9675                                }
    70409676                                break;
    7041                                
    7042                         case nodetest_type_pi:
    7043                                 if (n.type() == node_pi)
    7044                                         ns.push_back(n, alloc);
     9677
     9678                        case nodetest_pi:
     9679                                if (type == node_pi && n->name && strequal(n->name, _data.nodetest))
     9680                                {
     9681                                        ns.push_back(xml_node(n), alloc);
     9682                                        return true;
     9683                                }
    70459684                                break;
    7046                                                                        
    7047                         case nodetest_pi:
    7048                                 if (n.type() == node_pi && strequal(n.name(), _data.nodetest))
    7049                                         ns.push_back(n, alloc);
     9685
     9686                        case nodetest_all:
     9687                                if (type == node_element)
     9688                                {
     9689                                        ns.push_back(xml_node(n), alloc);
     9690                                        return true;
     9691                                }
    70509692                                break;
    7051                                
    7052                         case nodetest_all:
    7053                                 if (n.type() == node_element)
    7054                                         ns.push_back(n, alloc);
     9693
     9694                        case nodetest_all_in_namespace:
     9695                                if (type == node_element && n->name && starts_with(n->name, _data.nodetest))
     9696                                {
     9697                                        ns.push_back(xml_node(n), alloc);
     9698                                        return true;
     9699                                }
    70559700                                break;
    7056                                
    7057                         case nodetest_all_in_namespace:
    7058                                 if (n.type() == node_element && starts_with(n.name(), _data.nodetest))
    7059                                         ns.push_back(n, alloc);
     9701
     9702                        default:
     9703                                assert(false && "Unknown axis");
     9704                        }
     9705
     9706                        return false;
     9707                }
     9708
     9709                template <class T> void step_fill(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc, bool once, T)
     9710                {
     9711                        const axis_t axis = T::axis;
     9712
     9713                        switch (axis)
     9714                        {
     9715                        case axis_attribute:
     9716                        {
     9717                                for (xml_attribute_struct* a = n->first_attribute; a; a = a->next_attribute)
     9718                                        if (step_push(ns, a, n, alloc) & once)
     9719                                                return;
     9720
    70609721                                break;
    7061 
    7062                         default:
    7063                                 assert(!"Unknown axis");
    7064                         }
    7065                 }
    7066 
    7067                 template <class T> void step_fill(xpath_node_set_raw& ns, const xml_node& n, xpath_allocator* alloc, T)
    7068                 {
    7069                         const axis_t axis = T::axis;
    7070 
    7071                         switch (axis)
    7072                         {
    7073                         case axis_attribute:
    7074                         {
    7075                                 for (xml_attribute a = n.first_attribute(); a; a = a.next_attribute())
    7076                                         step_push(ns, a, n, alloc);
    7077                                
     9722                        }
     9723
     9724                        case axis_child:
     9725                        {
     9726                                for (xml_node_struct* c = n->first_child; c; c = c->next_sibling)
     9727                                        if (step_push(ns, c, alloc) & once)
     9728                                                return;
     9729
    70789730                                break;
    70799731                        }
    7080                        
    7081                         case axis_child:
    7082                         {
    7083                                 for (xml_node c = n.first_child(); c; c = c.next_sibling())
    7084                                         step_push(ns, c, alloc);
    7085                                        
    7086                                 break;
    7087                         }
    7088                        
     9732
    70899733                        case axis_descendant:
    70909734                        case axis_descendant_or_self:
    70919735                        {
    70929736                                if (axis == axis_descendant_or_self)
    7093                                         step_push(ns, n, alloc);
    7094                                        
    7095                                 xml_node cur = n.first_child();
    7096                                
    7097                                 while (cur && cur != n)
    7098                                 {
    7099                                         step_push(ns, cur, alloc);
    7100                                        
    7101                                         if (cur.first_child())
    7102                                                 cur = cur.first_child();
    7103                                         else if (cur.next_sibling())
    7104                                                 cur = cur.next_sibling();
     9737                                        if (step_push(ns, n, alloc) & once)
     9738                                                return;
     9739
     9740                                xml_node_struct* cur = n->first_child;
     9741
     9742                                while (cur)
     9743                                {
     9744                                        if (step_push(ns, cur, alloc) & once)
     9745                                                return;
     9746
     9747                                        if (cur->first_child)
     9748                                                cur = cur->first_child;
    71059749                                        else
    71069750                                        {
    7107                                                 while (!cur.next_sibling() && cur != n)
    7108                                                         cur = cur.parent();
    7109                                        
    7110                                                 if (cur != n) cur = cur.next_sibling();
     9751                                                while (!cur->next_sibling)
     9752                                                {
     9753                                                        cur = cur->parent;
     9754
     9755                                                        if (cur == n) return;
     9756                                                }
     9757
     9758                                                cur = cur->next_sibling;
    71119759                                        }
    71129760                                }
    7113                                
     9761
    71149762                                break;
    71159763                        }
    7116                        
     9764
    71179765                        case axis_following_sibling:
    71189766                        {
    7119                                 for (xml_node c = n.next_sibling(); c; c = c.next_sibling())
    7120                                         step_push(ns, c, alloc);
    7121                                
     9767                                for (xml_node_struct* c = n->next_sibling; c; c = c->next_sibling)
     9768                                        if (step_push(ns, c, alloc) & once)
     9769                                                return;
     9770
    71229771                                break;
    71239772                        }
    7124                        
     9773
    71259774                        case axis_preceding_sibling:
    71269775                        {
    7127                                 for (xml_node c = n.previous_sibling(); c; c = c.previous_sibling())
    7128                                         step_push(ns, c, alloc);
    7129                                
     9776                                for (xml_node_struct* c = n->prev_sibling_c; c->next_sibling; c = c->prev_sibling_c)
     9777                                        if (step_push(ns, c, alloc) & once)
     9778                                                return;
     9779
    71309780                                break;
    71319781                        }
    7132                        
     9782
    71339783                        case axis_following:
    71349784                        {
    7135                                 xml_node cur = n;
     9785                                xml_node_struct* cur = n;
    71369786
    71379787                                // exit from this node so that we don't include descendants
    7138                                 while (cur && !cur.next_sibling()) cur = cur.parent();
    7139                                 cur = cur.next_sibling();
    7140 
    7141                                 for (;;)
    7142                                 {
    7143                                         step_push(ns, cur, alloc);
    7144 
    7145                                         if (cur.first_child())
    7146                                                 cur = cur.first_child();
    7147                                         else if (cur.next_sibling())
    7148                                                 cur = cur.next_sibling();
     9788                                while (!cur->next_sibling)
     9789                                {
     9790                                        cur = cur->parent;
     9791
     9792                                        if (!cur) return;
     9793                                }
     9794
     9795                                cur = cur->next_sibling;
     9796
     9797                                while (cur)
     9798                                {
     9799                                        if (step_push(ns, cur, alloc) & once)
     9800                                                return;
     9801
     9802                                        if (cur->first_child)
     9803                                                cur = cur->first_child;
    71499804                                        else
    71509805                                        {
    7151                                                 while (cur && !cur.next_sibling()) cur = cur.parent();
    7152                                                 cur = cur.next_sibling();
    7153 
    7154                                                 if (!cur) break;
     9806                                                while (!cur->next_sibling)
     9807                                                {
     9808                                                        cur = cur->parent;
     9809
     9810                                                        if (!cur) return;
     9811                                                }
     9812
     9813                                                cur = cur->next_sibling;
    71559814                                        }
    71569815                                }
     
    71619820                        case axis_preceding:
    71629821                        {
    7163                                 xml_node cur = n;
    7164 
    7165                                 while (cur && !cur.previous_sibling()) cur = cur.parent();
    7166                                 cur = cur.previous_sibling();
    7167 
    7168                                 for (;;)
    7169                                 {
    7170                                         if (cur.last_child())
    7171                                                 cur = cur.last_child();
     9822                                xml_node_struct* cur = n;
     9823
     9824                                // exit from this node so that we don't include descendants
     9825                                while (!cur->prev_sibling_c->next_sibling)
     9826                                {
     9827                                        cur = cur->parent;
     9828
     9829                                        if (!cur) return;
     9830                                }
     9831
     9832                                cur = cur->prev_sibling_c;
     9833
     9834                                while (cur)
     9835                                {
     9836                                        if (cur->first_child)
     9837                                                cur = cur->first_child->prev_sibling_c;
    71729838                                        else
    71739839                                        {
    71749840                                                // leaf node, can't be ancestor
    7175                                                 step_push(ns, cur, alloc);
    7176 
    7177                                                 if (cur.previous_sibling())
    7178                                                         cur = cur.previous_sibling();
    7179                                                 else
     9841                                                if (step_push(ns, cur, alloc) & once)
     9842                                                        return;
     9843
     9844                                                while (!cur->prev_sibling_c->next_sibling)
    71809845                                                {
    7181                                                         do
    7182                                                         {
    7183                                                                 cur = cur.parent();
    7184                                                                 if (!cur) break;
    7185 
    7186                                                                 if (!node_is_ancestor(cur, n)) step_push(ns, cur, alloc);
    7187                                                         }
    7188                                                         while (!cur.previous_sibling());
    7189 
    7190                                                         cur = cur.previous_sibling();
    7191 
    7192                                                         if (!cur) break;
     9846                                                        cur = cur->parent;
     9847
     9848                                                        if (!cur) return;
     9849
     9850                                                        if (!node_is_ancestor(cur, n))
     9851                                                                if (step_push(ns, cur, alloc) & once)
     9852                                                                        return;
    71939853                                                }
     9854
     9855                                                cur = cur->prev_sibling_c;
    71949856                                        }
    71959857                                }
     
    71979859                                break;
    71989860                        }
    7199                        
     9861
    72009862                        case axis_ancestor:
    72019863                        case axis_ancestor_or_self:
    72029864                        {
    72039865                                if (axis == axis_ancestor_or_self)
    7204                                         step_push(ns, n, alloc);
    7205 
    7206                                 xml_node cur = n.parent();
    7207                                
     9866                                        if (step_push(ns, n, alloc) & once)
     9867                                                return;
     9868
     9869                                xml_node_struct* cur = n->parent;
     9870
    72089871                                while (cur)
    72099872                                {
    7210                                         step_push(ns, cur, alloc);
    7211                                        
    7212                                         cur = cur.parent();
    7213                                 }
    7214                                
     9873                                        if (step_push(ns, cur, alloc) & once)
     9874                                                return;
     9875
     9876                                        cur = cur->parent;
     9877                                }
     9878
    72159879                                break;
    72169880                        }
     
    72259889                        case axis_parent:
    72269890                        {
    7227                                 if (n.parent()) step_push(ns, n.parent(), alloc);
     9891                                if (n->parent)
     9892                                        step_push(ns, n->parent, alloc);
    72289893
    72299894                                break;
    72309895                        }
    7231                                
     9896
    72329897                        default:
    7233                                 assert(!"Unimplemented axis");
    7234                         }
    7235                 }
    7236                
    7237                 template <class T> void step_fill(xpath_node_set_raw& ns, const xml_attribute& a, const xml_node& p, xpath_allocator* alloc, T v)
     9898                                assert(false && "Unimplemented axis");
     9899                        }
     9900                }
     9901
     9902                template <class T> void step_fill(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* p, xpath_allocator* alloc, bool once, T v)
    72389903                {
    72399904                        const axis_t axis = T::axis;
     
    72459910                        {
    72469911                                if (axis == axis_ancestor_or_self && _test == nodetest_type_node) // reject attributes based on principal node type test
    7247                                         step_push(ns, a, p, alloc);
    7248 
    7249                                 xml_node cur = p;
    7250                                
     9912                                        if (step_push(ns, a, p, alloc) & once)
     9913                                                return;
     9914
     9915                                xml_node_struct* cur = p;
     9916
    72519917                                while (cur)
    72529918                                {
    7253                                         step_push(ns, cur, alloc);
    7254                                        
    7255                                         cur = cur.parent();
    7256                                 }
    7257                                
     9919                                        if (step_push(ns, cur, alloc) & once)
     9920                                                return;
     9921
     9922                                        cur = cur->parent;
     9923                                }
     9924
    72589925                                break;
    72599926                        }
     
    72709937                        case axis_following:
    72719938                        {
    7272                                 xml_node cur = p;
    7273                                
    7274                                 for (;;)
    7275                                 {
    7276                                         if (cur.first_child())
    7277                                                 cur = cur.first_child();
    7278                                         else if (cur.next_sibling())
    7279                                                 cur = cur.next_sibling();
     9939                                xml_node_struct* cur = p;
     9940
     9941                                while (cur)
     9942                                {
     9943                                        if (cur->first_child)
     9944                                                cur = cur->first_child;
    72809945                                        else
    72819946                                        {
    7282                                                 while (cur && !cur.next_sibling()) cur = cur.parent();
    7283                                                 cur = cur.next_sibling();
    7284                                                
    7285                                                 if (!cur) break;
     9947                                                while (!cur->next_sibling)
     9948                                                {
     9949                                                        cur = cur->parent;
     9950
     9951                                                        if (!cur) return;
     9952                                                }
     9953
     9954                                                cur = cur->next_sibling;
    72869955                                        }
    72879956
    7288                                         step_push(ns, cur, alloc);
     9957                                        if (step_push(ns, cur, alloc) & once)
     9958                                                return;
    72899959                                }
    72909960
     
    73029972                        {
    73039973                                // preceding:: axis does not include attribute nodes and attribute ancestors (they are the same as parent's ancestors), so we can reuse node preceding
    7304                                 step_fill(ns, p, alloc, v);
     9974                                step_fill(ns, p, alloc, once, v);
    73059975                                break;
    73069976                        }
    7307                        
     9977
    73089978                        default:
    7309                                 assert(!"Unimplemented axis");
    7310                         }
    7311                 }
    7312                
    7313                 template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, T v)
     9979                                assert(false && "Unimplemented axis");
     9980                        }
     9981                }
     9982
     9983                template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v)
    73149984                {
    73159985                        const axis_t axis = T::axis;
    7316                         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);
     9986                        const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
     9987
     9988                        if (xn.node())
     9989                                step_fill(ns, xn.node().internal_object(), alloc, once, v);
     9990                        else if (axis_has_attributes && xn.attribute() && xn.parent())
     9991                                step_fill(ns, xn.attribute().internal_object(), xn.parent().internal_object(), alloc, once, v);
     9992                }
     9993
     9994                template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v)
     9995                {
     9996                        const axis_t axis = T::axis;
     9997                        const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);
     9998                        const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
     9999
     10000                        bool once =
     10001                                (axis == axis_attribute && _test == nodetest_name) ||
     10002                                (!_right && eval_once(axis_type, eval)) ||
     10003                                (_right && !_right->_next && _right->_test == predicate_constant_one);
    731710004
    731810005                        xpath_node_set_raw ns;
    7319                         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);
     10006                        ns.set_type(axis_type);
    732010007
    732110008                        if (_left)
    732210009                        {
    7323                                 xpath_node_set_raw s = _left->eval_node_set(c, stack);
     10010                                xpath_node_set_raw s = _left->eval_node_set(c, stack, nodeset_eval_all);
    732410011
    732510012                                // self axis preserves the original order
     
    733210019                                        // in general, all axes generate elements in a particular order, but there is no order guarantee if axis is applied to two nodes
    733310020                                        if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
    7334                                        
    7335                                         if (it->node())
    7336                                                 step_fill(ns, it->node(), stack.result, v);
    7337                                         else if (attributes)
    7338                                                 step_fill(ns, it->attribute(), it->parent(), stack.result, v);
    7339                                                
    7340                                         apply_predicates(ns, size, stack);
     10021
     10022                                        step_fill(ns, *it, stack.result, once, v);
     10023                                        if (_right) apply_predicates(ns, size, stack, eval);
    734110024                                }
    734210025                        }
    734310026                        else
    734410027                        {
    7345                                 if (c.n.node())
    7346                                         step_fill(ns, c.n.node(), stack.result, v);
    7347                                 else if (attributes)
    7348                                         step_fill(ns, c.n.attribute(), c.n.parent(), stack.result, v);
    7349                                
    7350                                 apply_predicates(ns, 0, stack);
     10028                                step_fill(ns, c.n, stack.result, once, v);
     10029                                if (_right) apply_predicates(ns, 0, stack, eval);
    735110030                        }
    735210031
     
    735810037                        return ns;
    735910038                }
    7360                
     10039
    736110040        public:
    7362                 xpath_ast_node(ast_type_t type, xpath_value_type rettype, const char_t* value):
    7363                         _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0)
     10041                xpath_ast_node(ast_type_t type, xpath_value_type rettype_, const char_t* value):
     10042                        _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
    736410043                {
    736510044                        assert(type == ast_string_constant);
     
    736710046                }
    736810047
    7369                 xpath_ast_node(ast_type_t type, xpath_value_type rettype, double value):
    7370                         _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0)
     10048                xpath_ast_node(ast_type_t type, xpath_value_type rettype_, double value):
     10049                        _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
    737110050                {
    737210051                        assert(type == ast_number_constant);
    737310052                        _data.number = value;
    737410053                }
    7375                
    7376                 xpath_ast_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value):
    7377                         _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(0), _right(0), _next(0)
     10054
     10055                xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_variable* value):
     10056                        _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(0), _right(0), _next(0)
    737810057                {
    737910058                        assert(type == ast_variable);
    738010059                        _data.variable = value;
    738110060                }
    7382                
    7383                 xpath_ast_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0):
    7384                         _type((char)type), _rettype((char)rettype), _axis(0), _test(0), _left(left), _right(right), _next(0)
     10061
     10062                xpath_ast_node(ast_type_t type, xpath_value_type rettype_, xpath_ast_node* left = 0, xpath_ast_node* right = 0):
     10063                        _type(static_cast<char>(type)), _rettype(static_cast<char>(rettype_)), _axis(0), _test(0), _left(left), _right(right), _next(0)
    738510064                {
    738610065                }
    738710066
    738810067                xpath_ast_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents):
    7389                         _type((char)type), _rettype(xpath_type_node_set), _axis((char)axis), _test((char)test), _left(left), _right(0), _next(0)
    7390                 {
     10068                        _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)
     10069                {
     10070                        assert(type == ast_step);
    739110071                        _data.nodetest = contents;
     10072                }
     10073
     10074                xpath_ast_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test):
     10075                        _type(static_cast<char>(type)), _rettype(xpath_type_node_set), _axis(0), _test(static_cast<char>(test)), _left(left), _right(right), _next(0)
     10076                {
     10077                        assert(type == ast_filter || type == ast_predicate);
    739210078                }
    739310079
     
    740810094                        case ast_op_or:
    740910095                                return _left->eval_boolean(c, stack) || _right->eval_boolean(c, stack);
    7410                                
     10096
    741110097                        case ast_op_and:
    741210098                                return _left->eval_boolean(c, stack) && _right->eval_boolean(c, stack);
    7413                                
     10099
    741410100                        case ast_op_equal:
    741510101                                return compare_eq(_left, _right, c, stack, equal_to());
     
    741710103                        case ast_op_not_equal:
    741810104                                return compare_eq(_left, _right, c, stack, not_equal_to());
    7419        
     10105
    742010106                        case ast_op_less:
    742110107                                return compare_rel(_left, _right, c, stack, less());
    7422                        
     10108
    742310109                        case ast_op_greater:
    742410110                                return compare_rel(_right, _left, c, stack, less());
     
    742610112                        case ast_op_less_or_equal:
    742710113                                return compare_rel(_left, _right, c, stack, less_equal());
    7428                        
     10114
    742910115                        case ast_op_greater_or_equal:
    743010116                                return compare_rel(_right, _left, c, stack, less_equal());
     
    745210138                        case ast_func_boolean:
    745310139                                return _left->eval_boolean(c, stack);
    7454                                
     10140
    745510141                        case ast_func_not:
    745610142                                return !_left->eval_boolean(c, stack);
    7457                                
     10143
    745810144                        case ast_func_true:
    745910145                                return true;
    7460                                
     10146
    746110147                        case ast_func_false:
    746210148                                return false;
     
    746510151                        {
    746610152                                if (c.n.attribute()) return false;
    7467                                
     10153
    746810154                                xpath_allocator_capture cr(stack.result);
    746910155
    747010156                                xpath_string lang = _left->eval_string(c, stack);
    7471                                
     10157
    747210158                                for (xml_node n = c.n.node(); n; n = n.parent())
    747310159                                {
    747410160                                        xml_attribute a = n.attribute(PUGIXML_TEXT("xml:lang"));
    7475                                        
     10161
    747610162                                        if (a)
    747710163                                        {
    747810164                                                const char_t* value = a.value();
    7479                                                
     10165
    748010166                                                // strnicmp / strncasecmp is not portable
    748110167                                                for (const char_t* lit = lang.c_str(); *lit; ++lit)
     
    748410170                                                        ++value;
    748510171                                                }
    7486                                                
     10172
    748710173                                                return *value == 0 || *value == '-';
    748810174                                        }
    748910175                                }
    7490                                
     10176
    749110177                                return false;
     10178                        }
     10179
     10180                        case ast_opt_compare_attribute:
     10181                        {
     10182                                const char_t* value = (_right->_type == ast_string_constant) ? _right->_data.string : _right->_data.variable->get_string();
     10183
     10184                                xml_attribute attr = c.n.node().attribute(_left->_data.nodetest);
     10185
     10186                                return attr && strequal(attr.value(), value) && is_xpath_attribute(attr.name());
    749210187                        }
    749310188
     
    750810203                                case xpath_type_number:
    750910204                                        return convert_number_to_boolean(eval_number(c, stack));
    7510                                        
     10205
    751110206                                case xpath_type_string:
    751210207                                {
     
    751510210                                        return !eval_string(c, stack).empty();
    751610211                                }
    7517                                        
    7518                                 case xpath_type_node_set:                               
     10212
     10213                                case xpath_type_node_set:
    751910214                                {
    752010215                                        xpath_allocator_capture cr(stack.result);
    752110216
    7522                                         return !eval_node_set(c, stack).empty();
     10217                                        return !eval_node_set(c, stack, nodeset_eval_any).empty();
    752310218                                }
    752410219
    752510220                                default:
    7526                                         assert(!"Wrong expression for return type boolean");
     10221                                        assert(false && "Wrong expression for return type boolean");
    752710222                                        return false;
    752810223                                }
     
    753710232                        case ast_op_add:
    753810233                                return _left->eval_number(c, stack) + _right->eval_number(c, stack);
    7539                                
     10234
    754010235                        case ast_op_subtract:
    754110236                                return _left->eval_number(c, stack) - _right->eval_number(c, stack);
     
    755710252
    755810253                        case ast_func_last:
    7559                                 return (double)c.size;
    7560                        
     10254                                return static_cast<double>(c.size);
     10255
    756110256                        case ast_func_position:
    7562                                 return (double)c.position;
     10257                                return static_cast<double>(c.position);
    756310258
    756410259                        case ast_func_count:
     
    756610261                                xpath_allocator_capture cr(stack.result);
    756710262
    7568                                 return (double)_left->eval_node_set(c, stack).size();
    7569                         }
    7570                        
     10263                                return static_cast<double>(_left->eval_node_set(c, stack, nodeset_eval_all).size());
     10264                        }
     10265
    757110266                        case ast_func_string_length_0:
    757210267                        {
    757310268                                xpath_allocator_capture cr(stack.result);
    757410269
    7575                                 return (double)string_value(c.n, stack.result).length();
    7576                         }
    7577                        
     10270                                return static_cast<double>(string_value(c.n, stack.result).length());
     10271                        }
     10272
    757810273                        case ast_func_string_length_1:
    757910274                        {
    758010275                                xpath_allocator_capture cr(stack.result);
    758110276
    7582                                 return (double)_left->eval_string(c, stack).length();
    7583                         }
    7584                        
     10277                                return static_cast<double>(_left->eval_string(c, stack).length());
     10278                        }
     10279
    758510280                        case ast_func_number_0:
    758610281                        {
     
    758910284                                return convert_string_to_number(string_value(c.n, stack.result).c_str());
    759010285                        }
    7591                        
     10286
    759210287                        case ast_func_number_1:
    759310288                                return _left->eval_number(c, stack);
     
    759810293
    759910294                                double r = 0;
    7600                                
    7601                                 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
    7602                                
     10295
     10296                                xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_all);
     10297
    760310298                                for (const xpath_node* it = ns.begin(); it != ns.end(); ++it)
    760410299                                {
     
    760710302                                        r += convert_string_to_number(string_value(*it, stack.result).c_str());
    760810303                                }
    7609                        
     10304
    761010305                                return r;
    761110306                        }
     
    761410309                        {
    761510310                                double r = _left->eval_number(c, stack);
    7616                                
     10311
    761710312                                return r == r ? floor(r) : r;
    761810313                        }
     
    762110316                        {
    762210317                                double r = _left->eval_number(c, stack);
    7623                                
     10318
    762410319                                return r == r ? ceil(r) : r;
    762510320                        }
     
    762710322                        case ast_func_round:
    762810323                                return round_nearest_nzero(_left->eval_number(c, stack));
    7629                        
     10324
    763010325                        case ast_variable:
    763110326                        {
     
    764410339                                case xpath_type_boolean:
    764510340                                        return eval_boolean(c, stack) ? 1 : 0;
    7646                                        
     10341
    764710342                                case xpath_type_string:
    764810343                                {
     
    765110346                                        return convert_string_to_number(eval_string(c, stack).c_str());
    765210347                                }
    7653                                        
     10348
    765410349                                case xpath_type_node_set:
    765510350                                {
     
    765810353                                        return convert_string_to_number(eval_string(c, stack).c_str());
    765910354                                }
    7660                                        
     10355
    766110356                                default:
    7662                                         assert(!"Wrong expression for return type number");
     10357                                        assert(false && "Wrong expression for return type number");
    766310358                                        return 0;
    766410359                                }
    7665                                
    7666                         }
    7667                         }
    7668                 }
    7669                
     10360
     10361                        }
     10362                        }
     10363                }
     10364
    767010365                xpath_string eval_string_concat(const xpath_context& c, const xpath_stack& stack)
    767110366                {
     
    771410409                        *ri = 0;
    771510410
    7716                         return xpath_string(result, true);
     10411                        return xpath_string::from_heap_preallocated(result, ri);
    771710412                }
    771810413
     
    772210417                        {
    772310418                        case ast_string_constant:
    7724                                 return xpath_string_const(_data.string);
    7725                        
     10419                                return xpath_string::from_const(_data.string);
     10420
    772610421                        case ast_func_local_name_0:
    772710422                        {
    772810423                                xpath_node na = c.n;
    7729                                
    7730                                 return xpath_string_const(local_name(na));
     10424
     10425                                return xpath_string::from_const(local_name(na));
    773110426                        }
    773210427
     
    773510430                                xpath_allocator_capture cr(stack.result);
    773610431
    7737                                 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
     10432                                xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
    773810433                                xpath_node na = ns.first();
    7739                                
    7740                                 return xpath_string_const(local_name(na));
     10434
     10435                                return xpath_string::from_const(local_name(na));
    774110436                        }
    774210437
     
    774410439                        {
    774510440                                xpath_node na = c.n;
    7746                                
    7747                                 return xpath_string_const(qualified_name(na));
     10441
     10442                                return xpath_string::from_const(qualified_name(na));
    774810443                        }
    774910444
     
    775210447                                xpath_allocator_capture cr(stack.result);
    775310448
    7754                                 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
     10449                                xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
    775510450                                xpath_node na = ns.first();
    7756                                
    7757                                 return xpath_string_const(qualified_name(na));
     10451
     10452                                return xpath_string::from_const(qualified_name(na));
    775810453                        }
    775910454
     
    776110456                        {
    776210457                                xpath_node na = c.n;
    7763                                
    7764                                 return xpath_string_const(namespace_uri(na));
     10458
     10459                                return xpath_string::from_const(namespace_uri(na));
    776510460                        }
    776610461
     
    776910464                                xpath_allocator_capture cr(stack.result);
    777010465
    7771                                 xpath_node_set_raw ns = _left->eval_node_set(c, stack);
     10466                                xpath_node_set_raw ns = _left->eval_node_set(c, stack, nodeset_eval_first);
    777210467                                xpath_node na = ns.first();
    7773                                
    7774                                 return xpath_string_const(namespace_uri(na));
     10468
     10469                                return xpath_string::from_const(namespace_uri(na));
    777510470                        }
    777610471
     
    779410489
    779510490                                const char_t* pos = find_substring(s.c_str(), p.c_str());
    7796                                
    7797                                 return pos ? xpath_string(s.c_str(), pos, stack.result) : xpath_string();
    7798                         }
    7799                        
     10491
     10492                                return pos ? xpath_string::from_heap(s.c_str(), pos, stack.result) : xpath_string();
     10493                        }
     10494
    780010495                        case ast_func_substring_after:
    780110496                        {
     
    780610501                                xpath_string s = _left->eval_string(c, swapped_stack);
    780710502                                xpath_string p = _right->eval_string(c, swapped_stack);
    7808                                
     10503
    780910504                                const char_t* pos = find_substring(s.c_str(), p.c_str());
    781010505                                if (!pos) return xpath_string();
    781110506
    7812                                 const char_t* result = pos + p.length();
    7813 
    7814                                 return s.uses_heap() ? xpath_string(result, stack.result) : xpath_string_const(result);
     10507                                const char_t* rbegin = pos + p.length();
     10508                                const char_t* rend = s.c_str() + s.length();
     10509
     10510                                return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
    781510511                        }
    781610512
     
    782510521
    782610522                                double first = round_nearest(_right->eval_number(c, stack));
    7827                                
     10523
    782810524                                if (is_nan(first)) return xpath_string(); // NaN
    782910525                                else if (first >= s_length + 1) return xpath_string();
    7830                                
    7831                                 size_t pos = first < 1 ? 1 : (size_t)first;
     10526
     10527                                size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
    783210528                                assert(1 <= pos && pos <= s_length + 1);
    783310529
    783410530                                const char_t* rbegin = s.c_str() + (pos - 1);
    7835                                
    7836                                 return s.uses_heap() ? xpath_string(rbegin, stack.result) : xpath_string_const(rbegin);
    7837                         }
    7838                        
     10531                                const char_t* rend = s.c_str() + s.length();
     10532
     10533                                return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
     10534                        }
     10535
    783910536                        case ast_func_substring_3:
    784010537                        {
     
    784810545                                double first = round_nearest(_right->eval_number(c, stack));
    784910546                                double last = first + round_nearest(_right->_next->eval_number(c, stack));
    7850                                
     10547
    785110548                                if (is_nan(first) || is_nan(last)) return xpath_string();
    785210549                                else if (first >= s_length + 1) return xpath_string();
    785310550                                else if (first >= last) return xpath_string();
    785410551                                else if (last < 1) return xpath_string();
    7855                                
    7856                                 size_t pos = first < 1 ? 1 : (size_t)first;
    7857                                 size_t end = last >= s_length + 1 ? s_length + 1 : (size_t)last;
     10552
     10553                                size_t pos = first < 1 ? 1 : static_cast<size_t>(first);
     10554                                size_t end = last >= s_length + 1 ? s_length + 1 : static_cast<size_t>(last);
    785810555
    785910556                                assert(1 <= pos && pos <= end && end <= s_length + 1);
     
    786110558                                const char_t* rend = s.c_str() + (end - 1);
    786210559
    7863                                 return (end == s_length + 1 && !s.uses_heap()) ? xpath_string_const(rbegin) : xpath_string(rbegin, rend, stack.result);
     10560                                return (end == s_length + 1 && !s.uses_heap()) ? xpath_string::from_const(rbegin) : xpath_string::from_heap(rbegin, rend, stack.result);
    786410561                        }
    786510562
     
    786810565                                xpath_string s = string_value(c.n, stack.result);
    786910566
    7870                                 normalize_space(s.data(stack.result));
    7871 
    7872                                 return s;
     10567                                char_t* begin = s.data(stack.result);
     10568                                char_t* end = normalize_space(begin);
     10569
     10570                                return xpath_string::from_heap_preallocated(begin, end);
    787310571                        }
    787410572
     
    787710575                                xpath_string s = _left->eval_string(c, stack);
    787810576
    7879                                 normalize_space(s.data(stack.result));
    7880                        
    7881                                 return s;
     10577                                char_t* begin = s.data(stack.result);
     10578                                char_t* end = normalize_space(begin);
     10579
     10580                                return xpath_string::from_heap_preallocated(begin, end);
    788210581                        }
    788310582
     
    789210591                                xpath_string to = _right->_next->eval_string(c, swapped_stack);
    789310592
    7894                                 translate(s.data(stack.result), from.c_str(), to.c_str());
    7895 
    7896                                 return s;
     10593                                char_t* begin = s.data(stack.result);
     10594                                char_t* end = translate(begin, from.c_str(), to.c_str(), to.length());
     10595
     10596                                return xpath_string::from_heap_preallocated(begin, end);
     10597                        }
     10598
     10599                        case ast_opt_translate_table:
     10600                        {
     10601                                xpath_string s = _left->eval_string(c, stack);
     10602
     10603                                char_t* begin = s.data(stack.result);
     10604                                char_t* end = translate_table(begin, _data.table);
     10605
     10606                                return xpath_string::from_heap_preallocated(begin, end);
    789710607                        }
    789810608
     
    790210612
    790310613                                if (_rettype == xpath_type_string)
    7904                                         return xpath_string_const(_data.variable->get_string());
     10614                                        return xpath_string::from_const(_data.variable->get_string());
    790510615
    790610616                                // fallthrough to type conversion
     
    791210622                                {
    791310623                                case xpath_type_boolean:
    7914                                         return xpath_string_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
    7915                                        
     10624                                        return xpath_string::from_const(eval_boolean(c, stack) ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
     10625
    791610626                                case xpath_type_number:
    791710627                                        return convert_number_to_string(eval_number(c, stack), stack.result);
    7918                                        
     10628
    791910629                                case xpath_type_node_set:
    792010630                                {
     
    792310633                                        xpath_stack swapped_stack = {stack.temp, stack.result};
    792410634
    7925                                         xpath_node_set_raw ns = eval_node_set(c, swapped_stack);
     10635                                        xpath_node_set_raw ns = eval_node_set(c, swapped_stack, nodeset_eval_first);
    792610636                                        return ns.empty() ? xpath_string() : string_value(ns.first(), stack.result);
    792710637                                }
    7928                                
     10638
    792910639                                default:
    7930                                         assert(!"Wrong expression for return type string");
     10640                                        assert(false && "Wrong expression for return type string");
    793110641                                        return xpath_string();
    793210642                                }
     
    793510645                }
    793610646
    7937                 xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack)
     10647                xpath_node_set_raw eval_node_set(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval)
    793810648                {
    793910649                        switch (_type)
     
    794510655                                xpath_stack swapped_stack = {stack.temp, stack.result};
    794610656
    7947                                 xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack);
    7948                                 xpath_node_set_raw rs = _right->eval_node_set(c, stack);
    7949                                
     10657                                xpath_node_set_raw ls = _left->eval_node_set(c, swapped_stack, eval);
     10658                                xpath_node_set_raw rs = _right->eval_node_set(c, stack, eval);
     10659
    795010660                                // we can optimize merging two sorted sets, but this is a very rare operation, so don't bother
    7951                         rs.set_type(xpath_node_set::type_unsorted);
     10661                                rs.set_type(xpath_node_set::type_unsorted);
    795210662
    795310663                                rs.append(ls.begin(), ls.end(), stack.result);
    795410664                                rs.remove_duplicates();
    7955                                
     10665
    795610666                                return rs;
    795710667                        }
    795810668
    795910669                        case ast_filter:
    7960                         case ast_filter_posinv:
    7961                         {
    7962                                 xpath_node_set_raw set = _left->eval_node_set(c, stack);
     10670                        {
     10671                                xpath_node_set_raw set = _left->eval_node_set(c, stack, _test == predicate_constant_one ? nodeset_eval_first : nodeset_eval_all);
    796310672
    796410673                                // either expression is a number or it contains position() call; sort by document order
    7965                                 if (_type == ast_filter) set.sort_do();
    7966 
    7967                                 apply_predicate(set, 0, _right, stack);
    7968                        
     10674                                if (_test != predicate_posinv) set.sort_do();
     10675
     10676                                bool once = eval_once(set.type(), eval);
     10677
     10678                                apply_predicate(set, 0, stack, once);
     10679
    796910680                                return set;
    797010681                        }
    7971                        
     10682
    797210683                        case ast_func_id:
    797310684                                return xpath_node_set_raw();
    7974                        
     10685
    797510686                        case ast_step:
    797610687                        {
     
    797810689                                {
    797910690                                case axis_ancestor:
    7980                                         return step_do(c, stack, axis_to_type<axis_ancestor>());
    7981                                        
     10691                                        return step_do(c, stack, eval, axis_to_type<axis_ancestor>());
     10692
    798210693                                case axis_ancestor_or_self:
    7983                                         return step_do(c, stack, axis_to_type<axis_ancestor_or_self>());
     10694                                        return step_do(c, stack, eval, axis_to_type<axis_ancestor_or_self>());
    798410695
    798510696                                case axis_attribute:
    7986                                         return step_do(c, stack, axis_to_type<axis_attribute>());
     10697                                        return step_do(c, stack, eval, axis_to_type<axis_attribute>());
    798710698
    798810699                                case axis_child:
    7989                                         return step_do(c, stack, axis_to_type<axis_child>());
    7990                                
     10700                                        return step_do(c, stack, eval, axis_to_type<axis_child>());
     10701
    799110702                                case axis_descendant:
    7992                                         return step_do(c, stack, axis_to_type<axis_descendant>());
     10703                                        return step_do(c, stack, eval, axis_to_type<axis_descendant>());
    799310704
    799410705                                case axis_descendant_or_self:
    7995                                         return step_do(c, stack, axis_to_type<axis_descendant_or_self>());
     10706                                        return step_do(c, stack, eval, axis_to_type<axis_descendant_or_self>());
    799610707
    799710708                                case axis_following:
    7998                                         return step_do(c, stack, axis_to_type<axis_following>());
    7999                                
     10709                                        return step_do(c, stack, eval, axis_to_type<axis_following>());
     10710
    800010711                                case axis_following_sibling:
    8001                                         return step_do(c, stack, axis_to_type<axis_following_sibling>());
    8002                                
     10712                                        return step_do(c, stack, eval, axis_to_type<axis_following_sibling>());
     10713
    800310714                                case axis_namespace:
    800410715                                        // namespaced axis is not supported
    800510716                                        return xpath_node_set_raw();
    8006                                
     10717
    800710718                                case axis_parent:
    8008                                         return step_do(c, stack, axis_to_type<axis_parent>());
    8009                                
     10719                                        return step_do(c, stack, eval, axis_to_type<axis_parent>());
     10720
    801010721                                case axis_preceding:
    8011                                         return step_do(c, stack, axis_to_type<axis_preceding>());
     10722                                        return step_do(c, stack, eval, axis_to_type<axis_preceding>());
    801210723
    801310724                                case axis_preceding_sibling:
    8014                                         return step_do(c, stack, axis_to_type<axis_preceding_sibling>());
    8015                                
     10725                                        return step_do(c, stack, eval, axis_to_type<axis_preceding_sibling>());
     10726
    801610727                                case axis_self:
    8017                                         return step_do(c, stack, axis_to_type<axis_self>());
     10728                                        return step_do(c, stack, eval, axis_to_type<axis_self>());
     10729
     10730                                default:
     10731                                        assert(false && "Unknown axis");
     10732                                        return xpath_node_set_raw();
    801810733                                }
    801910734                        }
     
    805310768
    805410769                        default:
    8055                                 assert(!"Wrong expression for return type node set");
     10770                                assert(false && "Wrong expression for return type node set");
    805610771                                return xpath_node_set_raw();
    805710772                        }
    805810773                }
    8059                
    8060                 bool is_posinv()
     10774
     10775                void optimize(xpath_allocator* alloc)
     10776                {
     10777                        if (_left)
     10778                                _left->optimize(alloc);
     10779
     10780                        if (_right)
     10781                                _right->optimize(alloc);
     10782
     10783                        if (_next)
     10784                                _next->optimize(alloc);
     10785
     10786                        optimize_self(alloc);
     10787                }
     10788
     10789                void optimize_self(xpath_allocator* alloc)
     10790                {
     10791                        // Rewrite [position()=expr] with [expr]
     10792                        // Note that this step has to go before classification to recognize [position()=1]
     10793                        if ((_type == ast_filter || _type == ast_predicate) &&
     10794                                _right->_type == ast_op_equal && _right->_left->_type == ast_func_position && _right->_right->_rettype == xpath_type_number)
     10795                        {
     10796                                _right = _right->_right;
     10797                        }
     10798
     10799                        // Classify filter/predicate ops to perform various optimizations during evaluation
     10800                        if (_type == ast_filter || _type == ast_predicate)
     10801                        {
     10802                                assert(_test == predicate_default);
     10803
     10804                                if (_right->_type == ast_number_constant && _right->_data.number == 1.0)
     10805                                        _test = predicate_constant_one;
     10806                                else if (_right->_rettype == xpath_type_number && (_right->_type == ast_number_constant || _right->_type == ast_variable || _right->_type == ast_func_last))
     10807                                        _test = predicate_constant;
     10808                                else if (_right->_rettype != xpath_type_number && _right->is_posinv_expr())
     10809                                        _test = predicate_posinv;
     10810                        }
     10811
     10812                        // Rewrite descendant-or-self::node()/child::foo with descendant::foo
     10813                        // The former is a full form of //foo, the latter is much faster since it executes the node test immediately
     10814                        // Do a similar kind of rewrite for self/descendant/descendant-or-self axes
     10815                        // Note that we only rewrite positionally invariant steps (//foo[1] != /descendant::foo[1])
     10816                        if (_type == ast_step && (_axis == axis_child || _axis == axis_self || _axis == axis_descendant || _axis == axis_descendant_or_self) && _left &&
     10817                                _left->_type == ast_step && _left->_axis == axis_descendant_or_self && _left->_test == nodetest_type_node && !_left->_right &&
     10818                                is_posinv_step())
     10819                        {
     10820                                if (_axis == axis_child || _axis == axis_descendant)
     10821                                        _axis = axis_descendant;
     10822                                else
     10823                                        _axis = axis_descendant_or_self;
     10824
     10825                                _left = _left->_left;
     10826                        }
     10827
     10828                        // Use optimized lookup table implementation for translate() with constant arguments
     10829                        if (_type == ast_func_translate && _right->_type == ast_string_constant && _right->_next->_type == ast_string_constant)
     10830                        {
     10831                                unsigned char* table = translate_table_generate(alloc, _right->_data.string, _right->_next->_data.string);
     10832
     10833                                if (table)
     10834                                {
     10835                                        _type = ast_opt_translate_table;
     10836                                        _data.table = table;
     10837                                }
     10838                        }
     10839
     10840                        // Use optimized path for @attr = 'value' or @attr = $value
     10841                        if (_type == ast_op_equal &&
     10842                                _left->_type == ast_step && _left->_axis == axis_attribute && _left->_test == nodetest_name && !_left->_left && !_left->_right &&
     10843                                (_right->_type == ast_string_constant || (_right->_type == ast_variable && _right->_rettype == xpath_type_string)))
     10844                        {
     10845                                _type = ast_opt_compare_attribute;
     10846                        }
     10847                }
     10848
     10849                bool is_posinv_expr() const
    806110850                {
    806210851                        switch (_type)
    806310852                        {
    806410853                        case ast_func_position:
     10854                        case ast_func_last:
    806510855                                return false;
    806610856
     
    807610866                        case ast_predicate:
    807710867                        case ast_filter:
    8078                         case ast_filter_posinv:
    807910868                                return true;
    808010869
    808110870                        default:
    8082                                 if (_left && !_left->is_posinv()) return false;
    8083                                
     10871                                if (_left && !_left->is_posinv_expr()) return false;
     10872
    808410873                                for (xpath_ast_node* n = _right; n; n = n->_next)
    8085                                         if (!n->is_posinv()) return false;
    8086                                        
     10874                                        if (!n->is_posinv_expr()) return false;
     10875
    808710876                                return true;
    808810877                        }
    808910878                }
    809010879
     10880                bool is_posinv_step() const
     10881                {
     10882                        assert(_type == ast_step);
     10883
     10884                        for (xpath_ast_node* n = _right; n; n = n->_next)
     10885                        {
     10886                                assert(n->_type == ast_predicate);
     10887
     10888                                if (n->_test != predicate_posinv)
     10889                                        return false;
     10890                        }
     10891
     10892                        return true;
     10893                }
     10894
    809110895                xpath_value_type rettype() const
    809210896                {
     
    809710901        struct xpath_parser
    809810902        {
    8099             xpath_allocator* _alloc;
    8100             xpath_lexer _lexer;
     10903                xpath_allocator* _alloc;
     10904                xpath_lexer _lexer;
    810110905
    810210906                const char_t* _query;
     
    810410908
    810510909                xpath_parse_result* _result;
     10910
     10911                char_t _scratch[32];
    810610912
    810710913        #ifdef PUGIXML_NO_EXCEPTIONS
     
    812210928
    812310929                void throw_error_oom()
    8124         {
    8125         #ifdef PUGIXML_NO_EXCEPTIONS
    8126             throw_error("Out of memory");
    8127         #else
    8128             throw std::bad_alloc();
    8129         #endif
    8130         }
     10930                {
     10931                #ifdef PUGIXML_NO_EXCEPTIONS
     10932                        throw_error("Out of memory");
     10933                #else
     10934                        throw std::bad_alloc();
     10935                #endif
     10936                }
    813110937
    813210938                void* alloc_node()
     
    814710953                                char_t* c = static_cast<char_t*>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t)));
    814810954                                if (!c) throw_error_oom();
     10955                                assert(c); // workaround for clang static analysis
    814910956
    815010957                                memcpy(c, value.begin, length * sizeof(char_t));
     
    816010967                        assert(argc <= 1);
    816110968
    8162                         if (argc == 1 && args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
     10969                        if (argc == 1 && args[0]->rettype() != xpath_type_node_set)
     10970                                throw_error("Function has to be applied to node set");
    816310971
    816410972                        return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
     
    817210980                                if (name == PUGIXML_TEXT("boolean") && argc == 1)
    817310981                                        return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]);
    8174                                        
     10982
    817510983                                break;
    8176                        
     10984
    817710985                        case 'c':
    817810986                                if (name == PUGIXML_TEXT("count") && argc == 1)
    817910987                                {
    8180                                         if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
     10988                                        if (args[0]->rettype() != xpath_type_node_set)
     10989                                                throw_error("Function has to be applied to node set");
     10990
    818110991                                        return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]);
    818210992                                }
    818310993                                else if (name == PUGIXML_TEXT("contains") && argc == 2)
    8184                                         return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_string, args[0], args[1]);
     10994                                        return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]);
    818510995                                else if (name == PUGIXML_TEXT("concat") && argc >= 2)
    818610996                                        return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]);
    818710997                                else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
    818810998                                        return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]);
    8189                                        
     10999
    819011000                                break;
    8191                        
     11001
    819211002                        case 'f':
    819311003                                if (name == PUGIXML_TEXT("false") && argc == 0)
     
    819511005                                else if (name == PUGIXML_TEXT("floor") && argc == 1)
    819611006                                        return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]);
    8197                                        
     11007
    819811008                                break;
    8199                        
     11009
    820011010                        case 'i':
    820111011                                if (name == PUGIXML_TEXT("id") && argc == 1)
    820211012                                        return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]);
    8203                                        
     11013
    820411014                                break;
    8205                        
     11015
    820611016                        case 'l':
    820711017                                if (name == PUGIXML_TEXT("last") && argc == 0)
     
    821111021                                else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
    821211022                                        return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args);
    8213                        
     11023
    821411024                                break;
    8215                        
     11025
    821611026                        case 'n':
    821711027                                if (name == PUGIXML_TEXT("name") && argc <= 1)
     
    822511035                                else if (name == PUGIXML_TEXT("number") && argc <= 1)
    822611036                                        return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
    8227                        
     11037
    822811038                                break;
    8229                        
     11039
    823011040                        case 'p':
    823111041                                if (name == PUGIXML_TEXT("position") && argc == 0)
    823211042                                        return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number);
    8233                                
     11043
    823411044                                break;
    8235                        
     11045
    823611046                        case 'r':
    823711047                                if (name == PUGIXML_TEXT("round") && argc == 1)
     
    823911049
    824011050                                break;
    8241                        
     11051
    824211052                        case 's':
    824311053                                if (name == PUGIXML_TEXT("string") && argc <= 1)
    824411054                                        return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
    824511055                                else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
    8246                                         return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_string, args[0]);
     11056                                        return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]);
    824711057                                else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
    824811058                                        return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
     
    826011070
    826111071                                break;
    8262                        
     11072
    826311073                        case 't':
    826411074                                if (name == PUGIXML_TEXT("translate") && argc == 3)
     
    826611076                                else if (name == PUGIXML_TEXT("true") && argc == 0)
    826711077                                        return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean);
    8268                                        
     11078
     11079                                break;
     11080
     11081                        default:
    826911082                                break;
    827011083                        }
     
    828811101                                else if (name == PUGIXML_TEXT("attribute"))
    828911102                                        return axis_attribute;
    8290                                
     11103
    829111104                                break;
    8292                        
     11105
    829311106                        case 'c':
    829411107                                if (name == PUGIXML_TEXT("child"))
    829511108                                        return axis_child;
    8296                                
     11109
    829711110                                break;
    8298                        
     11111
    829911112                        case 'd':
    830011113                                if (name == PUGIXML_TEXT("descendant"))
     
    830211115                                else if (name == PUGIXML_TEXT("descendant-or-self"))
    830311116                                        return axis_descendant_or_self;
    8304                                
     11117
    830511118                                break;
    8306                        
     11119
    830711120                        case 'f':
    830811121                                if (name == PUGIXML_TEXT("following"))
     
    831011123                                else if (name == PUGIXML_TEXT("following-sibling"))
    831111124                                        return axis_following_sibling;
    8312                                
     11125
    831311126                                break;
    8314                        
     11127
    831511128                        case 'n':
    831611129                                if (name == PUGIXML_TEXT("namespace"))
    831711130                                        return axis_namespace;
    8318                                
     11131
    831911132                                break;
    8320                        
     11133
    832111134                        case 'p':
    832211135                                if (name == PUGIXML_TEXT("parent"))
     
    832611139                                else if (name == PUGIXML_TEXT("preceding-sibling"))
    832711140                                        return axis_preceding_sibling;
    8328                                
     11141
    832911142                                break;
    8330                        
     11143
    833111144                        case 's':
    833211145                                if (name == PUGIXML_TEXT("self"))
    833311146                                        return axis_self;
    8334                                
     11147
     11148                                break;
     11149
     11150                        default:
    833511151                                break;
    833611152                        }
     
    836711183
    836811184                                break;
     11185
     11186                        default:
     11187                                break;
    836911188                        }
    837011189
     
    837211191                }
    837311192
    8374             // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
    8375             xpath_ast_node* parse_primary_expression()
    8376             {
    8377                 switch (_lexer.current())
    8378                 {
    8379                 case lex_var_ref:
    8380                 {
     11193                // PrimaryExpr ::= VariableReference | '(' Expr ')' | Literal | Number | FunctionCall
     11194                xpath_ast_node* parse_primary_expression()
     11195                {
     11196                        switch (_lexer.current())
     11197                        {
     11198                        case lex_var_ref:
     11199                        {
    838111200                                xpath_lexer_string name = _lexer.contents();
    838211201
     
    838411203                                        throw_error("Unknown variable: variable set is not provided");
    838511204
    8386                                 xpath_variable* var = get_variable(_variables, name.begin, name.end);
     11205                                xpath_variable* var = 0;
     11206                                if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var))
     11207                                        throw_error_oom();
    838711208
    838811209                                if (!var)
     
    839111212                                _lexer.next();
    839211213
    8393                         return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
     11214                                return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
    839411215                        }
    839511216
     
    842211243                                double value = 0;
    842311244
    8424                                 if (!convert_string_to_number(_lexer.contents().begin, _lexer.contents().end, &value))
     11245                                if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value))
    842511246                                        throw_error_oom();
    842611247
     
    843511256                                xpath_ast_node* args[2] = {0};
    843611257                                size_t argc = 0;
    8437                                
     11258
    843811259                                xpath_lexer_string function = _lexer.contents();
    843911260                                _lexer.next();
    8440                                
     11261
    844111262                                xpath_ast_node* last_arg = 0;
    8442                                
     11263
    844311264                                if (_lexer.current() != lex_open_brace)
    844411265                                        throw_error("Unrecognized function call");
     
    845311274                                                throw_error("No comma between function arguments");
    845411275                                        _lexer.next();
    8455                                        
     11276
    845611277                                        xpath_ast_node* n = parse_expression();
    8457                                        
     11278
    845811279                                        if (argc < 2) args[argc] = n;
    845911280                                        else last_arg->set_next(n);
     
    846211283                                        last_arg = n;
    846311284                                }
    8464                                
     11285
    846511286                                _lexer.next();
    846611287
     
    846811289                        }
    846911290
    8470                 default:
    8471                         throw_error("Unrecognizable primary expression");
    8472 
    8473                         return 0;
    8474                 }
    8475             }
    8476            
    8477             // FilterExpr ::= PrimaryExpr | FilterExpr Predicate
    8478             // Predicate ::= '[' PredicateExpr ']'
    8479             // PredicateExpr ::= Expr
    8480             xpath_ast_node* parse_filter_expression()
    8481             {
    8482                 xpath_ast_node* n = parse_primary_expression();
    8483 
    8484                 while (_lexer.current() == lex_open_square_brace)
    8485                 {
    8486                         _lexer.next();
     11291                        default:
     11292                                throw_error("Unrecognizable primary expression");
     11293
     11294                                return 0;
     11295                        }
     11296                }
     11297
     11298                // FilterExpr ::= PrimaryExpr | FilterExpr Predicate
     11299                // Predicate ::= '[' PredicateExpr ']'
     11300                // PredicateExpr ::= Expr
     11301                xpath_ast_node* parse_filter_expression()
     11302                {
     11303                        xpath_ast_node* n = parse_primary_expression();
     11304
     11305                        while (_lexer.current() == lex_open_square_brace)
     11306                        {
     11307                                _lexer.next();
    848711308
    848811309                                xpath_ast_node* expr = parse_expression();
    848911310
    8490                                 if (n->rettype() != xpath_type_node_set) throw_error("Predicate has to be applied to node set");
    8491 
    8492                                 bool posinv = expr->rettype() != xpath_type_number && expr->is_posinv();
    8493 
    8494                         n = new (alloc_node()) xpath_ast_node(posinv ? ast_filter_posinv : ast_filter, xpath_type_node_set, n, expr);
    8495 
    8496                         if (_lexer.current() != lex_close_square_brace)
    8497                                 throw_error("Unmatched square brace");
    8498                
    8499                         _lexer.next();
    8500                 }
    8501                
    8502                 return n;
    8503             }
    8504            
    8505             // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
    8506             // AxisSpecifier ::= AxisName '::' | '@'?
    8507             // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
    8508             // NameTest ::= '*' | NCName ':' '*' | QName
    8509             // AbbreviatedStep ::= '.' | '..'
    8510             xpath_ast_node* parse_step(xpath_ast_node* set)
    8511             {
     11311                                if (n->rettype() != xpath_type_node_set)
     11312                                        throw_error("Predicate has to be applied to node set");
     11313
     11314                                n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default);
     11315
     11316                                if (_lexer.current() != lex_close_square_brace)
     11317                                        throw_error("Unmatched square brace");
     11318
     11319                                _lexer.next();
     11320                        }
     11321
     11322                        return n;
     11323                }
     11324
     11325                // Step ::= AxisSpecifier NodeTest Predicate* | AbbreviatedStep
     11326                // AxisSpecifier ::= AxisName '::' | '@'?
     11327                // NodeTest ::= NameTest | NodeType '(' ')' | 'processing-instruction' '(' Literal ')'
     11328                // NameTest ::= '*' | NCName ':' '*' | QName
     11329                // AbbreviatedStep ::= '.' | '..'
     11330                xpath_ast_node* parse_step(xpath_ast_node* set)
     11331                {
    851211332                        if (set && set->rettype() != xpath_type_node_set)
    851311333                                throw_error("Step has to be applied to node set");
     
    852011340                                axis = axis_attribute;
    852111341                                axis_specified = true;
    8522                                
     11342
    852311343                                _lexer.next();
    852411344                        }
     
    852611346                        {
    852711347                                _lexer.next();
    8528                                
     11348
    852911349                                return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0);
    853011350                        }
     
    853211352                        {
    853311353                                _lexer.next();
    8534                                
     11354
    853511355                                return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0);
    853611356                        }
    8537            
     11357
    853811358                        nodetest_t nt_type = nodetest_none;
    853911359                        xpath_lexer_string nt_name;
    8540                        
     11360
    854111361                        if (_lexer.current() == lex_string)
    854211362                        {
     
    854911369                                {
    855011370                                        // parse axis name
    8551                                         if (axis_specified) throw_error("Two axis specifiers in one step");
     11371                                        if (axis_specified)
     11372                                                throw_error("Two axis specifiers in one step");
    855211373
    855311374                                        axis = parse_axis_name(nt_name, axis_specified);
    855411375
    8555                                         if (!axis_specified) throw_error("Unknown axis");
     11376                                        if (!axis_specified)
     11377                                                throw_error("Unknown axis");
    855611378
    855711379                                        // read actual node test
     
    857111393                                        else throw_error("Unrecognized node test");
    857211394                                }
    8573                                
     11395
    857411396                                if (nt_type == nodetest_none)
    857511397                                {
     
    857811400                                        {
    857911401                                                _lexer.next();
    8580                                                
     11402
    858111403                                                if (_lexer.current() == lex_close_brace)
    858211404                                                {
     
    858511407                                                        nt_type = parse_node_test_type(nt_name);
    858611408
    8587                                                         if (nt_type == nodetest_none) throw_error("Unrecognized node type");
    8588                                                        
     11409                                                        if (nt_type == nodetest_none)
     11410                                                                throw_error("Unrecognized node type");
     11411
    858911412                                                        nt_name = xpath_lexer_string();
    859011413                                                }
     
    859311416                                                        if (_lexer.current() != lex_quoted_string)
    859411417                                                                throw_error("Only literals are allowed as arguments to processing-instruction()");
    8595                                                
     11418
    859611419                                                        nt_type = nodetest_pi;
    859711420                                                        nt_name = _lexer.contents();
    859811421                                                        _lexer.next();
    8599                                                        
     11422
    860011423                                                        if (_lexer.current() != lex_close_brace)
    860111424                                                                throw_error("Unmatched brace near processing-instruction()");
     
    860311426                                                }
    860411427                                                else
     11428                                                {
    860511429                                                        throw_error("Unmatched brace near node type test");
    8606 
     11430                                                }
    860711431                                        }
    860811432                                        // QName or NCName:*
     
    861211436                                                {
    861311437                                                        nt_name.end--; // erase *
    8614                                                        
     11438
    861511439                                                        nt_type = nodetest_all_in_namespace;
    861611440                                                }
    8617                                                 else nt_type = nodetest_name;
     11441                                                else
     11442                                                {
     11443                                                        nt_type = nodetest_name;
     11444                                                }
    861811445                                        }
    861911446                                }
     
    862411451                                _lexer.next();
    862511452                        }
    8626                         else throw_error("Unrecognized node test");
    8627                        
    8628                         xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, alloc_string(nt_name));
    8629                        
     11453                        else
     11454                        {
     11455                                throw_error("Unrecognized node test");
     11456                        }
     11457
     11458                        const char_t* nt_name_copy = alloc_string(nt_name);
     11459                        xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, nt_name_copy);
     11460
    863011461                        xpath_ast_node* last = 0;
    8631                        
     11462
    863211463                        while (_lexer.current() == lex_open_square_brace)
    863311464                        {
    863411465                                _lexer.next();
    8635                                
     11466
    863611467                                xpath_ast_node* expr = parse_expression();
    863711468
    8638                                 xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, xpath_type_node_set, expr);
    8639                                
     11469                                xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default);
     11470
    864011471                                if (_lexer.current() != lex_close_square_brace)
    8641                                 throw_error("Unmatched square brace");
     11472                                        throw_error("Unmatched square brace");
    864211473                                _lexer.next();
    8643                                
     11474
    864411475                                if (last) last->set_next(pred);
    864511476                                else n->set_right(pred);
    8646                                
     11477
    864711478                                last = pred;
    864811479                        }
    8649                        
     11480
    865011481                        return n;
    8651             }
    8652            
    8653             // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
    8654             xpath_ast_node* parse_relative_location_path(xpath_ast_node* set)
    8655             {
     11482                }
     11483
     11484                // RelativeLocationPath ::= Step | RelativeLocationPath '/' Step | RelativeLocationPath '//' Step
     11485                xpath_ast_node* parse_relative_location_path(xpath_ast_node* set)
     11486                {
    865611487                        xpath_ast_node* n = parse_step(set);
    8657                        
     11488
    865811489                        while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
    865911490                        {
     
    866311494                                if (l == lex_double_slash)
    866411495                                        n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
    8665                                
     11496
    866611497                                n = parse_step(n);
    866711498                        }
    8668                        
     11499
    866911500                        return n;
    8670             }
    8671            
    8672             // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
    8673             // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
    8674             xpath_ast_node* parse_location_path()
    8675             {
     11501                }
     11502
     11503                // LocationPath ::= RelativeLocationPath | AbsoluteLocationPath
     11504                // AbsoluteLocationPath ::= '/' RelativeLocationPath? | '//' RelativeLocationPath
     11505                xpath_ast_node* parse_location_path()
     11506                {
    867611507                        if (_lexer.current() == lex_slash)
    867711508                        {
    867811509                                _lexer.next();
    8679                                
     11510
    868011511                                xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
    868111512
     
    869111522                        {
    869211523                                _lexer.next();
    8693                                
     11524
    869411525                                xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
    869511526                                n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
    8696                                
     11527
    869711528                                return parse_relative_location_path(n);
    869811529                        }
     
    870011531                        // 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
    870111532                        return parse_relative_location_path(0);
    8702             }
    8703            
    8704             // PathExpr ::= LocationPath
    8705             //                          | FilterExpr
    8706             //                          | FilterExpr '/' RelativeLocationPath
    8707             //                          | FilterExpr '//' RelativeLocationPath
    8708             xpath_ast_node* parse_path_expression()
    8709             {
     11533                }
     11534
     11535                // PathExpr ::= LocationPath
     11536                //                              | FilterExpr
     11537                //                              | FilterExpr '/' RelativeLocationPath
     11538                //                              | FilterExpr '//' RelativeLocationPath
     11539                // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
     11540                // UnaryExpr ::= UnionExpr | '-' UnaryExpr
     11541                xpath_ast_node* parse_path_or_unary_expression()
     11542                {
    871011543                        // Clarification.
    871111544                        // PathExpr begins with either LocationPath or FilterExpr.
     
    871511548                        // function call.
    871611549
    8717                         if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace || 
     11550                        if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
    871811551                                _lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
    871911552                                _lexer.current() == lex_string)
    8720                 {
    8721                         if (_lexer.current() == lex_string)
    8722                         {
    8723                                 // This is either a function call, or not - if not, we shall proceed with location path
    8724                                 const char_t* state = _lexer.state();
    8725                                
    8726                                         while (IS_CHARTYPE(*state, ct_space)) ++state;
    8727                                
    8728                                 if (*state != '(') return parse_location_path();
     11553                        {
     11554                                if (_lexer.current() == lex_string)
     11555                                {
     11556                                        // This is either a function call, or not - if not, we shall proceed with location path
     11557                                        const char_t* state = _lexer.state();
     11558
     11559                                        while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
     11560
     11561                                        if (*state != '(') return parse_location_path();
    872911562
    873011563                                        // This looks like a function call; however this still can be a node-test. Check it.
    8731                                         if (parse_node_test_type(_lexer.contents()) != nodetest_none) return parse_location_path();
    8732                         }
    8733                        
    8734                         xpath_ast_node* n = parse_filter_expression();
    8735 
    8736                         if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
    8737                         {
     11564                                        if (parse_node_test_type(_lexer.contents()) != nodetest_none)
     11565                                                return parse_location_path();
     11566                                }
     11567
     11568                                xpath_ast_node* n = parse_filter_expression();
     11569
     11570                                if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
     11571                                {
    873811572                                        lexeme_t l = _lexer.current();
    8739                                 _lexer.next();
    8740                                
     11573                                        _lexer.next();
     11574
    874111575                                        if (l == lex_double_slash)
    874211576                                        {
    8743                                                 if (n->rettype() != xpath_type_node_set) throw_error("Step has to be applied to node set");
     11577                                                if (n->rettype() != xpath_type_node_set)
     11578                                                        throw_error("Step has to be applied to node set");
    874411579
    874511580                                                n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
    874611581                                        }
    8747        
    8748                                 // select from location path
    8749                                 return parse_relative_location_path(n);
    8750                         }
    8751 
    8752                         return n;
    8753                 }
    8754                 else return parse_location_path();
    8755             }
    8756 
    8757             // UnionExpr ::= PathExpr | UnionExpr '|' PathExpr
    8758             xpath_ast_node* parse_union_expression()
    8759             {
    8760                 xpath_ast_node* n = parse_path_expression();
    8761 
    8762                 while (_lexer.current() == lex_union)
    8763                 {
    8764                         _lexer.next();
    8765 
    8766                                 xpath_ast_node* expr = parse_union_expression();
    8767 
    8768                                 if (n->rettype() != xpath_type_node_set || expr->rettype() != xpath_type_node_set)
     11582
     11583                                        // select from location path
     11584                                        return parse_relative_location_path(n);
     11585                                }
     11586
     11587                                return n;
     11588                        }
     11589                        else if (_lexer.current() == lex_minus)
     11590                        {
     11591                                _lexer.next();
     11592
     11593                                // precedence 7+ - only parses union expressions
     11594                                xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7);
     11595
     11596                                return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr);
     11597                        }
     11598                        else
     11599                        {
     11600                                return parse_location_path();
     11601                        }
     11602                }
     11603
     11604                struct binary_op_t
     11605                {
     11606                        ast_type_t asttype;
     11607                        xpath_value_type rettype;
     11608                        int precedence;
     11609
     11610                        binary_op_t(): asttype(ast_unknown), rettype(xpath_type_none), precedence(0)
     11611                        {
     11612                        }
     11613
     11614                        binary_op_t(ast_type_t asttype_, xpath_value_type rettype_, int precedence_): asttype(asttype_), rettype(rettype_), precedence(precedence_)
     11615                        {
     11616                        }
     11617
     11618                        static binary_op_t parse(xpath_lexer& lexer)
     11619                        {
     11620                                switch (lexer.current())
     11621                                {
     11622                                case lex_string:
     11623                                        if (lexer.contents() == PUGIXML_TEXT("or"))
     11624                                                return binary_op_t(ast_op_or, xpath_type_boolean, 1);
     11625                                        else if (lexer.contents() == PUGIXML_TEXT("and"))
     11626                                                return binary_op_t(ast_op_and, xpath_type_boolean, 2);
     11627                                        else if (lexer.contents() == PUGIXML_TEXT("div"))
     11628                                                return binary_op_t(ast_op_divide, xpath_type_number, 6);
     11629                                        else if (lexer.contents() == PUGIXML_TEXT("mod"))
     11630                                                return binary_op_t(ast_op_mod, xpath_type_number, 6);
     11631                                        else
     11632                                                return binary_op_t();
     11633
     11634                                case lex_equal:
     11635                                        return binary_op_t(ast_op_equal, xpath_type_boolean, 3);
     11636
     11637                                case lex_not_equal:
     11638                                        return binary_op_t(ast_op_not_equal, xpath_type_boolean, 3);
     11639
     11640                                case lex_less:
     11641                                        return binary_op_t(ast_op_less, xpath_type_boolean, 4);
     11642
     11643                                case lex_greater:
     11644                                        return binary_op_t(ast_op_greater, xpath_type_boolean, 4);
     11645
     11646                                case lex_less_or_equal:
     11647                                        return binary_op_t(ast_op_less_or_equal, xpath_type_boolean, 4);
     11648
     11649                                case lex_greater_or_equal:
     11650                                        return binary_op_t(ast_op_greater_or_equal, xpath_type_boolean, 4);
     11651
     11652                                case lex_plus:
     11653                                        return binary_op_t(ast_op_add, xpath_type_number, 5);
     11654
     11655                                case lex_minus:
     11656                                        return binary_op_t(ast_op_subtract, xpath_type_number, 5);
     11657
     11658                                case lex_multiply:
     11659                                        return binary_op_t(ast_op_multiply, xpath_type_number, 6);
     11660
     11661                                case lex_union:
     11662                                        return binary_op_t(ast_op_union, xpath_type_node_set, 7);
     11663
     11664                                default:
     11665                                        return binary_op_t();
     11666                                }
     11667                        }
     11668                };
     11669
     11670                xpath_ast_node* parse_expression_rec(xpath_ast_node* lhs, int limit)
     11671                {
     11672                        binary_op_t op = binary_op_t::parse(_lexer);
     11673
     11674                        while (op.asttype != ast_unknown && op.precedence >= limit)
     11675                        {
     11676                                _lexer.next();
     11677
     11678                                xpath_ast_node* rhs = parse_path_or_unary_expression();
     11679
     11680                                binary_op_t nextop = binary_op_t::parse(_lexer);
     11681
     11682                                while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)
     11683                                {
     11684                                        rhs = parse_expression_rec(rhs, nextop.precedence);
     11685
     11686                                        nextop = binary_op_t::parse(_lexer);
     11687                                }
     11688
     11689                                if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))
    876911690                                        throw_error("Union operator has to be applied to node sets");
    877011691
    8771                         n = new (alloc_node()) xpath_ast_node(ast_op_union, xpath_type_node_set, n, expr);
    8772                 }
    8773 
    8774                 return n;
    8775             }
    8776 
    8777             // UnaryExpr ::= UnionExpr | '-' UnaryExpr
    8778             xpath_ast_node* parse_unary_expression()
    8779             {
    8780                 if (_lexer.current() == lex_minus)
    8781                 {
    8782                         _lexer.next();
    8783 
    8784                                 xpath_ast_node* expr = parse_unary_expression();
    8785 
    8786                         return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr);
    8787                 }
    8788                 else return parse_union_expression();
    8789             }
    8790            
    8791             // MultiplicativeExpr ::= UnaryExpr
    8792             //                                            | MultiplicativeExpr '*' UnaryExpr
    8793             //                                            | MultiplicativeExpr 'div' UnaryExpr
    8794             //                                            | MultiplicativeExpr 'mod' UnaryExpr
    8795             xpath_ast_node* parse_multiplicative_expression()
    8796             {
    8797                 xpath_ast_node* n = parse_unary_expression();
    8798 
    8799                 while (_lexer.current() == lex_multiply || (_lexer.current() == lex_string &&
    8800                            (_lexer.contents() == PUGIXML_TEXT("mod") || _lexer.contents() == PUGIXML_TEXT("div"))))
    8801                 {
    8802                         ast_type_t op = _lexer.current() == lex_multiply ? ast_op_multiply :
    8803                                 _lexer.contents().begin[0] == 'd' ? ast_op_divide : ast_op_mod;
    8804                         _lexer.next();
    8805 
    8806                                 xpath_ast_node* expr = parse_unary_expression();
    8807 
    8808                         n = new (alloc_node()) xpath_ast_node(op, xpath_type_number, n, expr);
    8809                 }
    8810 
    8811                 return n;
    8812             }
    8813 
    8814             // AdditiveExpr ::= MultiplicativeExpr
    8815             //                                  | AdditiveExpr '+' MultiplicativeExpr
    8816             //                                  | AdditiveExpr '-' MultiplicativeExpr
    8817             xpath_ast_node* parse_additive_expression()
    8818             {
    8819                 xpath_ast_node* n = parse_multiplicative_expression();
    8820 
    8821                 while (_lexer.current() == lex_plus || _lexer.current() == lex_minus)
    8822                 {
    8823                         lexeme_t l = _lexer.current();
    8824 
    8825                         _lexer.next();
    8826 
    8827                                 xpath_ast_node* expr = parse_multiplicative_expression();
    8828 
    8829                         n = new (alloc_node()) xpath_ast_node(l == lex_plus ? ast_op_add : ast_op_subtract, xpath_type_number, n, expr);
    8830                 }
    8831 
    8832                 return n;
    8833             }
    8834 
    8835             // RelationalExpr ::= AdditiveExpr
    8836             //                                    | RelationalExpr '<' AdditiveExpr
    8837             //                                    | RelationalExpr '>' AdditiveExpr
    8838             //                                    | RelationalExpr '<=' AdditiveExpr
    8839             //                                    | RelationalExpr '>=' AdditiveExpr
    8840             xpath_ast_node* parse_relational_expression()
    8841             {
    8842                 xpath_ast_node* n = parse_additive_expression();
    8843 
    8844                 while (_lexer.current() == lex_less || _lexer.current() == lex_less_or_equal ||
    8845                            _lexer.current() == lex_greater || _lexer.current() == lex_greater_or_equal)
    8846                 {
    8847                         lexeme_t l = _lexer.current();
    8848                         _lexer.next();
    8849 
    8850                                 xpath_ast_node* expr = parse_additive_expression();
    8851 
    8852                         n = new (alloc_node()) xpath_ast_node(l == lex_less ? ast_op_less : l == lex_greater ? ast_op_greater :
    8853                                                         l == lex_less_or_equal ? ast_op_less_or_equal : ast_op_greater_or_equal, xpath_type_boolean, n, expr);
    8854                 }
    8855 
    8856                 return n;
    8857             }
    8858            
    8859             // EqualityExpr ::= RelationalExpr
    8860             //                                  | EqualityExpr '=' RelationalExpr
    8861             //                                  | EqualityExpr '!=' RelationalExpr
    8862             xpath_ast_node* parse_equality_expression()
    8863             {
    8864                 xpath_ast_node* n = parse_relational_expression();
    8865 
    8866                 while (_lexer.current() == lex_equal || _lexer.current() == lex_not_equal)
    8867                 {
    8868                         lexeme_t l = _lexer.current();
    8869 
    8870                         _lexer.next();
    8871 
    8872                                 xpath_ast_node* expr = parse_relational_expression();
    8873 
    8874                         n = new (alloc_node()) xpath_ast_node(l == lex_equal ? ast_op_equal : ast_op_not_equal, xpath_type_boolean, n, expr);
    8875                 }
    8876 
    8877                 return n;
    8878             }
    8879            
    8880             // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
    8881             xpath_ast_node* parse_and_expression()
    8882             {
    8883                 xpath_ast_node* n = parse_equality_expression();
    8884 
    8885                 while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("and"))
    8886                 {
    8887                         _lexer.next();
    8888 
    8889                                 xpath_ast_node* expr = parse_equality_expression();
    8890 
    8891                         n = new (alloc_node()) xpath_ast_node(ast_op_and, xpath_type_boolean, n, expr);
    8892                 }
    8893 
    8894                 return n;
    8895             }
    8896 
    8897             // OrExpr ::= AndExpr | OrExpr 'or' AndExpr
    8898             xpath_ast_node* parse_or_expression()
    8899             {
    8900                 xpath_ast_node* n = parse_and_expression();
    8901 
    8902                 while (_lexer.current() == lex_string && _lexer.contents() == PUGIXML_TEXT("or"))
    8903                 {
    8904                         _lexer.next();
    8905 
    8906                                 xpath_ast_node* expr = parse_and_expression();
    8907 
    8908                         n = new (alloc_node()) xpath_ast_node(ast_op_or, xpath_type_boolean, n, expr);
    8909                 }
    8910 
    8911                 return n;
    8912             }
    8913                
     11692                                lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs);
     11693
     11694                                op = binary_op_t::parse(_lexer);
     11695                        }
     11696
     11697                        return lhs;
     11698                }
     11699
    891411700                // Expr ::= OrExpr
     11701                // OrExpr ::= AndExpr | OrExpr 'or' AndExpr
     11702                // AndExpr ::= EqualityExpr | AndExpr 'and' EqualityExpr
     11703                // EqualityExpr ::= RelationalExpr
     11704                //                                      | EqualityExpr '=' RelationalExpr
     11705                //                                      | EqualityExpr '!=' RelationalExpr
     11706                // RelationalExpr ::= AdditiveExpr
     11707                //                                        | RelationalExpr '<' AdditiveExpr
     11708                //                                        | RelationalExpr '>' AdditiveExpr
     11709                //                                        | RelationalExpr '<=' AdditiveExpr
     11710                //                                        | RelationalExpr '>=' AdditiveExpr
     11711                // AdditiveExpr ::= MultiplicativeExpr
     11712                //                                      | AdditiveExpr '+' MultiplicativeExpr
     11713                //                                      | AdditiveExpr '-' MultiplicativeExpr
     11714                // MultiplicativeExpr ::= UnaryExpr
     11715                //                                                | MultiplicativeExpr '*' UnaryExpr
     11716                //                                                | MultiplicativeExpr 'div' UnaryExpr
     11717                //                                                | MultiplicativeExpr 'mod' UnaryExpr
    891511718                xpath_ast_node* parse_expression()
    891611719                {
    8917                         return parse_or_expression();
     11720                        return parse_expression_rec(parse_path_or_unary_expression(), 0);
    891811721                }
    891911722
     
    892511728                {
    892611729                        xpath_ast_node* result = parse_expression();
    8927                        
     11730
     11731                        // check if there are unparsed tokens left
    892811732                        if (_lexer.current() != lex_eof)
    8929                         {
    8930                                 // there are still unparsed tokens left, error
    893111733                                throw_error("Incorrect query");
    8932                         }
    8933                        
     11734
    893411735                        return result;
    893511736                }
     
    894911750        };
    895011751
    8951     struct xpath_query_impl
    8952     {
     11752        struct xpath_query_impl
     11753        {
    895311754                static xpath_query_impl* create()
    895411755                {
    8955                         void* memory = global_allocate(sizeof(xpath_query_impl));
    8956 
    8957             return new (memory) xpath_query_impl();
    8958                 }
    8959 
    8960                 static void destroy(void* ptr)
    8961                 {
    8962                         if (!ptr) return;
    8963                        
     11756                        void* memory = xml_memory::allocate(sizeof(xpath_query_impl));
     11757                        if (!memory) return 0;
     11758
     11759                        return new (memory) xpath_query_impl();
     11760                }
     11761
     11762                static void destroy(xpath_query_impl* impl)
     11763                {
    896411764                        // free all allocated pages
    8965                         static_cast<xpath_query_impl*>(ptr)->alloc.release();
     11765                        impl->alloc.release();
    896611766
    896711767                        // free allocator memory (with the first page)
    8968                         global_deallocate(ptr);
    8969                 }
    8970 
    8971         xpath_query_impl(): root(0), alloc(&block)
    8972         {
    8973             block.next = 0;
    8974         }
    8975 
    8976         xpath_ast_node* root;
    8977         xpath_allocator alloc;
    8978         xpath_memory_block block;
    8979     };
    8980 
    8981         xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd)
     11768                        xml_memory::deallocate(impl);
     11769                }
     11770
     11771                xpath_query_impl(): root(0), alloc(&block)
     11772                {
     11773                        block.next = 0;
     11774                        block.capacity = sizeof(block.data);
     11775                }
     11776
     11777                xpath_ast_node* root;
     11778                xpath_allocator alloc;
     11779                xpath_memory_block block;
     11780        };
     11781
     11782        PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd)
    898211783        {
    898311784                if (!impl) return xpath_string();
     
    899111792                return impl->root->eval_string(c, sd.stack);
    899211793        }
    8993 }
     11794
     11795        PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)
     11796        {
     11797                if (!impl) return 0;
     11798
     11799                if (impl->root->rettype() != xpath_type_node_set)
     11800                {
     11801                #ifdef PUGIXML_NO_EXCEPTIONS
     11802                        return 0;
     11803                #else
     11804                        xpath_parse_result res;
     11805                        res.error = "Expression does not evaluate to node set";
     11806
     11807                        throw xpath_exception(res);
     11808                #endif
     11809                }
     11810
     11811                return impl->root;
     11812        }
     11813PUGI__NS_END
    899411814
    899511815namespace pugi
    899611816{
    899711817#ifndef PUGIXML_NO_EXCEPTIONS
    8998         xpath_exception::xpath_exception(const xpath_parse_result& result): _result(result)
    8999         {
    9000                 assert(result.error);
    9001         }
    9002        
    9003         const char* xpath_exception::what() const throw()
     11818        PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_)
     11819        {
     11820                assert(_result.error);
     11821        }
     11822
     11823        PUGI__FN const char* xpath_exception::what() const throw()
    900411824        {
    900511825                return _result.error;
    900611826        }
    900711827
    9008         const xpath_parse_result& xpath_exception::result() const
     11828        PUGI__FN const xpath_parse_result& xpath_exception::result() const
    900911829        {
    901011830                return _result;
    901111831        }
    901211832#endif
    9013        
    9014         xpath_node::xpath_node()
    9015         {
    9016         }
    9017                
    9018         xpath_node::xpath_node(const xml_node& node): _node(node)
    9019         {
    9020         }
    9021                
    9022         xpath_node::xpath_node(const xml_attribute& attribute, const xml_node& parent): _node(attribute ? parent : xml_node()), _attribute(attribute)
    9023         {
    9024         }
    9025 
    9026         xml_node xpath_node::node() const
     11833
     11834        PUGI__FN xpath_node::xpath_node()
     11835        {
     11836        }
     11837
     11838        PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_)
     11839        {
     11840        }
     11841
     11842        PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
     11843        {
     11844        }
     11845
     11846        PUGI__FN xml_node xpath_node::node() const
    902711847        {
    902811848                return _attribute ? xml_node() : _node;
    902911849        }
    9030                
    9031         xml_attribute xpath_node::attribute() const
     11850
     11851        PUGI__FN xml_attribute xpath_node::attribute() const
    903211852        {
    903311853                return _attribute;
    903411854        }
    9035        
    9036         xml_node xpath_node::parent() const
     11855
     11856        PUGI__FN xml_node xpath_node::parent() const
    903711857        {
    903811858                return _attribute ? _node : _node.parent();
    903911859        }
    904011860
    9041         xpath_node::operator xpath_node::unspecified_bool_type() const
    9042         {
    9043                 return (_node || _attribute) ? &xpath_node::_node : 0;
    9044         }
    9045        
    9046         bool xpath_node::operator!() const
     11861        PUGI__FN static void unspecified_bool_xpath_node(xpath_node***)
     11862        {
     11863        }
     11864
     11865        PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const
     11866        {
     11867                return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
     11868        }
     11869
     11870        PUGI__FN bool xpath_node::operator!() const
    904711871        {
    904811872                return !(_node || _attribute);
    904911873        }
    905011874
    9051         bool xpath_node::operator==(const xpath_node& n) const
     11875        PUGI__FN bool xpath_node::operator==(const xpath_node& n) const
    905211876        {
    905311877                return _node == n._node && _attribute == n._attribute;
    905411878        }
    9055        
    9056         bool xpath_node::operator!=(const xpath_node& n) const
     11879
     11880        PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const
    905711881        {
    905811882                return _node != n._node || _attribute != n._attribute;
     
    906011884
    906111885#ifdef __BORLANDC__
    9062         bool operator&&(const xpath_node& lhs, bool rhs)
     11886        PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs)
    906311887        {
    906411888                return (bool)lhs && rhs;
    906511889        }
    906611890
    9067         bool operator||(const xpath_node& lhs, bool rhs)
     11891        PUGI__FN bool operator||(const xpath_node& lhs, bool rhs)
    906811892        {
    906911893                return (bool)lhs || rhs;
     
    907111895#endif
    907211896
    9073         void xpath_node_set::_assign(const_iterator begin, const_iterator end)
    9074         {
    9075                 assert(begin <= end);
    9076 
    9077                 size_t size = static_cast<size_t>(end - begin);
    9078 
    9079                 if (size <= 1)
     11897        PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)
     11898        {
     11899                assert(begin_ <= end_);
     11900
     11901                size_t size_ = static_cast<size_t>(end_ - begin_);
     11902
     11903                if (size_ <= 1)
    908011904                {
    908111905                        // deallocate old buffer
    9082                         if (_begin != &_storage) global_deallocate(_begin);
     11906                        if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
    908311907
    908411908                        // use internal buffer
    9085                         if (begin != end) _storage = *begin;
     11909                        if (begin_ != end_) _storage = *begin_;
    908611910
    908711911                        _begin = &_storage;
    9088                         _end = &_storage + size;
     11912                        _end = &_storage + size_;
     11913                        _type = type_;
    908911914                }
    909011915                else
    909111916                {
    909211917                        // make heap copy
    9093                         xpath_node* storage = static_cast<xpath_node*>(global_allocate(size * sizeof(xpath_node)));
     11918                        xpath_node* storage = static_cast<xpath_node*>(impl::xml_memory::allocate(size_ * sizeof(xpath_node)));
    909411919
    909511920                        if (!storage)
     
    910211927                        }
    910311928
    9104                         memcpy(storage, begin, size * sizeof(xpath_node));
    9105                        
     11929                        memcpy(storage, begin_, size_ * sizeof(xpath_node));
     11930
    910611931                        // deallocate old buffer
    9107                         if (_begin != &_storage) global_deallocate(_begin);
     11932                        if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
    910811933
    910911934                        // finalize
    911011935                        _begin = storage;
    9111                         _end = storage + size;
    9112                 }
    9113         }
    9114 
    9115         xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage)
    9116         {
    9117         }
    9118 
    9119         xpath_node_set::xpath_node_set(const_iterator begin, const_iterator end, type_t type): _type(type), _begin(&_storage), _end(&_storage)
    9120         {
    9121                 _assign(begin, end);
    9122         }
    9123 
    9124         xpath_node_set::~xpath_node_set()
    9125         {
    9126                 if (_begin != &_storage) global_deallocate(_begin);
    9127         }
    9128                
    9129         xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage)
    9130         {
    9131                 _assign(ns._begin, ns._end);
    9132         }
    9133        
    9134         xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
     11936                        _end = storage + size_;
     11937                        _type = type_;
     11938                }
     11939        }
     11940
     11941#ifdef PUGIXML_HAS_MOVE
     11942        PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs)
     11943        {
     11944                _type = rhs._type;
     11945                _storage = rhs._storage;
     11946                _begin = (rhs._begin == &rhs._storage) ? &_storage : rhs._begin;
     11947                _end = _begin + (rhs._end - rhs._begin);
     11948
     11949                rhs._type = type_unsorted;
     11950                rhs._begin = &rhs._storage;
     11951                rhs._end = rhs._begin;
     11952        }
     11953#endif
     11954
     11955        PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage)
     11956        {
     11957        }
     11958
     11959        PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(&_storage), _end(&_storage)
     11960        {
     11961                _assign(begin_, end_, type_);
     11962        }
     11963
     11964        PUGI__FN xpath_node_set::~xpath_node_set()
     11965        {
     11966                if (_begin != &_storage)
     11967                        impl::xml_memory::deallocate(_begin);
     11968        }
     11969
     11970        PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage)
     11971        {
     11972                _assign(ns._begin, ns._end, ns._type);
     11973        }
     11974
     11975        PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
    913511976        {
    913611977                if (this == &ns) return *this;
    9137                
    9138                 _type = ns._type;
    9139                 _assign(ns._begin, ns._end);
     11978
     11979                _assign(ns._begin, ns._end, ns._type);
    914011980
    914111981                return *this;
    914211982        }
    914311983
    9144         xpath_node_set::type_t xpath_node_set::type() const
     11984#ifdef PUGIXML_HAS_MOVE
     11985        PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs): _type(type_unsorted), _begin(&_storage), _end(&_storage)
     11986        {
     11987                _move(rhs);
     11988        }
     11989
     11990        PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs)
     11991        {
     11992                if (this == &rhs) return *this;
     11993
     11994                if (_begin != &_storage)
     11995                        impl::xml_memory::deallocate(_begin);
     11996
     11997                _move(rhs);
     11998
     11999                return *this;
     12000        }
     12001#endif
     12002
     12003        PUGI__FN xpath_node_set::type_t xpath_node_set::type() const
    914512004        {
    914612005                return _type;
    914712006        }
    9148                
    9149         size_t xpath_node_set::size() const
     12007
     12008        PUGI__FN size_t xpath_node_set::size() const
    915012009        {
    915112010                return _end - _begin;
    915212011        }
    9153                
    9154         bool xpath_node_set::empty() const
     12012
     12013        PUGI__FN bool xpath_node_set::empty() const
    915512014        {
    915612015                return _begin == _end;
    915712016        }
    9158                
    9159         const xpath_node& xpath_node_set::operator[](size_t index) const
     12017
     12018        PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const
    916012019        {
    916112020                assert(index < size());
     
    916312022        }
    916412023
    9165         xpath_node_set::const_iterator xpath_node_set::begin() const
     12024        PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const
    916612025        {
    916712026                return _begin;
    916812027        }
    9169                
    9170         xpath_node_set::const_iterator xpath_node_set::end() const
     12028
     12029        PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const
    917112030        {
    917212031                return _end;
    917312032        }
    9174        
    9175         void xpath_node_set::sort(bool reverse)
    9176         {
    9177                 _type = xpath_sort(_begin, _end, _type, reverse);
    9178         }
    9179 
    9180         xpath_node xpath_node_set::first() const
    9181         {
    9182                 return xpath_first(_begin, _end, _type);
    9183         }
    9184 
    9185     xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
    9186     {
    9187     }
    9188 
    9189     xpath_parse_result::operator bool() const
    9190     {
    9191         return error == 0;
    9192     }
    9193         const char* xpath_parse_result::description() const
     12033
     12034        PUGI__FN void xpath_node_set::sort(bool reverse)
     12035        {
     12036                _type = impl::xpath_sort(_begin, _end, _type, reverse);
     12037        }
     12038
     12039        PUGI__FN xpath_node xpath_node_set::first() const
     12040        {
     12041                return impl::xpath_first(_begin, _end, _type);
     12042        }
     12043
     12044        PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
     12045        {
     12046        }
     12047
     12048        PUGI__FN xpath_parse_result::operator bool() const
     12049        {
     12050                return error == 0;
     12051        }
     12052
     12053        PUGI__FN const char* xpath_parse_result::description() const
    919412054        {
    919512055                return error ? error : "No error";
    919612056        }
    919712057
    9198         xpath_variable::xpath_variable()
    9199     {
    9200     }
    9201 
    9202         const char_t* xpath_variable::name() const
     12058        PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0)
     12059        {
     12060        }
     12061
     12062        PUGI__FN const char_t* xpath_variable::name() const
    920312063        {
    920412064                switch (_type)
    920512065                {
    920612066                case xpath_type_node_set:
    9207                         return static_cast<const xpath_variable_node_set*>(this)->name;
     12067                        return static_cast<const impl::xpath_variable_node_set*>(this)->name;
    920812068
    920912069                case xpath_type_number:
    9210                         return static_cast<const xpath_variable_number*>(this)->name;
     12070                        return static_cast<const impl::xpath_variable_number*>(this)->name;
    921112071
    921212072                case xpath_type_string:
    9213                         return static_cast<const xpath_variable_string*>(this)->name;
     12073                        return static_cast<const impl::xpath_variable_string*>(this)->name;
    921412074
    921512075                case xpath_type_boolean:
    9216                         return static_cast<const xpath_variable_boolean*>(this)->name;
     12076                        return static_cast<const impl::xpath_variable_boolean*>(this)->name;
    921712077
    921812078                default:
    9219                         assert(!"Invalid variable type");
     12079                        assert(false && "Invalid variable type");
    922012080                        return 0;
    922112081                }
    922212082        }
    922312083
    9224         xpath_value_type xpath_variable::type() const
     12084        PUGI__FN xpath_value_type xpath_variable::type() const
    922512085        {
    922612086                return _type;
    922712087        }
    922812088
    9229         bool xpath_variable::get_boolean() const
    9230         {
    9231                 return (_type == xpath_type_boolean) ? static_cast<const xpath_variable_boolean*>(this)->value : false;
    9232         }
    9233 
    9234         double xpath_variable::get_number() const
    9235         {
    9236                 return (_type == xpath_type_number) ? static_cast<const xpath_variable_number*>(this)->value : gen_nan();
    9237         }
    9238 
    9239         const char_t* xpath_variable::get_string() const
    9240         {
    9241                 const char_t* value = (_type == xpath_type_string) ? static_cast<const xpath_variable_string*>(this)->value : 0;
     12089        PUGI__FN bool xpath_variable::get_boolean() const
     12090        {
     12091                return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
     12092        }
     12093
     12094        PUGI__FN double xpath_variable::get_number() const
     12095        {
     12096                return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();
     12097        }
     12098
     12099        PUGI__FN const char_t* xpath_variable::get_string() const
     12100        {
     12101                const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0;
    924212102                return value ? value : PUGIXML_TEXT("");
    924312103        }
    924412104
    9245         const xpath_node_set& xpath_variable::get_node_set() const
    9246         {
    9247                 return (_type == xpath_type_node_set) ? static_cast<const xpath_variable_node_set*>(this)->value : dummy_node_set;
    9248         }
    9249 
    9250         bool xpath_variable::set(bool value)
     12105        PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const
     12106        {
     12107                return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
     12108        }
     12109
     12110        PUGI__FN bool xpath_variable::set(bool value)
    925112111        {
    925212112                if (_type != xpath_type_boolean) return false;
    925312113
    9254                 static_cast<xpath_variable_boolean*>(this)->value = value;
     12114                static_cast<impl::xpath_variable_boolean*>(this)->value = value;
    925512115                return true;
    925612116        }
    925712117
    9258         bool xpath_variable::set(double value)
     12118        PUGI__FN bool xpath_variable::set(double value)
    925912119        {
    926012120                if (_type != xpath_type_number) return false;
    926112121
    9262                 static_cast<xpath_variable_number*>(this)->value = value;
     12122                static_cast<impl::xpath_variable_number*>(this)->value = value;
    926312123                return true;
    926412124        }
    926512125
    9266         bool xpath_variable::set(const char_t* value)
     12126        PUGI__FN bool xpath_variable::set(const char_t* value)
    926712127        {
    926812128                if (_type != xpath_type_string) return false;
    926912129
    9270                 xpath_variable_string* var = static_cast<xpath_variable_string*>(this);
     12130                impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);
    927112131
    927212132                // duplicate string
    9273                 size_t size = (strlength(value) + 1) * sizeof(char_t);
    9274 
    9275                 char_t* copy = static_cast<char_t*>(global_allocate(size));
     12133                size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
     12134
     12135                char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));
    927612136                if (!copy) return false;
    927712137
     
    927912139
    928012140                // replace old string
    9281                 if (var->value) global_deallocate(var->value);
     12141                if (var->value) impl::xml_memory::deallocate(var->value);
    928212142                var->value = copy;
    928312143
     
    928512145        }
    928612146
    9287         bool xpath_variable::set(const xpath_node_set& value)
     12147        PUGI__FN bool xpath_variable::set(const xpath_node_set& value)
    928812148        {
    928912149                if (_type != xpath_type_node_set) return false;
    929012150
    9291                 static_cast<xpath_variable_node_set*>(this)->value = value;
     12151                static_cast<impl::xpath_variable_node_set*>(this)->value = value;
    929212152                return true;
    929312153        }
    929412154
    9295         xpath_variable_set::xpath_variable_set()
    9296         {
    9297                 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0;
    9298         }
    9299 
    9300         xpath_variable_set::~xpath_variable_set()
     12155        PUGI__FN xpath_variable_set::xpath_variable_set()
    930112156        {
    930212157                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
    9303                 {
    9304                         xpath_variable* var = _data[i];
    9305 
    9306                         while (var)
    9307                         {
    9308                                 xpath_variable* next = var->_next;
    9309 
    9310                                 delete_xpath_variable(var->_type, var);
    9311 
    9312                                 var = next;
    9313                         }
    9314                 }
    9315         }
    9316 
    9317         xpath_variable* xpath_variable_set::find(const char_t* name) const
     12158                        _data[i] = 0;
     12159        }
     12160
     12161        PUGI__FN xpath_variable_set::~xpath_variable_set()
     12162        {
     12163                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12164                        _destroy(_data[i]);
     12165        }
     12166
     12167        PUGI__FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs)
     12168        {
     12169                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12170                        _data[i] = 0;
     12171
     12172                _assign(rhs);
     12173        }
     12174
     12175        PUGI__FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs)
     12176        {
     12177                if (this == &rhs) return *this;
     12178
     12179                _assign(rhs);
     12180
     12181                return *this;
     12182        }
     12183
     12184#ifdef PUGIXML_HAS_MOVE
     12185        PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs)
     12186        {
     12187                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12188                {
     12189                        _data[i] = rhs._data[i];
     12190                        rhs._data[i] = 0;
     12191                }
     12192        }
     12193
     12194        PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs)
     12195        {
     12196                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12197                {
     12198                        _destroy(_data[i]);
     12199
     12200                        _data[i] = rhs._data[i];
     12201                        rhs._data[i] = 0;
     12202                }
     12203
     12204                return *this;
     12205        }
     12206#endif
     12207
     12208        PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs)
     12209        {
     12210                xpath_variable_set temp;
     12211
     12212                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12213                        if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))
     12214                                return;
     12215
     12216                _swap(temp);
     12217        }
     12218
     12219        PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs)
     12220        {
     12221                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12222                {
     12223                        xpath_variable* chain = _data[i];
     12224
     12225                        _data[i] = rhs._data[i];
     12226                        rhs._data[i] = chain;
     12227                }
     12228        }
     12229
     12230        PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const
    931812231        {
    931912232                const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
    9320                 size_t hash = hash_string(name) % hash_size;
     12233                size_t hash = impl::hash_string(name) % hash_size;
    932112234
    932212235                // look for existing variable
    932312236                for (xpath_variable* var = _data[hash]; var; var = var->_next)
    9324                         if (strequal(var->name(), name))
     12237                        if (impl::strequal(var->name(), name))
    932512238                                return var;
    932612239
     
    932812241        }
    932912242
    9330         xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
     12243        PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)
     12244        {
     12245                xpath_variable* last = 0;
     12246
     12247                while (var)
     12248                {
     12249                        // allocate storage for new variable
     12250                        xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
     12251                        if (!nvar) return false;
     12252
     12253                        // link the variable to the result immediately to handle failures gracefully
     12254                        if (last)
     12255                                last->_next = nvar;
     12256                        else
     12257                                *out_result = nvar;
     12258
     12259                        last = nvar;
     12260
     12261                        // copy the value; this can fail due to out-of-memory conditions
     12262                        if (!impl::copy_xpath_variable(nvar, var)) return false;
     12263
     12264                        var = var->_next;
     12265                }
     12266
     12267                return true;
     12268        }
     12269
     12270        PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var)
     12271        {
     12272                while (var)
     12273                {
     12274                        xpath_variable* next = var->_next;
     12275
     12276                        impl::delete_xpath_variable(var->_type, var);
     12277
     12278                        var = next;
     12279                }
     12280        }
     12281
     12282        PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
    933112283        {
    933212284                const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
    9333                 size_t hash = hash_string(name) % hash_size;
     12285                size_t hash = impl::hash_string(name) % hash_size;
    933412286
    933512287                // look for existing variable
    933612288                for (xpath_variable* var = _data[hash]; var; var = var->_next)
    9337                         if (strequal(var->name(), name))
     12289                        if (impl::strequal(var->name(), name))
    933812290                                return var->type() == type ? var : 0;
    933912291
    934012292                // add new variable
    9341                 xpath_variable* result = new_xpath_variable(type, name);
     12293                xpath_variable* result = impl::new_xpath_variable(type, name);
    934212294
    934312295                if (result)
    934412296                {
    9345                         result->_type = type;
    934612297                        result->_next = _data[hash];
    934712298
     
    935212303        }
    935312304
    9354         bool xpath_variable_set::set(const char_t* name, bool value)
     12305        PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value)
    935512306        {
    935612307                xpath_variable* var = add(name, xpath_type_boolean);
     
    935812309        }
    935912310
    9360         bool xpath_variable_set::set(const char_t* name, double value)
     12311        PUGI__FN bool xpath_variable_set::set(const char_t* name, double value)
    936112312        {
    936212313                xpath_variable* var = add(name, xpath_type_number);
     
    936412315        }
    936512316
    9366         bool xpath_variable_set::set(const char_t* name, const char_t* value)
     12317        PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value)
    936712318        {
    936812319                xpath_variable* var = add(name, xpath_type_string);
     
    937012321        }
    937112322
    9372         bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
     12323        PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
    937312324        {
    937412325                xpath_variable* var = add(name, xpath_type_node_set);
     
    937612327        }
    937712328
    9378         xpath_variable* xpath_variable_set::get(const char_t* name)
    9379         {
    9380                 return find(name);
    9381         }
    9382 
    9383         const xpath_variable* xpath_variable_set::get(const char_t* name) const
    9384         {
    9385                 return find(name);
    9386         }
    9387 
    9388         xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
    9389         {
    9390                 xpath_query_impl* impl = xpath_query_impl::create();
    9391 
    9392                 if (!impl)
     12329        PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name)
     12330        {
     12331                return _find(name);
     12332        }
     12333
     12334        PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
     12335        {
     12336                return _find(name);
     12337        }
     12338
     12339        PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
     12340        {
     12341                impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
     12342
     12343                if (!qimpl)
    939312344                {
    939412345                #ifdef PUGIXML_NO_EXCEPTIONS
    939512346                        _result.error = "Out of memory";
    9396         #else
     12347                #else
    939712348                        throw std::bad_alloc();
    939812349                #endif
     
    940012351                else
    940112352                {
    9402                         buffer_holder impl_holder(impl, xpath_query_impl::destroy);
    9403 
    9404                         impl->root = xpath_parser::parse(query, variables, &impl->alloc, &_result);
    9405 
    9406                         if (impl->root)
    9407                         {
    9408                 _impl = static_cast<xpath_query_impl*>(impl_holder.release());
     12353                        using impl::auto_deleter; // MSVC7 workaround
     12354                        auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);
     12355
     12356                        qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
     12357
     12358                        if (qimpl->root)
     12359                        {
     12360                                qimpl->root->optimize(&qimpl->alloc);
     12361
     12362                                _impl = impl.release();
    940912363                                _result.error = 0;
    941012364                        }
     
    941212366        }
    941312367
    9414         xpath_query::~xpath_query()
    9415         {
    9416                 xpath_query_impl::destroy(_impl);
    9417         }
    9418 
    9419         xpath_value_type xpath_query::return_type() const
     12368        PUGI__FN xpath_query::xpath_query(): _impl(0)
     12369        {
     12370        }
     12371
     12372        PUGI__FN xpath_query::~xpath_query()
     12373        {
     12374                if (_impl)
     12375                        impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
     12376        }
     12377
     12378#ifdef PUGIXML_HAS_MOVE
     12379        PUGI__FN xpath_query::xpath_query(xpath_query&& rhs)
     12380        {
     12381                _impl = rhs._impl;
     12382                _result = rhs._result;
     12383                rhs._impl = 0;
     12384                rhs._result = xpath_parse_result();
     12385        }
     12386
     12387        PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs)
     12388        {
     12389                if (this == &rhs) return *this;
     12390
     12391                if (_impl)
     12392                        impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
     12393
     12394                _impl = rhs._impl;
     12395                _result = rhs._result;
     12396                rhs._impl = 0;
     12397                rhs._result = xpath_parse_result();
     12398
     12399                return *this;
     12400        }
     12401#endif
     12402
     12403        PUGI__FN xpath_value_type xpath_query::return_type() const
    942012404        {
    942112405                if (!_impl) return xpath_type_none;
    942212406
    9423                 return static_cast<xpath_query_impl*>(_impl)->root->rettype();
    9424         }
    9425 
    9426         bool xpath_query::evaluate_boolean(const xpath_node& n) const
     12407                return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();
     12408        }
     12409
     12410        PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const
    942712411        {
    942812412                if (!_impl) return false;
    9429                
    9430                 xpath_context c(n, 1, 1);
    9431                 xpath_stack_data sd;
     12413
     12414                impl::xpath_context c(n, 1, 1);
     12415                impl::xpath_stack_data sd;
    943212416
    943312417        #ifdef PUGIXML_NO_EXCEPTIONS
    943412418                if (setjmp(sd.error_handler)) return false;
    943512419        #endif
    9436                
    9437                 return static_cast<xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
    9438         }
    9439        
    9440         double xpath_query::evaluate_number(const xpath_node& n) const
    9441         {
    9442                 if (!_impl) return gen_nan();
    9443                
    9444                 xpath_context c(n, 1, 1);
    9445                 xpath_stack_data sd;
     12420
     12421                return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
     12422        }
     12423
     12424        PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
     12425        {
     12426                if (!_impl) return impl::gen_nan();
     12427
     12428                impl::xpath_context c(n, 1, 1);
     12429                impl::xpath_stack_data sd;
    944612430
    944712431        #ifdef PUGIXML_NO_EXCEPTIONS
    9448                 if (setjmp(sd.error_handler)) return gen_nan();
     12432                if (setjmp(sd.error_handler)) return impl::gen_nan();
    944912433        #endif
    945012434
    9451                 return static_cast<xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
     12435                return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
    945212436        }
    945312437
    945412438#ifndef PUGIXML_NO_STL
    9455         string_t xpath_query::evaluate_string(const xpath_node& n) const
    9456         {
    9457                 xpath_stack_data sd;
    9458 
    9459                 return evaluate_string_impl(static_cast<xpath_query_impl*>(_impl), n, sd).c_str();
     12439        PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const
     12440        {
     12441                impl::xpath_stack_data sd;
     12442
     12443                impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd);
     12444
     12445                return string_t(r.c_str(), r.length());
    946012446        }
    946112447#endif
    946212448
    9463         size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
    9464         {
    9465                 xpath_stack_data sd;
    9466 
    9467                 xpath_string r = evaluate_string_impl(static_cast<xpath_query_impl*>(_impl), n, sd);
     12449        PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
     12450        {
     12451                impl::xpath_stack_data sd;
     12452
     12453                impl::xpath_string r = impl::evaluate_string_impl(static_cast<impl::xpath_query_impl*>(_impl), n, sd);
    946812454
    946912455                size_t full_size = r.length() + 1;
    9470                
     12456
    947112457                if (capacity > 0)
    9472         {
    9473             size_t size = (full_size < capacity) ? full_size : capacity;
    9474             assert(size > 0);
    9475 
    9476             memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
    9477             buffer[size - 1] = 0;
    9478         }
    9479                
     12458                {
     12459                        size_t size = (full_size < capacity) ? full_size : capacity;
     12460                        assert(size > 0);
     12461
     12462                        memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
     12463                        buffer[size - 1] = 0;
     12464                }
     12465
    948012466                return full_size;
    948112467        }
    948212468
    9483         xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const
    9484         {
    9485                 if (!_impl) return xpath_node_set();
    9486 
    9487         xpath_ast_node* root = static_cast<xpath_query_impl*>(_impl)->root;
    9488 
    9489                 if (root->rettype() != xpath_type_node_set)
    9490                 {
    9491                 #ifdef PUGIXML_NO_EXCEPTIONS
    9492                         return xpath_node_set();
    9493                 #else
    9494                         xpath_parse_result result;
    9495                         result.error = "Expression does not evaluate to node set";
    9496 
    9497                         throw xpath_exception(result);
    9498                 #endif
    9499                 }
    9500                
    9501                 xpath_context c(n, 1, 1);
    9502                 xpath_stack_data sd;
     12469        PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const
     12470        {
     12471                impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
     12472                if (!root) return xpath_node_set();
     12473
     12474                impl::xpath_context c(n, 1, 1);
     12475                impl::xpath_stack_data sd;
    950312476
    950412477        #ifdef PUGIXML_NO_EXCEPTIONS
     
    950612479        #endif
    950712480
    9508                 xpath_node_set_raw r = root->eval_node_set(c, sd.stack);
     12481                impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
    950912482
    951012483                return xpath_node_set(r.begin(), r.end(), r.type());
    951112484        }
    951212485
    9513         const xpath_parse_result& xpath_query::result() const
     12486        PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const
     12487        {
     12488                impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
     12489                if (!root) return xpath_node();
     12490
     12491                impl::xpath_context c(n, 1, 1);
     12492                impl::xpath_stack_data sd;
     12493
     12494        #ifdef PUGIXML_NO_EXCEPTIONS
     12495                if (setjmp(sd.error_handler)) return xpath_node();
     12496        #endif
     12497
     12498                impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);
     12499
     12500                return r.first();
     12501        }
     12502
     12503        PUGI__FN const xpath_parse_result& xpath_query::result() const
    951412504        {
    951512505                return _result;
    951612506        }
    951712507
    9518         xpath_query::operator xpath_query::unspecified_bool_type() const
    9519         {
    9520                 return _impl ? &xpath_query::_impl : 0;
    9521         }
    9522 
    9523         bool xpath_query::operator!() const
     12508        PUGI__FN static void unspecified_bool_xpath_query(xpath_query***)
     12509        {
     12510        }
     12511
     12512        PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
     12513        {
     12514                return _impl ? unspecified_bool_xpath_query : 0;
     12515        }
     12516
     12517        PUGI__FN bool xpath_query::operator!() const
    952412518        {
    952512519                return !_impl;
    952612520        }
    952712521
    9528         xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const
     12522        PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const
     12523        {
     12524                xpath_query q(query, variables);
     12525                return select_node(q);
     12526        }
     12527
     12528        PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const
     12529        {
     12530                return query.evaluate_node(*this);
     12531        }
     12532
     12533        PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const
     12534        {
     12535                xpath_query q(query, variables);
     12536                return select_nodes(q);
     12537        }
     12538
     12539        PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const
     12540        {
     12541                return query.evaluate_node_set(*this);
     12542        }
     12543
     12544        PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const
    952912545        {
    953012546                xpath_query q(query, variables);
     
    953212548        }
    953312549
    9534         xpath_node xml_node::select_single_node(const xpath_query& query) const
    9535         {
    9536                 xpath_node_set s = query.evaluate_node_set(*this);
    9537                 return s.empty() ? xpath_node() : s.first();
    9538         }
    9539 
    9540         xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const
    9541         {
    9542                 xpath_query q(query, variables);
    9543                 return select_nodes(q);
    9544         }
    9545 
    9546         xpath_node_set xml_node::select_nodes(const xpath_query& query) const
    9547         {
    9548                 return query.evaluate_node_set(*this);
     12550        PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const
     12551        {
     12552                return query.evaluate_node(*this);
    954912553        }
    955012554}
     
    955212556#endif
    955312557
     12558#ifdef __BORLANDC__
     12559#       pragma option pop
     12560#endif
     12561
     12562// Intel C++ does not properly keep warning state for function templates,
     12563// so popping warning state at the end of translation unit leads to warnings in the middle.
     12564#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
     12565#       pragma warning(pop)
     12566#endif
     12567
     12568// Undefine all local macros (makes sure we're not leaking macros in header-only mode)
     12569#undef PUGI__NO_INLINE
     12570#undef PUGI__UNLIKELY
     12571#undef PUGI__STATIC_ASSERT
     12572#undef PUGI__DMC_VOLATILE
     12573#undef PUGI__MSVC_CRT_VERSION
     12574#undef PUGI__NS_BEGIN
     12575#undef PUGI__NS_END
     12576#undef PUGI__FN
     12577#undef PUGI__FN_NO_INLINE
     12578#undef PUGI__GETHEADER_IMPL
     12579#undef PUGI__GETPAGE_IMPL
     12580#undef PUGI__GETPAGE
     12581#undef PUGI__NODETYPE
     12582#undef PUGI__IS_CHARTYPE_IMPL
     12583#undef PUGI__IS_CHARTYPE
     12584#undef PUGI__IS_CHARTYPEX
     12585#undef PUGI__ENDSWITH
     12586#undef PUGI__SKIPWS
     12587#undef PUGI__OPTSET
     12588#undef PUGI__PUSHNODE
     12589#undef PUGI__POPNODE
     12590#undef PUGI__SCANFOR
     12591#undef PUGI__SCANWHILE
     12592#undef PUGI__SCANWHILE_UNROLL
     12593#undef PUGI__ENDSEG
     12594#undef PUGI__THROW_ERROR
     12595#undef PUGI__CHECK_ERROR
     12596
     12597#endif
     12598
    955412599/**
    9555  * Copyright (c) 2006-2010 Arseny Kapoulkine
     12600 * Copyright (c) 2006-2016 Arseny Kapoulkine
    955612601 *
    955712602 * Permission is hereby granted, free of charge, to any person
     
    956612611 * The above copyright notice and this permission notice shall be
    956712612 * included in all copies or substantial portions of the Software.
    9568  * 
     12613 *
    956912614 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    957012615 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
Note: See TracChangeset for help on using the changeset viewer.