summaryrefslogtreecommitdiff
path: root/src/pugixml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pugixml.cpp')
-rw-r--r--src/pugixml.cpp314
1 files changed, 203 insertions, 111 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 1d390eb..787f693 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -1,6 +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/
@@ -286,8 +285,6 @@ PUGI__NS_BEGIN
{
static xml_memory_page* construct(void* memory)
{
- if (!memory) return 0; //$ redundant, left for performance
-
xml_memory_page* result = static_cast<xml_memory_page*>(memory);
result->allocator = 0;
@@ -328,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
@@ -338,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;
@@ -402,6 +400,8 @@ PUGI__NS_BEGIN
char_t* allocate_string(size_t length)
{
+ PUGI__STATIC_ASSERT(xml_memory_page_size <= (1 << 16));
+
// allocate memory for string and header block
size_t size = sizeof(xml_memory_string_header) + length * sizeof(char_t);
@@ -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;
}
@@ -2356,23 +2357,28 @@ PUGI__NS_BEGIN
char_t* parse_doctype_ignore(char_t* s)
{
+ size_t depth = 0;
+
assert(s[0] == '<' && s[1] == '!' && s[2] == '[');
- s++;
+ s += 3;
while (*s)
{
if (s[0] == '<' && s[1] == '!' && s[2] == '[')
{
// nested ignore section
- s = parse_doctype_ignore(s);
- if (!s) return s;
+ s += 3;
+ depth++;
}
else if (s[0] == ']' && s[1] == ']' && s[2] == '>')
{
// ignore section end
s += 3;
- return s;
+ if (depth == 0)
+ return s;
+
+ depth--;
}
else s++;
}
@@ -2380,10 +2386,12 @@ PUGI__NS_BEGIN
PUGI__THROW_ERROR(status_bad_doctype, s);
}
- char_t* parse_doctype_group(char_t* s, char_t endch, bool toplevel)
+ char_t* parse_doctype_group(char_t* s, char_t endch)
{
+ size_t depth = 0;
+
assert((s[0] == '<' || s[0] == 0) && s[1] == '!');
- s++;
+ s += 2;
while (*s)
{
@@ -2398,12 +2406,8 @@ PUGI__NS_BEGIN
else
{
// some control group
- s = parse_doctype_group(s, endch, false);
- if (!s) return s;
-
- // skip >
- assert(*s == '>');
- s++;
+ s += 2;
+ depth++;
}
}
else if (s[0] == '<' || s[0] == '"' || s[0] == '\'')
@@ -2414,12 +2418,16 @@ PUGI__NS_BEGIN
}
else if (*s == '>')
{
- return s;
+ if (depth == 0)
+ return s;
+
+ depth--;
+ s++;
}
else s++;
}
- if (!toplevel || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
+ if (depth != 0 || endch != '>') PUGI__THROW_ERROR(status_bad_doctype, s);
return s;
}
@@ -2511,7 +2519,7 @@ PUGI__NS_BEGIN
char_t* mark = s + 9;
- s = parse_doctype_group(s, endch, true);
+ s = parse_doctype_group(s, endch);
if (!s) return s;
assert((*s == 0 && endch == '>') || *s == '>');
@@ -2670,15 +2678,11 @@ PUGI__NS_BEGIN
a->name = s; // Save the offset.
PUGI__SCANWHILE_UNROLL(PUGI__IS_CHARTYPE(ss, ct_symbol)); // Scan for a terminator.
- PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
-
PUGI__ENDSEG(); // Save char in 'ch', terminate & step over.
- PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
if (PUGI__IS_CHARTYPE(ch, ct_space))
{
PUGI__SKIPWS(); // Eat any whitespace.
- PUGI__CHECK_ERROR(status_bad_attribute, s); //$ redundant, left for performance
ch = *s;
++s;
@@ -3647,11 +3651,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);
@@ -3662,11 +3667,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;
@@ -3684,6 +3689,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;
@@ -3719,6 +3729,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)
@@ -3949,10 +3961,18 @@ PUGI__NS_BEGIN
return set_value_buffer(dest, header, header_mask, buf);
}
+ PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, float value)
+ {
+ char buf[128];
+ sprintf(buf, "%.9g", value);
+
+ return set_value_buffer(dest, header, header_mask, buf);
+ }
+
PUGI__FN bool set_value_convert(char_t*& dest, uintptr_t& header, uintptr_t header_mask, double value)
{
char buf[128];
- sprintf(buf, "%g", value);
+ sprintf(buf, "%.17g", value);
return set_value_buffer(dest, header, header_mask, buf);
}
@@ -3990,7 +4010,7 @@ PUGI__NS_BEGIN
_fseeki64(file, 0, SEEK_END);
length_type length = _ftelli64(file);
_fseeki64(file, 0, SEEK_SET);
- #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && !defined(__STRICT_ANSI__)
+ #elif defined(__MINGW32__) && !defined(__NO_MINGW_LFS) && (!defined(__STRICT_ANSI__) || defined(__MINGW64_VERSION_MAJOR))
// there are 64-bit versions of fseek/ftell, let's use them
typedef off64_t length_type;
@@ -4235,7 +4255,7 @@ PUGI__NS_BEGIN
}
#endif
-#if defined(PUGI__MSVC_CRT_VERSION) || defined(__BORLANDC__) || (defined(__MINGW32__) && !defined(__STRICT_ANSI__))
+#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)
{
return _wfopen(path, mode);
@@ -4545,6 +4565,12 @@ namespace pugi
return *this;
}
+ PUGI__FN xml_attribute& xml_attribute::operator=(float rhs)
+ {
+ set_value(rhs);
+ return *this;
+ }
+
PUGI__FN xml_attribute& xml_attribute::operator=(bool rhs)
{
set_value(rhs);
@@ -4600,6 +4626,13 @@ namespace pugi
return impl::set_value_convert(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs);
}
+ PUGI__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);
+ }
+
PUGI__FN bool xml_attribute::set_value(bool rhs)
{
if (!_attr) return false;
@@ -4803,11 +4836,7 @@ namespace pugi
PUGI__FN xml_node xml_node::root() const
{
- if (!_root) return xml_node();
-
- impl::xml_memory_page* page = reinterpret_cast<impl::xml_memory_page*>(_root->header & impl::xml_memory_page_pointer_mask);
-
- return xml_node(static_cast<impl::xml_document_struct*>(page->allocator));
+ return _root ? xml_node(&impl::get_document(_root)) : xml_node();
}
PUGI__FN xml_text xml_node::text() const
@@ -4883,7 +4912,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();
@@ -4897,7 +4926,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();
@@ -4911,7 +4940,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)));
@@ -4926,7 +4955,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)));
@@ -4981,7 +5010,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();
@@ -4995,7 +5024,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();
@@ -5009,7 +5038,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_));
@@ -5024,7 +5053,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_));
@@ -5075,38 +5104,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();
- if (result) impl::node_copy_tree(result.internal_object(), proto.internal_object());
+ xml_node n(impl::allocate_node(impl::get_allocator(_root), type_));
+ if (!n) return xml_node();
- return result;
+ impl::append_node(n._root, _root);
+ impl::node_copy_tree(n._root, proto._root);
+
+ 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.internal_object(), proto.internal_object());
+ 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.internal_object(), proto.internal_object());
+ 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.internal_object(), proto.internal_object());
+ 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)
@@ -5202,8 +5253,7 @@ namespace pugi
if (!impl::allow_insert_child(type(), node_element)) return impl::make_parse_result(status_append_invalid_root);
// get document node
- impl::xml_document_struct* doc = static_cast<impl::xml_document_struct*>(root()._root);
- assert(doc);
+ impl::xml_document_struct* doc = &impl::get_document(_root);
// disable document_buffer_order optimization since in a document with multiple buffers comparing buffer pointers does not make sense
doc->header |= impl::xml_memory_page_contents_shared_mask;
@@ -5414,13 +5464,12 @@ namespace pugi
PUGI__FN ptrdiff_t xml_node::offset_debug() const
{
- xml_node_struct* r = root()._root;
+ if (!_root) return -1;
- if (!r) return -1;
+ impl::xml_document_struct& doc = impl::get_document(_root);
- const char_t* buffer = static_cast<impl::xml_document_struct*>(r)->buffer;
-
- if (!buffer) return -1;
+ // we can determine the offset reliably only if there is exactly once parse buffer
+ if (!doc.buffer || doc.extra_buffers) return -1;
switch (type())
{
@@ -5430,13 +5479,13 @@ namespace pugi
case node_element:
case node_declaration:
case node_pi:
- return (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) ? -1 : _root->name - buffer;
+ return _root->name && (_root->header & impl::xml_memory_page_name_allocated_or_shared_mask) == 0 ? _root->name - doc.buffer : -1;
case node_pcdata:
case node_cdata:
case node_comment:
case node_doctype:
- return (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) ? -1 : _root->value - buffer;
+ return _root->value && (_root->header & impl::xml_memory_page_value_allocated_or_shared_mask) == 0 ? _root->value - doc.buffer : -1;
default:
return -1;
@@ -5587,6 +5636,13 @@ namespace pugi
return dn ? impl::set_value_convert(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs) : false;
}
+ PUGI__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) : false;
+ }
+
PUGI__FN bool xml_text::set(double rhs)
{
xml_node_struct* dn = _data_new();
@@ -5641,6 +5697,12 @@ namespace pugi
return *this;
}
+ PUGI__FN xml_text& xml_text::operator=(float rhs)
+ {
+ set(rhs);
+ return *this;
+ }
+
PUGI__FN xml_text& xml_text::operator=(bool rhs)
{
set(rhs);
@@ -5981,6 +6043,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; )
{
@@ -6010,7 +6073,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
@@ -6022,6 +6085,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();
@@ -6076,7 +6144,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\""));
@@ -7384,7 +7452,7 @@ PUGI__NS_BEGIN
return node.attribute() ? namespace_uri(node.attribute(), node.parent()) : namespace_uri(node.node());
}
- PUGI__FN void normalize_space(char_t* buffer)
+ PUGI__FN char_t* normalize_space(char_t* buffer)
{
char_t* write = buffer;
@@ -7408,9 +7476,11 @@ PUGI__NS_BEGIN
// zero-terminate
*write = 0;
+
+ return write;
}
- PUGI__FN void translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)
+ PUGI__FN char_t* translate(char_t* buffer, const char_t* from, const char_t* to, size_t to_length)
{
char_t* write = buffer;
@@ -7428,6 +7498,8 @@ PUGI__NS_BEGIN
// zero-terminate
*write = 0;
+
+ return write;
}
PUGI__FN unsigned char* translate_table_generate(xpath_allocator* alloc, const char_t* from, const char_t* to)
@@ -7442,6 +7514,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);
@@ -7463,7 +7536,7 @@ PUGI__NS_BEGIN
return static_cast<unsigned char*>(result);
}
- PUGI__FN void translate_table(char_t* buffer, const unsigned char* table)
+ PUGI__FN char_t* translate_table(char_t* buffer, const unsigned char* table)
{
char_t* write = buffer;
@@ -7476,6 +7549,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);
}
@@ -7487,6 +7562,8 @@ PUGI__NS_BEGIN
// zero-terminate
*write = 0;
+
+ return write;
}
inline bool is_xpath_attribute(const char_t* name)
@@ -7749,26 +7826,14 @@ PUGI__NS_BEGIN
return xpath_first(_begin, _end, _type);
}
+ void push_back_grow(const xpath_node& node, xpath_allocator* alloc);
+
void push_back(const xpath_node& node, xpath_allocator* alloc)
{
- if (_end == _eos)
- {
- size_t capacity = static_cast<size_t>(_eos - _begin);
-
- // get new capacity (1.5x rule)
- size_t new_capacity = capacity + capacity / 2 + 1;
-
- // reallocate the old array or allocate a new one
- xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
- assert(data);
-
- // finalize
- _begin = data;
- _end = data + capacity;
- _eos = data + new_capacity;
- }
-
- *_end++ = node;
+ if (_end != _eos)
+ *_end++ = node;
+ else
+ push_back_grow(node, alloc);
}
void append(const xpath_node* begin_, const xpath_node* end_, xpath_allocator* alloc)
@@ -7825,6 +7890,26 @@ PUGI__NS_BEGIN
_type = value;
}
};
+
+ PUGI__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);
+
+ // get new capacity (1.5x rule)
+ size_t new_capacity = capacity + capacity / 2 + 1;
+
+ // reallocate the old array or allocate a new one
+ xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), new_capacity * sizeof(xpath_node)));
+ assert(data);
+
+ // finalize
+ _begin = data;
+ _end = data + capacity;
+ _eos = data + new_capacity;
+
+ // push
+ *_end++ = node;
+ }
PUGI__NS_END
PUGI__NS_BEGIN
@@ -8432,9 +8517,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)
@@ -8606,7 +8691,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);
@@ -8614,7 +8699,7 @@ PUGI__NS_BEGIN
bool step_push(xpath_node_set_raw& ns, xml_attribute_struct* a, xml_node_struct* parent, xpath_allocator* alloc)
{
- assert(a);
+ assert(a);
const char_t* name = a->name ? a->name : PUGIXML_TEXT("");
@@ -8654,7 +8739,7 @@ PUGI__NS_BEGIN
bool step_push(xpath_node_set_raw& ns, xml_node_struct* n, xpath_allocator* alloc)
{
- assert(n);
+ assert(n);
xml_node_type type = PUGI__NODETYPE(n);
@@ -9004,7 +9089,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);
@@ -9015,15 +9100,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)
{
@@ -9040,13 +9126,13 @@ PUGI__NS_BEGIN
if (axis != axis_self && size != 0) ns.set_type(xpath_node_set::type_unsorted);
step_fill(ns, *it, stack.result, once, v);
- apply_predicates(ns, size, stack, eval);
+ if (_right) apply_predicates(ns, size, stack, eval);
}
}
else
{
step_fill(ns, c.n, stack.result, once, v);
- apply_predicates(ns, 0, stack, eval);
+ if (_right) apply_predicates(ns, 0, stack, eval);
}
// child, attribute and self axes always generate unique set of nodes
@@ -9524,9 +9610,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:
@@ -9547,8 +9634,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:
@@ -9582,18 +9670,20 @@ PUGI__NS_BEGIN
{
xpath_string s = string_value(c.n, stack.result);
- normalize_space(s.data(stack.result));
+ char_t* begin = s.data(stack.result);
+ char_t* end = normalize_space(begin);
- return s;
+ return xpath_string::from_heap_preallocated(begin, end);
}
case ast_func_normalize_space_1:
{
xpath_string s = _left->eval_string(c, stack);
- normalize_space(s.data(stack.result));
+ char_t* begin = s.data(stack.result);
+ char_t* end = normalize_space(begin);
- return s;
+ return xpath_string::from_heap_preallocated(begin, end);
}
case ast_func_translate:
@@ -9606,18 +9696,20 @@ PUGI__NS_BEGIN
xpath_string from = _right->eval_string(c, swapped_stack);
xpath_string to = _right->_next->eval_string(c, swapped_stack);
- translate(s.data(stack.result), from.c_str(), to.c_str(), to.length());
+ char_t* begin = s.data(stack.result);
+ char_t* end = translate(begin, from.c_str(), to.c_str(), to.length());
- return s;
+ return xpath_string::from_heap_preallocated(begin, end);
}
case ast_opt_translate_table:
{
xpath_string s = _left->eval_string(c, stack);
- translate_table(s.data(stack.result), _data.table);
+ char_t* begin = s.data(stack.result);
+ char_t* end = translate_table(begin, _data.table);
- return s;
+ return xpath_string::from_heap_preallocated(begin, end);
}
case ast_variable:
@@ -9687,7 +9779,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);