Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(531)

Unified Diff: third_party/libxml/src/xpath.c

Issue 1193533007: Upgrade to libxml 2.9.2 and libxslt 1.1.28 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: no iconv Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/libxml/src/xmlwriter.c ('k') | third_party/libxml/src/xpointer.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
}
« no previous file with comments | « third_party/libxml/src/xmlwriter.c ('k') | third_party/libxml/src/xpointer.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698