| Index: third_party/libxslt/libxslt/pattern.c
|
| diff --git a/third_party/libxslt/libxslt/pattern.c b/third_party/libxslt/libxslt/pattern.c
|
| index 9e9fbd699604bc0a8d0f056d84bc450679a3ff6c..57f8b9f8f14f334ab4ad543e371599d3c60b4bd5 100644
|
| --- a/third_party/libxslt/libxslt/pattern.c
|
| +++ b/third_party/libxslt/libxslt/pattern.c
|
| @@ -25,6 +25,7 @@
|
| #include <libxml/hash.h>
|
| #include <libxml/xmlerror.h>
|
| #include <libxml/parserInternals.h>
|
| +#include <libxml/xpath.h>
|
| #include "xslt.h"
|
| #include "xsltInternals.h"
|
| #include "xsltutils.h"
|
| @@ -127,9 +128,9 @@ struct _xsltParserContext {
|
| };
|
|
|
| /************************************************************************
|
| - * *
|
| - * Type functions *
|
| - * *
|
| + * *
|
| + * Type functions *
|
| + * *
|
| ************************************************************************/
|
|
|
| /**
|
| @@ -303,6 +304,10 @@ xsltCompMatchAdd(xsltParserContextPtr ctxt, xsltCompMatchPtr comp,
|
| "xsltCompMatchAdd: memory re-allocation failure.\n");
|
| if (ctxt->style != NULL)
|
| ctxt->style->errors++;
|
| + if (value)
|
| + xmlFree(value);
|
| + if (value2)
|
| + xmlFree(value2);
|
| return (-1);
|
| }
|
| comp->maxStep *= 2;
|
| @@ -368,7 +373,7 @@ xsltSwapTopCompMatch(xsltCompMatchPtr comp) {
|
| if (j > 0) {
|
| register xmlChar *tmp;
|
| register xsltOp op;
|
| - register xmlXPathCompExprPtr expr;
|
| + register xmlXPathCompExprPtr expr;
|
| register int t;
|
| i = j - 1;
|
| tmp = comp->steps[i].value;
|
| @@ -446,11 +451,14 @@ xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) {
|
| xsltCompMatchAdd(ctxt, comp, XSLT_OP_END, NULL, NULL, 0);
|
|
|
| /*
|
| - * detect consecutive XSLT_OP_PREDICATE indicating a direct
|
| - * matching should be done.
|
| + * Detect consecutive XSLT_OP_PREDICATE and predicates on ops which
|
| + * haven't been optimized yet indicating a direct matching should be done.
|
| */
|
| for (i = 0;i < comp->nbStep - 1;i++) {
|
| - if ((comp->steps[i].op == XSLT_OP_PREDICATE) &&
|
| + xsltOp op = comp->steps[i].op;
|
| +
|
| + if ((op != XSLT_OP_ELEM) &&
|
| + (op != XSLT_OP_ALL) &&
|
| (comp->steps[i + 1].op == XSLT_OP_PREDICATE)) {
|
|
|
| comp->direct = 1;
|
| @@ -469,9 +477,9 @@ xsltReverseCompMatch(xsltParserContextPtr ctxt, xsltCompMatchPtr comp) {
|
| }
|
|
|
| /************************************************************************
|
| - * *
|
| - * The interpreter for the precompiled patterns *
|
| - * *
|
| + * *
|
| + * The interpreter for the precompiled patterns *
|
| + * *
|
| ************************************************************************/
|
|
|
| static int
|
| @@ -540,19 +548,21 @@ xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
|
| ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
|
| list = (xmlXPathObjectPtr)
|
| XSLT_RUNTIME_EXTRA_LST(ctxt, sel->lenExtra);
|
| -
|
| +
|
| if ((list == NULL) || (prevdoc != doc)) {
|
| xmlXPathObjectPtr newlist;
|
| xmlNodePtr parent = node->parent;
|
| xmlDocPtr olddoc;
|
| xmlNodePtr oldnode;
|
| - int oldNsNr;
|
| + int oldNsNr, oldContextSize, oldProximityPosition;
|
| xmlNsPtr *oldNamespaces;
|
|
|
| oldnode = ctxt->xpathCtxt->node;
|
| olddoc = ctxt->xpathCtxt->doc;
|
| oldNsNr = ctxt->xpathCtxt->nsNr;
|
| oldNamespaces = ctxt->xpathCtxt->namespaces;
|
| + oldContextSize = ctxt->xpathCtxt->contextSize;
|
| + oldProximityPosition = ctxt->xpathCtxt->proximityPosition;
|
| ctxt->xpathCtxt->node = node;
|
| ctxt->xpathCtxt->doc = doc;
|
| ctxt->xpathCtxt->namespaces = nsList;
|
| @@ -562,6 +572,8 @@ xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
|
| ctxt->xpathCtxt->doc = olddoc;
|
| ctxt->xpathCtxt->namespaces = oldNamespaces;
|
| ctxt->xpathCtxt->nsNr = oldNsNr;
|
| + ctxt->xpathCtxt->contextSize = oldContextSize;
|
| + ctxt->xpathCtxt->proximityPosition = oldProximityPosition;
|
| if (newlist == NULL)
|
| return(-1);
|
| if (newlist->type != XPATH_NODESET) {
|
| @@ -572,7 +584,7 @@ xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
|
|
|
| if ((parent == NULL) || (node->doc == NULL) || isRVT)
|
| nocache = 1;
|
| -
|
| +
|
| if (nocache == 0) {
|
| if (list != NULL)
|
| xmlXPathFreeObject(list);
|
| @@ -612,6 +624,280 @@ xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
|
| }
|
|
|
| /**
|
| + * xsltTestPredicateMatch:
|
| + * @ctxt: a XSLT process context
|
| + * @comp: the precompiled pattern
|
| + * @node: a node
|
| + * @step: the predicate step
|
| + * @sel: the previous step
|
| + *
|
| + * Test whether the node matches the predicate
|
| + *
|
| + * Returns 1 if it matches, 0 if it doesn't and -1 in case of failure
|
| + */
|
| +static int
|
| +xsltTestPredicateMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
|
| + xmlNodePtr node, xsltStepOpPtr step,
|
| + xsltStepOpPtr sel) {
|
| + xmlNodePtr oldNode;
|
| + xmlDocPtr doc;
|
| + int oldCS, oldCP;
|
| + int pos = 0, len = 0;
|
| + int isRVT;
|
| + int match;
|
| +
|
| + if (step->value == NULL)
|
| + return(0);
|
| + if (step->comp == NULL)
|
| + return(0);
|
| +
|
| + doc = node->doc;
|
| + if (XSLT_IS_RES_TREE_FRAG(doc))
|
| + isRVT = 1;
|
| + else
|
| + isRVT = 0;
|
| +
|
| + /*
|
| + * Recompute contextSize and proximityPosition.
|
| + *
|
| + * TODO: Make this work for additional ops. Currently, only XSLT_OP_ELEM
|
| + * and XSLT_OP_ALL are supported.
|
| + */
|
| + oldCS = ctxt->xpathCtxt->contextSize;
|
| + oldCP = ctxt->xpathCtxt->proximityPosition;
|
| + if ((sel != NULL) &&
|
| + (sel->op == XSLT_OP_ELEM) &&
|
| + (sel->value != NULL) &&
|
| + (node->type == XML_ELEMENT_NODE) &&
|
| + (node->parent != NULL)) {
|
| + xmlNodePtr previous;
|
| + int nocache = 0;
|
| +
|
| + previous = (xmlNodePtr)
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
|
| + if ((previous != NULL) &&
|
| + (previous->parent == node->parent)) {
|
| + /*
|
| + * just walk back to adjust the index
|
| + */
|
| + int indx = 0;
|
| + xmlNodePtr sibling = node;
|
| +
|
| + while (sibling != NULL) {
|
| + if (sibling == previous)
|
| + break;
|
| + if ((sibling->type == XML_ELEMENT_NODE) &&
|
| + (previous->name != NULL) &&
|
| + (sibling->name != NULL) &&
|
| + (previous->name[0] == sibling->name[0]) &&
|
| + (xmlStrEqual(previous->name, sibling->name)))
|
| + {
|
| + if ((sel->value2 == NULL) ||
|
| + ((sibling->ns != NULL) &&
|
| + (xmlStrEqual(sel->value2, sibling->ns->href))))
|
| + indx++;
|
| + }
|
| + sibling = sibling->prev;
|
| + }
|
| + if (sibling == NULL) {
|
| + /* hum going backward in document order ... */
|
| + indx = 0;
|
| + sibling = node;
|
| + while (sibling != NULL) {
|
| + if (sibling == previous)
|
| + break;
|
| + if ((sibling->type == XML_ELEMENT_NODE) &&
|
| + (previous->name != NULL) &&
|
| + (sibling->name != NULL) &&
|
| + (previous->name[0] == sibling->name[0]) &&
|
| + (xmlStrEqual(previous->name, sibling->name)))
|
| + {
|
| + if ((sel->value2 == NULL) ||
|
| + ((sibling->ns != NULL) &&
|
| + (xmlStrEqual(sel->value2,
|
| + sibling->ns->href))))
|
| + {
|
| + indx--;
|
| + }
|
| + }
|
| + sibling = sibling->next;
|
| + }
|
| + }
|
| + if (sibling != NULL) {
|
| + pos = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) + indx;
|
| + /*
|
| + * If the node is in a Value Tree we need to
|
| + * save len, but cannot cache the node!
|
| + * (bugs 153137 and 158840)
|
| + */
|
| + if (node->doc != NULL) {
|
| + len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
|
| + if (!isRVT) {
|
| + XSLT_RUNTIME_EXTRA(ctxt,
|
| + sel->previousExtra, ptr) = node;
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
|
| + }
|
| + }
|
| + } else
|
| + pos = 0;
|
| + } else {
|
| + /*
|
| + * recompute the index
|
| + */
|
| + xmlNodePtr parent = node->parent;
|
| + xmlNodePtr siblings = NULL;
|
| +
|
| + if (parent) siblings = parent->children;
|
| +
|
| + while (siblings != NULL) {
|
| + if (siblings->type == XML_ELEMENT_NODE) {
|
| + if (siblings == node) {
|
| + len++;
|
| + pos = len;
|
| + } else if ((node->name != NULL) &&
|
| + (siblings->name != NULL) &&
|
| + (node->name[0] == siblings->name[0]) &&
|
| + (xmlStrEqual(node->name, siblings->name))) {
|
| + if ((sel->value2 == NULL) ||
|
| + ((siblings->ns != NULL) &&
|
| + (xmlStrEqual(sel->value2, siblings->ns->href))))
|
| + len++;
|
| + }
|
| + }
|
| + siblings = siblings->next;
|
| + }
|
| + if ((parent == NULL) || (node->doc == NULL))
|
| + nocache = 1;
|
| + else {
|
| + while (parent->parent != NULL)
|
| + parent = parent->parent;
|
| + if (((parent->type != XML_DOCUMENT_NODE) &&
|
| + (parent->type != XML_HTML_DOCUMENT_NODE)) ||
|
| + (parent != (xmlNodePtr) node->doc))
|
| + nocache = 1;
|
| + }
|
| + }
|
| + if (pos != 0) {
|
| + ctxt->xpathCtxt->contextSize = len;
|
| + ctxt->xpathCtxt->proximityPosition = pos;
|
| + /*
|
| + * If the node is in a Value Tree we cannot
|
| + * cache it !
|
| + */
|
| + if ((!isRVT) && (node->doc != NULL) &&
|
| + (nocache == 0)) {
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
|
| + }
|
| + }
|
| + } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
|
| + (node->type == XML_ELEMENT_NODE)) {
|
| + xmlNodePtr previous;
|
| + int nocache = 0;
|
| +
|
| + previous = (xmlNodePtr)
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
|
| + if ((previous != NULL) &&
|
| + (previous->parent == node->parent)) {
|
| + /*
|
| + * just walk back to adjust the index
|
| + */
|
| + int indx = 0;
|
| + xmlNodePtr sibling = node;
|
| +
|
| + while (sibling != NULL) {
|
| + if (sibling == previous)
|
| + break;
|
| + if (sibling->type == XML_ELEMENT_NODE)
|
| + indx++;
|
| + sibling = sibling->prev;
|
| + }
|
| + if (sibling == NULL) {
|
| + /* hum going backward in document order ... */
|
| + indx = 0;
|
| + sibling = node;
|
| + while (sibling != NULL) {
|
| + if (sibling == previous)
|
| + break;
|
| + if (sibling->type == XML_ELEMENT_NODE)
|
| + indx--;
|
| + sibling = sibling->next;
|
| + }
|
| + }
|
| + if (sibling != NULL) {
|
| + pos = XSLT_RUNTIME_EXTRA(ctxt,
|
| + sel->indexExtra, ival) + indx;
|
| + /*
|
| + * If the node is in a Value Tree we cannot
|
| + * cache it !
|
| + */
|
| + if ((node->doc != NULL) && !isRVT) {
|
| + len = XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival);
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
|
| + }
|
| + } else
|
| + pos = 0;
|
| + } else {
|
| + /*
|
| + * recompute the index
|
| + */
|
| + xmlNodePtr parent = node->parent;
|
| + xmlNodePtr siblings = NULL;
|
| +
|
| + if (parent) siblings = parent->children;
|
| +
|
| + while (siblings != NULL) {
|
| + if (siblings->type == XML_ELEMENT_NODE) {
|
| + len++;
|
| + if (siblings == node) {
|
| + pos = len;
|
| + }
|
| + }
|
| + siblings = siblings->next;
|
| + }
|
| + if ((parent == NULL) || (node->doc == NULL))
|
| + nocache = 1;
|
| + else {
|
| + while (parent->parent != NULL)
|
| + parent = parent->parent;
|
| + if (((parent->type != XML_DOCUMENT_NODE) &&
|
| + (parent->type != XML_HTML_DOCUMENT_NODE)) ||
|
| + (parent != (xmlNodePtr) node->doc))
|
| + nocache = 1;
|
| + }
|
| + }
|
| + if (pos != 0) {
|
| + ctxt->xpathCtxt->contextSize = len;
|
| + ctxt->xpathCtxt->proximityPosition = pos;
|
| + /*
|
| + * If the node is in a Value Tree we cannot
|
| + * cache it !
|
| + */
|
| + if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) = node;
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) = pos;
|
| + XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) = len;
|
| + }
|
| + }
|
| + }
|
| +
|
| + oldNode = ctxt->node;
|
| + ctxt->node = node;
|
| +
|
| + match = xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList, comp->nsNr);
|
| +
|
| + if (pos != 0) {
|
| + ctxt->xpathCtxt->contextSize = oldCS;
|
| + ctxt->xpathCtxt->proximityPosition = oldCP;
|
| + }
|
| + ctxt->node = oldNode;
|
| +
|
| + return match;
|
| +}
|
| +
|
| +/**
|
| * xsltTestCompMatch:
|
| * @ctxt: a XSLT process context
|
| * @comp: the precompiled pattern
|
| @@ -625,9 +911,10 @@ xsltTestCompMatchDirect(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
|
| */
|
| static int
|
| xsltTestCompMatch(xsltTransformContextPtr ctxt, xsltCompMatchPtr comp,
|
| - xmlNodePtr node, const xmlChar *mode,
|
| + xmlNodePtr matchNode, const xmlChar *mode,
|
| const xmlChar *modeURI) {
|
| int i;
|
| + xmlNodePtr node = matchNode;
|
| xsltStepOpPtr step, sel = NULL;
|
| xsltStepStates states = {0, 0, NULL}; /* // may require backtrack */
|
|
|
| @@ -754,8 +1041,8 @@ restart:
|
| if (step->op == XSLT_OP_ROOT)
|
| goto found;
|
| /* added NS, ID and KEY as a result of bug 168208 */
|
| - if ((step->op != XSLT_OP_ELEM) &&
|
| - (step->op != XSLT_OP_ALL) &&
|
| + if ((step->op != XSLT_OP_ELEM) &&
|
| + (step->op != XSLT_OP_ALL) &&
|
| (step->op != XSLT_OP_NS) &&
|
| (step->op != XSLT_OP_ID) &&
|
| (step->op != XSLT_OP_KEY))
|
| @@ -845,14 +1132,9 @@ restart:
|
| goto rollback;
|
| break;
|
| case XSLT_OP_PREDICATE: {
|
| - xmlNodePtr oldNode;
|
| - xmlDocPtr doc;
|
| - int oldCS, oldCP;
|
| - int pos = 0, len = 0;
|
| - int isRVT;
|
| -
|
| /*
|
| - * when there is cascading XSLT_OP_PREDICATE, then use a
|
| + * When there is cascading XSLT_OP_PREDICATE or a predicate
|
| + * after an op which hasn't been optimized yet, then use a
|
| * direct computation approach. It's not done directly
|
| * at the beginning of the routine to filter out as much
|
| * as possible this costly computation.
|
| @@ -862,279 +1144,14 @@ restart:
|
| /* Free the rollback states */
|
| xmlFree(states.states);
|
| }
|
| - return(xsltTestCompMatchDirect(ctxt, comp, node,
|
| - comp->nsList, comp->nsNr));
|
| + return(xsltTestCompMatchDirect(ctxt, comp, matchNode,
|
| + comp->nsList, comp->nsNr));
|
| }
|
|
|
| - doc = node->doc;
|
| - if (XSLT_IS_RES_TREE_FRAG(doc))
|
| - isRVT = 1;
|
| - else
|
| - isRVT = 0;
|
| -
|
| - /*
|
| - * Depending on the last selection, one may need to
|
| - * recompute contextSize and proximityPosition.
|
| - */
|
| - oldCS = ctxt->xpathCtxt->contextSize;
|
| - oldCP = ctxt->xpathCtxt->proximityPosition;
|
| - if ((sel != NULL) &&
|
| - (sel->op == XSLT_OP_ELEM) &&
|
| - (sel->value != NULL) &&
|
| - (node->type == XML_ELEMENT_NODE) &&
|
| - (node->parent != NULL)) {
|
| - xmlNodePtr previous;
|
| - int ix, nocache = 0;
|
| -
|
| - previous = (xmlNodePtr)
|
| - XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
|
| - ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
|
| - if ((previous != NULL) &&
|
| - (previous->parent == node->parent)) {
|
| - /*
|
| - * just walk back to adjust the index
|
| - */
|
| - int indx = 0;
|
| - xmlNodePtr sibling = node;
|
| -
|
| - while (sibling != NULL) {
|
| - if (sibling == previous)
|
| - break;
|
| - if ((previous->type == XML_ELEMENT_NODE) &&
|
| - (previous->name != NULL) &&
|
| - (sibling->name != NULL) &&
|
| - (previous->name[0] == sibling->name[0]) &&
|
| - (xmlStrEqual(previous->name, sibling->name)))
|
| - {
|
| - if ((sel->value2 == NULL) ||
|
| - ((sibling->ns != NULL) &&
|
| - (xmlStrEqual(sel->value2,
|
| - sibling->ns->href))))
|
| - indx++;
|
| - }
|
| - sibling = sibling->prev;
|
| - }
|
| - if (sibling == NULL) {
|
| - /* hum going backward in document order ... */
|
| - indx = 0;
|
| - sibling = node;
|
| - while (sibling != NULL) {
|
| - if (sibling == previous)
|
| - break;
|
| - if ((previous->type == XML_ELEMENT_NODE) &&
|
| - (previous->name != NULL) &&
|
| - (sibling->name != NULL) &&
|
| - (previous->name[0] == sibling->name[0]) &&
|
| - (xmlStrEqual(previous->name, sibling->name)))
|
| - {
|
| - if ((sel->value2 == NULL) ||
|
| - ((sibling->ns != NULL) &&
|
| - (xmlStrEqual(sel->value2,
|
| - sibling->ns->href))))
|
| - {
|
| - indx--;
|
| - }
|
| - }
|
| - sibling = sibling->next;
|
| - }
|
| - }
|
| - if (sibling != NULL) {
|
| - pos = ix + indx;
|
| - /*
|
| - * If the node is in a Value Tree we need to
|
| - * save len, but cannot cache the node!
|
| - * (bugs 153137 and 158840)
|
| - */
|
| - if (node->doc != NULL) {
|
| - len = XSLT_RUNTIME_EXTRA(ctxt,
|
| - sel->lenExtra, ival);
|
| - if (!isRVT) {
|
| - XSLT_RUNTIME_EXTRA(ctxt,
|
| - sel->previousExtra, ptr) = node;
|
| - XSLT_RUNTIME_EXTRA(ctxt,
|
| - sel->indexExtra, ival) = pos;
|
| - }
|
| - }
|
| - ix = pos;
|
| - } else
|
| - pos = 0;
|
| - } else {
|
| - /*
|
| - * recompute the index
|
| - */
|
| - xmlNodePtr parent = node->parent;
|
| - xmlNodePtr siblings = NULL;
|
| -
|
| - if (parent) siblings = parent->children;
|
| -
|
| - while (siblings != NULL) {
|
| - if (siblings->type == XML_ELEMENT_NODE) {
|
| - if (siblings == node) {
|
| - len++;
|
| - pos = len;
|
| - } else if ((node->name != NULL) &&
|
| - (siblings->name != NULL) &&
|
| - (node->name[0] == siblings->name[0]) &&
|
| - (xmlStrEqual(node->name, siblings->name))) {
|
| - if ((sel->value2 == NULL) ||
|
| - ((siblings->ns != NULL) &&
|
| - (xmlStrEqual(sel->value2,
|
| - siblings->ns->href))))
|
| - len++;
|
| - }
|
| - }
|
| - siblings = siblings->next;
|
| - }
|
| - if ((parent == NULL) || (node->doc == NULL))
|
| - nocache = 1;
|
| - else {
|
| - while (parent->parent != NULL)
|
| - parent = parent->parent;
|
| - if (((parent->type != XML_DOCUMENT_NODE) &&
|
| - (parent->type != XML_HTML_DOCUMENT_NODE)) ||
|
| - (parent != (xmlNodePtr) node->doc))
|
| - nocache = 1;
|
| - }
|
| - }
|
| - if (pos != 0) {
|
| - ctxt->xpathCtxt->contextSize = len;
|
| - ctxt->xpathCtxt->proximityPosition = pos;
|
| - /*
|
| - * If the node is in a Value Tree we cannot
|
| - * cache it !
|
| - */
|
| - if ((!isRVT) && (node->doc != NULL) &&
|
| - (nocache == 0)) {
|
| - XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
|
| - node;
|
| - XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
|
| - pos;
|
| - XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
|
| - len;
|
| - }
|
| - }
|
| - } else if ((sel != NULL) && (sel->op == XSLT_OP_ALL) &&
|
| - (node->type == XML_ELEMENT_NODE)) {
|
| - xmlNodePtr previous;
|
| - int ix, nocache = 0;
|
| -
|
| - previous = (xmlNodePtr)
|
| - XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr);
|
| - ix = XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival);
|
| - if ((previous != NULL) &&
|
| - (previous->parent == node->parent)) {
|
| - /*
|
| - * just walk back to adjust the index
|
| - */
|
| - int indx = 0;
|
| - xmlNodePtr sibling = node;
|
| -
|
| - while (sibling != NULL) {
|
| - if (sibling == previous)
|
| - break;
|
| - if (sibling->type == XML_ELEMENT_NODE)
|
| - indx++;
|
| - sibling = sibling->prev;
|
| - }
|
| - if (sibling == NULL) {
|
| - /* hum going backward in document order ... */
|
| - indx = 0;
|
| - sibling = node;
|
| - while (sibling != NULL) {
|
| - if (sibling == previous)
|
| - break;
|
| - if (sibling->type == XML_ELEMENT_NODE)
|
| - indx--;
|
| - sibling = sibling->next;
|
| - }
|
| - }
|
| - if (sibling != NULL) {
|
| - pos = ix + indx;
|
| - /*
|
| - * If the node is in a Value Tree we cannot
|
| - * cache it !
|
| - */
|
| - if ((node->doc != NULL) && !isRVT) {
|
| - len = XSLT_RUNTIME_EXTRA(ctxt,
|
| - sel->lenExtra, ival);
|
| - XSLT_RUNTIME_EXTRA(ctxt,
|
| - sel->previousExtra, ptr) = node;
|
| - XSLT_RUNTIME_EXTRA(ctxt,
|
| - sel->indexExtra, ival) = pos;
|
| - }
|
| - } else
|
| - pos = 0;
|
| - } else {
|
| - /*
|
| - * recompute the index
|
| - */
|
| - xmlNodePtr parent = node->parent;
|
| - xmlNodePtr siblings = NULL;
|
| -
|
| - if (parent) siblings = parent->children;
|
| -
|
| - while (siblings != NULL) {
|
| - if (siblings->type == XML_ELEMENT_NODE) {
|
| - len++;
|
| - if (siblings == node) {
|
| - pos = len;
|
| - }
|
| - }
|
| - siblings = siblings->next;
|
| - }
|
| - if ((parent == NULL) || (node->doc == NULL))
|
| - nocache = 1;
|
| - else {
|
| - while (parent->parent != NULL)
|
| - parent = parent->parent;
|
| - if (((parent->type != XML_DOCUMENT_NODE) &&
|
| - (parent->type != XML_HTML_DOCUMENT_NODE)) ||
|
| - (parent != (xmlNodePtr) node->doc))
|
| - nocache = 1;
|
| - }
|
| - }
|
| - if (pos != 0) {
|
| - ctxt->xpathCtxt->contextSize = len;
|
| - ctxt->xpathCtxt->proximityPosition = pos;
|
| - /*
|
| - * If the node is in a Value Tree we cannot
|
| - * cache it !
|
| - */
|
| - if ((node->doc != NULL) && (nocache == 0) && !isRVT) {
|
| - XSLT_RUNTIME_EXTRA(ctxt, sel->previousExtra, ptr) =
|
| - node;
|
| - XSLT_RUNTIME_EXTRA(ctxt, sel->indexExtra, ival) =
|
| - pos;
|
| - XSLT_RUNTIME_EXTRA(ctxt, sel->lenExtra, ival) =
|
| - len;
|
| - }
|
| - }
|
| - }
|
| - oldNode = ctxt->node;
|
| - ctxt->node = node;
|
| -
|
| - if (step->value == NULL)
|
| - goto wrong_index;
|
| - if (step->comp == NULL)
|
| - goto wrong_index;
|
| -
|
| - if (!xsltEvalXPathPredicate(ctxt, step->comp, comp->nsList,
|
| - comp->nsNr))
|
| - goto wrong_index;
|
| + if (!xsltTestPredicateMatch(ctxt, comp, node, step, sel))
|
| + goto rollback;
|
|
|
| - if (pos != 0) {
|
| - ctxt->xpathCtxt->contextSize = oldCS;
|
| - ctxt->xpathCtxt->proximityPosition = oldCP;
|
| - }
|
| - ctxt->node = oldNode;
|
| break;
|
| -wrong_index:
|
| - if (pos != 0) {
|
| - ctxt->xpathCtxt->contextSize = oldCS;
|
| - ctxt->xpathCtxt->proximityPosition = oldCP;
|
| - }
|
| - ctxt->node = oldNode;
|
| - goto rollback;
|
| }
|
| case XSLT_OP_PI:
|
| if (node->type != XML_PI_NODE)
|
| @@ -1227,17 +1244,17 @@ xsltTestCompMatchList(xsltTransformContextPtr ctxt, xmlNodePtr node,
|
| #define NXT(val) ctxt->cur[(val)]
|
| #define CUR_PTR ctxt->cur
|
|
|
| -#define SKIP_BLANKS \
|
| +#define SKIP_BLANKS \
|
| while (IS_BLANK_CH(CUR)) NEXT
|
|
|
| #define CURRENT (*ctxt->cur)
|
| #define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
|
|
|
|
|
| -#define PUSH(op, val, val2, novar) \
|
| +#define PUSH(op, val, val2, novar) \
|
| if (xsltCompMatchAdd(ctxt, ctxt->comp, (op), (val), (val2), (novar))) goto error;
|
|
|
| -#define SWAP() \
|
| +#define SWAP() \
|
| xsltSwapTopCompMatch(ctxt->comp);
|
|
|
| #define XSLT_ERROR(X) \
|
| @@ -1381,17 +1398,22 @@ xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
|
| NEXT;
|
| SKIP_BLANKS;
|
| lit = xsltScanLiteral(ctxt);
|
| - if (ctxt->error)
|
| + if (ctxt->error) {
|
| + xsltTransformError(NULL, NULL, NULL,
|
| + "xsltCompileIdKeyPattern : Literal expected\n");
|
| return;
|
| + }
|
| SKIP_BLANKS;
|
| if (CUR != ')') {
|
| xsltTransformError(NULL, NULL, NULL,
|
| "xsltCompileIdKeyPattern : ) expected\n");
|
| + xmlFree(lit);
|
| ctxt->error = 1;
|
| return;
|
| }
|
| NEXT;
|
| PUSH(XSLT_OP_ID, lit, NULL, novar);
|
| + lit = NULL;
|
| } else if ((aid) && (xmlStrEqual(name, (const xmlChar *)"key"))) {
|
| if (axis != 0) {
|
| xsltTransformError(NULL, NULL, NULL,
|
| @@ -1402,37 +1424,52 @@ xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
|
| NEXT;
|
| SKIP_BLANKS;
|
| lit = xsltScanLiteral(ctxt);
|
| - if (ctxt->error)
|
| + if (ctxt->error) {
|
| + xsltTransformError(NULL, NULL, NULL,
|
| + "xsltCompileIdKeyPattern : Literal expected\n");
|
| return;
|
| + }
|
| SKIP_BLANKS;
|
| if (CUR != ',') {
|
| xsltTransformError(NULL, NULL, NULL,
|
| "xsltCompileIdKeyPattern : , expected\n");
|
| + xmlFree(lit);
|
| ctxt->error = 1;
|
| return;
|
| }
|
| NEXT;
|
| SKIP_BLANKS;
|
| lit2 = xsltScanLiteral(ctxt);
|
| - if (ctxt->error)
|
| + if (ctxt->error) {
|
| + xsltTransformError(NULL, NULL, NULL,
|
| + "xsltCompileIdKeyPattern : Literal expected\n");
|
| + xmlFree(lit);
|
| return;
|
| + }
|
| SKIP_BLANKS;
|
| if (CUR != ')') {
|
| xsltTransformError(NULL, NULL, NULL,
|
| "xsltCompileIdKeyPattern : ) expected\n");
|
| + xmlFree(lit);
|
| + xmlFree(lit2);
|
| ctxt->error = 1;
|
| return;
|
| }
|
| NEXT;
|
| /* URGENT TODO: support namespace in keys */
|
| PUSH(XSLT_OP_KEY, lit, lit2, novar);
|
| + lit = NULL;
|
| + lit2 = NULL;
|
| } else if (xmlStrEqual(name, (const xmlChar *)"processing-instruction")) {
|
| NEXT;
|
| SKIP_BLANKS;
|
| if (CUR != ')') {
|
| lit = xsltScanLiteral(ctxt);
|
| - if (ctxt->error)
|
| + if (ctxt->error) {
|
| + xsltTransformError(NULL, NULL, NULL,
|
| + "xsltCompileIdKeyPattern : Literal expected\n");
|
| return;
|
| + }
|
| SKIP_BLANKS;
|
| if (CUR != ')') {
|
| xsltTransformError(NULL, NULL, NULL,
|
| @@ -1443,6 +1480,7 @@ xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
|
| }
|
| NEXT;
|
| PUSH(XSLT_OP_PI, lit, NULL, novar);
|
| + lit = NULL;
|
| } else if (xmlStrEqual(name, (const xmlChar *)"text")) {
|
| NEXT;
|
| SKIP_BLANKS;
|
| @@ -1493,8 +1531,7 @@ xsltCompileIdKeyPattern(xsltParserContextPtr ctxt, xmlChar *name,
|
| return;
|
| }
|
| error:
|
| - if (name != NULL)
|
| - xmlFree(name);
|
| + return;
|
| }
|
|
|
| /**
|
| @@ -1506,7 +1543,7 @@ error:
|
| * Compile the XSLT StepPattern and generates a precompiled
|
| * form suitable for fast matching.
|
| *
|
| - * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
|
| + * [5] StepPattern ::= ChildOrAttributeAxisSpecifier NodeTest Predicate*
|
| * [6] ChildOrAttributeAxisSpecifier ::= AbbreviatedAxisSpecifier
|
| * | ('child' | 'attribute') '::'
|
| * from XPath
|
| @@ -1557,6 +1594,8 @@ parse_node_test:
|
| SKIP_BLANKS;
|
| if (CUR == '(') {
|
| xsltCompileIdKeyPattern(ctxt, token, 0, novar, axis);
|
| + xmlFree(token);
|
| + token = NULL;
|
| if (ctxt->error)
|
| goto error;
|
| } else if (CUR == ':') {
|
| @@ -1575,20 +1614,24 @@ parse_node_test:
|
| "xsltCompileStepPattern : no namespace bound to prefix %s\n",
|
| prefix);
|
| xmlFree(prefix);
|
| + prefix=NULL;
|
| ctxt->error = 1;
|
| goto error;
|
| } else {
|
| URL = xmlStrdup(ns->href);
|
| }
|
| xmlFree(prefix);
|
| + prefix=NULL;
|
| if (token == NULL) {
|
| if (CUR == '*') {
|
| NEXT;
|
| if (axis == AXIS_ATTRIBUTE) {
|
| PUSH(XSLT_OP_ATTR, NULL, URL, novar);
|
| + URL = NULL;
|
| }
|
| else {
|
| PUSH(XSLT_OP_NS, URL, NULL, novar);
|
| + URL = NULL;
|
| }
|
| } else {
|
| xsltTransformError(NULL, NULL, NULL,
|
| @@ -1599,9 +1642,13 @@ parse_node_test:
|
| } else {
|
| if (axis == AXIS_ATTRIBUTE) {
|
| PUSH(XSLT_OP_ATTR, token, URL, novar);
|
| + token = NULL;
|
| + URL = NULL;
|
| }
|
| else {
|
| PUSH(XSLT_OP_ELEM, token, URL, novar);
|
| + token = NULL;
|
| + URL = NULL;
|
| }
|
| }
|
| } else {
|
| @@ -1623,6 +1670,7 @@ parse_node_test:
|
| goto error;
|
| }
|
| xmlFree(token);
|
| + token = NULL;
|
| SKIP_BLANKS;
|
| token = xsltScanNCName(ctxt);
|
| goto parse_node_test;
|
| @@ -1637,9 +1685,13 @@ parse_node_test:
|
| URL = xmlStrdup(URI);
|
| if (axis == AXIS_ATTRIBUTE) {
|
| PUSH(XSLT_OP_ATTR, token, URL, novar);
|
| + token = NULL;
|
| + URL = NULL;
|
| }
|
| else {
|
| PUSH(XSLT_OP_ELEM, token, URL, novar);
|
| + token = NULL;
|
| + URL = NULL;
|
| }
|
| }
|
| parse_predicate:
|
| @@ -1679,6 +1731,7 @@ parse_predicate:
|
| }
|
| ret = xmlStrndup(q, CUR_PTR - q);
|
| PUSH(XSLT_OP_PREDICATE, ret, NULL, novar);
|
| + ret = NULL;
|
| /* push the predicate lower than local test */
|
| SWAP();
|
| NEXT;
|
| @@ -1787,8 +1840,8 @@ xsltCompileLocationPathPattern(xsltParserContextPtr ctxt, int novar) {
|
| SKIP_BLANKS;
|
| if ((CUR == '(') && !xmlXPathIsNodeType(name)) {
|
| xsltCompileIdKeyPattern(ctxt, name, 1, novar, 0);
|
| - if (ctxt->error)
|
| - return;
|
| + xmlFree(name);
|
| + name = NULL;
|
| if ((CUR == '/') && (NXT(1) == '/')) {
|
| PUSH(XSLT_OP_ANCESTOR, NULL, NULL, novar);
|
| NEXT;
|
| @@ -1866,8 +1919,8 @@ xsltCompilePatternInternal(const xmlChar *pattern, xmlDocPtr doc,
|
| while ((pattern[end] != 0) && (pattern[end] != '"'))
|
| end++;
|
| }
|
| - if (pattern[end] == 0)
|
| - break;
|
| + if (pattern[end] == 0)
|
| + break;
|
| end++;
|
| }
|
| if (current == end) {
|
| @@ -2044,12 +2097,12 @@ xsltAddTemplate(xsltStylesheetPtr style, xsltTemplatePtr cur,
|
| pat = xsltCompilePatternInternal(cur->match, style->doc, cur->elem,
|
| style, NULL, 1);
|
| if (pat == NULL)
|
| - return(-1);
|
| + return(-1);
|
| while (pat) {
|
| next = pat->next;
|
| pat->next = NULL;
|
| name = NULL;
|
| -
|
| +
|
| pat->template = cur;
|
| if (mode != NULL)
|
| pat->mode = xmlDictLookup(style->dict, mode, -1);
|
| @@ -2436,7 +2489,7 @@ keyed_match:
|
| goto error;
|
|
|
| switch (node->type) {
|
| - case XML_ELEMENT_NODE:
|
| + case XML_ELEMENT_NODE:
|
| if (node->psvi != NULL) keyed = 1;
|
| break;
|
| case XML_ATTRIBUTE_NODE:
|
| @@ -2445,13 +2498,13 @@ keyed_match:
|
| case XML_TEXT_NODE:
|
| case XML_CDATA_SECTION_NODE:
|
| case XML_COMMENT_NODE:
|
| - case XML_PI_NODE:
|
| + case XML_PI_NODE:
|
| if (node->psvi != NULL) keyed = 1;
|
| break;
|
| case XML_DOCUMENT_NODE:
|
| case XML_HTML_DOCUMENT_NODE:
|
| if (((xmlDocPtr) node)->psvi != NULL) keyed = 1;
|
| - break;
|
| + break;
|
| default:
|
| break;
|
| }
|
|
|