| Index: third_party/libxml/src/xpath.c
|
| diff --git a/third_party/libxml/src/xpath.c b/third_party/libxml/src/xpath.c
|
| index 9423ef808a364dbfe7d1b9a21c17b61f8c8cb019..dc41ce6b327774adad749c3c58401f485b5a5f0c 100644
|
| --- a/third_party/libxml/src/xpath.c
|
| +++ b/third_party/libxml/src/xpath.c
|
| @@ -55,6 +55,8 @@
|
| #include <libxml/pattern.h>
|
| #endif
|
|
|
| +#include "buf.h"
|
| +
|
| #ifdef LIBXML_PATTERN_ENABLED
|
| #define XPATH_STREAMING
|
| #endif
|
| @@ -64,6 +66,15 @@
|
| "Unimplemented block at %s:%d\n", \
|
| __FILE__, __LINE__);
|
|
|
| +/**
|
| + * WITH_TIM_SORT:
|
| + *
|
| + * Use the Timsort algorithm provided in timsort.h to sort
|
| + * nodeset as this is a great improvement over the old Shell sort
|
| + * used in xmlXPathNodeSetSort()
|
| + */
|
| +#define WITH_TIM_SORT
|
| +
|
| /*
|
| * XP_OPTIMIZED_NON_ELEM_COMPARISON:
|
| * If defined, this will use xmlXPathCmpNodesExt() instead of
|
| @@ -90,252 +101,609 @@
|
| /* #define XP_DEBUG_OBJ_USAGE */
|
|
|
| /*
|
| - * TODO:
|
| - * There are a few spots where some tests are done which depend upon ascii
|
| - * data. These should be enhanced for full UTF8 support (see particularly
|
| - * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
|
| + * XPATH_MAX_STEPS:
|
| + * when compiling an XPath expression we arbitrary limit the maximum
|
| + * number of step operation in the compiled expression. 1000000 is
|
| + * an insanely large value which should never be reached under normal
|
| + * circumstances
|
| */
|
| -
|
| -#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
|
| -
|
| -/************************************************************************
|
| - * *
|
| - * Floating point stuff *
|
| - * *
|
| - ************************************************************************/
|
| -
|
| -#ifndef TRIO_REPLACE_STDIO
|
| -#define TRIO_PUBLIC static
|
| -#endif
|
| -#include "trionan.c"
|
| +#define XPATH_MAX_STEPS 1000000
|
|
|
| /*
|
| - * The lack of portability of this section of the libc is annoying !
|
| - */
|
| -double xmlXPathNAN = 0;
|
| -double xmlXPathPINF = 1;
|
| -double xmlXPathNINF = -1;
|
| -static double xmlXPathNZERO = 0; /* not exported from headers */
|
| -static int xmlXPathInitialized = 0;
|
| -
|
| -/**
|
| - * xmlXPathInit:
|
| - *
|
| - * Initialize the XPath environment
|
| - */
|
| -void
|
| -xmlXPathInit(void) {
|
| - if (xmlXPathInitialized) return;
|
| -
|
| - xmlXPathPINF = trio_pinf();
|
| - xmlXPathNINF = trio_ninf();
|
| - xmlXPathNAN = trio_nan();
|
| - xmlXPathNZERO = trio_nzero();
|
| -
|
| - xmlXPathInitialized = 1;
|
| -}
|
| -
|
| -/**
|
| - * xmlXPathIsNaN:
|
| - * @val: a double value
|
| - *
|
| - * Provides a portable isnan() function to detect whether a double
|
| - * is a NotaNumber. Based on trio code
|
| - * http://sourceforge.net/projects/ctrio/
|
| - *
|
| - * Returns 1 if the value is a NaN, 0 otherwise
|
| - */
|
| -int
|
| -xmlXPathIsNaN(double val) {
|
| - return(trio_isnan(val));
|
| -}
|
| -
|
| -/**
|
| - * xmlXPathIsInf:
|
| - * @val: a double value
|
| - *
|
| - * Provides a portable isinf() function to detect whether a double
|
| - * is a +Infinite or -Infinite. Based on trio code
|
| - * http://sourceforge.net/projects/ctrio/
|
| - *
|
| - * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
|
| - */
|
| -int
|
| -xmlXPathIsInf(double val) {
|
| - return(trio_isinf(val));
|
| -}
|
| -
|
| -#endif /* SCHEMAS or XPATH */
|
| -#ifdef LIBXML_XPATH_ENABLED
|
| -/**
|
| - * xmlXPathGetSign:
|
| - * @val: a double value
|
| - *
|
| - * Provides a portable function to detect the sign of a double
|
| - * Modified from trio code
|
| - * http://sourceforge.net/projects/ctrio/
|
| - *
|
| - * Returns 1 if the value is Negative, 0 if positive
|
| + * XPATH_MAX_STACK_DEPTH:
|
| + * when evaluating an XPath expression we arbitrary limit the maximum
|
| + * number of object allowed to be pushed on the stack. 1000000 is
|
| + * an insanely large value which should never be reached under normal
|
| + * circumstances
|
| */
|
| -static int
|
| -xmlXPathGetSign(double val) {
|
| - return(trio_signbit(val));
|
| -}
|
| -
|
| +#define XPATH_MAX_STACK_DEPTH 1000000
|
|
|
| /*
|
| - * TODO: when compatibility allows remove all "fake node libxslt" strings
|
| - * the test should just be name[0] = ' '
|
| + * XPATH_MAX_NODESET_LENGTH:
|
| + * when evaluating an XPath expression nodesets are created and we
|
| + * arbitrary limit the maximum length of those node set. 10000000 is
|
| + * an insanely large value which should never be reached under normal
|
| + * circumstances, one would first need to construct an in memory tree
|
| + * with more than 10 millions nodes.
|
| */
|
| -#ifdef DEBUG_XPATH_EXPRESSION
|
| -#define DEBUG_STEP
|
| -#define DEBUG_EXPR
|
| -#define DEBUG_EVAL_COUNTS
|
| -#endif
|
| +#define XPATH_MAX_NODESET_LENGTH 10000000
|
|
|
| -static xmlNs xmlXPathXMLNamespaceStruct = {
|
| - NULL,
|
| - XML_NAMESPACE_DECL,
|
| - XML_XML_NAMESPACE,
|
| - BAD_CAST "xml",
|
| - NULL,
|
| - NULL
|
| -};
|
| -static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
|
| -#ifndef LIBXML_THREAD_ENABLED
|
| /*
|
| - * Optimizer is disabled only when threaded apps are detected while
|
| - * the library ain't compiled for thread safety.
|
| + * TODO:
|
| + * There are a few spots where some tests are done which depend upon ascii
|
| + * data. These should be enhanced for full UTF8 support (see particularly
|
| + * any use of the macros IS_ASCII_CHARACTER and IS_ASCII_DIGIT)
|
| */
|
| -static int xmlXPathDisableOptimizer = 0;
|
| -#endif
|
| -
|
| -/************************************************************************
|
| - * *
|
| - * Error handling routines *
|
| - * *
|
| - ************************************************************************/
|
|
|
| +#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
|
| /**
|
| - * XP_ERRORNULL:
|
| - * @X: the error code
|
| + * xmlXPathCmpNodesExt:
|
| + * @node1: the first node
|
| + * @node2: the second node
|
| *
|
| - * Macro to raise an XPath error and return NULL.
|
| - */
|
| -#define XP_ERRORNULL(X) \
|
| - { xmlXPathErr(ctxt, X); return(NULL); }
|
| -
|
| -/*
|
| - * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
|
| - */
|
| -static const char *xmlXPathErrorMessages[] = {
|
| - "Ok\n",
|
| - "Number encoding\n",
|
| - "Unfinished literal\n",
|
| - "Start of literal\n",
|
| - "Expected $ for variable reference\n",
|
| - "Undefined variable\n",
|
| - "Invalid predicate\n",
|
| - "Invalid expression\n",
|
| - "Missing closing curly brace\n",
|
| - "Unregistered function\n",
|
| - "Invalid operand\n",
|
| - "Invalid type\n",
|
| - "Invalid number of arguments\n",
|
| - "Invalid context size\n",
|
| - "Invalid context position\n",
|
| - "Memory allocation error\n",
|
| - "Syntax error\n",
|
| - "Resource error\n",
|
| - "Sub resource error\n",
|
| - "Undefined namespace prefix\n",
|
| - "Encoding error\n",
|
| - "Char out of XML range\n",
|
| - "Invalid or incomplete context\n",
|
| - "?? Unknown error ??\n" /* Must be last in the list! */
|
| -};
|
| -#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
|
| - sizeof(xmlXPathErrorMessages[0])) - 1)
|
| -/**
|
| - * xmlXPathErrMemory:
|
| - * @ctxt: an XPath context
|
| - * @extra: extra informations
|
| + * Compare two nodes w.r.t document order.
|
| + * This one is optimized for handling of non-element nodes.
|
| *
|
| - * Handle a redefinition of attribute error
|
| + * Returns -2 in case of error 1 if first point < second point, 0 if
|
| + * it's the same node, -1 otherwise
|
| */
|
| -static void
|
| -xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
|
| -{
|
| - if (ctxt != NULL) {
|
| - if (extra) {
|
| - xmlChar buf[200];
|
| +static int
|
| +xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
|
| + int depth1, depth2;
|
| + int misc = 0, precedence1 = 0, precedence2 = 0;
|
| + xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
|
| + xmlNodePtr cur, root;
|
| + long l1, l2;
|
|
|
| - xmlStrPrintf(buf, 200,
|
| - BAD_CAST "Memory allocation failed : %s\n",
|
| - extra);
|
| - ctxt->lastError.message = (char *) xmlStrdup(buf);
|
| - } else {
|
| - ctxt->lastError.message = (char *)
|
| - xmlStrdup(BAD_CAST "Memory allocation failed\n");
|
| - }
|
| - ctxt->lastError.domain = XML_FROM_XPATH;
|
| - ctxt->lastError.code = XML_ERR_NO_MEMORY;
|
| - if (ctxt->error != NULL)
|
| - ctxt->error(ctxt->userData, &ctxt->lastError);
|
| - } else {
|
| - if (extra)
|
| - __xmlRaiseError(NULL, NULL, NULL,
|
| - NULL, NULL, XML_FROM_XPATH,
|
| - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
|
| - extra, NULL, NULL, 0, 0,
|
| - "Memory allocation failed : %s\n", extra);
|
| - else
|
| - __xmlRaiseError(NULL, NULL, NULL,
|
| - NULL, NULL, XML_FROM_XPATH,
|
| - XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
|
| - NULL, NULL, NULL, 0, 0,
|
| - "Memory allocation failed\n");
|
| - }
|
| -}
|
| + if ((node1 == NULL) || (node2 == NULL))
|
| + return(-2);
|
|
|
| -/**
|
| - * xmlXPathPErrMemory:
|
| - * @ctxt: an XPath parser context
|
| - * @extra: extra informations
|
| - *
|
| - * Handle a redefinition of attribute error
|
| - */
|
| -static void
|
| -xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
|
| -{
|
| - if (ctxt == NULL)
|
| - xmlXPathErrMemory(NULL, extra);
|
| - else {
|
| - ctxt->error = XPATH_MEMORY_ERROR;
|
| - xmlXPathErrMemory(ctxt->context, extra);
|
| - }
|
| -}
|
| + if (node1 == node2)
|
| + return(0);
|
|
|
| -/**
|
| - * xmlXPathErr:
|
| - * @ctxt: a XPath parser context
|
| - * @error: the error code
|
| - *
|
| - * Handle an XPath error
|
| - */
|
| -void
|
| -xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
|
| -{
|
| - if ((error < 0) || (error > MAXERRNO))
|
| - error = MAXERRNO;
|
| - if (ctxt == NULL) {
|
| - __xmlRaiseError(NULL, NULL, NULL,
|
| - NULL, NULL, XML_FROM_XPATH,
|
| - error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
|
| - XML_ERR_ERROR, NULL, 0,
|
| - NULL, NULL, NULL, 0, 0,
|
| - "%s", xmlXPathErrorMessages[error]);
|
| - return;
|
| + /*
|
| + * a couple of optimizations which will avoid computations in most cases
|
| + */
|
| + switch (node1->type) {
|
| + case XML_ELEMENT_NODE:
|
| + if (node2->type == XML_ELEMENT_NODE) {
|
| + if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
|
| + (0 > (long) node2->content) &&
|
| + (node1->doc == node2->doc))
|
| + {
|
| + l1 = -((long) node1->content);
|
| + l2 = -((long) node2->content);
|
| + if (l1 < l2)
|
| + return(1);
|
| + if (l1 > l2)
|
| + return(-1);
|
| + } else
|
| + goto turtle_comparison;
|
| + }
|
| + break;
|
| + case XML_ATTRIBUTE_NODE:
|
| + precedence1 = 1; /* element is owner */
|
| + miscNode1 = node1;
|
| + node1 = node1->parent;
|
| + misc = 1;
|
| + break;
|
| + case XML_TEXT_NODE:
|
| + case XML_CDATA_SECTION_NODE:
|
| + case XML_COMMENT_NODE:
|
| + case XML_PI_NODE: {
|
| + miscNode1 = node1;
|
| + /*
|
| + * Find nearest element node.
|
| + */
|
| + if (node1->prev != NULL) {
|
| + do {
|
| + node1 = node1->prev;
|
| + if (node1->type == XML_ELEMENT_NODE) {
|
| + precedence1 = 3; /* element in prev-sibl axis */
|
| + break;
|
| + }
|
| + if (node1->prev == NULL) {
|
| + precedence1 = 2; /* element is parent */
|
| + /*
|
| + * URGENT TODO: Are there any cases, where the
|
| + * parent of such a node is not an element node?
|
| + */
|
| + node1 = node1->parent;
|
| + break;
|
| + }
|
| + } while (1);
|
| + } else {
|
| + precedence1 = 2; /* element is parent */
|
| + node1 = node1->parent;
|
| + }
|
| + if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
|
| + (0 <= (long) node1->content)) {
|
| + /*
|
| + * Fallback for whatever case.
|
| + */
|
| + node1 = miscNode1;
|
| + precedence1 = 0;
|
| + } else
|
| + misc = 1;
|
| + }
|
| + break;
|
| + case XML_NAMESPACE_DECL:
|
| + /*
|
| + * TODO: why do we return 1 for namespace nodes?
|
| + */
|
| + return(1);
|
| + default:
|
| + break;
|
| + }
|
| + switch (node2->type) {
|
| + case XML_ELEMENT_NODE:
|
| + break;
|
| + case XML_ATTRIBUTE_NODE:
|
| + precedence2 = 1; /* element is owner */
|
| + miscNode2 = node2;
|
| + node2 = node2->parent;
|
| + misc = 1;
|
| + break;
|
| + case XML_TEXT_NODE:
|
| + case XML_CDATA_SECTION_NODE:
|
| + case XML_COMMENT_NODE:
|
| + case XML_PI_NODE: {
|
| + miscNode2 = node2;
|
| + if (node2->prev != NULL) {
|
| + do {
|
| + node2 = node2->prev;
|
| + if (node2->type == XML_ELEMENT_NODE) {
|
| + precedence2 = 3; /* element in prev-sibl axis */
|
| + break;
|
| + }
|
| + if (node2->prev == NULL) {
|
| + precedence2 = 2; /* element is parent */
|
| + node2 = node2->parent;
|
| + break;
|
| + }
|
| + } while (1);
|
| + } else {
|
| + precedence2 = 2; /* element is parent */
|
| + node2 = node2->parent;
|
| + }
|
| + if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
|
| + (0 <= (long) node2->content))
|
| + {
|
| + node2 = miscNode2;
|
| + precedence2 = 0;
|
| + } else
|
| + misc = 1;
|
| + }
|
| + break;
|
| + case XML_NAMESPACE_DECL:
|
| + return(1);
|
| + default:
|
| + break;
|
| + }
|
| + if (misc) {
|
| + if (node1 == node2) {
|
| + if (precedence1 == precedence2) {
|
| + /*
|
| + * The ugly case; but normally there aren't many
|
| + * adjacent non-element nodes around.
|
| + */
|
| + cur = miscNode2->prev;
|
| + while (cur != NULL) {
|
| + if (cur == miscNode1)
|
| + return(1);
|
| + if (cur->type == XML_ELEMENT_NODE)
|
| + return(-1);
|
| + cur = cur->prev;
|
| + }
|
| + return (-1);
|
| + } else {
|
| + /*
|
| + * Evaluate based on higher precedence wrt to the element.
|
| + * TODO: This assumes attributes are sorted before content.
|
| + * Is this 100% correct?
|
| + */
|
| + if (precedence1 < precedence2)
|
| + return(1);
|
| + else
|
| + return(-1);
|
| + }
|
| + }
|
| + /*
|
| + * Special case: One of the helper-elements is contained by the other.
|
| + * <foo>
|
| + * <node2>
|
| + * <node1>Text-1(precedence1 == 2)</node1>
|
| + * </node2>
|
| + * Text-6(precedence2 == 3)
|
| + * </foo>
|
| + */
|
| + if ((precedence2 == 3) && (precedence1 > 1)) {
|
| + cur = node1->parent;
|
| + while (cur) {
|
| + if (cur == node2)
|
| + return(1);
|
| + cur = cur->parent;
|
| + }
|
| + }
|
| + if ((precedence1 == 3) && (precedence2 > 1)) {
|
| + cur = node2->parent;
|
| + while (cur) {
|
| + if (cur == node1)
|
| + return(-1);
|
| + cur = cur->parent;
|
| + }
|
| + }
|
| + }
|
| +
|
| + /*
|
| + * Speedup using document order if availble.
|
| + */
|
| + if ((node1->type == XML_ELEMENT_NODE) &&
|
| + (node2->type == XML_ELEMENT_NODE) &&
|
| + (0 > (long) node1->content) &&
|
| + (0 > (long) node2->content) &&
|
| + (node1->doc == node2->doc)) {
|
| +
|
| + l1 = -((long) node1->content);
|
| + l2 = -((long) node2->content);
|
| + if (l1 < l2)
|
| + return(1);
|
| + if (l1 > l2)
|
| + return(-1);
|
| + }
|
| +
|
| +turtle_comparison:
|
| +
|
| + if (node1 == node2->prev)
|
| + return(1);
|
| + if (node1 == node2->next)
|
| + return(-1);
|
| + /*
|
| + * compute depth to root
|
| + */
|
| + for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
|
| + if (cur == node1)
|
| + return(1);
|
| + depth2++;
|
| + }
|
| + root = cur;
|
| + for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
|
| + if (cur == node2)
|
| + return(-1);
|
| + depth1++;
|
| + }
|
| + /*
|
| + * Distinct document (or distinct entities :-( ) case.
|
| + */
|
| + if (root != cur) {
|
| + return(-2);
|
| + }
|
| + /*
|
| + * get the nearest common ancestor.
|
| + */
|
| + while (depth1 > depth2) {
|
| + depth1--;
|
| + node1 = node1->parent;
|
| + }
|
| + while (depth2 > depth1) {
|
| + depth2--;
|
| + node2 = node2->parent;
|
| + }
|
| + while (node1->parent != node2->parent) {
|
| + node1 = node1->parent;
|
| + node2 = node2->parent;
|
| + /* should not happen but just in case ... */
|
| + if ((node1 == NULL) || (node2 == NULL))
|
| + return(-2);
|
| + }
|
| + /*
|
| + * Find who's first.
|
| + */
|
| + if (node1 == node2->prev)
|
| + return(1);
|
| + if (node1 == node2->next)
|
| + return(-1);
|
| + /*
|
| + * Speedup using document order if availble.
|
| + */
|
| + if ((node1->type == XML_ELEMENT_NODE) &&
|
| + (node2->type == XML_ELEMENT_NODE) &&
|
| + (0 > (long) node1->content) &&
|
| + (0 > (long) node2->content) &&
|
| + (node1->doc == node2->doc)) {
|
| +
|
| + l1 = -((long) node1->content);
|
| + l2 = -((long) node2->content);
|
| + if (l1 < l2)
|
| + return(1);
|
| + if (l1 > l2)
|
| + return(-1);
|
| + }
|
| +
|
| + for (cur = node1->next;cur != NULL;cur = cur->next)
|
| + if (cur == node2)
|
| + return(1);
|
| + return(-1); /* assume there is no sibling list corruption */
|
| +}
|
| +#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
|
| +
|
| +/*
|
| + * Wrapper for the Timsort argorithm from timsort.h
|
| + */
|
| +#ifdef WITH_TIM_SORT
|
| +#define SORT_NAME libxml_domnode
|
| +#define SORT_TYPE xmlNodePtr
|
| +/**
|
| + * wrap_cmp:
|
| + * @x: a node
|
| + * @y: another node
|
| + *
|
| + * Comparison function for the Timsort implementation
|
| + *
|
| + * Returns -2 in case of error -1 if first point < second point, 0 if
|
| + * it's the same node, +1 otherwise
|
| + */
|
| +static
|
| +int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
|
| +#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
|
| + static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
|
| + {
|
| + int res = xmlXPathCmpNodesExt(x, y);
|
| + return res == -2 ? res : -res;
|
| + }
|
| +#else
|
| + static int wrap_cmp( xmlNodePtr x, xmlNodePtr y )
|
| + {
|
| + int res = xmlXPathCmpNodes(x, y);
|
| + return res == -2 ? res : -res;
|
| + }
|
| +#endif
|
| +#define SORT_CMP(x, y) (wrap_cmp(x, y))
|
| +#include "timsort.h"
|
| +#endif /* WITH_TIM_SORT */
|
| +
|
| +#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
|
| +
|
| +/************************************************************************
|
| + * *
|
| + * Floating point stuff *
|
| + * *
|
| + ************************************************************************/
|
| +
|
| +#ifndef TRIO_REPLACE_STDIO
|
| +#define TRIO_PUBLIC static
|
| +#endif
|
| +#include "trionan.c"
|
| +
|
| +/*
|
| + * The lack of portability of this section of the libc is annoying !
|
| + */
|
| +double xmlXPathNAN = 0;
|
| +double xmlXPathPINF = 1;
|
| +double xmlXPathNINF = -1;
|
| +static double xmlXPathNZERO = 0; /* not exported from headers */
|
| +static int xmlXPathInitialized = 0;
|
| +
|
| +/**
|
| + * xmlXPathInit:
|
| + *
|
| + * Initialize the XPath environment
|
| + */
|
| +void
|
| +xmlXPathInit(void) {
|
| + if (xmlXPathInitialized) return;
|
| +
|
| + xmlXPathPINF = trio_pinf();
|
| + xmlXPathNINF = trio_ninf();
|
| + xmlXPathNAN = trio_nan();
|
| + xmlXPathNZERO = trio_nzero();
|
| +
|
| + xmlXPathInitialized = 1;
|
| +}
|
| +
|
| +/**
|
| + * xmlXPathIsNaN:
|
| + * @val: a double value
|
| + *
|
| + * Provides a portable isnan() function to detect whether a double
|
| + * is a NotaNumber. Based on trio code
|
| + * http://sourceforge.net/projects/ctrio/
|
| + *
|
| + * Returns 1 if the value is a NaN, 0 otherwise
|
| + */
|
| +int
|
| +xmlXPathIsNaN(double val) {
|
| + return(trio_isnan(val));
|
| +}
|
| +
|
| +/**
|
| + * xmlXPathIsInf:
|
| + * @val: a double value
|
| + *
|
| + * Provides a portable isinf() function to detect whether a double
|
| + * is a +Infinite or -Infinite. Based on trio code
|
| + * http://sourceforge.net/projects/ctrio/
|
| + *
|
| + * Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
|
| + */
|
| +int
|
| +xmlXPathIsInf(double val) {
|
| + return(trio_isinf(val));
|
| +}
|
| +
|
| +#endif /* SCHEMAS or XPATH */
|
| +#ifdef LIBXML_XPATH_ENABLED
|
| +/**
|
| + * xmlXPathGetSign:
|
| + * @val: a double value
|
| + *
|
| + * Provides a portable function to detect the sign of a double
|
| + * Modified from trio code
|
| + * http://sourceforge.net/projects/ctrio/
|
| + *
|
| + * Returns 1 if the value is Negative, 0 if positive
|
| + */
|
| +static int
|
| +xmlXPathGetSign(double val) {
|
| + return(trio_signbit(val));
|
| +}
|
| +
|
| +
|
| +/*
|
| + * TODO: when compatibility allows remove all "fake node libxslt" strings
|
| + * the test should just be name[0] = ' '
|
| + */
|
| +#ifdef DEBUG_XPATH_EXPRESSION
|
| +#define DEBUG_STEP
|
| +#define DEBUG_EXPR
|
| +#define DEBUG_EVAL_COUNTS
|
| +#endif
|
| +
|
| +static xmlNs xmlXPathXMLNamespaceStruct = {
|
| + NULL,
|
| + XML_NAMESPACE_DECL,
|
| + XML_XML_NAMESPACE,
|
| + BAD_CAST "xml",
|
| + NULL,
|
| + NULL
|
| +};
|
| +static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
|
| +#ifndef LIBXML_THREAD_ENABLED
|
| +/*
|
| + * Optimizer is disabled only when threaded apps are detected while
|
| + * the library ain't compiled for thread safety.
|
| + */
|
| +static int xmlXPathDisableOptimizer = 0;
|
| +#endif
|
| +
|
| +/************************************************************************
|
| + * *
|
| + * Error handling routines *
|
| + * *
|
| + ************************************************************************/
|
| +
|
| +/**
|
| + * XP_ERRORNULL:
|
| + * @X: the error code
|
| + *
|
| + * Macro to raise an XPath error and return NULL.
|
| + */
|
| +#define XP_ERRORNULL(X) \
|
| + { xmlXPathErr(ctxt, X); return(NULL); }
|
| +
|
| +/*
|
| + * The array xmlXPathErrorMessages corresponds to the enum xmlXPathError
|
| + */
|
| +static const char *xmlXPathErrorMessages[] = {
|
| + "Ok\n",
|
| + "Number encoding\n",
|
| + "Unfinished literal\n",
|
| + "Start of literal\n",
|
| + "Expected $ for variable reference\n",
|
| + "Undefined variable\n",
|
| + "Invalid predicate\n",
|
| + "Invalid expression\n",
|
| + "Missing closing curly brace\n",
|
| + "Unregistered function\n",
|
| + "Invalid operand\n",
|
| + "Invalid type\n",
|
| + "Invalid number of arguments\n",
|
| + "Invalid context size\n",
|
| + "Invalid context position\n",
|
| + "Memory allocation error\n",
|
| + "Syntax error\n",
|
| + "Resource error\n",
|
| + "Sub resource error\n",
|
| + "Undefined namespace prefix\n",
|
| + "Encoding error\n",
|
| + "Char out of XML range\n",
|
| + "Invalid or incomplete context\n",
|
| + "Stack usage error\n",
|
| + "Forbidden variable\n",
|
| + "?? Unknown error ??\n" /* Must be last in the list! */
|
| +};
|
| +#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
|
| + sizeof(xmlXPathErrorMessages[0])) - 1)
|
| +/**
|
| + * xmlXPathErrMemory:
|
| + * @ctxt: an XPath context
|
| + * @extra: extra informations
|
| + *
|
| + * Handle a redefinition of attribute error
|
| + */
|
| +static void
|
| +xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
|
| +{
|
| + if (ctxt != NULL) {
|
| + if (extra) {
|
| + xmlChar buf[200];
|
| +
|
| + xmlStrPrintf(buf, 200,
|
| + BAD_CAST "Memory allocation failed : %s\n",
|
| + extra);
|
| + ctxt->lastError.message = (char *) xmlStrdup(buf);
|
| + } else {
|
| + ctxt->lastError.message = (char *)
|
| + xmlStrdup(BAD_CAST "Memory allocation failed\n");
|
| + }
|
| + ctxt->lastError.domain = XML_FROM_XPATH;
|
| + ctxt->lastError.code = XML_ERR_NO_MEMORY;
|
| + if (ctxt->error != NULL)
|
| + ctxt->error(ctxt->userData, &ctxt->lastError);
|
| + } else {
|
| + if (extra)
|
| + __xmlRaiseError(NULL, NULL, NULL,
|
| + NULL, NULL, XML_FROM_XPATH,
|
| + XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
|
| + extra, NULL, NULL, 0, 0,
|
| + "Memory allocation failed : %s\n", extra);
|
| + else
|
| + __xmlRaiseError(NULL, NULL, NULL,
|
| + NULL, NULL, XML_FROM_XPATH,
|
| + XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0,
|
| + NULL, NULL, NULL, 0, 0,
|
| + "Memory allocation failed\n");
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * xmlXPathPErrMemory:
|
| + * @ctxt: an XPath parser context
|
| + * @extra: extra informations
|
| + *
|
| + * Handle a redefinition of attribute error
|
| + */
|
| +static void
|
| +xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
|
| +{
|
| + if (ctxt == NULL)
|
| + xmlXPathErrMemory(NULL, extra);
|
| + else {
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| + xmlXPathErrMemory(ctxt->context, extra);
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * xmlXPathErr:
|
| + * @ctxt: a XPath parser context
|
| + * @error: the error code
|
| + *
|
| + * Handle an XPath error
|
| + */
|
| +void
|
| +xmlXPathErr(xmlXPathParserContextPtr ctxt, int error)
|
| +{
|
| + if ((error < 0) || (error > MAXERRNO))
|
| + error = MAXERRNO;
|
| + if (ctxt == NULL) {
|
| + __xmlRaiseError(NULL, NULL, NULL,
|
| + NULL, NULL, XML_FROM_XPATH,
|
| + error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
|
| + XML_ERR_ERROR, NULL, 0,
|
| + NULL, NULL, NULL, 0, 0,
|
| + "%s", xmlXPathErrorMessages[error]);
|
| + return;
|
| }
|
| ctxt->error = error;
|
| if (ctxt->context == NULL) {
|
| @@ -419,8 +787,7 @@ xmlPointerListAddSize(xmlPointerListPtr list,
|
| if (list->items == NULL) {
|
| if (initialSize <= 0)
|
| initialSize = 1;
|
| - list->items = (void **) xmlMalloc(
|
| - initialSize * sizeof(void *));
|
| + list->items = (void **) xmlMalloc(initialSize * sizeof(void *));
|
| if (list->items == NULL) {
|
| xmlXPathErrMemory(NULL,
|
| "xmlPointerListCreate: allocating item\n");
|
| @@ -429,12 +796,17 @@ xmlPointerListAddSize(xmlPointerListPtr list,
|
| list->number = 0;
|
| list->size = initialSize;
|
| } else if (list->size <= list->number) {
|
| + if (list->size > 50000000) {
|
| + xmlXPathErrMemory(NULL,
|
| + "xmlPointerListAddSize: re-allocating item\n");
|
| + return(-1);
|
| + }
|
| list->size *= 2;
|
| list->items = (void **) xmlRealloc(list->items,
|
| list->size * sizeof(void *));
|
| if (list->items == NULL) {
|
| xmlXPathErrMemory(NULL,
|
| - "xmlPointerListCreate: re-allocating item\n");
|
| + "xmlPointerListAddSize: re-allocating item\n");
|
| list->size = 0;
|
| return(-1);
|
| }
|
| @@ -552,8 +924,6 @@ typedef enum {
|
| NODE_TYPE_PI = XML_PI_NODE
|
| } xmlXPathTypeVal;
|
|
|
| -#define XP_REWRITE_DOS_CHILD_ELEM 1
|
| -
|
| typedef struct _xmlXPathStepOp xmlXPathStepOp;
|
| typedef xmlXPathStepOp *xmlXPathStepOpPtr;
|
| struct _xmlXPathStepOp {
|
| @@ -567,7 +937,6 @@ struct _xmlXPathStepOp {
|
| void *value5;
|
| void *cache;
|
| void *cacheURI;
|
| - int rewriteType;
|
| };
|
|
|
| struct _xmlXPathCompExpr {
|
| @@ -722,6 +1091,10 @@ xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
|
| if (comp->nbStep >= comp->maxStep) {
|
| xmlXPathStepOp *real;
|
|
|
| + if (comp->maxStep >= XPATH_MAX_STEPS) {
|
| + xmlXPathErrMemory(NULL, "adding step\n");
|
| + return(-1);
|
| + }
|
| comp->maxStep *= 2;
|
| real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
|
| comp->maxStep * sizeof(xmlXPathStepOp));
|
| @@ -733,7 +1106,6 @@ xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, int ch2,
|
| comp->steps = real;
|
| }
|
| comp->last = comp->nbStep;
|
| - comp->steps[comp->nbStep].rewriteType = 0;
|
| comp->steps[comp->nbStep].ch1 = ch1;
|
| comp->steps[comp->nbStep].ch2 = ch2;
|
| comp->steps[comp->nbStep].op = op;
|
| @@ -2051,6 +2423,11 @@ xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
|
| ret->type = XPATH_NODESET;
|
| ret->boolval = 0;
|
| ret->nodesetval = xmlXPathNodeSetCreate(val);
|
| + if (ret->nodesetval == NULL) {
|
| + ctxt->lastError.domain = XML_FROM_XPATH;
|
| + ctxt->lastError.code = XML_ERR_NO_MEMORY;
|
| + return(NULL);
|
| + }
|
| #ifdef XP_DEBUG_OBJ_USAGE
|
| xmlXPathDebugObjUsageRequested(ctxt, XPATH_NODESET);
|
| #endif
|
| @@ -2398,6 +2775,42 @@ xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
|
| ************************************************************************/
|
|
|
| /**
|
| + * xmlXPathSetFrame:
|
| + * @ctxt: an XPath parser context
|
| + *
|
| + * Set the callee evaluation frame
|
| + *
|
| + * Returns the previous frame value to be restored once done
|
| + */
|
| +static int
|
| +xmlXPathSetFrame(xmlXPathParserContextPtr ctxt) {
|
| + int ret;
|
| +
|
| + if (ctxt == NULL)
|
| + return(0);
|
| + ret = ctxt->valueFrame;
|
| + ctxt->valueFrame = ctxt->valueNr;
|
| + return(ret);
|
| +}
|
| +
|
| +/**
|
| + * xmlXPathPopFrame:
|
| + * @ctxt: an XPath parser context
|
| + * @frame: the previous frame value
|
| + *
|
| + * Remove the callee evaluation frame
|
| + */
|
| +static void
|
| +xmlXPathPopFrame(xmlXPathParserContextPtr ctxt, int frame) {
|
| + if (ctxt == NULL)
|
| + return;
|
| + if (ctxt->valueNr < ctxt->valueFrame) {
|
| + xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
|
| + }
|
| + ctxt->valueFrame = frame;
|
| +}
|
| +
|
| +/**
|
| * valuePop:
|
| * @ctxt: an XPath evaluation context
|
| *
|
| @@ -2412,6 +2825,12 @@ valuePop(xmlXPathParserContextPtr ctxt)
|
|
|
| if ((ctxt == NULL) || (ctxt->valueNr <= 0))
|
| return (NULL);
|
| +
|
| + if (ctxt->valueNr <= ctxt->valueFrame) {
|
| + xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_STACK_ERROR);
|
| + return (NULL);
|
| + }
|
| +
|
| ctxt->valueNr--;
|
| if (ctxt->valueNr > 0)
|
| ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
|
| @@ -2437,11 +2856,17 @@ valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
|
| if (ctxt->valueNr >= ctxt->valueMax) {
|
| xmlXPathObjectPtr *tmp;
|
|
|
| + if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
|
| + xmlXPathErrMemory(NULL, "XPath stack depth limit reached\n");
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| + return (0);
|
| + }
|
| tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
|
| 2 * ctxt->valueMax *
|
| sizeof(ctxt->valueTab[0]));
|
| if (tmp == NULL) {
|
| - xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
|
| + xmlXPathErrMemory(NULL, "pushing value\n");
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| return (0);
|
| }
|
| ctxt->valueMax *= 2;
|
| @@ -2751,6 +3176,12 @@ xmlXPathFormatNumber(double number, char buffer[], int buffersize)
|
| fraction_place, number);
|
| }
|
|
|
| + /* Remove leading spaces sometimes inserted by snprintf */
|
| + while (work[0] == ' ') {
|
| + for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
|
| + size--;
|
| + }
|
| +
|
| /* Remove fractional trailing zeroes */
|
| after_fraction = work + size;
|
| ptr = after_fraction;
|
| @@ -2791,390 +3222,103 @@ xmlXPathFormatNumber(double number, char buffer[], int buffersize)
|
| *
|
| * Returns the number of elements found in the document or -1 in case
|
| * of error.
|
| - */
|
| -long
|
| -xmlXPathOrderDocElems(xmlDocPtr doc) {
|
| - long count = 0;
|
| - xmlNodePtr cur;
|
| -
|
| - if (doc == NULL)
|
| - return(-1);
|
| - cur = doc->children;
|
| - while (cur != NULL) {
|
| - if (cur->type == XML_ELEMENT_NODE) {
|
| - cur->content = (void *) (-(++count));
|
| - if (cur->children != NULL) {
|
| - cur = cur->children;
|
| - continue;
|
| - }
|
| - }
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - continue;
|
| - }
|
| - do {
|
| - cur = cur->parent;
|
| - if (cur == NULL)
|
| - break;
|
| - if (cur == (xmlNodePtr) doc) {
|
| - cur = NULL;
|
| - break;
|
| - }
|
| - if (cur->next != NULL) {
|
| - cur = cur->next;
|
| - break;
|
| - }
|
| - } while (cur != NULL);
|
| - }
|
| - return(count);
|
| -}
|
| -
|
| -/**
|
| - * xmlXPathCmpNodes:
|
| - * @node1: the first node
|
| - * @node2: the second node
|
| - *
|
| - * Compare two nodes w.r.t document order
|
| - *
|
| - * Returns -2 in case of error 1 if first point < second point, 0 if
|
| - * it's the same node, -1 otherwise
|
| - */
|
| -int
|
| -xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
|
| - int depth1, depth2;
|
| - int attr1 = 0, attr2 = 0;
|
| - xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
|
| - xmlNodePtr cur, root;
|
| -
|
| - if ((node1 == NULL) || (node2 == NULL))
|
| - return(-2);
|
| - /*
|
| - * a couple of optimizations which will avoid computations in most cases
|
| - */
|
| - if (node1 == node2) /* trivial case */
|
| - return(0);
|
| - if (node1->type == XML_ATTRIBUTE_NODE) {
|
| - attr1 = 1;
|
| - attrNode1 = node1;
|
| - node1 = node1->parent;
|
| - }
|
| - if (node2->type == XML_ATTRIBUTE_NODE) {
|
| - attr2 = 1;
|
| - attrNode2 = node2;
|
| - node2 = node2->parent;
|
| - }
|
| - if (node1 == node2) {
|
| - if (attr1 == attr2) {
|
| - /* not required, but we keep attributes in order */
|
| - if (attr1 != 0) {
|
| - cur = attrNode2->prev;
|
| - while (cur != NULL) {
|
| - if (cur == attrNode1)
|
| - return (1);
|
| - cur = cur->prev;
|
| - }
|
| - return (-1);
|
| - }
|
| - return(0);
|
| - }
|
| - if (attr2 == 1)
|
| - return(1);
|
| - return(-1);
|
| - }
|
| - if ((node1->type == XML_NAMESPACE_DECL) ||
|
| - (node2->type == XML_NAMESPACE_DECL))
|
| - return(1);
|
| - if (node1 == node2->prev)
|
| - return(1);
|
| - if (node1 == node2->next)
|
| - return(-1);
|
| -
|
| - /*
|
| - * Speedup using document order if availble.
|
| - */
|
| - if ((node1->type == XML_ELEMENT_NODE) &&
|
| - (node2->type == XML_ELEMENT_NODE) &&
|
| - (0 > (long) node1->content) &&
|
| - (0 > (long) node2->content) &&
|
| - (node1->doc == node2->doc)) {
|
| - long l1, l2;
|
| -
|
| - l1 = -((long) node1->content);
|
| - l2 = -((long) node2->content);
|
| - if (l1 < l2)
|
| - return(1);
|
| - if (l1 > l2)
|
| - return(-1);
|
| - }
|
| -
|
| - /*
|
| - * compute depth to root
|
| - */
|
| - for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
|
| - if (cur == node1)
|
| - return(1);
|
| - depth2++;
|
| - }
|
| - root = cur;
|
| - for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
|
| - if (cur == node2)
|
| - return(-1);
|
| - depth1++;
|
| - }
|
| - /*
|
| - * Distinct document (or distinct entities :-( ) case.
|
| - */
|
| - if (root != cur) {
|
| - return(-2);
|
| - }
|
| - /*
|
| - * get the nearest common ancestor.
|
| - */
|
| - while (depth1 > depth2) {
|
| - depth1--;
|
| - node1 = node1->parent;
|
| - }
|
| - while (depth2 > depth1) {
|
| - depth2--;
|
| - node2 = node2->parent;
|
| - }
|
| - while (node1->parent != node2->parent) {
|
| - node1 = node1->parent;
|
| - node2 = node2->parent;
|
| - /* should not happen but just in case ... */
|
| - if ((node1 == NULL) || (node2 == NULL))
|
| - return(-2);
|
| - }
|
| - /*
|
| - * Find who's first.
|
| - */
|
| - if (node1 == node2->prev)
|
| - return(1);
|
| - if (node1 == node2->next)
|
| - return(-1);
|
| - /*
|
| - * Speedup using document order if availble.
|
| - */
|
| - if ((node1->type == XML_ELEMENT_NODE) &&
|
| - (node2->type == XML_ELEMENT_NODE) &&
|
| - (0 > (long) node1->content) &&
|
| - (0 > (long) node2->content) &&
|
| - (node1->doc == node2->doc)) {
|
| - long l1, l2;
|
| + */
|
| +long
|
| +xmlXPathOrderDocElems(xmlDocPtr doc) {
|
| + long count = 0;
|
| + xmlNodePtr cur;
|
|
|
| - l1 = -((long) node1->content);
|
| - l2 = -((long) node2->content);
|
| - if (l1 < l2)
|
| - return(1);
|
| - if (l1 > l2)
|
| - return(-1);
|
| + if (doc == NULL)
|
| + return(-1);
|
| + cur = doc->children;
|
| + while (cur != NULL) {
|
| + if (cur->type == XML_ELEMENT_NODE) {
|
| + cur->content = (void *) (-(++count));
|
| + if (cur->children != NULL) {
|
| + cur = cur->children;
|
| + continue;
|
| + }
|
| + }
|
| + if (cur->next != NULL) {
|
| + cur = cur->next;
|
| + continue;
|
| + }
|
| + do {
|
| + cur = cur->parent;
|
| + if (cur == NULL)
|
| + break;
|
| + if (cur == (xmlNodePtr) doc) {
|
| + cur = NULL;
|
| + break;
|
| + }
|
| + if (cur->next != NULL) {
|
| + cur = cur->next;
|
| + break;
|
| + }
|
| + } while (cur != NULL);
|
| }
|
| -
|
| - for (cur = node1->next;cur != NULL;cur = cur->next)
|
| - if (cur == node2)
|
| - return(1);
|
| - return(-1); /* assume there is no sibling list corruption */
|
| + return(count);
|
| }
|
|
|
| -#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
|
| /**
|
| - * xmlXPathCmpNodesExt:
|
| + * xmlXPathCmpNodes:
|
| * @node1: the first node
|
| * @node2: the second node
|
| *
|
| - * Compare two nodes w.r.t document order.
|
| - * This one is optimized for handling of non-element nodes.
|
| + * Compare two nodes w.r.t document order
|
| *
|
| * Returns -2 in case of error 1 if first point < second point, 0 if
|
| * it's the same node, -1 otherwise
|
| */
|
| -static int
|
| -xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
|
| +int
|
| +xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
|
| int depth1, depth2;
|
| - int misc = 0, precedence1 = 0, precedence2 = 0;
|
| - xmlNodePtr miscNode1 = NULL, miscNode2 = NULL;
|
| + int attr1 = 0, attr2 = 0;
|
| + xmlNodePtr attrNode1 = NULL, attrNode2 = NULL;
|
| xmlNodePtr cur, root;
|
| - long l1, l2;
|
|
|
| if ((node1 == NULL) || (node2 == NULL))
|
| return(-2);
|
| -
|
| - if (node1 == node2)
|
| - return(0);
|
| -
|
| /*
|
| * a couple of optimizations which will avoid computations in most cases
|
| */
|
| - switch (node1->type) {
|
| - case XML_ELEMENT_NODE:
|
| - if (node2->type == XML_ELEMENT_NODE) {
|
| - if ((0 > (long) node1->content) && /* TODO: Would a != 0 suffice here? */
|
| - (0 > (long) node2->content) &&
|
| - (node1->doc == node2->doc))
|
| - {
|
| - l1 = -((long) node1->content);
|
| - l2 = -((long) node2->content);
|
| - if (l1 < l2)
|
| - return(1);
|
| - if (l1 > l2)
|
| - return(-1);
|
| - } else
|
| - goto turtle_comparison;
|
| - }
|
| - break;
|
| - case XML_ATTRIBUTE_NODE:
|
| - precedence1 = 1; /* element is owner */
|
| - miscNode1 = node1;
|
| - node1 = node1->parent;
|
| - misc = 1;
|
| - break;
|
| - case XML_TEXT_NODE:
|
| - case XML_CDATA_SECTION_NODE:
|
| - case XML_COMMENT_NODE:
|
| - case XML_PI_NODE: {
|
| - miscNode1 = node1;
|
| - /*
|
| - * Find nearest element node.
|
| - */
|
| - if (node1->prev != NULL) {
|
| - do {
|
| - node1 = node1->prev;
|
| - if (node1->type == XML_ELEMENT_NODE) {
|
| - precedence1 = 3; /* element in prev-sibl axis */
|
| - break;
|
| - }
|
| - if (node1->prev == NULL) {
|
| - precedence1 = 2; /* element is parent */
|
| - /*
|
| - * URGENT TODO: Are there any cases, where the
|
| - * parent of such a node is not an element node?
|
| - */
|
| - node1 = node1->parent;
|
| - break;
|
| - }
|
| - } while (1);
|
| - } else {
|
| - precedence1 = 2; /* element is parent */
|
| - node1 = node1->parent;
|
| - }
|
| - if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
|
| - (0 <= (long) node1->content)) {
|
| - /*
|
| - * Fallback for whatever case.
|
| - */
|
| - node1 = miscNode1;
|
| - precedence1 = 0;
|
| - } else
|
| - misc = 1;
|
| - }
|
| - break;
|
| - case XML_NAMESPACE_DECL:
|
| - /*
|
| - * TODO: why do we return 1 for namespace nodes?
|
| - */
|
| - return(1);
|
| - default:
|
| - break;
|
| + if (node1 == node2) /* trivial case */
|
| + return(0);
|
| + if (node1->type == XML_ATTRIBUTE_NODE) {
|
| + attr1 = 1;
|
| + attrNode1 = node1;
|
| + node1 = node1->parent;
|
| }
|
| - switch (node2->type) {
|
| - case XML_ELEMENT_NODE:
|
| - break;
|
| - case XML_ATTRIBUTE_NODE:
|
| - precedence2 = 1; /* element is owner */
|
| - miscNode2 = node2;
|
| - node2 = node2->parent;
|
| - misc = 1;
|
| - break;
|
| - case XML_TEXT_NODE:
|
| - case XML_CDATA_SECTION_NODE:
|
| - case XML_COMMENT_NODE:
|
| - case XML_PI_NODE: {
|
| - miscNode2 = node2;
|
| - if (node2->prev != NULL) {
|
| - do {
|
| - node2 = node2->prev;
|
| - if (node2->type == XML_ELEMENT_NODE) {
|
| - precedence2 = 3; /* element in prev-sibl axis */
|
| - break;
|
| - }
|
| - if (node2->prev == NULL) {
|
| - precedence2 = 2; /* element is parent */
|
| - node2 = node2->parent;
|
| - break;
|
| - }
|
| - } while (1);
|
| - } else {
|
| - precedence2 = 2; /* element is parent */
|
| - node2 = node2->parent;
|
| - }
|
| - if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
|
| - (0 <= (long) node1->content))
|
| - {
|
| - node2 = miscNode2;
|
| - precedence2 = 0;
|
| - } else
|
| - misc = 1;
|
| - }
|
| - break;
|
| - case XML_NAMESPACE_DECL:
|
| - return(1);
|
| - default:
|
| - break;
|
| + if (node2->type == XML_ATTRIBUTE_NODE) {
|
| + attr2 = 1;
|
| + attrNode2 = node2;
|
| + node2 = node2->parent;
|
| }
|
| - if (misc) {
|
| - if (node1 == node2) {
|
| - if (precedence1 == precedence2) {
|
| - /*
|
| - * The ugly case; but normally there aren't many
|
| - * adjacent non-element nodes around.
|
| - */
|
| - cur = miscNode2->prev;
|
| + if (node1 == node2) {
|
| + if (attr1 == attr2) {
|
| + /* not required, but we keep attributes in order */
|
| + if (attr1 != 0) {
|
| + cur = attrNode2->prev;
|
| while (cur != NULL) {
|
| - if (cur == miscNode1)
|
| - return(1);
|
| - if (cur->type == XML_ELEMENT_NODE)
|
| - return(-1);
|
| + if (cur == attrNode1)
|
| + return (1);
|
| cur = cur->prev;
|
| }
|
| return (-1);
|
| - } else {
|
| - /*
|
| - * Evaluate based on higher precedence wrt to the element.
|
| - * TODO: This assumes attributes are sorted before content.
|
| - * Is this 100% correct?
|
| - */
|
| - if (precedence1 < precedence2)
|
| - return(1);
|
| - else
|
| - return(-1);
|
| - }
|
| - }
|
| - /*
|
| - * Special case: One of the helper-elements is contained by the other.
|
| - * <foo>
|
| - * <node2>
|
| - * <node1>Text-1(precedence1 == 2)</node1>
|
| - * </node2>
|
| - * Text-6(precedence2 == 3)
|
| - * </foo>
|
| - */
|
| - if ((precedence2 == 3) && (precedence1 > 1)) {
|
| - cur = node1->parent;
|
| - while (cur) {
|
| - if (cur == node2)
|
| - return(1);
|
| - cur = cur->parent;
|
| - }
|
| - }
|
| - if ((precedence1 == 3) && (precedence2 > 1)) {
|
| - cur = node2->parent;
|
| - while (cur) {
|
| - if (cur == node1)
|
| - return(-1);
|
| - cur = cur->parent;
|
| }
|
| + return(0);
|
| }
|
| + if (attr2 == 1)
|
| + return(1);
|
| + return(-1);
|
| }
|
| + if ((node1->type == XML_NAMESPACE_DECL) ||
|
| + (node2->type == XML_NAMESPACE_DECL))
|
| + return(1);
|
| + if (node1 == node2->prev)
|
| + return(1);
|
| + if (node1 == node2->next)
|
| + return(-1);
|
|
|
| /*
|
| * Speedup using document order if availble.
|
| @@ -3184,6 +3328,7 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
|
| (0 > (long) node1->content) &&
|
| (0 > (long) node2->content) &&
|
| (node1->doc == node2->doc)) {
|
| + long l1, l2;
|
|
|
| l1 = -((long) node1->content);
|
| l2 = -((long) node2->content);
|
| @@ -3191,14 +3336,8 @@ xmlXPathCmpNodesExt(xmlNodePtr node1, xmlNodePtr node2) {
|
| return(1);
|
| if (l1 > l2)
|
| return(-1);
|
| - }
|
| -
|
| -turtle_comparison:
|
| + }
|
|
|
| - if (node1 == node2->prev)
|
| - return(1);
|
| - if (node1 == node2->next)
|
| - return(-1);
|
| /*
|
| * compute depth to root
|
| */
|
| @@ -3252,6 +3391,7 @@ turtle_comparison:
|
| (0 > (long) node1->content) &&
|
| (0 > (long) node2->content) &&
|
| (node1->doc == node2->doc)) {
|
| + long l1, l2;
|
|
|
| l1 = -((long) node1->content);
|
| l2 = -((long) node2->content);
|
| @@ -3266,7 +3406,6 @@ turtle_comparison:
|
| return(1);
|
| return(-1); /* assume there is no sibling list corruption */
|
| }
|
| -#endif /* XP_OPTIMIZED_NON_ELEM_COMPARISON */
|
|
|
| /**
|
| * xmlXPathNodeSetSort:
|
| @@ -3276,13 +3415,19 @@ turtle_comparison:
|
| */
|
| void
|
| xmlXPathNodeSetSort(xmlNodeSetPtr set) {
|
| +#ifndef WITH_TIM_SORT
|
| int i, j, incr, len;
|
| xmlNodePtr tmp;
|
| +#endif
|
|
|
| if (set == NULL)
|
| return;
|
|
|
| - /* Use Shell's sort to sort the node-set */
|
| +#ifndef WITH_TIM_SORT
|
| + /*
|
| + * Use the old Shell's sort implementation to sort the node-set
|
| + * Timsort ought to be quite faster
|
| + */
|
| len = set->nodeNr;
|
| for (incr = len / 2; incr > 0; incr /= 2) {
|
| for (i = incr; i < len; i++) {
|
| @@ -3305,6 +3450,9 @@ xmlXPathNodeSetSort(xmlNodeSetPtr set) {
|
| }
|
| }
|
| }
|
| +#else /* WITH_TIM_SORT */
|
| + libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
|
| +#endif /* WITH_TIM_SORT */
|
| }
|
|
|
| #define XML_NODESET_DEFAULT 10
|
| @@ -3483,8 +3631,10 @@ xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
|
| * @ns: a the namespace node
|
| *
|
| * add a new namespace node to an existing NodeSet
|
| + *
|
| + * Returns 0 in case of success and -1 in case of error
|
| */
|
| -void
|
| +int
|
| xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
|
| int i;
|
|
|
| @@ -3492,7 +3642,7 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
|
| if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
|
| (ns->type != XML_NAMESPACE_DECL) ||
|
| (node->type != XML_ELEMENT_NODE))
|
| - return;
|
| + return(-1);
|
|
|
| /* @@ with_ns to check whether namespace nodes should be looked at @@ */
|
| /*
|
| @@ -3503,7 +3653,7 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
|
| (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
|
| (((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
|
| (xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
|
| - return;
|
| + return(0);
|
| }
|
|
|
| /*
|
| @@ -3514,7 +3664,7 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
|
| sizeof(xmlNodePtr));
|
| if (cur->nodeTab == NULL) {
|
| xmlXPathErrMemory(NULL, "growing nodeset\n");
|
| - return;
|
| + return(-1);
|
| }
|
| memset(cur->nodeTab, 0 ,
|
| XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
|
| @@ -3522,16 +3672,21 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
|
| } else if (cur->nodeNr == cur->nodeMax) {
|
| xmlNodePtr *temp;
|
|
|
| - cur->nodeMax *= 2;
|
| - temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
|
| + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
| + xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
|
| + return(-1);
|
| + }
|
| + temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
|
| sizeof(xmlNodePtr));
|
| if (temp == NULL) {
|
| xmlXPathErrMemory(NULL, "growing nodeset\n");
|
| - return;
|
| + return(-1);
|
| }
|
| + cur->nodeMax *= 2;
|
| cur->nodeTab = temp;
|
| }
|
| cur->nodeTab[cur->nodeNr++] = xmlXPathNodeSetDupNs(node, ns);
|
| + return(0);
|
| }
|
|
|
| /**
|
| @@ -3540,24 +3695,21 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
|
| * @val: a new xmlNodePtr
|
| *
|
| * add a new xmlNodePtr to an existing NodeSet
|
| + *
|
| + * Returns 0 in case of success, and -1 in case of error
|
| */
|
| -void
|
| +int
|
| xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| int i;
|
|
|
| - if ((cur == NULL) || (val == NULL)) return;
|
| -
|
| -#if 0
|
| - if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
|
| - return; /* an XSLT fake node */
|
| -#endif
|
| + if ((cur == NULL) || (val == NULL)) return(-1);
|
|
|
| /* @@ with_ns to check whether namespace nodes should be looked at @@ */
|
| /*
|
| * prevent duplcates
|
| */
|
| for (i = 0;i < cur->nodeNr;i++)
|
| - if (cur->nodeTab[i] == val) return;
|
| + if (cur->nodeTab[i] == val) return(0);
|
|
|
| /*
|
| * grow the nodeTab if needed
|
| @@ -3567,7 +3719,7 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| sizeof(xmlNodePtr));
|
| if (cur->nodeTab == NULL) {
|
| xmlXPathErrMemory(NULL, "growing nodeset\n");
|
| - return;
|
| + return(-1);
|
| }
|
| memset(cur->nodeTab, 0 ,
|
| XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
|
| @@ -3575,13 +3727,17 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| } else if (cur->nodeNr == cur->nodeMax) {
|
| xmlNodePtr *temp;
|
|
|
| - cur->nodeMax *= 2;
|
| - temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
|
| + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
| + xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
|
| + return(-1);
|
| + }
|
| + temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
|
| sizeof(xmlNodePtr));
|
| if (temp == NULL) {
|
| xmlXPathErrMemory(NULL, "growing nodeset\n");
|
| - return;
|
| + return(-1);
|
| }
|
| + cur->nodeMax *= 2;
|
| cur->nodeTab = temp;
|
| }
|
| if (val->type == XML_NAMESPACE_DECL) {
|
| @@ -3591,6 +3747,7 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
|
| } else
|
| cur->nodeTab[cur->nodeNr++] = val;
|
| + return(0);
|
| }
|
|
|
| /**
|
| @@ -3600,15 +3757,12 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| *
|
| * add a new xmlNodePtr to an existing NodeSet, optimized version
|
| * when we are sure the node is not already in the set.
|
| + *
|
| + * Returns 0 in case of success and -1 in case of failure
|
| */
|
| -void
|
| +int
|
| xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| - if ((cur == NULL) || (val == NULL)) return;
|
| -
|
| -#if 0
|
| - if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' '))
|
| - return; /* an XSLT fake node */
|
| -#endif
|
| + if ((cur == NULL) || (val == NULL)) return(-1);
|
|
|
| /* @@ with_ns to check whether namespace nodes should be looked at @@ */
|
| /*
|
| @@ -3619,7 +3773,7 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| sizeof(xmlNodePtr));
|
| if (cur->nodeTab == NULL) {
|
| xmlXPathErrMemory(NULL, "growing nodeset\n");
|
| - return;
|
| + return(-1);
|
| }
|
| memset(cur->nodeTab, 0 ,
|
| XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
|
| @@ -3627,14 +3781,18 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| } else if (cur->nodeNr == cur->nodeMax) {
|
| xmlNodePtr *temp;
|
|
|
| - cur->nodeMax *= 2;
|
| - temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
|
| + if (cur->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
| + xmlXPathErrMemory(NULL, "growing nodeset hit limit\n");
|
| + return(-1);
|
| + }
|
| + temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax * 2 *
|
| sizeof(xmlNodePtr));
|
| if (temp == NULL) {
|
| xmlXPathErrMemory(NULL, "growing nodeset\n");
|
| - return;
|
| + return(-1);
|
| }
|
| cur->nodeTab = temp;
|
| + cur->nodeMax *= 2;
|
| }
|
| if (val->type == XML_NAMESPACE_DECL) {
|
| xmlNsPtr ns = (xmlNsPtr) val;
|
| @@ -3643,6 +3801,7 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
|
| xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
|
| } else
|
| cur->nodeTab[cur->nodeNr++] = val;
|
| + return(0);
|
| }
|
|
|
| /**
|
| @@ -3738,14 +3897,18 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
| } else if (val1->nodeNr == val1->nodeMax) {
|
| xmlNodePtr *temp;
|
|
|
| - val1->nodeMax *= 2;
|
| - temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
|
| + if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
| + xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
| + return(NULL);
|
| + }
|
| + temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
|
| sizeof(xmlNodePtr));
|
| if (temp == NULL) {
|
| xmlXPathErrMemory(NULL, "merging nodeset\n");
|
| return(NULL);
|
| }
|
| val1->nodeTab = temp;
|
| + val1->nodeMax *= 2;
|
| }
|
| if (n2->type == XML_NAMESPACE_DECL) {
|
| xmlNsPtr ns = (xmlNsPtr) n2;
|
| @@ -3759,68 +3922,6 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
| return(val1);
|
| }
|
|
|
| -#if 0 /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
|
| -/**
|
| - * xmlXPathNodeSetMergeUnique:
|
| - * @val1: the first NodeSet or NULL
|
| - * @val2: the second NodeSet
|
| - *
|
| - * Merges two nodesets, all nodes from @val2 are added to @val1
|
| - * if @val1 is NULL, a new set is created and copied from @val2
|
| - *
|
| - * Returns @val1 once extended or NULL in case of error.
|
| - */
|
| -static xmlNodeSetPtr
|
| -xmlXPathNodeSetMergeUnique(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
|
| - int i;
|
| -
|
| - if (val2 == NULL) return(val1);
|
| - if (val1 == NULL) {
|
| - val1 = xmlXPathNodeSetCreate(NULL);
|
| - }
|
| - if (val1 == NULL)
|
| - return (NULL);
|
| -
|
| - /* @@ with_ns to check whether namespace nodes should be looked at @@ */
|
| -
|
| - for (i = 0;i < val2->nodeNr;i++) {
|
| - /*
|
| - * grow the nodeTab if needed
|
| - */
|
| - if (val1->nodeMax == 0) {
|
| - val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
|
| - sizeof(xmlNodePtr));
|
| - if (val1->nodeTab == NULL) {
|
| - xmlXPathErrMemory(NULL, "merging nodeset\n");
|
| - return(NULL);
|
| - }
|
| - memset(val1->nodeTab, 0 ,
|
| - XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
|
| - val1->nodeMax = XML_NODESET_DEFAULT;
|
| - } else if (val1->nodeNr == val1->nodeMax) {
|
| - xmlNodePtr *temp;
|
| -
|
| - val1->nodeMax *= 2;
|
| - temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
|
| - sizeof(xmlNodePtr));
|
| - if (temp == NULL) {
|
| - xmlXPathErrMemory(NULL, "merging nodeset\n");
|
| - return(NULL);
|
| - }
|
| - val1->nodeTab = temp;
|
| - }
|
| - if (val2->nodeTab[i]->type == XML_NAMESPACE_DECL) {
|
| - xmlNsPtr ns = (xmlNsPtr) val2->nodeTab[i];
|
| -
|
| - val1->nodeTab[val1->nodeNr++] =
|
| - xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
|
| - } else
|
| - val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
|
| - }
|
| -
|
| - return(val1);
|
| -}
|
| -#endif /* xmlXPathNodeSetMergeUnique() is currently not used anymore */
|
|
|
| /**
|
| * xmlXPathNodeSetMergeAndClear:
|
| @@ -3907,14 +4008,18 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
|
| } else if (set1->nodeNr >= set1->nodeMax) {
|
| xmlNodePtr *temp;
|
|
|
| - set1->nodeMax *= 2;
|
| + if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
| + xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
| + return(NULL);
|
| + }
|
| temp = (xmlNodePtr *) xmlRealloc(
|
| - set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
|
| + set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
|
| if (temp == NULL) {
|
| xmlXPathErrMemory(NULL, "merging nodeset\n");
|
| return(NULL);
|
| }
|
| set1->nodeTab = temp;
|
| + set1->nodeMax *= 2;
|
| }
|
| if (n2->type == XML_NAMESPACE_DECL) {
|
| xmlNsPtr ns = (xmlNsPtr) n2;
|
| @@ -3991,14 +4096,18 @@ xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2,
|
| } else if (set1->nodeNr >= set1->nodeMax) {
|
| xmlNodePtr *temp;
|
|
|
| - set1->nodeMax *= 2;
|
| + if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
|
| + xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
|
| + return(NULL);
|
| + }
|
| temp = (xmlNodePtr *) xmlRealloc(
|
| - set1->nodeTab, set1->nodeMax * sizeof(xmlNodePtr));
|
| + set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
|
| if (temp == NULL) {
|
| xmlXPathErrMemory(NULL, "merging nodeset\n");
|
| return(NULL);
|
| }
|
| set1->nodeTab = temp;
|
| + set1->nodeMax *= 2;
|
| }
|
| set1->nodeTab[set1->nodeNr++] = n2;
|
| }
|
| @@ -4289,9 +4398,12 @@ xmlXPathNewNodeSetList(xmlNodeSetPtr val)
|
| ret = xmlXPathNewNodeSet(NULL);
|
| else {
|
| ret = xmlXPathNewNodeSet(val->nodeTab[0]);
|
| - if (ret)
|
| - for (i = 1; i < val->nodeNr; ++i)
|
| - xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
|
| + if (ret) {
|
| + for (i = 1; i < val->nodeNr; ++i) {
|
| + if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
|
| + < 0) break;
|
| + }
|
| + }
|
| }
|
|
|
| return (ret);
|
| @@ -4367,8 +4479,10 @@ xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
|
|
|
| for (i = 0; i < l1; i++) {
|
| cur = xmlXPathNodeSetItem(nodes1, i);
|
| - if (!xmlXPathNodeSetContains(nodes2, cur))
|
| - xmlXPathNodeSetAddUnique(ret, cur);
|
| + if (!xmlXPathNodeSetContains(nodes2, cur)) {
|
| + if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
|
| + break;
|
| + }
|
| }
|
| return(ret);
|
| }
|
| @@ -4401,8 +4515,10 @@ xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
|
|
|
| for (i = 0; i < l1; i++) {
|
| cur = xmlXPathNodeSetItem(nodes1, i);
|
| - if (xmlXPathNodeSetContains(nodes2, cur))
|
| - xmlXPathNodeSetAddUnique(ret, cur);
|
| + if (xmlXPathNodeSetContains(nodes2, cur)) {
|
| + if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
|
| + break;
|
| + }
|
| }
|
| return(ret);
|
| }
|
| @@ -4438,7 +4554,8 @@ xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
|
| strval = xmlXPathCastNodeToString(cur);
|
| if (xmlHashLookup(hash, strval) == NULL) {
|
| xmlHashAddEntry(hash, strval, strval);
|
| - xmlXPathNodeSetAddUnique(ret, cur);
|
| + if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
|
| + break;
|
| } else {
|
| xmlFree(strval);
|
| }
|
| @@ -4530,7 +4647,8 @@ xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
|
| cur = xmlXPathNodeSetItem(nodes, i);
|
| if (cur == node)
|
| break;
|
| - xmlXPathNodeSetAddUnique(ret, cur);
|
| + if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
|
| + break;
|
| }
|
| return(ret);
|
| }
|
| @@ -4634,7 +4752,8 @@ xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
|
| cur = xmlXPathNodeSetItem(nodes, i);
|
| if (cur == node)
|
| break;
|
| - xmlXPathNodeSetAddUnique(ret, cur);
|
| + if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
|
| + break;
|
| }
|
| xmlXPathNodeSetSort(ret); /* bug 413451 */
|
| return(ret);
|
| @@ -6154,6 +6273,7 @@ xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
|
| ret->valueNr = 0;
|
| ret->valueMax = 10;
|
| ret->value = NULL;
|
| + ret->valueFrame = 0;
|
|
|
| ret->context = ctxt;
|
| ret->comp = comp;
|
| @@ -7656,6 +7776,7 @@ xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
|
| return(NULL);
|
| }
|
|
|
| +#if 0
|
| /**
|
| * xmlXPathNextDescendantOrSelfElemParent:
|
| * @ctxt: the XPath Parser context
|
| @@ -7683,7 +7804,7 @@ xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
|
| #ifdef LIBXML_DOCB_ENABLED
|
| case XML_DOCB_DOCUMENT_NODE:
|
| #endif
|
| - case XML_HTML_DOCUMENT_NODE:
|
| + case XML_HTML_DOCUMENT_NODE:
|
| return(contextNode);
|
| default:
|
| return(NULL);
|
| @@ -7731,6 +7852,7 @@ next_sibling:
|
| }
|
| return(NULL);
|
| }
|
| +#endif
|
|
|
| /**
|
| * xmlXPathNextDescendant:
|
| @@ -7758,6 +7880,8 @@ xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
|
| return(ctxt->context->node->children);
|
| }
|
|
|
| + if (cur->type == XML_NAMESPACE_DECL)
|
| + return(NULL);
|
| if (cur->children != NULL) {
|
| /*
|
| * Do not descend on entities declarations
|
| @@ -8140,6 +8264,10 @@ xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
|
| static int
|
| xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
|
| if ((ancestor == NULL) || (node == NULL)) return(0);
|
| + if (node->type == XML_NAMESPACE_DECL)
|
| + return(0);
|
| + if (ancestor->type == XML_NAMESPACE_DECL)
|
| + return(0);
|
| /* nodes need to be in the same document */
|
| if (ancestor->doc != node->doc) return(0);
|
| /* avoid searching if ancestor or node is the root node */
|
| @@ -8177,7 +8305,7 @@ xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
|
| if (cur->type == XML_ATTRIBUTE_NODE)
|
| return(cur->parent);
|
| }
|
| - if (cur == NULL)
|
| + if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
|
| return (NULL);
|
| if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
|
| cur = cur->prev;
|
| @@ -8224,6 +8352,8 @@ xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
|
| return (NULL);
|
| ctxt->ancestor = cur->parent;
|
| }
|
| + if (cur->type == XML_NAMESPACE_DECL)
|
| + return(NULL);
|
| if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
|
| cur = cur->prev;
|
| while (cur->prev == NULL) {
|
| @@ -8431,7 +8561,7 @@ xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| int i = 0;
|
|
|
| tmp = cur->nodesetval->nodeTab[0];
|
| - if (tmp != NULL) {
|
| + if ((tmp != NULL) && (tmp->type != XML_NAMESPACE_DECL)) {
|
| tmp = tmp->children;
|
| while (tmp != NULL) {
|
| tmp = tmp->next;
|
| @@ -9101,7 +9231,7 @@ void
|
| xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| xmlXPathObjectPtr str;
|
| xmlXPathObjectPtr find;
|
| - xmlBufferPtr target;
|
| + xmlBufPtr target;
|
| const xmlChar *point;
|
| int offset;
|
|
|
| @@ -9111,16 +9241,16 @@ xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| CAST_TO_STRING;
|
| str = valuePop(ctxt);
|
|
|
| - target = xmlBufferCreate();
|
| + target = xmlBufCreate();
|
| if (target) {
|
| point = xmlStrstr(str->stringval, find->stringval);
|
| if (point) {
|
| offset = (int)(point - str->stringval);
|
| - xmlBufferAdd(target, str->stringval, offset);
|
| + xmlBufAdd(target, str->stringval, offset);
|
| }
|
| valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
|
| - xmlBufferContent(target)));
|
| - xmlBufferFree(target);
|
| + xmlBufContent(target)));
|
| + xmlBufFree(target);
|
| }
|
| xmlXPathReleaseObject(ctxt->context, str);
|
| xmlXPathReleaseObject(ctxt->context, find);
|
| @@ -9144,7 +9274,7 @@ void
|
| xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| xmlXPathObjectPtr str;
|
| xmlXPathObjectPtr find;
|
| - xmlBufferPtr target;
|
| + xmlBufPtr target;
|
| const xmlChar *point;
|
| int offset;
|
|
|
| @@ -9154,17 +9284,17 @@ xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| CAST_TO_STRING;
|
| str = valuePop(ctxt);
|
|
|
| - target = xmlBufferCreate();
|
| + target = xmlBufCreate();
|
| if (target) {
|
| point = xmlStrstr(str->stringval, find->stringval);
|
| if (point) {
|
| offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
|
| - xmlBufferAdd(target, &str->stringval[offset],
|
| + xmlBufAdd(target, &str->stringval[offset],
|
| xmlStrlen(str->stringval) - offset);
|
| }
|
| valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
|
| - xmlBufferContent(target)));
|
| - xmlBufferFree(target);
|
| + xmlBufContent(target)));
|
| + xmlBufFree(target);
|
| }
|
| xmlXPathReleaseObject(ctxt->context, str);
|
| xmlXPathReleaseObject(ctxt->context, find);
|
| @@ -9188,7 +9318,7 @@ void
|
| xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| xmlXPathObjectPtr obj = NULL;
|
| xmlChar *source = NULL;
|
| - xmlBufferPtr target;
|
| + xmlBufPtr target;
|
| xmlChar blank;
|
|
|
| if (ctxt == NULL) return;
|
| @@ -9206,7 +9336,7 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| obj = valuePop(ctxt);
|
| source = obj->stringval;
|
|
|
| - target = xmlBufferCreate();
|
| + target = xmlBufCreate();
|
| if (target && source) {
|
|
|
| /* Skip leading whitespaces */
|
| @@ -9220,16 +9350,16 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| blank = 0x20;
|
| } else {
|
| if (blank) {
|
| - xmlBufferAdd(target, &blank, 1);
|
| + xmlBufAdd(target, &blank, 1);
|
| blank = 0;
|
| }
|
| - xmlBufferAdd(target, source, 1);
|
| + xmlBufAdd(target, source, 1);
|
| }
|
| source++;
|
| }
|
| valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
|
| - xmlBufferContent(target)));
|
| - xmlBufferFree(target);
|
| + xmlBufContent(target)));
|
| + xmlBufFree(target);
|
| }
|
| xmlXPathReleaseObject(ctxt->context, obj);
|
| }
|
| @@ -9260,7 +9390,7 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| xmlXPathObjectPtr str;
|
| xmlXPathObjectPtr from;
|
| xmlXPathObjectPtr to;
|
| - xmlBufferPtr target;
|
| + xmlBufPtr target;
|
| int offset, max;
|
| xmlChar ch;
|
| const xmlChar *point;
|
| @@ -9275,7 +9405,7 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| CAST_TO_STRING;
|
| str = valuePop(ctxt);
|
|
|
| - target = xmlBufferCreate();
|
| + target = xmlBufCreate();
|
| if (target) {
|
| max = xmlUTF8Strlen(to->stringval);
|
| for (cptr = str->stringval; (ch=*cptr); ) {
|
| @@ -9284,10 +9414,10 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| if (offset < max) {
|
| point = xmlUTF8Strpos(to->stringval, offset);
|
| if (point)
|
| - xmlBufferAdd(target, point, xmlUTF8Strsize(point, 1));
|
| + xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
|
| }
|
| } else
|
| - xmlBufferAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
|
| + xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
|
|
|
| /* Step to next character in input */
|
| cptr++;
|
| @@ -9296,6 +9426,7 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| if ( (ch & 0xc0) != 0xc0 ) {
|
| xmlGenericError(xmlGenericErrorContext,
|
| "xmlXPathTranslateFunction: Invalid UTF8 string\n");
|
| + /* not asserting an XPath error is probably better */
|
| break;
|
| }
|
| /* then skip over remaining bytes for this char */
|
| @@ -9303,6 +9434,7 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| if ( (*cptr++ & 0xc0) != 0x80 ) {
|
| xmlGenericError(xmlGenericErrorContext,
|
| "xmlXPathTranslateFunction: Invalid UTF8 string\n");
|
| + /* not asserting an XPath error is probably better */
|
| break;
|
| }
|
| if (ch & 0x80) /* must have had error encountered */
|
| @@ -9311,8 +9443,8 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| }
|
| }
|
| valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
|
| - xmlBufferContent(target)));
|
| - xmlBufferFree(target);
|
| + xmlBufContent(target)));
|
| + xmlBufFree(target);
|
| xmlXPathReleaseObject(ctxt->context, str);
|
| xmlXPathReleaseObject(ctxt->context, from);
|
| xmlXPathReleaseObject(ctxt->context, to);
|
| @@ -9819,7 +9951,7 @@ xmlChar *
|
| xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
|
| const xmlChar *in;
|
| xmlChar *ret;
|
| - int count = 0;
|
| + size_t count = 0;
|
|
|
| if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
|
| /*
|
| @@ -9838,6 +9970,10 @@ xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
|
| in++;
|
| if ((*in > 0) && (*in < 0x80)) {
|
| count = in - ctxt->cur;
|
| + if (count > XML_MAX_NAME_LENGTH) {
|
| + ctxt->cur = in;
|
| + XP_ERRORNULL(XPATH_EXPR_ERROR);
|
| + }
|
| ret = xmlStrndup(ctxt->cur, count);
|
| ctxt->cur = in;
|
| return(ret);
|
| @@ -9881,6 +10017,9 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
|
| xmlChar *buffer;
|
| int max = len * 2;
|
|
|
| + if (len > XML_MAX_NAME_LENGTH) {
|
| + XP_ERRORNULL(XPATH_EXPR_ERROR);
|
| + }
|
| buffer = (xmlChar *) xmlMallocAtomic(max * sizeof(xmlChar));
|
| if (buffer == NULL) {
|
| XP_ERRORNULL(XPATH_MEMORY_ERROR);
|
| @@ -9892,6 +10031,9 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
|
| (IS_COMBINING(c)) ||
|
| (IS_EXTENDER(c))) {
|
| if (len + 10 > max) {
|
| + if (max > XML_MAX_NAME_LENGTH) {
|
| + XP_ERRORNULL(XPATH_EXPR_ERROR);
|
| + }
|
| max *= 2;
|
| buffer = (xmlChar *) xmlRealloc(buffer,
|
| max * sizeof(xmlChar));
|
| @@ -10044,7 +10186,6 @@ static void
|
| xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
|
| {
|
| double ret = 0.0;
|
| - double mult = 1;
|
| int ok = 0;
|
| int exponent = 0;
|
| int is_exponent_negative = 0;
|
| @@ -10080,15 +10221,23 @@ xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
|
| }
|
| #endif
|
| if (CUR == '.') {
|
| + int v, frac = 0;
|
| + double fraction = 0;
|
| +
|
| NEXT;
|
| if (((CUR < '0') || (CUR > '9')) && (!ok)) {
|
| XP_ERROR(XPATH_NUMBER_ERROR);
|
| }
|
| - while ((CUR >= '0') && (CUR <= '9')) {
|
| - mult /= 10;
|
| - ret = ret + (CUR - '0') * mult;
|
| + while ((CUR >= '0') && (CUR <= '9') && (frac < MAX_FRAC)) {
|
| + v = (CUR - '0');
|
| + fraction = fraction * 10 + v;
|
| + frac = frac + 1;
|
| NEXT;
|
| }
|
| + fraction /= my_pow10[frac];
|
| + ret = ret + fraction;
|
| + while ((CUR >= '0') && (CUR <= '9'))
|
| + NEXT;
|
| }
|
| if ((CUR == 'e') || (CUR == 'E')) {
|
| NEXT;
|
| @@ -10237,7 +10386,7 @@ xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
|
| name, prefix);
|
| SKIP_BLANKS;
|
| if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
|
| - XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
|
| + XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
|
| }
|
| }
|
|
|
| @@ -11262,7 +11411,10 @@ xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
|
| }
|
| }
|
|
|
| - CHECK_ERROR;
|
| + if (ctxt->error != XPATH_EXPRESSION_OK) {
|
| + xmlFree(name);
|
| + return;
|
| + }
|
|
|
| name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
|
| if (test == 0)
|
| @@ -11598,9 +11750,13 @@ xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
|
| */
|
| if (contextObj == NULL)
|
| contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
|
| - else
|
| - xmlXPathNodeSetAddUnique(contextObj->nodesetval,
|
| - contextNode);
|
| + else {
|
| + if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
|
| + contextNode) < 0) {
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| + goto evaluation_exit;
|
| + }
|
| + }
|
|
|
| valuePush(ctxt, contextObj);
|
|
|
| @@ -11701,6 +11857,7 @@ xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
|
| xmlXPathObjectPtr contextObj = NULL, exprRes = NULL;
|
| xmlNodePtr oldContextNode, contextNode = NULL;
|
| xmlXPathContextPtr xpctxt = ctxt->context;
|
| + int frame;
|
|
|
| #ifdef LIBXML_XPTR_ENABLED
|
| /*
|
| @@ -11720,6 +11877,8 @@ xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
|
| */
|
| exprOp = &ctxt->comp->steps[op->ch2];
|
| for (i = 0; i < set->nodeNr; i++) {
|
| + xmlXPathObjectPtr tmp;
|
| +
|
| if (set->nodeTab[i] == NULL)
|
| continue;
|
|
|
| @@ -11743,17 +11902,21 @@ xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
|
| */
|
| if (contextObj == NULL)
|
| contextObj = xmlXPathCacheNewNodeSet(xpctxt, contextNode);
|
| - else
|
| - xmlXPathNodeSetAddUnique(contextObj->nodesetval,
|
| - contextNode);
|
| + else {
|
| + if (xmlXPathNodeSetAddUnique(contextObj->nodesetval,
|
| + contextNode) < 0) {
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| + goto evaluation_exit;
|
| + }
|
| + }
|
|
|
| + frame = xmlXPathSetFrame(ctxt);
|
| valuePush(ctxt, contextObj);
|
| res = xmlXPathCompOpEvalToBoolean(ctxt, exprOp, 1);
|
| + tmp = valuePop(ctxt);
|
| + xmlXPathPopFrame(ctxt, frame);
|
|
|
| if ((ctxt->error != XPATH_EXPRESSION_OK) || (res == -1)) {
|
| - xmlXPathObjectPtr tmp;
|
| - /* pop the result if any */
|
| - tmp = valuePop(ctxt);
|
| while (tmp != contextObj) {
|
| /*
|
| * Free up the result
|
| @@ -11764,6 +11927,8 @@ xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserContextPtr ctxt,
|
| }
|
| goto evaluation_error;
|
| }
|
| + /* push the result back onto the stack */
|
| + valuePush(ctxt, tmp);
|
|
|
| if (res)
|
| pos++;
|
| @@ -11915,22 +12080,25 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
|
| #define XP_TEST_HIT \
|
| if (hasAxisRange != 0) { \
|
| if (++pos == maxPos) { \
|
| - addNode(seq, cur); \
|
| - goto axis_range_end; } \
|
| + if (addNode(seq, cur) < 0) \
|
| + ctxt->error = XPATH_MEMORY_ERROR; \
|
| + goto axis_range_end; } \
|
| } else { \
|
| - addNode(seq, cur); \
|
| + if (addNode(seq, cur) < 0) \
|
| + ctxt->error = XPATH_MEMORY_ERROR; \
|
| if (breakOnFirstHit) goto first_hit; }
|
|
|
| #define XP_TEST_HIT_NS \
|
| if (hasAxisRange != 0) { \
|
| if (++pos == maxPos) { \
|
| hasNsNodes = 1; \
|
| - xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur); \
|
| + if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
|
| + ctxt->error = XPATH_MEMORY_ERROR; \
|
| goto axis_range_end; } \
|
| } else { \
|
| hasNsNodes = 1; \
|
| - xmlXPathNodeSetAddNs(seq, \
|
| - xpctxt->node, (xmlNsPtr) cur); \
|
| + if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
|
| + ctxt->error = XPATH_MEMORY_ERROR; \
|
| if (breakOnFirstHit) goto first_hit; }
|
|
|
| xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
|
| @@ -11950,8 +12118,6 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
|
| xmlNodeSetPtr contextSeq;
|
| int contextIdx;
|
| xmlNodePtr contextNode;
|
| - /* The context node for a compound traversal */
|
| - xmlNodePtr outerContextNode;
|
| /* The final resulting node set wrt to all context nodes */
|
| xmlNodeSetPtr outSeq;
|
| /*
|
| @@ -11967,9 +12133,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
|
| int breakOnFirstHit;
|
|
|
| xmlXPathTraversalFunction next = NULL;
|
| - /* compound axis traversal */
|
| - xmlXPathTraversalFunctionExt outerNext = NULL;
|
| - void (*addNode) (xmlNodeSetPtr, xmlNodePtr);
|
| + int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
|
| xmlXPathNodeSetMergeFunction mergeAndClear;
|
| xmlNodePtr oldContextNode;
|
| xmlXPathContextPtr xpctxt = ctxt->context;
|
| @@ -12018,13 +12182,6 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
|
| break;
|
| case AXIS_CHILD:
|
| last = NULL;
|
| - if (op->rewriteType == XP_REWRITE_DOS_CHILD_ELEM) {
|
| - /*
|
| - * This iterator will give us only nodes which can
|
| - * hold element nodes.
|
| - */
|
| - outerNext = xmlXPathNextDescendantOrSelfElemParent;
|
| - }
|
| if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
|
| (type == NODE_TYPE_NODE))
|
| {
|
| @@ -12154,32 +12311,13 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
|
| addNode = xmlXPathNodeSetAddUnique;
|
| outSeq = NULL;
|
| seq = NULL;
|
| - outerContextNode = NULL;
|
| contextNode = NULL;
|
| contextIdx = 0;
|
|
|
|
|
| - while ((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) {
|
| - if (outerNext != NULL) {
|
| - /*
|
| - * This is a compound traversal.
|
| - */
|
| - if (contextNode == NULL) {
|
| - /*
|
| - * Set the context for the outer traversal.
|
| - */
|
| - outerContextNode = contextSeq->nodeTab[contextIdx++];
|
| - contextNode = outerNext(NULL, outerContextNode);
|
| - } else
|
| - contextNode = outerNext(contextNode, outerContextNode);
|
| - if (contextNode == NULL)
|
| - continue;
|
| - /*
|
| - * Set the context for the main traversal.
|
| - */
|
| - xpctxt->node = contextNode;
|
| - } else
|
| - xpctxt->node = contextSeq->nodeTab[contextIdx++];
|
| + while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
|
| + (ctxt->error == XPATH_EXPRESSION_OK)) {
|
| + xpctxt->node = contextSeq->nodeTab[contextIdx++];
|
|
|
| if (seq == NULL) {
|
| seq = xmlXPathNodeSetCreate(NULL);
|
| @@ -12287,7 +12425,14 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
|
| if (axis == AXIS_ATTRIBUTE) {
|
| if (cur->type == XML_ATTRIBUTE_NODE)
|
| {
|
| - XP_TEST_HIT
|
| + if (prefix == NULL)
|
| + {
|
| + XP_TEST_HIT
|
| + } else if ((cur->ns != NULL) &&
|
| + (xmlStrEqual(URI, cur->ns->href)))
|
| + {
|
| + XP_TEST_HIT
|
| + }
|
| }
|
| } else if (axis == AXIS_NAMESPACE) {
|
| if (cur->type == XML_NAMESPACE_DECL)
|
| @@ -12377,7 +12522,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
|
| }
|
| break;
|
| } /* switch(test) */
|
| - } while (cur != NULL);
|
| + } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
|
|
|
| goto apply_predicates;
|
|
|
| @@ -12418,13 +12563,16 @@ first_hit: /* ---------------------------------------------------------- */
|
| #endif
|
|
|
| apply_predicates: /* --------------------------------------------------- */
|
| + if (ctxt->error != XPATH_EXPRESSION_OK)
|
| + goto error;
|
| +
|
| /*
|
| * Apply predicates.
|
| */
|
| if ((predOp != NULL) && (seq->nodeNr > 0)) {
|
| /*
|
| * E.g. when we have a "/foo[some expression][n]".
|
| - */
|
| + */
|
| /*
|
| * QUESTION TODO: The old predicate evaluation took into
|
| * account location-sets.
|
| @@ -12433,7 +12581,7 @@ apply_predicates: /* --------------------------------------------------- */
|
| * All what I learned now from the evaluation semantics
|
| * does not indicate that a location-set will be processed
|
| * here, so this looks OK.
|
| - */
|
| + */
|
| /*
|
| * Iterate over all predicates, starting with the outermost
|
| * predicate.
|
| @@ -12926,8 +13074,10 @@ xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
|
| tmp = xmlXPathCacheNewNodeSet(ctxt->context,
|
| ctxt->context->node);
|
| } else {
|
| - xmlXPathNodeSetAddUnique(tmp->nodesetval,
|
| - ctxt->context->node);
|
| + if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
|
| + ctxt->context->node) < 0) {
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| + }
|
| }
|
| valuePush(ctxt, tmp);
|
| if (op->ch2 != -1)
|
| @@ -13040,8 +13190,10 @@ xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
|
| tmp = xmlXPathCacheNewNodeSet(ctxt->context,
|
| ctxt->context->node);
|
| } else {
|
| - xmlXPathNodeSetAddUnique(tmp->nodesetval,
|
| - ctxt->context->node);
|
| + if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
|
| + ctxt->context->node) < 0) {
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| + }
|
| }
|
| valuePush(ctxt, tmp);
|
| ctxt->context->contextSize = oldset->nodeNr;
|
| @@ -13059,7 +13211,8 @@ xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
|
| */
|
| res = valuePop(ctxt);
|
| if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
|
| - xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
|
| + if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) < 0)
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| }
|
| /*
|
| * Cleanup
|
| @@ -13368,23 +13521,33 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
| xmlXPathFunction func;
|
| const xmlChar *oldFunc, *oldFuncURI;
|
| int i;
|
| + int frame;
|
|
|
| - if (op->ch1 != -1)
|
| + frame = xmlXPathSetFrame(ctxt);
|
| + if (op->ch1 != -1) {
|
| total +=
|
| xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
|
| - if (ctxt->valueNr < op->value) {
|
| + if (ctxt->error != XPATH_EXPRESSION_OK) {
|
| + xmlXPathPopFrame(ctxt, frame);
|
| + return (total);
|
| + }
|
| + }
|
| + if (ctxt->valueNr < ctxt->valueFrame + op->value) {
|
| xmlGenericError(xmlGenericErrorContext,
|
| "xmlXPathCompOpEval: parameter error\n");
|
| ctxt->error = XPATH_INVALID_OPERAND;
|
| + xmlXPathPopFrame(ctxt, frame);
|
| return (total);
|
| }
|
| - for (i = 0; i < op->value; i++)
|
| + for (i = 0; i < op->value; i++) {
|
| if (ctxt->valueTab[(ctxt->valueNr - 1) - i] == NULL) {
|
| xmlGenericError(xmlGenericErrorContext,
|
| "xmlXPathCompOpEval: parameter error\n");
|
| ctxt->error = XPATH_INVALID_OPERAND;
|
| + xmlXPathPopFrame(ctxt, frame);
|
| return (total);
|
| }
|
| + }
|
| if (op->cache != NULL)
|
| XML_CAST_FPTR(func) = op->cache;
|
| else {
|
| @@ -13400,6 +13563,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
| xmlGenericError(xmlGenericErrorContext,
|
| "xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
|
| (char *)op->value4, (char *)op->value5);
|
| + xmlXPathPopFrame(ctxt, frame);
|
| ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
|
| return (total);
|
| }
|
| @@ -13422,6 +13586,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
| func(ctxt, op->value);
|
| ctxt->context->function = oldFunc;
|
| ctxt->context->functionURI = oldFuncURI;
|
| + xmlXPathPopFrame(ctxt, frame);
|
| return (total);
|
| }
|
| case XPATH_OP_ARG:
|
| @@ -13429,17 +13594,20 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
| bak = ctxt->context->node;
|
| pp = ctxt->context->proximityPosition;
|
| cs = ctxt->context->contextSize;
|
| - if (op->ch1 != -1)
|
| + if (op->ch1 != -1) {
|
| total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
|
| - ctxt->context->contextSize = cs;
|
| - ctxt->context->proximityPosition = pp;
|
| - ctxt->context->node = bak;
|
| - ctxt->context->doc = bakd;
|
| - CHECK_ERROR0;
|
| + ctxt->context->contextSize = cs;
|
| + ctxt->context->proximityPosition = pp;
|
| + ctxt->context->node = bak;
|
| + ctxt->context->doc = bakd;
|
| + CHECK_ERROR0;
|
| + }
|
| if (op->ch2 != -1) {
|
| total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
|
| - ctxt->context->doc = bakd;
|
| - ctxt->context->node = bak;
|
| + ctxt->context->contextSize = cs;
|
| + ctxt->context->proximityPosition = pp;
|
| + ctxt->context->node = bak;
|
| + ctxt->context->doc = bakd;
|
| CHECK_ERROR0;
|
| }
|
| return (total);
|
| @@ -13731,8 +13899,10 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
| tmp = xmlXPathCacheNewNodeSet(ctxt->context,
|
| ctxt->context->node);
|
| } else {
|
| - xmlXPathNodeSetAddUnique(tmp->nodesetval,
|
| - ctxt->context->node);
|
| + if (xmlXPathNodeSetAddUnique(tmp->nodesetval,
|
| + ctxt->context->node) < 0) {
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| + }
|
| }
|
| valuePush(ctxt, tmp);
|
| ctxt->context->contextSize = oldset->nodeNr;
|
| @@ -13762,7 +13932,9 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
| */
|
| res = valuePop(ctxt);
|
| if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
|
| - xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
|
| + if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i])
|
| + < 0)
|
| + ctxt->error = XPATH_MEMORY_ERROR;
|
| }
|
|
|
| /*
|
| @@ -13978,6 +14150,7 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
|
| }
|
| xmlGenericError(xmlGenericErrorContext,
|
| "XPath: unknown precompiled operation %d\n", op->op);
|
| + ctxt->error = XPATH_INVALID_OPERAND;
|
| return (total);
|
| }
|
|
|
| @@ -14124,7 +14297,7 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
|
| if (toBool)
|
| return(1);
|
| xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
|
| - (xmlNodePtr) ctxt->doc);
|
| + (xmlNodePtr) ctxt->doc);
|
| } else {
|
| /* Select "self::node()" */
|
| if (toBool)
|
| @@ -14217,7 +14390,11 @@ next_node:
|
| } else if (ret == 1) {
|
| if (toBool)
|
| goto return_1;
|
| - xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
|
| + if (xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur)
|
| + < 0) {
|
| + ctxt->lastError.domain = XML_FROM_XPATH;
|
| + ctxt->lastError.code = XML_ERR_NO_MEMORY;
|
| + }
|
| }
|
| if ((cur->children == NULL) || (depth >= max_depth)) {
|
| ret = xmlStreamPop(patstream);
|
| @@ -14233,6 +14410,7 @@ next_node:
|
| }
|
|
|
| scan_children:
|
| + if (cur->type == XML_NAMESPACE_DECL) break;
|
| if ((cur->children != NULL) && (depth < max_depth)) {
|
| /*
|
| * Do not descend on entities declarations
|
| @@ -14325,6 +14503,7 @@ xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
|
| ctxt->valueNr = 0;
|
| ctxt->valueMax = 10;
|
| ctxt->value = NULL;
|
| + ctxt->valueFrame = 0;
|
| }
|
| #ifdef XPATH_STREAMING
|
| if (ctxt->comp->stream) {
|
| @@ -14552,57 +14731,64 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
|
| }
|
| #endif /* XPATH_STREAMING */
|
|
|
| -static int
|
| -xmlXPathCanRewriteDosExpression(xmlChar *expr)
|
| -{
|
| - if (expr == NULL)
|
| - return(0);
|
| - do {
|
| - if ((*expr == '/') && (*(++expr) == '/'))
|
| - return(1);
|
| - } while (*expr++);
|
| - return(0);
|
| -}
|
| static void
|
| -xmlXPathRewriteDOSExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
|
| +xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op)
|
| {
|
| /*
|
| * Try to rewrite "descendant-or-self::node()/foo" to an optimized
|
| * internal representation.
|
| */
|
| - if (op->ch1 != -1) {
|
| - if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
|
| - ((xmlXPathAxisVal) op->value == AXIS_CHILD /* 4 */) &&
|
| - ((xmlXPathTestVal) op->value2 == NODE_TEST_NAME /* 5 */) &&
|
| - ((xmlXPathTypeVal) op->value3 == NODE_TYPE_NODE /* 0 */))
|
| - {
|
| - /*
|
| - * This is a "child::foo"
|
| - */
|
| - xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
|
| -
|
| - if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
|
| - (prevop->ch1 != -1) &&
|
| - ((xmlXPathAxisVal) prevop->value ==
|
| - AXIS_DESCENDANT_OR_SELF) &&
|
| - (prevop->ch2 == -1) &&
|
| - ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
|
| - ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE) &&
|
| - (comp->steps[prevop->ch1].op == XPATH_OP_ROOT))
|
| - {
|
| - /*
|
| - * This is a "/descendant-or-self::node()" without predicates.
|
| - * Eliminate it.
|
| - */
|
| - op->ch1 = prevop->ch1;
|
| - op->rewriteType = XP_REWRITE_DOS_CHILD_ELEM;
|
| - }
|
| +
|
| + if ((op->op == XPATH_OP_COLLECT /* 11 */) &&
|
| + (op->ch1 != -1) &&
|
| + (op->ch2 == -1 /* no predicate */))
|
| + {
|
| + xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
|
| +
|
| + if ((prevop->op == XPATH_OP_COLLECT /* 11 */) &&
|
| + ((xmlXPathAxisVal) prevop->value ==
|
| + AXIS_DESCENDANT_OR_SELF) &&
|
| + (prevop->ch2 == -1) &&
|
| + ((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
|
| + ((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
|
| + {
|
| + /*
|
| + * This is a "descendant-or-self::node()" without predicates.
|
| + * Try to eliminate it.
|
| + */
|
| +
|
| + switch ((xmlXPathAxisVal) op->value) {
|
| + case AXIS_CHILD:
|
| + case AXIS_DESCENDANT:
|
| + /*
|
| + * Convert "descendant-or-self::node()/child::" or
|
| + * "descendant-or-self::node()/descendant::" to
|
| + * "descendant::"
|
| + */
|
| + op->ch1 = prevop->ch1;
|
| + op->value = AXIS_DESCENDANT;
|
| + break;
|
| + case AXIS_SELF:
|
| + case AXIS_DESCENDANT_OR_SELF:
|
| + /*
|
| + * Convert "descendant-or-self::node()/self::" or
|
| + * "descendant-or-self::node()/descendant-or-self::" to
|
| + * to "descendant-or-self::"
|
| + */
|
| + op->ch1 = prevop->ch1;
|
| + op->value = AXIS_DESCENDANT_OR_SELF;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| }
|
| - if (op->ch1 != -1)
|
| - xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch1]);
|
| }
|
| +
|
| + /* Recurse */
|
| + if (op->ch1 != -1)
|
| + xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]);
|
| if (op->ch2 != -1)
|
| - xmlXPathRewriteDOSExpression(comp, &comp->steps[op->ch2]);
|
| + xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]);
|
| }
|
|
|
| /**
|
| @@ -14660,12 +14846,8 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
|
| comp->string = xmlStrdup(str);
|
| comp->nb = 0;
|
| #endif
|
| - if ((comp->expr != NULL) &&
|
| - (comp->nbStep > 2) &&
|
| - (comp->last >= 0) &&
|
| - (xmlXPathCanRewriteDosExpression(comp->expr) == 1))
|
| - {
|
| - xmlXPathRewriteDOSExpression(comp, &comp->steps[comp->last]);
|
| + if ((comp->nbStep > 1) && (comp->last >= 0)) {
|
| + xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]);
|
| }
|
| }
|
| return(comp);
|
| @@ -14842,17 +15024,12 @@ xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
|
| #endif
|
| {
|
| xmlXPathCompileExpr(ctxt, 1);
|
| - /*
|
| - * In this scenario the expression string will sit in ctxt->base.
|
| - */
|
| if ((ctxt->error == XPATH_EXPRESSION_OK) &&
|
| (ctxt->comp != NULL) &&
|
| - (ctxt->base != NULL) &&
|
| - (ctxt->comp->nbStep > 2) &&
|
| - (ctxt->comp->last >= 0) &&
|
| - (xmlXPathCanRewriteDosExpression((xmlChar *) ctxt->base) == 1))
|
| + (ctxt->comp->nbStep > 1) &&
|
| + (ctxt->comp->last >= 0))
|
| {
|
| - xmlXPathRewriteDOSExpression(ctxt->comp,
|
| + xmlXPathOptimizeExpression(ctxt->comp,
|
| &ctxt->comp->steps[ctxt->comp->last]);
|
| }
|
| }
|
| @@ -14923,6 +15100,49 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
|
| }
|
|
|
| /**
|
| + * xmlXPathSetContextNode:
|
| + * @node: the node to to use as the context node
|
| + * @ctx: the XPath context
|
| + *
|
| + * Sets 'node' as the context node. The node must be in the same
|
| + * document as that associated with the context.
|
| + *
|
| + * Returns -1 in case of error or 0 if successful
|
| + */
|
| +int
|
| +xmlXPathSetContextNode(xmlNodePtr node, xmlXPathContextPtr ctx) {
|
| + if ((node == NULL) || (ctx == NULL))
|
| + return(-1);
|
| +
|
| + if (node->doc == ctx->doc) {
|
| + ctx->node = node;
|
| + return(0);
|
| + }
|
| + return(-1);
|
| +}
|
| +
|
| +/**
|
| + * xmlXPathNodeEval:
|
| + * @node: the node to to use as the context node
|
| + * @str: the XPath expression
|
| + * @ctx: the XPath context
|
| + *
|
| + * Evaluate the XPath Location Path in the given context. The node 'node'
|
| + * is set as the context node. The context node is not restored.
|
| + *
|
| + * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
|
| + * the caller has to free the object.
|
| + */
|
| +xmlXPathObjectPtr
|
| +xmlXPathNodeEval(xmlNodePtr node, const xmlChar *str, xmlXPathContextPtr ctx) {
|
| + if (str == NULL)
|
| + return(NULL);
|
| + if (xmlXPathSetContextNode(node, ctx) < 0)
|
| + return(NULL);
|
| + return(xmlXPathEval(str, ctx));
|
| +}
|
| +
|
| +/**
|
| * xmlXPathEvalExpression:
|
| * @str: the XPath expression
|
| * @ctxt: the XPath context
|
| @@ -15026,7 +15246,7 @@ static void
|
| xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| xmlXPathObjectPtr str;
|
| int escape_reserved;
|
| - xmlBufferPtr target;
|
| + xmlBufPtr target;
|
| xmlChar *cptr;
|
| xmlChar escape[4];
|
|
|
| @@ -15037,7 +15257,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| CAST_TO_STRING;
|
| str = valuePop(ctxt);
|
|
|
| - target = xmlBufferCreate();
|
| + target = xmlBufCreate();
|
|
|
| escape[0] = '%';
|
| escape[3] = 0;
|
| @@ -15062,7 +15282,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| *cptr == ':' || *cptr == '@' || *cptr == '&' ||
|
| *cptr == '=' || *cptr == '+' || *cptr == '$' ||
|
| *cptr == ','))) {
|
| - xmlBufferAdd(target, cptr, 1);
|
| + xmlBufAdd(target, cptr, 1);
|
| } else {
|
| if ((*cptr >> 4) < 10)
|
| escape[1] = '0' + (*cptr >> 4);
|
| @@ -15073,13 +15293,13 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
| else
|
| escape[2] = 'A' - 10 + (*cptr & 0xF);
|
|
|
| - xmlBufferAdd(target, &escape[0], 3);
|
| + xmlBufAdd(target, &escape[0], 3);
|
| }
|
| }
|
| }
|
| valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
|
| - xmlBufferContent(target)));
|
| - xmlBufferFree(target);
|
| + xmlBufContent(target)));
|
| + xmlBufFree(target);
|
| xmlXPathReleaseObject(ctxt->context, str);
|
| }
|
|
|
|
|