summaryrefslogtreecommitdiff
path: root/src/pugixml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/pugixml.cpp')
-rw-r--r--src/pugixml.cpp521
1 files changed, 295 insertions, 226 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 0813ae6..7e6fe64 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -29,9 +29,6 @@
#ifndef PUGIXML_NO_XPATH
# include <math.h>
# include <float.h>
-# ifdef PUGIXML_NO_EXCEPTIONS
-# include <setjmp.h>
-# endif
#endif
#ifndef PUGIXML_NO_STL
@@ -47,10 +44,8 @@
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4324) // structure was padded due to __declspec(align())
-# pragma warning(disable: 4611) // interaction between '_setjmp' and C++ object destruction is non-portable
# pragma warning(disable: 4702) // unreachable code
# pragma warning(disable: 4996) // this function or variable may be unsafe
-# pragma warning(disable: 4793) // function compiled as native: presence of '_setjmp' makes a function unmanaged
#endif
#ifdef __INTEL_COMPILER
@@ -6118,7 +6113,7 @@ namespace pugi
if (j != _root)
result[--offset] = delimiter;
- if (j->name && *j->name)
+ if (j->name)
{
size_t length = impl::strlength(j->name);
@@ -6137,7 +6132,7 @@ namespace pugi
{
xml_node found = *this; // Current search context.
- if (!_root || !path_ || !path_[0]) return found;
+ if (!_root || !path_[0]) return found;
if (path_[0] == delimiter)
{
@@ -7392,24 +7387,17 @@ PUGI__NS_BEGIN
};
};
- class xpath_allocator
+ struct xpath_allocator
{
xpath_memory_block* _root;
size_t _root_size;
+ bool* _error;
- public:
- #ifdef PUGIXML_NO_EXCEPTIONS
- jmp_buf* error_handler;
- #endif
-
- xpath_allocator(xpath_memory_block* root, size_t root_size = 0): _root(root), _root_size(root_size)
+ xpath_allocator(xpath_memory_block* root, bool* error = 0): _root(root), _root_size(0), _error(error)
{
- #ifdef PUGIXML_NO_EXCEPTIONS
- error_handler = 0;
- #endif
}
- void* allocate_nothrow(size_t size)
+ void* allocate(size_t size)
{
// round size up to block alignment boundary
size = (size + xpath_memory_block_alignment - 1) & ~(xpath_memory_block_alignment - 1);
@@ -7430,7 +7418,11 @@ PUGI__NS_BEGIN
size_t block_size = block_capacity + offsetof(xpath_memory_block, data);
xpath_memory_block* block = static_cast<xpath_memory_block*>(xml_memory::allocate(block_size));
- if (!block) return 0;
+ if (!block)
+ {
+ if (_error) *_error = true;
+ return 0;
+ }
block->next = _root;
block->capacity = block_capacity;
@@ -7442,23 +7434,6 @@ PUGI__NS_BEGIN
}
}
- void* allocate(size_t size)
- {
- void* result = allocate_nothrow(size);
-
- if (!result)
- {
- #ifdef PUGIXML_NO_EXCEPTIONS
- assert(error_handler);
- longjmp(*error_handler, 1);
- #else
- throw std::bad_alloc();
- #endif
- }
-
- return result;
- }
-
void* reallocate(void* ptr, size_t old_size, size_t new_size)
{
// round size up to block alignment boundary
@@ -7468,33 +7443,35 @@ PUGI__NS_BEGIN
// we can only reallocate the last object
assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);
- // adjust root size so that we have not allocated the object at all
- bool only_object = (_root_size == old_size);
-
- if (ptr) _root_size -= old_size;
+ // try to reallocate the object inplace
+ if (ptr && _root_size - old_size + new_size <= _root->capacity)
+ {
+ _root_size = _root_size - old_size + new_size;
+ return ptr;
+ }
- // allocate a new version (this will obviously reuse the memory if possible)
+ // allocate a new block
void* result = allocate(new_size);
- assert(result);
+ if (!result) return 0;
// we have a new block
- if (result != ptr && ptr)
+ if (ptr)
{
- // copy old data
+ // copy old data (we only support growing)
assert(new_size >= old_size);
memcpy(result, ptr, old_size);
// free the previous page if it had no other objects
- if (only_object)
- {
- assert(_root->data == result);
- assert(_root->next);
+ assert(_root->data == result);
+ assert(_root->next);
+ if (_root->next->data == ptr)
+ {
+ // deallocate the whole page, unless it was the first one
xpath_memory_block* next = _root->next->next;
if (next)
{
- // deallocate the whole page, unless it was the first one
xml_memory::deallocate(_root->next);
_root->next = next;
}
@@ -7566,22 +7543,15 @@ PUGI__NS_BEGIN
xpath_allocator result;
xpath_allocator temp;
xpath_stack stack;
+ bool oom;
- #ifdef PUGIXML_NO_EXCEPTIONS
- jmp_buf error_handler;
- #endif
-
- xpath_stack_data(): result(blocks + 0), temp(blocks + 1)
+ xpath_stack_data(): result(blocks + 0, &oom), temp(blocks + 1, &oom), oom(false)
{
blocks[0].next = blocks[1].next = 0;
blocks[0].capacity = blocks[1].capacity = sizeof(blocks[0].data);
stack.result = &result;
stack.temp = &temp;
-
- #ifdef PUGIXML_NO_EXCEPTIONS
- result.error_handler = temp.error_handler = &error_handler;
- #endif
}
~xpath_stack_data()
@@ -7603,7 +7573,7 @@ PUGI__NS_BEGIN
static char_t* duplicate_string(const char_t* string, size_t length, xpath_allocator* alloc)
{
char_t* result = static_cast<char_t*>(alloc->allocate((length + 1) * sizeof(char_t)));
- assert(result);
+ if (!result) return 0;
memcpy(result, string, length * sizeof(char_t));
result[length] = 0;
@@ -7632,9 +7602,13 @@ PUGI__NS_BEGIN
{
assert(begin <= end);
+ if (begin == end)
+ return xpath_string();
+
size_t length = static_cast<size_t>(end - begin);
+ const char_t* data = duplicate_string(begin, length, alloc);
- return length == 0 ? xpath_string() : xpath_string(duplicate_string(begin, length, alloc), true, length);
+ return data ? xpath_string(data, true, length) : xpath_string();
}
xpath_string(): _buffer(PUGIXML_TEXT("")), _uses_heap(false), _length_heap(0)
@@ -7660,7 +7634,7 @@ PUGI__NS_BEGIN
// allocate new buffer
char_t* result = static_cast<char_t*>(alloc->reallocate(_uses_heap ? const_cast<char_t*>(_buffer) : 0, (target_length + 1) * sizeof(char_t), (result_length + 1) * sizeof(char_t)));
- assert(result);
+ if (!result) return;
// append first string to the new buffer in case there was no reallocation
if (!_uses_heap) memcpy(result, _buffer, target_length * sizeof(char_t));
@@ -7692,8 +7666,11 @@ PUGI__NS_BEGIN
if (!_uses_heap)
{
size_t length_ = strlength(_buffer);
+ const char_t* data_ = duplicate_string(_buffer, length_, alloc);
- _buffer = duplicate_string(_buffer, length_, alloc);
+ if (!data_) return 0;
+
+ _buffer = data_;
_uses_heap = true;
_length_heap = length_;
}
@@ -8117,7 +8094,7 @@ PUGI__NS_BEGIN
// allocate a buffer of suitable length for the number
size_t result_size = strlen(mantissa_buffer) + (exponent > 0 ? exponent : -exponent) + 4;
char_t* result = static_cast<char_t*>(alloc->allocate(sizeof(char_t) * result_size));
- assert(result);
+ if (!result) return xpath_string();
// make the number!
char_t* s = result;
@@ -8401,12 +8378,10 @@ PUGI__NS_BEGIN
if (!table[i])
table[i] = static_cast<unsigned char>(i);
- void* result = alloc->allocate_nothrow(sizeof(table));
+ void* result = alloc->allocate(sizeof(table));
+ if (!result) return 0;
- if (result)
- {
- memcpy(result, table, sizeof(table));
- }
+ memcpy(result, table, sizeof(table));
return static_cast<unsigned char*>(result);
}
@@ -8749,7 +8724,7 @@ PUGI__NS_BEGIN
{
// reallocate the old array or allocate a new one
xpath_node* data = static_cast<xpath_node*>(alloc->reallocate(_begin, capacity * sizeof(xpath_node), (size_ + count) * sizeof(xpath_node)));
- assert(data);
+ if (!data) return;
// finalize
_begin = data;
@@ -8801,7 +8776,7 @@ PUGI__NS_BEGIN
// 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);
+ if (!data) return;
// finalize
_begin = data;
@@ -10387,7 +10362,7 @@ PUGI__NS_BEGIN
if (count > sizeof(static_buffer) / sizeof(static_buffer[0]))
{
buffer = static_cast<xpath_string*>(stack.temp->allocate(count * sizeof(xpath_string)));
- assert(buffer);
+ if (!buffer) return xpath_string();
}
// evaluate all strings to temporary stack
@@ -10405,7 +10380,7 @@ PUGI__NS_BEGIN
// create final string
char_t* result = static_cast<char_t*>(stack.result->allocate((length + 1) * sizeof(char_t)));
- assert(result);
+ if (!result) return xpath_string();
char_t* ri = result;
@@ -10572,6 +10547,8 @@ PUGI__NS_BEGIN
xpath_string s = string_value(c.n, stack.result);
char_t* begin = s.data(stack.result);
+ if (!begin) return xpath_string();
+
char_t* end = normalize_space(begin);
return xpath_string::from_heap_preallocated(begin, end);
@@ -10582,6 +10559,8 @@ PUGI__NS_BEGIN
xpath_string s = _left->eval_string(c, stack);
char_t* begin = s.data(stack.result);
+ if (!begin) return xpath_string();
+
char_t* end = normalize_space(begin);
return xpath_string::from_heap_preallocated(begin, end);
@@ -10598,6 +10577,8 @@ PUGI__NS_BEGIN
xpath_string to = _right->_next->eval_string(c, swapped_stack);
char_t* begin = s.data(stack.result);
+ if (!begin) return xpath_string();
+
char_t* end = translate(begin, from.c_str(), to.c_str(), to.length());
return xpath_string::from_heap_preallocated(begin, end);
@@ -10608,6 +10589,8 @@ PUGI__NS_BEGIN
xpath_string s = _left->eval_string(c, stack);
char_t* begin = s.data(stack.result);
+ if (!begin) return xpath_string();
+
char_t* end = translate_table(begin, _data.table);
return xpath_string::from_heap_preallocated(begin, end);
@@ -10917,66 +10900,77 @@ PUGI__NS_BEGIN
char_t _scratch[32];
- #ifdef PUGIXML_NO_EXCEPTIONS
- jmp_buf _error_handler;
- #endif
-
- void throw_error(const char* message)
+ xpath_ast_node* error(const char* message)
{
_result->error = message;
_result->offset = _lexer.current_pos() - _query;
- #ifdef PUGIXML_NO_EXCEPTIONS
- longjmp(_error_handler, 1);
- #else
- throw xpath_exception(*_result);
- #endif
+ return 0;
}
- void throw_error_oom()
+ xpath_ast_node* error_oom()
{
- #ifdef PUGIXML_NO_EXCEPTIONS
- throw_error("Out of memory");
- #else
- throw std::bad_alloc();
- #endif
+ assert(_alloc->_error);
+ *_alloc->_error = true;
+
+ return 0;
}
void* alloc_node()
{
- void* result = _alloc->allocate_nothrow(sizeof(xpath_ast_node));
+ return _alloc->allocate(sizeof(xpath_ast_node));
+ }
- if (!result) throw_error_oom();
+ xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, const char_t* value)
+ {
+ void* memory = alloc_node();
+ return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
+ }
- return result;
+ xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, double value)
+ {
+ void* memory = alloc_node();
+ return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
}
- const char_t* alloc_string(const xpath_lexer_string& value)
+ xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_variable* value)
{
- if (value.begin)
- {
- size_t length = static_cast<size_t>(value.end - value.begin);
+ void* memory = alloc_node();
+ return memory ? new (memory) xpath_ast_node(type, rettype, value) : 0;
+ }
- char_t* c = static_cast<char_t*>(_alloc->allocate_nothrow((length + 1) * sizeof(char_t)));
- if (!c) throw_error_oom();
- assert(c); // workaround for clang static analysis
+ xpath_ast_node* alloc_node(ast_type_t type, xpath_value_type rettype, xpath_ast_node* left = 0, xpath_ast_node* right = 0)
+ {
+ void* memory = alloc_node();
+ return memory ? new (memory) xpath_ast_node(type, rettype, left, right) : 0;
+ }
- memcpy(c, value.begin, length * sizeof(char_t));
- c[length] = 0;
+ xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, axis_t axis, nodetest_t test, const char_t* contents)
+ {
+ void* memory = alloc_node();
+ return memory ? new (memory) xpath_ast_node(type, left, axis, test, contents) : 0;
+ }
- return c;
- }
- else return 0;
+ xpath_ast_node* alloc_node(ast_type_t type, xpath_ast_node* left, xpath_ast_node* right, predicate_t test)
+ {
+ void* memory = alloc_node();
+ return memory ? new (memory) xpath_ast_node(type, left, right, test) : 0;
}
- xpath_ast_node* parse_function_helper(ast_type_t type0, ast_type_t type1, size_t argc, xpath_ast_node* args[2])
+ const char_t* alloc_string(const xpath_lexer_string& value)
{
- assert(argc <= 1);
+ if (!value.begin)
+ return PUGIXML_TEXT("");
+
+ size_t length = static_cast<size_t>(value.end - value.begin);
- if (argc == 1 && args[0]->rettype() != xpath_type_node_set)
- throw_error("Function has to be applied to node set");
+ char_t* c = static_cast<char_t*>(_alloc->allocate((length + 1) * sizeof(char_t)));
+ if (!c) return 0;
- return new (alloc_node()) xpath_ast_node(argc == 0 ? type0 : type1, xpath_type_string, args[0]);
+ memcpy(c, value.begin, length * sizeof(char_t));
+ c[length] = 0;
+
+ return c;
}
xpath_ast_node* parse_function(const xpath_lexer_string& name, size_t argc, xpath_ast_node* args[2])
@@ -10985,103 +10979,110 @@ PUGI__NS_BEGIN
{
case 'b':
if (name == PUGIXML_TEXT("boolean") && argc == 1)
- return new (alloc_node()) xpath_ast_node(ast_func_boolean, xpath_type_boolean, args[0]);
+ return alloc_node(ast_func_boolean, xpath_type_boolean, args[0]);
break;
case 'c':
if (name == PUGIXML_TEXT("count") && argc == 1)
{
- if (args[0]->rettype() != xpath_type_node_set)
- throw_error("Function has to be applied to node set");
-
- return new (alloc_node()) xpath_ast_node(ast_func_count, xpath_type_number, args[0]);
+ if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
+ return alloc_node(ast_func_count, xpath_type_number, args[0]);
}
else if (name == PUGIXML_TEXT("contains") && argc == 2)
- return new (alloc_node()) xpath_ast_node(ast_func_contains, xpath_type_boolean, args[0], args[1]);
+ return alloc_node(ast_func_contains, xpath_type_boolean, args[0], args[1]);
else if (name == PUGIXML_TEXT("concat") && argc >= 2)
- return new (alloc_node()) xpath_ast_node(ast_func_concat, xpath_type_string, args[0], args[1]);
+ return alloc_node(ast_func_concat, xpath_type_string, args[0], args[1]);
else if (name == PUGIXML_TEXT("ceiling") && argc == 1)
- return new (alloc_node()) xpath_ast_node(ast_func_ceiling, xpath_type_number, args[0]);
+ return alloc_node(ast_func_ceiling, xpath_type_number, args[0]);
break;
case 'f':
if (name == PUGIXML_TEXT("false") && argc == 0)
- return new (alloc_node()) xpath_ast_node(ast_func_false, xpath_type_boolean);
+ return alloc_node(ast_func_false, xpath_type_boolean);
else if (name == PUGIXML_TEXT("floor") && argc == 1)
- return new (alloc_node()) xpath_ast_node(ast_func_floor, xpath_type_number, args[0]);
+ return alloc_node(ast_func_floor, xpath_type_number, args[0]);
break;
case 'i':
if (name == PUGIXML_TEXT("id") && argc == 1)
- return new (alloc_node()) xpath_ast_node(ast_func_id, xpath_type_node_set, args[0]);
+ return alloc_node(ast_func_id, xpath_type_node_set, args[0]);
break;
case 'l':
if (name == PUGIXML_TEXT("last") && argc == 0)
- return new (alloc_node()) xpath_ast_node(ast_func_last, xpath_type_number);
+ return alloc_node(ast_func_last, xpath_type_number);
else if (name == PUGIXML_TEXT("lang") && argc == 1)
- return new (alloc_node()) xpath_ast_node(ast_func_lang, xpath_type_boolean, args[0]);
+ return alloc_node(ast_func_lang, xpath_type_boolean, args[0]);
else if (name == PUGIXML_TEXT("local-name") && argc <= 1)
- return parse_function_helper(ast_func_local_name_0, ast_func_local_name_1, argc, args);
+ {
+ if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
+ return alloc_node(argc == 0 ? ast_func_local_name_0 : ast_func_local_name_1, xpath_type_string, args[0]);
+ }
break;
case 'n':
if (name == PUGIXML_TEXT("name") && argc <= 1)
- return parse_function_helper(ast_func_name_0, ast_func_name_1, argc, args);
+ {
+ if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
+ return alloc_node(argc == 0 ? ast_func_name_0 : ast_func_name_1, xpath_type_string, args[0]);
+ }
else if (name == PUGIXML_TEXT("namespace-uri") && argc <= 1)
- return parse_function_helper(ast_func_namespace_uri_0, ast_func_namespace_uri_1, argc, args);
+ {
+ if (argc == 1 && args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
+ return alloc_node(argc == 0 ? ast_func_namespace_uri_0 : ast_func_namespace_uri_1, xpath_type_string, args[0]);
+ }
else if (name == PUGIXML_TEXT("normalize-space") && argc <= 1)
- return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);
+ return alloc_node(argc == 0 ? ast_func_normalize_space_0 : ast_func_normalize_space_1, xpath_type_string, args[0], args[1]);
else if (name == PUGIXML_TEXT("not") && argc == 1)
- return new (alloc_node()) xpath_ast_node(ast_func_not, xpath_type_boolean, args[0]);
+ return alloc_node(ast_func_not, xpath_type_boolean, args[0]);
else if (name == PUGIXML_TEXT("number") && argc <= 1)
- return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
+ return alloc_node(argc == 0 ? ast_func_number_0 : ast_func_number_1, xpath_type_number, args[0]);
break;
case 'p':
if (name == PUGIXML_TEXT("position") && argc == 0)
- return new (alloc_node()) xpath_ast_node(ast_func_position, xpath_type_number);
+ return alloc_node(ast_func_position, xpath_type_number);
break;
case 'r':
if (name == PUGIXML_TEXT("round") && argc == 1)
- return new (alloc_node()) xpath_ast_node(ast_func_round, xpath_type_number, args[0]);
+ return alloc_node(ast_func_round, xpath_type_number, args[0]);
break;
case 's':
if (name == PUGIXML_TEXT("string") && argc <= 1)
- return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
+ return alloc_node(argc == 0 ? ast_func_string_0 : ast_func_string_1, xpath_type_string, args[0]);
else if (name == PUGIXML_TEXT("string-length") && argc <= 1)
- return new (alloc_node()) xpath_ast_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]);
+ return alloc_node(argc == 0 ? ast_func_string_length_0 : ast_func_string_length_1, xpath_type_number, args[0]);
else if (name == PUGIXML_TEXT("starts-with") && argc == 2)
- return new (alloc_node()) xpath_ast_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
+ return alloc_node(ast_func_starts_with, xpath_type_boolean, args[0], args[1]);
else if (name == PUGIXML_TEXT("substring-before") && argc == 2)
- return new (alloc_node()) xpath_ast_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
+ return alloc_node(ast_func_substring_before, xpath_type_string, args[0], args[1]);
else if (name == PUGIXML_TEXT("substring-after") && argc == 2)
- return new (alloc_node()) xpath_ast_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
+ return alloc_node(ast_func_substring_after, xpath_type_string, args[0], args[1]);
else if (name == PUGIXML_TEXT("substring") && (argc == 2 || argc == 3))
- return new (alloc_node()) xpath_ast_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
+ return alloc_node(argc == 2 ? ast_func_substring_2 : ast_func_substring_3, xpath_type_string, args[0], args[1]);
else if (name == PUGIXML_TEXT("sum") && argc == 1)
{
- if (args[0]->rettype() != xpath_type_node_set) throw_error("Function has to be applied to node set");
- return new (alloc_node()) xpath_ast_node(ast_func_sum, xpath_type_number, args[0]);
+ if (args[0]->rettype() != xpath_type_node_set) return error("Function has to be applied to node set");
+ return alloc_node(ast_func_sum, xpath_type_number, args[0]);
}
break;
case 't':
if (name == PUGIXML_TEXT("translate") && argc == 3)
- return new (alloc_node()) xpath_ast_node(ast_func_translate, xpath_type_string, args[0], args[1]);
+ return alloc_node(ast_func_translate, xpath_type_string, args[0], args[1]);
else if (name == PUGIXML_TEXT("true") && argc == 0)
- return new (alloc_node()) xpath_ast_node(ast_func_true, xpath_type_boolean);
+ return alloc_node(ast_func_true, xpath_type_boolean);
break;
@@ -11089,9 +11090,7 @@ PUGI__NS_BEGIN
break;
}
- throw_error("Unrecognized function or wrong parameter count");
-
- return 0;
+ return error("Unrecognized function or wrong parameter count");
}
axis_t parse_axis_name(const xpath_lexer_string& name, bool& specified)
@@ -11207,18 +11206,18 @@ PUGI__NS_BEGIN
xpath_lexer_string name = _lexer.contents();
if (!_variables)
- throw_error("Unknown variable: variable set is not provided");
+ return error("Unknown variable: variable set is not provided");
xpath_variable* var = 0;
if (!get_variable_scratch(_scratch, _variables, name.begin, name.end, &var))
- throw_error_oom();
+ return error_oom();
if (!var)
- throw_error("Unknown variable: variable set does not contain the given name");
+ return error("Unknown variable: variable set does not contain the given name");
_lexer.next();
- return new (alloc_node()) xpath_ast_node(ast_variable, var->type(), var);
+ return alloc_node(ast_variable, var->type(), var);
}
case lex_open_brace:
@@ -11226,9 +11225,10 @@ PUGI__NS_BEGIN
_lexer.next();
xpath_ast_node* n = parse_expression();
+ if (!n) return 0;
if (_lexer.current() != lex_close_brace)
- throw_error("Unmatched braces");
+ return error("Expected ')' to match an opening '('");
_lexer.next();
@@ -11238,11 +11238,11 @@ PUGI__NS_BEGIN
case lex_quoted_string:
{
const char_t* value = alloc_string(_lexer.contents());
+ if (!value) return 0;
- xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_string_constant, xpath_type_string, value);
_lexer.next();
- return n;
+ return alloc_node(ast_string_constant, xpath_type_string, value);
}
case lex_number:
@@ -11250,12 +11250,11 @@ PUGI__NS_BEGIN
double value = 0;
if (!convert_string_to_number_scratch(_scratch, _lexer.contents().begin, _lexer.contents().end, &value))
- throw_error_oom();
+ return error_oom();
- xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_number_constant, xpath_type_number, value);
_lexer.next();
- return n;
+ return alloc_node(ast_number_constant, xpath_type_number, value);
}
case lex_string:
@@ -11269,19 +11268,20 @@ PUGI__NS_BEGIN
xpath_ast_node* last_arg = 0;
if (_lexer.current() != lex_open_brace)
- throw_error("Unrecognized function call");
+ return error("Unrecognized function call");
_lexer.next();
- if (_lexer.current() != lex_close_brace)
- args[argc++] = parse_expression();
-
while (_lexer.current() != lex_close_brace)
{
- if (_lexer.current() != lex_comma)
- throw_error("No comma between function arguments");
- _lexer.next();
+ if (argc > 0)
+ {
+ if (_lexer.current() != lex_comma)
+ return error("No comma between function arguments");
+ _lexer.next();
+ }
xpath_ast_node* n = parse_expression();
+ if (!n) return 0;
if (argc < 2) args[argc] = n;
else last_arg->set_next(n);
@@ -11296,9 +11296,7 @@ PUGI__NS_BEGIN
}
default:
- throw_error("Unrecognizable primary expression");
-
- return 0;
+ return error("Unrecognizable primary expression");
}
}
@@ -11308,20 +11306,23 @@ PUGI__NS_BEGIN
xpath_ast_node* parse_filter_expression()
{
xpath_ast_node* n = parse_primary_expression();
+ if (!n) return 0;
while (_lexer.current() == lex_open_square_brace)
{
_lexer.next();
- xpath_ast_node* expr = parse_expression();
-
if (n->rettype() != xpath_type_node_set)
- throw_error("Predicate has to be applied to node set");
+ return error("Predicate has to be applied to node set");
+
+ xpath_ast_node* expr = parse_expression();
+ if (!expr) return 0;
- n = new (alloc_node()) xpath_ast_node(ast_filter, n, expr, predicate_default);
+ n = alloc_node(ast_filter, n, expr, predicate_default);
+ if (!n) return 0;
if (_lexer.current() != lex_close_square_brace)
- throw_error("Unmatched square brace");
+ return error("Expected ']' to match an opening '['");
_lexer.next();
}
@@ -11337,7 +11338,7 @@ PUGI__NS_BEGIN
xpath_ast_node* parse_step(xpath_ast_node* set)
{
if (set && set->rettype() != xpath_type_node_set)
- throw_error("Step has to be applied to node set");
+ return error("Step has to be applied to node set");
bool axis_specified = false;
axis_t axis = axis_child; // implied child axis
@@ -11353,13 +11354,19 @@ PUGI__NS_BEGIN
{
_lexer.next();
- return new (alloc_node()) xpath_ast_node(ast_step, set, axis_self, nodetest_type_node, 0);
+ if (_lexer.current() == lex_open_square_brace)
+ return error("Predicates are not allowed after an abbreviated step");
+
+ return alloc_node(ast_step, set, axis_self, nodetest_type_node, 0);
}
else if (_lexer.current() == lex_double_dot)
{
_lexer.next();
- return new (alloc_node()) xpath_ast_node(ast_step, set, axis_parent, nodetest_type_node, 0);
+ if (_lexer.current() == lex_open_square_brace)
+ return error("Predicates are not allowed after an abbreviated step");
+
+ return alloc_node(ast_step, set, axis_parent, nodetest_type_node, 0);
}
nodetest_t nt_type = nodetest_none;
@@ -11376,12 +11383,12 @@ PUGI__NS_BEGIN
{
// parse axis name
if (axis_specified)
- throw_error("Two axis specifiers in one step");
+ return error("Two axis specifiers in one step");
axis = parse_axis_name(nt_name, axis_specified);
if (!axis_specified)
- throw_error("Unknown axis");
+ return error("Unknown axis");
// read actual node test
_lexer.next();
@@ -11397,7 +11404,10 @@ PUGI__NS_BEGIN
nt_name = _lexer.contents();
_lexer.next();
}
- else throw_error("Unrecognized node test");
+ else
+ {
+ return error("Unrecognized node test");
+ }
}
if (nt_type == nodetest_none)
@@ -11414,26 +11424,26 @@ PUGI__NS_BEGIN
nt_type = parse_node_test_type(nt_name);
if (nt_type == nodetest_none)
- throw_error("Unrecognized node type");
+ return error("Unrecognized node type");
nt_name = xpath_lexer_string();
}
else if (nt_name == PUGIXML_TEXT("processing-instruction"))
{
if (_lexer.current() != lex_quoted_string)
- throw_error("Only literals are allowed as arguments to processing-instruction()");
+ return error("Only literals are allowed as arguments to processing-instruction()");
nt_type = nodetest_pi;
nt_name = _lexer.contents();
_lexer.next();
if (_lexer.current() != lex_close_brace)
- throw_error("Unmatched brace near processing-instruction()");
+ return error("Unmatched brace near processing-instruction()");
_lexer.next();
}
else
{
- throw_error("Unmatched brace near node type test");
+ return error("Unmatched brace near node type test");
}
}
// QName or NCName:*
@@ -11459,11 +11469,14 @@ PUGI__NS_BEGIN
}
else
{
- throw_error("Unrecognized node test");
+ return error("Unrecognized node test");
}
const char_t* nt_name_copy = alloc_string(nt_name);
- xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step, set, axis, nt_type, nt_name_copy);
+ if (!nt_name_copy) return 0;
+
+ xpath_ast_node* n = alloc_node(ast_step, set, axis, nt_type, nt_name_copy);
+ if (!n) return 0;
xpath_ast_node* last = 0;
@@ -11472,11 +11485,13 @@ PUGI__NS_BEGIN
_lexer.next();
xpath_ast_node* expr = parse_expression();
+ if (!expr) return 0;
- xpath_ast_node* pred = new (alloc_node()) xpath_ast_node(ast_predicate, 0, expr, predicate_default);
+ xpath_ast_node* pred = alloc_node(ast_predicate, 0, expr, predicate_default);
+ if (!pred) return 0;
if (_lexer.current() != lex_close_square_brace)
- throw_error("Unmatched square brace");
+ return error("Expected ']' to match an opening '['");
_lexer.next();
if (last) last->set_next(pred);
@@ -11492,6 +11507,7 @@ PUGI__NS_BEGIN
xpath_ast_node* parse_relative_location_path(xpath_ast_node* set)
{
xpath_ast_node* n = parse_step(set);
+ if (!n) return 0;
while (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
{
@@ -11499,9 +11515,13 @@ PUGI__NS_BEGIN
_lexer.next();
if (l == lex_double_slash)
- n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+ {
+ n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+ if (!n) return 0;
+ }
n = parse_step(n);
+ if (!n) return 0;
}
return n;
@@ -11515,7 +11535,8 @@ PUGI__NS_BEGIN
{
_lexer.next();
- xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
+ xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set);
+ if (!n) return 0;
// relative location path can start from axis_attribute, dot, double_dot, multiply and string lexemes; any other lexeme means standalone root path
lexeme_t l = _lexer.current();
@@ -11529,8 +11550,11 @@ PUGI__NS_BEGIN
{
_lexer.next();
- xpath_ast_node* n = new (alloc_node()) xpath_ast_node(ast_step_root, xpath_type_node_set);
- n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+ xpath_ast_node* n = alloc_node(ast_step_root, xpath_type_node_set);
+ if (!n) return 0;
+
+ n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+ if (!n) return 0;
return parse_relative_location_path(n);
}
@@ -11553,7 +11577,6 @@ PUGI__NS_BEGIN
// PrimaryExpr begins with '$' in case of it being a variable reference,
// '(' in case of it being an expression, string literal, number constant or
// function call.
-
if (_lexer.current() == lex_var_ref || _lexer.current() == lex_open_brace ||
_lexer.current() == lex_quoted_string || _lexer.current() == lex_number ||
_lexer.current() == lex_string)
@@ -11565,7 +11588,8 @@ PUGI__NS_BEGIN
while (PUGI__IS_CHARTYPE(*state, ct_space)) ++state;
- if (*state != '(') return parse_location_path();
+ if (*state != '(')
+ return parse_location_path();
// This looks like a function call; however this still can be a node-test. Check it.
if (parse_node_test_type(_lexer.contents()) != nodetest_none)
@@ -11573,6 +11597,7 @@ PUGI__NS_BEGIN
}
xpath_ast_node* n = parse_filter_expression();
+ if (!n) return 0;
if (_lexer.current() == lex_slash || _lexer.current() == lex_double_slash)
{
@@ -11582,9 +11607,10 @@ PUGI__NS_BEGIN
if (l == lex_double_slash)
{
if (n->rettype() != xpath_type_node_set)
- throw_error("Step has to be applied to node set");
+ return error("Step has to be applied to node set");
- n = new (alloc_node()) xpath_ast_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+ n = alloc_node(ast_step, n, axis_descendant_or_self, nodetest_type_node, 0);
+ if (!n) return 0;
}
// select from location path
@@ -11598,9 +11624,10 @@ PUGI__NS_BEGIN
_lexer.next();
// precedence 7+ - only parses union expressions
- xpath_ast_node* expr = parse_expression_rec(parse_path_or_unary_expression(), 7);
+ xpath_ast_node* n = parse_expression(7);
+ if (!n) return 0;
- return new (alloc_node()) xpath_ast_node(ast_op_negate, xpath_type_number, expr);
+ return alloc_node(ast_op_negate, xpath_type_number, n);
}
else
{
@@ -11683,20 +11710,23 @@ PUGI__NS_BEGIN
_lexer.next();
xpath_ast_node* rhs = parse_path_or_unary_expression();
+ if (!rhs) return 0;
binary_op_t nextop = binary_op_t::parse(_lexer);
while (nextop.asttype != ast_unknown && nextop.precedence > op.precedence)
{
rhs = parse_expression_rec(rhs, nextop.precedence);
+ if (!rhs) return 0;
nextop = binary_op_t::parse(_lexer);
}
if (op.asttype == ast_op_union && (lhs->rettype() != xpath_type_node_set || rhs->rettype() != xpath_type_node_set))
- throw_error("Union operator has to be applied to node sets");
+ return error("Union operator has to be applied to node sets");
- lhs = new (alloc_node()) xpath_ast_node(op.asttype, op.rettype, lhs, rhs);
+ lhs = alloc_node(op.asttype, op.rettype, lhs, rhs);
+ if (!lhs) return 0;
op = binary_op_t::parse(_lexer);
}
@@ -11722,9 +11752,12 @@ PUGI__NS_BEGIN
// | MultiplicativeExpr '*' UnaryExpr
// | MultiplicativeExpr 'div' UnaryExpr
// | MultiplicativeExpr 'mod' UnaryExpr
- xpath_ast_node* parse_expression()
+ xpath_ast_node* parse_expression(int limit = 0)
{
- return parse_expression_rec(parse_path_or_unary_expression(), 0);
+ xpath_ast_node* n = parse_path_or_unary_expression();
+ if (!n) return 0;
+
+ return parse_expression_rec(n, limit);
}
xpath_parser(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result): _alloc(alloc), _lexer(query), _query(query), _variables(variables), _result(result)
@@ -11733,26 +11766,21 @@ PUGI__NS_BEGIN
xpath_ast_node* parse()
{
- xpath_ast_node* result = parse_expression();
+ xpath_ast_node* n = parse_expression();
+ if (!n) return 0;
// check if there are unparsed tokens left
if (_lexer.current() != lex_eof)
- throw_error("Incorrect query");
+ return error("Incorrect query");
- return result;
+ return n;
}
static xpath_ast_node* parse(const char_t* query, xpath_variable_set* variables, xpath_allocator* alloc, xpath_parse_result* result)
{
xpath_parser parser(query, variables, alloc, result);
- #ifdef PUGIXML_NO_EXCEPTIONS
- int error = setjmp(parser._error_handler);
-
- return (error == 0) ? parser.parse() : 0;
- #else
return parser.parse();
- #endif
}
};
@@ -11775,7 +11803,7 @@ PUGI__NS_BEGIN
xml_memory::deallocate(impl);
}
- xpath_query_impl(): root(0), alloc(&block)
+ xpath_query_impl(): root(0), alloc(&block, &oom), oom(false)
{
block.next = 0;
block.capacity = sizeof(block.data);
@@ -11784,19 +11812,27 @@ PUGI__NS_BEGIN
xpath_ast_node* root;
xpath_allocator alloc;
xpath_memory_block block;
+ bool oom;
};
PUGI__FN xpath_string evaluate_string_impl(xpath_query_impl* impl, const xpath_node& n, xpath_stack_data& sd)
{
if (!impl) return xpath_string();
- #ifdef PUGIXML_NO_EXCEPTIONS
- if (setjmp(sd.error_handler)) return xpath_string();
- #endif
-
xpath_context c(n, 1, 1);
- return impl->root->eval_string(c, sd.stack);
+ xpath_string r = impl->root->eval_string(c, sd.stack);
+
+ if (sd.oom)
+ {
+ #ifdef PUGIXML_NO_EXCEPTIONS
+ return xpath_string();
+ #else
+ throw std::bad_alloc();
+ #endif
+ }
+
+ return r;
}
PUGI__FN impl::xpath_ast_node* evaluate_node_set_prepare(xpath_query_impl* impl)
@@ -12369,6 +12405,15 @@ namespace pugi
_impl = impl.release();
_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
+ }
}
}
@@ -12421,11 +12466,18 @@ namespace pugi
impl::xpath_context c(n, 1, 1);
impl::xpath_stack_data sd;
- #ifdef PUGIXML_NO_EXCEPTIONS
- if (setjmp(sd.error_handler)) return false;
- #endif
+ bool r = static_cast<impl::xpath_query_impl*>(_impl)->root->eval_boolean(c, sd.stack);
- return 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
+ }
+
+ return r;
}
PUGI__FN double xpath_query::evaluate_number(const xpath_node& n) const
@@ -12435,11 +12487,18 @@ namespace pugi
impl::xpath_context c(n, 1, 1);
impl::xpath_stack_data sd;
- #ifdef PUGIXML_NO_EXCEPTIONS
- if (setjmp(sd.error_handler)) return impl::gen_nan();
- #endif
+ 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
+ }
- return static_cast<impl::xpath_query_impl*>(_impl)->root->eval_number(c, sd.stack);
+ return r;
}
#ifndef PUGIXML_NO_STL
@@ -12481,12 +12540,17 @@ namespace pugi
impl::xpath_context c(n, 1, 1);
impl::xpath_stack_data sd;
- #ifdef PUGIXML_NO_EXCEPTIONS
- if (setjmp(sd.error_handler)) return xpath_node_set();
- #endif
-
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());
}
@@ -12498,12 +12562,17 @@ namespace pugi
impl::xpath_context c(n, 1, 1);
impl::xpath_stack_data sd;
- #ifdef PUGIXML_NO_EXCEPTIONS
- if (setjmp(sd.error_handler)) return xpath_node();
- #endif
-
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();
}