diff options
Diffstat (limited to 'src/pugixml.cpp')
-rw-r--r-- | src/pugixml.cpp | 314 |
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); |