diff options
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | src/pugixml.cpp | 105 | ||||
| -rw-r--r-- | tests/test_document.cpp | 4 | ||||
| -rw-r--r-- | tests/test_dom_modify.cpp | 13 | ||||
| -rw-r--r-- | tests/test_xpath_operators.cpp | 48 | ||||
| -rw-r--r-- | tests/test_xpath_paths.cpp | 2 | 
6 files changed, 131 insertions, 45 deletions
| @@ -30,7 +30,7 @@ all: $(EXECUTABLE)  ifeq ($(config),coverage)  test: $(EXECUTABLE) -	@find $(BUILD) -name '*.gcda' | xargs rm +	@find $(BUILD) -name '*.gcda' | xargs -r rm  	./$(EXECUTABLE)  	@gcov -b -c $(BUILD)/src/pugixml.cpp.gcda | sed -e '/./{H;$!d;}' -e 'x;/pugixml.cpp/!d;'  	@ls *.gcov | grep -v pugixml.cpp.gcov | xargs rm @@ -51,4 +51,4 @@ $(BUILD)/%.o: %  -include $(OBJECTS:.o=.d) -.PHONY: all test clean	
\ No newline at end of file +.PHONY: all test clean	 diff --git a/src/pugixml.cpp b/src/pugixml.cpp index 163af21..5e9c4b8 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1845,7 +1845,11 @@ PUGI__NS_BEGIN  			char_t* buffer = static_cast<char_t*>(xml_memory::allocate((length + 1) * sizeof(char_t)));  			if (!buffer) return false; -			memcpy(buffer, contents, length * sizeof(char_t)); +			if (contents) +				memcpy(buffer, contents, length * sizeof(char_t)); +			else +				assert(length == 0); +  			buffer[length] = 0;  			out_buffer = buffer; @@ -3016,8 +3020,6 @@ PUGI__NS_BEGIN  					PUGI__PUSHNODE(node_doctype);  					cursor->contents = mark; - -					PUGI__POPNODE();  				}  			}  			else if (*s == 0 && endch == '-') PUGI__THROW_ERROR(status_bad_comment, s); @@ -4156,7 +4158,7 @@ PUGI__NS_BEGIN  		while (node != root);  	} -	PUGI__FN bool has_declaration(const xml_node node) +	PUGI__FN bool has_declaration(xml_node node)  	{  		for (xml_node child = node.first_child(); child; child = child.next_sibling())  		{ @@ -4187,7 +4189,7 @@ PUGI__NS_BEGIN  		return true;  	} -	PUGI__FN bool allow_move(const xml_node parent, const xml_node child) +	PUGI__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())) @@ -7875,7 +7877,7 @@ PUGI__NS_BEGIN  			prefix_length = pos ? static_cast<size_t>(pos - name) : 0;  		} -		bool operator()(const xml_attribute a) const +		bool operator()(xml_attribute a) const  		{  			const char_t* name = a.name(); @@ -7885,7 +7887,7 @@ PUGI__NS_BEGIN  		}  	}; -	PUGI__FN const char_t* namespace_uri(const xml_node node) +	PUGI__FN const char_t* namespace_uri(xml_node node)  	{  		namespace_uri_predicate pred = node.name(); @@ -7903,7 +7905,7 @@ PUGI__NS_BEGIN  		return PUGIXML_TEXT("");  	} -	PUGI__FN const char_t* namespace_uri(const xml_attribute attr, const xml_node parent) +	PUGI__FN const char_t* namespace_uri(xml_attribute attr, xml_node parent)  	{  		namespace_uri_predicate pred = attr.name(); @@ -8318,6 +8320,8 @@ PUGI__NS_BEGIN  		void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)  		{ +			if (begin_ == end_) return; +  			size_t size_ = static_cast<size_t>(_end - _begin);  			size_t capacity = static_cast<size_t>(_eos - _begin);  			size_t count = static_cast<size_t>(end_ - begin_); @@ -9051,44 +9055,59 @@ PUGI__NS_BEGIN  			}  		} -		static void apply_predicate(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) +		static void apply_predicate_boolean(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once)  		{  			assert(ns.size() >= first); +			assert(expr->rettype() != xpath_type_number);  			size_t i = 1;  			size_t size = ns.size() - first; -				 +  			xpath_node* last = ns.begin() + first;  			// remove_if... or well, sort of  			for (xpath_node* it = last; it != ns.end(); ++it, ++i)  			{  				xpath_context c(*it, i, size); -			 -				if (expr->rettype() == xpath_type_number) + +				if (expr->eval_boolean(c, stack))  				{ -					if (expr->eval_number(c, stack) == i) -					{ -						*last++ = *it; +					*last++ = *it; -						if (once) break; -					} +					if (once) break;  				} -				else +			} + +			ns.truncate(last); +		} + +		static void apply_predicate_number(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack, bool once) +		{ +			assert(ns.size() >= first); +			assert(expr->rettype() == xpath_type_number); + +			size_t i = 1; +			size_t size = ns.size() - first; + +			xpath_node* last = ns.begin() + first; + +			// remove_if... or well, sort of +			for (xpath_node* it = last; it != ns.end(); ++it, ++i) +			{ +				xpath_context c(*it, i, size); + +				if (expr->eval_number(c, stack) == i)  				{ -					if (expr->eval_boolean(c, stack)) -					{ -						*last++ = *it; +					*last++ = *it; -						if (once) break; -					} +					if (once) break;  				}  			} -			 +  			ns.truncate(last);  		} -		static void apply_predicate_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack) +		static void apply_predicate_number_const(xpath_node_set_raw& ns, size_t first, xpath_ast_node* expr, const xpath_stack& stack)  		{  			assert(ns.size() >= first);  			assert(expr->rettype() == xpath_type_number); @@ -9116,21 +9135,28 @@ PUGI__NS_BEGIN  			ns.truncate(last);  		} +		void apply_predicate(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, bool once) +		{ +			if (ns.size() == first) return; + +			assert(_type == ast_filter || _type == ast_predicate); + +			if (_test == predicate_constant || _test == predicate_constant_one) +				apply_predicate_number_const(ns, first, _right, stack); +			else if (_right->rettype() == xpath_type_number) +				apply_predicate_number(ns, first, _right, stack, once); +			else +				apply_predicate_boolean(ns, first, _right, stack, once); +		} +  		void apply_predicates(xpath_node_set_raw& ns, size_t first, const xpath_stack& stack, nodeset_eval_t eval)  		{  			if (ns.size() == first) return; -			 +  			bool last_once = eval_once(ns.type() == xpath_node_set::type_sorted, eval);  			for (xpath_ast_node* pred = _right; pred; pred = pred->_next) -			{ -				assert(pred->_type == ast_predicate); - -				if (pred->_test == predicate_constant || pred->_test == predicate_constant_one) -					apply_predicate_const(ns, first, pred->_right, stack); -				else -					apply_predicate(ns, first, pred->_right, stack, !pred->_next && last_once); -			} +				pred->apply_predicate(ns, first, stack, !pred->_next && last_once);  		}  		bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc) @@ -10208,16 +10234,9 @@ PUGI__NS_BEGIN  				// either expression is a number or it contains position() call; sort by document order  				if (_test != predicate_posinv) set.sort_do(); -				if (_test == predicate_constant || _test == predicate_constant_one) -				{ -					apply_predicate_const(set, 0, _right, stack); -				} -				else -				{ -					bool once = eval_once(set.type() == xpath_node_set::type_sorted, eval); +				bool once = eval_once(set.type() == xpath_node_set::type_sorted, eval); -					apply_predicate(set, 0, _right, stack, once); -				} +				apply_predicate(set, 0, stack, once);  				return set;  			} diff --git a/tests/test_document.cpp b/tests/test_document.cpp index 2cc39a6..2774a07 100644 --- a/tests/test_document.cpp +++ b/tests/test_document.cpp @@ -301,6 +301,10 @@ TEST(document_load_file_error)  	CHECK(doc.load_file("filedoesnotexist").status == status_file_not_found); +#ifndef _WIN32 +	CHECK(doc.load_file("/dev/tty").status == status_io_error); +#endif +  	test_runner::_memory_fail_threshold = 1;  	CHECK(doc.load_file("tests/data/small.xml").status == status_out_of_memory);  } diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp index 07fe6dc..45cf3ea 100644 --- a/tests/test_dom_modify.cpp +++ b/tests/test_dom_modify.cpp @@ -1091,6 +1091,19 @@ TEST_XML(dom_node_append_buffer_fragment, "<node />")  	CHECK_NODE(doc, STR("<node>1234</node>"));  } +TEST_XML(dom_node_append_buffer_empty, "<node />") +{ +	xml_node node = doc.child(STR("node")); + +	CHECK(node.append_buffer("", 0).status == status_no_document_element); +	CHECK(node.append_buffer("", 0, parse_fragment).status == status_ok); + +	CHECK(node.append_buffer(0, 0).status == status_no_document_element); +	CHECK(node.append_buffer(0, 0, parse_fragment).status == status_ok); + +	CHECK_NODE(doc, STR("<node />")); +} +  TEST_XML(dom_node_prepend_move, "<node>foo<child/></node>")  {  	xml_node child = doc.child(STR("node")).child(STR("child")); diff --git a/tests/test_xpath_operators.cpp b/tests/test_xpath_operators.cpp index c028224..57e3755 100644 --- a/tests/test_xpath_operators.cpp +++ b/tests/test_xpath_operators.cpp @@ -481,4 +481,52 @@ TEST(xpath_operators_associativity_arithmetic)  	CHECK_XPATH_NUMBER(c, STR("1-1+1"), 1);  } +TEST(xpath_operators_mod) +{ +	// Check that mod operator conforms to Java spec (since this is the only concrete source of information about XPath mod) +	xml_node c; + +	// Basic tests from spec +	CHECK_XPATH_NUMBER(c, STR("5 mod 3"), 2); +	CHECK_XPATH_NUMBER(c, STR("5 mod -3"), 2); +	CHECK_XPATH_NUMBER(c, STR("-5 mod 3"), -2); +	CHECK_XPATH_NUMBER(c, STR("-5 mod -3"), -2); + +	// If either operand is NaN, the result is NaN +	CHECK_XPATH_NUMBER_NAN(c, STR("(0 div 0) mod 3")); +	CHECK_XPATH_NUMBER_NAN(c, STR("3 mod (0 div 0)")); +	CHECK_XPATH_NUMBER_NAN(c, STR("(0 div 0) mod (0 div 0)")); + +	// If the dividend is an infinity, or the divisor is a zero, or both, the result is NaN +	CHECK_XPATH_NUMBER_NAN(c, STR("(1 div 0) mod 3")); +	CHECK_XPATH_NUMBER_NAN(c, STR("(1 div 0) mod -3")); +	CHECK_XPATH_NUMBER_NAN(c, STR("(-1 div 0) mod 3")); +	CHECK_XPATH_NUMBER_NAN(c, STR("1 mod 0")); +	CHECK_XPATH_NUMBER_NAN(c, STR("-1 mod 0")); +	CHECK_XPATH_NUMBER_NAN(c, STR("(1 div 0) mod 0")); +	CHECK_XPATH_NUMBER_NAN(c, STR("(-1 div 0) mod 0")); + +	// If the dividend is finite and the divisor is an infinity, the result equals the dividend +	CHECK_XPATH_NUMBER(c, STR("1 mod (1 div 0)"), 1); +	CHECK_XPATH_NUMBER(c, STR("1 mod (-1 div 0)"), 1); +	CHECK_XPATH_NUMBER(c, STR("-1 mod (1 div 0)"), -1); +	CHECK_XPATH_NUMBER(c, STR("0 mod (1 div 0)"), 0); +	CHECK_XPATH_NUMBER(c, STR("0 mod (-1 div 0)"), 0); +	CHECK_XPATH_NUMBER(c, STR("100000 mod (1 div 0)"), 100000); + +	// If the dividend is a zero and the divisor is finite, the result equals the dividend. +	CHECK_XPATH_NUMBER(c, STR("0 mod 1000000"), 0); +	CHECK_XPATH_NUMBER(c, STR("0 mod -1000000"), 0); + +	// In the remaining cases ...  the floating-point remainder r from the division of a dividend n by a divisor d +	// is defined by the mathematical relation r = n - (d * q) where q is an integer that is negative only if n/d is +	// negative and positive only if n/d is positive, and whose magnitude is as large as possible without exceeding the magnitude of the true +	// mathematical quotient of n and d. +	CHECK_XPATH_NUMBER(c, STR("9007199254740991 mod 2"), 1); +	CHECK_XPATH_NUMBER(c, STR("9007199254740991 mod 3"), 1); +	CHECK_XPATH_NUMBER(c, STR("18446744073709551615 mod 2"), 0); +	CHECK_XPATH_NUMBER(c, STR("18446744073709551615 mod 3"), 1); +	CHECK_XPATH_NUMBER(c, STR("115792089237316195423570985008687907853269984665640564039457584007913129639935 mod 2"), 0); +	CHECK_XPATH_NUMBER(c, STR("115792089237316195423570985008687907853269984665640564039457584007913129639935 mod 3"), 1); +}  #endif diff --git a/tests/test_xpath_paths.cpp b/tests/test_xpath_paths.cpp index df0dfa4..e51a395 100644 --- a/tests/test_xpath_paths.cpp +++ b/tests/test_xpath_paths.cpp @@ -664,6 +664,8 @@ TEST_XML(xpath_paths_optimize_step_once, "<node><para1><para2/><para3/><para4><p      CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor-or-self::*"), true);      CHECK_XPATH_BOOLEAN(doc, STR("//para5/ancestor::*"), true); + +    CHECK_XPATH_BOOLEAN(doc, STR("//@attr5/ancestor-or-self::node()"), true);  }  TEST_XML(xpath_paths_null_nodeset_entries, "<node attr='value'/>") | 
