Changeset 33a694 for ThirdParty


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.
Location:
ThirdParty/vmg/src/thirdparty/pugixml
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • ThirdParty/vmg/src/thirdparty/pugixml/pugiconfig.hpp

    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 *
     
    1818// #define PUGIXML_WCHAR_MODE
    1919
     20// Uncomment this to enable compact mode
     21// #define PUGIXML_COMPACT
     22
    2023// Uncomment this to disable XPath
    2124// #define PUGIXML_NO_XPATH
    2225
    2326// Uncomment this to disable STL
    24 // Note: you can't use XPath with PUGIXML_NO_STL
    2527// #define PUGIXML_NO_STL
    2628
    2729// Uncomment this to disable exceptions
    28 // Note: you can't use XPath with PUGIXML_NO_EXCEPTIONS
    2930// #define PUGIXML_NO_EXCEPTIONS
    3031
     
    3536// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
    3637
     38// Tune these constants to adjust memory-related behavior
     39// #define PUGIXML_MEMORY_PAGE_SIZE 32768
     40// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
     41// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
     42
     43// Uncomment this to switch to header-only version
     44// #define PUGIXML_HEADER_ONLY
     45
     46// Uncomment this to enable long long support
     47// #define PUGIXML_HAS_LONG_LONG
     48
    3749#endif
    3850
    3951/**
    40  * Copyright (c) 2006-2010 Arseny Kapoulkine
     52 * Copyright (c) 2006-2016 Arseny Kapoulkine
    4153 *
    4254 * Permission is hereby granted, free of charge, to any person
     
    5163 * The above copyright notice and this permission notice shall be
    5264 * included in all copies or substantial portions of the Software.
    53  * 
     65 *
    5466 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    5567 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  • 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
  • ThirdParty/vmg/src/thirdparty/pugixml/pugixml.hpp

    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 PUGIXML_VERSION
     15// Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons
     16#       define PUGIXML_VERSION 180
     17#endif
     18
     19// Include user configuration file (this can define various configuration macros)
     20#include "pugiconfig.hpp"
     21
    1422#ifndef HEADER_PUGIXML_HPP
    1523#define HEADER_PUGIXML_HPP
    1624
    17 #include "pugiconfig.hpp"
    18 
     25// Include stddef.h for size_t and ptrdiff_t
     26#include <stddef.h>
     27
     28// Include exception header for XPath
     29#if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS)
     30#       include <exception>
     31#endif
     32
     33// Include STL headers
    1934#ifndef PUGIXML_NO_STL
    20 namespace std
    21 {
    22         struct bidirectional_iterator_tag;
    23 
    24 #ifdef __SUNPRO_CC
    25         // Sun C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions
    26         template <class _T> class allocator;
    27         template <class _charT> struct char_traits;
    28         template <class _charT, class _Traits> class basic_istream;
    29         template <class _charT, class _Traits> class basic_ostream;
    30         template <class _charT, class _Traits, class _Allocator> class basic_string;
    31 #else
    32         // Borland C++ compiler has a bug which forces template argument names in forward declarations to be the same as in actual definitions
    33         template <class _Ty> class allocator;
    34         template <class _Ty> struct char_traits;
    35         template <class _Elem, class _Traits> class basic_istream;
    36         template <class _Elem, class _Traits> class basic_ostream;
    37         template <class _Elem, class _Traits, class _Ax> class basic_string;
    38 #endif
    39 
    40         // Digital Mars compiler has a bug which requires a forward declaration for explicit instantiation (otherwise type selection is messed up later, producing link errors)
    41         // Also note that we have to declare char_traits as a class here, since it's defined that way
    42 #ifdef __DMC__
    43         template <> class char_traits<char>;
    44 #endif
    45 }
     35#       include <iterator>
     36#       include <iosfwd>
     37#       include <string>
    4638#endif
    4739
     
    5749#endif
    5850
    59 // Include exception header for XPath
    60 #if !defined(PUGIXML_NO_XPATH) && !defined(PUGIXML_NO_EXCEPTIONS)
    61 #       include <exception>
    62 #endif
    63 
    6451// If no API is defined, assume default
    6552#ifndef PUGIXML_API
    66 #   define PUGIXML_API
     53#       define PUGIXML_API
    6754#endif
    6855
    6956// If no API for classes is defined, assume default
    7057#ifndef PUGIXML_CLASS
    71 #   define PUGIXML_CLASS PUGIXML_API
     58#       define PUGIXML_CLASS PUGIXML_API
    7259#endif
    7360
    7461// If no API for functions is defined, assume default
    7562#ifndef PUGIXML_FUNCTION
    76 #   define PUGIXML_FUNCTION PUGIXML_API
    77 #endif
    78 
    79 #include <stddef.h>
     63#       define PUGIXML_FUNCTION PUGIXML_API
     64#endif
     65
     66// If the platform is known to have long long support, enable long long functions
     67#ifndef PUGIXML_HAS_LONG_LONG
     68#       if __cplusplus >= 201103
     69#               define PUGIXML_HAS_LONG_LONG
     70#       elif defined(_MSC_VER) && _MSC_VER >= 1400
     71#               define PUGIXML_HAS_LONG_LONG
     72#       endif
     73#endif
     74
     75// If the platform is known to have move semantics support, compile move ctor/operator implementation
     76#ifndef PUGIXML_HAS_MOVE
     77#       if __cplusplus >= 201103
     78#               define PUGIXML_HAS_MOVE
     79#       elif defined(_MSC_VER) && _MSC_VER >= 1600
     80#               define PUGIXML_HAS_MOVE
     81#       endif
     82#endif
     83
     84// If C++ is 2011 or higher, add 'override' qualifiers
     85#ifndef PUGIXML_OVERRIDE
     86#       if __cplusplus >= 201103
     87#               define PUGIXML_OVERRIDE override
     88#       else
     89#               define PUGIXML_OVERRIDE
     90#       endif
     91#endif
    8092
    8193// Character interface macros
     
    105117        enum xml_node_type
    106118        {
    107                 node_null,          // Empty (null) node handle
     119                node_null,                      // Empty (null) node handle
    108120                node_document,          // A document tree's absolute root
    109121                node_element,           // Element tag, i.e. '<node/>'
     
    113125                node_pi,                        // Processing instruction, i.e. '<?name?>'
    114126                node_declaration,       // Document declaration, i.e. '<?xml version="1.0"?>'
    115         node_doctype        // Document type declaration, i.e. '<!DOCTYPE doc>'
     127                node_doctype            // Document type declaration, i.e. '<!DOCTYPE doc>'
    116128        };
    117129
     
    119131
    120132        // Minimal parsing mode (equivalent to turning all other flags off).
    121     // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed.
     133        // Only elements and PCDATA sections are added to the DOM tree, no text conversions are performed.
    122134        const unsigned int parse_minimal = 0x0000;
    123135
     
    132144
    133145        // This flag determines if plain character data (node_pcdata) that consist only of whitespace are added to the DOM tree.
    134     // This flag is off by default; turning it on usually results in slower parsing and more memory consumption.
     146        // This flag is off by default; turning it on usually results in slower parsing and more memory consumption.
    135147        const unsigned int parse_ws_pcdata = 0x0008;
    136148
     
    140152        // This flag determines if EOL characters are normalized (converted to #xA) during parsing. This flag is on by default.
    141153        const unsigned int parse_eol = 0x0020;
    142        
    143         // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default.
    144         const unsigned int parse_wconv_attribute = 0x0040;
    145 
    146         // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default.
    147         const unsigned int parse_wnorm_attribute = 0x0080;
    148        
    149     // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default.
     154
     155        // This flag determines if attribute values are normalized using CDATA normalization rules during parsing. This flag is on by default.
     156        const unsigned int parse_wconv_attribute = 0x0040;
     157
     158        // This flag determines if attribute values are normalized using NMTOKENS normalization rules during parsing. This flag is off by default.
     159        const unsigned int parse_wnorm_attribute = 0x0080;
     160
     161        // This flag determines if document declaration (node_declaration) is added to the DOM tree. This flag is off by default.
    150162        const unsigned int parse_declaration = 0x0100;
    151163
    152     // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default.
     164        // This flag determines if document type declaration (node_doctype) is added to the DOM tree. This flag is off by default.
    153165        const unsigned int parse_doctype = 0x0200;
    154166
     167        // This flag determines if plain character data (node_pcdata) that is the only child of the parent node and that consists only
     168        // of whitespace is added to the DOM tree.
     169        // This flag is off by default; turning it on may result in slower parsing and more memory consumption.
     170        const unsigned int parse_ws_pcdata_single = 0x0400;
     171
     172        // This flag determines if leading and trailing whitespace is to be removed from plain character data. This flag is off by default.
     173        const unsigned int parse_trim_pcdata = 0x0800;
     174
     175        // This flag determines if plain character data that does not have a parent node is added to the DOM tree, and if an empty document
     176        // is a valid document. This flag is off by default.
     177        const unsigned int parse_fragment = 0x1000;
     178
     179        // This flag determines if plain character data is be stored in the parent element's value. This significantly changes the structure of
     180        // the document; this flag is only recommended for parsing documents with many PCDATA nodes in memory-constrained environments.
     181        // This flag is off by default.
     182        const unsigned int parse_embed_pcdata = 0x2000;
     183
    155184        // The default parsing mode.
    156     // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded,
    157     // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
     185        // Elements, PCDATA and CDATA sections are added to the DOM tree, character/reference entities are expanded,
     186        // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
    158187        const unsigned int parse_default = parse_cdata | parse_escapes | parse_wconv_attribute | parse_eol;
    159188
    160     // The full parsing mode.
    161     // Nodes of all types are added to the DOM tree, character/reference entities are expanded,
    162     // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
    163     const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype;
     189        // The full parsing mode.
     190        // Nodes of all types are added to the DOM tree, character/reference entities are expanded,
     191        // End-of-Line characters are normalized, attribute values are normalized using CDATA normalization rules.
     192        const unsigned int parse_full = parse_default | parse_pi | parse_comments | parse_declaration | parse_doctype;
    164193
    165194        // These flags determine the encoding of input data for XML document
    166195        enum xml_encoding
    167196        {
    168                 encoding_auto,      // Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found
    169                 encoding_utf8,      // UTF8 encoding
    170                 encoding_utf16_le,  // Little-endian UTF16
    171                 encoding_utf16_be,  // Big-endian UTF16
    172                 encoding_utf16,     // UTF16 with native endianness
    173                 encoding_utf32_le,  // Little-endian UTF32
    174                 encoding_utf32_be,  // Big-endian UTF32
    175                 encoding_utf32,     // UTF32 with native endianness
    176                 encoding_wchar      // The same encoding wchar_t has (either UTF16 or UTF32)
     197                encoding_auto,          // Auto-detect input encoding using BOM or < / <? detection; use UTF8 if BOM is not found
     198                encoding_utf8,          // UTF8 encoding
     199                encoding_utf16_le,      // Little-endian UTF16
     200                encoding_utf16_be,      // Big-endian UTF16
     201                encoding_utf16,         // UTF16 with native endianness
     202                encoding_utf32_le,      // Little-endian UTF32
     203                encoding_utf32_be,      // Big-endian UTF32
     204                encoding_utf32,         // UTF32 with native endianness
     205                encoding_wchar,         // The same encoding wchar_t has (either UTF16 or UTF32)
     206                encoding_latin1
    177207        };
    178208
    179209        // Formatting flags
    180        
     210
    181211        // Indent the nodes that are written to output stream with as many indentation strings as deep the node is in DOM tree. This flag is on by default.
    182212        const unsigned int format_indent = 0x01;
    183        
     213
    184214        // Write encoding-specific BOM to the output stream. This flag is off by default.
    185215        const unsigned int format_write_bom = 0x02;
     
    187217        // Use raw output mode (no indentation and no line breaks are written). This flag is off by default.
    188218        const unsigned int format_raw = 0x04;
    189        
     219
    190220        // Omit default XML declaration even if there is no declaration in the document. This flag is off by default.
    191221        const unsigned int format_no_declaration = 0x08;
    192222
     223        // Don't escape attribute values and PCDATA contents. This flag is off by default.
     224        const unsigned int format_no_escapes = 0x10;
     225
     226        // Open file using text mode in xml_document::save_file. This enables special character (i.e. new-line) conversions on some systems. This flag is off by default.
     227        const unsigned int format_save_file_text = 0x20;
     228
     229        // Write every attribute on a new line with appropriate indentation. This flag is off by default.
     230        const unsigned int format_indent_attributes = 0x40;
     231
     232        // Don't output empty element tags, instead writing an explicit start and end tag even if there are no children. This flag is off by default.
     233        const unsigned int format_no_empty_element_tags = 0x80;
     234
    193235        // The default set of formatting flags.
    194     // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.
     236        // Nodes are indented depending on their depth in DOM tree, a default declaration is output if document has none.
    195237        const unsigned int format_default = format_indent;
    196                
     238
    197239        // Forward declarations
    198240        struct xml_attribute_struct;
     
    201243        class xml_node_iterator;
    202244        class xml_attribute_iterator;
     245        class xml_named_node_iterator;
    203246
    204247        class xml_tree_walker;
    205        
     248
     249        struct xml_parse_result;
     250
    206251        class xml_node;
     252
     253        class xml_text;
    207254
    208255        #ifndef PUGIXML_NO_XPATH
     
    213260        #endif
    214261
     262        // Range-based for loop support
     263        template <typename It> class xml_object_range
     264        {
     265        public:
     266                typedef It const_iterator;
     267                typedef It iterator;
     268
     269                xml_object_range(It b, It e): _begin(b), _end(e)
     270                {
     271                }
     272
     273                It begin() const { return _begin; }
     274                It end() const { return _end; }
     275
     276        private:
     277                It _begin, _end;
     278        };
     279
    215280        // Writer interface for node printing (see xml_node::print)
    216281        class PUGIXML_CLASS xml_writer
     
    227292        {
    228293        public:
    229         // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio
     294                // Construct writer from a FILE* object; void* is used to avoid header dependencies on stdio
    230295                xml_writer_file(void* file);
    231296
    232                 virtual void write(const void* data, size_t size);
     297                virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE;
    233298
    234299        private:
     
    241306        {
    242307        public:
    243         // Construct writer from an output stream object
     308                // Construct writer from an output stream object
    244309                xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream);
    245310                xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream);
    246311
    247                 virtual void write(const void* data, size_t size);
     312                virtual void write(const void* data, size_t size) PUGIXML_OVERRIDE;
    248313
    249314        private:
     
    261326        private:
    262327                xml_attribute_struct* _attr;
    263        
    264         typedef xml_attribute_struct* xml_attribute::*unspecified_bool_type;
    265 
    266         public:
    267         // Default constructor. Constructs an empty attribute.
     328
     329                typedef void (*unspecified_bool_type)(xml_attribute***);
     330
     331        public:
     332                // Default constructor. Constructs an empty attribute.
    268333                xml_attribute();
    269                
    270         // Constructs attribute from internal pointer
     334
     335                // Constructs attribute from internal pointer
    271336                explicit xml_attribute(xml_attribute_struct* attr);
    272337
    273         // Safe bool conversion operator
    274         operator unspecified_bool_type() const;
    275 
    276         // Borland C++ workaround
    277         bool operator!() const;
     338                // Safe bool conversion operator
     339                operator unspecified_bool_type() const;
     340
     341                // Borland C++ workaround
     342                bool operator!() const;
    278343
    279344                // Comparison operators (compares wrapped attribute pointers)
     
    292357                const char_t* value() const;
    293358
    294                 // Get attribute value as a number, or 0 if conversion did not succeed or attribute is empty
    295                 int as_int() const;
    296                 unsigned int as_uint() const;
    297                 double as_double() const;
    298                 float as_float() const;
    299 
    300         // Get attribute value as bool (returns true if first character is in '1tTyY' set), or false if attribute is empty
    301                 bool as_bool() const;
    302 
    303         // Set attribute name/value (returns false if attribute is empty or there is not enough memory)
     359                // Get attribute value, or the default value if attribute is empty
     360                const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const;
     361
     362                // Get attribute value as a number, or the default value if conversion did not succeed or attribute is empty
     363                int as_int(int def = 0) const;
     364                unsigned int as_uint(unsigned int def = 0) const;
     365                double as_double(double def = 0) const;
     366                float as_float(float def = 0) const;
     367
     368        #ifdef PUGIXML_HAS_LONG_LONG
     369                long long as_llong(long long def = 0) const;
     370                unsigned long long as_ullong(unsigned long long def = 0) const;
     371        #endif
     372
     373                // Get attribute value as bool (returns true if first character is in '1tTyY' set), or the default value if attribute is empty
     374                bool as_bool(bool def = false) const;
     375
     376                // Set attribute name/value (returns false if attribute is empty or there is not enough memory)
    304377                bool set_name(const char_t* rhs);
    305378                bool set_value(const char_t* rhs);
    306379
    307         // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
     380                // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
    308381                bool set_value(int rhs);
    309382                bool set_value(unsigned int rhs);
     383                bool set_value(long rhs);
     384                bool set_value(unsigned long rhs);
    310385                bool set_value(double rhs);
     386                bool set_value(float rhs);
    311387                bool set_value(bool rhs);
     388
     389        #ifdef PUGIXML_HAS_LONG_LONG
     390                bool set_value(long long rhs);
     391                bool set_value(unsigned long long rhs);
     392        #endif
    312393
    313394                // Set attribute value (equivalent to set_value without error checking)
     
    315396                xml_attribute& operator=(int rhs);
    316397                xml_attribute& operator=(unsigned int rhs);
     398                xml_attribute& operator=(long rhs);
     399                xml_attribute& operator=(unsigned long rhs);
    317400                xml_attribute& operator=(double rhs);
     401                xml_attribute& operator=(float rhs);
    318402                xml_attribute& operator=(bool rhs);
    319403
    320         // Get next/previous attribute in the attribute list of the parent node
    321         xml_attribute next_attribute() const;
    322         xml_attribute previous_attribute() const;
    323 
    324         // Get hash value (unique for handles to the same object)
    325         size_t hash_value() const;
     404        #ifdef PUGIXML_HAS_LONG_LONG
     405                xml_attribute& operator=(long long rhs);
     406                xml_attribute& operator=(unsigned long long rhs);
     407        #endif
     408
     409                // Get next/previous attribute in the attribute list of the parent node
     410                xml_attribute next_attribute() const;
     411                xml_attribute previous_attribute() const;
     412
     413                // Get hash value (unique for handles to the same object)
     414                size_t hash_value() const;
    326415
    327416                // Get internal pointer
     
    340429                friend class xml_attribute_iterator;
    341430                friend class xml_node_iterator;
     431                friend class xml_named_node_iterator;
    342432
    343433        protected:
    344434                xml_node_struct* _root;
    345435
    346         typedef xml_node_struct* xml_node::*unspecified_bool_type;
     436                typedef void (*unspecified_bool_type)(xml_node***);
    347437
    348438        public:
     
    350440                xml_node();
    351441
    352         // Constructs node from internal pointer
     442                // Constructs node from internal pointer
    353443                explicit xml_node(xml_node_struct* p);
    354444
    355         // Safe bool conversion operator
     445                // Safe bool conversion operator
    356446                operator unspecified_bool_type() const;
    357447
    358448                // Borland C++ workaround
    359449                bool operator!() const;
    360        
     450
    361451                // Comparison operators (compares wrapped node pointers)
    362452                bool operator==(const xml_node& r) const;
     
    373463                xml_node_type type() const;
    374464
    375                 // Get node name/value, or "" if node is empty or it has no name/value
     465                // Get node name, or "" if node is empty or it has no name
    376466                const char_t* name() const;
     467
     468                // Get node value, or "" if node is empty or it has no value
     469                // Note: For <node>text</node> node.value() does not return "text"! Use child_value() or text() methods to access text inside nodes.
    377470                const char_t* value() const;
    378        
     471
    379472                // Get attribute list
    380473                xml_attribute first_attribute() const;
    381         xml_attribute last_attribute() const;
    382 
    383         // Get children list
     474                xml_attribute last_attribute() const;
     475
     476                // Get children list
    384477                xml_node first_child() const;
    385         xml_node last_child() const;
    386 
    387         // Get next/previous sibling in the children list of the parent node
     478                xml_node last_child() const;
     479
     480                // Get next/previous sibling in the children list of the parent node
    388481                xml_node next_sibling() const;
    389482                xml_node previous_sibling() const;
    390                
    391         // Get parent node
     483
     484                // Get parent node
    392485                xml_node parent() const;
    393486
    394487                // Get root of DOM tree this node belongs to
    395488                xml_node root() const;
     489
     490                // Get text object for the current node
     491                xml_text text() const;
    396492
    397493                // Get child, attribute or next/previous sibling with the specified name
     
    401497                xml_node previous_sibling(const char_t* name) const;
    402498
     499                // Get attribute, starting the search from a hint (and updating hint so that searching for a sequence of attributes is fast)
     500                xml_attribute attribute(const char_t* name, xml_attribute& hint) const;
     501
    403502                // Get child value of current node; that is, value of the first child node of type PCDATA/CDATA
    404503                const char_t* child_value() const;
     
    410509                bool set_name(const char_t* rhs);
    411510                bool set_value(const char_t* rhs);
    412                
     511
    413512                // Add attribute with specified name. Returns added attribute, or empty attribute on errors.
    414513                xml_attribute append_attribute(const char_t* name);
     
    441540                xml_node insert_copy_before(const xml_node& proto, const xml_node& node);
    442541
     542                // Move the specified node to become a child of this node. Returns moved node, or empty node on errors.
     543                xml_node append_move(const xml_node& moved);
     544                xml_node prepend_move(const xml_node& moved);
     545                xml_node insert_move_after(const xml_node& moved, const xml_node& node);
     546                xml_node insert_move_before(const xml_node& moved, const xml_node& node);
     547
    443548                // Remove specified attribute
    444549                bool remove_attribute(const xml_attribute& a);
     
    448553                bool remove_child(const xml_node& n);
    449554                bool remove_child(const char_t* name);
     555
     556                // Parses buffer as an XML document fragment and appends all nodes as children of the current node.
     557                // Copies/converts the buffer, so it may be deleted or changed after the function returns.
     558                // Note: append_buffer allocates memory that has the lifetime of the owning document; removing the appended nodes does not immediately reclaim that memory.
     559                xml_parse_result append_buffer(const void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    450560
    451561                // Find attribute using predicate. Returns first attribute for which predicate returned true.
     
    453563                {
    454564                        if (!_root) return xml_attribute();
    455                        
     565
    456566                        for (xml_attribute attrib = first_attribute(); attrib; attrib = attrib.next_attribute())
    457567                                if (pred(attrib))
    458568                                        return attrib;
    459                
     569
    460570                        return xml_attribute();
    461571                }
     
    465575                {
    466576                        if (!_root) return xml_node();
    467        
     577
    468578                        for (xml_node node = first_child(); node; node = node.next_sibling())
    469579                                if (pred(node))
    470580                                        return node;
    471        
    472                 return xml_node();
     581
     582                        return xml_node();
    473583                }
    474584
     
    479589
    480590                        xml_node cur = first_child();
    481                        
     591
    482592                        while (cur._root && cur._root != _root)
    483593                        {
     
    511621                // Recursively traverse subtree with xml_tree_walker
    512622                bool traverse(xml_tree_walker& walker);
    513        
     623
    514624        #ifndef PUGIXML_NO_XPATH
    515625                // Select single node by evaluating XPath query. Returns first node from the resulting node set.
    516                 xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
    517                 xpath_node select_single_node(const xpath_query& query) const;
     626                xpath_node select_node(const char_t* query, xpath_variable_set* variables = 0) const;
     627                xpath_node select_node(const xpath_query& query) const;
    518628
    519629                // Select node set by evaluating XPath query
    520630                xpath_node_set select_nodes(const char_t* query, xpath_variable_set* variables = 0) const;
    521631                xpath_node_set select_nodes(const xpath_query& query) const;
    522         #endif
    523                
     632
     633                // (deprecated: use select_node instead) Select single node by evaluating XPath query.
     634                xpath_node select_single_node(const char_t* query, xpath_variable_set* variables = 0) const;
     635                xpath_node select_single_node(const xpath_query& query) const;
     636
     637        #endif
     638
    524639                // Print subtree using a writer object
    525640                void print(xml_writer& writer, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto, unsigned int depth = 0) const;
     
    543658                attribute_iterator attributes_end() const;
    544659
     660                // Range-based for support
     661                xml_object_range<xml_node_iterator> children() const;
     662                xml_object_range<xml_named_node_iterator> children(const char_t* name) const;
     663                xml_object_range<xml_attribute_iterator> attributes() const;
     664
    545665                // Get node offset in parsed file/string (in char_t units) for debugging purposes
    546666                ptrdiff_t offset_debug() const;
    547667
    548         // Get hash value (unique for handles to the same object)
    549         size_t hash_value() const;
     668                // Get hash value (unique for handles to the same object)
     669                size_t hash_value() const;
    550670
    551671                // Get internal pointer
     
    559679#endif
    560680
     681        // A helper for working with text inside PCDATA nodes
     682        class PUGIXML_CLASS xml_text
     683        {
     684                friend class xml_node;
     685
     686                xml_node_struct* _root;
     687
     688                typedef void (*unspecified_bool_type)(xml_text***);
     689
     690                explicit xml_text(xml_node_struct* root);
     691
     692                xml_node_struct* _data_new();
     693                xml_node_struct* _data() const;
     694
     695        public:
     696                // Default constructor. Constructs an empty object.
     697                xml_text();
     698
     699                // Safe bool conversion operator
     700                operator unspecified_bool_type() const;
     701
     702                // Borland C++ workaround
     703                bool operator!() const;
     704
     705                // Check if text object is empty
     706                bool empty() const;
     707
     708                // Get text, or "" if object is empty
     709                const char_t* get() const;
     710
     711                // Get text, or the default value if object is empty
     712                const char_t* as_string(const char_t* def = PUGIXML_TEXT("")) const;
     713
     714                // Get text as a number, or the default value if conversion did not succeed or object is empty
     715                int as_int(int def = 0) const;
     716                unsigned int as_uint(unsigned int def = 0) const;
     717                double as_double(double def = 0) const;
     718                float as_float(float def = 0) const;
     719
     720        #ifdef PUGIXML_HAS_LONG_LONG
     721                long long as_llong(long long def = 0) const;
     722                unsigned long long as_ullong(unsigned long long def = 0) const;
     723        #endif
     724
     725                // Get text as bool (returns true if first character is in '1tTyY' set), or the default value if object is empty
     726                bool as_bool(bool def = false) const;
     727
     728                // Set text (returns false if object is empty or there is not enough memory)
     729                bool set(const char_t* rhs);
     730
     731                // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false")
     732                bool set(int rhs);
     733                bool set(unsigned int rhs);
     734                bool set(long rhs);
     735                bool set(unsigned long rhs);
     736                bool set(double rhs);
     737                bool set(float rhs);
     738                bool set(bool rhs);
     739
     740        #ifdef PUGIXML_HAS_LONG_LONG
     741                bool set(long long rhs);
     742                bool set(unsigned long long rhs);
     743        #endif
     744
     745                // Set text (equivalent to set without error checking)
     746                xml_text& operator=(const char_t* rhs);
     747                xml_text& operator=(int rhs);
     748                xml_text& operator=(unsigned int rhs);
     749                xml_text& operator=(long rhs);
     750                xml_text& operator=(unsigned long rhs);
     751                xml_text& operator=(double rhs);
     752                xml_text& operator=(float rhs);
     753                xml_text& operator=(bool rhs);
     754
     755        #ifdef PUGIXML_HAS_LONG_LONG
     756                xml_text& operator=(long long rhs);
     757                xml_text& operator=(unsigned long long rhs);
     758        #endif
     759
     760                // Get the data node (node_pcdata or node_cdata) for this object
     761                xml_node data() const;
     762        };
     763
     764#ifdef __BORLANDC__
     765        // Borland C++ workaround
     766        bool PUGIXML_FUNCTION operator&&(const xml_text& lhs, bool rhs);
     767        bool PUGIXML_FUNCTION operator||(const xml_text& lhs, bool rhs);
     768#endif
     769
    561770        // Child node iterator (a bidirectional iterator over a collection of xml_node)
    562771        class PUGIXML_CLASS xml_node_iterator
     
    565774
    566775        private:
    567                 xml_node _wrap;
     776                mutable xml_node _wrap;
    568777                xml_node _parent;
    569778
     
    581790        #endif
    582791
    583         // Default constructor
     792                // Default constructor
    584793                xml_node_iterator();
    585794
    586         // Construct an iterator which points to the specified node
     795                // Construct an iterator which points to the specified node
    587796                xml_node_iterator(const xml_node& node);
    588797
    589         // Iterator operators
     798                // Iterator operators
    590799                bool operator==(const xml_node_iterator& rhs) const;
    591800                bool operator!=(const xml_node_iterator& rhs) const;
    592801
    593                 xml_node& operator*();
    594                 xml_node* operator->();
     802                xml_node& operator*() const;
     803                xml_node* operator->() const;
    595804
    596805                const xml_node_iterator& operator++();
     
    607816
    608817        private:
    609                 xml_attribute _wrap;
     818                mutable xml_attribute _wrap;
    610819                xml_node _parent;
    611820
     
    623832        #endif
    624833
    625         // Default constructor
     834                // Default constructor
    626835                xml_attribute_iterator();
    627836
    628         // Construct an iterator which points to the specified attribute
     837                // Construct an iterator which points to the specified attribute
    629838                xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent);
    630839
     
    633842                bool operator!=(const xml_attribute_iterator& rhs) const;
    634843
    635                 xml_attribute& operator*();
    636                 xml_attribute* operator->();
     844                xml_attribute& operator*() const;
     845                xml_attribute* operator->() const;
    637846
    638847                const xml_attribute_iterator& operator++();
     
    643852        };
    644853
     854        // Named node range helper
     855        class PUGIXML_CLASS xml_named_node_iterator
     856        {
     857                friend class xml_node;
     858
     859        public:
     860                // Iterator traits
     861                typedef ptrdiff_t difference_type;
     862                typedef xml_node value_type;
     863                typedef xml_node* pointer;
     864                typedef xml_node& reference;
     865
     866        #ifndef PUGIXML_NO_STL
     867                typedef std::bidirectional_iterator_tag iterator_category;
     868        #endif
     869
     870                // Default constructor
     871                xml_named_node_iterator();
     872
     873                // Construct an iterator which points to the specified node
     874                xml_named_node_iterator(const xml_node& node, const char_t* name);
     875
     876                // Iterator operators
     877                bool operator==(const xml_named_node_iterator& rhs) const;
     878                bool operator!=(const xml_named_node_iterator& rhs) const;
     879
     880                xml_node& operator*() const;
     881                xml_node* operator->() const;
     882
     883                const xml_named_node_iterator& operator++();
     884                xml_named_node_iterator operator++(int);
     885
     886                const xml_named_node_iterator& operator--();
     887                xml_named_node_iterator operator--(int);
     888
     889        private:
     890                mutable xml_node _wrap;
     891                xml_node _parent;
     892                const char_t* _name;
     893
     894                xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name);
     895        };
     896
    645897        // Abstract tree walker class (see xml_node::traverse)
    646898        class PUGIXML_CLASS xml_tree_walker
     
    650902        private:
    651903                int _depth;
    652        
     904
    653905        protected:
    654906                // Get current traversal depth
    655907                int depth() const;
    656        
     908
    657909        public:
    658910                xml_tree_walker();
     
    672924        enum xml_parse_status
    673925        {
    674                 status_ok = 0,              // No error
    675 
    676                 status_file_not_found,      // File was not found during load_file()
    677                 status_io_error,            // Error reading from file/stream
    678                 status_out_of_memory,       // Could not allocate memory
    679                 status_internal_error,      // Internal error occurred
    680 
    681                 status_unrecognized_tag,    // Parser could not determine tag type
    682 
    683                 status_bad_pi,              // Parsing error occurred while parsing document declaration/processing instruction
    684                 status_bad_comment,         // Parsing error occurred while parsing comment
    685                 status_bad_cdata,           // Parsing error occurred while parsing CDATA section
    686                 status_bad_doctype,         // Parsing error occurred while parsing document type declaration
    687                 status_bad_pcdata,          // Parsing error occurred while parsing PCDATA section
    688                 status_bad_start_element,   // Parsing error occurred while parsing start element tag
    689                 status_bad_attribute,       // Parsing error occurred while parsing element attribute
    690                 status_bad_end_element,     // Parsing error occurred while parsing end element tag
    691                 status_end_element_mismatch // There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag)
     926                status_ok = 0,                          // No error
     927
     928                status_file_not_found,          // File was not found during load_file()
     929                status_io_error,                        // Error reading from file/stream
     930                status_out_of_memory,           // Could not allocate memory
     931                status_internal_error,          // Internal error occurred
     932
     933                status_unrecognized_tag,        // Parser could not determine tag type
     934
     935                status_bad_pi,                          // Parsing error occurred while parsing document declaration/processing instruction
     936                status_bad_comment,                     // Parsing error occurred while parsing comment
     937                status_bad_cdata,                       // Parsing error occurred while parsing CDATA section
     938                status_bad_doctype,                     // Parsing error occurred while parsing document type declaration
     939                status_bad_pcdata,                      // Parsing error occurred while parsing PCDATA section
     940                status_bad_start_element,       // Parsing error occurred while parsing start element tag
     941                status_bad_attribute,           // Parsing error occurred while parsing element attribute
     942                status_bad_end_element,         // Parsing error occurred while parsing end element tag
     943                status_end_element_mismatch,// There was a mismatch of start-end tags (closing tag had incorrect name, some tag was not closed or there was an excessive closing tag)
     944
     945                status_append_invalid_root,     // Unable to append nodes since root type is not node_element or node_document (exclusive to xml_node::append_buffer)
     946
     947                status_no_document_element      // Parsing resulted in a document without element nodes
    692948        };
    693949
     
    704960                xml_encoding encoding;
    705961
    706         // Default constructor, initializes object to failed state
     962                // Default constructor, initializes object to failed state
    707963                xml_parse_result();
    708964
     
    721977
    722978                char _memory[192];
    723                
     979
    724980                // Non-copyable semantics
    725981                xml_document(const xml_document&);
    726                 const xml_document& operator=(const xml_document&);
    727 
    728                 void create();
    729                 void destroy();
    730 
    731                 xml_parse_result load_buffer_impl(void* contents, size_t size, unsigned int options, xml_encoding encoding, bool is_mutable, bool own);
     982                xml_document& operator=(const xml_document&);
     983
     984                void _create();
     985                void _destroy();
    732986
    733987        public:
     
    738992                ~xml_document();
    739993
    740         // Removes all nodes, leaving the empty document
     994                // Removes all nodes, leaving the empty document
    741995                void reset();
    742996
    743         // Removes all nodes, then copies the entire contents of the specified document
     997                // Removes all nodes, then copies the entire contents of the specified document
    744998                void reset(const xml_document& proto);
    745999
     
    7501004        #endif
    7511005
     1006                // (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied.
     1007                xml_parse_result load(const char_t* contents, unsigned int options = parse_default);
     1008
    7521009                // Load document from zero-terminated string. No encoding conversions are applied.
    753                 xml_parse_result load(const char_t* contents, unsigned int options = parse_default);
     1010                xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default);
    7541011
    7551012                // Load document from file
     
    7611018
    7621019                // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).
    763         // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed.
     1020                // You should ensure that buffer data will persist throughout the document's lifetime, and free the buffer memory manually once document is destroyed.
    7641021                xml_parse_result load_buffer_inplace(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    7651022
    7661023                // Load document from buffer, using the buffer for in-place parsing (the buffer is modified and used for storage of document data).
    767         // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore).
     1024                // You should allocate the buffer with pugixml allocation function; document will free the buffer when it is no longer needed (you can't use it anymore).
    7681025                xml_parse_result load_buffer_inplace_own(void* contents, size_t size, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
    7691026
     
    7811038                bool save_file(const wchar_t* path, const char_t* indent = PUGIXML_TEXT("\t"), unsigned int flags = format_default, xml_encoding encoding = encoding_auto) const;
    7821039
    783         // Get document element
    784         xml_node document_element() const;
     1040                // Get document element
     1041                xml_node document_element() const;
    7851042        };
    7861043
     
    7891046        enum xpath_value_type
    7901047        {
    791                 xpath_type_none,      // Unknown type (query failed to compile)
     1048                xpath_type_none,          // Unknown type (query failed to compile)
    7921049                xpath_type_node_set,  // Node set (xpath_node_set)
    793                 xpath_type_number,    // Number
    794                 xpath_type_string,    // String
    795                 xpath_type_boolean    // Boolean
    796         };
    797 
    798     // XPath parsing result
     1050                xpath_type_number,        // Number
     1051                xpath_type_string,        // String
     1052                xpath_type_boolean        // Boolean
     1053        };
     1054
     1055        // XPath parsing result
    7991056        struct PUGIXML_CLASS xpath_parse_result
    8001057        {
     
    8051062                ptrdiff_t offset;
    8061063
    807         // Default constructor, initializes object to failed state
     1064                // Default constructor, initializes object to failed state
    8081065                xpath_parse_result();
    8091066
     
    8241081                xpath_variable* _next;
    8251082
    826                 xpath_variable();
     1083                xpath_variable(xpath_value_type type);
    8271084
    8281085                // Non-copyable semantics
    8291086                xpath_variable(const xpath_variable&);
    8301087                xpath_variable& operator=(const xpath_variable&);
    831                
    832         public:
    833         // Get variable name
     1088
     1089        public:
     1090                // Get variable name
    8341091                const char_t* name() const;
    8351092
    836         // Get variable type
     1093                // Get variable type
    8371094                xpath_value_type type() const;
    8381095
    839         // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error
     1096                // Get variable value; no type conversion is performed, default value (false, NaN, empty string, empty node set) is returned on type mismatch error
    8401097                bool get_boolean() const;
    8411098                double get_number() const;
     
    8431100                const xpath_node_set& get_node_set() const;
    8441101
    845         // Set variable value; no type conversion is performed, false is returned on type mismatch error
     1102                // Set variable value; no type conversion is performed, false is returned on type mismatch error
    8461103                bool set(bool value);
    8471104                bool set(double value);
     
    8561113                xpath_variable* _data[64];
    8571114
    858                 // Non-copyable semantics
    859                 xpath_variable_set(const xpath_variable_set&);
    860                 xpath_variable_set& operator=(const xpath_variable_set&);
    861 
    862                 xpath_variable* find(const char_t* name) const;
    863 
    864         public:
    865         // Default constructor/destructor
     1115                void _assign(const xpath_variable_set& rhs);
     1116                void _swap(xpath_variable_set& rhs);
     1117
     1118                xpath_variable* _find(const char_t* name) const;
     1119
     1120                static bool _clone(xpath_variable* var, xpath_variable** out_result);
     1121                static void _destroy(xpath_variable* var);
     1122
     1123        public:
     1124                // Default constructor/destructor
    8661125                xpath_variable_set();
    8671126                ~xpath_variable_set();
    8681127
    869         // Add a new variable or get the existing one, if the types match
     1128                // Copy constructor/assignment operator
     1129                xpath_variable_set(const xpath_variable_set& rhs);
     1130                xpath_variable_set& operator=(const xpath_variable_set& rhs);
     1131
     1132        #ifdef PUGIXML_HAS_MOVE
     1133                // Move semantics support
     1134                xpath_variable_set(xpath_variable_set&& rhs);
     1135                xpath_variable_set& operator=(xpath_variable_set&& rhs);
     1136        #endif
     1137
     1138                // Add a new variable or get the existing one, if the types match
    8701139                xpath_variable* add(const char_t* name, xpath_value_type type);
    8711140
    872         // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch
     1141                // Set value of an existing variable; no type conversion is performed, false is returned if there is no such variable or if types mismatch
    8731142                bool set(const char_t* name, bool value);
    8741143                bool set(const char_t* name, double value);
     
    8761145                bool set(const char_t* name, const xpath_node_set& value);
    8771146
    878         // Get existing variable by name
     1147                // Get existing variable by name
    8791148                xpath_variable* get(const char_t* name);
    8801149                const xpath_variable* get(const char_t* name) const;
     
    8881157                xpath_parse_result _result;
    8891158
    890         typedef void* xpath_query::*unspecified_bool_type;
     1159                typedef void (*unspecified_bool_type)(xpath_query***);
    8911160
    8921161                // Non-copyable semantics
     
    8951164
    8961165        public:
    897         // Construct a compiled object from XPath expression.
    898         // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors.
     1166                // Construct a compiled object from XPath expression.
     1167                // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on compilation errors.
    8991168                explicit xpath_query(const char_t* query, xpath_variable_set* variables = 0);
     1169
     1170                // Constructor
     1171                xpath_query();
    9001172
    9011173                // Destructor
    9021174                ~xpath_query();
    9031175
     1176        #ifdef PUGIXML_HAS_MOVE
     1177                // Move semantics support
     1178                xpath_query(xpath_query&& rhs);
     1179                xpath_query& operator=(xpath_query&& rhs);
     1180        #endif
     1181
    9041182                // Get query expression return type
    9051183                xpath_value_type return_type() const;
    906                
     1184
    9071185                // Evaluate expression as boolean value in the specified context; performs type conversion if necessary.
    908         // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
     1186                // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
    9091187                bool evaluate_boolean(const xpath_node& n) const;
    910                
     1188
    9111189                // Evaluate expression as double value in the specified context; performs type conversion if necessary.
    912         // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
     1190                // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
    9131191                double evaluate_number(const xpath_node& n) const;
    914                
     1192
    9151193        #ifndef PUGIXML_NO_STL
    9161194                // Evaluate expression as string value in the specified context; performs type conversion if necessary.
    917         // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
     1195                // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
    9181196                string_t evaluate_string(const xpath_node& n) const;
    9191197        #endif
    920                
     1198
    9211199                // Evaluate expression as string value in the specified context; performs type conversion if necessary.
    922         // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero).
    923         // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
    924         // If PUGIXML_NO_EXCEPTIONS is defined, returns empty  set instead.
     1200                // At most capacity characters are written to the destination buffer, full result size is returned (includes terminating zero).
     1201                // If PUGIXML_NO_EXCEPTIONS is not defined, throws std::bad_alloc on out of memory errors.
     1202                // If PUGIXML_NO_EXCEPTIONS is defined, returns empty  set instead.
    9251203                size_t evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const;
    9261204
    9271205                // Evaluate expression as node set in the specified context.
    928         // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
    929         // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead.
     1206                // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
     1207                // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node set instead.
    9301208                xpath_node_set evaluate_node_set(const xpath_node& n) const;
     1209
     1210                // Evaluate expression as node set in the specified context.
     1211                // Return first node in document order, or empty node if node set is empty.
     1212                // If PUGIXML_NO_EXCEPTIONS is not defined, throws xpath_exception on type mismatch and std::bad_alloc on out of memory errors.
     1213                // If PUGIXML_NO_EXCEPTIONS is defined, returns empty node instead.
     1214                xpath_node evaluate_node(const xpath_node& n) const;
    9311215
    9321216                // Get parsing result (used to get compilation errors in PUGIXML_NO_EXCEPTIONS mode)
     
    9361220                operator unspecified_bool_type() const;
    9371221
    938         // Borland C++ workaround
     1222                // Borland C++ workaround
    9391223                bool operator!() const;
    9401224        };
    941        
     1225
    9421226        #ifndef PUGIXML_NO_EXCEPTIONS
    9431227        // XPath exception class
     
    9521236
    9531237                // Get error message
    954                 virtual const char* what() const throw();
    955 
    956         // Get parse result
     1238                virtual const char* what() const throw() PUGIXML_OVERRIDE;
     1239
     1240                // Get parse result
    9571241                const xpath_parse_result& result() const;
    9581242        };
    9591243        #endif
    960        
     1244
    9611245        // XPath node class (either xml_node or xml_attribute)
    9621246        class PUGIXML_CLASS xpath_node
     
    9651249                xml_node _node;
    9661250                xml_attribute _attribute;
    967        
    968         typedef xml_node xpath_node::*unspecified_bool_type;
     1251
     1252                typedef void (*unspecified_bool_type)(xpath_node***);
    9691253
    9701254        public:
    9711255                // Default constructor; constructs empty XPath node
    9721256                xpath_node();
    973                
     1257
    9741258                // Construct XPath node from XML node/attribute
    9751259                xpath_node(const xml_node& node);
     
    9791263                xml_node node() const;
    9801264                xml_attribute attribute() const;
    981                
     1265
    9821266                // Get parent of contained node/attribute
    9831267                xml_node parent() const;
    9841268
    985         // Safe bool conversion operator
     1269                // Safe bool conversion operator
    9861270                operator unspecified_bool_type() const;
    987                
    988         // Borland C++ workaround
    989         bool operator!() const;
     1271
     1272                // Borland C++ workaround
     1273                bool operator!() const;
    9901274
    9911275                // Comparison operators
     
    10111295                        type_sorted_reverse             // Sorted by document order (descending)
    10121296                };
    1013                
     1297
    10141298                // Constant iterator type
    10151299                typedef const xpath_node* const_iterator;
    1016        
     1300
     1301                // We define non-constant iterator to be the same as constant iterator so that various generic algorithms (i.e. boost foreach) work
     1302                typedef const xpath_node* iterator;
     1303
    10171304                // Default constructor. Constructs empty set.
    10181305                xpath_node_set();
     
    10231310                // Destructor
    10241311                ~xpath_node_set();
    1025                
     1312
    10261313                // Copy constructor/assignment operator
    10271314                xpath_node_set(const xpath_node_set& ns);
    10281315                xpath_node_set& operator=(const xpath_node_set& ns);
    10291316
     1317        #ifdef PUGIXML_HAS_MOVE
     1318                // Move semantics support
     1319                xpath_node_set(xpath_node_set&& rhs);
     1320                xpath_node_set& operator=(xpath_node_set&& rhs);
     1321        #endif
     1322
    10301323                // Get collection type
    10311324                type_t type() const;
    1032                
     1325
    10331326                // Get collection size
    10341327                size_t size() const;
    10351328
    1036         // Indexing operator
     1329                // Indexing operator
    10371330                const xpath_node& operator[](size_t index) const;
    1038                
     1331
    10391332                // Collection iterators
    10401333                const_iterator begin() const;
     
    10431336                // Sort the collection in ascending/descending order by document order
    10441337                void sort(bool reverse = false);
    1045                
     1338
    10461339                // Get first node in the collection by document order
    10471340                xpath_node first() const;
    1048                
     1341
    10491342                // Check if collection is empty
    10501343                bool empty() const;
    1051    
     1344
    10521345        private:
    10531346                type_t _type;
    1054                
     1347
    10551348                xpath_node _storage;
    1056                
     1349
    10571350                xpath_node* _begin;
    10581351                xpath_node* _end;
    10591352
    1060                 void _assign(const_iterator begin, const_iterator end);
     1353                void _assign(const_iterator begin, const_iterator end, type_t type);
     1354                void _move(xpath_node_set& rhs);
    10611355        };
    10621356#endif
     
    10661360        std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const wchar_t* str);
    10671361        std::basic_string<char, std::char_traits<char>, std::allocator<char> > PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >& str);
    1068        
     1362
    10691363        // Convert UTF8 to wide string
    10701364        std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > PUGIXML_FUNCTION as_wide(const char* str);
     
    10741368        // Memory allocation function interface; returns pointer to allocated memory or NULL on failure
    10751369        typedef void* (*allocation_function)(size_t size);
    1076        
     1370
    10771371        // Memory deallocation function interface
    1078     typedef void (*deallocation_function)(void* ptr);
    1079 
    1080     // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions.
    1081     void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
    1082    
    1083     // Get current memory management functions
    1084     allocation_function PUGIXML_FUNCTION get_memory_allocation_function();
    1085     deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function();
     1372        typedef void (*deallocation_function)(void* ptr);
     1373
     1374        // Override default memory management functions. All subsequent allocations/deallocations will be performed via supplied functions.
     1375        void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate);
     1376
     1377        // Get current memory management functions
     1378        allocation_function PUGIXML_FUNCTION get_memory_allocation_function();
     1379        deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function();
    10861380}
    10871381
     
    10921386        std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_node_iterator&);
    10931387        std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_attribute_iterator&);
     1388        std::bidirectional_iterator_tag PUGIXML_FUNCTION _Iter_cat(const pugi::xml_named_node_iterator&);
    10941389}
    10951390#endif
     
    11011396        std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_node_iterator&);
    11021397        std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_attribute_iterator&);
     1398        std::bidirectional_iterator_tag PUGIXML_FUNCTION __iterator_category(const pugi::xml_named_node_iterator&);
    11031399}
    11041400#endif
     
    11061402#endif
    11071403
     1404// Make sure implementation is included in header-only mode
     1405// Use macro expansion in #include to work around QMake (QTBUG-11923)
     1406#if defined(PUGIXML_HEADER_ONLY) && !defined(PUGIXML_SOURCE)
     1407#       define PUGIXML_SOURCE "pugixml.cpp"
     1408#       include PUGIXML_SOURCE
     1409#endif
     1410
    11081411/**
    1109  * Copyright (c) 2006-2010 Arseny Kapoulkine
     1412 * Copyright (c) 2006-2016 Arseny Kapoulkine
    11101413 *
    11111414 * Permission is hereby granted, free of charge, to any person
     
    11201423 * The above copyright notice and this permission notice shall be
    11211424 * included in all copies or substantial portions of the Software.
    1122  * 
     1425 *
    11231426 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    11241427 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  • ThirdParty/vmg/src/thirdparty/pugixml/readme.txt

    r6798a5 r33a694  
    1 pugixml 1.0 - an XML processing library
     1pugixml 1.8 - an XML processing library
    22
    3 Copyright (C) 2006-2010, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
     3Copyright (C) 2006-2016, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
    44Report bugs and download new versions at http://pugixml.org/
    55
     
    2929This library is distributed under the MIT License:
    3030
    31 Copyright (c) 2006-2010 Arseny Kapoulkine
     31Copyright (c) 2006-2016 Arseny Kapoulkine
    3232
    3333Permission is hereby granted, free of charge, to any person
Note: See TracChangeset for help on using the changeset viewer.