Newer
Older
arseny.kapoulkine@gmail.com
committed
PUGI__FN bool xpath_node_set::empty() const
{
return _begin == _end;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN const xpath_node& xpath_node_set::operator[](size_t index) const
{
assert(index < size());
return _begin[index];
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_node_set::const_iterator xpath_node_set::begin() const
{
return _begin;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_node_set::const_iterator xpath_node_set::end() const
{
return _end;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN void xpath_node_set::sort(bool reverse)
arseny.kapoulkine@gmail.com
committed
_type = impl::xpath_sort(_begin, _end, _type, reverse);
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_node xpath_node_set::first() const
arseny.kapoulkine@gmail.com
committed
return impl::xpath_first(_begin, _end, _type);
PUGI__FN xpath_parse_result::xpath_parse_result(): error("Internal error"), offset(0)
{
}
arseny.kapoulkine
committed
PUGI__FN xpath_parse_result::operator bool() const
{
return error == 0;
}
arseny.kapoulkine@gmail.com
committed
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)
{
}
arseny.kapoulkine
committed
arseny.kapoulkine@gmail.com
committed
PUGI__FN const char_t* xpath_variable::name() const
{
switch (_type)
{
case xpath_type_node_set:
arseny.kapoulkine@gmail.com
committed
return static_cast<const impl::xpath_variable_node_set*>(this)->name;
case xpath_type_number:
arseny.kapoulkine@gmail.com
committed
return static_cast<const impl::xpath_variable_number*>(this)->name;
case xpath_type_string:
arseny.kapoulkine@gmail.com
committed
return static_cast<const impl::xpath_variable_string*>(this)->name;
case xpath_type_boolean:
arseny.kapoulkine@gmail.com
committed
return static_cast<const impl::xpath_variable_boolean*>(this)->name;
assert(false && "Invalid variable type"); // unreachable
return 0;
}
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_value_type xpath_variable::type() const
{
return _type;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN bool xpath_variable::get_boolean() const
arseny.kapoulkine@gmail.com
committed
return (_type == xpath_type_boolean) ? static_cast<const impl::xpath_variable_boolean*>(this)->value : false;
arseny.kapoulkine@gmail.com
committed
PUGI__FN double xpath_variable::get_number() const
arseny.kapoulkine@gmail.com
committed
return (_type == xpath_type_number) ? static_cast<const impl::xpath_variable_number*>(this)->value : impl::gen_nan();
arseny.kapoulkine@gmail.com
committed
PUGI__FN const char_t* xpath_variable::get_string() const
arseny.kapoulkine@gmail.com
committed
const char_t* value = (_type == xpath_type_string) ? static_cast<const impl::xpath_variable_string*>(this)->value : 0;
return value ? value : PUGIXML_TEXT("");
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN const xpath_node_set& xpath_variable::get_node_set() const
arseny.kapoulkine@gmail.com
committed
return (_type == xpath_type_node_set) ? static_cast<const impl::xpath_variable_node_set*>(this)->value : impl::dummy_node_set;
arseny.kapoulkine@gmail.com
committed
PUGI__FN bool xpath_variable::set(bool value)
{
if (_type != xpath_type_boolean) return false;
arseny.kapoulkine@gmail.com
committed
static_cast<impl::xpath_variable_boolean*>(this)->value = value;
return true;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN bool xpath_variable::set(double value)
{
if (_type != xpath_type_number) return false;
arseny.kapoulkine@gmail.com
committed
static_cast<impl::xpath_variable_number*>(this)->value = value;
return true;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN bool xpath_variable::set(const char_t* value)
{
if (_type != xpath_type_string) return false;
arseny.kapoulkine@gmail.com
committed
impl::xpath_variable_string* var = static_cast<impl::xpath_variable_string*>(this);
// duplicate string
arseny.kapoulkine@gmail.com
committed
size_t size = (impl::strlength(value) + 1) * sizeof(char_t);
arseny.kapoulkine
committed
arseny.kapoulkine@gmail.com
committed
char_t* copy = static_cast<char_t*>(impl::xml_memory::allocate(size));
if (!copy) return false;
arseny.kapoulkine
committed
memcpy(copy, value, size);
// replace old string
arseny.kapoulkine@gmail.com
committed
if (var->value) impl::xml_memory::deallocate(var->value);
var->value = copy;
return true;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN bool xpath_variable::set(const xpath_node_set& value)
{
if (_type != xpath_type_node_set) return false;
arseny.kapoulkine@gmail.com
committed
static_cast<impl::xpath_variable_node_set*>(this)->value = value;
return true;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_variable_set::xpath_variable_set()
for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
_data[i] = 0;
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_variable_set::~xpath_variable_set()
{
for (size_t i = 0; i < sizeof(_data) / sizeof(_data[0]); ++i)
12156
12157
12158
12159
12160
12161
12162
12163
12164
12165
12166
12167
12168
12169
12170
12171
12172
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;
}
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;
}
return *this;
}
#endif
12197
12198
12199
12200
12201
12202
12203
12204
12205
12206
12207
12208
12209
12210
12211
12212
12213
12214
12215
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]);
arseny.kapoulkine@gmail.com
committed
size_t hash = impl::hash_string(name) % hash_size;
// look for existing variable
for (xpath_variable* var = _data[hash]; var; var = var->_next)
arseny.kapoulkine@gmail.com
committed
if (impl::strequal(var->name(), name))
return var;
return 0;
}
12232
12233
12234
12235
12236
12237
12238
12239
12240
12241
12242
12243
12244
12245
12246
12247
12248
12249
12250
12251
12252
12253
12254
12255
12256
12257
12258
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;
}
}
arseny.kapoulkine@gmail.com
committed
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]);
arseny.kapoulkine@gmail.com
committed
size_t hash = impl::hash_string(name) % hash_size;
// look for existing variable
for (xpath_variable* var = _data[hash]; var; var = var->_next)
arseny.kapoulkine@gmail.com
committed
if (impl::strequal(var->name(), name))
return var->type() == type ? var : 0;
// add new variable
arseny.kapoulkine@gmail.com
committed
xpath_variable* result = impl::new_xpath_variable(type, name);
if (result)
{
result->_next = _data[hash];
_data[hash] = result;
}
return result;
}
arseny.kapoulkine@gmail.com
committed
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;
}
arseny.kapoulkine@gmail.com
committed
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;
}
arseny.kapoulkine@gmail.com
committed
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;
}
arseny.kapoulkine@gmail.com
committed
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;
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_variable* xpath_variable_set::get(const char_t* name)
return _find(name);
arseny.kapoulkine@gmail.com
committed
PUGI__FN const xpath_variable* xpath_variable_set::get(const char_t* name) const
return _find(name);
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_query::xpath_query(const char_t* query, xpath_variable_set* variables): _impl(0)
arseny.kapoulkine@gmail.com
committed
impl::xpath_query_impl* qimpl = impl::xpath_query_impl::create();
arseny.kapoulkine@gmail.com
committed
if (!qimpl)
arseny.kapoulkine
committed
#ifdef PUGIXML_NO_EXCEPTIONS
_result.error = "Out of memory";
arseny.kapoulkine
committed
throw std::bad_alloc();
arseny.kapoulkine
committed
#endif
using impl::auto_deleter; // MSVC7 workaround
auto_deleter<impl::xpath_query_impl> impl(qimpl, impl::xpath_query_impl::destroy);
arseny.kapoulkine@gmail.com
committed
qimpl->root = impl::xpath_parser::parse(query, variables, &qimpl->alloc, &_result);
arseny.kapoulkine@gmail.com
committed
if (qimpl->root)
arseny.kapoulkine
committed
{
qimpl->root->optimize(&qimpl->alloc);
_impl = impl.release();
arseny.kapoulkine
committed
_result.error = 0;
}
else
{
#ifdef PUGIXML_NO_EXCEPTIONS
if (qimpl->oom) _result.error = "Out of memory";
#else
if (qimpl->oom) throw std::bad_alloc();
throw xpath_exception(_result);
#endif
}
PUGI__FN xpath_query::xpath_query(): _impl(0)
{
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_query::~xpath_query()
if (_impl)
impl::xpath_query_impl::destroy(static_cast<impl::xpath_query_impl*>(_impl));
PUGI__FN xpath_query::xpath_query(xpath_query&& rhs)
{
_impl = rhs._impl;
rhs._result = xpath_parse_result();
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;
rhs._result = xpath_parse_result();
return *this;
}
#endif
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_value_type xpath_query::return_type() const
if (!_impl) return xpath_type_none;
arseny.kapoulkine@gmail.com
committed
return static_cast<impl::xpath_query_impl*>(_impl)->root->rettype();
arseny.kapoulkine@gmail.com
committed
PUGI__FN bool xpath_query::evaluate_boolean(const xpath_node& n) const
if (!_impl) return false;
arseny.kapoulkine@gmail.com
committed
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
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
arseny.kapoulkine@gmail.com
committed
if (!_impl) return impl::gen_nan();
arseny.kapoulkine@gmail.com
committed
impl::xpath_context c(n, 1, 1);
impl::xpath_stack_data sd;
arseny.kapoulkine
committed
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
}
arseny.kapoulkine
committed
#ifndef PUGIXML_NO_STL
arseny.kapoulkine@gmail.com
committed
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);
arseny.kapoulkine@gmail.com
committed
impl::xpath_stack_data sd;
arseny.kapoulkine
committed
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());
arseny.kapoulkine
committed
}
#endif
arseny.kapoulkine@gmail.com
committed
PUGI__FN size_t xpath_query::evaluate_string(char_t* buffer, size_t capacity, const xpath_node& n) const
arseny.kapoulkine
committed
{
impl::xpath_context c(n, 1, 1);
arseny.kapoulkine@gmail.com
committed
impl::xpath_stack_data sd;
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
}
arseny.kapoulkine
committed
size_t full_size = r.length() + 1;
arseny.kapoulkine
committed
if (capacity > 0)
{
size_t size = (full_size < capacity) ? full_size : capacity;
assert(size > 0);
arseny.kapoulkine
committed
memcpy(buffer, r.c_str(), (size - 1) * sizeof(char_t));
buffer[size - 1] = 0;
}
arseny.kapoulkine
committed
return full_size;
arseny.kapoulkine@gmail.com
committed
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();
arseny.kapoulkine
committed
arseny.kapoulkine@gmail.com
committed
impl::xpath_context c(n, 1, 1);
impl::xpath_stack_data sd;
arseny.kapoulkine
committed
impl::xpath_node_set_raw r = root->eval_node_set(c, sd.stack, impl::nodeset_eval_all);
arseny.kapoulkine
committed
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
}
arseny.kapoulkine@gmail.com
committed
PUGI__FN const xpath_parse_result& xpath_query::result() const
{
return _result;
}
PUGI__FN static void unspecified_bool_xpath_query(xpath_query***)
{
}
arseny.kapoulkine
committed
arseny.kapoulkine@gmail.com
committed
PUGI__FN xpath_query::operator xpath_query::unspecified_bool_type() const
arseny.kapoulkine
committed
return _impl ? unspecified_bool_xpath_query : 0;
arseny.kapoulkine@gmail.com
committed
PUGI__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
xpath_query q(query, variables);
return q.evaluate_node(*this);
PUGI__FN xpath_node xml_node::select_node(const xpath_query& query) const
return query.evaluate_node(*this);
arseny.kapoulkine@gmail.com
committed
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);
arseny.kapoulkine@gmail.com
committed
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);
return q.evaluate_node(*this);
}
PUGI__FN xpath_node xml_node::select_single_node(const xpath_query& query) const
{
return query.evaluate_node(*this);
}
}
#endif
arseny.kapoulkine@gmail.com
committed
#ifdef __BORLANDC__
# pragma option pop
arseny.kapoulkine@gmail.com
committed
#endif
arseny.kapoulkine@gmail.com
committed
// Intel C++ does not properly keep warning state for function templates,
arseny.kapoulkine@gmail.com
committed
// so popping warning state at the end of translation unit leads to warnings in the middle.
arseny.kapoulkine@gmail.com
committed
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
# pragma warning(pop)
arseny.kapoulkine@gmail.com
committed
#endif
// Undefine all local macros (makes sure we're not leaking macros in header-only mode)
#undef PUGI__NO_INLINE
arseny.kapoulkine@gmail.com
committed
#undef PUGI__STATIC_ASSERT
#undef PUGI__DMC_VOLATILE
#undef PUGI__UNSIGNED_OVERFLOW
arseny.kapoulkine@gmail.com
committed
#undef PUGI__MSVC_CRT_VERSION
#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
arseny.kapoulkine@gmail.com
committed
#undef PUGI__IS_CHARTYPE_IMPL
#undef PUGI__IS_CHARTYPE
#undef PUGI__IS_CHARTYPEX
arseny.kapoulkine@gmail.com
committed
#undef PUGI__SKIPWS
#undef PUGI__OPTSET
#undef PUGI__PUSHNODE
#undef PUGI__POPNODE
#undef PUGI__SCANFOR
#undef PUGI__SCANWHILE
#undef PUGI__SCANWHILE_UNROLL
arseny.kapoulkine@gmail.com
committed
#undef PUGI__ENDSEG
#undef PUGI__THROW_ERROR
#undef PUGI__CHECK_ERROR
#endif
* 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.
*/