Skip to content
Snippets Groups Projects
pugixml.cpp 318 KiB
Newer Older
	PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const
	PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const
	PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const
		_type = impl::xpath_sort(_begin, _end, _type, reverse);
	PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
	{
	}
	PUGI__FN xpath_parse_result::operator bool() const
	{
		return error == 0;
	}

	PUGI__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
	{
		switch (_type)
		{
		case xpath_type_node_set:
			return static_cast<const impl::xpath_variable_node_set*>(this)->name;
			return static_cast<const impl::xpath_variable_number*>(this)->name;
			return static_cast<const impl::xpath_variable_string*>(this)->name;
			return static_cast<const impl::xpath_variable_boolean*>(this)->name;
			assert(false && "Invalid variable type"); // unreachable
	PUGI__FN xpath_value_type xpath_variable::type() const
		return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
		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
		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
		return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
	{
		if (_type != xpath_type_boolean) return false;

		static_cast<impl::xpath_variable_boolean*>(this)->value = value;
	{
		if (_type != xpath_type_number) return false;

		static_cast<impl::xpath_variable_number*>(this)->value = value;
	PUGI__FN bool xpath_variable::set(const char_t* value)
	{
		if (_type != xpath_type_string) return false;

		impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);
		size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
		char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));
		if (var->value) impl::xml_memory::deallocate(var->value);
	PUGI__FN bool xpath_variable::set(const xpath_node_set& value)
	{
		if (_type != xpath_type_node_set) return false;

		static_cast<impl::xpath_variable_node_set*>(this)->value = value;
		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
			_data[i] = 0;
	{
		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)
	{
		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
			_data[i] = 0;

		_assign(rhs);
	}

	PUGI__FN xpath_variable_set& xpath_variable_set::operator=(const xpath_variable_set& rhs)
	{
		if (this == &rhs) return *this;

		_assign(rhs);

		return *this;
	}

#ifdef PUGIXML_HAS_MOVE
	PUGI__FN xpath_variable_set::xpath_variable_set(xpath_variable_set&& rhs)
	{
		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
		{
			_data[i] = rhs._data[i];
			rhs._data[i] = 0;
		}
	}
	PUGI__FN xpath_variable_set& xpath_variable_set::operator=(xpath_variable_set&& rhs)
	{
		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
		{
			_destroy(_data[i]);
			_data[i] = rhs._data[i];
			rhs._data[i] = 0;
		}
	PUGI__FN void xpath_variable_set::_assign(const xpath_variable_set& rhs)
	{
		xpath_variable_set temp;

		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
			if (rhs._data[i] && !_clone(rhs._data[i], &temp._data[i]))
				return;

		_swap(temp);
	}

	PUGI__FN void xpath_variable_set::_swap(xpath_variable_set& rhs)
	{
		for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
		{
			xpath_variable* chain = _data[i];

			_data[i] = rhs._data[i];
			rhs._data[i] = chain;
	PUGI__FN xpath_variable* xpath_variable_set::_find(const char_t* name) const
	{
		const size_t hash_size = sizeof(_data) / sizeof(_data[0]);

		// look for existing variable
		for (xpath_variable* var = _data[hash]; var; var = var->_next)
	PUGI__FN bool xpath_variable_set::_clone(xpath_variable* var, xpath_variable** out_result)
	{
		xpath_variable* last = 0;

		while (var)
		{
			// allocate storage for new variable
			xpath_variable* nvar = impl::new_xpath_variable(var->_type, var->name());
			if (!nvar) return false;

			// link the variable to the result immediately to handle failures gracefully
			if (last)
				last->_next = nvar;
			else
				*out_result = nvar;

			last = nvar;

			// copy the value; this can fail due to out-of-memory conditions
			if (!impl::copy_xpath_variable(nvar, var)) return false;

			var = var->_next;
		}

		return true;
	}

	PUGI__FN void xpath_variable_set::_destroy(xpath_variable* var)
	{
		while (var)
		{
			xpath_variable* next = var->_next;

			impl::delete_xpath_variable(var->_type, var);

			var = next;
		}
	}

	PUGI__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]);

		// look for existing variable
		for (xpath_variable* var = _data[hash]; var; var = var->_next)
				return var->type() == type ? var : 0;

		// add new variable
		xpath_variable* result = impl::new_xpath_variable(type, name);

		if (result)
		{
			result->_next = _data[hash];

			_data[hash] = result;
		}

		return result;
	}

	PUGI__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)
	{
		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)
	{
		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)
	{
		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__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
	PUGI__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();
			_result.error = "Out of memory";
			using impl::auto_deleter; // MSVC7 workaround
			auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);
			qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
				qimpl->root->optimize(&qimpl->alloc);
				_impl = impl.release();
			#ifdef PUGIXML_NO_EXCEPTIONS
				if (qimpl->oom) _result.error = "Out of memory";
			#else
				if (qimpl->oom) throw std::bad_alloc();
				throw xpath_exception(_result);
	PUGI__FN xpath_query::xpath_query(): _impl(0)
	{
	}

		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)
	{
		_impl = rhs._impl;
		_result = rhs._result;
		rhs._result = xpath_parse_result();
A. Breust's avatar
A. Breust committed
	PUGI__FN xpath_query& xpath_query::operator=(xpath_query&& rhs)
	{
		if (this == &rhs) return *this;

		if (_impl)
			impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));

		_impl = rhs._impl;
		_result = rhs._result;
		rhs._result = xpath_parse_result();
	PUGI__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
		impl::xpath_context c(n, 1, 1);
		impl::xpath_stack_data sd;
		bool r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);

		if (sd.oom)
		{
		#ifdef PUGIXML_NO_EXCEPTIONS
			return false;
		#else
			throw std::bad_alloc();
		#endif
		}
	PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
		impl::xpath_context c(n, 1, 1);
		impl::xpath_stack_data sd;
		double r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);

		if (sd.oom)
		{
		#ifdef PUGIXML_NO_EXCEPTIONS
			return impl::gen_nan();
		#else
			throw std::bad_alloc();
		#endif
		}
	PUGI__FN string_t xpath_query::evaluate_string(const xpath_node& n) const
		if (!_impl) return string_t();

		impl::xpath_context c(n, 1, 1);
		impl::xpath_string r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_string(c, sd.stack);

		if (sd.oom)
		{
		#ifdef PUGIXML_NO_EXCEPTIONS
			return string_t();
		#else
			throw std::bad_alloc();
		#endif
		}

		return string_t(r.c_str(), r.length());
	PUGI__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_string r = _impl ? static_cast<impl::xpath_query_impl*>(_impl)->root->eval_string(c, sd.stack) : impl::xpath_string();

		if (sd.oom)
		{
		#ifdef PUGIXML_NO_EXCEPTIONS
			r = impl::xpath_string();
		#else
			throw std::bad_alloc();
		#endif
		}
		{
			size_t size = (full_size < capacity) ? full_size : capacity;
			assert(size > 0);
			memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
			buffer[size - 1] = 0;
		}
	PUGI__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();
		impl::xpath_context c(n, 1, 1);
		impl::xpath_stack_data sd;
		impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
		if (sd.oom)
		{
		#ifdef PUGIXML_NO_EXCEPTIONS
			return xpath_node_set();
		#else
			throw std::bad_alloc();
		#endif
		}
		return xpath_node_set(r.begin(), r.end(), r.type());
	PUGI__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();

		impl::xpath_context c(n, 1, 1);
		impl::xpath_stack_data sd;

		impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_first);
		if (sd.oom)
		{
		#ifdef PUGIXML_NO_EXCEPTIONS
			return xpath_node();
		#else
			throw std::bad_alloc();
		#endif
		}
		return r.first();
	PUGI__FN const xpath_parse_result& xpath_query::result() const
	PUGI__FN static void unspecified_bool_xpath_query(xpath_query***)
	{
	}
	PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
		return _impl ? unspecified_bool_xpath_query : 0;
	PUGI__FN xpath_node xml_node::select_node(const char_t* query, xpath_variable_set* variables) const
		xpath_query q(query, variables);
	PUGI__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
		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
	{
		return query.evaluate_node_set(*this);
	}

	PUGI__FN xpath_node xml_node::select_single_node(const char_t* query, xpath_variable_set* variables) const
	{
		xpath_query q(query, variables);
	}

	PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const
	{
		return query.evaluate_node(*this);
	}
// Intel C++ does not properly keep warning state for function templates,
// so popping warning state at the end of translation unit leads to warnings in the middle.
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#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__UNSIGNED_OVERFLOW
#undef PUGI__MSVC_CRT_VERSION
#undef PUGI__NS_BEGIN
#undef PUGI__NS_END
#undef PUGI__FN
#undef PUGI__FN_NO_INLINE
#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
 * Copyright (c) 2006-2017 Arseny Kapoulkine
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */