--- embedaddon/libxml2/xpath.c 2013/07/22 01:22:22 1.1.1.2 +++ embedaddon/libxml2/xpath.c 2014/06/15 19:53:29 1.1.1.3 @@ -55,6 +55,8 @@ #include #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,12 +101,76 @@ /* #define XP_DEBUG_OBJ_USAGE */ /* + * 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 + */ +#define XPATH_MAX_STEPS 1000000 + +/* + * 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 + */ +#define XPATH_MAX_STACK_DEPTH 1000000 + +/* + * 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. + */ +#define XPATH_MAX_NODESET_LENGTH 10000000 + +/* * 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) */ +/* + * 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 xmlXPathCmpNodesExt(xmlNodePtr, xmlNodePtr); + 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) /************************************************************************ @@ -253,6 +328,7 @@ static const char *xmlXPathErrorMessages[] = { "Char out of XML range\n", "Invalid or incomplete context\n", "Stack usage errror\n", + "Forbidden variable\n", "?? Unknown error ??\n" /* Must be last in the list! */ }; #define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \ @@ -420,8 +496,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"); @@ -430,12 +505,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); } @@ -553,8 +633,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 { @@ -568,7 +646,6 @@ struct _xmlXPathStepOp { void *value5; void *cache; void *cacheURI; - int rewriteType; }; struct _xmlXPathCompExpr { @@ -723,6 +800,10 @@ xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, 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)); @@ -734,7 +815,6 @@ xmlXPathCompExprAdd(xmlXPathCompExprPtr comp, int ch1, 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; @@ -2052,6 +2132,11 @@ xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNo 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 @@ -2480,11 +2565,16 @@ valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjec 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); } @@ -3320,13 +3410,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++) { @@ -3349,6 +3445,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 @@ -3527,8 +3626,10 @@ xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr * @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; @@ -3536,7 +3637,7 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr nod 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 @@ */ /* @@ -3547,7 +3648,7 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr nod (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); } /* @@ -3558,7 +3659,7 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr nod 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)); @@ -3566,16 +3667,21 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr nod } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp; + 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); } /** @@ -3584,24 +3690,21 @@ xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr nod * @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 ((cur == NULL) || (val == NULL)) return(-1); -#if 0 - if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) - return; /* an XSLT fake node */ -#endif - /* @@ 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 @@ -3611,7 +3714,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)); @@ -3619,11 +3722,15 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp; + 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; @@ -3635,6 +3742,7 @@ xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); } else cur->nodeTab[cur->nodeNr++] = val; + return(0); } /** @@ -3644,16 +3752,13 @@ 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 ((cur == NULL) || (val == NULL)) return(-1); -#if 0 - if ((val->type == XML_ELEMENT_NODE) && (val->name[0] == ' ')) - return; /* an XSLT fake node */ -#endif - /* @@ with_ns to check whether namespace nodes should be looked at @@ */ /* * grow the nodeTab if needed @@ -3663,7 +3768,7 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr 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)); @@ -3671,11 +3776,15 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr } else if (cur->nodeNr == cur->nodeMax) { xmlNodePtr *temp; + 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; @@ -3687,6 +3796,7 @@ xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns); } else cur->nodeTab[cur->nodeNr++] = val; + return(0); } /** @@ -3782,6 +3892,10 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr } else if (val1->nodeNr == val1->nodeMax) { xmlNodePtr *temp; + 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) { @@ -3803,69 +3917,7 @@ xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr 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: * @set1: the first NodeSet or NULL @@ -3951,6 +4003,10 @@ xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNo } else if (set1->nodeNr >= set1->nodeMax) { xmlNodePtr *temp; + if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { + xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); + return(NULL); + } temp = (xmlNodePtr *) xmlRealloc( set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); if (temp == NULL) { @@ -4035,6 +4091,10 @@ xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1 } else if (set1->nodeNr >= set1->nodeMax) { xmlNodePtr *temp; + if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) { + xmlXPathErrMemory(NULL, "merging nodeset hit limit\n"); + return(NULL); + } temp = (xmlNodePtr *) xmlRealloc( set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr)); if (temp == NULL) { @@ -4333,9 +4393,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); @@ -4411,8 +4474,10 @@ xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPt 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); } @@ -4445,8 +4510,10 @@ xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSet 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); } @@ -4482,7 +4549,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); } @@ -4574,7 +4642,8 @@ xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNod cur = xmlXPathNodeSetItem(nodes, i); if (cur == node) break; - xmlXPathNodeSetAddUnique(ret, cur); + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) + break; } return(ret); } @@ -4678,7 +4747,8 @@ xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNo cur = xmlXPathNodeSetItem(nodes, i); if (cur == node) break; - xmlXPathNodeSetAddUnique(ret, cur); + if (xmlXPathNodeSetAddUnique(ret, cur) < 0) + break; } xmlXPathNodeSetSort(ret); /* bug 413451 */ return(ret); @@ -7701,6 +7771,7 @@ xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt return(NULL); } +#if 0 /** * xmlXPathNextDescendantOrSelfElemParent: * @ctxt: the XPath Parser context @@ -7728,7 +7799,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); @@ -7776,6 +7847,7 @@ next_sibling: } return(NULL); } +#endif /** * xmlXPathNextDescendant: @@ -7803,6 +7875,8 @@ xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, return(ctxt->context->node->children); } + if (cur->type == XML_NAMESPACE_DECL) + return(NULL); if (cur->children != NULL) { /* * Do not descend on entities declarations @@ -8185,6 +8259,10 @@ xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, x 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 */ @@ -8222,7 +8300,7 @@ xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, x 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; @@ -8269,6 +8347,8 @@ xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr 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) { @@ -8476,7 +8556,7 @@ xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, i 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; @@ -9146,7 +9226,7 @@ void xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr str; xmlXPathObjectPtr find; - xmlBufferPtr target; + xmlBufPtr target; const xmlChar *point; int offset; @@ -9156,16 +9236,16 @@ xmlXPathSubstringBeforeFunction(xmlXPathParserContextP 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); @@ -9189,7 +9269,7 @@ void xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr str; xmlXPathObjectPtr find; - xmlBufferPtr target; + xmlBufPtr target; const xmlChar *point; int offset; @@ -9199,17 +9279,17 @@ xmlXPathSubstringAfterFunction(xmlXPathParserContextPt 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); @@ -9233,7 +9313,7 @@ void xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr obj = NULL; xmlChar *source = NULL; - xmlBufferPtr target; + xmlBufPtr target; xmlChar blank; if (ctxt == NULL) return; @@ -9251,7 +9331,7 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctx obj = valuePop(ctxt); source = obj->stringval; - target = xmlBufferCreate(); + target = xmlBufCreate(); if (target && source) { /* Skip leading whitespaces */ @@ -9265,16 +9345,16 @@ xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctx 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); } @@ -9305,7 +9385,7 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctx xmlXPathObjectPtr str; xmlXPathObjectPtr from; xmlXPathObjectPtr to; - xmlBufferPtr target; + xmlBufPtr target; int offset, max; xmlChar ch; const xmlChar *point; @@ -9320,7 +9400,7 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctx CAST_TO_STRING; str = valuePop(ctxt); - target = xmlBufferCreate(); + target = xmlBufCreate(); if (target) { max = xmlUTF8Strlen(to->stringval); for (cptr = str->stringval; (ch=*cptr); ) { @@ -9329,10 +9409,10 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctx 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++; @@ -9358,8 +9438,8 @@ xmlXPathTranslateFunction(xmlXPathParserContextPtr ctx } } 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); @@ -9866,7 +9946,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); /* @@ -9885,6 +9965,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); @@ -9928,6 +10012,9 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt 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); @@ -9939,6 +10026,9 @@ xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt (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)); @@ -10291,7 +10381,7 @@ xmlXPathCompVariableReference(xmlXPathParserContextPtr 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); } } @@ -11655,9 +11745,13 @@ xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr c */ 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); @@ -11803,9 +11897,13 @@ xmlXPathCompOpEvalPositionalPredicate(xmlXPathParserCo */ 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); @@ -11977,22 +12075,25 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ct #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; @@ -12012,8 +12113,6 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ct 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; /* @@ -12029,9 +12128,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ct 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; @@ -12080,13 +12177,6 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ct 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)) { @@ -12216,32 +12306,13 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ct 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); @@ -12328,7 +12399,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ct break; } } else if (cur->type == type) { - if (type == XML_NAMESPACE_DECL) + if (cur->type == XML_NAMESPACE_DECL) XP_TEST_HIT_NS else XP_TEST_HIT @@ -12439,7 +12510,7 @@ xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ct } break; } /* switch(test) */ - } while (cur != NULL); + } while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK)); goto apply_predicates; @@ -12480,13 +12551,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. @@ -12495,7 +12569,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. @@ -12988,8 +13062,10 @@ xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr 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) @@ -13102,8 +13178,10 @@ xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr 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; @@ -13121,7 +13199,8 @@ xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr */ 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 @@ -13800,8 +13879,10 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlX 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; @@ -13831,7 +13912,9 @@ xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlX */ res = valuePop(ctxt); if (xmlXPathEvaluatePredicateResult(ctxt, res)) { - xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]); + if (xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]) + < 0) + ctxt->error = XPATH_MEMORY_ERROR; } /* @@ -14194,7 +14277,7 @@ xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatt if (toBool) return(1); xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, - (xmlNodePtr) ctxt->doc); + (xmlNodePtr) ctxt->doc); } else { /* Select "self::node()" */ if (toBool) @@ -14287,7 +14370,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); @@ -14303,6 +14390,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 @@ -14623,57 +14711,63 @@ xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, cons } #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->ch1 != -1) && + (op->op == XPATH_OP_COLLECT /* 11 */)) + { + 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]); } /** @@ -14731,12 +14825,8 @@ xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xml 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); @@ -14913,17 +15003,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]); } } @@ -14994,6 +15079,49 @@ xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ct } /** + * 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 @@ -15097,7 +15225,7 @@ static void xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) { xmlXPathObjectPtr str; int escape_reserved; - xmlBufferPtr target; + xmlBufPtr target; xmlChar *cptr; xmlChar escape[4]; @@ -15108,7 +15236,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctx CAST_TO_STRING; str = valuePop(ctxt); - target = xmlBufferCreate(); + target = xmlBufCreate(); escape[0] = '%'; escape[3] = 0; @@ -15133,7 +15261,7 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctx *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); @@ -15144,13 +15272,13 @@ xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctx 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); }