xpath.c fix bug 85256
diff --git a/xpath.c b/xpath.c
index f824989..dab0545 100644
--- a/xpath.c
+++ b/xpath.c
@@ -3261,8 +3261,8 @@
#endif
ret = xmlStrdup((const xmlChar *) "");
break;
- case XPATH_XSLT_TREE:
case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
ret = xmlXPathCastNodeSetToString(val->nodesetval);
break;
case XPATH_STRING:
@@ -3307,8 +3307,8 @@
xmlGenericError(xmlGenericErrorContext, "STRING: undefined\n");
#endif
break;
- case XPATH_XSLT_TREE:
case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
res = xmlXPathCastNodeSetToString(val->nodesetval);
break;
case XPATH_STRING:
@@ -3426,8 +3426,8 @@
#endif
ret = xmlXPathNAN;
break;
- case XPATH_XSLT_TREE:
case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
break;
case XPATH_STRING:
@@ -3538,8 +3538,8 @@
#endif
ret = 0;
break;
- case XPATH_XSLT_TREE:
case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
break;
case XPATH_STRING:
@@ -4169,6 +4169,7 @@
* xmlXPathEqualNodeSetString
* @arg: the nodeset object argument
* @str: the string to compare to.
+ * @neq: flag to show whether for '=' (0) or '!=' (1)
*
* Implement the equal operation on XPath objects content: @arg1 == @arg2
* If one object to be compared is a node-set and the other is a string,
@@ -4179,7 +4180,7 @@
* Returns 0 or 1 depending on the results of the test.
*/
static int
-xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str)
+xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
{
int i;
xmlNodeSetPtr ns;
@@ -4195,19 +4196,26 @@
return (0);
if (ns->nodeNr <= 0) {
if (hash == 0)
- return(1);
- return(0);
+ return(neq ^ 1);
+ return(neq);
}
for (i = 0; i < ns->nodeNr; i++) {
if (xmlXPathNodeValHash(ns->nodeTab[i]) == hash) {
str2 = xmlNodeGetContent(ns->nodeTab[i]);
if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
xmlFree(str2);
+ if (neq)
+ continue;
return (1);
- }
+ } else if (neq) {
+ if (str2 != NULL)
+ xmlFree(str2);
+ return (1);
+ }
if (str2 != NULL)
xmlFree(str2);
- }
+ } else if (neq)
+ return (1);
}
return (0);
}
@@ -4216,6 +4224,7 @@
* xmlXPathEqualNodeSetFloat
* @arg: the nodeset object argument
* @f: the float to compare to
+ * @neq: flag to show whether to compare '=' (0) or '!=' (1)
*
* Implement the equal operation on XPath objects content: @arg1 == @arg2
* If one object to be compared is a node-set and the other is a number,
@@ -4227,15 +4236,43 @@
* Returns 0 or 1 depending on the results of the test.
*/
static int
-xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
- char buf[100] = "";
+xmlXPathEqualNodeSetFloat(xmlXPathParserContextPtr ctxt,
+ xmlXPathObjectPtr arg, double f, int neq) {
+ int i, ret=0;
+ xmlNodeSetPtr ns;
+ xmlChar *str2;
+ xmlXPathObjectPtr val;
+ double v;
if ((arg == NULL) ||
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
return(0);
- xmlXPathFormatNumber(f, buf, sizeof(buf));
- return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
+ ns = arg->nodesetval;
+ if (ns != NULL) {
+ for (i=0;i<ns->nodeNr;i++) {
+ str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
+ if (str2 != NULL) {
+ valuePush(ctxt, xmlXPathNewString(str2));
+ xmlFree(str2);
+ xmlXPathNumberFunction(ctxt, 1);
+ val = valuePop(ctxt);
+ v = val->floatval;
+ xmlXPathFreeObject(val);
+ if (!xmlXPathIsNaN(v)) {
+ if ((!neq) && (v==f)) {
+ ret = 1;
+ break;
+ } else if ((neq) && (v!=f)) {
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return(ret);
}
@@ -4243,8 +4280,10 @@
* xmlXPathEqualNodeSets
* @arg1: first nodeset object argument
* @arg2: second nodeset object argument
+ * @neq: flag to show whether to test '=' (0) or '!=' (1)
*
- * Implement the equal operation on XPath nodesets: @arg1 == @arg2
+ * Implement the equal / not equal operation on XPath nodesets:
+ * @arg1 == @arg2 or @arg1 != @arg2
* If both objects to be compared are node-sets, then the comparison
* will be true if and only if there is a node in the first node-set and
* a node in the second node-set such that the result of performing the
@@ -4255,7 +4294,7 @@
* Returns 0 or 1 depending on the results of the test.
*/
static int
-xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
+xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
int i, j;
unsigned int *hashs1;
unsigned int *hashs2;
@@ -4281,12 +4320,13 @@
return(0);
/*
- * check if there is a node pertaining to both sets
+ * for equal, check if there is a node pertaining to both sets
*/
- for (i = 0;i < ns1->nodeNr;i++)
- for (j = 0;j < ns2->nodeNr;j++)
- if (ns1->nodeTab[i] == ns2->nodeTab[j])
- return(1);
+ if (neq == 0)
+ for (i = 0;i < ns1->nodeNr;i++)
+ for (j = 0;j < ns2->nodeNr;j++)
+ if (ns1->nodeTab[i] == ns2->nodeTab[j])
+ return(1);
values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
if (values1 == NULL)
@@ -4316,12 +4356,18 @@
for (j = 0;j < ns2->nodeNr;j++) {
if (i == 0)
hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[j]);
- if (hashs1[i] == hashs2[j]) {
+ if (hashs1[i] != hashs2[j]) {
+ if (neq) {
+ ret = 1;
+ break;
+ }
+ }
+ else {
if (values1[i] == NULL)
values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
if (values2[j] == NULL)
values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
- ret = xmlStrEqual(values1[i], values2[j]);
+ ret = xmlStrEqual(values1[i], values2[j]) ^ neq;
if (ret)
break;
}
@@ -4342,37 +4388,14 @@
return(ret);
}
-/**
- * xmlXPathEqualValues:
- * @ctxt: the XPath Parser context
- *
- * Implement the equal operation on XPath objects content: @arg1 == @arg2
- *
- * Returns 0 or 1 depending on the results of the test.
- */
-int
-xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
- xmlXPathObjectPtr arg1, arg2;
+static int
+xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
+ xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
int ret = 0;
-
- arg1 = valuePop(ctxt);
- if (arg1 == NULL)
- XP_ERROR0(XPATH_INVALID_OPERAND);
-
- arg2 = valuePop(ctxt);
- if (arg2 == NULL) {
- xmlXPathFreeObject(arg1);
- XP_ERROR0(XPATH_INVALID_OPERAND);
- }
-
- if (arg1 == arg2) {
-#ifdef DEBUG_EXPR
- xmlGenericError(xmlGenericErrorContext,
- "Equal: by pointer\n");
-#endif
- return(1);
- }
-
+ /*
+ *At this point we are assured neither arg1 nor arg2
+ *is a nodeset, so we can just pick the appropriate routine.
+ */
switch (arg1->type) {
case XPATH_UNDEFINED:
#ifdef DEBUG_EXPR
@@ -4380,40 +4403,6 @@
"Equal: undefined\n");
#endif
break;
- case XPATH_XSLT_TREE:
- case XPATH_NODESET:
- switch (arg2->type) {
- case XPATH_UNDEFINED:
-#ifdef DEBUG_EXPR
- xmlGenericError(xmlGenericErrorContext,
- "Equal: undefined\n");
-#endif
- break;
- case XPATH_XSLT_TREE:
- case XPATH_NODESET:
- ret = xmlXPathEqualNodeSets(arg1, arg2);
- break;
- case XPATH_BOOLEAN:
- if ((arg1->nodesetval == NULL) ||
- (arg1->nodesetval->nodeNr == 0)) ret = 0;
- else
- ret = 1;
- ret = (ret == arg2->boolval);
- break;
- case XPATH_NUMBER:
- ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
- break;
- case XPATH_STRING:
- ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
- break;
- case XPATH_USERS:
- case XPATH_POINT:
- case XPATH_RANGE:
- case XPATH_LOCATIONSET:
- TODO
- break;
- }
- break;
case XPATH_BOOLEAN:
switch (arg2->type) {
case XPATH_UNDEFINED:
@@ -4422,15 +4411,6 @@
"Equal: undefined\n");
#endif
break;
- case XPATH_NODESET:
- case XPATH_XSLT_TREE:
- if ((arg2->nodesetval == NULL) ||
- (arg2->nodesetval->nodeNr == 0))
- ret = 0;
- else
- ret = 1;
- ret = (ret == arg1->boolval);
- break;
case XPATH_BOOLEAN:
#ifdef DEBUG_EXPR
xmlGenericError(xmlGenericErrorContext,
@@ -4457,6 +4437,9 @@
case XPATH_LOCATIONSET:
TODO
break;
+ case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
+ break;
}
break;
case XPATH_NUMBER:
@@ -4467,10 +4450,6 @@
"Equal: undefined\n");
#endif
break;
- case XPATH_NODESET:
- case XPATH_XSLT_TREE:
- ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
- break;
case XPATH_BOOLEAN:
if (arg1->floatval) ret = 1;
else ret = 0;
@@ -4515,6 +4494,9 @@
case XPATH_LOCATIONSET:
TODO
break;
+ case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
+ break;
}
break;
case XPATH_STRING:
@@ -4525,10 +4507,6 @@
"Equal: undefined\n");
#endif
break;
- case XPATH_NODESET:
- case XPATH_XSLT_TREE:
- ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
- break;
case XPATH_BOOLEAN:
if ((arg1->stringval == NULL) ||
(arg1->stringval[0] == 0)) ret = 0;
@@ -4576,6 +4554,9 @@
case XPATH_LOCATIONSET:
TODO
break;
+ case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
+ break;
}
break;
case XPATH_USERS:
@@ -4584,12 +4565,180 @@
case XPATH_LOCATIONSET:
TODO
break;
+ case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
+ break;
}
xmlXPathFreeObject(arg1);
xmlXPathFreeObject(arg2);
return(ret);
}
+/**
+ * xmlXPathEqualValues:
+ * @ctxt: the XPath Parser context
+ *
+ * Implement the equal operation on XPath objects content: @arg1 == @arg2
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
+ xmlXPathObjectPtr arg1, arg2, argtmp;
+ int ret = 0;
+
+ arg2 = valuePop(ctxt);
+ arg1 = valuePop(ctxt);
+ if ((arg1 == NULL) || (arg2 == NULL)) {
+ if (arg1 != NULL)
+ xmlXPathFreeObject(arg1);
+ else
+ xmlXPathFreeObject(arg2);
+ XP_ERROR0(XPATH_INVALID_OPERAND);
+ }
+
+ if (arg1 == arg2) {
+#ifdef DEBUG_EXPR
+ xmlGenericError(xmlGenericErrorContext,
+ "Equal: by pointer\n");
+#endif
+ return(1);
+ }
+
+ /*
+ *If either argument is a nodeset, it's a 'special case'
+ */
+ if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
+ (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
+ /*
+ *Hack it to assure arg1 is the nodeset
+ */
+ if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
+ argtmp = arg2;
+ arg2 = arg1;
+ arg1 = argtmp;
+ }
+ switch (arg2->type) {
+ case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+ xmlGenericError(xmlGenericErrorContext,
+ "Equal: undefined\n");
+#endif
+ break;
+ case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
+ ret = xmlXPathEqualNodeSets(arg1, arg2, 0);
+ break;
+ case XPATH_BOOLEAN:
+ if ((arg1->nodesetval == NULL) ||
+ (arg1->nodesetval->nodeNr == 0)) ret = 0;
+ else
+ ret = 1;
+ ret = (ret == arg2->boolval);
+ break;
+ case XPATH_NUMBER:
+ ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 0);
+ break;
+ case XPATH_STRING:
+ ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval, 0);
+ break;
+ case XPATH_USERS:
+ case XPATH_POINT:
+ case XPATH_RANGE:
+ case XPATH_LOCATIONSET:
+ TODO
+ break;
+ }
+ xmlXPathFreeObject(arg1);
+ xmlXPathFreeObject(arg2);
+ return(ret);
+ }
+
+ return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
+}
+
+/**
+ * xmlXPathNotEqualValues:
+ * @ctxt: the XPath Parser context
+ *
+ * Implement the equal operation on XPath objects content: @arg1 == @arg2
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
+ xmlXPathObjectPtr arg1, arg2, argtmp;
+ int ret = 0;
+
+ arg2 = valuePop(ctxt);
+ arg1 = valuePop(ctxt);
+ if ((arg1 == NULL) || (arg2 == NULL)) {
+ if (arg1 != NULL)
+ xmlXPathFreeObject(arg1);
+ else
+ xmlXPathFreeObject(arg2);
+ XP_ERROR0(XPATH_INVALID_OPERAND);
+ }
+
+ if (arg1 == arg2) {
+#ifdef DEBUG_EXPR
+ xmlGenericError(xmlGenericErrorContext,
+ "NotEqual: by pointer\n");
+#endif
+ return(0);
+ }
+
+ /*
+ *If either argument is a nodeset, it's a 'special case'
+ */
+ if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
+ (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
+ /*
+ *Hack it to assure arg1 is the nodeset
+ */
+ if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
+ argtmp = arg2;
+ arg2 = arg1;
+ arg1 = argtmp;
+ }
+ switch (arg2->type) {
+ case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+ xmlGenericError(xmlGenericErrorContext,
+ "NotEqual: undefined\n");
+#endif
+ break;
+ case XPATH_NODESET:
+ case XPATH_XSLT_TREE:
+ ret = xmlXPathEqualNodeSets(arg1, arg2, 1);
+ break;
+ case XPATH_BOOLEAN:
+ if ((arg1->nodesetval == NULL) ||
+ (arg1->nodesetval->nodeNr == 0)) ret = 0;
+ else
+ ret = 1;
+ ret = (ret == arg2->boolval);
+ break;
+ case XPATH_NUMBER:
+ ret = xmlXPathEqualNodeSetFloat(ctxt, arg1, arg2->floatval, 1);
+ break;
+ case XPATH_STRING:
+ ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval,1);
+ break;
+ case XPATH_USERS:
+ case XPATH_POINT:
+ case XPATH_RANGE:
+ case XPATH_LOCATIONSET:
+ TODO
+ break;
+ }
+ xmlXPathFreeObject(arg1);
+ xmlXPathFreeObject(arg2);
+ return(ret);
+ }
+
+ return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
+}
/**
* xmlXPathCompareValues:
@@ -4620,22 +4769,23 @@
int ret = 0, arg1i = 0, arg2i = 0;
xmlXPathObjectPtr arg1, arg2;
- arg2 = valuePop(ctxt);
- if (arg2 == NULL) {
- XP_ERROR0(XPATH_INVALID_OPERAND);
- }
-
+ arg2 = valuePop(ctxt);
arg1 = valuePop(ctxt);
- if (arg1 == NULL) {
- xmlXPathFreeObject(arg2);
+ if ((arg1 == NULL) || (arg2 == NULL)) {
+ if (arg1 != NULL)
+ xmlXPathFreeObject(arg1);
+ else
+ xmlXPathFreeObject(arg2);
XP_ERROR0(XPATH_INVALID_OPERAND);
}
- if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
- if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
+ if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
+ (arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
+ if (((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE)) &&
+ ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE))){
ret = xmlXPathCompareNodeSets(inf, strict, arg1, arg2);
} else {
- if (arg1->type == XPATH_NODESET) {
+ if ((arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
arg1, arg2);
} else {
@@ -5595,7 +5745,7 @@
if ((cur == NULL) || (cur->nodesetval == NULL))
valuePush(ctxt, xmlXPathNewFloat((double) 0));
- else if (cur->type == XPATH_NODESET) {
+ else if ((cur->type == XPATH_NODESET) || (cur->type == XPATH_XSLT_TREE)) {
valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
} else {
if ((cur->nodesetval->nodeNr != 1) ||
@@ -5691,7 +5841,7 @@
CHECK_ARITY(1);
obj = valuePop(ctxt);
if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
- if (obj->type == XPATH_NODESET) {
+ if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
xmlNodeSetPtr ns;
int i;
@@ -9664,11 +9814,11 @@
ctxt->context->contextSize = cs;
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
- equal = xmlXPathEqualValues(ctxt);
- if (op->value)
- valuePush(ctxt, xmlXPathNewBoolean(equal));
- else
- valuePush(ctxt, xmlXPathNewBoolean(!equal));
+ if (op->value)
+ equal = xmlXPathEqualValues(ctxt);
+ else
+ equal = xmlXPathNotEqualValues(ctxt);
+ valuePush(ctxt, xmlXPathNewBoolean(equal));
return (total);
case XPATH_OP_CMP:
bakd = ctxt->context->doc;