Ignore:
Timestamp:
Jan 9, 2017, 11:09:38 AM (2 years ago)
Author:
jrpelegrina
Message:

Update new version: 3.15.02

File:
1 edited

Legend:

Unmodified
Added
Removed
  • filezilla/trunk/fuentes/src/pugixml/pugixml.cpp

    r130 r3185  
    11/**
    2  * pugixml parser - version 1.6
     2 * pugixml parser - version 1.7
    33 * --------------------------------------------------------
    44 * Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
     
    2121#include <string.h>
    2222#include <assert.h>
     23#include <limits.h>
    2324
    2425#ifdef PUGIXML_WCHAR_MODE
     
    106107using std::memcpy;
    107108using std::memmove;
     109using std::memset;
    108110#endif
    109111
     
    134136#       include <stdint.h>
    135137#else
     138namespace pugi
     139{
    136140#       ifndef _UINTPTR_T_DEFINED
    137 // No native uintptr_t in MSVC6 and in some WinCE versions
    138 typedef size_t uintptr_t;
    139 #define _UINTPTR_T_DEFINED
     141        typedef size_t uintptr_t;
    140142#       endif
    141 PUGI__NS_BEGIN
     143
    142144        typedef unsigned __int8 uint8_t;
    143145        typedef unsigned __int16 uint16_t;
    144146        typedef unsigned __int32 uint32_t;
    145 PUGI__NS_END
     147}
    146148#endif
    147149
     
    222224        #endif
    223225        }
    224 
    225 #ifdef PUGIXML_WCHAR_MODE
    226         // Convert string to wide string, assuming all symbols are ASCII
    227         PUGI__FN void widen_ascii(wchar_t* dest, const char* source)
    228         {
    229                 for (const char* i = source; *i; ++i) *dest++ = *i;
    230                 *dest = 0;
    231         }
    232 #endif
    233226PUGI__NS_END
    234227
    235 #if !defined(PUGIXML_NO_STL) || !defined(PUGIXML_NO_XPATH)
    236 // auto_ptr-like buffer holder for exception recovery
     228// auto_ptr-like object for exception recovery
    237229PUGI__NS_BEGIN
    238         struct buffer_holder
    239         {
    240                 void* data;
    241                 void (*deleter)(void*);
    242 
    243                 buffer_holder(void* data_, void (*deleter_)(void*)): data(data_), deleter(deleter_)
    244                 {
    245                 }
    246 
    247                 ~buffer_holder()
     230        template <typename T, typename D = void(*)(T*)> struct auto_deleter
     231        {
     232                T* data;
     233                D deleter;
     234
     235                auto_deleter(T* data_, D deleter_): data(data_), deleter(deleter_)
     236                {
     237                }
     238
     239                ~auto_deleter()
    248240                {
    249241                        if (data) deleter(data);
    250242                }
    251243
    252                 void* release()
    253                 {
    254                         void* result = data;
     244                T* release()
     245                {
     246                        T* result = data;
    255247                        data = 0;
    256248                        return result;
    257249                }
    258250        };
     251PUGI__NS_END
     252
     253#ifdef PUGIXML_COMPACT
     254PUGI__NS_BEGIN
     255        class compact_hash_table
     256        {
     257        public:
     258                compact_hash_table(): _items(0), _capacity(0), _count(0)
     259                {
     260                }
     261
     262                void clear()
     263                {
     264                        if (_items)
     265                        {
     266                                xml_memory::deallocate(_items);
     267                                _items = 0;
     268                                _capacity = 0;
     269                                _count = 0;
     270                        }
     271                }
     272
     273                void** find(const void* key)
     274                {
     275                        assert(key);
     276
     277                        if (_capacity == 0) return 0;
     278
     279                        size_t hashmod = _capacity - 1;
     280                        size_t bucket = hash(key) & hashmod;
     281
     282                        for (size_t probe = 0; probe <= hashmod; ++probe)
     283                        {
     284                                item_t& probe_item = _items[bucket];
     285
     286                                if (probe_item.key == key)
     287                                        return &probe_item.value;
     288
     289                                if (probe_item.key == 0)
     290                                        return 0;
     291
     292                                // hash collision, quadratic probing
     293                                bucket = (bucket + probe + 1) & hashmod;
     294                        }
     295
     296                        assert(!"Hash table is full");
     297                        return 0;
     298                }
     299
     300                void** insert(const void* key)
     301                {
     302                        assert(key);
     303                        assert(_capacity != 0 && _count < _capacity - _capacity / 4);
     304
     305                        size_t hashmod = _capacity - 1;
     306                        size_t bucket = hash(key) & hashmod;
     307
     308                        for (size_t probe = 0; probe <= hashmod; ++probe)
     309                        {
     310                                item_t& probe_item = _items[bucket];
     311
     312                                if (probe_item.key == 0)
     313                                {
     314                                        probe_item.key = key;
     315                                        _count++;
     316                                        return &probe_item.value;
     317                                }
     318
     319                                if (probe_item.key == key)
     320                                        return &probe_item.value;
     321
     322                                // hash collision, quadratic probing
     323                                bucket = (bucket + probe + 1) & hashmod;
     324                        }
     325
     326                        assert(!"Hash table is full");
     327                        return 0;
     328                }
     329
     330                bool reserve()
     331                {
     332                        if (_count + 16 >= _capacity - _capacity / 4)
     333                                return rehash();
     334
     335                        return true;
     336                }
     337
     338        private:
     339                struct item_t
     340                {
     341                        const void* key;
     342                        void* value;
     343                };
     344
     345                item_t* _items;
     346                size_t _capacity;
     347
     348                size_t _count;
     349
     350                bool rehash();
     351
     352                static unsigned int hash(const void* key)
     353                {
     354                        unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key));
     355
     356                        // MurmurHash3 32-bit finalizer
     357                        h ^= h >> 16;
     358                        h *= 0x85ebca6bu;
     359                        h ^= h >> 13;
     360                        h *= 0xc2b2ae35u;
     361                        h ^= h >> 16;
     362
     363                        return h;
     364                }
     365        };
     366
     367        PUGI__FN_NO_INLINE bool compact_hash_table::rehash()
     368        {
     369                compact_hash_table rt;
     370                rt._capacity = (_capacity == 0) ? 32 : _capacity * 2;
     371                rt._items = static_cast<item_t*>(xml_memory::allocate(sizeof(item_t) * rt._capacity));
     372
     373                if (!rt._items)
     374                        return false;
     375
     376                memset(rt._items, 0, sizeof(item_t) * rt._capacity);
     377
     378                for (size_t i = 0; i < _capacity; ++i)
     379                        if (_items[i].key)
     380                                *rt.insert(_items[i].key) = _items[i].value;
     381
     382                if (_items)
     383                        xml_memory::deallocate(_items);
     384
     385                _capacity = rt._capacity;
     386                _items = rt._items;
     387
     388                assert(_count == rt._count);
     389
     390                return true;
     391        }
     392
    259393PUGI__NS_END
    260394#endif
     
    269403                ;
    270404
     405#ifdef PUGIXML_COMPACT
     406        static const uintptr_t xml_memory_block_alignment = 4;
     407
     408        static const uintptr_t xml_memory_page_alignment = sizeof(void*);
     409#else
     410        static const uintptr_t xml_memory_block_alignment = sizeof(void*);
     411
    271412        static const uintptr_t xml_memory_page_alignment = 64;
    272413        static const uintptr_t xml_memory_page_pointer_mask = ~(xml_memory_page_alignment - 1);
     414#endif
     415
     416        // extra metadata bits
    273417        static const uintptr_t xml_memory_page_contents_shared_mask = 32;
    274418        static const uintptr_t xml_memory_page_name_allocated_mask = 16;
    275419        static const uintptr_t xml_memory_page_value_allocated_mask = 8;
    276420        static const uintptr_t xml_memory_page_type_mask = 7;
     421
     422        // combined masks for string uniqueness
    277423        static const uintptr_t xml_memory_page_name_allocated_or_shared_mask = xml_memory_page_name_allocated_mask | xml_memory_page_contents_shared_mask;
    278424        static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask;
    279425
     426#ifdef PUGIXML_COMPACT
     427        #define PUGI__GETPAGE_IMPL(header) (header).get_page()
     428#else
     429        #define PUGI__GETPAGE_IMPL(header) reinterpret_cast<impl::xml_memory_page*>((header) & impl::xml_memory_page_pointer_mask)
     430#endif
     431
     432        #define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header)
    280433        #define PUGI__NODETYPE(n) static_cast<xml_node_type>(((n)->header & impl::xml_memory_page_type_mask) + 1)
    281434
     
    294447                        result->freed_size = 0;
    295448
     449                #ifdef PUGIXML_COMPACT
     450                        result->compact_string_base = 0;
     451                        result->compact_shared_parent = 0;
     452                        result->compact_page_marker = 0;
     453                #endif
     454
    296455                        return result;
    297456                }
     
    304463                size_t busy_size;
    305464                size_t freed_size;
     465
     466        #ifdef PUGIXML_COMPACT
     467                char_t* compact_string_base;
     468                void* compact_shared_parent;
     469                uint32_t* compact_page_marker;
     470        #endif
    306471        };
    307472
     
    316481                xml_allocator(xml_memory_page* root): _root(root), _busy_size(root->busy_size)
    317482                {
     483                #ifdef PUGIXML_COMPACT
     484                        _hash = 0;
     485                #endif
    318486                }
    319487
     
    353521                void* allocate_memory(size_t size, xml_memory_page*& out_page)
    354522                {
    355                         if (_busy_size + size > xml_memory_page_size) return allocate_memory_oob(size, out_page);
     523                        if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size))
     524                                return allocate_memory_oob(size, out_page);
    356525
    357526                        void* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size;
     
    363532                        return buf;
    364533                }
     534
     535        #ifdef PUGIXML_COMPACT
     536                void* allocate_object(size_t size, xml_memory_page*& out_page)
     537                {
     538                        void* result = allocate_memory(size + sizeof(uint32_t), out_page);
     539                        if (!result) return 0;
     540
     541                        // adjust for marker
     542                        ptrdiff_t offset = static_cast<char*>(result) - reinterpret_cast<char*>(out_page->compact_page_marker);
     543
     544                        if (PUGI__UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment))
     545                        {
     546                                // insert new marker
     547                                uint32_t* marker = static_cast<uint32_t*>(result);
     548
     549                                *marker = static_cast<uint32_t>(reinterpret_cast<char*>(marker) - reinterpret_cast<char*>(out_page));
     550                                out_page->compact_page_marker = marker;
     551
     552                                // since we don't reuse the page space until we reallocate it, we can just pretend that we freed the marker block
     553                                // this will make sure deallocate_memory correctly tracks the size
     554                                out_page->freed_size += sizeof(uint32_t);
     555
     556                                return marker + 1;
     557                        }
     558                        else
     559                        {
     560                                // roll back uint32_t part
     561                                _busy_size -= sizeof(uint32_t);
     562
     563                                return result;
     564                        }
     565                }
     566        #else
     567                void* allocate_object(size_t size, xml_memory_page*& out_page)
     568                {
     569                        return allocate_memory(size, out_page);
     570                }
     571        #endif
    365572
    366573                void deallocate_memory(void* ptr, size_t size, xml_memory_page* page)
     
    381588
    382589                                        // top page freed, just reset sizes
    383                                         page->busy_size = page->freed_size = 0;
     590                                        page->busy_size = 0;
     591                                        page->freed_size = 0;
     592
     593                                #ifdef PUGIXML_COMPACT
     594                                        // reset compact state to maximize efficiency
     595                                        page->compact_string_base = 0;
     596                                        page->compact_shared_parent = 0;
     597                                        page->compact_page_marker = 0;
     598                                #endif
     599
    384600                                        _busy_size = 0;
    385601                                }
     
    401617                char_t* allocate_string(size_t length)
    402618                {
    403                         static const size_t max_encoded_offset = (1 << 16) * sizeof(void*);
     619                        static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment;
    404620
    405621                        PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
     
    408624                        size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
    409625                       
    410                         // round size up to pointer alignment boundary
    411                         size_t full_size = (size + (sizeof(void*) - 1)) & ~(sizeof(void*) - 1);
     626                        // round size up to block alignment boundary
     627                        size_t full_size = (size + (xml_memory_block_alignment - 1)) & ~(xml_memory_block_alignment - 1);
    412628
    413629                        xml_memory_page* page;
     
    419635                        ptrdiff_t page_offset = reinterpret_cast<char*>(header) - reinterpret_cast<char*>(page) - sizeof(xml_memory_page);
    420636
    421                         assert(page_offset % sizeof(void*) == 0);
     637                        assert(page_offset % xml_memory_block_alignment == 0);
    422638                        assert(page_offset >= 0 && static_cast<size_t>(page_offset) < max_encoded_offset);
    423                         header->page_offset = static_cast<uint16_t>(static_cast<size_t>(page_offset) / sizeof(void*));
     639                        header->page_offset = static_cast<uint16_t>(static_cast<size_t>(page_offset) / xml_memory_block_alignment);
    424640
    425641                        // full_size == 0 for large strings that occupy the whole page
    426                         assert(full_size % sizeof(void*) == 0);
     642                        assert(full_size % xml_memory_block_alignment == 0);
    427643                        assert(full_size < max_encoded_offset || (page->busy_size == full_size && page_offset == 0));
    428                         header->full_size = static_cast<uint16_t>(full_size < max_encoded_offset ? full_size / sizeof(void*) : 0);
     644                        header->full_size = static_cast<uint16_t>(full_size < max_encoded_offset ? full_size / xml_memory_block_alignment : 0);
    429645
    430646                        // round-trip through void* to avoid 'cast increases required alignment of target type' warning
     
    443659
    444660                        // deallocate
    445                         size_t page_offset = sizeof(xml_memory_page) + header->page_offset * sizeof(void*);
     661                        size_t page_offset = sizeof(xml_memory_page) + header->page_offset * xml_memory_block_alignment;
    446662                        xml_memory_page* page = reinterpret_cast<xml_memory_page*>(static_cast<void*>(reinterpret_cast<char*>(header) - page_offset));
    447663
    448664                        // if full_size == 0 then this string occupies the whole page
    449                         size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * sizeof(void*);
     665                        size_t full_size = header->full_size == 0 ? page->busy_size : header->full_size * xml_memory_block_alignment;
    450666
    451667                        deallocate_memory(header, full_size, page);
     668                }
     669
     670                bool reserve()
     671                {
     672                #ifdef PUGIXML_COMPACT
     673                        return _hash->reserve();
     674                #else
     675                        return true;
     676                #endif
    452677                }
    453678
    454679                xml_memory_page* _root;
    455680                size_t _busy_size;
     681
     682        #ifdef PUGIXML_COMPACT
     683                compact_hash_table* _hash;
     684        #endif
    456685        };
    457686
     
    487716                        _root->prev->next = page;
    488717                        _root->prev = page;
    489                 }
    490 
    491                 // allocate inside page
    492                 page->busy_size = size;
     718
     719                        page->busy_size = size;
     720                }
    493721
    494722                return reinterpret_cast<char*>(page) + sizeof(xml_memory_page);
     
    496724PUGI__NS_END
    497725
     726#ifdef PUGIXML_COMPACT
     727PUGI__NS_BEGIN
     728        static const uintptr_t compact_alignment_log2 = 2;
     729        static const uintptr_t compact_alignment = 1 << compact_alignment_log2;
     730
     731        class compact_header
     732        {
     733        public:
     734                compact_header(xml_memory_page* page, unsigned int flags)
     735                {
     736                        PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
     737
     738                        ptrdiff_t offset = (reinterpret_cast<char*>(this) - reinterpret_cast<char*>(page->compact_page_marker));
     739                        assert(offset % compact_alignment == 0 && static_cast<uintptr_t>(offset) < 256 * compact_alignment);
     740
     741                        _page = static_cast<unsigned char>(offset >> compact_alignment_log2);
     742                        _flags = static_cast<unsigned char>(flags);
     743                }
     744
     745                void operator&=(uintptr_t mod)
     746                {
     747                        _flags &= static_cast<unsigned char>(mod);
     748                }
     749
     750                void operator|=(uintptr_t mod)
     751                {
     752                        _flags |= static_cast<unsigned char>(mod);
     753                }
     754
     755                uintptr_t operator&(uintptr_t mod) const
     756                {
     757                        return _flags & mod;
     758                }
     759
     760                xml_memory_page* get_page() const
     761                {
     762                        // round-trip through void* to silence 'cast increases required alignment of target type' warnings
     763                        const char* page_marker = reinterpret_cast<const char*>(this) - (_page << compact_alignment_log2);
     764                        const char* page = page_marker - *reinterpret_cast<const uint32_t*>(static_cast<const void*>(page_marker));
     765
     766                        return const_cast<xml_memory_page*>(reinterpret_cast<const xml_memory_page*>(static_cast<const void*>(page)));
     767                }
     768
     769        private:
     770                unsigned char _page;
     771                unsigned char _flags;
     772        };
     773
     774        PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset)
     775        {
     776                const compact_header* header = reinterpret_cast<const compact_header*>(static_cast<const char*>(object) - header_offset);
     777
     778                return header->get_page();
     779        }
     780
     781        template <int header_offset, typename T> PUGI__FN_NO_INLINE T* compact_get_value(const void* object)
     782        {
     783                return static_cast<T*>(*compact_get_page(object, header_offset)->allocator->_hash->find(object));
     784        }
     785
     786        template <int header_offset, typename T> PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value)
     787        {
     788                *compact_get_page(object, header_offset)->allocator->_hash->insert(object) = value;
     789        }
     790
     791        template <typename T, int header_offset, int start = -126> class compact_pointer
     792        {
     793        public:
     794                compact_pointer(): _data(0)
     795                {
     796                }
     797
     798                void operator=(const compact_pointer& rhs)
     799                {
     800                        *this = rhs + 0;
     801                }
     802
     803                void operator=(T* value)
     804                {
     805                        if (value)
     806                        {
     807                                // value is guaranteed to be compact-aligned; 'this' is not
     808                                // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
     809                                // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
     810                                // compensate for arithmetic shift rounding for negative values
     811                                ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
     812                                ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) - start;
     813
     814                                if (static_cast<uintptr_t>(offset) <= 253)
     815                                        _data = static_cast<unsigned char>(offset + 1);
     816                                else
     817                                {
     818                                        compact_set_value<header_offset>(this, value);
     819
     820                                        _data = 255;
     821                                }
     822                        }
     823                        else
     824                                _data = 0;
     825                }
     826
     827                operator T*() const
     828                {
     829                        if (_data)
     830                        {
     831                                if (_data < 255)
     832                                {
     833                                        uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
     834
     835                                        return reinterpret_cast<T*>(base + ((_data - 1 + start) << compact_alignment_log2));
     836                                }
     837                                else
     838                                        return compact_get_value<header_offset, T>(this);
     839                        }
     840                        else
     841                                return 0;
     842                }
     843
     844                T* operator->() const
     845                {
     846                        return *this;
     847                }
     848
     849        private:
     850                unsigned char _data;
     851        };
     852
     853        template <typename T, int header_offset> class compact_pointer_parent
     854        {
     855        public:
     856                compact_pointer_parent(): _data(0)
     857                {
     858                }
     859
     860                void operator=(const compact_pointer_parent& rhs)
     861                {
     862                        *this = rhs + 0;
     863                }
     864
     865                void operator=(T* value)
     866                {
     867                        if (value)
     868                        {
     869                                // value is guaranteed to be compact-aligned; 'this' is not
     870                                // our decoding is based on 'this' aligned to compact alignment downwards (see operator T*)
     871                                // so for negative offsets (e.g. -3) we need to adjust the diff by compact_alignment - 1 to
     872                                // compensate for arithmetic shift behavior for negative values
     873                                ptrdiff_t diff = reinterpret_cast<char*>(value) - reinterpret_cast<char*>(this);
     874                                ptrdiff_t offset = ((diff + int(compact_alignment - 1)) >> compact_alignment_log2) + 65533;
     875
     876                                if (static_cast<uintptr_t>(offset) <= 65533)
     877                                {
     878                                        _data = static_cast<unsigned short>(offset + 1);
     879                                }
     880                                else
     881                                {
     882                                        xml_memory_page* page = compact_get_page(this, header_offset);
     883
     884                                        if (PUGI__UNLIKELY(page->compact_shared_parent == 0))
     885                                                page->compact_shared_parent = value;
     886
     887                                        if (page->compact_shared_parent == value)
     888                                        {
     889                                                _data = 65534;
     890                                        }
     891                                        else
     892                                        {
     893                                                compact_set_value<header_offset>(this, value);
     894
     895                                                _data = 65535;
     896                                        }
     897                                }
     898                        }
     899                        else
     900                        {
     901                                _data = 0;
     902                        }
     903                }
     904
     905                operator T*() const
     906                {
     907                        if (_data)
     908                        {
     909                                if (_data < 65534)
     910                                {
     911                                        uintptr_t base = reinterpret_cast<uintptr_t>(this) & ~(compact_alignment - 1);
     912
     913                                        return reinterpret_cast<T*>(base + ((_data - 1 - 65533) << compact_alignment_log2));
     914                                }
     915                                else if (_data == 65534)
     916                                        return static_cast<T*>(compact_get_page(this, header_offset)->compact_shared_parent);
     917                                else
     918                                        return compact_get_value<header_offset, T>(this);
     919                        }
     920                        else
     921                                return 0;
     922                }
     923
     924                T* operator->() const
     925                {
     926                        return *this;
     927                }
     928
     929        private:
     930                uint16_t _data;
     931        };
     932
     933        template <int header_offset, int base_offset> class compact_string
     934        {
     935        public:
     936                compact_string(): _data(0)
     937                {
     938                }
     939
     940                void operator=(const compact_string& rhs)
     941                {
     942                        *this = rhs + 0;
     943                }
     944
     945                void operator=(char_t* value)
     946                {
     947                        if (value)
     948                        {
     949                                xml_memory_page* page = compact_get_page(this, header_offset);
     950
     951                                if (PUGI__UNLIKELY(page->compact_string_base == 0))
     952                                        page->compact_string_base = value;
     953
     954                                ptrdiff_t offset = value - page->compact_string_base;
     955
     956                                if (static_cast<uintptr_t>(offset) < (65535 << 7))
     957                                {
     958                                        // round-trip through void* to silence 'cast increases required alignment of target type' warnings
     959                                        uint16_t* base = reinterpret_cast<uint16_t*>(static_cast<void*>(reinterpret_cast<char*>(this) - base_offset));
     960
     961                                        if (*base == 0)
     962                                        {
     963                                                *base = static_cast<uint16_t>((offset >> 7) + 1);
     964                                                _data = static_cast<unsigned char>((offset & 127) + 1);
     965                                        }
     966                                        else
     967                                        {
     968                                                ptrdiff_t remainder = offset - ((*base - 1) << 7);
     969
     970                                                if (static_cast<uintptr_t>(remainder) <= 253)
     971                                                {
     972                                                        _data = static_cast<unsigned char>(remainder + 1);
     973                                                }
     974                                                else
     975                                                {
     976                                                        compact_set_value<header_offset>(this, value);
     977
     978                                                        _data = 255;
     979                                                }
     980                                        }
     981                                }
     982                                else
     983                                {
     984                                        compact_set_value<header_offset>(this, value);
     985
     986                                        _data = 255;
     987                                }
     988                        }
     989                        else
     990                        {
     991                                _data = 0;
     992                        }
     993                }
     994
     995                operator char_t*() const
     996                {
     997                        if (_data)
     998                        {
     999                                if (_data < 255)
     1000                                {
     1001                                        xml_memory_page* page = compact_get_page(this, header_offset);
     1002
     1003                                        // round-trip through void* to silence 'cast increases required alignment of target type' warnings
     1004                                        const uint16_t* base = reinterpret_cast<const uint16_t*>(static_cast<const void*>(reinterpret_cast<const char*>(this) - base_offset));
     1005                                        assert(*base);
     1006
     1007                                        ptrdiff_t offset = ((*base - 1) << 7) + (_data - 1);
     1008
     1009                                        return page->compact_string_base + offset;
     1010                                }
     1011                                else
     1012                                {
     1013                                        return compact_get_value<header_offset, char_t>(this);
     1014                                }
     1015                        }
     1016                        else
     1017                                return 0;
     1018                }
     1019
     1020        private:
     1021                unsigned char _data;
     1022        };
     1023PUGI__NS_END
     1024#endif
     1025
     1026#ifdef PUGIXML_COMPACT
    4981027namespace pugi
    4991028{
    500         /// A 'name=value' XML attribute structure.
    5011029        struct xml_attribute_struct
    5021030        {
    503                 /// Default ctor
    504                 xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0)
    505                 {
    506                 }
    507 
    508                 uintptr_t header;
    509 
    510                 char_t* name;   ///< Pointer to attribute name.
    511                 char_t* value;  ///< Pointer to attribute value.
    512 
    513                 xml_attribute_struct* prev_attribute_c; ///< Previous attribute (cyclic list)
    514                 xml_attribute_struct* next_attribute;   ///< Next attribute
     1031                xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)
     1032                {
     1033                        PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8);
     1034                }
     1035
     1036                impl::compact_header header;
     1037
     1038                uint16_t namevalue_base;
     1039
     1040                impl::compact_string<4, 2> name;
     1041                impl::compact_string<5, 3> value;
     1042
     1043                impl::compact_pointer<xml_attribute_struct, 6> prev_attribute_c;
     1044                impl::compact_pointer<xml_attribute_struct, 7, 0> next_attribute;
    5151045        };
    5161046
    517         /// An XML document tree node.
    5181047        struct xml_node_struct
    5191048        {
    520                 /// Default ctor
    521                 /// \param type - node type
    522                 xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast<uintptr_t>(page) | (type - 1)), parent(0), name(0), value(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
    523                 {
    524                 }
    525 
    526                 uintptr_t header;
    527 
    528                 xml_node_struct*                parent;                                 ///< Pointer to parent
    529 
    530                 char_t*                                 name;                                   ///< Pointer to element name.
    531                 char_t*                                 value;                                  ///< Pointer to any associated string data.
    532 
    533                 xml_node_struct*                first_child;                    ///< First child
    534                
    535                 xml_node_struct*                prev_sibling_c;                 ///< Left brother (cyclic list)
    536                 xml_node_struct*                next_sibling;                   ///< Right brother
    537                
    538                 xml_attribute_struct*   first_attribute;                ///< First attribute
     1049                xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type - 1), namevalue_base(0)
     1050                {
     1051                        PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12);
     1052                }
     1053
     1054                impl::compact_header header;
     1055
     1056                uint16_t namevalue_base;
     1057
     1058                impl::compact_string<4, 2> name;
     1059                impl::compact_string<5, 3> value;
     1060
     1061                impl::compact_pointer_parent<xml_node_struct, 6> parent;
     1062
     1063                impl::compact_pointer<xml_node_struct, 8, 0> first_child;
     1064
     1065                impl::compact_pointer<xml_node_struct,  9>    prev_sibling_c;
     1066                impl::compact_pointer<xml_node_struct, 10, 0> next_sibling;
     1067
     1068                impl::compact_pointer<xml_attribute_struct, 11, 0> first_attribute;
    5391069        };
    5401070}
     1071#else
     1072namespace pugi
     1073{
     1074        struct xml_attribute_struct
     1075        {
     1076                xml_attribute_struct(impl::xml_memory_page* page): header(reinterpret_cast<uintptr_t>(page)), name(0), value(0), prev_attribute_c(0), next_attribute(0)
     1077                {
     1078                }
     1079
     1080                uintptr_t header;
     1081
     1082                char_t* name;
     1083                char_t* value;
     1084
     1085                xml_attribute_struct* prev_attribute_c;
     1086                xml_attribute_struct* next_attribute;
     1087        };
     1088
     1089        struct xml_node_struct
     1090        {
     1091                xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(reinterpret_cast<uintptr_t>(page) | (type - 1)), name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
     1092                {
     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
    5411111
    5421112PUGI__NS_BEGIN
     
    5511121                xml_document_struct(xml_memory_page* page): xml_node_struct(page, node_document), xml_allocator(page), buffer(0), extra_buffers(0)
    5521122                {
     1123                #ifdef PUGIXML_COMPACT
     1124                        _hash = &hash;
     1125                #endif
    5531126                }
    5541127
     
    5561129
    5571130                xml_extra_buffer* extra_buffers;
     1131
     1132        #ifdef PUGIXML_COMPACT
     1133                compact_hash_table hash;
     1134        #endif
    5581135        };
    5591136
    560         inline xml_allocator& get_allocator(const xml_node_struct* node)
    561         {
    562                 assert(node);
    563 
    564                 return *reinterpret_cast<xml_memory_page*>(node->header & xml_memory_page_pointer_mask)->allocator;
     1137        template <typename Object> inline xml_allocator& get_allocator(const Object* object)
     1138        {
     1139                assert(object);
     1140
     1141                return *PUGI__GETPAGE(object)->allocator;
    5651142        }
    5661143
     
    5691146                assert(object);
    5701147
    571                 return *static_cast<xml_document_struct*>(reinterpret_cast<xml_memory_page*>(object->header & xml_memory_page_pointer_mask)->allocator);
     1148                return *static_cast<xml_document_struct*>(PUGI__GETPAGE(object)->allocator);
    5721149        }
    5731150PUGI__NS_END
     
    5781155        {
    5791156                xml_memory_page* page;
    580                 void* memory = alloc.allocate_memory(sizeof(xml_attribute_struct), page);
     1157                void* memory = alloc.allocate_object(sizeof(xml_attribute_struct), page);
     1158                if (!memory) return 0;
    5811159
    5821160                return new (memory) xml_attribute_struct(page);
     
    5861164        {
    5871165                xml_memory_page* page;
    588                 void* memory = alloc.allocate_memory(sizeof(xml_node_struct), page);
     1166                void* memory = alloc.allocate_object(sizeof(xml_node_struct), page);
     1167                if (!memory) return 0;
    5891168
    5901169                return new (memory) xml_node_struct(page, type);
     
    5931172        inline void destroy_attribute(xml_attribute_struct* a, xml_allocator& alloc)
    5941173        {
    595                 uintptr_t header = a->header;
    596 
    597                 if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(a->name);
    598                 if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(a->value);
    599 
    600                 alloc.deallocate_memory(a, sizeof(xml_attribute_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
     1174                if (a->header & impl::xml_memory_page_name_allocated_mask)
     1175                        alloc.deallocate_string(a->name);
     1176
     1177                if (a->header & impl::xml_memory_page_value_allocated_mask)
     1178                        alloc.deallocate_string(a->value);
     1179
     1180                alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a));
    6011181        }
    6021182
    6031183        inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
    6041184        {
    605                 uintptr_t header = n->header;
    606 
    607                 if (header & impl::xml_memory_page_name_allocated_mask) alloc.deallocate_string(n->name);
    608                 if (header & impl::xml_memory_page_value_allocated_mask) alloc.deallocate_string(n->value);
     1185                if (n->header & impl::xml_memory_page_name_allocated_mask)
     1186                        alloc.deallocate_string(n->name);
     1187
     1188                if (n->header & impl::xml_memory_page_value_allocated_mask)
     1189                        alloc.deallocate_string(n->value);
    6091190
    6101191                for (xml_attribute_struct* attr = n->first_attribute; attr; )
     
    6261207                }
    6271208
    628                 alloc.deallocate_memory(n, sizeof(xml_node_struct), reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask));
     1209                alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n));
    6291210        }
    6301211
     
    7981379        PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
    7991380        {
     1381                if (!alloc.reserve()) return 0;
     1382
    8001383                xml_node_struct* child = allocate_node(alloc, type);
    8011384                if (!child) return 0;
     
    8081391        PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)
    8091392        {
     1393                if (!alloc.reserve()) return 0;
     1394
    8101395                xml_attribute_struct* attr = allocate_attribute(alloc);
    8111396                if (!attr) return 0;
     
    10131598        };
    10141599
    1015         template <size_t size> struct wchar_selector;
    1016 
    1017         template <> struct wchar_selector<2>
    1018         {
    1019                 typedef uint16_t type;
    1020                 typedef utf16_counter counter;
    1021                 typedef utf16_writer writer;
    1022         };
    1023 
    1024         template <> struct wchar_selector<4>
    1025         {
    1026                 typedef uint32_t type;
    1027                 typedef utf32_counter counter;
    1028                 typedef utf32_writer writer;
    1029         };
    1030 
    1031         typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
    1032         typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
    1033 
    1034         template <typename Traits, typename opt_swap = opt_false> struct utf_decoder
    1035         {
    1036                 static inline typename Traits::value_type decode_utf8_block(const uint8_t* data, size_t size, typename Traits::value_type result)
     1600        struct utf8_decoder
     1601        {
     1602                typedef uint8_t type;
     1603
     1604                template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
    10371605                {
    10381606                        const uint8_t utf8_byte_mask = 0x3f;
     
    10951663                        return result;
    10961664                }
    1097 
    1098                 static inline typename Traits::value_type decode_utf16_block(const uint16_t* data, size_t size, typename Traits::value_type result)
    1099                 {
    1100                         const uint16_t* end = data + size;
    1101 
    1102                         while (data < end)
    1103                         {
    1104                                 unsigned int lead = opt_swap::value ? endian_swap(*data) : *data;
     1665        };
     1666
     1667        template <typename opt_swap> struct utf16_decoder
     1668        {
     1669                typedef uint16_t type;
     1670
     1671                template <typename Traits> static inline typename Traits::value_type process(const uint16_t* data, size_t size, typename Traits::value_type result, Traits)
     1672                {
     1673                        while (size)
     1674                        {
     1675                                uint16_t lead = opt_swap::value ? endian_swap(*data) : *data;
    11051676
    11061677                                // U+0000..U+D7FF
     
    11091680                                        result = Traits::low(result, lead);
    11101681                                        data += 1;
     1682                                        size -= 1;
    11111683                                }
    11121684                                // U+E000..U+FFFF
     
    11151687                                        result = Traits::low(result, lead);
    11161688                                        data += 1;
     1689                                        size -= 1;
    11171690                                }
    11181691                                // surrogate pair lead
    1119                                 else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && data + 1 < end)
     1692                                else if (static_cast<unsigned int>(lead - 0xD800) < 0x400 && size >= 2)
    11201693                                {
    11211694                                        uint16_t next = opt_swap::value ? endian_swap(data[1]) : data[1];
     
    11251698                                                result = Traits::high(result, 0x10000 + ((lead & 0x3ff) << 10) + (next & 0x3ff));
    11261699                                                data += 2;
     1700                                                size -= 2;
    11271701                                        }
    11281702                                        else
    11291703                                        {
    11301704                                                data += 1;
     1705                                                size -= 1;
    11311706                                        }
    11321707                                }
     
    11341709                                {
    11351710                                        data += 1;
     1711                                        size -= 1;
    11361712                                }
    11371713                        }
     
    11391715                        return result;
    11401716                }
    1141 
    1142                 static inline typename Traits::value_type decode_utf32_block(const uint32_t* data, size_t size, typename Traits::value_type result)
    1143                 {
    1144                         const uint32_t* end = data + size;
    1145 
    1146                         while (data < end)
     1717        };
     1718
     1719        template <typename opt_swap> struct utf32_decoder
     1720        {
     1721                typedef uint32_t type;
     1722
     1723                template <typename Traits> static inline typename Traits::value_type process(const uint32_t* data, size_t size, typename Traits::value_type result, Traits)
     1724                {
     1725                        while (size)
    11471726                        {
    11481727                                uint32_t lead = opt_swap::value ? endian_swap(*data) : *data;
     
    11531732                                        result = Traits::low(result, lead);
    11541733                                        data += 1;
     1734                                        size -= 1;
    11551735                                }
    11561736                                // U+10000..U+10FFFF
     
    11591739                                        result = Traits::high(result, lead);
    11601740                                        data += 1;
     1741                                        size -= 1;
    11611742                                }
    11621743                        }
     
    11641745                        return result;
    11651746                }
    1166 
    1167                 static inline typename Traits::value_type decode_latin1_block(const uint8_t* data, size_t size, typename Traits::value_type result)
    1168                 {
    1169                         for (size_t i = 0; i < size; ++i)
    1170                         {
    1171                                 result = Traits::low(result, data[i]);
     1747        };
     1748
     1749        struct latin1_decoder
     1750        {
     1751                typedef uint8_t type;
     1752
     1753                template <typename Traits> static inline typename Traits::value_type process(const uint8_t* data, size_t size, typename Traits::value_type result, Traits)
     1754                {
     1755                        while (size)
     1756                        {
     1757                                result = Traits::low(result, *data);
     1758                                data += 1;
     1759                                size -= 1;
    11721760                        }
    11731761
    11741762                        return result;
    11751763                }
    1176 
    1177                 static inline typename Traits::value_type decode_wchar_block_impl(const uint16_t* data, size_t size, typename Traits::value_type result)
    1178                 {
    1179                         return decode_utf16_block(data, size, result);
    1180                 }
    1181 
    1182                 static inline typename Traits::value_type decode_wchar_block_impl(const uint32_t* data, size_t size, typename Traits::value_type result)
    1183                 {
    1184                         return decode_utf32_block(data, size, result);
    1185                 }
    1186 
    1187                 static inline typename Traits::value_type decode_wchar_block(const wchar_t* data, size_t size, typename Traits::value_type result)
    1188                 {
    1189                         return decode_wchar_block_impl(reinterpret_cast<const wchar_selector<sizeof(wchar_t)>::type*>(data), size, result);
    1190                 }
    11911764        };
    11921765
    1193         template <typename T> PUGI__FN void convert_utf_endian_swap(T* result, const T* data, size_t length)
    1194         {
    1195                 for (size_t i = 0; i < length; ++i) result[i] = endian_swap(data[i]);
    1196         }
     1766        template <size_t size> struct wchar_selector;
     1767
     1768        template <> struct wchar_selector<2>
     1769        {
     1770                typedef uint16_t type;
     1771                typedef utf16_counter counter;
     1772                typedef utf16_writer writer;
     1773                typedef utf16_decoder<opt_false> decoder;
     1774        };
     1775
     1776        template <> struct wchar_selector<4>
     1777        {
     1778                typedef uint32_t type;
     1779                typedef utf32_counter counter;
     1780                typedef utf32_writer writer;
     1781                typedef utf32_decoder<opt_false> decoder;
     1782        };
     1783
     1784        typedef wchar_selector<sizeof(wchar_t)>::counter wchar_counter;
     1785        typedef wchar_selector<sizeof(wchar_t)>::writer wchar_writer;
     1786
     1787        struct wchar_decoder
     1788        {
     1789                typedef wchar_t type;
     1790
     1791                template <typename Traits> static inline typename Traits::value_type process(const wchar_t* data, size_t size, typename Traits::value_type result, Traits traits)
     1792                {
     1793                        typedef wchar_selector<sizeof(wchar_t)>::decoder decoder;
     1794
     1795                        return decoder::process(reinterpret_cast<const typename decoder::type*>(data), size, result, traits);
     1796                }
     1797        };
    11971798
    11981799#ifdef PUGIXML_WCHAR_MODE
    11991800        PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
    12001801        {
    1201                 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])));
     1802                for (size_t i = 0; i < length; ++i)
     1803                        result[i] = static_cast<wchar_t>(endian_swap(static_cast<wchar_selector<sizeof(wchar_t)>::type>(data[i])));
    12021804        }
    12031805#endif
     
    14082010        }
    14092011
    1410         PUGI__FN bool convert_buffer_utf8(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size)
    1411         {
    1412                 const uint8_t* data = static_cast<const uint8_t*>(contents);
    1413                 size_t data_length = size;
     2012        template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
     2013        {
     2014                const typename D::type* data = static_cast<const typename D::type*>(contents);
     2015                size_t data_length = size / sizeof(typename D::type);
    14142016
    14152017                // first pass: get length in wchar_t units
    1416                 size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, data_length, 0);
     2018                size_t length = D::process(data, data_length, 0, wchar_counter());
    14172019
    14182020                // allocate buffer of suitable length
     
    14202022                if (!buffer) return false;
    14212023
    1422                 // second pass: convert utf8 input to wchar_t
     2024                // second pass: convert utf16 input to wchar_t
    14232025                wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
    1424                 wchar_writer::value_type oend = utf_decoder<wchar_writer>::decode_utf8_block(data, data_length, obegin);
     2026                wchar_writer::value_type oend = D::process(data, data_length, obegin, wchar_writer());
    14252027
    14262028                assert(oend == obegin + length);
     
    14332035        }
    14342036
    1435         template <typename opt_swap> PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
    1436         {
    1437                 const uint16_t* data = static_cast<const uint16_t*>(contents);
    1438                 size_t data_length = size / sizeof(uint16_t);
    1439 
    1440                 // first pass: get length in wchar_t units
    1441                 size_t length = utf_decoder<wchar_counter, opt_swap>::decode_utf16_block(data, data_length, 0);
     2037        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)
     2038        {
     2039                // get native encoding
     2040                xml_encoding wchar_encoding = get_wchar_encoding();
     2041
     2042                // fast path: no conversion required
     2043                if (encoding == wchar_encoding)
     2044                        return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
     2045
     2046                // only endian-swapping is required
     2047                if (need_endian_swap_utf(encoding, wchar_encoding))
     2048                        return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
     2049
     2050                // source encoding is utf8
     2051                if (encoding == encoding_utf8)
     2052                        return convert_buffer_generic(out_buffer, out_length, contents, size, utf8_decoder());
     2053
     2054                // source encoding is utf16
     2055                if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
     2056                {
     2057                        xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
     2058
     2059                        return (native_encoding == encoding) ?
     2060                                convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
     2061                                convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
     2062                }
     2063
     2064                // source encoding is utf32
     2065                if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
     2066                {
     2067                        xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
     2068
     2069                        return (native_encoding == encoding) ?
     2070                                convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
     2071                                convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
     2072                }
     2073
     2074                // source encoding is latin1
     2075                if (encoding == encoding_latin1)
     2076                        return convert_buffer_generic(out_buffer, out_length, contents, size, latin1_decoder());
     2077
     2078                assert(!"Invalid encoding");
     2079                return false;
     2080        }
     2081#else
     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);
     2086
     2087                // first pass: get length in utf8 units
     2088                size_t length = D::process(data, data_length, 0, utf8_counter());
    14422089
    14432090                // allocate buffer of suitable length
     
    14452092                if (!buffer) return false;
    14462093
    1447                 // second pass: convert utf16 input to wchar_t
    1448                 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
    1449                 wchar_writer::value_type oend = utf_decoder<wchar_writer, opt_swap>::decode_utf16_block(data, data_length, obegin);
     2094                // second pass: convert utf16 input to utf8
     2095                uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
     2096                uint8_t* oend = D::process(data, data_length, obegin, utf8_writer());
    14502097
    14512098                assert(oend == obegin + length);
     
    14582105        }
    14592106
    1460         template <typename opt_swap> PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
    1461         {
    1462                 const uint32_t* data = static_cast<const uint32_t*>(contents);
    1463                 size_t data_length = size / sizeof(uint32_t);
    1464 
    1465                 // first pass: get length in wchar_t units
    1466                 size_t length = utf_decoder<wchar_counter, opt_swap>::decode_utf32_block(data, data_length, 0);
     2107        PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
     2108        {
     2109                for (size_t i = 0; i < size; ++i)
     2110                        if (data[i] > 127)
     2111                                return i;
     2112
     2113                return size;
     2114        }
     2115
     2116        PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
     2117        {
     2118                const uint8_t* data = static_cast<const uint8_t*>(contents);
     2119                size_t data_length = size;
     2120
     2121                // get size of prefix that does not need utf8 conversion
     2122                size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
     2123                assert(prefix_length <= data_length);
     2124
     2125                const uint8_t* postfix = data + prefix_length;
     2126                size_t postfix_length = data_length - prefix_length;
     2127
     2128                // if no conversion is needed, just return the original buffer
     2129                if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
     2130
     2131                // first pass: get length in utf8 units
     2132                size_t length = prefix_length + latin1_decoder::process(postfix, postfix_length, 0, utf8_counter());
    14672133
    14682134                // allocate buffer of suitable length
     
    14702136                if (!buffer) return false;
    14712137
    1472                 // second pass: convert utf32 input to wchar_t
    1473                 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
    1474                 wchar_writer::value_type oend = utf_decoder<wchar_writer, opt_swap>::decode_utf32_block(data, data_length, obegin);
     2138                // second pass: convert latin1 input to utf8
     2139                memcpy(buffer, data, prefix_length);
     2140
     2141                uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
     2142                uint8_t* oend = latin1_decoder::process(postfix, postfix_length, obegin + prefix_length, utf8_writer());
    14752143
    14762144                assert(oend == obegin + length);
     
    14832151        }
    14842152
    1485         PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size)
    1486         {
    1487                 const uint8_t* data = static_cast<const uint8_t*>(contents);
    1488                 size_t data_length = size;
    1489 
    1490                 // get length in wchar_t units
    1491                 size_t length = data_length;
    1492 
    1493                 // allocate buffer of suitable length
    1494                 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
    1495                 if (!buffer) return false;
    1496 
    1497                 // convert latin1 input to wchar_t
    1498                 wchar_writer::value_type obegin = reinterpret_cast<wchar_writer::value_type>(buffer);
    1499                 wchar_writer::value_type oend = utf_decoder<wchar_writer>::decode_latin1_block(data, data_length, obegin);
    1500 
    1501                 assert(oend == obegin + length);
    1502                 *oend = 0;
    1503 
    1504                 out_buffer = buffer;
    1505                 out_length = length + 1;
    1506 
    1507                 return true;
    1508         }
    1509 
    15102153        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)
    15112154        {
    1512                 // get native encoding
    1513                 xml_encoding wchar_encoding = get_wchar_encoding();
    1514 
    15152155                // fast path: no conversion required
    1516                 if (encoding == wchar_encoding) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
    1517 
    1518                 // only endian-swapping is required
    1519                 if (need_endian_swap_utf(encoding, wchar_encoding)) return convert_buffer_endian_swap(out_buffer, out_length, contents, size, is_mutable);
    1520 
    1521                 // source encoding is utf8
    1522                 if (encoding == encoding_utf8) return convert_buffer_utf8(out_buffer, out_length, contents, size);
     2156                if (encoding == encoding_utf8)
     2157                        return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
    15232158
    15242159                // source encoding is utf16
     
    15282163
    15292164                        return (native_encoding == encoding) ?
    1530                                 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
    1531                                 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
     2165                                convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_false>()) :
     2166                                convert_buffer_generic(out_buffer, out_length, contents, size, utf16_decoder<opt_true>());
    15322167                }
    15332168
     
    15382173
    15392174                        return (native_encoding == encoding) ?
    1540                                 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
    1541                                 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
     2175                                convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_false>()) :
     2176                                convert_buffer_generic(out_buffer, out_length, contents, size, utf32_decoder<opt_true>());
    15422177                }
    15432178
    15442179                // source encoding is latin1
    1545                 if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size);
     2180                if (encoding == encoding_latin1)
     2181                        return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
    15462182
    15472183                assert(!"Invalid encoding");
    15482184                return false;
    15492185        }
    1550 #else
    1551         template <typename opt_swap> PUGI__FN bool convert_buffer_utf16(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
    1552         {
    1553                 const uint16_t* data = static_cast<const uint16_t*>(contents);
    1554                 size_t data_length = size / sizeof(uint16_t);
    1555 
    1556                 // first pass: get length in utf8 units
    1557                 size_t length = utf_decoder<utf8_counter, opt_swap>::decode_utf16_block(data, data_length, 0);
    1558 
    1559                 // allocate buffer of suitable length
    1560                 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
    1561                 if (!buffer) return false;
    1562 
    1563                 // second pass: convert utf16 input to utf8
    1564                 uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
    1565                 uint8_t* oend = utf_decoder<utf8_writer, opt_swap>::decode_utf16_block(data, data_length, obegin);
    1566 
    1567                 assert(oend == obegin + length);
    1568                 *oend = 0;
    1569 
    1570                 out_buffer = buffer;
    1571                 out_length = length + 1;
    1572 
    1573                 return true;
    1574         }
    1575 
    1576         template <typename opt_swap> PUGI__FN bool convert_buffer_utf32(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, opt_swap)
    1577         {
    1578                 const uint32_t* data = static_cast<const uint32_t*>(contents);
    1579                 size_t data_length = size / sizeof(uint32_t);
    1580 
    1581                 // first pass: get length in utf8 units
    1582                 size_t length = utf_decoder<utf8_counter, opt_swap>::decode_utf32_block(data, data_length, 0);
    1583 
    1584                 // allocate buffer of suitable length
    1585                 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
    1586                 if (!buffer) return false;
    1587 
    1588                 // second pass: convert utf32 input to utf8
    1589                 uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
    1590                 uint8_t* oend = utf_decoder<utf8_writer, opt_swap>::decode_utf32_block(data, data_length, obegin);
    1591 
    1592                 assert(oend == obegin + length);
    1593                 *oend = 0;
    1594 
    1595                 out_buffer = buffer;
    1596                 out_length = length + 1;
    1597 
    1598                 return true;
    1599         }
    1600 
    1601         PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
    1602         {
    1603                 for (size_t i = 0; i < size; ++i)
    1604                         if (data[i] > 127)
    1605                                 return i;
    1606 
    1607                 return size;
    1608         }
    1609 
    1610         PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
    1611         {
    1612                 const uint8_t* data = static_cast<const uint8_t*>(contents);
    1613                 size_t data_length = size;
    1614 
    1615                 // get size of prefix that does not need utf8 conversion
    1616                 size_t prefix_length = get_latin1_7bit_prefix_length(data, data_length);
    1617                 assert(prefix_length <= data_length);
    1618 
    1619                 const uint8_t* postfix = data + prefix_length;
    1620                 size_t postfix_length = data_length - prefix_length;
    1621 
    1622                 // if no conversion is needed, just return the original buffer
    1623                 if (postfix_length == 0) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
    1624 
    1625                 // first pass: get length in utf8 units
    1626                 size_t length = prefix_length + utf_decoder<utf8_counter>::decode_latin1_block(postfix, postfix_length, 0);
    1627 
    1628                 // allocate buffer of suitable length
    1629                 char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
    1630                 if (!buffer) return false;
    1631 
    1632                 // second pass: convert latin1 input to utf8
    1633                 memcpy(buffer, data, prefix_length);
    1634 
    1635                 uint8_t* obegin = reinterpret_cast<uint8_t*>(buffer);
    1636                 uint8_t* oend = utf_decoder<utf8_writer>::decode_latin1_block(postfix, postfix_length, obegin + prefix_length);
    1637 
    1638                 assert(oend == obegin + length);
    1639                 *oend = 0;
    1640 
    1641                 out_buffer = buffer;
    1642                 out_length = length + 1;
    1643 
    1644                 return true;
    1645         }
    1646 
    1647         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)
    1648         {
    1649                 // fast path: no conversion required
    1650                 if (encoding == encoding_utf8) return get_mutable_buffer(out_buffer, out_length, contents, size, is_mutable);
    1651 
    1652                 // source encoding is utf16
    1653                 if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
    1654                 {
    1655                         xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
    1656 
    1657                         return (native_encoding == encoding) ?
    1658                                 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_false()) :
    1659                                 convert_buffer_utf16(out_buffer, out_length, contents, size, opt_true());
    1660                 }
    1661 
    1662                 // source encoding is utf32
    1663                 if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
    1664                 {
    1665                         xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
    1666 
    1667                         return (native_encoding == encoding) ?
    1668                                 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_false()) :
    1669                                 convert_buffer_utf32(out_buffer, out_length, contents, size, opt_true());
    1670                 }
    1671 
    1672                 // source encoding is latin1
    1673                 if (encoding == encoding_latin1) return convert_buffer_latin1(out_buffer, out_length, contents, size, is_mutable);
    1674 
    1675                 assert(!"Invalid encoding");
    1676                 return false;
    1677         }
    16782186#endif
    16792187
     
    16812189        {
    16822190                // get length in utf8 characters
    1683                 return utf_decoder<utf8_counter>::decode_wchar_block(str, length, 0);
     2191                return wchar_decoder::process(str, length, 0, utf8_counter());
    16842192        }
    16852193
     
    16882196                // convert to utf8
    16892197                uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
    1690                 uint8_t* end = utf_decoder<utf8_writer>::decode_wchar_block(str, length, begin);
     2198                uint8_t* end = wchar_decoder::process(str, length, begin, utf8_writer());
    16912199       
    16922200                assert(begin + size == end);
    16932201                (void)!end;
    1694 
    1695                 // zero-terminate
    1696                 buffer[size] = 0;
     2202                (void)!size;
    16972203        }
    16982204       
     
    17182224
    17192225                // first pass: get length in wchar_t units
    1720                 size_t length = utf_decoder<wchar_counter>::decode_utf8_block(data, size, 0);
     2226                size_t length = utf8_decoder::process(data, size, 0, wchar_counter());
    17212227
    17222228                // allocate resulting string
     
    17282234                {
    17292235                        wchar_writer::value_type begin = reinterpret_cast<wchar_writer::value_type>(&result[0]);
    1730                         wchar_writer::value_type end = utf_decoder<wchar_writer>::decode_utf8_block(data, size, begin);
     2236                        wchar_writer::value_type end = utf8_decoder::process(data, size, begin, wchar_writer());
    17312237
    17322238                        assert(begin + length == end);
     
    17382244#endif
    17392245
    1740         inline bool strcpy_insitu_allow(size_t length, uintptr_t header, uintptr_t header_mask, char_t* target)
     2246        template <typename Header>
     2247        inline bool strcpy_insitu_allow(size_t length, const Header& header, uintptr_t header_mask, char_t* target)
    17412248        {
    17422249                // never reuse shared memory
     
    17542261        }
    17552262
    1756         PUGI__FN bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source)
    1757         {
    1758                 assert(header);
    1759 
    1760                 size_t source_length = strlength(source);
    1761 
     2263        template <typename String, typename Header>
     2264        PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length)
     2265        {
    17622266                if (source_length == 0)
    17632267                {
    17642268                        // empty string and null pointer are equivalent, so just deallocate old memory
    1765                         xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
     2269                        xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
    17662270
    17672271                        if (header & header_mask) alloc->deallocate_string(dest);
     
    17762280                {
    17772281                        // we can reuse old buffer, so just copy the new data (including zero terminator)
    1778                         memcpy(dest, source, (source_length + 1) * sizeof(char_t));
     2282                        memcpy(dest, source, source_length * sizeof(char_t));
     2283                        dest[source_length] = 0;
    17792284                       
    17802285                        return true;
     
    17822287                else
    17832288                {
    1784                         xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
     2289                        xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
     2290
     2291                        if (!alloc->reserve()) return false;
    17852292
    17862293                        // allocate new buffer
     
    17892296
    17902297                        // copy the string (including zero terminator)
    1791                         memcpy(buf, source, (source_length + 1) * sizeof(char_t));
     2298                        memcpy(buf, source, source_length * sizeof(char_t));
     2299                        buf[source_length] = 0;
    17922300
    17932301                        // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures)
     
    23132821        {
    23142822                xml_allocator alloc;
     2823                xml_allocator* alloc_state;
    23152824                char_t* error_offset;
    23162825                xml_parse_status error_status;
    23172826               
    2318                 xml_parser(const xml_allocator& alloc_): alloc(alloc_), error_offset(0), error_status(status_ok)
    2319                 {
     2827                xml_parser(xml_allocator* alloc_): alloc(*alloc_), alloc_state(alloc_), error_offset(0), error_status(status_ok)
     2828                {
     2829                }
     2830
     2831                ~xml_parser()
     2832                {
     2833                        *alloc_state = alloc;
    23202834                }
    23212835
     
    26153129                                                // store value and step over >
    26163130                                                cursor->value = value;
     3131
    26173132                                                PUGI__POPNODE();
    26183133
     
    28943409                static xml_parse_result parse(char_t* buffer, size_t length, xml_document_struct* xmldoc, xml_node_struct* root, unsigned int optmsk)
    28953410                {
    2896                         // allocator object is a part of document object
    2897                         xml_allocator& alloc_ = *static_cast<xml_allocator*>(xmldoc);
    2898 
    28993411                        // early-out for empty documents
    29003412                        if (length == 0)
     
    29023414
    29033415                        // get last child of the root before parsing
    2904                         xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c : 0;
     3416                        xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
    29053417       
    29063418                        // create parser on stack
    2907                         xml_parser parser(alloc_);
     3419                        xml_parser parser(static_cast<xml_allocator*>(xmldoc));
    29083420
    29093421                        // save last character and make buffer zero-terminated (speeds up parsing)
     
    29173429                        parser.parse_tree(buffer_data, root, optmsk, endch);
    29183430
    2919                         // update allocator state
    2920                         alloc_ = parser.alloc;
    2921 
    29223431                        xml_parse_result result = make_parse_result(parser.error_status, parser.error_offset ? parser.error_offset - buffer : 0);
    29233432                        assert(result.offset >= 0 && static_cast<size_t>(result.offset) <= length);
     
    29303439
    29313440                                // check if there are any element nodes parsed
    2932                                 xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling : root->first_child;
     3441                                xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0;
    29333442
    29343443                                if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
     
    29743483        }
    29753484
     3485        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)
     3486        {
     3487                PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
     3488
     3489                typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
     3490
     3491                return static_cast<size_t>(end - dest) * sizeof(*dest);
     3492        }
     3493
     3494        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)
     3495        {
     3496                PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
     3497
     3498                typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
     3499
     3500                if (opt_swap)
     3501                {
     3502                        for (typename T::value_type i = dest; i != end; ++i)
     3503                                *i = endian_swap(*i);
     3504                }
     3505
     3506                return static_cast<size_t>(end - dest) * sizeof(*dest);
     3507        }
     3508
    29763509#ifdef PUGIXML_WCHAR_MODE
    29773510        PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
     
    29953528                // convert to utf8
    29963529                if (encoding == encoding_utf8)
    2997                 {
    2998                         uint8_t* dest = r_u8;
    2999                         uint8_t* end = utf_decoder<utf8_writer>::decode_wchar_block(data, length, dest);
    3000 
    3001                         return static_cast<size_t>(end - dest);
    3002                 }
     3530                        return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), utf8_writer());
    30033531
    30043532                // convert to utf16
    30053533                if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
    30063534                {
    3007                         uint16_t* dest = r_u16;
    3008 
    3009                         // convert to native utf16
    3010                         uint16_t* end = utf_decoder<utf16_writer>::decode_wchar_block(data, length, dest);
    3011 
    3012                         // swap if necessary
    30133535                        xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
    30143536
    3015                         if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
    3016 
    3017                         return static_cast<size_t>(end - dest) * sizeof(uint16_t);
     3537                        return convert_buffer_output_generic(r_u16, data, length, wchar_decoder(), utf16_writer(), native_encoding != encoding);
    30183538                }
    30193539
     
    30213541                if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
    30223542                {
    3023                         uint32_t* dest = r_u32;
    3024 
    3025                         // convert to native utf32
    3026                         uint32_t* end = utf_decoder<utf32_writer>::decode_wchar_block(data, length, dest);
    3027 
    3028                         // swap if necessary
    30293543                        xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
    30303544
    3031                         if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
    3032 
    3033                         return static_cast<size_t>(end - dest) * sizeof(uint32_t);
     3545                        return convert_buffer_output_generic(r_u32, data, length, wchar_decoder(), utf32_writer(), native_encoding != encoding);
    30343546                }
    30353547
    30363548                // convert to latin1
    30373549                if (encoding == encoding_latin1)
    3038                 {
    3039                         uint8_t* dest = r_u8;
    3040                         uint8_t* end = utf_decoder<latin1_writer>::decode_wchar_block(data, length, dest);
    3041 
    3042                         return static_cast<size_t>(end - dest);
    3043                 }
     3550                        return convert_buffer_output_generic(r_u8, data, length, wchar_decoder(), latin1_writer());
    30443551
    30453552                assert(!"Invalid encoding");
     
    30673574                if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
    30683575                {
    3069                         uint16_t* dest = r_u16;
    3070 
    3071                         // convert to native utf16
    3072                         uint16_t* end = utf_decoder<utf16_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
    3073 
    3074                         // swap if necessary
    30753576                        xml_encoding native_encoding = is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
    30763577
    3077                         if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
    3078 
    3079                         return static_cast<size_t>(end - dest) * sizeof(uint16_t);
     3578                        return convert_buffer_output_generic(r_u16, data, length, utf8_decoder(), utf16_writer(), native_encoding != encoding);
    30803579                }
    30813580
    30823581                if (encoding == encoding_utf32_be || encoding == encoding_utf32_le)
    30833582                {
    3084                         uint32_t* dest = r_u32;
    3085 
    3086                         // convert to native utf32
    3087                         uint32_t* end = utf_decoder<utf32_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
    3088 
    3089                         // swap if necessary
    30903583                        xml_encoding native_encoding = is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
    30913584
    3092                         if (native_encoding != encoding) convert_utf_endian_swap(dest, dest, static_cast<size_t>(end - dest));
    3093 
    3094                         return static_cast<size_t>(end - dest) * sizeof(uint32_t);
     3585                        return convert_buffer_output_generic(r_u32, data, length, utf8_decoder(), utf32_writer(), native_encoding != encoding);
    30953586                }
    30963587
    30973588                if (encoding == encoding_latin1)
    3098                 {
    3099                         uint8_t* dest = r_u8;
    3100                         uint8_t* end = utf_decoder<latin1_writer>::decode_utf8_block(reinterpret_cast<const uint8_t*>(data), length, dest);
    3101 
    3102                         return static_cast<size_t>(end - dest);
    3103                 }
     3589                        return convert_buffer_output_generic(r_u8, data, length, utf8_decoder(), latin1_writer());
    31043590
    31053591                assert(!"Invalid encoding");
     
    31173603                {
    31183604                        PUGI__STATIC_ASSERT(bufcapacity >= 8);
    3119                 }
    3120 
    3121                 ~xml_buffered_writer()
    3122                 {
    3123                         flush();
    31243605                }
    31253606
     
    34843965        }
    34853966
    3486         PUGI__FN void node_output_attributes(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)
     3967        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)
    34873968        {
    34883969                const char_t* default_name = PUGIXML_TEXT(":anonymous");
     
    34903971                for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
    34913972                {
    3492                         writer.write(' ');
    3493                         writer.write_string(a->name ? a->name : default_name);
     3973                        if ((flags & (format_indent_attributes | format_raw)) == format_indent_attributes)
     3974                        {
     3975                                writer.write('\n');
     3976
     3977                                text_output_indent(writer, indent, indent_length, depth + 1);
     3978                        }
     3979                        else
     3980                        {
     3981                                writer.write(' ');
     3982                        }
     3983
     3984                        writer.write_string(a->name ? a->name + 0 : default_name);
    34943985                        writer.write('=', '"');
    34953986
     
    35013992        }
    35023993
    3503         PUGI__FN bool node_output_start(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)
     3994        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)
    35043995        {
    35053996                const char_t* default_name = PUGIXML_TEXT(":anonymous");
    3506                 const char_t* name = node->name ? node->name : default_name;
     3997                const char_t* name = node->name ? node->name + 0 : default_name;
    35073998
    35083999                writer.write('<');
     
    35104001
    35114002                if (node->first_attribute)
    3512                         node_output_attributes(writer, node, flags);
     4003                        node_output_attributes(writer, node, indent, indent_length, flags, depth);
    35134004
    35144005                if (!node->first_child)
     
    35294020        {
    35304021                const char_t* default_name = PUGIXML_TEXT(":anonymous");
    3531                 const char_t* name = node->name ? node->name : default_name;
     4022                const char_t* name = node->name ? node->name + 0 : default_name;
    35324023
    35334024                writer.write('<', '/');
     
    35434034                {
    35444035                        case node_pcdata:
    3545                                 text_output(writer, node->value ? node->value : PUGIXML_TEXT(""), ctx_special_pcdata, flags);
     4036                                text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags);
    35464037                                break;
    35474038
    35484039                        case node_cdata:
    3549                                 text_output_cdata(writer, node->value ? node->value : PUGIXML_TEXT(""));
     4040                                text_output_cdata(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
    35504041                                break;
    35514042
    35524043                        case node_comment:
    3553                                 node_output_comment(writer, node->value ? node->value : PUGIXML_TEXT(""));
     4044                                node_output_comment(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""));
    35544045                                break;
    35554046
    35564047                        case node_pi:
    35574048                                writer.write('<', '?');
    3558                                 writer.write_string(node->name ? node->name : default_name);
     4049                                writer.write_string(node->name ? node->name + 0 : default_name);
    35594050
    35604051                                if (node->value)
     
    35694060                        case node_declaration:
    35704061                                writer.write('<', '?');
    3571                                 writer.write_string(node->name ? node->name : default_name);
    3572                                 node_output_attributes(writer, node, flags);
     4062                                writer.write_string(node->name ? node->name + 0 : default_name);
     4063                                node_output_attributes(writer, node, PUGIXML_TEXT(""), 0, flags | format_raw, 0);
    35734064                                writer.write('?', '>');
    35744065                                break;
     
    36004091        PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth)
    36014092        {
    3602                 size_t indent_length = ((flags & (format_indent | format_raw)) == format_indent) ? strlength(indent) : 0;
     4093                size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0;
    36034094                unsigned int indent_flags = indent_indent;
    36044095
     
    36284119                                        indent_flags = indent_newline | indent_indent;
    36294120
    3630                                         if (node_output_start(writer, node, flags))
     4121                                        if (node_output_start(writer, node, indent, indent_length, flags, depth))
    36314122                                        {
    36324123                                                node = node->first_child;
     
    37474238        }
    37484239
    3749         PUGI__FN void node_copy_string(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char_t* source, uintptr_t& source_header, xml_allocator* alloc)
     4240        template <typename String, typename Header>
     4241        PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)
    37504242        {
    37514243                assert(!dest && (header & header_mask) == 0);
     
    37624254                        }
    37634255                        else
    3764                                 strcpy_insitu(dest, header, header_mask, source);
     4256                                strcpy_insitu(dest, header, header_mask, source, strlength(source));
    37654257                }
    37664258        }
     
    38284320        }
    38294321
     4322        PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
     4323        {
     4324                xml_allocator& alloc = get_allocator(da);
     4325                xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0;
     4326
     4327                node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
     4328                node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
     4329        }
     4330
    38304331        inline bool is_text_node(xml_node_struct* node)
    38314332        {
     
    38364337
    38374338        // get value with conversion functions
    3838         PUGI__FN int get_integer_base(const char_t* value)
    3839         {
     4339        template <typename U> U string_to_integer(const char_t* value, U minneg, U maxpos)
     4340        {
     4341                U result = 0;
    38404342                const char_t* s = value;
    38414343
     
    38434345                        s++;
    38444346
    3845                 if (*s == '-')
    3846                         s++;
    3847 
    3848                 return (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) ? 16 : 10;
    3849         }
    3850 
    3851         PUGI__FN int get_value_int(const char_t* value, int def)
    3852         {
    3853                 if (!value) return def;
    3854 
    3855                 int base = get_integer_base(value);
    3856 
    3857         #ifdef PUGIXML_WCHAR_MODE
    3858                 return static_cast<int>(wcstol(value, 0, base));
    3859         #else
    3860                 return static_cast<int>(strtol(value, 0, base));
    3861         #endif
    3862         }
    3863 
    3864         PUGI__FN unsigned int get_value_uint(const char_t* value, unsigned int def)
    3865         {
    3866                 if (!value) return def;
    3867 
    3868                 int base = get_integer_base(value);
    3869 
    3870         #ifdef PUGIXML_WCHAR_MODE
    3871                 return static_cast<unsigned int>(wcstoul(value, 0, base));
    3872         #else
    3873                 return static_cast<unsigned int>(strtoul(value, 0, base));
    3874         #endif
    3875         }
    3876 
    3877         PUGI__FN double get_value_double(const char_t* value, double def)
    3878         {
    3879                 if (!value) return def;
    3880 
     4347                bool negative = (*s == '-');
     4348
     4349                s += (*s == '+' || *s == '-');
     4350
     4351                bool overflow = false;
     4352
     4353                if (s[0] == '0' && (s[1] | ' ') == 'x')
     4354                {
     4355                        s += 2;
     4356
     4357                        // since overflow detection relies on length of the sequence skip leading zeros
     4358                        while (*s == '0')
     4359                                s++;
     4360
     4361                        const char_t* start = s;
     4362
     4363                        for (;;)
     4364                        {
     4365                                if (static_cast<unsigned>(*s - '0') < 10)
     4366                                        result = result * 16 + (*s - '0');
     4367                                else if (static_cast<unsigned>((*s | ' ') - 'a') < 6)
     4368                                        result = result * 16 + ((*s | ' ') - 'a' + 10);
     4369                                else
     4370                                        break;
     4371
     4372                                s++;
     4373                        }
     4374
     4375                        size_t digits = static_cast<size_t>(s - start);
     4376
     4377                        overflow = digits > sizeof(U) * 2;
     4378                }
     4379                else
     4380                {
     4381                        // since overflow detection relies on length of the sequence skip leading zeros
     4382                        while (*s == '0')
     4383                                s++;
     4384
     4385                        const char_t* start = s;
     4386
     4387                        for (;;)
     4388                        {
     4389                                if (static_cast<unsigned>(*s - '0') < 10)
     4390                                        result = result * 10 + (*s - '0');
     4391                                else
     4392                                        break;
     4393
     4394                                s++;
     4395                        }
     4396
     4397                        size_t digits = static_cast<size_t>(s - start);
     4398
     4399                        PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);
     4400
     4401                        const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
     4402                        const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6';
     4403                        const size_t high_bit = sizeof(U) * 8 - 1;
     4404
     4405                        overflow = digits >= max_digits10 && !(digits == max_digits10 && (*start < max_lead || (*start == max_lead && result >> high_bit)));
     4406                }
     4407
     4408                if (negative)
     4409                        return (overflow || result > minneg) ? 0 - minneg : 0 - result;
     4410                else
     4411                        return (overflow || result > maxpos) ? maxpos : result;
     4412        }
     4413
     4414        PUGI__FN int get_value_int(const char_t* value)
     4415        {
     4416                return string_to_integer<unsigned int>(value, 0 - static_cast<unsigned int>(INT_MIN), INT_MAX);
     4417        }
     4418
     4419        PUGI__FN unsigned int get_value_uint(const char_t* value)
     4420        {
     4421                return string_to_integer<unsigned int>(value, 0, UINT_MAX);
     4422        }
     4423
     4424        PUGI__FN double get_value_double(const char_t* value)
     4425        {
    38814426        #ifdef PUGIXML_WCHAR_MODE
    38824427                return wcstod(value, 0);
     
    38864431        }
    38874432
    3888         PUGI__FN float get_value_float(const char_t* value, float def)
    3889         {
    3890                 if (!value) return def;
    3891 
     4433        PUGI__FN float get_value_float(const char_t* value)
     4434        {
    38924435        #ifdef PUGIXML_WCHAR_MODE
    38934436                return static_cast<float>(wcstod(value, 0));
     
    38974440        }
    38984441
    3899         PUGI__FN bool get_value_bool(const char_t* value, bool def)
    3900         {
    3901                 if (!value) return def;
    3902 
     4442        PUGI__FN bool get_value_bool(const char_t* value)
     4443        {
    39034444                // only look at first char
    39044445                char_t first = *value;
     
    39094450
    39104451#ifdef PUGIXML_HAS_LONG_LONG
    3911         PUGI__FN long long get_value_llong(const char_t* value, long long def)
    3912         {
    3913                 if (!value) return def;
    3914 
    3915                 int base = get_integer_base(value);
    3916 
    3917         #ifdef PUGIXML_WCHAR_MODE
    3918                 #ifdef PUGI__MSVC_CRT_VERSION
    3919                         return _wcstoi64(value, 0, base);
    3920                 #else
    3921                         return wcstoll(value, 0, base);
    3922                 #endif
    3923         #else
    3924                 #ifdef PUGI__MSVC_CRT_VERSION
    3925                         return _strtoi64(value, 0, base);
    3926                 #else
    3927                         return strtoll(value, 0, base);
    3928                 #endif
    3929         #endif
    3930         }
    3931 
    3932         PUGI__FN unsigned long long get_value_ullong(const char_t* value, unsigned long long def)
    3933         {
    3934                 if (!value) return def;
    3935 
    3936                 int base = get_integer_base(value);
    3937 
    3938         #ifdef PUGIXML_WCHAR_MODE
    3939                 #ifdef PUGI__MSVC_CRT_VERSION
    3940                         return _wcstoui64(value, 0, base);
    3941                 #else
    3942                         return wcstoull(value, 0, base);
    3943                 #endif
    3944         #else
    3945                 #ifdef PUGI__MSVC_CRT_VERSION
    3946                         return _strtoui64(value, 0, base);
    3947                 #else
    3948                         return strtoull(value, 0, base);
    3949                 #endif
    3950         #endif
     4452        PUGI__FN long long get_value_llong(const char_t* value)
     4453        {
     4454                return string_to_integer<unsigned long long>(value, 0 - static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);
     4455        }
     4456
     4457        PUGI__FN unsigned long long get_value_ullong(const char_t* value)
     4458        {
     4459                return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);
    39514460        }
    39524461#endif
    39534462
     4463        template <typename U>
     4464        PUGI__FN char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative)
     4465        {
     4466                char_t* result = end - 1;
     4467                U rest = negative ? 0 - value : value;
     4468
     4469                do
     4470                {
     4471                        *result-- = static_cast<char_t>('0' + (rest % 10));
     4472                        rest /= 10;
     4473                }
     4474                while (rest);
     4475
     4476                assert(result >= begin);
     4477                (void)begin;
     4478
     4479                *result = '-';
     4480
     4481                return result + !negative;
     4482        }
     4483
    39544484        // set value with conversion functions
    3955         PUGI__FN bool set_value_buffer(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char (&buf)[128])
     4485        template <typename String, typename Header>
     4486        PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf)
    39564487        {
    39574488        #ifdef PUGIXML_WCHAR_MODE
    39584489                char_t wbuf[128];
    3959                 impl::widen_ascii(wbuf, buf);
    3960 
    3961                 return strcpy_insitu(dest, header, header_mask, wbuf);
     4490                assert(strlen(buf) < sizeof(wbuf) / sizeof(wbuf[0]));
     4491
     4492                size_t offset = 0;
     4493                for (; buf[offset]; ++offset) wbuf[offset] = buf[offset];
     4494
     4495                return strcpy_insitu(dest, header, header_mask, wbuf, offset);
    39624496        #else
    3963                 return strcpy_insitu(dest, header, header_mask, buf);
     4497                return strcpy_insitu(dest, header, header_mask, buf, strlen(buf));
    39644498        #endif
    39654499        }
    39664500
    3967         PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, int value)
    3968         {
    3969                 char buf[128];
    3970                 sprintf(buf, "%d", value);
    3971        
    3972                 return set_value_buffer(dest, header, header_mask, buf);
    3973         }
    3974 
    3975         PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned int value)
    3976         {
    3977                 char buf[128];
    3978                 sprintf(buf, "%u", value);
    3979 
    3980                 return set_value_buffer(dest, header, header_mask, buf);
    3981         }
    3982 
    3983         PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, float value)
     4501        template <typename String, typename Header>
     4502        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, int value)
     4503        {
     4504                char_t buf[64];
     4505                char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
     4506                char_t* begin = integer_to_string<unsigned int>(buf, end, value, value < 0);
     4507
     4508                return strcpy_insitu(dest, header, header_mask, begin, end - begin);
     4509        }
     4510
     4511        template <typename String, typename Header>
     4512        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned int value)
     4513        {
     4514                char_t buf[64];
     4515                char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
     4516                char_t* begin = integer_to_string<unsigned int>(buf, end, value, false);
     4517
     4518                return strcpy_insitu(dest, header, header_mask, begin, end - begin);
     4519        }
     4520
     4521        template <typename String, typename Header>
     4522        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value)
    39844523        {
    39854524                char buf[128];
    39864525                sprintf(buf, "%.9g", value);
    39874526
    3988                 return set_value_buffer(dest, header, header_mask, buf);
    3989         }
    3990        
    3991         PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, double value)
     4527                return set_value_ascii(dest, header, header_mask, buf);
     4528        }
     4529
     4530        template <typename String, typename Header>
     4531        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value)
    39924532        {
    39934533                char buf[128];
    39944534                sprintf(buf, "%.17g", value);
    39954535
    3996                 return set_value_buffer(dest, header, header_mask, buf);
     4536                return set_value_ascii(dest, header, header_mask, buf);
    39974537        }
    39984538       
    3999         PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, bool value)
    4000         {
    4001                 return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"));
     4539        template <typename String, typename Header>
     4540        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, bool value)
     4541        {
     4542                return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5);
    40024543        }
    40034544
    40044545#ifdef PUGIXML_HAS_LONG_LONG
    4005         PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, long long value)
    4006         {
    4007                 char buf[128];
    4008                 sprintf(buf, "%lld", value);
    4009        
    4010                 return set_value_buffer(dest, header, header_mask, buf);
    4011         }
    4012 
    4013         PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, unsigned long long value)
    4014         {
    4015                 char buf[128];
    4016                 sprintf(buf, "%llu", value);
    4017        
    4018                 return set_value_buffer(dest, header, header_mask, buf);
     4546        template <typename String, typename Header>
     4547        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, long long value)
     4548        {
     4549                char_t buf[64];
     4550                char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
     4551                char_t* begin = integer_to_string<unsigned long long>(buf, end, value, value < 0);
     4552
     4553                return strcpy_insitu(dest, header, header_mask, begin, end - begin);
     4554        }
     4555
     4556        template <typename String, typename Header>
     4557        PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, unsigned long long value)
     4558        {
     4559                char_t buf[64];
     4560                char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
     4561                char_t* begin = integer_to_string<unsigned long long>(buf, end, value, false);
     4562
     4563                return strcpy_insitu(dest, header, header_mask, begin, end - begin);
    40194564        }
    40204565#endif
     4566
     4567        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)
     4568        {
     4569                // check input buffer
     4570                if (!contents && size) return make_parse_result(status_io_error);
     4571
     4572                // get actual encoding
     4573                xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
     4574
     4575                // get private buffer
     4576                char_t* buffer = 0;
     4577                size_t length = 0;
     4578
     4579                if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
     4580
     4581                // delete original buffer if we performed a conversion
     4582                if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
     4583
     4584                // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
     4585                if (own || buffer != contents) *out_buffer = buffer;
     4586
     4587                // store buffer for offset_debug
     4588                doc->buffer = buffer;
     4589
     4590                // parse
     4591                xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
     4592
     4593                // remember encoding
     4594                res.encoding = buffer_encoding;
     4595
     4596                return res;
     4597        }
    40214598
    40224599        // 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
     
    40604637        }
    40614638
     4639        // This function assumes that buffer has extra sizeof(char_t) writable bytes after size
    40624640        PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding)
    40634641        {
     
    40844662        }
    40854663
    4086         PUGI__FN xml_parse_result load_file_impl(xml_document& doc, FILE* file, unsigned int options, xml_encoding encoding)
     4664        PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer)
    40874665        {
    40884666                if (!file) return make_parse_result(status_file_not_found);
     
    40914669                size_t size = 0;
    40924670                xml_parse_status size_status = get_file_size(file, size);
    4093 
    4094                 if (size_status != status_ok)
    4095                 {
    4096                         fclose(file);
    4097                         return make_parse_result(size_status);
    4098                 }
     4671                if (size_status != status_ok) return make_parse_result(size_status);
    40994672               
    41004673                size_t max_suffix_size = sizeof(char_t);
     
    41024675                // allocate buffer for the whole file
    41034676                char* contents = static_cast<char*>(xml_memory::allocate(size + max_suffix_size));
    4104 
    4105                 if (!contents)
    4106                 {
    4107                         fclose(file);
    4108                         return make_parse_result(status_out_of_memory);
    4109                 }
     4677                if (!contents) return make_parse_result(status_out_of_memory);
    41104678
    41114679                // read file in memory
    41124680                size_t read_size = fread(contents, 1, size, file);
    4113                 fclose(file);
    41144681
    41154682                if (read_size != size)
     
    41204687
    41214688                xml_encoding real_encoding = get_buffer_encoding(encoding, contents, size);
    4122                
    4123                 return doc.load_buffer_inplace_own(contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding);
     4689
     4690                return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer);
    41244691        }
    41254692
     
    41304697                {
    41314698                        void* memory = xml_memory::allocate(sizeof(xml_stream_chunk));
     4699                        if (!memory) return 0;
    41324700                       
    41334701                        return new (memory) xml_stream_chunk();
    41344702                }
    41354703
    4136                 static void destroy(void* ptr)
    4137                 {
    4138                         xml_stream_chunk* chunk = static_cast<xml_stream_chunk*>(ptr);
    4139 
     4704                static void destroy(xml_stream_chunk* chunk)
     4705                {
    41404706                        // free chunk chain
    41414707                        while (chunk)
     
    41614727        template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
    41624728        {
    4163                 buffer_holder chunks(0, xml_stream_chunk<T>::destroy);
     4729                auto_deleter<xml_stream_chunk<T> > chunks(0, xml_stream_chunk<T>::destroy);
    41644730
    41654731                // read file to a chunk list
     
    41974763                char* write = buffer;
    41984764
    4199                 for (xml_stream_chunk<T>* chunk = static_cast<xml_stream_chunk<T>*>(chunks.data); chunk; chunk = chunk->next)
     4765                for (xml_stream_chunk<T>* chunk = chunks.data; chunk; chunk = chunk->next)
    42004766                {
    42014767                        assert(write + chunk->size <= buffer + total);
     
    42314797
    42324798                // read stream data into memory (guard against stream exceptions with buffer holder)
    4233                 buffer_holder buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);
     4799                auto_deleter<void> buffer(xml_memory::allocate(read_length * sizeof(T) + max_suffix_size), xml_memory::deallocate);
    42344800                if (!buffer.data) return status_out_of_memory;
    42354801
     
    42494815        }
    42504816
    4251         template <typename T> PUGI__FN xml_parse_result load_stream_impl(xml_document& doc, std::basic_istream<T>& stream, unsigned int options, xml_encoding encoding)
     4817        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)
    42524818        {
    42534819                void* buffer = 0;
     
    42714837                xml_encoding real_encoding = get_buffer_encoding(encoding, buffer, size);
    42724838               
    4273                 return doc.load_buffer_inplace_own(buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding);
     4839                return load_buffer_impl(doc, doc, buffer, zero_terminate_buffer(buffer, size, real_encoding), options, real_encoding, true, true, out_buffer);
    42744840        }
    42754841#endif
     
    42964862                as_utf8_end(result, size, str, length);
    42974863
     4864                // zero-terminate
     4865                result[size] = 0;
     4866
    42984867                return result;
    42994868        }
     
    43264895                doc.save(writer, indent, flags, encoding);
    43274896
    4328                 int result = ferror(file);
    4329 
    4330                 fclose(file);
    4331 
    4332                 return result == 0;
    4333         }
    4334 
    4335         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)
    4336         {
    4337                 // check input buffer
    4338                 if (!contents && size) return make_parse_result(status_io_error);
    4339 
    4340                 // get actual encoding
    4341                 xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size);
    4342 
    4343                 // get private buffer
    4344                 char_t* buffer = 0;
    4345                 size_t length = 0;
    4346 
    4347                 if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory);
    4348                
    4349                 // delete original buffer if we performed a conversion
    4350                 if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents);
    4351 
    4352                 // store buffer for offset_debug
    4353                 doc->buffer = buffer;
    4354 
    4355                 // parse
    4356                 xml_parse_result res = impl::xml_parser::parse(buffer, length, doc, root, options);
    4357 
    4358                 // remember encoding
    4359                 res.encoding = buffer_encoding;
    4360 
    4361                 // grab onto buffer if it's our buffer, user is responsible for deallocating contents himself
    4362                 if (own || buffer != contents) *out_buffer = buffer;
    4363 
    4364                 return res;
    4365         }
     4897                return ferror(file) == 0;
     4898        }
     4899
     4900        struct name_null_sentry
     4901        {
     4902                xml_node_struct* node;
     4903                char_t* name;
     4904
     4905                name_null_sentry(xml_node_struct* node_): node(node_), name(node_->name)
     4906                {
     4907                        node->name = 0;
     4908                }
     4909
     4910                ~name_null_sentry()
     4911                {
     4912                        node->name = name;
     4913                }
     4914        };
    43664915PUGI__NS_END
    43674916
     
    44915040        PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const
    44925041        {
    4493                 return (_attr && _attr->value) ? _attr->value : def;
     5042                return (_attr && _attr->value) ? _attr->value + 0 : def;
    44945043        }
    44955044
    44965045        PUGI__FN int xml_attribute::as_int(int def) const
    44975046        {
    4498                 return impl::get_value_int(_attr ? _attr->value : 0, def);
     5047                return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def;
    44995048        }
    45005049
    45015050        PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
    45025051        {
    4503                 return impl::get_value_uint(_attr ? _attr->value : 0, def);
     5052                return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def;
    45045053        }
    45055054
    45065055        PUGI__FN double xml_attribute::as_double(double def) const
    45075056        {
    4508                 return impl::get_value_double(_attr ? _attr->value : 0, def);
     5057                return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def;
    45095058        }
    45105059
    45115060        PUGI__FN float xml_attribute::as_float(float def) const
    45125061        {
    4513                 return impl::get_value_float(_attr ? _attr->value : 0, def);
     5062                return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def;
    45145063        }
    45155064
    45165065        PUGI__FN bool xml_attribute::as_bool(bool def) const
    45175066        {
    4518                 return impl::get_value_bool(_attr ? _attr->value : 0, def);
     5067                return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def;
    45195068        }
    45205069
     
    45225071        PUGI__FN long long xml_attribute::as_llong(long long def) const
    45235072        {
    4524                 return impl::get_value_llong(_attr ? _attr->value : 0, def);
     5073                return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def;
    45255074        }
    45265075
    45275076        PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
    45285077        {
    4529                 return impl::get_value_ullong(_attr ? _attr->value : 0, def);
     5078                return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def;
    45305079        }
    45315080#endif
     
    45385087        PUGI__FN const char_t* xml_attribute::name() const
    45395088        {
    4540                 return (_attr && _attr->name) ? _attr->name : PUGIXML_TEXT("");
     5089                return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT("");
    45415090        }
    45425091
    45435092        PUGI__FN const char_t* xml_attribute::value() const
    45445093        {
    4545                 return (_attr && _attr->value) ? _attr->value : PUGIXML_TEXT("");
     5094                return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT("");
    45465095        }
    45475096
     
    45855134                return *this;
    45865135        }
    4587        
     5136
    45885137        PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs)
    45895138        {
     
    46105159                if (!_attr) return false;
    46115160               
    4612                 return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs);
     5161                return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
    46135162        }
    46145163               
     
    46175166                if (!_attr) return false;
    46185167
    4619                 return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
     5168                return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
    46205169        }
    46215170
     
    46475196                return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
    46485197        }
    4649        
     5198
    46505199        PUGI__FN bool xml_attribute::set_value(bool rhs)
    46515200        {
     
    47075256        PUGI__FN xml_node::iterator xml_node::begin() const
    47085257        {
    4709                 return iterator(_root ? _root->first_child : 0, _root);
     5258                return iterator(_root ? _root->first_child + 0 : 0, _root);
    47105259        }
    47115260
     
    47175266        PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const
    47185267        {
    4719                 return attribute_iterator(_root ? _root->first_attribute : 0, _root);
     5268                return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root);
    47205269        }
    47215270
     
    47775326        PUGI__FN const char_t* xml_node::name() const
    47785327        {
    4779                 return (_root && _root->name) ? _root->name : PUGIXML_TEXT("");
     5328                return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT("");
    47805329        }
    47815330
     
    47875336        PUGI__FN const char_t* xml_node::value() const
    47885337        {
    4789                 return (_root && _root->value) ? _root->value : PUGIXML_TEXT("");
     5338                return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT("");
    47905339        }
    47915340       
     
    48365385        }
    48375386
     5387        PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const
     5388        {
     5389                xml_attribute_struct* hint = hint_._attr;
     5390
     5391                // if hint is not an attribute of node, behavior is not defined
     5392                assert(!hint || (_root && impl::is_attribute_of(hint, _root)));
     5393
     5394                if (!_root) return xml_attribute();
     5395
     5396                // optimistically search from hint up until the end
     5397                for (xml_attribute_struct* i = hint; i; i = i->next_attribute)
     5398                        if (i->name && impl::strequal(name_, i->name))
     5399                        {
     5400                                // update hint to maximize efficiency of searching for consecutive attributes
     5401                                hint_._attr = i->next_attribute;
     5402
     5403                                return xml_attribute(i);
     5404                        }
     5405
     5406                // wrap around and search from the first attribute until the hint
     5407                // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails
     5408                for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute)
     5409                        if (j->name && impl::strequal(name_, j->name))
     5410                        {
     5411                                // update hint to maximize efficiency of searching for consecutive attributes
     5412                                hint_._attr = j->next_attribute;
     5413
     5414                                return xml_attribute(j);
     5415                        }
     5416
     5417                return xml_attribute();
     5418        }
     5419
    48385420        PUGI__FN xml_node xml_node::previous_sibling() const
    48395421        {
     
    48645446               
    48655447                for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
    4866                         if (i->value && impl::is_text_node(i))
     5448                        if (impl::is_text_node(i) && i->value)
    48675449                                return i->value;
    48685450
     
    48975479        PUGI__FN bool xml_node::set_name(const char_t* rhs)
    48985480        {
    4899                 switch (type())
    4900                 {
    4901                 case node_pi:
    4902                 case node_declaration:
    4903                 case node_element:
    4904                         return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs);
    4905 
    4906                 default:
     5481                xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
     5482
     5483                if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
    49075484                        return false;
    4908                 }
     5485
     5486                return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
    49095487        }
    49105488               
    49115489        PUGI__FN bool xml_node::set_value(const char_t* rhs)
    49125490        {
    4913                 switch (type())
    4914                 {
    4915                 case node_pi:
    4916                 case node_cdata:
    4917                 case node_pcdata:
    4918                 case node_comment:
    4919                 case node_doctype:
    4920                         return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs);
    4921 
    4922                 default:
     5491                xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
     5492
     5493                if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
    49235494                        return false;
    4924                 }
     5495
     5496                return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
    49255497        }
    49265498
     
    49295501                if (!impl::allow_insert_attribute(type())) return xml_attribute();
    49305502               
    4931                 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
     5503                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5504                if (!alloc.reserve()) return xml_attribute();
     5505
     5506                xml_attribute a(impl::allocate_attribute(alloc));
    49325507                if (!a) return xml_attribute();
    49335508
     
    49435518                if (!impl::allow_insert_attribute(type())) return xml_attribute();
    49445519               
    4945                 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
     5520                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5521                if (!alloc.reserve()) return xml_attribute();
     5522
     5523                xml_attribute a(impl::allocate_attribute(alloc));
    49465524                if (!a) return xml_attribute();
    49475525
     
    49585536                if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
    49595537               
    4960                 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
     5538                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5539                if (!alloc.reserve()) return xml_attribute();
     5540
     5541                xml_attribute a(impl::allocate_attribute(alloc));
    49615542                if (!a) return xml_attribute();
    49625543
     
    49735554                if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
    49745555               
    4975                 xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
     5556                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5557                if (!alloc.reserve()) return xml_attribute();
     5558
     5559                xml_attribute a(impl::allocate_attribute(alloc));
    49765560                if (!a) return xml_attribute();
    49775561
     
    49865570        {
    49875571                if (!proto) return xml_attribute();
    4988 
    4989                 xml_attribute result = append_attribute(proto.name());
    4990                 result.set_value(proto.value());
    4991 
    4992                 return result;
     5572                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5573
     5574                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5575                if (!alloc.reserve()) return xml_attribute();
     5576
     5577                xml_attribute a(impl::allocate_attribute(alloc));
     5578                if (!a) return xml_attribute();
     5579
     5580                impl::append_attribute(a._attr, _root);
     5581                impl::node_copy_attribute(a._attr, proto._attr);
     5582
     5583                return a;
    49935584        }
    49945585
     
    49965587        {
    49975588                if (!proto) return xml_attribute();
    4998 
    4999                 xml_attribute result = prepend_attribute(proto.name());
    5000                 result.set_value(proto.value());
    5001 
    5002                 return result;
     5589                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5590
     5591                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5592                if (!alloc.reserve()) return xml_attribute();
     5593
     5594                xml_attribute a(impl::allocate_attribute(alloc));
     5595                if (!a) return xml_attribute();
     5596
     5597                impl::prepend_attribute(a._attr, _root);
     5598                impl::node_copy_attribute(a._attr, proto._attr);
     5599
     5600                return a;
    50035601        }
    50045602
     
    50065604        {
    50075605                if (!proto) return xml_attribute();
    5008 
    5009                 xml_attribute result = insert_attribute_after(proto.name(), attr);
    5010                 result.set_value(proto.value());
    5011 
    5012                 return result;
     5606                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5607                if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
     5608
     5609                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5610                if (!alloc.reserve()) return xml_attribute();
     5611
     5612                xml_attribute a(impl::allocate_attribute(alloc));
     5613                if (!a) return xml_attribute();
     5614
     5615                impl::insert_attribute_after(a._attr, attr._attr, _root);
     5616                impl::node_copy_attribute(a._attr, proto._attr);
     5617
     5618                return a;
    50135619        }
    50145620
     
    50165622        {
    50175623                if (!proto) return xml_attribute();
    5018 
    5019                 xml_attribute result = insert_attribute_before(proto.name(), attr);
    5020                 result.set_value(proto.value());
    5021 
    5022                 return result;
     5624                if (!impl::allow_insert_attribute(type())) return xml_attribute();
     5625                if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
     5626
     5627                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5628                if (!alloc.reserve()) return xml_attribute();
     5629
     5630                xml_attribute a(impl::allocate_attribute(alloc));
     5631                if (!a) return xml_attribute();
     5632
     5633                impl::insert_attribute_before(a._attr, attr._attr, _root);
     5634                impl::node_copy_attribute(a._attr, proto._attr);
     5635
     5636                return a;
    50235637        }
    50245638
     
    50275641                if (!impl::allow_insert_child(type(), type_)) return xml_node();
    50285642               
    5029                 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
     5643                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5644                if (!alloc.reserve()) return xml_node();
     5645
     5646                xml_node n(impl::allocate_node(alloc, type_));
    50305647                if (!n) return xml_node();
    50315648
     
    50405657        {
    50415658                if (!impl::allow_insert_child(type(), type_)) return xml_node();
     5659
     5660                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5661                if (!alloc.reserve()) return xml_node();
    50425662               
    5043                 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
     5663                xml_node n(impl::allocate_node(alloc, type_));
    50445664                if (!n) return xml_node();
    50455665
     
    50555675                if (!impl::allow_insert_child(type(), type_)) return xml_node();
    50565676                if (!node._root || node._root->parent != _root) return xml_node();
     5677
     5678                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5679                if (!alloc.reserve()) return xml_node();
    50575680       
    5058                 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
     5681                xml_node n(impl::allocate_node(alloc, type_));
    50595682                if (!n) return xml_node();
    50605683
     
    50705693                if (!impl::allow_insert_child(type(), type_)) return xml_node();
    50715694                if (!node._root || node._root->parent != _root) return xml_node();
     5695
     5696                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5697                if (!alloc.reserve()) return xml_node();
    50725698       
    5073                 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
     5699                xml_node n(impl::allocate_node(alloc, type_));
    50745700                if (!n) return xml_node();
    50755701
     
    51225748                if (!impl::allow_insert_child(type(), type_)) return xml_node();
    51235749
    5124                 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
     5750                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5751                if (!alloc.reserve()) return xml_node();
     5752
     5753                xml_node n(impl::allocate_node(alloc, type_));
    51255754                if (!n) return xml_node();
    51265755
     
    51365765                if (!impl::allow_insert_child(type(), type_)) return xml_node();
    51375766
    5138                 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
     5767                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5768                if (!alloc.reserve()) return xml_node();
     5769
     5770                xml_node n(impl::allocate_node(alloc, type_));
    51395771                if (!n) return xml_node();
    51405772
     
    51515783                if (!node._root || node._root->parent != _root) return xml_node();
    51525784
    5153                 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
     5785                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5786                if (!alloc.reserve()) return xml_node();
     5787
     5788                xml_node n(impl::allocate_node(alloc, type_));
    51545789                if (!n) return xml_node();
    51555790
     
    51665801                if (!node._root || node._root->parent != _root) return xml_node();
    51675802
    5168                 xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
     5803                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5804                if (!alloc.reserve()) return xml_node();
     5805
     5806                xml_node n(impl::allocate_node(alloc, type_));
    51695807                if (!n) return xml_node();
    51705808
     
    51795817                if (!impl::allow_move(*this, moved)) return xml_node();
    51805818
     5819                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5820                if (!alloc.reserve()) return xml_node();
     5821
    51815822                // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
    51825823                impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
     
    51915832        {
    51925833                if (!impl::allow_move(*this, moved)) return xml_node();
     5834
     5835                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5836                if (!alloc.reserve()) return xml_node();
    51935837
    51945838                // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
     
    52075851                if (moved._root == node._root) return xml_node();
    52085852
     5853                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5854                if (!alloc.reserve()) return xml_node();
     5855
    52095856                // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
    52105857                impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
     
    52225869                if (moved._root == node._root) return xml_node();
    52235870
     5871                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5872                if (!alloc.reserve()) return xml_node();
     5873
    52245874                // disable document_buffer_order optimization since moving nodes around changes document order without changing buffer pointers
    52255875                impl::get_document(_root).header |= impl::xml_memory_page_contents_shared_mask;
     
    52415891                if (!impl::is_attribute_of(a._attr, _root)) return false;
    52425892
     5893                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5894                if (!alloc.reserve()) return false;
     5895
    52435896                impl::remove_attribute(a._attr, _root);
    5244                 impl::destroy_attribute(a._attr, impl::get_allocator(_root));
     5897                impl::destroy_attribute(a._attr, alloc);
    52455898
    52465899                return true;
     
    52565909                if (!_root || !n._root || n._root->parent != _root) return false;
    52575910
     5911                impl::xml_allocator& alloc = impl::get_allocator(_root);
     5912                if (!alloc.reserve()) return false;
     5913
    52585914                impl::remove_node(n._root);
    5259                 impl::destroy_node(n._root, impl::get_allocator(_root));
     5915                impl::destroy_node(n._root, alloc);
    52605916
    52615917                return true;
     
    52805936                if (!extra) return impl::make_parse_result(status_out_of_memory);
    52815937
    5282                 // save name; name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level
    5283                 char_t* rootname = _root->name;
    5284                 _root->name = 0;
    5285 
    5286                 // parse
    5287                 char_t* buffer = 0;
    5288                 xml_parse_result res = impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &buffer);
    5289 
    5290                 // restore name
    5291                 _root->name = rootname;
    5292 
    52935938                // add extra buffer to the list
    5294                 extra->buffer = buffer;
     5939                extra->buffer = 0;
    52955940                extra->next = doc->extra_buffers;
    52965941                doc->extra_buffers = extra;
    52975942
    5298                 return res;
     5943                // name of the root has to be NULL before parsing - otherwise closing node mismatches will not be detected at the top level
     5944                impl::name_null_sentry sentry(_root);
     5945
     5946                return impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &extra->buffer);
    52995947        }
    53005948
     
    53075955                        {
    53085956                                for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
    5309                                         if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT("")))
     5957                                        if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
    53105958                                                return xml_node(i);
    53115959                        }
     
    53205968                for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
    53215969                        for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute)
    5322                                 if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value : PUGIXML_TEXT("")))
     5970                                if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT("")))
    53235971                                        return xml_node(i);
    53245972
     
    53295977        PUGI__FN string_t xml_node::path(char_t delimiter) const
    53305978        {
    5331                 xml_node cursor = *this; // Make a copy.
    5332                
    5333                 string_t result = cursor.name();
    5334 
    5335                 while (cursor.parent())
    5336                 {
    5337                         cursor = cursor.parent();
    5338                        
    5339                         string_t temp = cursor.name();
    5340                         temp += delimiter;
    5341                         temp += result;
    5342                         result.swap(temp);
    5343                 }
     5979                if (!_root) return string_t();
     5980
     5981                size_t offset = 0;
     5982
     5983                for (xml_node_struct* i = _root; i; i = i->parent)
     5984                {
     5985                        offset += (i != _root);
     5986                        offset += i->name ? impl::strlength(i->name) : 0;
     5987                }
     5988
     5989                string_t result;
     5990                result.resize(offset);
     5991
     5992                for (xml_node_struct* j = _root; j; j = j->parent)
     5993                {
     5994                        if (j != _root)
     5995                                result[--offset] = delimiter;
     5996
     5997                        if (j->name && *j->name)
     5998                        {
     5999                                size_t length = impl::strlength(j->name);
     6000
     6001                                offset -= length;
     6002                                memcpy(&result[offset], j->name, length * sizeof(char_t));
     6003                        }
     6004                }
     6005
     6006                assert(offset == 0);
    53446007
    53456008                return result;
     
    54596122
    54606123                impl::node_output(buffered_writer, _root, indent, flags, depth);
     6124
     6125                buffered_writer.flush();
    54616126        }
    54626127
     
    55696234                xml_node_struct* d = _data();
    55706235
    5571                 return (d && d->value) ? d->value : PUGIXML_TEXT("");
     6236                return (d && d->value) ? d->value + 0 : PUGIXML_TEXT("");
    55726237        }
    55736238
     
    55766241                xml_node_struct* d = _data();
    55776242
    5578                 return (d && d->value) ? d->value : def;
     6243                return (d && d->value) ? d->value + 0 : def;
    55796244        }
    55806245
     
    55836248                xml_node_struct* d = _data();
    55846249
    5585                 return impl::get_value_int(d ? d->value : 0, def);
     6250                return (d && d->value) ? impl::get_value_int(d->value) : def;
    55866251        }
    55876252
     
    55906255                xml_node_struct* d = _data();
    55916256
    5592                 return impl::get_value_uint(d ? d->value : 0, def);
     6257                return (d && d->value) ? impl::get_value_uint(d->value) : def;
    55936258        }
    55946259
     
    55976262                xml_node_struct* d = _data();
    55986263
    5599                 return impl::get_value_double(d ? d->value : 0, def);
     6264                return (d && d->value) ? impl::get_value_double(d->value) : def;
    56006265        }
    56016266
     
    56046269                xml_node_struct* d = _data();
    56056270
    5606                 return impl::get_value_float(d ? d->value : 0, def);
     6271                return (d && d->value) ? impl::get_value_float(d->value) : def;
    56076272        }
    56086273
     
    56116276                xml_node_struct* d = _data();
    56126277
    5613                 return impl::get_value_bool(d ? d->value : 0, def);
     6278                return (d && d->value) ? impl::get_value_bool(d->value) : def;
    56146279        }
    56156280
     
    56196284                xml_node_struct* d = _data();
    56206285
    5621                 return impl::get_value_llong(d ? d->value : 0, def);
     6286                return (d && d->value) ? impl::get_value_llong(d->value) : def;
    56226287        }
    56236288
     
    56266291                xml_node_struct* d = _data();
    56276292
    5628                 return impl::get_value_ullong(d ? d->value : 0, def);
     6293                return (d && d->value) ? impl::get_value_ullong(d->value) : def;
    56296294        }
    56306295#endif
     
    56346299                xml_node_struct* dn = _data_new();
    56356300
    5636                 return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
     6301                return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false;
    56376302        }
    56386303
     
    60156680                assert(!_root);
    60166681
     6682        #ifdef PUGIXML_COMPACT
     6683                const size_t page_offset = sizeof(uint32_t);
     6684        #else
     6685                const size_t page_offset = 0;
     6686        #endif
     6687
    60176688                // initialize sentinel page
    6018                 PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment - sizeof(void*) <= sizeof(_memory));
     6689                PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + impl::xml_memory_page_alignment - sizeof(void*) + page_offset <= sizeof(_memory));
    60196690
    60206691                // align upwards to page boundary
     
    60276698                page->busy_size = impl::xml_memory_page_size;
    60286699
     6700                // setup first page marker
     6701        #ifdef PUGIXML_COMPACT
     6702                // round-trip through void* to avoid 'cast increases required alignment of target type' warning
     6703                page->compact_page_marker = reinterpret_cast<uint32_t*>(static_cast<void*>(reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page)));
     6704                *page->compact_page_marker = sizeof(impl::xml_memory_page);
     6705        #endif
     6706
    60296707                // allocate new root
    6030                 _root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page)) impl::xml_document_struct(page);
     6708                _root = new (reinterpret_cast<char*>(page) + sizeof(impl::xml_memory_page) + page_offset) impl::xml_document_struct(page);
    60316709                _root->prev_sibling_c = _root;
    60326710
     
    60566734
    60576735                // destroy dynamic storage, leave sentinel page (it's in static memory)
    6058                 impl::xml_memory_page* root_page = reinterpret_cast<impl::xml_memory_page*>(_root->header & impl::xml_memory_page_pointer_mask);
     6736                impl::xml_memory_page* root_page = PUGI__GETPAGE(_root);
    60596737                assert(root_page && !root_page->prev);
    60606738                assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));
     
    60696747                }
    60706748
     6749        #ifdef PUGIXML_COMPACT
     6750                // destroy hash table
     6751                static_cast<impl::xml_document_struct*>(_root)->hash.clear();
     6752        #endif
     6753
    60716754                _root = 0;
    60726755        }
     
    60776760                reset();
    60786761
    6079                 return impl::load_stream_impl(*this, stream, options, encoding);
     6762                return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding, &_buffer);
    60806763        }
    60816764
     
    60846767                reset();
    60856768
    6086                 return impl::load_stream_impl(*this, stream, options, encoding_wchar);
     6769                return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding_wchar, &_buffer);
    60876770        }
    60886771#endif
     
    61096792                reset();
    61106793
    6111                 FILE* file = fopen(path_, "rb");
    6112 
    6113                 return impl::load_file_impl(*this, file, options, encoding);
     6794                using impl::auto_deleter; // MSVC7 workaround
     6795                auto_deleter<FILE, int(*)(FILE*)> file(fopen(path_, "rb"), fclose);
     6796
     6797                return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
    61146798        }
    61156799
     
    61186802                reset();
    61196803
    6120                 FILE* file = impl::open_file_wide(path_, L"rb");
    6121 
    6122                 return impl::load_file_impl(*this, file, options, encoding);
     6804                using impl::auto_deleter; // MSVC7 workaround
     6805                auto_deleter<FILE, int(*)(FILE*)> file(impl::open_file_wide(path_, L"rb"), fclose);
     6806
     6807                return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
    61236808        }
    61246809
     
    61686853
    61696854                impl::node_output(buffered_writer, _root, indent, flags, 0);
     6855
     6856                buffered_writer.flush();
    61706857        }
    61716858
     
    61886875        PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
    61896876        {
    6190                 FILE* file = fopen(path_, (flags & format_save_file_text) ? "w" : "wb");
    6191                 return impl::save_file_impl(*this, file, indent, flags, encoding);
     6877                using impl::auto_deleter; // MSVC7 workaround
     6878                auto_deleter<FILE, int(*)(FILE*)> file(fopen(path_, (flags & format_save_file_text) ? "w" : "wb"), fclose);
     6879
     6880                return impl::save_file_impl(*this, file.data, indent, flags, encoding);
    61926881        }
    61936882
    61946883        PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
    61956884        {
    6196                 FILE* file = impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb");
    6197                 return impl::save_file_impl(*this, file, indent, flags, encoding);
     6885                using impl::auto_deleter; // MSVC7 workaround
     6886                auto_deleter<FILE, int(*)(FILE*)> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), fclose);
     6887
     6888                return impl::save_file_impl(*this, file.data, indent, flags, encoding);
    61986889        }
    61996890
     
    65247215// Allocator used for AST and evaluation stacks
    65257216PUGI__NS_BEGIN
     7217        static const size_t xpath_memory_page_size =
     7218        #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
     7219                PUGIXML_MEMORY_XPATH_PAGE_SIZE
     7220        #else
     7221                4096
     7222        #endif
     7223                ;
     7224
     7225        static const uintptr_t xpath_memory_block_alignment = sizeof(double) > sizeof(void*) ? sizeof(double) : sizeof(void*);
     7226
    65267227        struct xpath_memory_block
    65277228        {       
     
    65297230                size_t capacity;
    65307231
    6531                 char data[
    6532         #ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
    6533                         PUGIXML_MEMORY_XPATH_PAGE_SIZE
    6534         #else
    6535                         4096
    6536         #endif
    6537                 ];
     7232                union
     7233                {
     7234                        char data[xpath_memory_page_size];
     7235                        double alignment;
     7236                };
    65387237        };
    65397238               
     
    65577256                void* allocate_nothrow(size_t size)
    65587257                {
    6559                         // align size so that we're able to store pointers in subsequent blocks
    6560                         size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
     7258                        // round size up to block alignment boundary
     7259                        size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
    65617260
    65627261                        if (_root_size + size <= _root->capacity)
    65637262                        {
    6564                                 void* buf = _root->data + _root_size;
     7263                                void* buf = &_root->data[0] + _root_size;
    65657264                                _root_size += size;
    65667265                                return buf;
     
    66077306                void* reallocate(void* ptr, size_t old_size, size_t new_size)
    66087307                {
    6609                         // align size so that we're able to store pointers in subsequent blocks
    6610                         old_size = (old_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
    6611                         new_size = (new_size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
     7308                        // round size up to block alignment boundary
     7309                        old_size = (old_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
     7310                        new_size = (new_size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
    66127311
    66137312                        // we can only reallocate the last object
    6614                         assert(ptr == 0 || static_cast<char*>(ptr) + old_size == _root->data + _root_size);
     7313                        assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);
    66157314
    66167315                        // adjust root size so that we have not allocated the object at all
     
    73478046                return wcstod(string, 0);
    73488047        #else
    7349                 return atof(string);
     8048                return strtod(string, 0);
    73508049        #endif
    73518050        }
     
    75888287        struct xpath_variable_boolean: xpath_variable
    75898288        {
    7590                 xpath_variable_boolean(): value(false)
     8289                xpath_variable_boolean(): xpath_variable(xpath_type_boolean), value(false)
    75918290                {
    75928291                }
     
    75988297        struct xpath_variable_number: xpath_variable
    75998298        {
    7600                 xpath_variable_number(): value(0)
     8299                xpath_variable_number(): xpath_variable(xpath_type_number), value(0)
    76018300                {
    76028301                }
     
    76088307        struct xpath_variable_string: xpath_variable
    76098308        {
    7610                 xpath_variable_string(): value(0)
     8309                xpath_variable_string(): xpath_variable(xpath_type_string), value(0)
    76118310                {
    76128311                }
     
    76238322        struct xpath_variable_node_set: xpath_variable
    76248323        {
     8324                xpath_variable_node_set(): xpath_variable(xpath_type_node_set)
     8325                {
     8326                }
     8327
    76258328                xpath_node_set value;
    76268329                char_t name[1];
     
    77168419        }
    77178420
    7718         PUGI__FN xpath_variable* get_variable_scratch(char_t (&buffer)[32], xpath_variable_set* set, const char_t* begin, const char_t* end)
     8421        PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs)
     8422        {
     8423                switch (rhs->type())
     8424                {
     8425                case xpath_type_node_set:
     8426                        return lhs->set(static_cast<const xpath_variable_node_set*>(rhs)->value);
     8427
     8428                case xpath_type_number:
     8429                        return lhs->set(static_cast<const xpath_variable_number*>(rhs)->value);
     8430
     8431                case xpath_type_string:
     8432                        return lhs->set(static_cast<const xpath_variable_string*>(rhs)->value);
     8433
     8434                case xpath_type_boolean:
     8435                        return lhs->set(static_cast<const xpath_variable_boolean*>(rhs)->value);
     8436
     8437                default:
     8438                        assert(!"Invalid variable type");
     8439                        return false;
     8440                }
     8441        }
     8442
     8443        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)
    77198444        {
    77208445                size_t length = static_cast<size_t>(end - begin);
     
    77258450                        // need to make dummy on-heap copy
    77268451                        scratch = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));
    7727                         if (!scratch) return 0;
     8452                        if (!scratch) return false;
    77288453                }
    77298454
     
    77328457                scratch[length] = 0;
    77338458
    7734                 xpath_variable* result = set->get(scratch);
     8459                *out_result = set->get(scratch);
    77358460
    77368461                // free dummy buffer
    77378462                if (scratch != buffer) xml_memory::deallocate(scratch);
    77388463
    7739                 return result;
     8464                return true;
    77408465        }
    77418466PUGI__NS_END
     
    87169441                        assert(a);
    87179442
    8718                         const char_t* name = a->name ? a->name : PUGIXML_TEXT("");
     9443                        const char_t* name = a->name ? a->name + 0 : PUGIXML_TEXT("");
    87199444
    87209445                        switch (_test)
     
    989910624                        if (_next) _next->optimize(alloc);
    990010625
     10626                        optimize_self(alloc);
     10627                }
     10628
     10629                void optimize_self(xpath_allocator* alloc)
     10630                {
    990110631                        // Rewrite [position()=expr] with [expr]
    990210632                        // Note that this step has to go before classification to recognize [position()=1]
     
    1031011040                                        throw_error("Unknown variable: variable set is not provided");
    1031111041
    10312                                 xpath_variable* var = get_variable_scratch(_scratch, _variables, name.begin, name.end);
     11042                                xpath_variable* var = 0;
     11043                                if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var))
     11044                                        throw_error_oom();
    1031311045
    1031411046                                if (!var)
     
    1084611578                {
    1084711579                        void* memory = xml_memory::allocate(sizeof(xpath_query_impl));
     11580                        if (!memory) return 0;
    1084811581
    1084911582                        return new (memory) xpath_query_impl();
    1085011583                }
    1085111584
    10852                 static void destroy(void* ptr)
    10853                 {
    10854                         if (!ptr) return;
    10855                        
     11585                static void destroy(xpath_query_impl* impl)
     11586                {
    1085611587                        // free all allocated pages
    10857                         static_cast<xpath_query_impl*>(ptr)->alloc.release();
     11588                        impl->alloc.release();
    1085811589
    1085911590                        // free allocator memory (with the first page)
    10860                         xml_memory::deallocate(ptr);
     11591                        xml_memory::deallocate(impl);
    1086111592                }
    1086211593
     
    1098711718#endif
    1098811719
    10989         PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_)
     11720        PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)
    1099011721        {
    1099111722                assert(begin_ <= end_);
     
    1100311734                        _begin = &_storage;
    1100411735                        _end = &_storage + size_;
     11736                        _type = type_;
    1100511737                }
    1100611738                else
     
    1102611758                        _begin = storage;
    1102711759                        _end = storage + size_;
    11028                 }
    11029         }
     11760                        _type = type_;
     11761                }
     11762        }
     11763
     11764#if __cplusplus >= 201103
     11765        PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs)
     11766        {
     11767                _type = rhs._type;
     11768                _storage = rhs._storage;
     11769                _begin = (rhs._begin == &rhs._storage) ? &_storage : rhs._begin;
     11770                _end = _begin + (rhs._end - rhs._begin);
     11771
     11772                rhs._type = type_unsorted;
     11773                rhs._begin = &rhs._storage;
     11774                rhs._end = rhs._begin;
     11775        }
     11776#endif
    1103011777
    1103111778        PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(&_storage), _end(&_storage)
     
    1103311780        }
    1103411781
    11035         PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_), _begin(&_storage), _end(&_storage)
    11036         {
    11037                 _assign(begin_, end_);
     11782        PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(&_storage), _end(&_storage)
     11783        {
     11784                _assign(begin_, end_, type_);
    1103811785        }
    1103911786
    1104011787        PUGI__FN xpath_node_set::~xpath_node_set()
    1104111788        {
    11042                 if (_begin != &_storage) impl::xml_memory::deallocate(_begin);
     11789                if (_begin != &_storage)
     11790                        impl::xml_memory::deallocate(_begin);
    1104311791        }
    1104411792               
    11045         PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(ns._type), _begin(&_storage), _end(&_storage)
    11046         {
    11047                 _assign(ns._begin, ns._end);
     11793        PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(&_storage), _end(&_storage)
     11794        {
     11795                _assign(ns._begin, ns._end, ns._type);
    1104811796        }
    1104911797       
     
    1105111799        {
    1105211800                if (this == &ns) return *this;
    11053                
    11054                 _type = ns._type;
    11055                 _assign(ns._begin, ns._end);
     11801
     11802                _assign(ns._begin, ns._end, ns._type);
    1105611803
    1105711804                return *this;
    1105811805        }
     11806
     11807#if __cplusplus >= 201103
     11808        PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs): _type(type_unsorted), _begin(&_storage), _end(&_storage)
     11809        {
     11810                _move(rhs);
     11811        }
     11812
     11813        PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs)
     11814        {
     11815                if (this == &rhs) return *this;
     11816
     11817                if (_begin != &_storage)
     11818                        impl::xml_memory::deallocate(_begin);
     11819
     11820                _move(rhs);
     11821
     11822                return *this;
     11823        }
     11824#endif
    1105911825
    1106011826        PUGI__FN xpath_node_set::type_t xpath_node_set::type() const
     
    1111311879        }
    1111411880
    11115         PUGI__FN xpath_variable::xpath_variable(): _type(xpath_type_none), _next(0)
     11881        PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0)
    1111611882        {
    1111711883        }
     
    1121211978        PUGI__FN xpath_variable_set::xpath_variable_set()
    1121311979        {
    11214                 for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i) _data[i] = 0;
     11980                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     11981                        _data[i] = 0;
    1121511982        }
    1121611983
     
    1121811985        {
    1121911986                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
    11220                 {
    11221                         xpath_variable* var = _data[i];
    11222 
    11223                         while (var)
    11224                         {
    11225                                 xpath_variable* next = var->_next;
    11226 
    11227                                 impl::delete_xpath_variable(var->_type, var);
    11228 
    11229                                 var = next;
    11230                         }
    11231                 }
    11232         }
    11233 
    11234         PUGI__FN xpath_variable* xpath_variable_set::find(const char_t* name) const
     11987                        _destroy(_data[i]);
     11988        }
     11989
     11990        PUGI__FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs)
     11991        {
     11992                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     11993                        _data[i] = 0;
     11994
     11995                _assign(rhs);
     11996        }
     11997
     11998        PUGI__FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs)
     11999        {
     12000                if (this == &rhs) return *this;
     12001
     12002                _assign(rhs);
     12003
     12004                return *this;
     12005        }
     12006
     12007#if __cplusplus >= 201103
     12008        PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs)
     12009        {
     12010                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12011                {
     12012                        _data[i] = rhs._data[i];
     12013                        rhs._data[i] = 0;
     12014                }
     12015        }
     12016
     12017        PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs)
     12018        {
     12019                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12020                {
     12021                        _destroy(_data[i]);
     12022
     12023                        _data[i] = rhs._data[i];
     12024                        rhs._data[i] = 0;
     12025                }
     12026
     12027                return *this;
     12028        }
     12029#endif
     12030
     12031        PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs)
     12032        {
     12033                xpath_variable_set temp;
     12034
     12035                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12036                        if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))
     12037                                return;
     12038
     12039                _swap(temp);
     12040        }
     12041
     12042        PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs)
     12043        {
     12044                for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
     12045                {
     12046                        xpath_variable* chain = _data[i];
     12047
     12048                        _data[i] = rhs._data[i];
     12049                        rhs._data[i] = chain;
     12050                }
     12051        }
     12052
     12053        PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const
    1123512054        {
    1123612055                const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
     
    1124512064        }
    1124612065
     12066        PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)
     12067        {
     12068                xpath_variable* last = 0;
     12069
     12070                while (var)
     12071                {
     12072                        // allocate storage for new variable
     12073                        xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
     12074                        if (!nvar) return false;
     12075
     12076                        // link the variable to the result immediately to handle failures gracefully
     12077                        if (last)
     12078                                last->_next = nvar;
     12079                        else
     12080                                *out_result = nvar;
     12081
     12082                        last = nvar;
     12083
     12084                        // copy the value; this can fail due to out-of-memory conditions
     12085                        if (!impl::copy_xpath_variable(nvar, var)) return false;
     12086
     12087                        var = var->_next;
     12088                }
     12089
     12090                return true;
     12091        }
     12092
     12093        PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var)
     12094        {
     12095                while (var)
     12096                {
     12097                        xpath_variable* next = var->_next;
     12098
     12099                        impl::delete_xpath_variable(var->_type, var);
     12100
     12101                        var = next;
     12102                }
     12103        }
     12104
    1124712105        PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
    1124812106        {
     
    1126012118                if (result)
    1126112119                {
    11262                         result->_type = type;
    1126312120                        result->_next = _data[hash];
    1126412121
     
    1129512152        PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name)
    1129612153        {
    11297                 return find(name);
     12154                return _find(name);
    1129812155        }
    1129912156
    1130012157        PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
    1130112158        {
    11302                 return find(name);
     12159                return _find(name);
    1130312160        }
    1130412161
     
    1131712174                else
    1131812175                {
    11319                         impl::buffer_holder impl_holder(qimpl, impl::xpath_query_impl::destroy);
     12176                        using impl::auto_deleter; // MSVC7 workaround
     12177                        auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);
    1132012178
    1132112179                        qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
     
    1132512183                                qimpl->root->optimize(&qimpl->alloc);
    1132612184
    11327                                 _impl = static_cast<impl::xpath_query_impl*>(impl_holder.release());
     12185                                _impl = impl.release();
    1132812186                                _result.error = 0;
    1132912187                        }
     
    1133112189        }
    1133212190
     12191        PUGI__FN xpath_query::xpath_query(): _impl(0)
     12192        {
     12193        }
     12194
    1133312195        PUGI__FN xpath_query::~xpath_query()
    1133412196        {
    11335                 impl::xpath_query_impl::destroy(_impl);
    11336         }
     12197                if (_impl)
     12198                        impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
     12199        }
     12200
     12201#if __cplusplus >= 201103
     12202        PUGI__FN xpath_query::xpath_query(xpath_query&& rhs)
     12203        {
     12204                _impl = rhs._impl;
     12205                _result = rhs._result;
     12206                rhs._impl = 0;
     12207                rhs._result = xpath_parse_result();
     12208        }
     12209
     12210        PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs)
     12211        {
     12212                if (this == &rhs) return *this;
     12213
     12214                if (_impl)
     12215                        impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
     12216
     12217                _impl = rhs._impl;
     12218                _result = rhs._result;
     12219                rhs._impl = 0;
     12220                rhs._result = xpath_parse_result();
     12221
     12222                return *this;
     12223        }
     12224#endif
    1133712225
    1133812226        PUGI__FN xpath_value_type xpath_query::return_type() const
     
    1151112399#undef PUGI__FN
    1151212400#undef PUGI__FN_NO_INLINE
     12401#undef PUGI__GETPAGE_IMPL
     12402#undef PUGI__GETPAGE
    1151312403#undef PUGI__NODETYPE
    1151412404#undef PUGI__IS_CHARTYPE_IMPL
Note: See TracChangeset for help on using the changeset viewer.