From e9956ae3a6593efc6f8cb344a00432ece51d1574 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Mon, 17 Nov 2014 19:52:23 -0800
Subject: Rename xml_document::load to load_string

This should completely eliminate the confusion between load and load_file.
Of course, for compatibility reasons we have to preserve the old variant -
it will be deprecated in a future version and subsequently removed.
---
 src/pugixml.cpp | 7 ++++++-
 src/pugixml.hpp | 5 ++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 884184c..852ccb9 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -5995,7 +5995,7 @@ namespace pugi
 	}
 #endif
 
-	PUGI__FN xml_parse_result xml_document::load(const char_t* contents, unsigned int options)
+	PUGI__FN xml_parse_result xml_document::load_string(const char_t* contents, unsigned int options)
 	{
 		// Force native encoding (skip autodetection)
 	#ifdef PUGIXML_WCHAR_MODE
@@ -6007,6 +6007,11 @@ namespace pugi
 		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)
+	{
+		return load_string(contents, options);
+	}
+
 	PUGI__FN xml_parse_result xml_document::load_file(const char* path_, unsigned int options, xml_encoding encoding)
 	{
 		reset();
diff --git a/src/pugixml.hpp b/src/pugixml.hpp
index e252e16..7f52975 100644
--- a/src/pugixml.hpp
+++ b/src/pugixml.hpp
@@ -959,9 +959,12 @@ namespace pugi
 		xml_parse_result load(std::basic_istream<wchar_t, std::char_traits<wchar_t> >& stream, unsigned int options = parse_default);
 	#endif
 
-		// Load document from zero-terminated string. No encoding conversions are applied.
+		// (deprecated: use load_string instead) Load document from zero-terminated string. No encoding conversions are applied.
 		xml_parse_result load(const char_t* contents, unsigned int options = parse_default);
 
+		// Load document from zero-terminated string. No encoding conversions are applied.
+		xml_parse_result load_string(const char_t* contents, unsigned int options = parse_default);
+
 		// Load document from file
 		xml_parse_result load_file(const char* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
 		xml_parse_result load_file(const wchar_t* path, unsigned int options = parse_default, xml_encoding encoding = encoding_auto);
-- 
cgit v1.2.3


From b041e94f29fee9800f02ca6c257fe6cea4eae72a Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Mon, 17 Nov 2014 21:47:37 -0800
Subject: Update version to 1.5

---
 src/pugiconfig.hpp | 2 +-
 src/pugixml.cpp    | 2 +-
 src/pugixml.hpp    | 4 ++--
 3 files changed, 4 insertions(+), 4 deletions(-)

(limited to 'src')

diff --git a/src/pugiconfig.hpp b/src/pugiconfig.hpp
index 56f1d22..1c216e3 100644
--- a/src/pugiconfig.hpp
+++ b/src/pugiconfig.hpp
@@ -1,5 +1,5 @@
 /**
- * pugixml parser - version 1.4
+ * pugixml parser - version 1.5
  * --------------------------------------------------------
  * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
  * Report bugs and download new versions at http://pugixml.org/
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 852ccb9..3f6b2fd 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -1,6 +1,6 @@
 /**
 {
- * pugixml parser - version 1.4
+ * pugixml parser - version 1.5
  * --------------------------------------------------------
  * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
  * Report bugs and download new versions at http://pugixml.org/
diff --git a/src/pugixml.hpp b/src/pugixml.hpp
index 7f52975..917ef4a 100644
--- a/src/pugixml.hpp
+++ b/src/pugixml.hpp
@@ -1,5 +1,5 @@
 /**
- * pugixml parser - version 1.4
+ * pugixml parser - version 1.5
  * --------------------------------------------------------
  * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
  * Report bugs and download new versions at http://pugixml.org/
@@ -13,7 +13,7 @@
 
 #ifndef PUGIXML_VERSION
 // Define version macro; evaluates to major * 100 + minor so that it's safe to use in less-than comparisons
-#	define PUGIXML_VERSION 140
+#	define PUGIXML_VERSION 150
 #endif
 
 // Include user configuration file (this can define various configuration macros)
-- 
cgit v1.2.3


From 5c5038c264ed7ecb02048257b956e5206c07a566 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Wed, 19 Nov 2014 19:50:40 -0800
Subject: Change has_declaration to work on node pointers

This is more for consistency with the surrounding code than for performance.
---
 src/pugixml.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 3f6b2fd..f2f1dd9 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -3658,11 +3658,11 @@ PUGI__NS_BEGIN
 		while (node != root);
 	}
 
-	PUGI__FN bool has_declaration(xml_node node)
+	PUGI__FN bool has_declaration(xml_node_struct* node)
 	{
-		for (xml_node child = node.first_child(); child; child = child.next_sibling())
+		for (xml_node_struct* child = node->first_child; child; child = child->next_sibling)
 		{
-			xml_node_type type = child.type();
+			xml_node_type type = PUGI__NODETYPE(child);
 
 			if (type == node_declaration) return true;
 			if (type == node_element) return false;
@@ -6066,7 +6066,7 @@ namespace pugi
 		#endif
 		}
 
-		if (!(flags & format_no_declaration) && !impl::has_declaration(*this))
+		if (!(flags & format_no_declaration) && !impl::has_declaration(_root))
 		{
 			buffered_writer.write_string(PUGIXML_TEXT("<?xml version=\"1.0\""));
 			if (encoding == encoding_latin1) buffered_writer.write_string(PUGIXML_TEXT(" encoding=\"ISO-8859-1\""));
-- 
cgit v1.2.3


From 853b1977b83797ce4ceb9d235f0dafad344b2270 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Wed, 19 Nov 2014 20:56:06 -0800
Subject: Add more assertions for page memory handling code

---
 src/pugixml.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index f2f1dd9..90befd8 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -1,5 +1,4 @@
 /**
-{
  * pugixml parser - version 1.5
  * --------------------------------------------------------
  * Copyright (C) 2006-2014, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
@@ -326,7 +325,7 @@ PUGI__NS_BEGIN
 			void* memory = xml_memory::allocate(size + xml_memory_page_alignment);
 			if (!memory) return 0;
 
-			// align upwards to page boundary (note: this guarantees at least 1 usable byte before the page)
+			// align to next page boundary (note: this guarantees at least 1 usable byte before the page)
 			char* page_memory = reinterpret_cast<char*>((reinterpret_cast<uintptr_t>(memory) + xml_memory_page_alignment) & ~(xml_memory_page_alignment - 1));
 
 			// prepare page structure
@@ -336,6 +335,7 @@ PUGI__NS_BEGIN
 			page->allocator = _root->allocator;
 
 			// record the offset for freeing the memory block
+			assert(page_memory > memory && page_memory - static_cast<char*>(memory) <= 127);
 			page_memory[-1] = static_cast<char>(page_memory - static_cast<char*>(memory));
 
 			return page;
@@ -5966,6 +5966,7 @@ namespace pugi
 		// destroy dynamic storage, leave sentinel page (it's in static memory)
 		impl::xml_memory_page* root_page = reinterpret_cast<impl::xml_memory_page*>(_root->header & impl::xml_memory_page_pointer_mask);
 		assert(root_page && !root_page->prev);
+		assert(reinterpret_cast<char*>(root_page) >= _memory && reinterpret_cast<char*>(root_page) < _memory + sizeof(_memory));
 
 		for (impl::xml_memory_page* page = root_page->next; page; )
 		{
-- 
cgit v1.2.3


From c579d99649bae59aaf5344e3d428201113fab1e9 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Wed, 19 Nov 2014 20:56:36 -0800
Subject: Prevent depth underflow when printing documents

Since depth is unsigned this is actually well-defined but it's better to not
have the underflow anyway.
---
 src/pugixml.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 90befd8..961e5f3 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -3643,11 +3643,12 @@ PUGI__NS_BEGIN
 				}
 
 				node = node->parent;
-				depth--;
 
 				// write closing node
 				if (PUGI__NODETYPE(node) == node_element)
 				{
+					depth--;
+
 					if (indent_length)
 						text_output_indent(writer, indent, indent_length, depth);
 
-- 
cgit v1.2.3


From 6d048deba8dfb8ccb8122b6c905b08b75f5090bf Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Wed, 19 Nov 2014 20:57:22 -0800
Subject: Make sure remove_node fully detaches the node

Right now remove_node is only used in contexts where parent is reset after
removing but this might be important in the future.
---
 src/pugixml.cpp | 1 +
 1 file changed, 1 insertion(+)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 961e5f3..194c77d 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -711,6 +711,7 @@ PUGI__NS_BEGIN
 		else
 			parent->first_child = node->next_sibling;
 
+		node->parent = 0;
 		node->prev_sibling_c = 0;
 		node->next_sibling = 0;
 	}
-- 
cgit v1.2.3


From b8437664a9d6b5697f09611b96951c005ab2554a Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Wed, 19 Nov 2014 22:44:08 -0800
Subject: XPath: Minor string operation refactoring

Extract end of string to rend and add comments to translate_table.
---
 src/pugixml.cpp | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 194c77d..c15ed6b 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -7435,6 +7435,7 @@ PUGI__NS_BEGIN
 			if (fc >= 128 || tc >= 128)
 				return 0;
 
+			// code=128 means "skip character"
 			if (!table[fc])
 				table[fc] = static_cast<unsigned char>(tc ? tc : 128);
 
@@ -7469,6 +7470,8 @@ PUGI__NS_BEGIN
 			{
 				unsigned char code = table[index];
 
+				// code=128 means "skip character" (table size is 128 so 128 can be a special value)
+				// this code skips these characters without extra branches
 				*write = static_cast<char_t>(code);
 				write += 1 - (code >> 7);
 			}
@@ -9525,9 +9528,10 @@ PUGI__NS_BEGIN
 				const char_t* pos = find_substring(s.c_str(), p.c_str());
 				if (!pos) return xpath_string();
 
-				const char_t* result = pos + p.length();
+				const char_t* rbegin = pos + p.length();
+				const char_t* rend = s.c_str() + s.length();
 
-				return s.uses_heap() ? xpath_string::from_heap(result, s.c_str() + s.length(), stack.result) : xpath_string::from_const(result);
+				return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
 			}
 
 			case ast_func_substring_2:
@@ -9548,8 +9552,9 @@ PUGI__NS_BEGIN
 				assert(1 <= pos && pos <= s_length + 1);
 
 				const char_t* rbegin = s.c_str() + (pos - 1);
+				const char_t* rend = s.c_str() + s.length();
 				
-				return s.uses_heap() ? xpath_string::from_heap(rbegin, s.c_str() + s.length(), stack.result) : xpath_string::from_const(rbegin);
+				return s.uses_heap() ? xpath_string::from_heap(rbegin, rend, stack.result) : xpath_string::from_const(rbegin);
 			}
 			
 			case ast_func_substring_3:
-- 
cgit v1.2.3


From cd62478108860e36b5cab30d85640492d0f32d91 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Wed, 19 Nov 2014 22:50:06 -0800
Subject: XPath: Refactor eval_once to use set type

This will allow us to implement nodeset_eval_last evaluation mode if necessary
without relying on a fragile boolean argument.
---
 src/pugixml.cpp | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index c15ed6b..b69ba2c 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -8436,9 +8436,9 @@ PUGI__NS_BEGIN
 			return false;
 		}
 
-		static bool eval_once(bool forward, nodeset_eval_t eval)
+		static bool eval_once(xpath_node_set::type_t type, nodeset_eval_t eval)
 		{
-			return forward ? eval != nodeset_eval_all : eval == nodeset_eval_any;
+			return type == xpath_node_set::type_sorted ? eval != nodeset_eval_all : eval == nodeset_eval_any;
 		}
 
 		template <class Comp> static bool compare_rel(xpath_ast_node* lhs, xpath_ast_node* rhs, const xpath_context& c, const xpath_stack& stack, const Comp& comp)
@@ -8610,7 +8610,7 @@ PUGI__NS_BEGIN
 		{
 			if (ns.size() == first) return;
 
-			bool last_once = eval_once(ns.type() == xpath_node_set::type_sorted, eval);
+			bool last_once = eval_once(ns.type(), eval);
 
 			for (xpath_ast_node* pred = _right; pred; pred = pred->_next)
 				pred->apply_predicate(ns, first, stack, !pred->_next && last_once);
@@ -9008,7 +9008,7 @@ PUGI__NS_BEGIN
 		template <class T> void step_fill(xpath_node_set_raw& ns, const xpath_node& xn, xpath_allocator* alloc, bool once, T v)
 		{
 			const axis_t axis = T::axis;
-			bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
+			const bool axis_has_attributes = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_descendant_or_self || axis == axis_following || axis == axis_parent || axis == axis_preceding || axis == axis_self);
 
 			if (xn.node())
 				step_fill(ns, xn.node().internal_object(), alloc, once, v);
@@ -9019,15 +9019,16 @@ PUGI__NS_BEGIN
 		template <class T> xpath_node_set_raw step_do(const xpath_context& c, const xpath_stack& stack, nodeset_eval_t eval, T v)
 		{
 			const axis_t axis = T::axis;
-			bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);
+			const bool axis_reverse = (axis == axis_ancestor || axis == axis_ancestor_or_self || axis == axis_preceding || axis == axis_preceding_sibling);
+			const xpath_node_set::type_t axis_type = axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted;
 
 			bool once =
 				(axis == axis_attribute && _test == nodetest_name) ||
-				(!_right && eval_once(!axis_reverse, eval)) ||
+				(!_right && eval_once(axis_type, eval)) ||
 				(_right && !_right->_next && _right->_test == predicate_constant_one);
 
 			xpath_node_set_raw ns;
-			ns.set_type(axis_reverse ? xpath_node_set::type_sorted_reverse : xpath_node_set::type_sorted);
+			ns.set_type(axis_type);
 
 			if (_left)
 			{
@@ -9693,7 +9694,7 @@ PUGI__NS_BEGIN
 				// either expression is a number or it contains position() call; sort by document order
 				if (_test != predicate_posinv) set.sort_do();
 
-				bool once = eval_once(set.type() == xpath_node_set::type_sorted, eval);
+				bool once = eval_once(set.type(), eval);
 
 				apply_predicate(set, 0, stack, once);
 			
-- 
cgit v1.2.3


From 8f85b1ba7afb77228cffb31452272854abfa931e Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Thu, 20 Nov 2014 08:54:03 -0800
Subject: Minor refactoring of tree modification

Remove redundant this-> from type() call (argument used to be called type,
but it's now type_).
Use _root member directly when possible instead of calling internal_object.
---
 src/pugixml.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index b69ba2c..75b5295 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -4970,7 +4970,7 @@ namespace pugi
 
 	PUGI__FN xml_node xml_node::append_child(xml_node_type type_)
 	{
-		if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
+		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 		
 		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
 		if (!n) return xml_node();
@@ -4984,7 +4984,7 @@ namespace pugi
 
 	PUGI__FN xml_node xml_node::prepend_child(xml_node_type type_)
 	{
-		if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
+		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 		
 		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
 		if (!n) return xml_node();
@@ -4998,7 +4998,7 @@ namespace pugi
 
 	PUGI__FN xml_node xml_node::insert_child_before(xml_node_type type_, const xml_node& node)
 	{
-		if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
+		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 		if (!node._root || node._root->parent != _root) return xml_node();
 	
 		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
@@ -5013,7 +5013,7 @@ namespace pugi
 
 	PUGI__FN xml_node xml_node::insert_child_after(xml_node_type type_, const xml_node& node)
 	{
-		if (!impl::allow_insert_child(this->type(), type_)) return xml_node();
+		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 		if (!node._root || node._root->parent != _root) return xml_node();
 	
 		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
@@ -5066,7 +5066,7 @@ namespace pugi
 	{
 		xml_node result = append_child(proto.type());
 
-		if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object());
+		if (result) impl::node_copy_tree(result._root, proto._root);
 
 		return result;
 	}
@@ -5075,7 +5075,7 @@ namespace pugi
 	{
 		xml_node result = prepend_child(proto.type());
 
-		if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object());
+		if (result) impl::node_copy_tree(result._root, proto._root);
 
 		return result;
 	}
@@ -5084,7 +5084,7 @@ namespace pugi
 	{
 		xml_node result = insert_child_after(proto.type(), node);
 
-		if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object());
+		if (result) impl::node_copy_tree(result._root, proto._root);
 
 		return result;
 	}
@@ -5093,7 +5093,7 @@ namespace pugi
 	{
 		xml_node result = insert_child_before(proto.type(), node);
 
-		if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object());
+		if (result) impl::node_copy_tree(result._root, proto._root);
 
 		return result;
 	}
-- 
cgit v1.2.3


From a0dc468170a9f429446feafea48fc73ae348b648 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Thu, 20 Nov 2014 20:29:21 -0800
Subject: Refactor node type checks for attribute insertion

Add allow_insert_attribute (similar to allow_insert_child).
---
 src/pugixml.cpp | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 75b5295..420ac1f 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -3682,6 +3682,11 @@ PUGI__NS_BEGIN
 		return false;
 	}
 
+	PUGI__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)
 	{
 		if (parent != node_document && parent != node_element) return false;
@@ -4872,7 +4877,7 @@ namespace pugi
 
 	PUGI__FN xml_attribute xml_node::append_attribute(const char_t* name_)
 	{
-		if (type() != node_element && type() != node_declaration) return xml_attribute();
+		if (!impl::allow_insert_attribute(type())) return xml_attribute();
 		
 		xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
 		if (!a) return xml_attribute();
@@ -4886,7 +4891,7 @@ namespace pugi
 
 	PUGI__FN xml_attribute xml_node::prepend_attribute(const char_t* name_)
 	{
-		if (type() != node_element && type() != node_declaration) return xml_attribute();
+		if (!impl::allow_insert_attribute(type())) return xml_attribute();
 		
 		xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
 		if (!a) return xml_attribute();
@@ -4900,7 +4905,7 @@ namespace pugi
 
 	PUGI__FN xml_attribute xml_node::insert_attribute_after(const char_t* name_, const xml_attribute& attr)
 	{
-		if (type() != node_element && type() != node_declaration) return xml_attribute();
+		if (!impl::allow_insert_attribute(type())) return xml_attribute();
 		if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
 		
 		xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
@@ -4915,7 +4920,7 @@ namespace pugi
 
 	PUGI__FN xml_attribute xml_node::insert_attribute_before(const char_t* name_, const xml_attribute& attr)
 	{
-		if (type() != node_element && type() != node_declaration) return xml_attribute();
+		if (!impl::allow_insert_attribute(type())) return xml_attribute();
 		if (!attr || !impl::is_attribute_of(attr._attr, _root)) return xml_attribute();
 		
 		xml_attribute a(impl::allocate_attribute(impl::get_allocator(_root)));
-- 
cgit v1.2.3


From 125aa55061ccde4ae7351a9a6c7270a15c9e0204 Mon Sep 17 00:00:00 2001
From: Arseny Kapoulkine <arseny.kapoulkine@gmail.com>
Date: Thu, 20 Nov 2014 23:39:40 -0800
Subject: Fix node_declaration copying with empty name

node_copy_string relied on the fact that target node had an empty name and
value. Normally this is a safe assumption (and a good one to make since it
makes copying faster), however it was not checked and there was one case when
it did not hold.

Since we're reusing the logic for inserting nodes, newly inserted declaration
nodes had the name set automatically to xml, which in our case violates the
assumption and is counter-productive since we'll override the name right after
setting it.

For now the best solution is to do the same insertion manually - that results
in some code duplication that we can refactor later (same logic is partially
shared by _move variants anyway so on a level duplicating is not that bad).
---
 src/pugixml.cpp | 48 ++++++++++++++++++++++++++++++++++++------------
 1 file changed, 36 insertions(+), 12 deletions(-)

(limited to 'src')

diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 420ac1f..ff84d44 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -3722,6 +3722,8 @@ PUGI__NS_BEGIN
 
 	PUGI__FN void node_copy_string(char_t*& dest, uintptr_t& header, uintptr_t header_mask, char_t* source, uintptr_t& source_header, xml_allocator* alloc)
 	{
+		assert(!dest && (header & header_mask) == 0);
+
 		if (source)
 		{
 			if (alloc && (source_header & header_mask) == 0)
@@ -5069,38 +5071,60 @@ namespace pugi
 
 	PUGI__FN xml_node xml_node::append_copy(const xml_node& proto)
 	{
-		xml_node result = append_child(proto.type());
+		xml_node_type type_ = proto.type();
+		if (!impl::allow_insert_child(type(), type_)) return xml_node();
+
+		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
+		if (!n) return xml_node();
 
-		if (result) impl::node_copy_tree(result._root, proto._root);
+		impl::append_node(n._root, _root);
+		impl::node_copy_tree(n._root, proto._root);
 
-		return result;
+		return n;
 	}
 
 	PUGI__FN xml_node xml_node::prepend_copy(const xml_node& proto)
 	{
-		xml_node result = prepend_child(proto.type());
+		xml_node_type type_ = proto.type();
+		if (!impl::allow_insert_child(type(), type_)) return xml_node();
 
-		if (result) impl::node_copy_tree(result._root, proto._root);
+		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
+		if (!n) return xml_node();
 
-		return result;
+		impl::prepend_node(n._root, _root);
+		impl::node_copy_tree(n._root, proto._root);
+
+		return n;
 	}
 
 	PUGI__FN xml_node xml_node::insert_copy_after(const xml_node& proto, const xml_node& node)
 	{
-		xml_node result = insert_child_after(proto.type(), node);
+		xml_node_type type_ = proto.type();
+		if (!impl::allow_insert_child(type(), type_)) return xml_node();
+		if (!node._root || node._root->parent != _root) return xml_node();
 
-		if (result) impl::node_copy_tree(result._root, proto._root);
+		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
+		if (!n) return xml_node();
 
-		return result;
+		impl::insert_node_after(n._root, node._root);
+		impl::node_copy_tree(n._root, proto._root);
+
+		return n;
 	}
 
 	PUGI__FN xml_node xml_node::insert_copy_before(const xml_node& proto, const xml_node& node)
 	{
-		xml_node result = insert_child_before(proto.type(), node);
+		xml_node_type type_ = proto.type();
+		if (!impl::allow_insert_child(type(), type_)) return xml_node();
+		if (!node._root || node._root->parent != _root) return xml_node();
 
-		if (result) impl::node_copy_tree(result._root, proto._root);
+		xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
+		if (!n) return xml_node();
 
-		return result;
+		impl::insert_node_before(n._root, node._root);
+		impl::node_copy_tree(n._root, proto._root);
+
+		return n;
 	}
 
 	PUGI__FN xml_node xml_node::append_move(const xml_node& moved)
-- 
cgit v1.2.3