diff dep/pugixml/src/pugixml.cpp @ 123:a45edd073f9e

deps/pugixml: update to v1.14.0
author Paper <mrpapersonic@gmail.com>
date Wed, 08 Nov 2023 21:40:02 -0500
parents d10b6c6b432e
children
line wrap: on
line diff
--- a/dep/pugixml/src/pugixml.cpp	Wed Nov 08 21:36:09 2023 -0500
+++ b/dep/pugixml/src/pugixml.cpp	Wed Nov 08 21:40:02 2023 -0500
@@ -1,7 +1,7 @@
 /**
- * pugixml parser - version 1.13
+ * pugixml parser - version 1.14
  * --------------------------------------------------------
- * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
+ * Copyright (C) 2006-2023, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
  * Report bugs and download new versions at https://pugixml.org/
  *
  * This library is distributed under the MIT License. See notice at the end
@@ -40,6 +40,11 @@
 // For placement new
 #include <new>
 
+// For load_file
+#if defined(__linux__) || defined(__APPLE__)
+#include <sys/stat.h>
+#endif
+
 #ifdef _MSC_VER
 #	pragma warning(push)
 #	pragma warning(disable: 4127) // conditional expression is constant
@@ -82,39 +87,39 @@
 
 // Inlining controls
 #if defined(_MSC_VER) && _MSC_VER >= 1300
-#	define PUGI__NO_INLINE __declspec(noinline)
+#	define PUGI_IMPL_NO_INLINE __declspec(noinline)
 #elif defined(__GNUC__)
-#	define PUGI__NO_INLINE __attribute__((noinline))
+#	define PUGI_IMPL_NO_INLINE __attribute__((noinline))
 #else
-#	define PUGI__NO_INLINE
+#	define PUGI_IMPL_NO_INLINE
 #endif
 
 // Branch weight controls
 #if defined(__GNUC__) && !defined(__c2__)
-#	define PUGI__UNLIKELY(cond) __builtin_expect(cond, 0)
+#	define PUGI_IMPL_UNLIKELY(cond) __builtin_expect(cond, 0)
 #else
-#	define PUGI__UNLIKELY(cond) (cond)
+#	define PUGI_IMPL_UNLIKELY(cond) (cond)
 #endif
 
 // Simple static assertion
-#define PUGI__STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
+#define PUGI_IMPL_STATIC_ASSERT(cond) { static const char condition_failed[(cond) ? 1 : -1] = {0}; (void)condition_failed[0]; }
 
 // Digital Mars C++ bug workaround for passing char loaded from memory via stack
 #ifdef __DMC__
-#	define PUGI__DMC_VOLATILE volatile
+#	define PUGI_IMPL_DMC_VOLATILE volatile
 #else
-#	define PUGI__DMC_VOLATILE
+#	define PUGI_IMPL_DMC_VOLATILE
 #endif
 
 // Integer sanitizer workaround; we only apply this for clang since gcc8 has no_sanitize but not unsigned-integer-overflow and produces "attribute directive ignored" warnings
 #if defined(__clang__) && defined(__has_attribute)
 #	if __has_attribute(no_sanitize)
-#		define PUGI__UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow")))
+#		define PUGI_IMPL_UNSIGNED_OVERFLOW __attribute__((no_sanitize("unsigned-integer-overflow")))
 #	else
-#		define PUGI__UNSIGNED_OVERFLOW
+#		define PUGI_IMPL_UNSIGNED_OVERFLOW
 #	endif
 #else
-#	define PUGI__UNSIGNED_OVERFLOW
+#	define PUGI_IMPL_UNSIGNED_OVERFLOW
 #endif
 
 // Borland C++ bug workaround for not defining ::memcpy depending on header include order (can't always use std::memcpy because some compilers don't have it at all)
@@ -124,6 +129,12 @@
 using std::memset;
 #endif
 
+// Old versions of GCC do not define ::malloc and ::free depending on header include order
+#if defined(__GNUC__) && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4))
+using std::malloc;
+using std::free;
+#endif
+
 // Some MinGW/GCC versions have headers that erroneously omit LLONG_MIN/LLONG_MAX/ULLONG_MAX definitions from limits.h in some configurations
 #if defined(PUGIXML_HAS_LONG_LONG) && defined(__GNUC__) && !defined(LLONG_MAX) && !defined(LLONG_MIN) && !defined(ULLONG_MAX)
 #	define LLONG_MIN (-LLONG_MAX - 1LL)
@@ -133,36 +144,38 @@
 
 // In some environments MSVC is a compiler but the CRT lacks certain MSVC-specific features
 #if defined(_MSC_VER) && !defined(__S3E__) && !defined(_WIN32_WCE)
-#	define PUGI__MSVC_CRT_VERSION _MSC_VER
+#	define PUGI_IMPL_MSVC_CRT_VERSION _MSC_VER
 #elif defined(_WIN32_WCE)
-#	define PUGI__MSVC_CRT_VERSION 1310 // MSVC7.1
+#	define PUGI_IMPL_MSVC_CRT_VERSION 1310 // MSVC7.1
 #endif
 
 // Not all platforms have snprintf; we define a wrapper that uses snprintf if possible. This only works with buffers with a known size.
 #if __cplusplus >= 201103
-#	define PUGI__SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
-#elif defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
-#	define PUGI__SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__)
+#	define PUGI_IMPL_SNPRINTF(buf, ...) snprintf(buf, sizeof(buf), __VA_ARGS__)
+#elif defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400
+#	define PUGI_IMPL_SNPRINTF(buf, ...) _snprintf_s(buf, _countof(buf), _TRUNCATE, __VA_ARGS__)
+#elif defined(__APPLE__) && __clang_major__ >= 14 // Xcode 14 marks sprintf as deprecated while still using C++98 by default
+#	define PUGI_IMPL_SNPRINTF(buf, fmt, arg1, arg2) snprintf(buf, sizeof(buf), fmt, arg1, arg2)
 #else
-#	define PUGI__SNPRINTF sprintf
+#	define PUGI_IMPL_SNPRINTF sprintf
 #endif
 
 // We put implementation details into an anonymous namespace in source mode, but have to keep it in non-anonymous namespace in header-only mode to prevent binary bloat.
 #ifdef PUGIXML_HEADER_ONLY
-#	define PUGI__NS_BEGIN namespace pugi { namespace impl {
-#	define PUGI__NS_END } }
-#	define PUGI__FN inline
-#	define PUGI__FN_NO_INLINE inline
+#	define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl {
+#	define PUGI_IMPL_NS_END } }
+#	define PUGI_IMPL_FN inline
+#	define PUGI_IMPL_FN_NO_INLINE inline
 #else
 #	if defined(_MSC_VER) && _MSC_VER < 1300 // MSVC6 seems to have an amusing bug with anonymous namespaces inside namespaces
-#		define PUGI__NS_BEGIN namespace pugi { namespace impl {
-#		define PUGI__NS_END } }
+#		define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl {
+#		define PUGI_IMPL_NS_END } }
 #	else
-#		define PUGI__NS_BEGIN namespace pugi { namespace impl { namespace {
-#		define PUGI__NS_END } } }
+#		define PUGI_IMPL_NS_BEGIN namespace pugi { namespace impl { namespace {
+#		define PUGI_IMPL_NS_END } } }
 #	endif
-#	define PUGI__FN
-#	define PUGI__FN_NO_INLINE PUGI__NO_INLINE
+#	define PUGI_IMPL_FN
+#	define PUGI_IMPL_FN_NO_INLINE PUGI_IMPL_NO_INLINE
 #endif
 
 // uintptr_t
@@ -182,13 +195,13 @@
 #endif
 
 // Memory allocation
-PUGI__NS_BEGIN
-	PUGI__FN void* default_allocate(size_t size)
+PUGI_IMPL_NS_BEGIN
+	PUGI_IMPL_FN void* default_allocate(size_t size)
 	{
 		return malloc(size);
 	}
 
-	PUGI__FN void default_deallocate(void* ptr)
+	PUGI_IMPL_FN void default_deallocate(void* ptr)
 	{
 		free(ptr);
 	}
@@ -206,12 +219,12 @@
 	template <typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;
 
 	typedef xml_memory_management_function_storage<int> xml_memory;
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 // String utilities
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	// Get string length
-	PUGI__FN size_t strlength(const char_t* s)
+	PUGI_IMPL_FN size_t strlength(const char_t* s)
 	{
 		assert(s);
 
@@ -223,7 +236,7 @@
 	}
 
 	// Compare two strings
-	PUGI__FN bool strequal(const char_t* src, const char_t* dst)
+	PUGI_IMPL_FN bool strequal(const char_t* src, const char_t* dst)
 	{
 		assert(src && dst);
 
@@ -235,7 +248,7 @@
 	}
 
 	// Compare lhs with [rhs_begin, rhs_end)
-	PUGI__FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
+	PUGI_IMPL_FN bool strequalrange(const char_t* lhs, const char_t* rhs, size_t count)
 	{
 		for (size_t i = 0; i < count; ++i)
 			if (lhs[i] != rhs[i])
@@ -245,7 +258,7 @@
 	}
 
 	// Get length of wide string, even if CRT lacks wide character support
-	PUGI__FN size_t strlength_wide(const wchar_t* s)
+	PUGI_IMPL_FN size_t strlength_wide(const wchar_t* s)
 	{
 		assert(s);
 
@@ -257,10 +270,10 @@
 		return static_cast<size_t>(end - s);
 	#endif
 	}
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 // auto_ptr-like object for exception recovery
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	template <typename T> struct auto_deleter
 	{
 		typedef void (*D)(T*);
@@ -284,10 +297,10 @@
 			return result;
 		}
 	};
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 #ifdef PUGIXML_COMPACT
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	class compact_hash_table
 	{
 	public:
@@ -378,7 +391,7 @@
 			return 0;
 		}
 
-		static PUGI__UNSIGNED_OVERFLOW unsigned int hash(const void* key)
+		static PUGI_IMPL_UNSIGNED_OVERFLOW unsigned int hash(const void* key)
 		{
 			unsigned int h = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(key) & 0xffffffff);
 
@@ -393,7 +406,7 @@
 		}
 	};
 
-	PUGI__FN_NO_INLINE bool compact_hash_table::rehash(size_t count)
+	PUGI_IMPL_FN_NO_INLINE bool compact_hash_table::rehash(size_t count)
 	{
 		size_t capacity = 32;
 		while (count >= capacity - capacity / 4)
@@ -423,10 +436,10 @@
 		return true;
 	}
 
-PUGI__NS_END
+PUGI_IMPL_NS_END
 #endif
 
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 #ifdef PUGIXML_COMPACT
 	static const uintptr_t xml_memory_block_alignment = 4;
 #else
@@ -444,16 +457,16 @@
 	static const uintptr_t xml_memory_page_value_allocated_or_shared_mask = xml_memory_page_value_allocated_mask | xml_memory_page_contents_shared_mask;
 
 #ifdef PUGIXML_COMPACT
-	#define PUGI__GETHEADER_IMPL(object, page, flags) // unused
-	#define PUGI__GETPAGE_IMPL(header) (header).get_page()
+	#define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) // unused
+	#define PUGI_IMPL_GETPAGE_IMPL(header) (header).get_page()
 #else
-	#define PUGI__GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))
+	#define PUGI_IMPL_GETHEADER_IMPL(object, page, flags) (((reinterpret_cast<char*>(object) - reinterpret_cast<char*>(page)) << 8) | (flags))
 	// this macro casts pointers through void* to avoid 'cast increases required alignment of target type' warnings
-	#define PUGI__GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8))))
+	#define PUGI_IMPL_GETPAGE_IMPL(header) static_cast<impl::xml_memory_page*>(const_cast<void*>(static_cast<const void*>(reinterpret_cast<const char*>(&header) - (header >> 8))))
 #endif
 
-	#define PUGI__GETPAGE(n) PUGI__GETPAGE_IMPL((n)->header)
-	#define PUGI__NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
+	#define PUGI_IMPL_GETPAGE(n) PUGI_IMPL_GETPAGE_IMPL((n)->header)
+	#define PUGI_IMPL_NODETYPE(n) static_cast<xml_node_type>((n)->header & impl::xml_memory_page_type_mask)
 
 	struct xml_allocator;
 
@@ -543,7 +556,7 @@
 
 		void* allocate_memory(size_t size, xml_memory_page*& out_page)
 		{
-			if (PUGI__UNLIKELY(_busy_size + size > xml_memory_page_size))
+			if (PUGI_IMPL_UNLIKELY(_busy_size + size > xml_memory_page_size))
 				return allocate_memory_oob(size, out_page);
 
 			void* buf = reinterpret_cast<char*>(_root) + sizeof(xml_memory_page) + _busy_size;
@@ -564,7 +577,7 @@
 			// adjust for marker
 			ptrdiff_t offset = static_cast<char*>(result) - reinterpret_cast<char*>(out_page->compact_page_marker);
 
-			if (PUGI__UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment))
+			if (PUGI_IMPL_UNLIKELY(static_cast<uintptr_t>(offset) >= 256 * xml_memory_block_alignment))
 			{
 				// insert new marker
 				uint32_t* marker = static_cast<uint32_t*>(result);
@@ -641,7 +654,7 @@
 		{
 			static const size_t max_encoded_offset = (1 << 16) * xml_memory_block_alignment;
 
-			PUGI__STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
+			PUGI_IMPL_STATIC_ASSERT(xml_memory_page_size <= max_encoded_offset);
 
 			// allocate memory for string and header block
 			size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
@@ -707,7 +720,7 @@
 	#endif
 	};
 
-	PUGI__FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)
+	PUGI_IMPL_FN_NO_INLINE void* xml_allocator::allocate_memory_oob(size_t size, xml_memory_page*& out_page)
 	{
 		const size_t large_allocation_threshold = xml_memory_page_size / 4;
 
@@ -744,10 +757,10 @@
 
 		return reinterpret_cast<char*>(page) + sizeof(xml_memory_page);
 	}
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 #ifdef PUGIXML_COMPACT
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	static const uintptr_t compact_alignment_log2 = 2;
 	static const uintptr_t compact_alignment = 1 << compact_alignment_log2;
 
@@ -756,7 +769,7 @@
 	public:
 		compact_header(xml_memory_page* page, unsigned int flags)
 		{
-			PUGI__STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
+			PUGI_IMPL_STATIC_ASSERT(xml_memory_block_alignment == compact_alignment);
 
 			ptrdiff_t offset = (reinterpret_cast<char*>(this) - reinterpret_cast<char*>(page->compact_page_marker));
 			assert(offset % compact_alignment == 0 && static_cast<uintptr_t>(offset) < 256 * compact_alignment);
@@ -794,19 +807,19 @@
 		unsigned char _flags;
 	};
 
-	PUGI__FN xml_memory_page* compact_get_page(const void* object, int header_offset)
+	PUGI_IMPL_FN xml_memory_page* compact_get_page(const void* object, int header_offset)
 	{
 		const compact_header* header = reinterpret_cast<const compact_header*>(static_cast<const char*>(object) - header_offset);
 
 		return header->get_page();
 	}
 
-	template <int header_offset, typename T> PUGI__FN_NO_INLINE T* compact_get_value(const void* object)
+	template <int header_offset, typename T> PUGI_IMPL_FN_NO_INLINE T* compact_get_value(const void* object)
 	{
 		return static_cast<T*>(compact_get_page(object, header_offset)->allocator->_hash->find(object));
 	}
 
-	template <int header_offset, typename T> PUGI__FN_NO_INLINE void compact_set_value(const void* object, T* value)
+	template <int header_offset, typename T> PUGI_IMPL_FN_NO_INLINE void compact_set_value(const void* object, T* value)
 	{
 		compact_get_page(object, header_offset)->allocator->_hash->insert(object, value);
 	}
@@ -904,7 +917,7 @@
 				{
 					xml_memory_page* page = compact_get_page(this, header_offset);
 
-					if (PUGI__UNLIKELY(page->compact_shared_parent == 0))
+					if (PUGI_IMPL_UNLIKELY(page->compact_shared_parent == 0))
 						page->compact_shared_parent = value;
 
 					if (page->compact_shared_parent == value)
@@ -971,7 +984,7 @@
 			{
 				xml_memory_page* page = compact_get_page(this, header_offset);
 
-				if (PUGI__UNLIKELY(page->compact_string_base == 0))
+				if (PUGI_IMPL_UNLIKELY(page->compact_string_base == 0))
 					page->compact_string_base = value;
 
 				ptrdiff_t offset = value - page->compact_string_base;
@@ -1043,7 +1056,7 @@
 	private:
 		unsigned char _data;
 	};
-PUGI__NS_END
+PUGI_IMPL_NS_END
 #endif
 
 #ifdef PUGIXML_COMPACT
@@ -1053,7 +1066,7 @@
 	{
 		xml_attribute_struct(impl::xml_memory_page* page): header(page, 0), namevalue_base(0)
 		{
-			PUGI__STATIC_ASSERT(sizeof(xml_attribute_struct) == 8);
+			PUGI_IMPL_STATIC_ASSERT(sizeof(xml_attribute_struct) == 8);
 		}
 
 		impl::compact_header header;
@@ -1071,7 +1084,7 @@
 	{
 		xml_node_struct(impl::xml_memory_page* page, xml_node_type type): header(page, type), namevalue_base(0)
 		{
-			PUGI__STATIC_ASSERT(sizeof(xml_node_struct) == 12);
+			PUGI_IMPL_STATIC_ASSERT(sizeof(xml_node_struct) == 12);
 		}
 
 		impl::compact_header header;
@@ -1098,7 +1111,7 @@
 	{
 		xml_attribute_struct(impl::xml_memory_page* page): name(0), value(0), prev_attribute_c(0), next_attribute(0)
 		{
-			header = PUGI__GETHEADER_IMPL(this, page, 0);
+			header = PUGI_IMPL_GETHEADER_IMPL(this, page, 0);
 		}
 
 		uintptr_t header;
@@ -1114,7 +1127,7 @@
 	{
 		xml_node_struct(impl::xml_memory_page* page, xml_node_type type): name(0), value(0), parent(0), first_child(0), prev_sibling_c(0), next_sibling(0), first_attribute(0)
 		{
-			header = PUGI__GETHEADER_IMPL(this, page, type);
+			header = PUGI_IMPL_GETHEADER_IMPL(this, page, type);
 		}
 
 		uintptr_t header;
@@ -1134,7 +1147,7 @@
 }
 #endif
 
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	struct xml_extra_buffer
 	{
 		char_t* buffer;
@@ -1160,19 +1173,19 @@
 	{
 		assert(object);
 
-		return *PUGI__GETPAGE(object)->allocator;
+		return *PUGI_IMPL_GETPAGE(object)->allocator;
 	}
 
 	template <typename Object> inline xml_document_struct& get_document(const Object* object)
 	{
 		assert(object);
 
-		return *static_cast<xml_document_struct*>(PUGI__GETPAGE(object)->allocator);
-	}
-PUGI__NS_END
+		return *static_cast<xml_document_struct*>(PUGI_IMPL_GETPAGE(object)->allocator);
+	}
+PUGI_IMPL_NS_END
 
 // Low-level DOM operations
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	inline xml_attribute_struct* allocate_attribute(xml_allocator& alloc)
 	{
 		xml_memory_page* page;
@@ -1199,7 +1212,7 @@
 		if (a->header & impl::xml_memory_page_value_allocated_mask)
 			alloc.deallocate_string(a->value);
 
-		alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI__GETPAGE(a));
+		alloc.deallocate_memory(a, sizeof(xml_attribute_struct), PUGI_IMPL_GETPAGE(a));
 	}
 
 	inline void destroy_node(xml_node_struct* n, xml_allocator& alloc)
@@ -1228,7 +1241,7 @@
 			child = next;
 		}
 
-		alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI__GETPAGE(n));
+		alloc.deallocate_memory(n, sizeof(xml_node_struct), PUGI_IMPL_GETPAGE(n));
 	}
 
 	inline void append_node(xml_node_struct* child, xml_node_struct* node)
@@ -1412,7 +1425,7 @@
 		attr->next_attribute = 0;
 	}
 
-	PUGI__FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
+	PUGI_IMPL_FN_NO_INLINE xml_node_struct* append_new_node(xml_node_struct* node, xml_allocator& alloc, xml_node_type type = node_element)
 	{
 		if (!alloc.reserve()) return 0;
 
@@ -1424,7 +1437,7 @@
 		return child;
 	}
 
-	PUGI__FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)
+	PUGI_IMPL_FN_NO_INLINE xml_attribute_struct* append_new_attribute(xml_node_struct* node, xml_allocator& alloc)
 	{
 		if (!alloc.reserve()) return 0;
 
@@ -1435,10 +1448,10 @@
 
 		return attr;
 	}
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 // Helper classes for code generation
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	struct opt_false
 	{
 		enum { value = 0 };
@@ -1448,10 +1461,10 @@
 	{
 		enum { value = 1 };
 	};
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 // Unicode utilities
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	inline uint16_t endian_swap(uint16_t value)
 	{
 		return static_cast<uint16_t>(((value & 0xff) << 8) | (value >> 8));
@@ -1833,15 +1846,15 @@
 	};
 
 #ifdef PUGIXML_WCHAR_MODE
-	PUGI__FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
+	PUGI_IMPL_FN void convert_wchar_endian_swap(wchar_t* result, const wchar_t* data, size_t length)
 	{
 		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])));
 	}
 #endif
-PUGI__NS_END
-
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_END
+
+PUGI_IMPL_NS_BEGIN
 	enum chartype_t
 	{
 		ct_parse_pcdata = 1,	// \0, &, \r, <
@@ -1907,24 +1920,24 @@
 	};
 
 #ifdef PUGIXML_WCHAR_MODE
-	#define PUGI__IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
+	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) ((static_cast<unsigned int>(c) < 128 ? table[static_cast<unsigned int>(c)] : table[128]) & (ct))
 #else
-	#define PUGI__IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
+	#define PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, table) (table[static_cast<unsigned char>(c)] & (ct))
 #endif
 
-	#define PUGI__IS_CHARTYPE(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartype_table)
-	#define PUGI__IS_CHARTYPEX(c, ct) PUGI__IS_CHARTYPE_IMPL(c, ct, chartypex_table)
-
-	PUGI__FN bool is_little_endian()
+	#define PUGI_IMPL_IS_CHARTYPE(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartype_table)
+	#define PUGI_IMPL_IS_CHARTYPEX(c, ct) PUGI_IMPL_IS_CHARTYPE_IMPL(c, ct, chartypex_table)
+
+	PUGI_IMPL_FN bool is_little_endian()
 	{
 		unsigned int ui = 1;
 
 		return *reinterpret_cast<unsigned char*>(&ui) == 1;
 	}
 
-	PUGI__FN xml_encoding get_wchar_encoding()
-	{
-		PUGI__STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
+	PUGI_IMPL_FN xml_encoding get_wchar_encoding()
+	{
+		PUGI_IMPL_STATIC_ASSERT(sizeof(wchar_t) == 2 || sizeof(wchar_t) == 4);
 
 		if (sizeof(wchar_t) == 2)
 			return is_little_endian() ? encoding_utf16_le : encoding_utf16_be;
@@ -1932,13 +1945,13 @@
 			return is_little_endian() ? encoding_utf32_le : encoding_utf32_be;
 	}
 
-	PUGI__FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length)
-	{
-	#define PUGI__SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
-	#define PUGI__SCANCHARTYPE(ct) { while (offset < size && PUGI__IS_CHARTYPE(data[offset], ct)) offset++; }
+	PUGI_IMPL_FN bool parse_declaration_encoding(const uint8_t* data, size_t size, const uint8_t*& out_encoding, size_t& out_length)
+	{
+	#define PUGI_IMPL_SCANCHAR(ch) { if (offset >= size || data[offset] != ch) return false; offset++; }
+	#define PUGI_IMPL_SCANCHARTYPE(ct) { while (offset < size && PUGI_IMPL_IS_CHARTYPE(data[offset], ct)) offset++; }
 
 		// check if we have a non-empty XML declaration
-		if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI__IS_CHARTYPE(data[5], ct_space)))
+		if (size < 6 || !((data[0] == '<') & (data[1] == '?') & (data[2] == 'x') & (data[3] == 'm') & (data[4] == 'l') && PUGI_IMPL_IS_CHARTYPE(data[5], ct_space)))
 			return false;
 
 		// scan XML declaration until the encoding field
@@ -1953,28 +1966,28 @@
 				size_t offset = i;
 
 				// encoding follows the version field which can't contain 'en' so this has to be the encoding if XML is well formed
-				PUGI__SCANCHAR('e'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('c'); PUGI__SCANCHAR('o');
-				PUGI__SCANCHAR('d'); PUGI__SCANCHAR('i'); PUGI__SCANCHAR('n'); PUGI__SCANCHAR('g');
+				PUGI_IMPL_SCANCHAR('e'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('c'); PUGI_IMPL_SCANCHAR('o');
+				PUGI_IMPL_SCANCHAR('d'); PUGI_IMPL_SCANCHAR('i'); PUGI_IMPL_SCANCHAR('n'); PUGI_IMPL_SCANCHAR('g');
 
 				// S? = S?
-				PUGI__SCANCHARTYPE(ct_space);
-				PUGI__SCANCHAR('=');
-				PUGI__SCANCHARTYPE(ct_space);
+				PUGI_IMPL_SCANCHARTYPE(ct_space);
+				PUGI_IMPL_SCANCHAR('=');
+				PUGI_IMPL_SCANCHARTYPE(ct_space);
 
 				// the only two valid delimiters are ' and "
 				uint8_t delimiter = (offset < size && data[offset] == '"') ? '"' : '\'';
 
-				PUGI__SCANCHAR(delimiter);
+				PUGI_IMPL_SCANCHAR(delimiter);
 
 				size_t start = offset;
 
 				out_encoding = data + offset;
 
-				PUGI__SCANCHARTYPE(ct_symbol);
+				PUGI_IMPL_SCANCHARTYPE(ct_symbol);
 
 				out_length = offset - start;
 
-				PUGI__SCANCHAR(delimiter);
+				PUGI_IMPL_SCANCHAR(delimiter);
 
 				return true;
 			}
@@ -1982,11 +1995,11 @@
 
 		return false;
 
-	#undef PUGI__SCANCHAR
-	#undef PUGI__SCANCHARTYPE
-	}
-
-	PUGI__FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size)
+	#undef PUGI_IMPL_SCANCHAR
+	#undef PUGI_IMPL_SCANCHARTYPE
+	}
+
+	PUGI_IMPL_FN xml_encoding guess_buffer_encoding(const uint8_t* data, size_t size)
 	{
 		// skip encoding autodetection if input buffer is too small
 		if (size < 4) return encoding_utf8;
@@ -2034,7 +2047,7 @@
 		return encoding_utf8;
 	}
 
-	PUGI__FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
+	PUGI_IMPL_FN xml_encoding get_buffer_encoding(xml_encoding encoding, const void* contents, size_t size)
 	{
 		// replace wchar encoding with utf implementation
 		if (encoding == encoding_wchar) return get_wchar_encoding();
@@ -2054,7 +2067,7 @@
 		return guess_buffer_encoding(data, size);
 	}
 
-	PUGI__FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
+	PUGI_IMPL_FN bool get_mutable_buffer(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
 	{
 		size_t length = size / sizeof(char_t);
 
@@ -2083,13 +2096,13 @@
 	}
 
 #ifdef PUGIXML_WCHAR_MODE
-	PUGI__FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
+	PUGI_IMPL_FN bool need_endian_swap_utf(xml_encoding le, xml_encoding re)
 	{
 		return (le == encoding_utf16_be && re == encoding_utf16_le) || (le == encoding_utf16_le && re == encoding_utf16_be) ||
 			   (le == encoding_utf32_be && re == encoding_utf32_le) || (le == encoding_utf32_le && re == encoding_utf32_be);
 	}
 
-	PUGI__FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
+	PUGI_IMPL_FN bool convert_buffer_endian_swap(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
 	{
 		const char_t* data = static_cast<const char_t*>(contents);
 		size_t length = size / sizeof(char_t);
@@ -2118,7 +2131,7 @@
 		return true;
 	}
 
-	template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
+	template <typename D> PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
 	{
 		const typename D::type* data = static_cast<const typename D::type*>(contents);
 		size_t data_length = size / sizeof(typename D::type);
@@ -2143,7 +2156,7 @@
 		return true;
 	}
 
-	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)
+	PUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
 	{
 		// get native encoding
 		xml_encoding wchar_encoding = get_wchar_encoding();
@@ -2188,7 +2201,7 @@
 		return false;
 	}
 #else
-	template <typename D> PUGI__FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
+	template <typename D> PUGI_IMPL_FN bool convert_buffer_generic(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, D)
 	{
 		const typename D::type* data = static_cast<const typename D::type*>(contents);
 		size_t data_length = size / sizeof(typename D::type);
@@ -2213,7 +2226,7 @@
 		return true;
 	}
 
-	PUGI__FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
+	PUGI_IMPL_FN size_t get_latin1_7bit_prefix_length(const uint8_t* data, size_t size)
 	{
 		for (size_t i = 0; i < size; ++i)
 			if (data[i] > 127)
@@ -2222,7 +2235,7 @@
 		return size;
 	}
 
-	PUGI__FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
+	PUGI_IMPL_FN bool convert_buffer_latin1(char_t*& out_buffer, size_t& out_length, const void* contents, size_t size, bool is_mutable)
 	{
 		const uint8_t* data = static_cast<const uint8_t*>(contents);
 		size_t data_length = size;
@@ -2259,7 +2272,7 @@
 		return true;
 	}
 
-	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)
+	PUGI_IMPL_FN bool convert_buffer(char_t*& out_buffer, size_t& out_length, xml_encoding encoding, const void* contents, size_t size, bool is_mutable)
 	{
 		// fast path: no conversion required
 		if (encoding == encoding_utf8)
@@ -2294,13 +2307,13 @@
 	}
 #endif
 
-	PUGI__FN size_t as_utf8_begin(const wchar_t* str, size_t length)
+	PUGI_IMPL_FN size_t as_utf8_begin(const wchar_t* str, size_t length)
 	{
 		// get length in utf8 characters
 		return wchar_decoder::process(str, length, 0, utf8_counter());
 	}
 
-	PUGI__FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
+	PUGI_IMPL_FN void as_utf8_end(char* buffer, size_t size, const wchar_t* str, size_t length)
 	{
 		// convert to utf8
 		uint8_t* begin = reinterpret_cast<uint8_t*>(buffer);
@@ -2312,7 +2325,7 @@
 	}
 
 #ifndef PUGIXML_NO_STL
-	PUGI__FN std::string as_utf8_impl(const wchar_t* str, size_t length)
+	PUGI_IMPL_FN std::string as_utf8_impl(const wchar_t* str, size_t length)
 	{
 		// first pass: get length in utf8 characters
 		size_t size = as_utf8_begin(str, length);
@@ -2327,7 +2340,7 @@
 		return result;
 	}
 
-	PUGI__FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)
+	PUGI_IMPL_FN std::basic_string<wchar_t> as_wide_impl(const char* str, size_t size)
 	{
 		const uint8_t* data = reinterpret_cast<const uint8_t*>(str);
 
@@ -2370,12 +2383,14 @@
 	}
 
 	template <typename String, typename Header>
-	PUGI__FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length)
-	{
+	PUGI_IMPL_FN bool strcpy_insitu(String& dest, Header& header, uintptr_t header_mask, const char_t* source, size_t source_length)
+	{
+		assert((header & header_mask) == 0 || dest); // header bit indicates whether dest was previously allocated
+
 		if (source_length == 0)
 		{
 			// empty string and null pointer are equivalent, so just deallocate old memory
-			xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
+			xml_allocator* alloc = PUGI_IMPL_GETPAGE_IMPL(header)->allocator;
 
 			if (header & header_mask) alloc->deallocate_string(dest);
 
@@ -2395,7 +2410,7 @@
 		}
 		else
 		{
-			xml_allocator* alloc = PUGI__GETPAGE_IMPL(header)->allocator;
+			xml_allocator* alloc = PUGI_IMPL_GETPAGE_IMPL(header)->allocator;
 
 			if (!alloc->reserve()) return false;
 
@@ -2460,7 +2475,7 @@
 		}
 	};
 
-	PUGI__FN char_t* strconv_escape(char_t* s, gap& g)
+	PUGI_IMPL_FN char_t* strconv_escape(char_t* s, gap& g)
 	{
 		char_t* stre = s + 1;
 
@@ -2601,25 +2616,25 @@
 	}
 
 	// Parser utilities
-	#define PUGI__ENDSWITH(c, e)        ((c) == (e) || ((c) == 0 && endch == (e)))
-	#define PUGI__SKIPWS()              { while (PUGI__IS_CHARTYPE(*s, ct_space)) ++s; }
-	#define PUGI__OPTSET(OPT)           ( optmsk & (OPT) )
-	#define PUGI__PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI__THROW_ERROR(status_out_of_memory, s); }
-	#define PUGI__POPNODE()             { cursor = cursor->parent; }
-	#define PUGI__SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
-	#define PUGI__SCANWHILE(X)          { while (X) ++s; }
-	#define PUGI__SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI__UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI__UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI__UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI__UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
-	#define PUGI__ENDSEG()              { ch = *s; *s = 0; ++s; }
-	#define PUGI__THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(0)
-	#define PUGI__CHECK_ERROR(err, m)   { if (*s == 0) PUGI__THROW_ERROR(err, m); }
-
-	PUGI__FN char_t* strconv_comment(char_t* s, char_t endch)
+	#define PUGI_IMPL_ENDSWITH(c, e)        ((c) == (e) || ((c) == 0 && endch == (e)))
+	#define PUGI_IMPL_SKIPWS()              { while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space)) ++s; }
+	#define PUGI_IMPL_OPTSET(OPT)           ( optmsk & (OPT) )
+	#define PUGI_IMPL_PUSHNODE(TYPE)        { cursor = append_new_node(cursor, *alloc, TYPE); if (!cursor) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s); }
+	#define PUGI_IMPL_POPNODE()             { cursor = cursor->parent; }
+	#define PUGI_IMPL_SCANFOR(X)            { while (*s != 0 && !(X)) ++s; }
+	#define PUGI_IMPL_SCANWHILE(X)          { while (X) ++s; }
+	#define PUGI_IMPL_SCANWHILE_UNROLL(X)   { for (;;) { char_t ss = s[0]; if (PUGI_IMPL_UNLIKELY(!(X))) { break; } ss = s[1]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 1; break; } ss = s[2]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 2; break; } ss = s[3]; if (PUGI_IMPL_UNLIKELY(!(X))) { s += 3; break; } s += 4; } }
+	#define PUGI_IMPL_ENDSEG()              { ch = *s; *s = 0; ++s; }
+	#define PUGI_IMPL_THROW_ERROR(err, m)   return error_offset = m, error_status = err, static_cast<char_t*>(0)
+	#define PUGI_IMPL_CHECK_ERROR(err, m)   { if (*s == 0) PUGI_IMPL_THROW_ERROR(err, m); }
+
+	PUGI_IMPL_FN char_t* strconv_comment(char_t* s, char_t endch)
 	{
 		gap g;
 
 		while (true)
 		{
-			PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_comment));
+			PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_comment));
 
 			if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
 			{
@@ -2627,7 +2642,7 @@
 
 				if (*s == '\n') g.push(s, 1);
 			}
-			else if (s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>')) // comment ends here
+			else if (s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>')) // comment ends here
 			{
 				*g.flush(s) = 0;
 
@@ -2641,13 +2656,13 @@
 		}
 	}
 
-	PUGI__FN char_t* strconv_cdata(char_t* s, char_t endch)
+	PUGI_IMPL_FN char_t* strconv_cdata(char_t* s, char_t endch)
 	{
 		gap g;
 
 		while (true)
 		{
-			PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_cdata));
+			PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_cdata));
 
 			if (*s == '\r') // Either a single 0x0d or 0x0d 0x0a pair
 			{
@@ -2655,7 +2670,7 @@
 
 				if (*s == '\n') g.push(s, 1);
 			}
-			else if (s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>')) // CDATA ends here
+			else if (s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>')) // CDATA ends here
 			{
 				*g.flush(s) = 0;
 
@@ -2681,14 +2696,14 @@
 
 			while (true)
 			{
-				PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_pcdata));
+				PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_pcdata));
 
 				if (*s == '<') // PCDATA ends here
 				{
 					char_t* end = g.flush(s);
 
 					if (opt_trim::value)
-						while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
+						while (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space))
 							--end;
 
 					*end = 0;
@@ -2710,7 +2725,7 @@
 					char_t* end = g.flush(s);
 
 					if (opt_trim::value)
-						while (end > begin && PUGI__IS_CHARTYPE(end[-1], ct_space))
+						while (end > begin && PUGI_IMPL_IS_CHARTYPE(end[-1], ct_space))
 							--end;
 
 					*end = 0;
@@ -2722,9 +2737,9 @@
 		}
 	};
 
-	PUGI__FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
-	{
-		PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
+	PUGI_IMPL_FN strconv_pcdata_t get_strconv_pcdata(unsigned int optmask)
+	{
+		PUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_trim_pcdata == 0x0800);
 
 		switch (((optmask >> 4) & 3) | ((optmask >> 9) & 4)) // get bitmask for flags (trim eol escapes); this simultaneously checks 3 options from assertion above
 		{
@@ -2749,37 +2764,37 @@
 			gap g;
 
 			// trim leading whitespaces
-			if (PUGI__IS_CHARTYPE(*s, ct_space))
+			if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))
 			{
 				char_t* str = s;
 
 				do ++str;
-				while (PUGI__IS_CHARTYPE(*str, ct_space));
+				while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space));
 
 				g.push(s, str - s);
 			}
 
 			while (true)
 			{
-				PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space));
+				PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws | ct_space));
 
 				if (*s == end_quote)
 				{
 					char_t* str = g.flush(s);
 
 					do *str-- = 0;
-					while (PUGI__IS_CHARTYPE(*str, ct_space));
+					while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space));
 
 					return s + 1;
 				}
-				else if (PUGI__IS_CHARTYPE(*s, ct_space))
+				else if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))
 				{
 					*s++ = ' ';
 
-					if (PUGI__IS_CHARTYPE(*s, ct_space))
+					if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))
 					{
 						char_t* str = s + 1;
-						while (PUGI__IS_CHARTYPE(*str, ct_space)) ++str;
+						while (PUGI_IMPL_IS_CHARTYPE(*str, ct_space)) ++str;
 
 						g.push(s, str - s);
 					}
@@ -2802,7 +2817,7 @@
 
 			while (true)
 			{
-				PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr_ws));
+				PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr_ws));
 
 				if (*s == end_quote)
 				{
@@ -2810,7 +2825,7 @@
 
 					return s + 1;
 				}
-				else if (PUGI__IS_CHARTYPE(*s, ct_space))
+				else if (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))
 				{
 					if (*s == '\r')
 					{
@@ -2838,7 +2853,7 @@
 
 			while (true)
 			{
-				PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
+				PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr));
 
 				if (*s == end_quote)
 				{
@@ -2870,7 +2885,7 @@
 
 			while (true)
 			{
-				PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPE(ss, ct_parse_attr));
+				PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPE(ss, ct_parse_attr));
 
 				if (*s == end_quote)
 				{
@@ -2891,9 +2906,9 @@
 		}
 	};
 
-	PUGI__FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
-	{
-		PUGI__STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
+	PUGI_IMPL_FN strconv_attribute_t get_strconv_attribute(unsigned int optmask)
+	{
+		PUGI_IMPL_STATIC_ASSERT(parse_escapes == 0x10 && parse_eol == 0x20 && parse_wconv_attribute == 0x40 && parse_wnorm_attribute == 0x80);
 
 		switch ((optmask >> 4) & 15) // get bitmask for flags (wnorm wconv eol escapes); this simultaneously checks 4 options from assertion above
 		{
@@ -2949,8 +2964,8 @@
 			{
 				// quoted string
 				char_t ch = *s++;
-				PUGI__SCANFOR(*s == ch);
-				if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
+				PUGI_IMPL_SCANFOR(*s == ch);
+				if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);
 
 				s++;
 			}
@@ -2958,20 +2973,20 @@
 			{
 				// <? ... ?>
 				s += 2;
-				PUGI__SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
-				if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
+				PUGI_IMPL_SCANFOR(s[0] == '?' && s[1] == '>'); // no need for ENDSWITH because ?> can't terminate proper doctype
+				if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);
 
 				s += 2;
 			}
 			else if (s[0] == '<' && s[1] == '!' && s[2] == '-' && s[3] == '-')
 			{
 				s += 4;
-				PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
-				if (!*s) PUGI__THROW_ERROR(status_bad_doctype, s);
+				PUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && s[2] == '>'); // no need for ENDSWITH because --> can't terminate proper doctype
+				if (!*s) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);
 
 				s += 3;
 			}
-			else PUGI__THROW_ERROR(status_bad_doctype, s);
+			else PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);
 
 			return s;
 		}
@@ -3004,7 +3019,7 @@
 				else s++;
 			}
 
-			PUGI__THROW_ERROR(status_bad_doctype, s);
+			PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);
 		}
 
 		char_t* parse_doctype_group(char_t* s, char_t endch)
@@ -3048,7 +3063,7 @@
 				else s++;
 			}
 
-			if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
+			if (depth != 0 || endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);
 
 			return s;
 		}
@@ -3066,31 +3081,31 @@
 				{
 					++s;
 
-					if (PUGI__OPTSET(parse_comments))
+					if (PUGI_IMPL_OPTSET(parse_comments))
 					{
-						PUGI__PUSHNODE(node_comment); // Append a new node on the tree.
+						PUGI_IMPL_PUSHNODE(node_comment); // Append a new node on the tree.
 						cursor->value = s; // Save the offset.
 					}
 
-					if (PUGI__OPTSET(parse_eol) && PUGI__OPTSET(parse_comments))
+					if (PUGI_IMPL_OPTSET(parse_eol) && PUGI_IMPL_OPTSET(parse_comments))
 					{
 						s = strconv_comment(s, endch);
 
-						if (!s) PUGI__THROW_ERROR(status_bad_comment, cursor->value);
+						if (!s) PUGI_IMPL_THROW_ERROR(status_bad_comment, cursor->value);
 					}
 					else
 					{
 						// Scan for terminating '-->'.
-						PUGI__SCANFOR(s[0] == '-' && s[1] == '-' && PUGI__ENDSWITH(s[2], '>'));
-						PUGI__CHECK_ERROR(status_bad_comment, s);
-
-						if (PUGI__OPTSET(parse_comments))
+						PUGI_IMPL_SCANFOR(s[0] == '-' && s[1] == '-' && PUGI_IMPL_ENDSWITH(s[2], '>'));
+						PUGI_IMPL_CHECK_ERROR(status_bad_comment, s);
+
+						if (PUGI_IMPL_OPTSET(parse_comments))
 							*s = 0; // Zero-terminate this segment at the first terminating '-'.
 
 						s += (s[2] == '>' ? 3 : 2); // Step over the '\0->'.
 					}
 				}
-				else PUGI__THROW_ERROR(status_bad_comment, s);
+				else PUGI_IMPL_THROW_ERROR(status_bad_comment, s);
 			}
 			else if (*s == '[')
 			{
@@ -3099,22 +3114,22 @@
 				{
 					++s;
 
-					if (PUGI__OPTSET(parse_cdata))
+					if (PUGI_IMPL_OPTSET(parse_cdata))
 					{
-						PUGI__PUSHNODE(node_cdata); // Append a new node on the tree.
+						PUGI_IMPL_PUSHNODE(node_cdata); // Append a new node on the tree.
 						cursor->value = s; // Save the offset.
 
-						if (PUGI__OPTSET(parse_eol))
+						if (PUGI_IMPL_OPTSET(parse_eol))
 						{
 							s = strconv_cdata(s, endch);
 
-							if (!s) PUGI__THROW_ERROR(status_bad_cdata, cursor->value);
+							if (!s) PUGI_IMPL_THROW_ERROR(status_bad_cdata, cursor->value);
 						}
 						else
 						{
 							// Scan for terminating ']]>'.
-							PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
-							PUGI__CHECK_ERROR(status_bad_cdata, s);
+							PUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>'));
+							PUGI_IMPL_CHECK_ERROR(status_bad_cdata, s);
 
 							*s++ = 0; // Zero-terminate this segment.
 						}
@@ -3122,21 +3137,21 @@
 					else // Flagged for discard, but we still have to scan for the terminator.
 					{
 						// Scan for terminating ']]>'.
-						PUGI__SCANFOR(s[0] == ']' && s[1] == ']' && PUGI__ENDSWITH(s[2], '>'));
-						PUGI__CHECK_ERROR(status_bad_cdata, s);
+						PUGI_IMPL_SCANFOR(s[0] == ']' && s[1] == ']' && PUGI_IMPL_ENDSWITH(s[2], '>'));
+						PUGI_IMPL_CHECK_ERROR(status_bad_cdata, s);
 
 						++s;
 					}
 
 					s += (s[1] == '>' ? 2 : 1); // Step over the last ']>'.
 				}
-				else PUGI__THROW_ERROR(status_bad_cdata, s);
-			}
-			else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI__ENDSWITH(s[6], 'E'))
+				else PUGI_IMPL_THROW_ERROR(status_bad_cdata, s);
+			}
+			else if (s[0] == 'D' && s[1] == 'O' && s[2] == 'C' && s[3] == 'T' && s[4] == 'Y' && s[5] == 'P' && PUGI_IMPL_ENDSWITH(s[6], 'E'))
 			{
 				s -= 2;
 
-				if (cursor->parent) PUGI__THROW_ERROR(status_bad_doctype, s);
+				if (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_doctype, s);
 
 				char_t* mark = s + 9;
 
@@ -3146,18 +3161,18 @@
 				assert((*s == 0 && endch == '>') || *s == '>');
 				if (*s) *s++ = 0;
 
-				if (PUGI__OPTSET(parse_doctype))
-				{
-					while (PUGI__IS_CHARTYPE(*mark, ct_space)) ++mark;
-
-					PUGI__PUSHNODE(node_doctype);
+				if (PUGI_IMPL_OPTSET(parse_doctype))
+				{
+					while (PUGI_IMPL_IS_CHARTYPE(*mark, ct_space)) ++mark;
+
+					PUGI_IMPL_PUSHNODE(node_doctype);
 
 					cursor->value = mark;
 				}
 			}
-			else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s);
-			else if (*s == 0 && endch == '[') PUGI__THROW_ERROR(status_bad_cdata, s);
-			else PUGI__THROW_ERROR(status_unrecognized_tag, s);
+			else if (*s == 0 && endch == '-') PUGI_IMPL_THROW_ERROR(status_bad_comment, s);
+			else if (*s == 0 && endch == '[') PUGI_IMPL_THROW_ERROR(status_bad_cdata, s);
+			else PUGI_IMPL_THROW_ERROR(status_unrecognized_tag, s);
 
 			return s;
 		}
@@ -3174,50 +3189,50 @@
 			// read PI target
 			char_t* target = s;
 
-			if (!PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_pi, s);
-
-			PUGI__SCANWHILE(PUGI__IS_CHARTYPE(*s, ct_symbol));
-			PUGI__CHECK_ERROR(status_bad_pi, s);
+			if (!PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
+
+			PUGI_IMPL_SCANWHILE(PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol));
+			PUGI_IMPL_CHECK_ERROR(status_bad_pi, s);
 
 			// determine node type; stricmp / strcasecmp is not portable
 			bool declaration = (target[0] | ' ') == 'x' && (target[1] | ' ') == 'm' && (target[2] | ' ') == 'l' && target + 3 == s;
 
-			if (declaration ? PUGI__OPTSET(parse_declaration) : PUGI__OPTSET(parse_pi))
+			if (declaration ? PUGI_IMPL_OPTSET(parse_declaration) : PUGI_IMPL_OPTSET(parse_pi))
 			{
 				if (declaration)
 				{
 					// disallow non top-level declarations
-					if (cursor->parent) PUGI__THROW_ERROR(status_bad_pi, s);
-
-					PUGI__PUSHNODE(node_declaration);
+					if (cursor->parent) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
+
+					PUGI_IMPL_PUSHNODE(node_declaration);
 				}
 				else
 				{
-					PUGI__PUSHNODE(node_pi);
+					PUGI_IMPL_PUSHNODE(node_pi);
 				}
 
 				cursor->name = target;
 
-				PUGI__ENDSEG();
+				PUGI_IMPL_ENDSEG();
 
 				// parse value/attributes
 				if (ch == '?')
 				{
 					// empty node
-					if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_pi, s);
+					if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
 					s += (*s == '>');
 
-					PUGI__POPNODE();
-				}
-				else if (PUGI__IS_CHARTYPE(ch, ct_space))
-				{
-					PUGI__SKIPWS();
+					PUGI_IMPL_POPNODE();
+				}
+				else if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))
+				{
+					PUGI_IMPL_SKIPWS();
 
 					// scan for tag end
 					char_t* value = s;
 
-					PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
-					PUGI__CHECK_ERROR(status_bad_pi, s);
+					PUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>'));
+					PUGI_IMPL_CHECK_ERROR(status_bad_pi, s);
 
 					if (declaration)
 					{
@@ -3232,20 +3247,20 @@
 						// store value and step over >
 						cursor->value = value;
 
-						PUGI__POPNODE();
-
-						PUGI__ENDSEG();
+						PUGI_IMPL_POPNODE();
+
+						PUGI_IMPL_ENDSEG();
 
 						s += (*s == '>');
 					}
 				}
-				else PUGI__THROW_ERROR(status_bad_pi, s);
+				else PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
 			}
 			else
 			{
 				// scan for tag end
-				PUGI__SCANFOR(s[0] == '?' && PUGI__ENDSWITH(s[1], '>'));
-				PUGI__CHECK_ERROR(status_bad_pi, s);
+				PUGI_IMPL_SCANFOR(s[0] == '?' && PUGI_IMPL_ENDSWITH(s[1], '>'));
+				PUGI_IMPL_CHECK_ERROR(status_bad_pi, s);
 
 				s += (s[1] == '>' ? 2 : 1);
 			}
@@ -3264,6 +3279,7 @@
 			char_t ch = 0;
 			xml_node_struct* cursor = root;
 			char_t* mark = s;
+			char_t* merged_pcdata = s;
 
 			while (*s != 0)
 			{
@@ -3272,39 +3288,39 @@
 					++s;
 
 				LOC_TAG:
-					if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
+					if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // '<#...'
 					{
-						PUGI__PUSHNODE(node_element); // Append a new node to the tree.
+						PUGI_IMPL_PUSHNODE(node_element); // Append a new node to the tree.
 
 						cursor->name = s;
 
-						PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
-						PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
+						PUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
+						PUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over.
 
 						if (ch == '>')
 						{
 							// end of tag
 						}
-						else if (PUGI__IS_CHARTYPE(ch, ct_space))
+						else if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))
 						{
 						LOC_ATTRIBUTES:
 							while (true)
 							{
-								PUGI__SKIPWS(); // Eat any whitespace.
-
-								if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
+								PUGI_IMPL_SKIPWS(); // Eat any whitespace.
+
+								if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) // <... #...
 								{
 									xml_attribute_struct* a = append_new_attribute(cursor, *alloc); // Make space for this attribute.
-									if (!a) PUGI__THROW_ERROR(status_out_of_memory, s);
+									if (!a) PUGI_IMPL_THROW_ERROR(status_out_of_memory, s);
 
 									a->name = s; // Save the offset.
 
-									PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
-									PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
-
-									if (PUGI__IS_CHARTYPE(ch, ct_space))
+									PUGI_IMPL_SCANWHILE_UNROLL(PUGI_IMPL_IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
+									PUGI_IMPL_ENDSEG(); // Save char in 'ch', terminate & step over.
+
+									if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))
 									{
-										PUGI__SKIPWS(); // Eat any whitespace.
+										PUGI_IMPL_SKIPWS(); // Eat any whitespace.
 
 										ch = *s;
 										++s;
@@ -3312,7 +3328,7 @@
 
 									if (ch == '=') // '<... #=...'
 									{
-										PUGI__SKIPWS(); // Eat any whitespace.
+										PUGI_IMPL_SKIPWS(); // Eat any whitespace.
 
 										if (*s == '"' || *s == '\'') // '<... #="...'
 										{
@@ -3322,16 +3338,16 @@
 
 											s = strconv_attribute(s, ch);
 
-											if (!s) PUGI__THROW_ERROR(status_bad_attribute, a->value);
+											if (!s) PUGI_IMPL_THROW_ERROR(status_bad_attribute, a->value);
 
 											// After this line the loop continues from the start;
 											// Whitespaces, / and > are ok, symbols and EOF are wrong,
 											// everything else will be detected
-											if (PUGI__IS_CHARTYPE(*s, ct_start_symbol)) PUGI__THROW_ERROR(status_bad_attribute, s);
+											if (PUGI_IMPL_IS_CHARTYPE(*s, ct_start_symbol)) PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);
 										}
-										else PUGI__THROW_ERROR(status_bad_attribute, s);
+										else PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);
 									}
-									else PUGI__THROW_ERROR(status_bad_attribute, s);
+									else PUGI_IMPL_THROW_ERROR(status_bad_attribute, s);
 								}
 								else if (*s == '/')
 								{
@@ -3339,16 +3355,16 @@
 
 									if (*s == '>')
 									{
-										PUGI__POPNODE();
+										PUGI_IMPL_POPNODE();
 										s++;
 										break;
 									}
 									else if (*s == 0 && endch == '>')
 									{
-										PUGI__POPNODE();
+										PUGI_IMPL_POPNODE();
 										break;
 									}
-									else PUGI__THROW_ERROR(status_bad_start_element, s);
+									else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
 								}
 								else if (*s == '>')
 								{
@@ -3360,16 +3376,16 @@
 								{
 									break;
 								}
-								else PUGI__THROW_ERROR(status_bad_start_element, s);
+								else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
 							}
 
 							// !!!
 						}
 						else if (ch == '/') // '<#.../'
 						{
-							if (!PUGI__ENDSWITH(*s, '>')) PUGI__THROW_ERROR(status_bad_start_element, s);
-
-							PUGI__POPNODE(); // Pop.
+							if (!PUGI_IMPL_ENDSWITH(*s, '>')) PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
+
+							PUGI_IMPL_POPNODE(); // Pop.
 
 							s += (*s == '>');
 						}
@@ -3378,9 +3394,9 @@
 							// we stepped over null terminator, backtrack & handle closing tag
 							--s;
 
-							if (endch != '>') PUGI__THROW_ERROR(status_bad_start_element, s);
+							if (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
 						}
-						else PUGI__THROW_ERROR(status_bad_start_element, s);
+						else PUGI_IMPL_THROW_ERROR(status_bad_start_element, s);
 					}
 					else if (*s == '/')
 					{
@@ -3389,30 +3405,30 @@
 						mark = s;
 
 						char_t* name = cursor->name;
-						if (!name) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
-
-						while (PUGI__IS_CHARTYPE(*s, ct_symbol))
+						if (!name) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);
+
+						while (PUGI_IMPL_IS_CHARTYPE(*s, ct_symbol))
 						{
-							if (*s++ != *name++) PUGI__THROW_ERROR(status_end_element_mismatch, mark);
+							if (*s++ != *name++) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);
 						}
 
 						if (*name)
 						{
-							if (*s == 0 && name[0] == endch && name[1] == 0) PUGI__THROW_ERROR(status_bad_end_element, s);
-							else PUGI__THROW_ERROR(status_end_element_mismatch, mark);
+							if (*s == 0 && name[0] == endch && name[1] == 0) PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);
+							else PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, mark);
 						}
 
-						PUGI__POPNODE(); // Pop.
-
-						PUGI__SKIPWS();
+						PUGI_IMPL_POPNODE(); // Pop.
+
+						PUGI_IMPL_SKIPWS();
 
 						if (*s == 0)
 						{
-							if (endch != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
+							if (endch != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);
 						}
 						else
 						{
-							if (*s != '>') PUGI__THROW_ERROR(status_bad_end_element, s);
+							if (*s != '>') PUGI_IMPL_THROW_ERROR(status_bad_end_element, s);
 							++s;
 						}
 					}
@@ -3422,62 +3438,79 @@
 						if (!s) return s;
 
 						assert(cursor);
-						if (PUGI__NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES;
+						if (PUGI_IMPL_NODETYPE(cursor) == node_declaration) goto LOC_ATTRIBUTES;
 					}
 					else if (*s == '!') // '<!...'
 					{
 						s = parse_exclamation(s, cursor, optmsk, endch);
 						if (!s) return s;
 					}
-					else if (*s == 0 && endch == '?') PUGI__THROW_ERROR(status_bad_pi, s);
-					else PUGI__THROW_ERROR(status_unrecognized_tag, s);
+					else if (*s == 0 && endch == '?') PUGI_IMPL_THROW_ERROR(status_bad_pi, s);
+					else PUGI_IMPL_THROW_ERROR(status_unrecognized_tag, s);
 				}
 				else
 				{
 					mark = s; // Save this offset while searching for a terminator.
 
-					PUGI__SKIPWS(); // Eat whitespace if no genuine PCDATA here.
+					PUGI_IMPL_SKIPWS(); // Eat whitespace if no genuine PCDATA here.
 
 					if (*s == '<' || !*s)
 					{
 						// We skipped some whitespace characters because otherwise we would take the tag branch instead of PCDATA one
 						assert(mark != s);
 
-						if (!PUGI__OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI__OPTSET(parse_trim_pcdata))
+						if (!PUGI_IMPL_OPTSET(parse_ws_pcdata | parse_ws_pcdata_single) || PUGI_IMPL_OPTSET(parse_trim_pcdata))
 						{
 							continue;
 						}
-						else if (PUGI__OPTSET(parse_ws_pcdata_single))
+						else if (PUGI_IMPL_OPTSET(parse_ws_pcdata_single))
 						{
 							if (s[0] != '<' || s[1] != '/' || cursor->first_child) continue;
 						}
 					}
 
-					if (!PUGI__OPTSET(parse_trim_pcdata))
+					if (!PUGI_IMPL_OPTSET(parse_trim_pcdata))
 						s = mark;
 
-					if (cursor->parent || PUGI__OPTSET(parse_fragment))
+					if (cursor->parent || PUGI_IMPL_OPTSET(parse_fragment))
 					{
-						if (PUGI__OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value)
+						char_t* parsed_pcdata = s;
+
+						s = strconv_pcdata(s);
+
+						if (PUGI_IMPL_OPTSET(parse_embed_pcdata) && cursor->parent && !cursor->first_child && !cursor->value)
+						{
+							cursor->value = parsed_pcdata; // Save the offset.
+						}
+						else if (PUGI_IMPL_OPTSET(parse_merge_pcdata) && cursor->first_child && PUGI_IMPL_NODETYPE(cursor->first_child->prev_sibling_c) == node_pcdata)
 						{
-							cursor->value = s; // Save the offset.
+							assert(merged_pcdata >= cursor->first_child->prev_sibling_c->value);
+
+							// Catch up to the end of last parsed value; only needed for the first fragment.
+							merged_pcdata += strlength(merged_pcdata);
+
+							size_t length = strlength(parsed_pcdata);
+
+							// Must use memmove instead of memcpy as this move may overlap
+							memmove(merged_pcdata, parsed_pcdata, (length + 1) * sizeof(char_t));
+							merged_pcdata += length;
 						}
 						else
 						{
-							PUGI__PUSHNODE(node_pcdata); // Append a new node on the tree.
-
-							cursor->value = s; // Save the offset.
-
-							PUGI__POPNODE(); // Pop since this is a standalone.
+							xml_node_struct* prev_cursor = cursor;
+							PUGI_IMPL_PUSHNODE(node_pcdata); // Append a new node on the tree.
+
+							cursor->value = parsed_pcdata; // Save the offset.
+							merged_pcdata = parsed_pcdata; // Used for parse_merge_pcdata above, cheaper to save unconditionally
+
+							cursor = prev_cursor; // Pop since this is a standalone.
 						}
 
-						s = strconv_pcdata(s);
-
 						if (!*s) break;
 					}
 					else
 					{
-						PUGI__SCANFOR(*s == '<'); // '...<'
+						PUGI_IMPL_SCANFOR(*s == '<'); // '...<'
 						if (!*s) break;
 
 						++s;
@@ -3489,7 +3522,7 @@
 			}
 
 			// check that last tag is closed
-			if (cursor != root) PUGI__THROW_ERROR(status_end_element_mismatch, s);
+			if (cursor != root) PUGI_IMPL_THROW_ERROR(status_end_element_mismatch, s);
 
 			return s;
 		}
@@ -3511,7 +3544,7 @@
 		{
 			while (node)
 			{
-				if (PUGI__NODETYPE(node) == node_element) return true;
+				if (PUGI_IMPL_NODETYPE(node) == node_element) return true;
 
 				node = node->next_sibling;
 			}
@@ -3523,7 +3556,7 @@
 		{
 			// early-out for empty documents
 			if (length == 0)
-				return make_parse_result(PUGI__OPTSET(parse_fragment) ? status_ok : status_no_document_element);
+				return make_parse_result(PUGI_IMPL_OPTSET(parse_fragment) ? status_ok : status_no_document_element);
 
 			// get last child of the root before parsing
 			xml_node_struct* last_root_child = root->first_child ? root->first_child->prev_sibling_c + 0 : 0;
@@ -3551,9 +3584,9 @@
 					return make_parse_result(status_unrecognized_tag, length - 1);
 
 				// check if there are any element nodes parsed
-				xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child+ 0;
-
-				if (!PUGI__OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
+				xml_node_struct* first_root_child_parsed = last_root_child ? last_root_child->next_sibling + 0 : root->first_child + 0;
+
+				if (!PUGI_IMPL_OPTSET(parse_fragment) && !has_element_node_siblings(first_root_child_parsed))
 					return make_parse_result(status_no_document_element, length - 1);
 			}
 			else
@@ -3568,7 +3601,7 @@
 	};
 
 	// Output facilities
-	PUGI__FN xml_encoding get_write_native_encoding()
+	PUGI_IMPL_FN xml_encoding get_write_native_encoding()
 	{
 	#ifdef PUGIXML_WCHAR_MODE
 		return get_wchar_encoding();
@@ -3577,7 +3610,7 @@
 	#endif
 	}
 
-	PUGI__FN xml_encoding get_write_encoding(xml_encoding encoding)
+	PUGI_IMPL_FN xml_encoding get_write_encoding(xml_encoding encoding)
 	{
 		// replace wchar encoding with utf implementation
 		if (encoding == encoding_wchar) return get_wchar_encoding();
@@ -3595,18 +3628,18 @@
 		return encoding_utf8;
 	}
 
-	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)
-	{
-		PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
+	template <typename D, typename T> PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T)
+	{
+		PUGI_IMPL_STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
 
 		typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
 
 		return static_cast<size_t>(end - dest) * sizeof(*dest);
 	}
 
-	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)
-	{
-		PUGI__STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
+	template <typename D, typename T> PUGI_IMPL_FN size_t convert_buffer_output_generic(typename T::value_type dest, const char_t* data, size_t length, D, T, bool opt_swap)
+	{
+		PUGI_IMPL_STATIC_ASSERT(sizeof(char_t) == sizeof(typename D::type));
 
 		typename T::value_type end = D::process(reinterpret_cast<const typename D::type*>(data), length, dest, T());
 
@@ -3620,7 +3653,7 @@
 	}
 
 #ifdef PUGIXML_WCHAR_MODE
-	PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
+	PUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length)
 	{
 		if (length < 1) return 0;
 
@@ -3628,7 +3661,7 @@
 		return (sizeof(wchar_t) == 2 && static_cast<unsigned int>(static_cast<uint16_t>(data[length - 1]) - 0xD800) < 0x400) ? length - 1 : length;
 	}
 
-	PUGI__FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
+	PUGI_IMPL_FN size_t convert_buffer_output(char_t* r_char, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
 	{
 		// only endian-swapping is required
 		if (need_endian_swap_utf(encoding, get_wchar_encoding()))
@@ -3666,7 +3699,7 @@
 		return 0;
 	}
 #else
-	PUGI__FN size_t get_valid_length(const char_t* data, size_t length)
+	PUGI_IMPL_FN size_t get_valid_length(const char_t* data, size_t length)
 	{
 		if (length < 5) return 0;
 
@@ -3682,7 +3715,7 @@
 		return length;
 	}
 
-	PUGI__FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
+	PUGI_IMPL_FN size_t convert_buffer_output(char_t* /* r_char */, uint8_t* r_u8, uint16_t* r_u16, uint32_t* r_u32, const char_t* data, size_t length, xml_encoding encoding)
 	{
 		if (encoding == encoding_utf16_be || encoding == encoding_utf16_le)
 		{
@@ -3714,7 +3747,7 @@
 	public:
 		xml_buffered_writer(xml_writer& writer_, xml_encoding user_encoding): writer(writer_), bufsize(0), encoding(get_write_encoding(user_encoding))
 		{
-			PUGI__STATIC_ASSERT(bufcapacity >= 8);
+			PUGI_IMPL_STATIC_ASSERT(bufcapacity >= 8);
 		}
 
 		size_t flush()
@@ -3920,14 +3953,14 @@
 		xml_encoding encoding;
 	};
 
-	PUGI__FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
+	PUGI_IMPL_FN void text_output_escaped(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
 	{
 		while (*s)
 		{
 			const char_t* prev = s;
 
 			// While *s is a usual symbol
-			PUGI__SCANWHILE_UNROLL(!PUGI__IS_CHARTYPEX(ss, type));
+			PUGI_IMPL_SCANWHILE_UNROLL(!PUGI_IMPL_IS_CHARTYPEX(ss, type));
 
 			writer.write_buffer(prev, static_cast<size_t>(s - prev));
 
@@ -3972,7 +4005,7 @@
 		}
 	}
 
-	PUGI__FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
+	PUGI_IMPL_FN void text_output(xml_buffered_writer& writer, const char_t* s, chartypex_t type, unsigned int flags)
 	{
 		if (flags & format_no_escapes)
 			writer.write_string(s);
@@ -3980,7 +4013,7 @@
 			text_output_escaped(writer, s, type, flags);
 	}
 
-	PUGI__FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s)
+	PUGI_IMPL_FN void text_output_cdata(xml_buffered_writer& writer, const char_t* s)
 	{
 		do
 		{
@@ -4002,7 +4035,7 @@
 		while (*s);
 	}
 
-	PUGI__FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth)
+	PUGI_IMPL_FN void text_output_indent(xml_buffered_writer& writer, const char_t* indent, size_t indent_length, unsigned int depth)
 	{
 		switch (indent_length)
 		{
@@ -4042,7 +4075,7 @@
 		}
 	}
 
-	PUGI__FN void node_output_comment(xml_buffered_writer& writer, const char_t* s)
+	PUGI_IMPL_FN void node_output_comment(xml_buffered_writer& writer, const char_t* s)
 	{
 		writer.write('<', '!', '-', '-');
 
@@ -4067,7 +4100,7 @@
 		writer.write('-', '-', '>');
 	}
 
-	PUGI__FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s)
+	PUGI_IMPL_FN void node_output_pi_value(xml_buffered_writer& writer, const char_t* s)
 	{
 		while (*s)
 		{
@@ -4088,7 +4121,7 @@
 		}
 	}
 
-	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)
+	PUGI_IMPL_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)
 	{
 		const char_t* default_name = PUGIXML_TEXT(":anonymous");
 		const char_t enquotation_char = (flags & format_attribute_single_quote) ? '\'' : '"';
@@ -4116,7 +4149,7 @@
 		}
 	}
 
-	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)
+	PUGI_IMPL_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)
 	{
 		const char_t* default_name = PUGIXML_TEXT(":anonymous");
 		const char_t* name = node->name ? node->name + 0 : default_name;
@@ -4178,7 +4211,7 @@
 		}
 	}
 
-	PUGI__FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node)
+	PUGI_IMPL_FN void node_output_end(xml_buffered_writer& writer, xml_node_struct* node)
 	{
 		const char_t* default_name = PUGIXML_TEXT(":anonymous");
 		const char_t* name = node->name ? node->name + 0 : default_name;
@@ -4188,11 +4221,11 @@
 		writer.write('>');
 	}
 
-	PUGI__FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)
+	PUGI_IMPL_FN void node_output_simple(xml_buffered_writer& writer, xml_node_struct* node, unsigned int flags)
 	{
 		const char_t* default_name = PUGIXML_TEXT(":anonymous");
 
-		switch (PUGI__NODETYPE(node))
+		switch (PUGI_IMPL_NODETYPE(node))
 		{
 			case node_pcdata:
 				text_output(writer, node->value ? node->value + 0 : PUGIXML_TEXT(""), ctx_special_pcdata, flags);
@@ -4250,7 +4283,7 @@
 		indent_indent = 2
 	};
 
-	PUGI__FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth)
+	PUGI_IMPL_FN void node_output(xml_buffered_writer& writer, xml_node_struct* root, const char_t* indent, unsigned int flags, unsigned int depth)
 	{
 		size_t indent_length = ((flags & (format_indent | format_indent_attributes)) && (flags & format_raw) == 0) ? strlength(indent) : 0;
 		unsigned int indent_flags = indent_indent;
@@ -4262,7 +4295,7 @@
 			assert(node);
 
 			// begin writing current node
-			if (PUGI__NODETYPE(node) == node_pcdata || PUGI__NODETYPE(node) == node_cdata)
+			if (PUGI_IMPL_NODETYPE(node) == node_pcdata || PUGI_IMPL_NODETYPE(node) == node_cdata)
 			{
 				node_output_simple(writer, node, flags);
 
@@ -4276,7 +4309,7 @@
 				if ((indent_flags & indent_indent) && indent_length)
 					text_output_indent(writer, indent, indent_length, depth);
 
-				if (PUGI__NODETYPE(node) == node_element)
+				if (PUGI_IMPL_NODETYPE(node) == node_element)
 				{
 					indent_flags = indent_newline | indent_indent;
 
@@ -4291,7 +4324,7 @@
 						continue;
 					}
 				}
-				else if (PUGI__NODETYPE(node) == node_document)
+				else if (PUGI_IMPL_NODETYPE(node) == node_document)
 				{
 					indent_flags = indent_indent;
 
@@ -4321,7 +4354,7 @@
 				node = node->parent;
 
 				// write closing node
-				if (PUGI__NODETYPE(node) == node_element)
+				if (PUGI_IMPL_NODETYPE(node) == node_element)
 				{
 					depth--;
 
@@ -4343,11 +4376,11 @@
 			writer.write('\n');
 	}
 
-	PUGI__FN bool has_declaration(xml_node_struct* node)
+	PUGI_IMPL_FN bool has_declaration(xml_node_struct* node)
 	{
 		for (xml_node_struct* child = node->first_child; child; child = child->next_sibling)
 		{
-			xml_node_type type = PUGI__NODETYPE(child);
+			xml_node_type type = PUGI_IMPL_NODETYPE(child);
 
 			if (type == node_declaration) return true;
 			if (type == node_element) return false;
@@ -4356,7 +4389,7 @@
 		return false;
 	}
 
-	PUGI__FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node)
+	PUGI_IMPL_FN bool is_attribute_of(xml_attribute_struct* attr, xml_node_struct* node)
 	{
 		for (xml_attribute_struct* a = node->first_attribute; a; a = a->next_attribute)
 			if (a == attr)
@@ -4365,12 +4398,12 @@
 		return false;
 	}
 
-	PUGI__FN bool allow_insert_attribute(xml_node_type parent)
+	PUGI_IMPL_FN bool allow_insert_attribute(xml_node_type parent)
 	{
 		return parent == node_element || parent == node_declaration;
 	}
 
-	PUGI__FN bool allow_insert_child(xml_node_type parent, xml_node_type child)
+	PUGI_IMPL_FN bool allow_insert_child(xml_node_type parent, xml_node_type child)
 	{
 		if (parent != node_document && parent != node_element) return false;
 		if (child == node_document || child == node_null) return false;
@@ -4379,7 +4412,7 @@
 		return true;
 	}
 
-	PUGI__FN bool allow_move(xml_node parent, xml_node child)
+	PUGI_IMPL_FN bool allow_move(xml_node parent, xml_node child)
 	{
 		// check that child can be a child of parent
 		if (!allow_insert_child(parent.type(), child.type()))
@@ -4404,9 +4437,9 @@
 	}
 
 	template <typename String, typename Header>
-	PUGI__FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)
-	{
-		assert(!dest && (header & header_mask) == 0);
+	PUGI_IMPL_FN void node_copy_string(String& dest, Header& header, uintptr_t header_mask, char_t* source, Header& source_header, xml_allocator* alloc)
+	{
+		assert(!dest && (header & header_mask) == 0); // copies are performed into fresh nodes
 
 		if (source)
 		{
@@ -4423,7 +4456,7 @@
 		}
 	}
 
-	PUGI__FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc)
+	PUGI_IMPL_FN void node_copy_contents(xml_node_struct* dn, xml_node_struct* sn, xml_allocator* shared_alloc)
 	{
 		node_copy_string(dn->name, dn->header, xml_memory_page_name_allocated_mask, sn->name, sn->header, shared_alloc);
 		node_copy_string(dn->value, dn->header, xml_memory_page_value_allocated_mask, sn->value, sn->header, shared_alloc);
@@ -4440,7 +4473,7 @@
 		}
 	}
 
-	PUGI__FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)
+	PUGI_IMPL_FN void node_copy_tree(xml_node_struct* dn, xml_node_struct* sn)
 	{
 		xml_allocator& alloc = get_allocator(dn);
 		xml_allocator* shared_alloc = (&alloc == &get_allocator(sn)) ? &alloc : 0;
@@ -4458,7 +4491,7 @@
 			// when a tree is copied into one of the descendants, we need to skip that subtree to avoid an infinite loop
 			if (sit != dn)
 			{
-				xml_node_struct* copy = append_new_node(dit, alloc, PUGI__NODETYPE(sit));
+				xml_node_struct* copy = append_new_node(dit, alloc, PUGI_IMPL_NODETYPE(sit));
 
 				if (copy)
 				{
@@ -4494,7 +4527,7 @@
 		assert(!sit || dit == dn->parent);
 	}
 
-	PUGI__FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
+	PUGI_IMPL_FN void node_copy_attribute(xml_attribute_struct* da, xml_attribute_struct* sa)
 	{
 		xml_allocator& alloc = get_allocator(da);
 		xml_allocator* shared_alloc = (&alloc == &get_allocator(sa)) ? &alloc : 0;
@@ -4505,18 +4538,18 @@
 
 	inline bool is_text_node(xml_node_struct* node)
 	{
-		xml_node_type type = PUGI__NODETYPE(node);
+		xml_node_type type = PUGI_IMPL_NODETYPE(node);
 
 		return type == node_pcdata || type == node_cdata;
 	}
 
 	// get value with conversion functions
-	template <typename U> PUGI__FN PUGI__UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv)
+	template <typename U> PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW U string_to_integer(const char_t* value, U minv, U maxv)
 	{
 		U result = 0;
 		const char_t* s = value;
 
-		while (PUGI__IS_CHARTYPE(*s, ct_space))
+		while (PUGI_IMPL_IS_CHARTYPE(*s, ct_space))
 			s++;
 
 		bool negative = (*s == '-');
@@ -4571,7 +4604,7 @@
 
 			size_t digits = static_cast<size_t>(s - start);
 
-			PUGI__STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);
+			PUGI_IMPL_STATIC_ASSERT(sizeof(U) == 8 || sizeof(U) == 4 || sizeof(U) == 2);
 
 			const size_t max_digits10 = sizeof(U) == 8 ? 20 : sizeof(U) == 4 ? 10 : 5;
 			const char_t max_lead = sizeof(U) == 8 ? '1' : sizeof(U) == 4 ? '4' : '6';
@@ -4593,17 +4626,17 @@
 			return (overflow || result > maxv) ? maxv : result;
 	}
 
-	PUGI__FN int get_value_int(const char_t* value)
+	PUGI_IMPL_FN int get_value_int(const char_t* value)
 	{
 		return string_to_integer<unsigned int>(value, static_cast<unsigned int>(INT_MIN), INT_MAX);
 	}
 
-	PUGI__FN unsigned int get_value_uint(const char_t* value)
+	PUGI_IMPL_FN unsigned int get_value_uint(const char_t* value)
 	{
 		return string_to_integer<unsigned int>(value, 0, UINT_MAX);
 	}
 
-	PUGI__FN double get_value_double(const char_t* value)
+	PUGI_IMPL_FN double get_value_double(const char_t* value)
 	{
 	#ifdef PUGIXML_WCHAR_MODE
 		return wcstod(value, 0);
@@ -4612,7 +4645,7 @@
 	#endif
 	}
 
-	PUGI__FN float get_value_float(const char_t* value)
+	PUGI_IMPL_FN float get_value_float(const char_t* value)
 	{
 	#ifdef PUGIXML_WCHAR_MODE
 		return static_cast<float>(wcstod(value, 0));
@@ -4621,7 +4654,7 @@
 	#endif
 	}
 
-	PUGI__FN bool get_value_bool(const char_t* value)
+	PUGI_IMPL_FN bool get_value_bool(const char_t* value)
 	{
 		// only look at first char
 		char_t first = *value;
@@ -4631,18 +4664,18 @@
 	}
 
 #ifdef PUGIXML_HAS_LONG_LONG
-	PUGI__FN long long get_value_llong(const char_t* value)
+	PUGI_IMPL_FN long long get_value_llong(const char_t* value)
 	{
 		return string_to_integer<unsigned long long>(value, static_cast<unsigned long long>(LLONG_MIN), LLONG_MAX);
 	}
 
-	PUGI__FN unsigned long long get_value_ullong(const char_t* value)
+	PUGI_IMPL_FN unsigned long long get_value_ullong(const char_t* value)
 	{
 		return string_to_integer<unsigned long long>(value, 0, ULLONG_MAX);
 	}
 #endif
 
-	template <typename U> PUGI__FN PUGI__UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative)
+	template <typename U> PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW char_t* integer_to_string(char_t* begin, char_t* end, U value, bool negative)
 	{
 		char_t* result = end - 1;
 		U rest = negative ? 0 - value : value;
@@ -4664,7 +4697,7 @@
 
 	// set value with conversion functions
 	template <typename String, typename Header>
-	PUGI__FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf)
+	PUGI_IMPL_FN bool set_value_ascii(String& dest, Header& header, uintptr_t header_mask, char* buf)
 	{
 	#ifdef PUGIXML_WCHAR_MODE
 		char_t wbuf[128];
@@ -4680,7 +4713,7 @@
 	}
 
 	template <typename U, typename String, typename Header>
-	PUGI__FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative)
+	PUGI_IMPL_FN bool set_value_integer(String& dest, Header& header, uintptr_t header_mask, U value, bool negative)
 	{
 		char_t buf[64];
 		char_t* end = buf + sizeof(buf) / sizeof(buf[0]);
@@ -4690,30 +4723,30 @@
 	}
 
 	template <typename String, typename Header>
-	PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision)
+	PUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, float value, int precision)
 	{
 		char buf[128];
-		PUGI__SNPRINTF(buf, "%.*g", precision, double(value));
+		PUGI_IMPL_SNPRINTF(buf, "%.*g", precision, double(value));
 
 		return set_value_ascii(dest, header, header_mask, buf);
 	}
 
 	template <typename String, typename Header>
-	PUGI__FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision)
+	PUGI_IMPL_FN bool set_value_convert(String& dest, Header& header, uintptr_t header_mask, double value, int precision)
 	{
 		char buf[128];
-		PUGI__SNPRINTF(buf, "%.*g", precision, value);
+		PUGI_IMPL_SNPRINTF(buf, "%.*g", precision, value);
 
 		return set_value_ascii(dest, header, header_mask, buf);
 	}
 
 	template <typename String, typename Header>
-	PUGI__FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value)
+	PUGI_IMPL_FN bool set_value_bool(String& dest, Header& header, uintptr_t header_mask, bool value)
 	{
 		return strcpy_insitu(dest, header, header_mask, value ? PUGIXML_TEXT("true") : PUGIXML_TEXT("false"), value ? 4 : 5);
 	}
 
-	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)
+	PUGI_IMPL_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)
 	{
 		// check input buffer
 		if (!contents && size) return make_parse_result(status_io_error);
@@ -4753,9 +4786,19 @@
 	}
 
 	// 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
-	PUGI__FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
-	{
-	#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
+	PUGI_IMPL_FN xml_parse_status get_file_size(FILE* file, size_t& out_result)
+	{
+	#if defined(__linux__) || defined(__APPLE__)
+		// this simultaneously retrieves the file size and file mode (to guard against loading non-files)
+		struct stat st;
+		if (fstat(fileno(file), &st) != 0) return status_io_error;
+
+		// anything that's not a regular file doesn't have a coherent length
+		if (!S_ISREG(st.st_mode)) return status_io_error;
+
+		typedef off_t length_type;
+		length_type length = st.st_size;
+	#elif defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400
 		// there are 64-bit versions of fseek/ftell, let's use them
 		typedef __int64 length_type;
 
@@ -4793,7 +4836,7 @@
 	}
 
 	// This function assumes that buffer has extra sizeof(char_t) writable bytes after size
-	PUGI__FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding)
+	PUGI_IMPL_FN size_t zero_terminate_buffer(void* buffer, size_t size, xml_encoding encoding)
 	{
 		// We only need to zero-terminate if encoding conversion does not do it for us
 	#ifdef PUGIXML_WCHAR_MODE
@@ -4817,7 +4860,7 @@
 		return size;
 	}
 
-	PUGI__FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer)
+	PUGI_IMPL_FN xml_parse_result load_file_impl(xml_document_struct* doc, FILE* file, unsigned int options, xml_encoding encoding, char_t** out_buffer)
 	{
 		if (!file) return make_parse_result(status_file_not_found);
 
@@ -4846,7 +4889,7 @@
 		return load_buffer_impl(doc, doc, contents, zero_terminate_buffer(contents, size, real_encoding), options, real_encoding, true, true, out_buffer);
 	}
 
-	PUGI__FN void close_file(FILE* file)
+	PUGI_IMPL_FN void close_file(FILE* file)
 	{
 		fclose(file);
 	}
@@ -4885,7 +4928,7 @@
 		T data[xml_memory_page_size / sizeof(T)];
 	};
 
-	template <typename T> PUGI__FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
+	template <typename T> PUGI_IMPL_FN xml_parse_status load_stream_data_noseek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
 	{
 		auto_deleter<xml_stream_chunk<T> > chunks(0, xml_stream_chunk<T>::destroy);
 
@@ -4939,7 +4982,7 @@
 		return status_ok;
 	}
 
-	template <typename T> PUGI__FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
+	template <typename T> PUGI_IMPL_FN xml_parse_status load_stream_data_seek(std::basic_istream<T>& stream, void** out_buffer, size_t* out_size)
 	{
 		// get length of remaining data in stream
 		typename std::basic_istream<T>::pos_type pos = stream.tellg();
@@ -4975,7 +5018,7 @@
 		return status_ok;
 	}
 
-	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)
+	template <typename T> PUGI_IMPL_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)
 	{
 		void* buffer = 0;
 		size_t size = 0;
@@ -5001,10 +5044,10 @@
 	}
 #endif
 
-#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))
-	PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
-	{
-#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
+#if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR)))
+	PUGI_IMPL_FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
+	{
+#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400
 		FILE* file = 0;
 		return _wfopen_s(&file, path, mode) == 0 ? file : 0;
 #else
@@ -5012,7 +5055,7 @@
 #endif
 	}
 #else
-	PUGI__FN char* convert_path_heap(const wchar_t* str)
+	PUGI_IMPL_FN char* convert_path_heap(const wchar_t* str)
 	{
 		assert(str);
 
@@ -5033,7 +5076,7 @@
 		return result;
 	}
 
-	PUGI__FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
+	PUGI_IMPL_FN FILE* open_file_wide(const wchar_t* path, const wchar_t* mode)
 	{
 		// there is no standard function to open wide paths, so our best bet is to try utf8 path
 		char* path_utf8 = convert_path_heap(path);
@@ -5053,9 +5096,9 @@
 	}
 #endif
 
-	PUGI__FN FILE* open_file(const char* path, const char* mode)
-	{
-#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
+	PUGI_IMPL_FN FILE* open_file(const char* path, const char* mode)
+	{
+#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400
 		FILE* file = 0;
 		return fopen_s(&file, path, mode) == 0 ? file : 0;
 #else
@@ -5063,7 +5106,7 @@
 #endif
 	}
 
-	PUGI__FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)
+	PUGI_IMPL_FN bool save_file_impl(const xml_document& doc, FILE* file, const char_t* indent, unsigned int flags, xml_encoding encoding)
 	{
 		if (!file) return false;
 
@@ -5088,30 +5131,34 @@
 			node->name = name;
 		}
 	};
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 namespace pugi
 {
-	PUGI__FN xml_writer_file::xml_writer_file(void* file_): file(file_)
-	{
-	}
-
-	PUGI__FN void xml_writer_file::write(const void* data, size_t size)
+	PUGI_IMPL_FN xml_writer::~xml_writer()
+	{
+	}
+
+	PUGI_IMPL_FN xml_writer_file::xml_writer_file(void* file_): file(file_)
+	{
+	}
+
+	PUGI_IMPL_FN void xml_writer_file::write(const void* data, size_t size)
 	{
 		size_t result = fwrite(data, 1, size, static_cast<FILE*>(file));
 		(void)!result; // unfortunately we can't do proper error handling here
 	}
 
 #ifndef PUGIXML_NO_STL
-	PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
-	{
-	}
-
-	PUGI__FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
-	{
-	}
-
-	PUGI__FN void xml_writer_stream::write(const void* data, size_t size)
+	PUGI_IMPL_FN xml_writer_stream::xml_writer_stream(std::basic_ostream<char, std::char_traits<char> >& stream): narrow_stream(&stream), wide_stream(0)
+	{
+	}
+
+	PUGI_IMPL_FN xml_writer_stream::xml_writer_stream(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream): narrow_stream(0), wide_stream(&stream)
+	{
+	}
+
+	PUGI_IMPL_FN void xml_writer_stream::write(const void* data, size_t size)
 	{
 		if (narrow_stream)
 		{
@@ -5128,130 +5175,130 @@
 	}
 #endif
 
-	PUGI__FN xml_tree_walker::xml_tree_walker(): _depth(0)
-	{
-	}
-
-	PUGI__FN xml_tree_walker::~xml_tree_walker()
-	{
-	}
-
-	PUGI__FN int xml_tree_walker::depth() const
+	PUGI_IMPL_FN xml_tree_walker::xml_tree_walker(): _depth(0)
+	{
+	}
+
+	PUGI_IMPL_FN xml_tree_walker::~xml_tree_walker()
+	{
+	}
+
+	PUGI_IMPL_FN int xml_tree_walker::depth() const
 	{
 		return _depth;
 	}
 
-	PUGI__FN bool xml_tree_walker::begin(xml_node&)
+	PUGI_IMPL_FN bool xml_tree_walker::begin(xml_node&)
 	{
 		return true;
 	}
 
-	PUGI__FN bool xml_tree_walker::end(xml_node&)
+	PUGI_IMPL_FN bool xml_tree_walker::end(xml_node&)
 	{
 		return true;
 	}
 
-	PUGI__FN xml_attribute::xml_attribute(): _attr(0)
-	{
-	}
-
-	PUGI__FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
-	{
-	}
-
-	PUGI__FN static void unspecified_bool_xml_attribute(xml_attribute***)
-	{
-	}
-
-	PUGI__FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
+	PUGI_IMPL_FN xml_attribute::xml_attribute(): _attr(0)
+	{
+	}
+
+	PUGI_IMPL_FN xml_attribute::xml_attribute(xml_attribute_struct* attr): _attr(attr)
+	{
+	}
+
+	PUGI_IMPL_FN static void unspecified_bool_xml_attribute(xml_attribute***)
+	{
+	}
+
+	PUGI_IMPL_FN xml_attribute::operator xml_attribute::unspecified_bool_type() const
 	{
 		return _attr ? unspecified_bool_xml_attribute : 0;
 	}
 
-	PUGI__FN bool xml_attribute::operator!() const
+	PUGI_IMPL_FN bool xml_attribute::operator!() const
 	{
 		return !_attr;
 	}
 
-	PUGI__FN bool xml_attribute::operator==(const xml_attribute& r) const
+	PUGI_IMPL_FN bool xml_attribute::operator==(const xml_attribute& r) const
 	{
 		return (_attr == r._attr);
 	}
 
-	PUGI__FN bool xml_attribute::operator!=(const xml_attribute& r) const
+	PUGI_IMPL_FN bool xml_attribute::operator!=(const xml_attribute& r) const
 	{
 		return (_attr != r._attr);
 	}
 
-	PUGI__FN bool xml_attribute::operator<(const xml_attribute& r) const
+	PUGI_IMPL_FN bool xml_attribute::operator<(const xml_attribute& r) const
 	{
 		return (_attr < r._attr);
 	}
 
-	PUGI__FN bool xml_attribute::operator>(const xml_attribute& r) const
+	PUGI_IMPL_FN bool xml_attribute::operator>(const xml_attribute& r) const
 	{
 		return (_attr > r._attr);
 	}
 
-	PUGI__FN bool xml_attribute::operator<=(const xml_attribute& r) const
+	PUGI_IMPL_FN bool xml_attribute::operator<=(const xml_attribute& r) const
 	{
 		return (_attr <= r._attr);
 	}
 
-	PUGI__FN bool xml_attribute::operator>=(const xml_attribute& r) const
+	PUGI_IMPL_FN bool xml_attribute::operator>=(const xml_attribute& r) const
 	{
 		return (_attr >= r._attr);
 	}
 
-	PUGI__FN xml_attribute xml_attribute::next_attribute() const
+	PUGI_IMPL_FN xml_attribute xml_attribute::next_attribute() const
 	{
 		if (!_attr) return xml_attribute();
 		return xml_attribute(_attr->next_attribute);
 	}
 
-	PUGI__FN xml_attribute xml_attribute::previous_attribute() const
+	PUGI_IMPL_FN xml_attribute xml_attribute::previous_attribute() const
 	{
 		if (!_attr) return xml_attribute();
 		xml_attribute_struct* prev = _attr->prev_attribute_c;
 		return prev->next_attribute ? xml_attribute(prev) : xml_attribute();
 	}
 
-	PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const
+	PUGI_IMPL_FN const char_t* xml_attribute::as_string(const char_t* def) const
 	{
 		if (!_attr) return def;
 		const char_t* value = _attr->value;
 		return value ? value : def;
 	}
 
-	PUGI__FN int xml_attribute::as_int(int def) const
+	PUGI_IMPL_FN int xml_attribute::as_int(int def) const
 	{
 		if (!_attr) return def;
 		const char_t* value = _attr->value;
 		return value ? impl::get_value_int(value) : def;
 	}
 
-	PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const
+	PUGI_IMPL_FN unsigned int xml_attribute::as_uint(unsigned int def) const
 	{
 		if (!_attr) return def;
 		const char_t* value = _attr->value;
 		return value ? impl::get_value_uint(value) : def;
 	}
 
-	PUGI__FN double xml_attribute::as_double(double def) const
+	PUGI_IMPL_FN double xml_attribute::as_double(double def) const
 	{
 		if (!_attr) return def;
 		const char_t* value = _attr->value;
 		return value ? impl::get_value_double(value) : def;
 	}
 
-	PUGI__FN float xml_attribute::as_float(float def) const
+	PUGI_IMPL_FN float xml_attribute::as_float(float def) const
 	{
 		if (!_attr) return def;
 		const char_t* value = _attr->value;
 		return value ? impl::get_value_float(value) : def;
 	}
 
-	PUGI__FN bool xml_attribute::as_bool(bool def) const
+	PUGI_IMPL_FN bool xml_attribute::as_bool(bool def) const
 	{
 		if (!_attr) return def;
 		const char_t* value = _attr->value;
@@ -5259,14 +5306,14 @@
 	}
 
 #ifdef PUGIXML_HAS_LONG_LONG
-	PUGI__FN long long xml_attribute::as_llong(long long def) const
+	PUGI_IMPL_FN long long xml_attribute::as_llong(long long def) const
 	{
 		if (!_attr) return def;
 		const char_t* value = _attr->value;
 		return value ? impl::get_value_llong(value) : def;
 	}
 
-	PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
+	PUGI_IMPL_FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const
 	{
 		if (!_attr) return def;
 		const char_t* value = _attr->value;
@@ -5274,175 +5321,182 @@
 	}
 #endif
 
-	PUGI__FN bool xml_attribute::empty() const
+	PUGI_IMPL_FN bool xml_attribute::empty() const
 	{
 		return !_attr;
 	}
 
-	PUGI__FN const char_t* xml_attribute::name() const
+	PUGI_IMPL_FN const char_t* xml_attribute::name() const
 	{
 		if (!_attr) return PUGIXML_TEXT("");
 		const char_t* name = _attr->name;
 		return name ? name : PUGIXML_TEXT("");
 	}
 
-	PUGI__FN const char_t* xml_attribute::value() const
+	PUGI_IMPL_FN const char_t* xml_attribute::value() const
 	{
 		if (!_attr) return PUGIXML_TEXT("");
 		const char_t* value = _attr->value;
 		return value ? value : PUGIXML_TEXT("");
 	}
 
-	PUGI__FN size_t xml_attribute::hash_value() const
+	PUGI_IMPL_FN size_t xml_attribute::hash_value() const
 	{
 		return static_cast<size_t>(reinterpret_cast<uintptr_t>(_attr) / sizeof(xml_attribute_struct));
 	}
 
-	PUGI__FN xml_attribute_struct* xml_attribute::internal_object() const
+	PUGI_IMPL_FN xml_attribute_struct* xml_attribute::internal_object() const
 	{
 		return _attr;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(const char_t* rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(const char_t* rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(int rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(int rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(unsigned int rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned int rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(long rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned long rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(double rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(double rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(float rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(float rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(bool rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
 #ifdef PUGIXML_HAS_LONG_LONG
-	PUGI__FN xml_attribute& xml_attribute::operator=(long long rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(long long rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute::operator=(unsigned long long rhs)
+	PUGI_IMPL_FN xml_attribute& xml_attribute::operator=(unsigned long long rhs)
 	{
 		set_value(rhs);
 		return *this;
 	}
 #endif
 
-	PUGI__FN bool xml_attribute::set_name(const char_t* rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_name(const char_t* rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
 	}
 
-	PUGI__FN bool xml_attribute::set_value(const char_t* rhs, size_t sz)
+	PUGI_IMPL_FN bool xml_attribute::set_name(const char_t* rhs, size_t size)
 	{
 		if (!_attr) return false;
 
-		return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, sz);
-	}
-
-	PUGI__FN bool xml_attribute::set_value(const char_t* rhs)
+		return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, size);
+	}
+
+	PUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
 	}
 
-	PUGI__FN bool xml_attribute::set_value(int rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(const char_t* rhs, size_t size)
+	{
+		if (!_attr) return false;
+
+		return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, size);
+	}
+
+	PUGI_IMPL_FN bool xml_attribute::set_value(int rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(unsigned int rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(unsigned int rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_integer<unsigned int>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(long rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(long rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(unsigned long rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(unsigned long rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_integer<unsigned long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, false);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(double rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(double rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(double rhs, int precision)
+	PUGI_IMPL_FN bool xml_attribute::set_value(double rhs, int precision)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(float rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(float rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(float rhs, int precision)
+	PUGI_IMPL_FN bool xml_attribute::set_value(float rhs, int precision)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, precision);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(bool rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(bool rhs)
 	{
 		if (!_attr) return false;
 
@@ -5450,14 +5504,14 @@
 	}
 
 #ifdef PUGIXML_HAS_LONG_LONG
-	PUGI__FN bool xml_attribute::set_value(long long rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(long long rhs)
 	{
 		if (!_attr) return false;
 
 		return impl::set_value_integer<unsigned long long>(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0);
 	}
 
-	PUGI__FN bool xml_attribute::set_value(unsigned long long rhs)
+	PUGI_IMPL_FN bool xml_attribute::set_value(unsigned long long rhs)
 	{
 		if (!_attr) return false;
 
@@ -5466,129 +5520,129 @@
 #endif
 
 #ifdef __BORLANDC__
-	PUGI__FN bool operator&&(const xml_attribute& lhs, bool rhs)
+	PUGI_IMPL_FN bool operator&&(const xml_attribute& lhs, bool rhs)
 	{
 		return (bool)lhs && rhs;
 	}
 
-	PUGI__FN bool operator||(const xml_attribute& lhs, bool rhs)
+	PUGI_IMPL_FN bool operator||(const xml_attribute& lhs, bool rhs)
 	{
 		return (bool)lhs || rhs;
 	}
 #endif
 
-	PUGI__FN xml_node::xml_node(): _root(0)
-	{
-	}
-
-	PUGI__FN xml_node::xml_node(xml_node_struct* p): _root(p)
-	{
-	}
-
-	PUGI__FN static void unspecified_bool_xml_node(xml_node***)
-	{
-	}
-
-	PUGI__FN xml_node::operator xml_node::unspecified_bool_type() const
+	PUGI_IMPL_FN xml_node::xml_node(): _root(0)
+	{
+	}
+
+	PUGI_IMPL_FN xml_node::xml_node(xml_node_struct* p): _root(p)
+	{
+	}
+
+	PUGI_IMPL_FN static void unspecified_bool_xml_node(xml_node***)
+	{
+	}
+
+	PUGI_IMPL_FN xml_node::operator xml_node::unspecified_bool_type() const
 	{
 		return _root ? unspecified_bool_xml_node : 0;
 	}
 
-	PUGI__FN bool xml_node::operator!() const
+	PUGI_IMPL_FN bool xml_node::operator!() const
 	{
 		return !_root;
 	}
 
-	PUGI__FN xml_node::iterator xml_node::begin() const
+	PUGI_IMPL_FN xml_node::iterator xml_node::begin() const
 	{
 		return iterator(_root ? _root->first_child + 0 : 0, _root);
 	}
 
-	PUGI__FN xml_node::iterator xml_node::end() const
+	PUGI_IMPL_FN xml_node::iterator xml_node::end() const
 	{
 		return iterator(0, _root);
 	}
 
-	PUGI__FN xml_node::attribute_iterator xml_node::attributes_begin() const
+	PUGI_IMPL_FN xml_node::attribute_iterator xml_node::attributes_begin() const
 	{
 		return attribute_iterator(_root ? _root->first_attribute + 0 : 0, _root);
 	}
 
-	PUGI__FN xml_node::attribute_iterator xml_node::attributes_end() const
+	PUGI_IMPL_FN xml_node::attribute_iterator xml_node::attributes_end() const
 	{
 		return attribute_iterator(0, _root);
 	}
 
-	PUGI__FN xml_object_range<xml_node_iterator> xml_node::children() const
+	PUGI_IMPL_FN xml_object_range<xml_node_iterator> xml_node::children() const
 	{
 		return xml_object_range<xml_node_iterator>(begin(), end());
 	}
 
-	PUGI__FN xml_object_range<xml_named_node_iterator> xml_node::children(const char_t* name_) const
+	PUGI_IMPL_FN xml_object_range<xml_named_node_iterator> xml_node::children(const char_t* name_) const
 	{
 		return xml_object_range<xml_named_node_iterator>(xml_named_node_iterator(child(name_)._root, _root, name_), xml_named_node_iterator(0, _root, name_));
 	}
 
-	PUGI__FN xml_object_range<xml_attribute_iterator> xml_node::attributes() const
+	PUGI_IMPL_FN xml_object_range<xml_attribute_iterator> xml_node::attributes() const
 	{
 		return xml_object_range<xml_attribute_iterator>(attributes_begin(), attributes_end());
 	}
 
-	PUGI__FN bool xml_node::operator==(const xml_node& r) const
+	PUGI_IMPL_FN bool xml_node::operator==(const xml_node& r) const
 	{
 		return (_root == r._root);
 	}
 
-	PUGI__FN bool xml_node::operator!=(const xml_node& r) const
+	PUGI_IMPL_FN bool xml_node::operator!=(const xml_node& r) const
 	{
 		return (_root != r._root);
 	}
 
-	PUGI__FN bool xml_node::operator<(const xml_node& r) const
+	PUGI_IMPL_FN bool xml_node::operator<(const xml_node& r) const
 	{
 		return (_root < r._root);
 	}
 
-	PUGI__FN bool xml_node::operator>(const xml_node& r) const
+	PUGI_IMPL_FN bool xml_node::operator>(const xml_node& r) const
 	{
 		return (_root > r._root);
 	}
 
-	PUGI__FN bool xml_node::operator<=(const xml_node& r) const
+	PUGI_IMPL_FN bool xml_node::operator<=(const xml_node& r) const
 	{
 		return (_root <= r._root);
 	}
 
-	PUGI__FN bool xml_node::operator>=(const xml_node& r) const
+	PUGI_IMPL_FN bool xml_node::operator>=(const xml_node& r) const
 	{
 		return (_root >= r._root);
 	}
 
-	PUGI__FN bool xml_node::empty() const
+	PUGI_IMPL_FN bool xml_node::empty() const
 	{
 		return !_root;
 	}
 
-	PUGI__FN const char_t* xml_node::name() const
+	PUGI_IMPL_FN const char_t* xml_node::name() const
 	{
 		if (!_root) return PUGIXML_TEXT("");
 		const char_t* name = _root->name;
 		return name ? name : PUGIXML_TEXT("");
 	}
 
-	PUGI__FN xml_node_type xml_node::type() const
-	{
-		return _root ? PUGI__NODETYPE(_root) : node_null;
-	}
-
-	PUGI__FN const char_t* xml_node::value() const
+	PUGI_IMPL_FN xml_node_type xml_node::type() const
+	{
+		return _root ? PUGI_IMPL_NODETYPE(_root) : node_null;
+	}
+
+	PUGI_IMPL_FN const char_t* xml_node::value() const
 	{
 		if (!_root) return PUGIXML_TEXT("");
 		const char_t* value = _root->value;
 		return value ? value : PUGIXML_TEXT("");
 	}
 
-	PUGI__FN xml_node xml_node::child(const char_t* name_) const
+	PUGI_IMPL_FN xml_node xml_node::child(const char_t* name_) const
 	{
 		if (!_root) return xml_node();
 
@@ -5602,7 +5656,7 @@
 		return xml_node();
 	}
 
-	PUGI__FN xml_attribute xml_node::attribute(const char_t* name_) const
+	PUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_) const
 	{
 		if (!_root) return xml_attribute();
 
@@ -5616,7 +5670,7 @@
 		return xml_attribute();
 	}
 
-	PUGI__FN xml_node xml_node::next_sibling(const char_t* name_) const
+	PUGI_IMPL_FN xml_node xml_node::next_sibling(const char_t* name_) const
 	{
 		if (!_root) return xml_node();
 
@@ -5630,12 +5684,12 @@
 		return xml_node();
 	}
 
-	PUGI__FN xml_node xml_node::next_sibling() const
+	PUGI_IMPL_FN xml_node xml_node::next_sibling() const
 	{
 		return _root ? xml_node(_root->next_sibling) : xml_node();
 	}
 
-	PUGI__FN xml_node xml_node::previous_sibling(const char_t* name_) const
+	PUGI_IMPL_FN xml_node xml_node::previous_sibling(const char_t* name_) const
 	{
 		if (!_root) return xml_node();
 
@@ -5649,7 +5703,7 @@
 		return xml_node();
 	}
 
-	PUGI__FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const
+	PUGI_IMPL_FN xml_attribute xml_node::attribute(const char_t* name_, xml_attribute& hint_) const
 	{
 		xml_attribute_struct* hint = hint_._attr;
 
@@ -5688,34 +5742,34 @@
 		return xml_attribute();
 	}
 
-	PUGI__FN xml_node xml_node::previous_sibling() const
+	PUGI_IMPL_FN xml_node xml_node::previous_sibling() const
 	{
 		if (!_root) return xml_node();
 		xml_node_struct* prev = _root->prev_sibling_c;
 		return prev->next_sibling ? xml_node(prev) : xml_node();
 	}
 
-	PUGI__FN xml_node xml_node::parent() const
+	PUGI_IMPL_FN xml_node xml_node::parent() const
 	{
 		return _root ? xml_node(_root->parent) : xml_node();
 	}
 
-	PUGI__FN xml_node xml_node::root() const
+	PUGI_IMPL_FN xml_node xml_node::root() const
 	{
 		return _root ? xml_node(&impl::get_document(_root)) : xml_node();
 	}
 
-	PUGI__FN xml_text xml_node::text() const
+	PUGI_IMPL_FN xml_text xml_node::text() const
 	{
 		return xml_text(_root);
 	}
 
-	PUGI__FN const char_t* xml_node::child_value() const
+	PUGI_IMPL_FN const char_t* xml_node::child_value() const
 	{
 		if (!_root) return PUGIXML_TEXT("");
 
 		// element nodes can have value if parse_embed_pcdata was used
-		if (PUGI__NODETYPE(_root) == node_element && _root->value)
+		if (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value)
 			return _root->value;
 
 		for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
@@ -5728,40 +5782,40 @@
 		return PUGIXML_TEXT("");
 	}
 
-	PUGI__FN const char_t* xml_node::child_value(const char_t* name_) const
+	PUGI_IMPL_FN const char_t* xml_node::child_value(const char_t* name_) const
 	{
 		return child(name_).child_value();
 	}
 
-	PUGI__FN xml_attribute xml_node::first_attribute() const
+	PUGI_IMPL_FN xml_attribute xml_node::first_attribute() const
 	{
 		if (!_root) return xml_attribute();
 		return xml_attribute(_root->first_attribute);
 	}
 
-	PUGI__FN xml_attribute xml_node::last_attribute() const
+	PUGI_IMPL_FN xml_attribute xml_node::last_attribute() const
 	{
 		if (!_root) return xml_attribute();
 		xml_attribute_struct* first = _root->first_attribute;
 		return first ? xml_attribute(first->prev_attribute_c) : xml_attribute();
 	}
 
-	PUGI__FN xml_node xml_node::first_child() const
+	PUGI_IMPL_FN xml_node xml_node::first_child() const
 	{
 		if (!_root) return xml_node();
 		return xml_node(_root->first_child);
 	}
 
-	PUGI__FN xml_node xml_node::last_child() const
+	PUGI_IMPL_FN xml_node xml_node::last_child() const
 	{
 		if (!_root) return xml_node();
 		xml_node_struct* first = _root->first_child;
 		return first ? xml_node(first->prev_sibling_c) : xml_node();
 	}
 
-	PUGI__FN bool xml_node::set_name(const char_t* rhs)
-	{
-		xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
+	PUGI_IMPL_FN bool xml_node::set_name(const char_t* rhs)
+	{
+		xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;
 
 		if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
 			return false;
@@ -5769,19 +5823,19 @@
 		return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs));
 	}
 
-	PUGI__FN bool xml_node::set_value(const char_t* rhs, size_t sz)
-	{
-		xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
-
-		if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
+	PUGI_IMPL_FN bool xml_node::set_name(const char_t* rhs, size_t size)
+	{
+		xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;
+
+		if (type_ != node_element && type_ != node_pi && type_ != node_declaration)
 			return false;
 
-		return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, sz);
-	}
-
-	PUGI__FN bool xml_node::set_value(const char_t* rhs)
-	{
-		xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null;
+		return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, size);
+	}
+
+	PUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs)
+	{
+		xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;
 
 		if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
 			return false;
@@ -5789,7 +5843,17 @@
 		return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs));
 	}
 
-	PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_)
+	PUGI_IMPL_FN bool xml_node::set_value(const char_t* rhs, size_t size)
+	{
+		xml_node_type type_ = _root ? PUGI_IMPL_NODETYPE(_root) : node_null;
+
+		if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype)
+			return false;
+
+		return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, size);
+	}
+
+	PUGI_IMPL_FN xml_attribute xml_node::append_attribute(const char_t* name_)
 	{
 		if (!impl::allow_insert_attribute(type())) return xml_attribute();
 
@@ -5806,7 +5870,7 @@
 		return a;
 	}
 
-	PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_)
+	PUGI_IMPL_FN xml_attribute xml_node::prepend_attribute(const char_t* name_)
 	{
 		if (!impl::allow_insert_attribute(type())) return xml_attribute();
 
@@ -5823,7 +5887,7 @@
 		return a;
 	}
 
-	PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr)
+	PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr)
 	{
 		if (!impl::allow_insert_attribute(type())) return xml_attribute();
 		if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
@@ -5841,7 +5905,7 @@
 		return a;
 	}
 
-	PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr)
+	PUGI_IMPL_FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr)
 	{
 		if (!impl::allow_insert_attribute(type())) return xml_attribute();
 		if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
@@ -5859,7 +5923,7 @@
 		return a;
 	}
 
-	PUGI__FN xml_attribute xml_node::append_copy(const xml_attribute& proto)
+	PUGI_IMPL_FN xml_attribute xml_node::append_copy(const xml_attribute& proto)
 	{
 		if (!proto) return xml_attribute();
 		if (!impl::allow_insert_attribute(type())) return xml_attribute();
@@ -5876,7 +5940,7 @@
 		return a;
 	}
 
-	PUGI__FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto)
+	PUGI_IMPL_FN xml_attribute xml_node::prepend_copy(const xml_attribute& proto)
 	{
 		if (!proto) return xml_attribute();
 		if (!impl::allow_insert_attribute(type())) return xml_attribute();
@@ -5893,7 +5957,7 @@
 		return a;
 	}
 
-	PUGI__FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr)
+	PUGI_IMPL_FN xml_attribute xml_node::insert_copy_after(const xml_attribute& proto, const xml_attribute& attr)
 	{
 		if (!proto) return xml_attribute();
 		if (!impl::allow_insert_attribute(type())) return xml_attribute();
@@ -5911,7 +5975,7 @@
 		return a;
 	}
 
-	PUGI__FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr)
+	PUGI_IMPL_FN xml_attribute xml_node::insert_copy_before(const xml_attribute& proto, const xml_attribute& attr)
 	{
 		if (!proto) return xml_attribute();
 		if (!impl::allow_insert_attribute(type())) return xml_attribute();
@@ -5929,7 +5993,7 @@
 		return a;
 	}
 
-	PUGI__FN xml_node xml_node::append_child(xml_node_type type_)
+	PUGI_IMPL_FN xml_node xml_node::append_child(xml_node_type type_)
 	{
 		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 
@@ -5946,7 +6010,7 @@
 		return n;
 	}
 
-	PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_)
+	PUGI_IMPL_FN xml_node xml_node::prepend_child(xml_node_type type_)
 	{
 		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 
@@ -5963,7 +6027,7 @@
 		return n;
 	}
 
-	PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node)
+	PUGI_IMPL_FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node)
 	{
 		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 		if (!node._root || node._root->parent != _root) return xml_node();
@@ -5981,7 +6045,7 @@
 		return n;
 	}
 
-	PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node)
+	PUGI_IMPL_FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node)
 	{
 		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 		if (!node._root || node._root->parent != _root) return xml_node();
@@ -5999,7 +6063,7 @@
 		return n;
 	}
 
-	PUGI__FN xml_node xml_node::append_child(const char_t* name_)
+	PUGI_IMPL_FN xml_node xml_node::append_child(const char_t* name_)
 	{
 		xml_node result = append_child(node_element);
 
@@ -6008,7 +6072,7 @@
 		return result;
 	}
 
-	PUGI__FN xml_node xml_node::prepend_child(const char_t* name_)
+	PUGI_IMPL_FN xml_node xml_node::prepend_child(const char_t* name_)
 	{
 		xml_node result = prepend_child(node_element);
 
@@ -6017,7 +6081,7 @@
 		return result;
 	}
 
-	PUGI__FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node)
+	PUGI_IMPL_FN xml_node xml_node::insert_child_after(const char_t* name_, const xml_node& node)
 	{
 		xml_node result = insert_child_after(node_element, node);
 
@@ -6026,7 +6090,7 @@
 		return result;
 	}
 
-	PUGI__FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node)
+	PUGI_IMPL_FN xml_node xml_node::insert_child_before(const char_t* name_, const xml_node& node)
 	{
 		xml_node result = insert_child_before(node_element, node);
 
@@ -6035,7 +6099,7 @@
 		return result;
 	}
 
-	PUGI__FN xml_node xml_node::append_copy(const xml_node& proto)
+	PUGI_IMPL_FN xml_node xml_node::append_copy(const xml_node& proto)
 	{
 		xml_node_type type_ = proto.type();
 		if (!impl::allow_insert_child(type(), type_)) return xml_node();
@@ -6052,7 +6116,7 @@
 		return n;
 	}
 
-	PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto)
+	PUGI_IMPL_FN xml_node xml_node::prepend_copy(const xml_node& proto)
 	{
 		xml_node_type type_ = proto.type();
 		if (!impl::allow_insert_child(type(), type_)) return xml_node();
@@ -6069,7 +6133,7 @@
 		return n;
 	}
 
-	PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)
+	PUGI_IMPL_FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)
 	{
 		xml_node_type type_ = proto.type();
 		if (!impl::allow_insert_child(type(), type_)) return xml_node();
@@ -6087,7 +6151,7 @@
 		return n;
 	}
 
-	PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)
+	PUGI_IMPL_FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)
 	{
 		xml_node_type type_ = proto.type();
 		if (!impl::allow_insert_child(type(), type_)) return xml_node();
@@ -6105,7 +6169,7 @@
 		return n;
 	}
 
-	PUGI__FN xml_node xml_node::append_move(const xml_node& moved)
+	PUGI_IMPL_FN xml_node xml_node::append_move(const xml_node& moved)
 	{
 		if (!impl::allow_move(*this, moved)) return xml_node();
 
@@ -6121,7 +6185,7 @@
 		return moved;
 	}
 
-	PUGI__FN xml_node xml_node::prepend_move(const xml_node& moved)
+	PUGI_IMPL_FN xml_node xml_node::prepend_move(const xml_node& moved)
 	{
 		if (!impl::allow_move(*this, moved)) return xml_node();
 
@@ -6137,7 +6201,7 @@
 		return moved;
 	}
 
-	PUGI__FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node)
+	PUGI_IMPL_FN xml_node xml_node::insert_move_after(const xml_node& moved, const xml_node& node)
 	{
 		if (!impl::allow_move(*this, moved)) return xml_node();
 		if (!node._root || node._root->parent != _root) return xml_node();
@@ -6155,7 +6219,7 @@
 		return moved;
 	}
 
-	PUGI__FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node)
+	PUGI_IMPL_FN xml_node xml_node::insert_move_before(const xml_node& moved, const xml_node& node)
 	{
 		if (!impl::allow_move(*this, moved)) return xml_node();
 		if (!node._root || node._root->parent != _root) return xml_node();
@@ -6173,12 +6237,12 @@
 		return moved;
 	}
 
-	PUGI__FN bool xml_node::remove_attribute(const char_t* name_)
+	PUGI_IMPL_FN bool xml_node::remove_attribute(const char_t* name_)
 	{
 		return remove_attribute(attribute(name_));
 	}
 
-	PUGI__FN bool xml_node::remove_attribute(const xml_attribute& a)
+	PUGI_IMPL_FN bool xml_node::remove_attribute(const xml_attribute& a)
 	{
 		if (!_root || !a._attr) return false;
 		if (!impl::is_attribute_of(a._attr, _root)) return false;
@@ -6192,7 +6256,7 @@
 		return true;
 	}
 
-	PUGI__FN bool xml_node::remove_attributes()
+	PUGI_IMPL_FN bool xml_node::remove_attributes()
 	{
 		if (!_root) return false;
 
@@ -6213,12 +6277,12 @@
 		return true;
 	}
 
-	PUGI__FN bool xml_node::remove_child(const char_t* name_)
+	PUGI_IMPL_FN bool xml_node::remove_child(const char_t* name_)
 	{
 		return remove_child(child(name_));
 	}
 
-	PUGI__FN bool xml_node::remove_child(const xml_node& n)
+	PUGI_IMPL_FN bool xml_node::remove_child(const xml_node& n)
 	{
 		if (!_root || !n._root || n._root->parent != _root) return false;
 
@@ -6231,7 +6295,7 @@
 		return true;
 	}
 
-	PUGI__FN bool xml_node::remove_children()
+	PUGI_IMPL_FN bool xml_node::remove_children()
 	{
 		if (!_root) return false;
 
@@ -6252,11 +6316,14 @@
 		return true;
 	}
 
-	PUGI__FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
+	PUGI_IMPL_FN xml_parse_result xml_node::append_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
 	{
 		// append_buffer is only valid for elements/documents
 		if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root);
 
+		// append buffer can not merge PCDATA into existing PCDATA nodes
+		if ((options & parse_merge_pcdata) != 0 && last_child().type() == node_pcdata) return impl::make_parse_result(status_append_invalid_root);
+
 		// get document node
 		impl::xml_document_struct* doc = &impl::get_document(_root);
 
@@ -6287,7 +6354,7 @@
 		return impl::load_buffer_impl(doc, _root, const_cast<void*>(contents), size, options, encoding, false, false, &extra->buffer);
 	}
 
-	PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const
+	PUGI_IMPL_FN xml_node xml_node::find_child_by_attribute(const char_t* name_, const char_t* attr_name, const char_t* attr_value) const
 	{
 		if (!_root) return xml_node();
 
@@ -6312,7 +6379,7 @@
 		return xml_node();
 	}
 
-	PUGI__FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
+	PUGI_IMPL_FN xml_node xml_node::find_child_by_attribute(const char_t* attr_name, const char_t* attr_value) const
 	{
 		if (!_root) return xml_node();
 
@@ -6332,7 +6399,7 @@
 	}
 
 #ifndef PUGIXML_NO_STL
-	PUGI__FN string_t xml_node::path(char_t delimiter) const
+	PUGI_IMPL_FN string_t xml_node::path(char_t delimiter) const
 	{
 		if (!_root) return string_t();
 
@@ -6369,7 +6436,7 @@
 	}
 #endif
 
-	PUGI__FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const
+	PUGI_IMPL_FN xml_node xml_node::first_element_by_path(const char_t* path_, char_t delimiter) const
 	{
 		xml_node context = path_[0] == delimiter ? root() : *this;
 
@@ -6410,7 +6477,7 @@
 		}
 	}
 
-	PUGI__FN bool xml_node::traverse(xml_tree_walker& walker)
+	PUGI_IMPL_FN bool xml_node::traverse(xml_tree_walker& walker)
 	{
 		walker._depth = -1;
 
@@ -6457,17 +6524,17 @@
 		return walker.end(arg_end);
 	}
 
-	PUGI__FN size_t xml_node::hash_value() const
+	PUGI_IMPL_FN size_t xml_node::hash_value() const
 	{
 		return static_cast<size_t>(reinterpret_cast<uintptr_t>(_root) / sizeof(xml_node_struct));
 	}
 
-	PUGI__FN xml_node_struct* xml_node::internal_object() const
+	PUGI_IMPL_FN xml_node_struct* xml_node::internal_object() const
 	{
 		return _root;
 	}
 
-	PUGI__FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
+	PUGI_IMPL_FN void xml_node::print(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
 	{
 		if (!_root) return;
 
@@ -6479,14 +6546,14 @@
 	}
 
 #ifndef PUGIXML_NO_STL
-	PUGI__FN void xml_node::print(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
+	PUGI_IMPL_FN void xml_node::print(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding, unsigned int depth) const
 	{
 		xml_writer_stream writer(stream);
 
 		print(writer, indent, flags, encoding, depth);
 	}
 
-	PUGI__FN void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const
+	PUGI_IMPL_FN void xml_node::print(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags, unsigned int depth) const
 	{
 		xml_writer_stream writer(stream);
 
@@ -6494,7 +6561,7 @@
 	}
 #endif
 
-	PUGI__FN ptrdiff_t xml_node::offset_debug() const
+	PUGI_IMPL_FN ptrdiff_t xml_node::offset_debug() const
 	{
 		if (!_root) return -1;
 
@@ -6526,27 +6593,27 @@
 	}
 
 #ifdef __BORLANDC__
-	PUGI__FN bool operator&&(const xml_node& lhs, bool rhs)
+	PUGI_IMPL_FN bool operator&&(const xml_node& lhs, bool rhs)
 	{
 		return (bool)lhs && rhs;
 	}
 
-	PUGI__FN bool operator||(const xml_node& lhs, bool rhs)
+	PUGI_IMPL_FN bool operator||(const xml_node& lhs, bool rhs)
 	{
 		return (bool)lhs || rhs;
 	}
 #endif
 
-	PUGI__FN xml_text::xml_text(xml_node_struct* root): _root(root)
-	{
-	}
-
-	PUGI__FN xml_node_struct* xml_text::_data() const
+	PUGI_IMPL_FN xml_text::xml_text(xml_node_struct* root): _root(root)
+	{
+	}
+
+	PUGI_IMPL_FN xml_node_struct* xml_text::_data() const
 	{
 		if (!_root || impl::is_text_node(_root)) return _root;
 
 		// element nodes can have value if parse_embed_pcdata was used
-		if (PUGI__NODETYPE(_root) == node_element && _root->value)
+		if (PUGI_IMPL_NODETYPE(_root) == node_element && _root->value)
 			return _root;
 
 		for (xml_node_struct* node = _root->first_child; node; node = node->next_sibling)
@@ -6556,7 +6623,7 @@
 		return 0;
 	}
 
-	PUGI__FN xml_node_struct* xml_text::_data_new()
+	PUGI_IMPL_FN xml_node_struct* xml_text::_data_new()
 	{
 		xml_node_struct* d = _data();
 		if (d) return d;
@@ -6564,30 +6631,30 @@
 		return xml_node(_root).append_child(node_pcdata).internal_object();
 	}
 
-	PUGI__FN xml_text::xml_text(): _root(0)
-	{
-	}
-
-	PUGI__FN static void unspecified_bool_xml_text(xml_text***)
-	{
-	}
-
-	PUGI__FN xml_text::operator xml_text::unspecified_bool_type() const
+	PUGI_IMPL_FN xml_text::xml_text(): _root(0)
+	{
+	}
+
+	PUGI_IMPL_FN static void unspecified_bool_xml_text(xml_text***)
+	{
+	}
+
+	PUGI_IMPL_FN xml_text::operator xml_text::unspecified_bool_type() const
 	{
 		return _data() ? unspecified_bool_xml_text : 0;
 	}
 
-	PUGI__FN bool xml_text::operator!() const
+	PUGI_IMPL_FN bool xml_text::operator!() const
 	{
 		return !_data();
 	}
 
-	PUGI__FN bool xml_text::empty() const
+	PUGI_IMPL_FN bool xml_text::empty() const
 	{
 		return _data() == 0;
 	}
 
-	PUGI__FN const char_t* xml_text::get() const
+	PUGI_IMPL_FN const char_t* xml_text::get() const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return PUGIXML_TEXT("");
@@ -6595,7 +6662,7 @@
 		return value ? value : PUGIXML_TEXT("");
 	}
 
-	PUGI__FN const char_t* xml_text::as_string(const char_t* def) const
+	PUGI_IMPL_FN const char_t* xml_text::as_string(const char_t* def) const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return def;
@@ -6603,7 +6670,7 @@
 		return value ? value : def;
 	}
 
-	PUGI__FN int xml_text::as_int(int def) const
+	PUGI_IMPL_FN int xml_text::as_int(int def) const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return def;
@@ -6611,7 +6678,7 @@
 		return value ? impl::get_value_int(value) : def;
 	}
 
-	PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const
+	PUGI_IMPL_FN unsigned int xml_text::as_uint(unsigned int def) const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return def;
@@ -6619,7 +6686,7 @@
 		return value ? impl::get_value_uint(value) : def;
 	}
 
-	PUGI__FN double xml_text::as_double(double def) const
+	PUGI_IMPL_FN double xml_text::as_double(double def) const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return def;
@@ -6627,7 +6694,7 @@
 		return value ? impl::get_value_double(value) : def;
 	}
 
-	PUGI__FN float xml_text::as_float(float def) const
+	PUGI_IMPL_FN float xml_text::as_float(float def) const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return def;
@@ -6635,7 +6702,7 @@
 		return value ? impl::get_value_float(value) : def;
 	}
 
-	PUGI__FN bool xml_text::as_bool(bool def) const
+	PUGI_IMPL_FN bool xml_text::as_bool(bool def) const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return def;
@@ -6644,7 +6711,7 @@
 	}
 
 #ifdef PUGIXML_HAS_LONG_LONG
-	PUGI__FN long long xml_text::as_llong(long long def) const
+	PUGI_IMPL_FN long long xml_text::as_llong(long long def) const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return def;
@@ -6652,7 +6719,7 @@
 		return value ? impl::get_value_llong(value) : def;
 	}
 
-	PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const
+	PUGI_IMPL_FN unsigned long long xml_text::as_ullong(unsigned long long def) const
 	{
 		xml_node_struct* d = _data();
 		if (!d) return def;
@@ -6661,77 +6728,77 @@
 	}
 #endif
 
-	PUGI__FN bool xml_text::set(const char_t* rhs, size_t sz)
-	{
-		xml_node_struct* dn = _data_new();
-
-		return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, sz) : false;
-	}
-
-	PUGI__FN bool xml_text::set(const char_t* rhs)
+	PUGI_IMPL_FN bool xml_text::set(const char_t* rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, impl::strlength(rhs)) : false;
 	}
 
-	PUGI__FN bool xml_text::set(int rhs)
+	PUGI_IMPL_FN bool xml_text::set(const char_t* rhs, size_t size)
+	{
+		xml_node_struct* dn = _data_new();
+
+		return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, size) : false;
+	}
+
+	PUGI_IMPL_FN bool xml_text::set(int rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
 	}
 
-	PUGI__FN bool xml_text::set(unsigned int rhs)
+	PUGI_IMPL_FN bool xml_text::set(unsigned int rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_integer<unsigned int>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
 	}
 
-	PUGI__FN bool xml_text::set(long rhs)
+	PUGI_IMPL_FN bool xml_text::set(long rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
 	}
 
-	PUGI__FN bool xml_text::set(unsigned long rhs)
+	PUGI_IMPL_FN bool xml_text::set(unsigned long rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_integer<unsigned long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, false) : false;
 	}
 
-	PUGI__FN bool xml_text::set(float rhs)
+	PUGI_IMPL_FN bool xml_text::set(float rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_float_precision) : false;
 	}
 
-	PUGI__FN bool xml_text::set(float rhs, int precision)
+	PUGI_IMPL_FN bool xml_text::set(float rhs, int precision)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false;
 	}
 
-	PUGI__FN bool xml_text::set(double rhs)
+	PUGI_IMPL_FN bool xml_text::set(double rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, default_double_precision) : false;
 	}
 
-	PUGI__FN bool xml_text::set(double rhs, int precision)
+	PUGI_IMPL_FN bool xml_text::set(double rhs, int precision)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, precision) : false;
 	}
 
-	PUGI__FN bool xml_text::set(bool rhs)
+	PUGI_IMPL_FN bool xml_text::set(bool rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
@@ -6739,14 +6806,14 @@
 	}
 
 #ifdef PUGIXML_HAS_LONG_LONG
-	PUGI__FN bool xml_text::set(long long rhs)
+	PUGI_IMPL_FN bool xml_text::set(long long rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
 		return dn ? impl::set_value_integer<unsigned long long>(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, rhs < 0) : false;
 	}
 
-	PUGI__FN bool xml_text::set(unsigned long long rhs)
+	PUGI_IMPL_FN bool xml_text::set(unsigned long long rhs)
 	{
 		xml_node_struct* dn = _data_new();
 
@@ -6754,256 +6821,256 @@
 	}
 #endif
 
-	PUGI__FN xml_text& xml_text::operator=(const char_t* rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(const char_t* rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_text& xml_text::operator=(int rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(int rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_text& xml_text::operator=(unsigned int rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned int rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_text& xml_text::operator=(long rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(long rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_text& xml_text::operator=(unsigned long rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned long rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_text& xml_text::operator=(double rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(double rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_text& xml_text::operator=(float rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(float rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_text& xml_text::operator=(bool rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(bool rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
 #ifdef PUGIXML_HAS_LONG_LONG
-	PUGI__FN xml_text& xml_text::operator=(long long rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(long long rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 
-	PUGI__FN xml_text& xml_text::operator=(unsigned long long rhs)
+	PUGI_IMPL_FN xml_text& xml_text::operator=(unsigned long long rhs)
 	{
 		set(rhs);
 		return *this;
 	}
 #endif
 
-	PUGI__FN xml_node xml_text::data() const
+	PUGI_IMPL_FN xml_node xml_text::data() const
 	{
 		return xml_node(_data());
 	}
 
 #ifdef __BORLANDC__
-	PUGI__FN bool operator&&(const xml_text& lhs, bool rhs)
+	PUGI_IMPL_FN bool operator&&(const xml_text& lhs, bool rhs)
 	{
 		return (bool)lhs && rhs;
 	}
 
-	PUGI__FN bool operator||(const xml_text& lhs, bool rhs)
+	PUGI_IMPL_FN bool operator||(const xml_text& lhs, bool rhs)
 	{
 		return (bool)lhs || rhs;
 	}
 #endif
 
-	PUGI__FN xml_node_iterator::xml_node_iterator()
-	{
-	}
-
-	PUGI__FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
-	{
-	}
-
-	PUGI__FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
-	{
-	}
-
-	PUGI__FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const
+	PUGI_IMPL_FN xml_node_iterator::xml_node_iterator()
+	{
+	}
+
+	PUGI_IMPL_FN xml_node_iterator::xml_node_iterator(const xml_node& node): _wrap(node), _parent(node.parent())
+	{
+	}
+
+	PUGI_IMPL_FN xml_node_iterator::xml_node_iterator(xml_node_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
+	{
+	}
+
+	PUGI_IMPL_FN bool xml_node_iterator::operator==(const xml_node_iterator& rhs) const
 	{
 		return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
 	}
 
-	PUGI__FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const
+	PUGI_IMPL_FN bool xml_node_iterator::operator!=(const xml_node_iterator& rhs) const
 	{
 		return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
 	}
 
-	PUGI__FN xml_node& xml_node_iterator::operator*() const
+	PUGI_IMPL_FN xml_node& xml_node_iterator::operator*() const
 	{
 		assert(_wrap._root);
 		return _wrap;
 	}
 
-	PUGI__FN xml_node* xml_node_iterator::operator->() const
+	PUGI_IMPL_FN xml_node* xml_node_iterator::operator->() const
 	{
 		assert(_wrap._root);
 		return const_cast<xml_node*>(&_wrap); // BCC5 workaround
 	}
 
-	PUGI__FN xml_node_iterator& xml_node_iterator::operator++()
+	PUGI_IMPL_FN xml_node_iterator& xml_node_iterator::operator++()
 	{
 		assert(_wrap._root);
 		_wrap._root = _wrap._root->next_sibling;
 		return *this;
 	}
 
-	PUGI__FN xml_node_iterator xml_node_iterator::operator++(int)
+	PUGI_IMPL_FN xml_node_iterator xml_node_iterator::operator++(int)
 	{
 		xml_node_iterator temp = *this;
 		++*this;
 		return temp;
 	}
 
-	PUGI__FN xml_node_iterator& xml_node_iterator::operator--()
+	PUGI_IMPL_FN xml_node_iterator& xml_node_iterator::operator--()
 	{
 		_wrap = _wrap._root ? _wrap.previous_sibling() : _parent.last_child();
 		return *this;
 	}
 
-	PUGI__FN xml_node_iterator xml_node_iterator::operator--(int)
+	PUGI_IMPL_FN xml_node_iterator xml_node_iterator::operator--(int)
 	{
 		xml_node_iterator temp = *this;
 		--*this;
 		return temp;
 	}
 
-	PUGI__FN xml_attribute_iterator::xml_attribute_iterator()
-	{
-	}
-
-	PUGI__FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
-	{
-	}
-
-	PUGI__FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
-	{
-	}
-
-	PUGI__FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const
+	PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator()
+	{
+	}
+
+	PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(const xml_attribute& attr, const xml_node& parent): _wrap(attr), _parent(parent)
+	{
+	}
+
+	PUGI_IMPL_FN xml_attribute_iterator::xml_attribute_iterator(xml_attribute_struct* ref, xml_node_struct* parent): _wrap(ref), _parent(parent)
+	{
+	}
+
+	PUGI_IMPL_FN bool xml_attribute_iterator::operator==(const xml_attribute_iterator& rhs) const
 	{
 		return _wrap._attr == rhs._wrap._attr && _parent._root == rhs._parent._root;
 	}
 
-	PUGI__FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const
+	PUGI_IMPL_FN bool xml_attribute_iterator::operator!=(const xml_attribute_iterator& rhs) const
 	{
 		return _wrap._attr != rhs._wrap._attr || _parent._root != rhs._parent._root;
 	}
 
-	PUGI__FN xml_attribute& xml_attribute_iterator::operator*() const
+	PUGI_IMPL_FN xml_attribute& xml_attribute_iterator::operator*() const
 	{
 		assert(_wrap._attr);
 		return _wrap;
 	}
 
-	PUGI__FN xml_attribute* xml_attribute_iterator::operator->() const
+	PUGI_IMPL_FN xml_attribute* xml_attribute_iterator::operator->() const
 	{
 		assert(_wrap._attr);
 		return const_cast<xml_attribute*>(&_wrap); // BCC5 workaround
 	}
 
-	PUGI__FN xml_attribute_iterator& xml_attribute_iterator::operator++()
+	PUGI_IMPL_FN xml_attribute_iterator& xml_attribute_iterator::operator++()
 	{
 		assert(_wrap._attr);
 		_wrap._attr = _wrap._attr->next_attribute;
 		return *this;
 	}
 
-	PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator++(int)
+	PUGI_IMPL_FN xml_attribute_iterator xml_attribute_iterator::operator++(int)
 	{
 		xml_attribute_iterator temp = *this;
 		++*this;
 		return temp;
 	}
 
-	PUGI__FN xml_attribute_iterator& xml_attribute_iterator::operator--()
+	PUGI_IMPL_FN xml_attribute_iterator& xml_attribute_iterator::operator--()
 	{
 		_wrap = _wrap._attr ? _wrap.previous_attribute() : _parent.last_attribute();
 		return *this;
 	}
 
-	PUGI__FN xml_attribute_iterator xml_attribute_iterator::operator--(int)
+	PUGI_IMPL_FN xml_attribute_iterator xml_attribute_iterator::operator--(int)
 	{
 		xml_attribute_iterator temp = *this;
 		--*this;
 		return temp;
 	}
 
-	PUGI__FN xml_named_node_iterator::xml_named_node_iterator(): _name(0)
-	{
-	}
-
-	PUGI__FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name)
-	{
-	}
-
-	PUGI__FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name)
-	{
-	}
-
-	PUGI__FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const
+	PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(): _name(0)
+	{
+	}
+
+	PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(const xml_node& node, const char_t* name): _wrap(node), _parent(node.parent()), _name(name)
+	{
+	}
+
+	PUGI_IMPL_FN xml_named_node_iterator::xml_named_node_iterator(xml_node_struct* ref, xml_node_struct* parent, const char_t* name): _wrap(ref), _parent(parent), _name(name)
+	{
+	}
+
+	PUGI_IMPL_FN bool xml_named_node_iterator::operator==(const xml_named_node_iterator& rhs) const
 	{
 		return _wrap._root == rhs._wrap._root && _parent._root == rhs._parent._root;
 	}
 
-	PUGI__FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const
+	PUGI_IMPL_FN bool xml_named_node_iterator::operator!=(const xml_named_node_iterator& rhs) const
 	{
 		return _wrap._root != rhs._wrap._root || _parent._root != rhs._parent._root;
 	}
 
-	PUGI__FN xml_node& xml_named_node_iterator::operator*() const
+	PUGI_IMPL_FN xml_node& xml_named_node_iterator::operator*() const
 	{
 		assert(_wrap._root);
 		return _wrap;
 	}
 
-	PUGI__FN xml_node* xml_named_node_iterator::operator->() const
+	PUGI_IMPL_FN xml_node* xml_named_node_iterator::operator->() const
 	{
 		assert(_wrap._root);
 		return const_cast<xml_node*>(&_wrap); // BCC5 workaround
 	}
 
-	PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator++()
+	PUGI_IMPL_FN xml_named_node_iterator& xml_named_node_iterator::operator++()
 	{
 		assert(_wrap._root);
 		_wrap = _wrap.next_sibling(_name);
 		return *this;
 	}
 
-	PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator++(int)
+	PUGI_IMPL_FN xml_named_node_iterator xml_named_node_iterator::operator++(int)
 	{
 		xml_named_node_iterator temp = *this;
 		++*this;
 		return temp;
 	}
 
-	PUGI__FN xml_named_node_iterator& xml_named_node_iterator::operator--()
+	PUGI_IMPL_FN xml_named_node_iterator& xml_named_node_iterator::operator--()
 	{
 		if (_wrap._root)
 			_wrap = _wrap.previous_sibling(_name);
@@ -7018,23 +7085,23 @@
 		return *this;
 	}
 
-	PUGI__FN xml_named_node_iterator xml_named_node_iterator::operator--(int)
+	PUGI_IMPL_FN xml_named_node_iterator xml_named_node_iterator::operator--(int)
 	{
 		xml_named_node_iterator temp = *this;
 		--*this;
 		return temp;
 	}
 
-	PUGI__FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
-	{
-	}
-
-	PUGI__FN xml_parse_result::operator bool() const
+	PUGI_IMPL_FN xml_parse_result::xml_parse_result(): status(status_internal_error), offset(0), encoding(encoding_auto)
+	{
+	}
+
+	PUGI_IMPL_FN xml_parse_result::operator bool() const
 	{
 		return status == status_ok;
 	}
 
-	PUGI__FN const char* xml_parse_result::description() const
+	PUGI_IMPL_FN const char* xml_parse_result::description() const
 	{
 		switch (status)
 		{
@@ -7065,24 +7132,24 @@
 		}
 	}
 
-	PUGI__FN xml_document::xml_document(): _buffer(0)
+	PUGI_IMPL_FN xml_document::xml_document(): _buffer(0)
 	{
 		_create();
 	}
 
-	PUGI__FN xml_document::~xml_document()
+	PUGI_IMPL_FN xml_document::~xml_document()
 	{
 		_destroy();
 	}
 
 #ifdef PUGIXML_HAS_MOVE
-	PUGI__FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(0)
+	PUGI_IMPL_FN xml_document::xml_document(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT: _buffer(0)
 	{
 		_create();
 		_move(rhs);
 	}
 
-	PUGI__FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
+	PUGI_IMPL_FN xml_document& xml_document::operator=(xml_document&& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
 	{
 		if (this == &rhs) return *this;
 
@@ -7094,20 +7161,20 @@
 	}
 #endif
 
-	PUGI__FN void xml_document::reset()
+	PUGI_IMPL_FN void xml_document::reset()
 	{
 		_destroy();
 		_create();
 	}
 
-	PUGI__FN void xml_document::reset(const xml_document& proto)
+	PUGI_IMPL_FN void xml_document::reset(const xml_document& proto)
 	{
 		reset();
 
 		impl::node_copy_tree(_root, proto._root);
 	}
 
-	PUGI__FN void xml_document::_create()
+	PUGI_IMPL_FN void xml_document::_create()
 	{
 		assert(!_root);
 
@@ -7119,7 +7186,7 @@
 	#endif
 
 		// initialize sentinel page
-		PUGI__STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory));
+		PUGI_IMPL_STATIC_ASSERT(sizeof(impl::xml_memory_page) + sizeof(impl::xml_document_struct) + page_offset <= sizeof(_memory));
 
 		// prepare page structure
 		impl::xml_memory_page* page = impl::xml_memory_page::construct(_memory);
@@ -7150,7 +7217,7 @@
 		assert(reinterpret_cast<char*>(_root) + sizeof(impl::xml_document_struct) <= _memory + sizeof(_memory));
 	}
 
-	PUGI__FN void xml_document::_destroy()
+	PUGI_IMPL_FN void xml_document::_destroy()
 	{
 		assert(_root);
 
@@ -7168,7 +7235,7 @@
 		}
 
 		// destroy dynamic storage, leave sentinel page (it's in static memory)
-		impl::xml_memory_page* root_page = PUGI__GETPAGE(_root);
+		impl::xml_memory_page* root_page = PUGI_IMPL_GETPAGE(_root);
 		assert(root_page && !root_page->prev);
 		assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));
 
@@ -7190,7 +7257,7 @@
 	}
 
 #ifdef PUGIXML_HAS_MOVE
-	PUGI__FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
+	PUGI_IMPL_FN void xml_document::_move(xml_document& rhs) PUGIXML_NOEXCEPT_IF_NOT_COMPACT
 	{
 		impl::xml_document_struct* doc = static_cast<impl::xml_document_struct*>(_root);
 		impl::xml_document_struct* other = static_cast<impl::xml_document_struct*>(rhs._root);
@@ -7224,7 +7291,7 @@
 
 		// move allocation state
 		// note that other->_root may point to the embedded document page, in which case we should keep original (empty) state
-		if (other->_root != PUGI__GETPAGE(other))
+		if (other->_root != PUGI_IMPL_GETPAGE(other))
 		{
 			doc->_root = other->_root;
 			doc->_busy_size = other->_busy_size;
@@ -7245,10 +7312,10 @@
 	#endif
 
 		// move page structure
-		impl::xml_memory_page* doc_page = PUGI__GETPAGE(doc);
+		impl::xml_memory_page* doc_page = PUGI_IMPL_GETPAGE(doc);
 		assert(doc_page && !doc_page->prev && !doc_page->next);
 
-		impl::xml_memory_page* other_page = PUGI__GETPAGE(other);
+		impl::xml_memory_page* other_page = PUGI_IMPL_GETPAGE(other);
 		assert(other_page && !other_page->prev);
 
 		// relink pages since root page is embedded into xml_document
@@ -7295,20 +7362,20 @@
 		}
 
 		// reset other document
-		new (other) impl::xml_document_struct(PUGI__GETPAGE(other));
+		new (other) impl::xml_document_struct(PUGI_IMPL_GETPAGE(other));
 		rhs._buffer = 0;
 	}
 #endif
 
 #ifndef PUGIXML_NO_STL
-	PUGI__FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
+	PUGI_IMPL_FN xml_parse_result xml_document::load(std::basic_istream<char, std::char_traits<char> >& stream, unsigned int options, xml_encoding encoding)
 	{
 		reset();
 
 		return impl::load_stream_impl(static_cast<impl::xml_document_struct*>(_root), stream, options, encoding, &_buffer);
 	}
 
-	PUGI__FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
+	PUGI_IMPL_FN xml_parse_result xml_document::load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options)
 	{
 		reset();
 
@@ -7316,7 +7383,7 @@
 	}
 #endif
 
-	PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options)
+	PUGI_IMPL_FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options)
 	{
 		// Force native encoding (skip autodetection)
 	#ifdef PUGIXML_WCHAR_MODE
@@ -7328,12 +7395,12 @@
 		return load_buffer(contents, impl::strlength(contents) * sizeof(char_t), options, encoding);
 	}
 
-	PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
+	PUGI_IMPL_FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
 	{
 		return load_string(contents, options);
 	}
 
-	PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
+	PUGI_IMPL_FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
 	{
 		reset();
 
@@ -7343,7 +7410,7 @@
 		return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
 	}
 
-	PUGI__FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)
+	PUGI_IMPL_FN xml_parse_result xml_document::load_file(const wchar_t* path_, unsigned int options, xml_encoding encoding)
 	{
 		reset();
 
@@ -7353,28 +7420,28 @@
 		return impl::load_file_impl(static_cast<impl::xml_document_struct*>(_root), file.data, options, encoding, &_buffer);
 	}
 
-	PUGI__FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
+	PUGI_IMPL_FN xml_parse_result xml_document::load_buffer(const void* contents, size_t size, unsigned int options, xml_encoding encoding)
 	{
 		reset();
 
 		return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, const_cast<void*>(contents), size, options, encoding, false, false, &_buffer);
 	}
 
-	PUGI__FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
+	PUGI_IMPL_FN xml_parse_result xml_document::load_buffer_inplace(void* contents, size_t size, unsigned int options, xml_encoding encoding)
 	{
 		reset();
 
 		return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, false, &_buffer);
 	}
 
-	PUGI__FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
+	PUGI_IMPL_FN xml_parse_result xml_document::load_buffer_inplace_own(void* contents, size_t size, unsigned int options, xml_encoding encoding)
 	{
 		reset();
 
 		return impl::load_buffer_impl(static_cast<impl::xml_document_struct*>(_root), _root, contents, size, options, encoding, true, true, &_buffer);
 	}
 
-	PUGI__FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
+	PUGI_IMPL_FN void xml_document::save(xml_writer& writer, const char_t* indent, unsigned int flags, xml_encoding encoding) const
 	{
 		impl::xml_buffered_writer buffered_writer(writer, encoding);
 
@@ -7403,14 +7470,14 @@
 	}
 
 #ifndef PUGIXML_NO_STL
-	PUGI__FN void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const
+	PUGI_IMPL_FN void xml_document::save(std::basic_ostream<char, std::char_traits<char> >& stream, const char_t* indent, unsigned int flags, xml_encoding encoding) const
 	{
 		xml_writer_stream writer(stream);
 
 		save(writer, indent, flags, encoding);
 	}
 
-	PUGI__FN void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const
+	PUGI_IMPL_FN void xml_document::save(std::basic_ostream<wchar_t, std::char_traits<wchar_t> >& stream, const char_t* indent, unsigned int flags) const
 	{
 		xml_writer_stream writer(stream);
 
@@ -7418,7 +7485,7 @@
 	}
 #endif
 
-	PUGI__FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
+	PUGI_IMPL_FN bool xml_document::save_file(const char* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
 	{
 		using impl::auto_deleter; // MSVC7 workaround
 		auto_deleter<FILE> file(impl::open_file(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file);
@@ -7426,7 +7493,7 @@
 		return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0;
 	}
 
-	PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
+	PUGI_IMPL_FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const
 	{
 		using impl::auto_deleter; // MSVC7 workaround
 		auto_deleter<FILE> file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file);
@@ -7434,55 +7501,55 @@
 		return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0;
 	}
 
-	PUGI__FN xml_node xml_document::document_element() const
+	PUGI_IMPL_FN xml_node xml_document::document_element() const
 	{
 		assert(_root);
 
 		for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling)
-			if (PUGI__NODETYPE(i) == node_element)
+			if (PUGI_IMPL_NODETYPE(i) == node_element)
 				return xml_node(i);
 
 		return xml_node();
 	}
 
 #ifndef PUGIXML_NO_STL
-	PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
+	PUGI_IMPL_FN std::string PUGIXML_FUNCTION as_utf8(const wchar_t* str)
 	{
 		assert(str);
 
 		return impl::as_utf8_impl(str, impl::strlength_wide(str));
 	}
 
-	PUGI__FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str)
+	PUGI_IMPL_FN std::string PUGIXML_FUNCTION as_utf8(const std::basic_string<wchar_t>& str)
 	{
 		return impl::as_utf8_impl(str.c_str(), str.size());
 	}
 
-	PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str)
+	PUGI_IMPL_FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const char* str)
 	{
 		assert(str);
 
 		return impl::as_wide_impl(str, strlen(str));
 	}
 
-	PUGI__FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str)
+	PUGI_IMPL_FN std::basic_string<wchar_t> PUGIXML_FUNCTION as_wide(const std::string& str)
 	{
 		return impl::as_wide_impl(str.c_str(), str.size());
 	}
 #endif
 
-	PUGI__FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
+	PUGI_IMPL_FN void PUGIXML_FUNCTION set_memory_management_functions(allocation_function allocate, deallocation_function deallocate)
 	{
 		impl::xml_memory::allocate = allocate;
 		impl::xml_memory::deallocate = deallocate;
 	}
 
-	PUGI__FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
+	PUGI_IMPL_FN allocation_function PUGIXML_FUNCTION get_memory_allocation_function()
 	{
 		return impl::xml_memory::allocate;
 	}
 
-	PUGI__FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
+	PUGI_IMPL_FN deallocation_function PUGIXML_FUNCTION get_memory_deallocation_function()
 	{
 		return impl::xml_memory::deallocate;
 	}
@@ -7492,17 +7559,17 @@
 namespace std
 {
 	// Workarounds for (non-standard) iterator category detection for older versions (MSVC7/IC8 and earlier)
-	PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
+	PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_node_iterator&)
 	{
 		return std::bidirectional_iterator_tag();
 	}
 
-	PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
+	PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_attribute_iterator&)
 	{
 		return std::bidirectional_iterator_tag();
 	}
 
-	PUGI__FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)
+	PUGI_IMPL_FN std::bidirectional_iterator_tag _Iter_cat(const pugi::xml_named_node_iterator&)
 	{
 		return std::bidirectional_iterator_tag();
 	}
@@ -7513,17 +7580,17 @@
 namespace std
 {
 	// Workarounds for (non-standard) iterator category detection
-	PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)
+	PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_node_iterator&)
 	{
 		return std::bidirectional_iterator_tag();
 	}
 
-	PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)
+	PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_attribute_iterator&)
 	{
 		return std::bidirectional_iterator_tag();
 	}
 
-	PUGI__FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)
+	PUGI_IMPL_FN std::bidirectional_iterator_tag __iterator_category(const pugi::xml_named_node_iterator&)
 	{
 		return std::bidirectional_iterator_tag();
 	}
@@ -7532,7 +7599,7 @@
 
 #ifndef PUGIXML_NO_XPATH
 // STL replacements
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	struct equal_to
 	{
 		template <typename T> bool operator()(const T& lhs, const T& rhs) const
@@ -7572,7 +7639,7 @@
 		rhs = temp;
 	}
 
-	template <typename I, typename Pred> PUGI__FN I min_element(I begin, I end, const Pred& pred)
+	template <typename I, typename Pred> PUGI_IMPL_FN I min_element(I begin, I end, const Pred& pred)
 	{
 		I result = begin;
 
@@ -7583,13 +7650,13 @@
 		return result;
 	}
 
-	template <typename I> PUGI__FN void reverse(I begin, I end)
+	template <typename I> PUGI_IMPL_FN void reverse(I begin, I end)
 	{
 		while (end - begin > 1)
 			swap(*begin++, *--end);
 	}
 
-	template <typename I> PUGI__FN I unique(I begin, I end)
+	template <typename I> PUGI_IMPL_FN I unique(I begin, I end)
 	{
 		// fast skip head
 		while (end - begin > 1 && *begin != *(begin + 1))
@@ -7614,7 +7681,7 @@
 		return write + 1;
 	}
 
-	template <typename T, typename Pred> PUGI__FN void insertion_sort(T* begin, T* end, const Pred& pred)
+	template <typename T, typename Pred> PUGI_IMPL_FN void insertion_sort(T* begin, T* end, const Pred& pred)
 	{
 		if (begin == end)
 			return;
@@ -7648,7 +7715,7 @@
 		return middle;
 	}
 
-	template <typename T, typename Pred> PUGI__FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend)
+	template <typename T, typename Pred> PUGI_IMPL_FN void partition3(T* begin, T* end, T pivot, const Pred& pred, T** out_eqbeg, T** out_eqend)
 	{
 		// invariant: array is split into 4 groups: = < ? > (each variable denotes the boundary between the groups)
 		T* eq = begin;
@@ -7675,7 +7742,7 @@
 		*out_eqend = gt;
 	}
 
-	template <typename I, typename Pred> PUGI__FN void sort(I begin, I end, const Pred& pred)
+	template <typename I, typename Pred> PUGI_IMPL_FN void sort(I begin, I end, const Pred& pred)
 	{
 		// sort large chunks
 		while (end - begin > 16)
@@ -7705,7 +7772,7 @@
 		insertion_sort(begin, end, pred);
 	}
 
-	PUGI__FN bool hash_insert(const void** table, size_t size, const void* key)
+	PUGI_IMPL_FN bool hash_insert(const void** table, size_t size, const void* key)
 	{
 		assert(key);
 
@@ -7739,10 +7806,10 @@
 		assert(false && "Hash table is full"); // unreachable
 		return false;
 	}
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 // Allocator used for AST and evaluation stacks
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	static const size_t xpath_memory_page_size =
 	#ifdef PUGIXML_MEMORY_XPATH_PAGE_SIZE
 		PUGIXML_MEMORY_XPATH_PAGE_SIZE
@@ -7938,10 +8005,10 @@
 			temp.release();
 		}
 	};
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 // String class
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_BEGIN
 	class xpath_string
 	{
 		const char_t* _buffer;
@@ -8076,10 +8143,10 @@
 			return _uses_heap;
 		}
 	};
-PUGI__NS_END
-
-PUGI__NS_BEGIN
-	PUGI__FN bool starts_with(const char_t* string, const char_t* pattern)
+PUGI_IMPL_NS_END
+
+PUGI_IMPL_NS_BEGIN
+	PUGI_IMPL_FN bool starts_with(const char_t* string, const char_t* pattern)
 	{
 		while (*pattern && *string == *pattern)
 		{
@@ -8090,7 +8157,7 @@
 		return *pattern == 0;
 	}
 
-	PUGI__FN const char_t* find_char(const char_t* s, char_t c)
+	PUGI_IMPL_FN const char_t* find_char(const char_t* s, char_t c)
 	{
 	#ifdef PUGIXML_WCHAR_MODE
 		return wcschr(s, c);
@@ -8099,7 +8166,7 @@
 	#endif
 	}
 
-	PUGI__FN const char_t* find_substring(const char_t* s, const char_t* p)
+	PUGI_IMPL_FN const char_t* find_substring(const char_t* s, const char_t* p)
 	{
 	#ifdef PUGIXML_WCHAR_MODE
 		// MSVC6 wcsstr bug workaround (if s is empty it always returns 0)
@@ -8110,12 +8177,12 @@
 	}
 
 	// Converts symbol to lower case, if it is an ASCII one
-	PUGI__FN char_t tolower_ascii(char_t ch)
+	PUGI_IMPL_FN char_t tolower_ascii(char_t ch)
 	{
 		return static_cast<unsigned int>(ch - 'A') < 26 ? static_cast<char_t>(ch | ' ') : ch;
 	}
 
-	PUGI__FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
+	PUGI_IMPL_FN xpath_string string_value(const xpath_node& na, xpath_allocator* alloc)
 	{
 		if (na.attribute())
 			return xpath_string::from_const(na.attribute().value());
@@ -8169,7 +8236,7 @@
 		}
 	}
 
-	PUGI__FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)
+	PUGI_IMPL_FN bool node_is_before_sibling(xml_node_struct* ln, xml_node_struct* rn)
 	{
 		assert(ln->parent == rn->parent);
 
@@ -8193,7 +8260,7 @@
 		return !rs;
 	}
 
-	PUGI__FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
+	PUGI_IMPL_FN bool node_is_before(xml_node_struct* ln, xml_node_struct* rn)
 	{
 		// find common ancestor at the same depth, if any
 		xml_node_struct* lp = ln;
@@ -8236,14 +8303,14 @@
 		return node_is_before_sibling(ln, rn);
 	}
 
-	PUGI__FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)
+	PUGI_IMPL_FN bool node_is_ancestor(xml_node_struct* parent, xml_node_struct* node)
 	{
 		while (node && node != parent) node = node->parent;
 
 		return parent && node == parent;
 	}
 
-	PUGI__FN const void* document_buffer_order(const xpath_node& xnode)
+	PUGI_IMPL_FN const void* document_buffer_order(const xpath_node& xnode)
 	{
 		xml_node_struct* node = xnode.node().internal_object();
 
@@ -8328,10 +8395,10 @@
 		}
 	};
 
-	PUGI__FN double gen_nan()
+	PUGI_IMPL_FN double gen_nan()
 	{
 	#if defined(__STDC_IEC_559__) || ((FLT_RADIX - 0 == 2) && (FLT_MAX_EXP - 0 == 128) && (FLT_MANT_DIG - 0 == 24))
-		PUGI__STATIC_ASSERT(sizeof(float) == sizeof(uint32_t));
+		PUGI_IMPL_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t));
 		typedef uint32_t UI; // BCC5 workaround
 		union { float f; UI i; } u;
 		u.i = 0x7fc00000;
@@ -8343,9 +8410,9 @@
 	#endif
 	}
 
-	PUGI__FN bool is_nan(double value)
-	{
-	#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
+	PUGI_IMPL_FN bool is_nan(double value)
+	{
+	#if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__)
 		return !!_isnan(value);
 	#elif defined(fpclassify) && defined(FP_NAN)
 		return fpclassify(value) == FP_NAN;
@@ -8356,9 +8423,9 @@
 	#endif
 	}
 
-	PUGI__FN const char_t* convert_number_to_string_special(double value)
-	{
-	#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__)
+	PUGI_IMPL_FN const char_t* convert_number_to_string_special(double value)
+	{
+	#if defined(PUGI_IMPL_MSVC_CRT_VERSION) || defined(__BORLANDC__)
 		if (_finite(value)) return (value == 0) ? PUGIXML_TEXT("0") : 0;
 		if (_isnan(value)) return PUGIXML_TEXT("NaN");
 		return value > 0 ? PUGIXML_TEXT("Infinity") : PUGIXML_TEXT("-Infinity");
@@ -8388,12 +8455,12 @@
 	#endif
 	}
 
-	PUGI__FN bool convert_number_to_boolean(double value)
+	PUGI_IMPL_FN bool convert_number_to_boolean(double value)
 	{
 		return (value != 0 && !is_nan(value));
 	}
 
-	PUGI__FN void truncate_zeros(char* begin, char* end)
+	PUGI_IMPL_FN void truncate_zeros(char* begin, char* end)
 	{
 		while (begin != end && end[-1] == '0') end--;
 
@@ -8401,8 +8468,8 @@
 	}
 
 	// gets mantissa digits in the form of 0.xxxxx with 0. implied and the exponent
-#if defined(PUGI__MSVC_CRT_VERSION) && PUGI__MSVC_CRT_VERSION >= 1400
-	PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
+#if defined(PUGI_IMPL_MSVC_CRT_VERSION) && PUGI_IMPL_MSVC_CRT_VERSION >= 1400
+	PUGI_IMPL_FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
 	{
 		// get base values
 		int sign, exponent;
@@ -8416,10 +8483,10 @@
 		*out_exponent = exponent;
 	}
 #else
-	PUGI__FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
+	PUGI_IMPL_FN void convert_number_to_mantissa_exponent(double value, char (&buffer)[32], char** out_mantissa, int* out_exponent)
 	{
 		// get a scientific notation value with IEEE DBL_DIG decimals
-		PUGI__SNPRINTF(buffer, "%.*e", DBL_DIG, value);
+		PUGI_IMPL_SNPRINTF(buffer, "%.*e", DBL_DIG, value);
 
 		// get the exponent (possibly negative)
 		char* exponent_string = strchr(buffer, 'e');
@@ -8429,7 +8496,7 @@
 
 		// extract mantissa string: skip sign
 		char* mantissa = buffer[0] == '-' ? buffer + 1 : buffer;
-		assert(mantissa[0] != '0' && mantissa[1] == '.');
+		assert(mantissa[0] != '0' && (mantissa[1] == '.' || mantissa[1] == ','));
 
 		// divide mantissa by 10 to eliminate integer part
 		mantissa[1] = mantissa[0];
@@ -8445,7 +8512,7 @@
 	}
 #endif
 
-	PUGI__FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc)
+	PUGI_IMPL_FN xpath_string convert_number_to_string(double value, xpath_allocator* alloc)
 	{
 		// try special number conversion
 		const char_t* special = convert_number_to_string_special(value);
@@ -8512,10 +8579,10 @@
 		return xpath_string::from_heap_preallocated(result, s);
 	}
 
-	PUGI__FN bool check_string_to_number_format(const char_t* string)
+	PUGI_IMPL_FN bool check_string_to_number_format(const char_t* string)
 	{
 		// parse leading whitespace
-		while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
+		while (PUGI_IMPL_IS_CHARTYPE(*string, ct_space)) ++string;
 
 		// parse sign
 		if (*string == '-') ++string;
@@ -8523,26 +8590,26 @@
 		if (!*string) return false;
 
 		// if there is no integer part, there should be a decimal part with at least one digit
-		if (!PUGI__IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI__IS_CHARTYPEX(string[1], ctx_digit))) return false;
+		if (!PUGI_IMPL_IS_CHARTYPEX(string[0], ctx_digit) && (string[0] != '.' || !PUGI_IMPL_IS_CHARTYPEX(string[1], ctx_digit))) return false;
 
 		// parse integer part
-		while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
+		while (PUGI_IMPL_IS_CHARTYPEX(*string, ctx_digit)) ++string;
 
 		// parse decimal part
 		if (*string == '.')
 		{
 			++string;
 
-			while (PUGI__IS_CHARTYPEX(*string, ctx_digit)) ++string;
+			while (PUGI_IMPL_IS_CHARTYPEX(*string, ctx_digit)) ++string;
 		}
 
 		// parse trailing whitespace
-		while (PUGI__IS_CHARTYPE(*string, ct_space)) ++string;
+		while (PUGI_IMPL_IS_CHARTYPE(*string, ct_space)) ++string;
 
 		return *string == 0;
 	}
 
-	PUGI__FN double convert_string_to_number(const char_t* string)
+	PUGI_IMPL_FN double convert_string_to_number(const char_t* string)
 	{
 		// check string format
 		if (!check_string_to_number_format(string)) return gen_nan();
@@ -8555,7 +8622,7 @@
 	#endif
 	}
 
-	PUGI__FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result)
+	PUGI_IMPL_FN bool convert_string_to_number_scratch(char_t (&buffer)[32], const char_t* begin, const char_t* end, double* out_result)
 	{
 		size_t length = static_cast<size_t>(end - begin);
 		char_t* scratch = buffer;
@@ -8579,24 +8646,24 @@
 		return true;
 	}
 
-	PUGI__FN double round_nearest(double value)
+	PUGI_IMPL_FN double round_nearest(double value)
 	{
 		return floor(value + 0.5);
 	}
 
-	PUGI__FN double round_nearest_nzero(double value)
+	PUGI_IMPL_FN double round_nearest_nzero(double value)
 	{
 		// same as round_nearest, but returns -0 for [-0.5, -0]
 		// ceil is used to differentiate between +0 and -0 (we return -0 for [-0.5, -0] and +0 for +0)
 		return (value >= -0.5 && value <= 0) ? ceil(value) : floor(value + 0.5);
 	}
 
-	PUGI__FN const char_t* qualified_name(const xpath_node& node)
+	PUGI_IMPL_FN const char_t* qualified_name(const xpath_node& node)
 	{
 		return node.attribute() ? node.attribute().name() : node.node().name();
 	}
 
-	PUGI__FN const char_t* local_name(const xpath_node& node)
+	PUGI_IMPL_FN const char_t* local_name(const xpath_node& node)
 	{
 		const char_t* name = qualified_name(node);
 		const char_t* p = find_char(name, ':');
@@ -8627,7 +8694,7 @@
 		}
 	};
 
-	PUGI__FN const char_t* namespace_uri(xml_node node)
+	PUGI_IMPL_FN const char_t* namespace_uri(xml_node node)
 	{
 		namespace_uri_predicate pred = node.name();
 
@@ -8645,7 +8712,7 @@
 		return PUGIXML_TEXT("");
 	}
 
-	PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent)
+	PUGI_IMPL_FN const char_t* namespace_uri(xml_attribute attr, xml_node parent)
 	{
 		namespace_uri_predicate pred = attr.name();
 
@@ -8666,12 +8733,12 @@
 		return PUGIXML_TEXT("");
 	}
 
-	PUGI__FN const char_t* namespace_uri(const xpath_node& node)
+	PUGI_IMPL_FN const char_t* namespace_uri(const xpath_node& node)
 	{
 		return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
 	}
 
-	PUGI__FN char_t* normalize_space(char_t* buffer)
+	PUGI_IMPL_FN char_t* normalize_space(char_t* buffer)
 	{
 		char_t* write = buffer;
 
@@ -8679,10 +8746,10 @@
 		{
 			char_t ch = *it++;
 
-			if (PUGI__IS_CHARTYPE(ch, ct_space))
+			if (PUGI_IMPL_IS_CHARTYPE(ch, ct_space))
 			{
 				// replace whitespace sequence with single space
-				while (PUGI__IS_CHARTYPE(*it, ct_space)) it++;
+				while (PUGI_IMPL_IS_CHARTYPE(*it, ct_space)) it++;
 
 				// avoid leading spaces
 				if (write != buffer) *write++ = ' ';
@@ -8691,7 +8758,7 @@
 		}
 
 		// remove trailing space
-		if (write != buffer && PUGI__IS_CHARTYPE(write[-1], ct_space)) write--;
+		if (write != buffer && PUGI_IMPL_IS_CHARTYPE(write[-1], ct_space)) write--;
 
 		// zero-terminate
 		*write = 0;
@@ -8699,13 +8766,13 @@
 		return write;
 	}
 
-	PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)
+	PUGI_IMPL_FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)
 	{
 		char_t* write = buffer;
 
 		while (*buffer)
 		{
-			PUGI__DMC_VOLATILE char_t ch = *buffer++;
+			PUGI_IMPL_DMC_VOLATILE char_t ch = *buffer++;
 
 			const char_t* pos = find_char(from, ch);
 
@@ -8721,7 +8788,7 @@
 		return write;
 	}
 
-	PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to)
+	PUGI_IMPL_FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to)
 	{
 		unsigned char table[128] = {0};
 
@@ -8753,7 +8820,7 @@
 		return static_cast<unsigned char*>(result);
 	}
 
-	PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table)
+	PUGI_IMPL_FN char_t* translate_table(char_t* buffer, const unsigned char* table)
 	{
 		char_t* write = buffer;
 
@@ -8835,7 +8902,7 @@
 
 	static const xpath_node_set dummy_node_set;
 
-	PUGI__FN PUGI__UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str)
+	PUGI_IMPL_FN PUGI_IMPL_UNSIGNED_OVERFLOW unsigned int hash_string(const char_t* str)
 	{
 		// Jenkins one-at-a-time hash (http://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time)
 		unsigned int result = 0;
@@ -8854,7 +8921,7 @@
 		return result;
 	}
 
-	template <typename T> PUGI__FN T* new_xpath_variable(const char_t* name)
+	template <typename T> PUGI_IMPL_FN T* new_xpath_variable(const char_t* name)
 	{
 		size_t length = strlength(name);
 		if (length == 0) return 0; // empty variable names are invalid
@@ -8870,7 +8937,7 @@
 		return result;
 	}
 
-	PUGI__FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
+	PUGI_IMPL_FN xpath_variable* new_xpath_variable(xpath_value_type type, const char_t* name)
 	{
 		switch (type)
 		{
@@ -8891,13 +8958,13 @@
 		}
 	}
 
-	template <typename T> PUGI__FN void delete_xpath_variable(T* var)
+	template <typename T> PUGI_IMPL_FN void delete_xpath_variable(T* var)
 	{
 		var->~T();
 		xml_memory::deallocate(var);
 	}
 
-	PUGI__FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
+	PUGI_IMPL_FN void delete_xpath_variable(xpath_value_type type, xpath_variable* var)
 	{
 		switch (type)
 		{
@@ -8922,7 +8989,7 @@
 		}
 	}
 
-	PUGI__FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs)
+	PUGI_IMPL_FN bool copy_xpath_variable(xpath_variable* lhs, const xpath_variable* rhs)
 	{
 		switch (rhs->type())
 		{
@@ -8944,7 +9011,7 @@
 		}
 	}
 
-	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)
+	PUGI_IMPL_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)
 	{
 		size_t length = static_cast<size_t>(end - begin);
 		char_t* scratch = buffer;
@@ -8967,11 +9034,11 @@
 
 		return true;
 	}
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 // Internal node set class
-PUGI__NS_BEGIN
-	PUGI__FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end)
+PUGI_IMPL_NS_BEGIN
+	PUGI_IMPL_FN xpath_node_set::type_t xpath_get_order(const xpath_node* begin, const xpath_node* end)
 	{
 		if (end - begin < 2)
 			return xpath_node_set::type_sorted;
@@ -8987,7 +9054,7 @@
 		return first ? xpath_node_set::type_sorted : xpath_node_set::type_sorted_reverse;
 	}
 
-	PUGI__FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
+	PUGI_IMPL_FN xpath_node_set::type_t xpath_sort(xpath_node* begin, xpath_node* end, xpath_node_set::type_t type, bool rev)
 	{
 		xpath_node_set::type_t order = rev ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
 
@@ -9010,7 +9077,7 @@
 		return order;
 	}
 
-	PUGI__FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
+	PUGI_IMPL_FN xpath_node xpath_first(const xpath_node* begin, const xpath_node* end, xpath_node_set::type_t type)
 	{
 		if (begin == end) return xpath_node();
 
@@ -9164,7 +9231,7 @@
 		}
 	};
 
-	PUGI__FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc)
+	PUGI_IMPL_FN_NO_INLINE void xpath_node_set_raw::push_back_grow(const xpath_node& node, xpath_allocator* alloc)
 	{
 		size_t capacity = static_cast<size_t>(_eos - _begin);
 
@@ -9183,9 +9250,9 @@
 		// push
 		*_end++ = node;
 	}
-PUGI__NS_END
-
-PUGI__NS_BEGIN
+PUGI_IMPL_NS_END
+
+PUGI_IMPL_NS_BEGIN
 	struct xpath_context
 	{
 		xpath_node n;
@@ -9267,7 +9334,7 @@
 		{
 			const char_t* cur = _cur;
 
-			while (PUGI__IS_CHARTYPE(*cur, ct_space)) ++cur;
+			while (PUGI_IMPL_IS_CHARTYPE(*cur, ct_space)) ++cur;
 
 			// save lexeme position for error reporting
 			_cur_lexeme_pos = cur;
@@ -9349,17 +9416,17 @@
 			case '$':
 				cur += 1;
 
-				if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
+				if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_start_symbol))
 				{
 					_cur_lexeme_contents.begin = cur;
 
-					while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
-
-					if (cur[0] == ':' && PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
+					while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
+
+					if (cur[0] == ':' && PUGI_IMPL_IS_CHARTYPEX(cur[1], ctx_symbol)) // qname
 					{
 						cur++; // :
 
-						while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
+						while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
 					}
 
 					_cur_lexeme_contents.end = cur;
@@ -9422,13 +9489,13 @@
 					cur += 2;
 					_cur_lexeme = lex_double_dot;
 				}
-				else if (PUGI__IS_CHARTYPEX(*(cur+1), ctx_digit))
+				else if (PUGI_IMPL_IS_CHARTYPEX(*(cur+1), ctx_digit))
 				{
 					_cur_lexeme_contents.begin = cur; // .
 
 					++cur;
 
-					while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
+					while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++;
 
 					_cur_lexeme_contents.end = cur;
 
@@ -9482,28 +9549,28 @@
 				break;
 
 			default:
-				if (PUGI__IS_CHARTYPEX(*cur, ctx_digit))
+				if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit))
 				{
 					_cur_lexeme_contents.begin = cur;
 
-					while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
+					while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++;
 
 					if (*cur == '.')
 					{
 						cur++;
 
-						while (PUGI__IS_CHARTYPEX(*cur, ctx_digit)) cur++;
+						while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_digit)) cur++;
 					}
 
 					_cur_lexeme_contents.end = cur;
 
 					_cur_lexeme = lex_number;
 				}
-				else if (PUGI__IS_CHARTYPEX(*cur, ctx_start_symbol))
+				else if (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_start_symbol))
 				{
 					_cur_lexeme_contents.begin = cur;
 
-					while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
+					while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
 
 					if (cur[0] == ':')
 					{
@@ -9511,11 +9578,11 @@
 						{
 							cur += 2; // :*
 						}
-						else if (PUGI__IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
+						else if (PUGI_IMPL_IS_CHARTYPEX(cur[1], ctx_symbol)) // namespace test qname
 						{
 							cur++; // :
 
-							while (PUGI__IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
+							while (PUGI_IMPL_IS_CHARTYPEX(*cur, ctx_symbol)) cur++;
 						}
 					}
 
@@ -9927,7 +9994,8 @@
 
 			xpath_node* last = ns.begin() + first;
 
-			xpath_context c(xpath_node(), 1, size);
+			xpath_node cn;
+			xpath_context c(cn, 1, size);
 
 			double er = expr->eval_number(c, stack);
 
@@ -10014,7 +10082,7 @@
 		{
 			assert(n);
 
-			xml_node_type type = PUGI__NODETYPE(n);
+			xml_node_type type = PUGI_IMPL_NODETYPE(n);
 
 			switch (_test)
 			{
@@ -12037,7 +12105,7 @@
 					// This is either a function call, or not - if not, we shall proceed with location path
 					const char_t* state = _lexer.state();
 
-					while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
+					while (PUGI_IMPL_IS_CHARTYPE(*state, ct_space)) ++state;
 
 					if (*state != '(')
 						return parse_location_path();
@@ -12280,7 +12348,7 @@
 		bool oom;
 	};
 
-	PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)
+	PUGI_IMPL_FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)
 	{
 		if (!impl) return 0;
 
@@ -12298,91 +12366,91 @@
 
 		return impl->root;
 	}
-PUGI__NS_END
+PUGI_IMPL_NS_END
 
 namespace pugi
 {
 #ifndef PUGIXML_NO_EXCEPTIONS
-	PUGI__FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_)
+	PUGI_IMPL_FN xpath_exception::xpath_exception(const xpath_parse_result& result_): _result(result_)
 	{
 		assert(_result.error);
 	}
 
-	PUGI__FN const char* xpath_exception::what() const throw()
+	PUGI_IMPL_FN const char* xpath_exception::what() const throw()
 	{
 		return _result.error;
 	}
 
-	PUGI__FN const xpath_parse_result& xpath_exception::result() const
+	PUGI_IMPL_FN const xpath_parse_result& xpath_exception::result() const
 	{
 		return _result;
 	}
 #endif
 
-	PUGI__FN xpath_node::xpath_node()
-	{
-	}
-
-	PUGI__FN xpath_node::xpath_node(const xml_node& node_): _node(node_)
-	{
-	}
-
-	PUGI__FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
-	{
-	}
-
-	PUGI__FN xml_node xpath_node::node() const
+	PUGI_IMPL_FN xpath_node::xpath_node()
+	{
+	}
+
+	PUGI_IMPL_FN xpath_node::xpath_node(const xml_node& node_): _node(node_)
+	{
+	}
+
+	PUGI_IMPL_FN xpath_node::xpath_node(const xml_attribute& attribute_, const xml_node& parent_): _node(attribute_ ? parent_ : xml_node()), _attribute(attribute_)
+	{
+	}
+
+	PUGI_IMPL_FN xml_node xpath_node::node() const
 	{
 		return _attribute ? xml_node() : _node;
 	}
 
-	PUGI__FN xml_attribute xpath_node::attribute() const
+	PUGI_IMPL_FN xml_attribute xpath_node::attribute() const
 	{
 		return _attribute;
 	}
 
-	PUGI__FN xml_node xpath_node::parent() const
+	PUGI_IMPL_FN xml_node xpath_node::parent() const
 	{
 		return _attribute ? _node : _node.parent();
 	}
 
-	PUGI__FN static void unspecified_bool_xpath_node(xpath_node***)
-	{
-	}
-
-	PUGI__FN xpath_node::operator xpath_node::unspecified_bool_type() const
+	PUGI_IMPL_FN static void unspecified_bool_xpath_node(xpath_node***)
+	{
+	}
+
+	PUGI_IMPL_FN xpath_node::operator xpath_node::unspecified_bool_type() const
 	{
 		return (_node || _attribute) ? unspecified_bool_xpath_node : 0;
 	}
 
-	PUGI__FN bool xpath_node::operator!() const
+	PUGI_IMPL_FN bool xpath_node::operator!() const
 	{
 		return !(_node || _attribute);
 	}
 
-	PUGI__FN bool xpath_node::operator==(const xpath_node& n) const
+	PUGI_IMPL_FN bool xpath_node::operator==(const xpath_node& n) const
 	{
 		return _node == n._node && _attribute == n._attribute;
 	}
 
-	PUGI__FN bool xpath_node::operator!=(const xpath_node& n) const
+	PUGI_IMPL_FN bool xpath_node::operator!=(const xpath_node& n) const
 	{
 		return _node != n._node || _attribute != n._attribute;
 	}
 
 #ifdef __BORLANDC__
-	PUGI__FN bool operator&&(const xpath_node& lhs, bool rhs)
+	PUGI_IMPL_FN bool operator&&(const xpath_node& lhs, bool rhs)
 	{
 		return (bool)lhs && rhs;
 	}
 
-	PUGI__FN bool operator||(const xpath_node& lhs, bool rhs)
+	PUGI_IMPL_FN bool operator||(const xpath_node& lhs, bool rhs)
 	{
 		return (bool)lhs || rhs;
 	}
 #endif
 
-	PUGI__FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)
+	PUGI_IMPL_FN void xpath_node_set::_assign(const_iterator begin_, const_iterator end_, type_t type_)
 	{
 		assert(begin_ <= end_);
 
@@ -12414,7 +12482,7 @@
 	}
 
 #ifdef PUGIXML_HAS_MOVE
-	PUGI__FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT
+	PUGI_IMPL_FN void xpath_node_set::_move(xpath_node_set& rhs) PUGIXML_NOEXCEPT
 	{
 		_type = rhs._type;
 		_storage[0] = rhs._storage[0];
@@ -12427,27 +12495,27 @@
 	}
 #endif
 
-	PUGI__FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage)
-	{
-	}
-
-	PUGI__FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage)
+	PUGI_IMPL_FN xpath_node_set::xpath_node_set(): _type(type_unsorted), _begin(_storage), _end(_storage)
+	{
+	}
+
+	PUGI_IMPL_FN xpath_node_set::xpath_node_set(const_iterator begin_, const_iterator end_, type_t type_): _type(type_unsorted), _begin(_storage), _end(_storage)
 	{
 		_assign(begin_, end_, type_);
 	}
 
-	PUGI__FN xpath_node_set::~xpath_node_set()
+	PUGI_IMPL_FN xpath_node_set::~xpath_node_set()
 	{
 		if (_begin != _storage)
 			impl::xml_memory::deallocate(_begin);
 	}
 
-	PUGI__FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage)
+	PUGI_IMPL_FN xpath_node_set::xpath_node_set(const xpath_node_set& ns): _type(type_unsorted), _begin(_storage), _end(_storage)
 	{
 		_assign(ns._begin, ns._end, ns._type);
 	}
 
-	PUGI__FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
+	PUGI_IMPL_FN xpath_node_set& xpath_node_set::operator=(const xpath_node_set& ns)
 	{
 		if (this == &ns) return *this;
 
@@ -12457,12 +12525,12 @@
 	}
 
 #ifdef PUGIXML_HAS_MOVE
-	PUGI__FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage)
+	PUGI_IMPL_FN xpath_node_set::xpath_node_set(xpath_node_set&& rhs) PUGIXML_NOEXCEPT: _type(type_unsorted), _begin(_storage), _end(_storage)
 	{
 		_move(rhs);
 	}
 
-	PUGI__FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT
+	PUGI_IMPL_FN xpath_node_set& xpath_node_set::operator=(xpath_node_set&& rhs) PUGIXML_NOEXCEPT
 	{
 		if (this == &rhs) return *this;
 
@@ -12475,66 +12543,66 @@
 	}
 #endif
 
-	PUGI__FN xpath_node_set::type_t xpath_node_set::type() const
+	PUGI_IMPL_FN xpath_node_set::type_t xpath_node_set::type() const
 	{
 		return _type;
 	}
 
-	PUGI__FN size_t xpath_node_set::size() const
+	PUGI_IMPL_FN size_t xpath_node_set::size() const
 	{
 		return _end - _begin;
 	}
 
-	PUGI__FN bool xpath_node_set::empty() const
+	PUGI_IMPL_FN bool xpath_node_set::empty() const
 	{
 		return _begin == _end;
 	}
 
-	PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const
+	PUGI_IMPL_FN const xpath_node& xpath_node_set::operator[](size_t index) const
 	{
 		assert(index < size());
 		return _begin[index];
 	}
 
-	PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const
+	PUGI_IMPL_FN xpath_node_set::const_iterator xpath_node_set::begin() const
 	{
 		return _begin;
 	}
 
-	PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const
+	PUGI_IMPL_FN xpath_node_set::const_iterator xpath_node_set::end() const
 	{
 		return _end;
 	}
 
-	PUGI__FN void xpath_node_set::sort(bool reverse)
+	PUGI_IMPL_FN void xpath_node_set::sort(bool reverse)
 	{
 		_type = impl::xpath_sort(_begin, _end, _type, reverse);
 	}
 
-	PUGI__FN xpath_node xpath_node_set::first() const
+	PUGI_IMPL_FN xpath_node xpath_node_set::first() const
 	{
 		return impl::xpath_first(_begin, _end, _type);
 	}
 
-	PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
-	{
-	}
-
-	PUGI__FN xpath_parse_result::operator bool() const
+	PUGI_IMPL_FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
+	{
+	}
+
+	PUGI_IMPL_FN xpath_parse_result::operator bool() const
 	{
 		return error == 0;
 	}
 
-	PUGI__FN const char* xpath_parse_result::description() const
+	PUGI_IMPL_FN const char* xpath_parse_result::description() const
 	{
 		return error ? error : "No error";
 	}
 
-	PUGI__FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0)
-	{
-	}
-
-	PUGI__FN const char_t* xpath_variable::name() const
+	PUGI_IMPL_FN xpath_variable::xpath_variable(xpath_value_type type_): _type(type_), _next(0)
+	{
+	}
+
+	PUGI_IMPL_FN const char_t* xpath_variable::name() const
 	{
 		switch (_type)
 		{
@@ -12556,33 +12624,33 @@
 		}
 	}
 
-	PUGI__FN xpath_value_type xpath_variable::type() const
+	PUGI_IMPL_FN xpath_value_type xpath_variable::type() const
 	{
 		return _type;
 	}
 
-	PUGI__FN bool xpath_variable::get_boolean() const
+	PUGI_IMPL_FN bool xpath_variable::get_boolean() const
 	{
 		return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
 	}
 
-	PUGI__FN double xpath_variable::get_number() const
+	PUGI_IMPL_FN double xpath_variable::get_number() const
 	{
 		return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();
 	}
 
-	PUGI__FN const char_t* xpath_variable::get_string() const
+	PUGI_IMPL_FN const char_t* xpath_variable::get_string() const
 	{
 		const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0;
 		return value ? value : PUGIXML_TEXT("");
 	}
 
-	PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const
+	PUGI_IMPL_FN const xpath_node_set& xpath_variable::get_node_set() const
 	{
 		return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
 	}
 
-	PUGI__FN bool xpath_variable::set(bool value)
+	PUGI_IMPL_FN bool xpath_variable::set(bool value)
 	{
 		if (_type != xpath_type_boolean) return false;
 
@@ -12590,7 +12658,7 @@
 		return true;
 	}
 
-	PUGI__FN bool xpath_variable::set(double value)
+	PUGI_IMPL_FN bool xpath_variable::set(double value)
 	{
 		if (_type != xpath_type_number) return false;
 
@@ -12598,7 +12666,7 @@
 		return true;
 	}
 
-	PUGI__FN bool xpath_variable::set(const char_t* value)
+	PUGI_IMPL_FN bool xpath_variable::set(const char_t* value)
 	{
 		if (_type != xpath_type_string) return false;
 
@@ -12619,7 +12687,7 @@
 		return true;
 	}
 
-	PUGI__FN bool xpath_variable::set(const xpath_node_set& value)
+	PUGI_IMPL_FN bool xpath_variable::set(const xpath_node_set& value)
 	{
 		if (_type != xpath_type_node_set) return false;
 
@@ -12627,19 +12695,19 @@
 		return true;
 	}
 
-	PUGI__FN xpath_variable_set::xpath_variable_set()
+	PUGI_IMPL_FN xpath_variable_set::xpath_variable_set()
 	{
 		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
 			_data[i] = 0;
 	}
 
-	PUGI__FN xpath_variable_set::~xpath_variable_set()
+	PUGI_IMPL_FN xpath_variable_set::~xpath_variable_set()
 	{
 		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
 			_destroy(_data[i]);
 	}
 
-	PUGI__FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs)
+	PUGI_IMPL_FN xpath_variable_set::xpath_variable_set(const xpath_variable_set& rhs)
 	{
 		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
 			_data[i] = 0;
@@ -12647,7 +12715,7 @@
 		_assign(rhs);
 	}
 
-	PUGI__FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs)
+	PUGI_IMPL_FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs)
 	{
 		if (this == &rhs) return *this;
 
@@ -12657,7 +12725,7 @@
 	}
 
 #ifdef PUGIXML_HAS_MOVE
-	PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT
+	PUGI_IMPL_FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT
 	{
 		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
 		{
@@ -12666,7 +12734,7 @@
 		}
 	}
 
-	PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT
+	PUGI_IMPL_FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs) PUGIXML_NOEXCEPT
 	{
 		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
 		{
@@ -12680,7 +12748,7 @@
 	}
 #endif
 
-	PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs)
+	PUGI_IMPL_FN void xpath_variable_set::_assign(const xpath_variable_set& rhs)
 	{
 		xpath_variable_set temp;
 
@@ -12691,7 +12759,7 @@
 		_swap(temp);
 	}
 
-	PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs)
+	PUGI_IMPL_FN void xpath_variable_set::_swap(xpath_variable_set& rhs)
 	{
 		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
 		{
@@ -12702,7 +12770,7 @@
 		}
 	}
 
-	PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const
+	PUGI_IMPL_FN xpath_variable* xpath_variable_set::_find(const char_t* name) const
 	{
 		const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
 		size_t hash = impl::hash_string(name) % hash_size;
@@ -12715,7 +12783,7 @@
 		return 0;
 	}
 
-	PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)
+	PUGI_IMPL_FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)
 	{
 		xpath_variable* last = 0;
 
@@ -12742,7 +12810,7 @@
 		return true;
 	}
 
-	PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var)
+	PUGI_IMPL_FN void xpath_variable_set::_destroy(xpath_variable* var)
 	{
 		while (var)
 		{
@@ -12754,7 +12822,7 @@
 		}
 	}
 
-	PUGI__FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
+	PUGI_IMPL_FN xpath_variable* xpath_variable_set::add(const char_t* name, xpath_value_type type)
 	{
 		const size_t hash_size = sizeof(_data) / sizeof(_data[0]);
 		size_t hash = impl::hash_string(name) % hash_size;
@@ -12777,41 +12845,41 @@
 		return result;
 	}
 
-	PUGI__FN bool xpath_variable_set::set(const char_t* name, bool value)
+	PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, bool value)
 	{
 		xpath_variable* var = add(name, xpath_type_boolean);
 		return var ? var->set(value) : false;
 	}
 
-	PUGI__FN bool xpath_variable_set::set(const char_t* name, double value)
+	PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, double value)
 	{
 		xpath_variable* var = add(name, xpath_type_number);
 		return var ? var->set(value) : false;
 	}
 
-	PUGI__FN bool xpath_variable_set::set(const char_t* name, const char_t* value)
+	PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, const char_t* value)
 	{
 		xpath_variable* var = add(name, xpath_type_string);
 		return var ? var->set(value) : false;
 	}
 
-	PUGI__FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
+	PUGI_IMPL_FN bool xpath_variable_set::set(const char_t* name, const xpath_node_set& value)
 	{
 		xpath_variable* var = add(name, xpath_type_node_set);
 		return var ? var->set(value) : false;
 	}
 
-	PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name)
+	PUGI_IMPL_FN xpath_variable* xpath_variable_set::get(const char_t* name)
 	{
 		return _find(name);
 	}
 
-	PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
+	PUGI_IMPL_FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
 	{
 		return _find(name);
 	}
 
-	PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
+	PUGI_IMPL_FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
 	{
 		impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
 
@@ -12849,18 +12917,18 @@
 		}
 	}
 
-	PUGI__FN xpath_query::xpath_query(): _impl(0)
-	{
-	}
-
-	PUGI__FN xpath_query::~xpath_query()
+	PUGI_IMPL_FN xpath_query::xpath_query(): _impl(0)
+	{
+	}
+
+	PUGI_IMPL_FN xpath_query::~xpath_query()
 	{
 		if (_impl)
 			impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
 	}
 
 #ifdef PUGIXML_HAS_MOVE
-	PUGI__FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT
+	PUGI_IMPL_FN xpath_query::xpath_query(xpath_query&& rhs) PUGIXML_NOEXCEPT
 	{
 		_impl = rhs._impl;
 		_result = rhs._result;
@@ -12868,7 +12936,7 @@
 		rhs._result = xpath_parse_result();
 	}
 
-	PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT
+	PUGI_IMPL_FN xpath_query& xpath_query::operator=(xpath_query&& rhs) PUGIXML_NOEXCEPT
 	{
 		if (this == &rhs) return *this;
 
@@ -12884,14 +12952,14 @@
 	}
 #endif
 
-	PUGI__FN xpath_value_type xpath_query::return_type() const
+	PUGI_IMPL_FN xpath_value_type xpath_query::return_type() const
 	{
 		if (!_impl) return xpath_type_none;
 
 		return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();
 	}
 
-	PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const
+	PUGI_IMPL_FN bool xpath_query::evaluate_boolean(const xpath_node& n) const
 	{
 		if (!_impl) return false;
 
@@ -12912,7 +12980,7 @@
 		return r;
 	}
 
-	PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
+	PUGI_IMPL_FN double xpath_query::evaluate_number(const xpath_node& n) const
 	{
 		if (!_impl) return impl::gen_nan();
 
@@ -12934,7 +13002,7 @@
 	}
 
 #ifndef PUGIXML_NO_STL
-	PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const
+	PUGI_IMPL_FN string_t xpath_query::evaluate_string(const xpath_node& n) const
 	{
 		if (!_impl) return string_t();
 
@@ -12956,7 +13024,7 @@
 	}
 #endif
 
-	PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
+	PUGI_IMPL_FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
 	{
 		impl::xpath_context c(n, 1, 1);
 		impl::xpath_stack_data sd;
@@ -12986,7 +13054,7 @@
 		return full_size;
 	}
 
-	PUGI__FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const
+	PUGI_IMPL_FN xpath_node_set xpath_query::evaluate_node_set(const xpath_node& n) const
 	{
 		impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
 		if (!root) return xpath_node_set();
@@ -13008,7 +13076,7 @@
 		return xpath_node_set(r.begin(), r.end(), r.type());
 	}
 
-	PUGI__FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const
+	PUGI_IMPL_FN xpath_node xpath_query::evaluate_node(const xpath_node& n) const
 	{
 		impl::xpath_ast_node* root = impl::evaluate_node_set_prepare(static_cast<impl::xpath_query_impl*>(_impl));
 		if (!root) return xpath_node();
@@ -13030,54 +13098,54 @@
 		return r.first();
 	}
 
-	PUGI__FN const xpath_parse_result& xpath_query::result() const
+	PUGI_IMPL_FN const xpath_parse_result& xpath_query::result() const
 	{
 		return _result;
 	}
 
-	PUGI__FN static void unspecified_bool_xpath_query(xpath_query***)
-	{
-	}
-
-	PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
+	PUGI_IMPL_FN static void unspecified_bool_xpath_query(xpath_query***)
+	{
+	}
+
+	PUGI_IMPL_FN xpath_query::operator xpath_query::unspecified_bool_type() const
 	{
 		return _impl ? unspecified_bool_xpath_query : 0;
 	}
 
-	PUGI__FN bool xpath_query::operator!() const
+	PUGI_IMPL_FN bool xpath_query::operator!() const
 	{
 		return !_impl;
 	}
 
-	PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const
+	PUGI_IMPL_FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const
 	{
 		xpath_query q(query, variables);
 		return q.evaluate_node(*this);
 	}
 
-	PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const
+	PUGI_IMPL_FN xpath_node xml_node::select_node(const xpath_query& query) const
 	{
 		return query.evaluate_node(*this);
 	}
 
-	PUGI__FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const
+	PUGI_IMPL_FN xpath_node_set xml_node::select_nodes(const char_t* query, xpath_variable_set* variables) const
 	{
 		xpath_query q(query, variables);
 		return q.evaluate_node_set(*this);
 	}
 
-	PUGI__FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const
+	PUGI_IMPL_FN xpath_node_set xml_node::select_nodes(const xpath_query& query) const
 	{
 		return query.evaluate_node_set(*this);
 	}
 
-	PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const
+	PUGI_IMPL_FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const
 	{
 		xpath_query q(query, variables);
 		return q.evaluate_node(*this);
 	}
 
-	PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const
+	PUGI_IMPL_FN xpath_node xml_node::select_single_node(const xpath_query& query) const
 	{
 		return query.evaluate_node(*this);
 	}
@@ -13100,40 +13168,40 @@
 #endif
 
 // Undefine all local macros (makes sure we're not leaking macros in header-only mode)
-#undef PUGI__NO_INLINE
-#undef PUGI__UNLIKELY
-#undef PUGI__STATIC_ASSERT
-#undef PUGI__DMC_VOLATILE
-#undef PUGI__UNSIGNED_OVERFLOW
-#undef PUGI__MSVC_CRT_VERSION
-#undef PUGI__SNPRINTF
-#undef PUGI__NS_BEGIN
-#undef PUGI__NS_END
-#undef PUGI__FN
-#undef PUGI__FN_NO_INLINE
-#undef PUGI__GETHEADER_IMPL
-#undef PUGI__GETPAGE_IMPL
-#undef PUGI__GETPAGE
-#undef PUGI__NODETYPE
-#undef PUGI__IS_CHARTYPE_IMPL
-#undef PUGI__IS_CHARTYPE
-#undef PUGI__IS_CHARTYPEX
-#undef PUGI__ENDSWITH
-#undef PUGI__SKIPWS
-#undef PUGI__OPTSET
-#undef PUGI__PUSHNODE
-#undef PUGI__POPNODE
-#undef PUGI__SCANFOR
-#undef PUGI__SCANWHILE
-#undef PUGI__SCANWHILE_UNROLL
-#undef PUGI__ENDSEG
-#undef PUGI__THROW_ERROR
-#undef PUGI__CHECK_ERROR
+#undef PUGI_IMPL_NO_INLINE
+#undef PUGI_IMPL_UNLIKELY
+#undef PUGI_IMPL_STATIC_ASSERT
+#undef PUGI_IMPL_DMC_VOLATILE
+#undef PUGI_IMPL_UNSIGNED_OVERFLOW
+#undef PUGI_IMPL_MSVC_CRT_VERSION
+#undef PUGI_IMPL_SNPRINTF
+#undef PUGI_IMPL_NS_BEGIN
+#undef PUGI_IMPL_NS_END
+#undef PUGI_IMPL_FN
+#undef PUGI_IMPL_FN_NO_INLINE
+#undef PUGI_IMPL_GETHEADER_IMPL
+#undef PUGI_IMPL_GETPAGE_IMPL
+#undef PUGI_IMPL_GETPAGE
+#undef PUGI_IMPL_NODETYPE
+#undef PUGI_IMPL_IS_CHARTYPE_IMPL
+#undef PUGI_IMPL_IS_CHARTYPE
+#undef PUGI_IMPL_IS_CHARTYPEX
+#undef PUGI_IMPL_ENDSWITH
+#undef PUGI_IMPL_SKIPWS
+#undef PUGI_IMPL_OPTSET
+#undef PUGI_IMPL_PUSHNODE
+#undef PUGI_IMPL_POPNODE
+#undef PUGI_IMPL_SCANFOR
+#undef PUGI_IMPL_SCANWHILE
+#undef PUGI_IMPL_SCANWHILE_UNROLL
+#undef PUGI_IMPL_ENDSEG
+#undef PUGI_IMPL_THROW_ERROR
+#undef PUGI_IMPL_CHECK_ERROR
 
 #endif
 
 /**
- * Copyright (c) 2006-2022 Arseny Kapoulkine
+ * Copyright (c) 2006-2023 Arseny Kapoulkine
  *
  * Permission is hereby granted, free of charge, to any person
  * obtaining a copy of this software and associated documentation