#if defined(__MVS__)
#pragma convert("ISO8859-1")
#endif
#define IN_LIBXML
#include "libxml.h"
#include <limits.h>
#include <string.h>
#include <stddef.h>
#include <math.h>
#include <float.h>
#include <ctype.h>
#include <libxml/xmlmemory.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include <libxml/parserInternals.h>
#include <libxml/hash.h>
#ifdef LIBXML_XPTR_LOCS_ENABLED
#include <libxml/xpointer.h>
#endif
#ifdef LIBXML_DEBUG_ENABLED
#include <libxml/debugXML.h>
#endif
#include <libxml/xmlerror.h>
#include <libxml/threads.h>
#ifdef LIBXML_PATTERN_ENABLED
#include <libxml/pattern.h>
#endif
#include "private/buf.h"
#include "private/error.h"
#include "private/xpath.h"
#ifdef LIBXML_PATTERN_ENABLED
#define XPATH_STREAMING
#endif
#define TODO \
xmlGenericError(xmlGenericErrorContext, \
"Unimplemented block at %s:%d\n", \
__FILE__, __LINE__);
#define WITH_TIM_SORT
#define XP_OPTIMIZED_NON_ELEM_COMPARISON
#define XP_OPTIMIZED_FILTER_FIRST
#define XPATH_MAX_STEPS 1000000
#define XPATH_MAX_STACK_DEPTH 1000000
#define XPATH_MAX_NODESET_LENGTH 10000000
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
#define XPATH_MAX_RECURSION_DEPTH 500
#elif defined(_WIN32)
#define XPATH_MAX_RECURSION_DEPTH 1000
#else
#define XPATH_MAX_RECURSION_DEPTH 5000
#endif
#if defined(LIBXML_XPATH_ENABLED) || defined(LIBXML_SCHEMAS_ENABLED)
double xmlXPathNAN = 0.0;
double xmlXPathPINF = 0.0;
double xmlXPathNINF = 0.0;
void
xmlXPathInit(void) {
xmlInitParser();
}
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
void
xmlInitXPathInternal(void) {
#if defined(NAN) && defined(INFINITY)
xmlXPathNAN = NAN;
xmlXPathPINF = INFINITY;
xmlXPathNINF = -INFINITY;
#else
double zero = 0.0;
xmlXPathNAN = 0.0 / zero;
xmlXPathPINF = 1.0 / zero;
xmlXPathNINF = -xmlXPathPINF;
#endif
}
int
xmlXPathIsNaN(double val) {
#ifdef isnan
return isnan(val);
#else
return !(val == val);
#endif
}
int
xmlXPathIsInf(double val) {
#ifdef isinf
return isinf(val) ? (val > 0 ? 1 : -1) : 0;
#else
if (val >= xmlXPathPINF)
return 1;
if (val <= -xmlXPathPINF)
return -1;
return 0;
#endif
}
#endif
#ifdef LIBXML_XPATH_ENABLED
static xmlNs xmlXPathXMLNamespaceStruct = {
NULL,
XML_NAMESPACE_DECL,
XML_XML_NAMESPACE,
BAD_CAST "xml",
NULL,
NULL
};
static xmlNsPtr xmlXPathXMLNamespace = &xmlXPathXMLNamespaceStruct;
#ifndef LIBXML_THREAD_ENABLED
static int xmlXPathDisableOptimizer = 0;
#endif
static void
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes);
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
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;
ptrdiff_t l1, l2;
if ((node1 == NULL) || (node2 == NULL))
return(-2);
if (node1 == node2)
return(0);
switch (node1->type) {
case XML_ELEMENT_NODE:
if (node2->type == XML_ELEMENT_NODE) {
if ((0 > (ptrdiff_t) node1->content) &&
(0 > (ptrdiff_t) node2->content) &&
(node1->doc == node2->doc))
{
l1 = -((ptrdiff_t) node1->content);
l2 = -((ptrdiff_t) node2->content);
if (l1 < l2)
return(1);
if (l1 > l2)
return(-1);
} else
goto turtle_comparison;
}
break;
case XML_ATTRIBUTE_NODE:
precedence1 = 1;
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;
if (node1->prev != NULL) {
do {
node1 = node1->prev;
if (node1->type == XML_ELEMENT_NODE) {
precedence1 = 3;
break;
}
if (node1->prev == NULL) {
precedence1 = 2;
node1 = node1->parent;
break;
}
} while (1);
} else {
precedence1 = 2;
node1 = node1->parent;
}
if ((node1 == NULL) || (node1->type != XML_ELEMENT_NODE) ||
(0 <= (ptrdiff_t) node1->content)) {
node1 = miscNode1;
precedence1 = 0;
} else
misc = 1;
}
break;
case XML_NAMESPACE_DECL:
return(1);
default:
break;
}
switch (node2->type) {
case XML_ELEMENT_NODE:
break;
case XML_ATTRIBUTE_NODE:
precedence2 = 1;
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;
break;
}
if (node2->prev == NULL) {
precedence2 = 2;
node2 = node2->parent;
break;
}
} while (1);
} else {
precedence2 = 2;
node2 = node2->parent;
}
if ((node2 == NULL) || (node2->type != XML_ELEMENT_NODE) ||
(0 <= (ptrdiff_t) 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) {
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 {
if (precedence1 < precedence2)
return(1);
else
return(-1);
}
}
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;
}
}
}
if ((node1->type == XML_ELEMENT_NODE) &&
(node2->type == XML_ELEMENT_NODE) &&
(0 > (ptrdiff_t) node1->content) &&
(0 > (ptrdiff_t) node2->content) &&
(node1->doc == node2->doc)) {
l1 = -((ptrdiff_t) node1->content);
l2 = -((ptrdiff_t) 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);
for (depth2 = 0, cur = node2; cur->parent != NULL; cur = cur->parent) {
if (cur->parent == node1)
return(1);
depth2++;
}
root = cur;
for (depth1 = 0, cur = node1; cur->parent != NULL; cur = cur->parent) {
if (cur->parent == node2)
return(-1);
depth1++;
}
if (root != cur) {
return(-2);
}
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;
if ((node1 == NULL) || (node2 == NULL))
return(-2);
}
if (node1 == node2->prev)
return(1);
if (node1 == node2->next)
return(-1);
if ((node1->type == XML_ELEMENT_NODE) &&
(node2->type == XML_ELEMENT_NODE) &&
(0 > (ptrdiff_t) node1->content) &&
(0 > (ptrdiff_t) node2->content) &&
(node1->doc == node2->doc)) {
l1 = -((ptrdiff_t) node1->content);
l2 = -((ptrdiff_t) 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);
}
#endif
#ifdef WITH_TIM_SORT
#define SORT_NAME libxml_domnode
#define SORT_TYPE xmlNodePtr
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
#define XP_ERRORNULL(X) \
{ xmlXPathErr(ctxt, X); return(NULL); }
static const char* const 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",
"Operation limit exceeded\n",
"Recursion limit exceeded\n",
"?? Unknown error ??\n"
};
#define MAXERRNO ((int)(sizeof(xmlXPathErrorMessages) / \
sizeof(xmlXPathErrorMessages[0])) - 1)
static void
xmlXPathErrMemory(xmlXPathContextPtr ctxt, const char *extra)
{
if (ctxt != NULL) {
xmlResetError(&ctxt->lastError);
if (extra) {
xmlChar buf[200];
xmlStrPrintf(buf, 200,
"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");
}
}
static void
xmlXPathPErrMemory(xmlXPathParserContextPtr ctxt, const char *extra)
{
if (ctxt == NULL)
xmlXPathErrMemory(NULL, extra);
else {
ctxt->error = XPATH_MEMORY_ERROR;
xmlXPathErrMemory(ctxt->context, extra);
}
}
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;
}
if (ctxt->error != 0)
return;
ctxt->error = error;
if (ctxt->context == NULL) {
__xmlRaiseError(NULL, NULL, NULL,
NULL, NULL, XML_FROM_XPATH,
error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
XML_ERR_ERROR, NULL, 0,
(const char *) ctxt->base, NULL, NULL,
ctxt->cur - ctxt->base, 0,
"%s", xmlXPathErrorMessages[error]);
return;
}
xmlResetError(&ctxt->context->lastError);
ctxt->context->lastError.domain = XML_FROM_XPATH;
ctxt->context->lastError.code = error + XML_XPATH_EXPRESSION_OK -
XPATH_EXPRESSION_OK;
ctxt->context->lastError.level = XML_ERR_ERROR;
ctxt->context->lastError.str1 = (char *) xmlStrdup(ctxt->base);
ctxt->context->lastError.int1 = ctxt->cur - ctxt->base;
ctxt->context->lastError.node = ctxt->context->debugNode;
if (ctxt->context->error != NULL) {
ctxt->context->error(ctxt->context->userData,
&ctxt->context->lastError);
} else {
__xmlRaiseError(NULL, NULL, NULL,
NULL, ctxt->context->debugNode, XML_FROM_XPATH,
error + XML_XPATH_EXPRESSION_OK - XPATH_EXPRESSION_OK,
XML_ERR_ERROR, NULL, 0,
(const char *) ctxt->base, NULL, NULL,
ctxt->cur - ctxt->base, 0,
"%s", xmlXPathErrorMessages[error]);
}
}
void
xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file ATTRIBUTE_UNUSED,
int line ATTRIBUTE_UNUSED, int no) {
xmlXPathErr(ctxt, no);
}
static int
xmlXPathCheckOpLimit(xmlXPathParserContextPtr ctxt, unsigned long opCount) {
xmlXPathContextPtr xpctxt = ctxt->context;
if ((opCount > xpctxt->opLimit) ||
(xpctxt->opCount > xpctxt->opLimit - opCount)) {
xpctxt->opCount = xpctxt->opLimit;
xmlXPathErr(ctxt, XPATH_OP_LIMIT_EXCEEDED);
return(-1);
}
xpctxt->opCount += opCount;
return(0);
}
#define OP_LIMIT_EXCEEDED(ctxt, n) \
((ctxt->context->opLimit != 0) && (xmlXPathCheckOpLimit(ctxt, n) < 0))
typedef struct _xmlPointerList xmlPointerList;
typedef xmlPointerList *xmlPointerListPtr;
struct _xmlPointerList {
void **items;
int number;
int size;
};
static int
xmlPointerListAddSize(xmlPointerListPtr list,
void *item,
int initialSize)
{
if (list->size <= list->number) {
void **tmp;
size_t newSize;
if (list->size == 0) {
if (initialSize <= 0)
initialSize = 1;
newSize = initialSize;
} else {
if (list->size > 50000000) {
xmlXPathErrMemory(NULL,
"xmlPointerListAddSize: re-allocating item\n");
return(-1);
}
newSize = list->size * 2;
}
tmp = (void **) xmlRealloc(list->items, newSize * sizeof(void *));
if (tmp == NULL) {
xmlXPathErrMemory(NULL,
"xmlPointerListAddSize: re-allocating item\n");
return(-1);
}
list->items = tmp;
list->size = newSize;
}
list->items[list->number++] = item;
return(0);
}
static xmlPointerListPtr
xmlPointerListCreate(int initialSize)
{
xmlPointerListPtr ret;
ret = xmlMalloc(sizeof(xmlPointerList));
if (ret == NULL) {
xmlXPathErrMemory(NULL,
"xmlPointerListCreate: allocating item\n");
return (NULL);
}
memset(ret, 0, sizeof(xmlPointerList));
if (initialSize > 0) {
xmlPointerListAddSize(ret, NULL, initialSize);
ret->number = 0;
}
return (ret);
}
static void
xmlPointerListFree(xmlPointerListPtr list)
{
if (list == NULL)
return;
if (list->items != NULL)
xmlFree(list->items);
xmlFree(list);
}
typedef enum {
XPATH_OP_END=0,
XPATH_OP_AND,
XPATH_OP_OR,
XPATH_OP_EQUAL,
XPATH_OP_CMP,
XPATH_OP_PLUS,
XPATH_OP_MULT,
XPATH_OP_UNION,
XPATH_OP_ROOT,
XPATH_OP_NODE,
XPATH_OP_COLLECT,
XPATH_OP_VALUE,
XPATH_OP_VARIABLE,
XPATH_OP_FUNCTION,
XPATH_OP_ARG,
XPATH_OP_PREDICATE,
XPATH_OP_FILTER,
XPATH_OP_SORT
#ifdef LIBXML_XPTR_LOCS_ENABLED
,XPATH_OP_RANGETO
#endif
} xmlXPathOp;
typedef enum {
AXIS_ANCESTOR = 1,
AXIS_ANCESTOR_OR_SELF,
AXIS_ATTRIBUTE,
AXIS_CHILD,
AXIS_DESCENDANT,
AXIS_DESCENDANT_OR_SELF,
AXIS_FOLLOWING,
AXIS_FOLLOWING_SIBLING,
AXIS_NAMESPACE,
AXIS_PARENT,
AXIS_PRECEDING,
AXIS_PRECEDING_SIBLING,
AXIS_SELF
} xmlXPathAxisVal;
typedef enum {
NODE_TEST_NONE = 0,
NODE_TEST_TYPE = 1,
NODE_TEST_PI = 2,
NODE_TEST_ALL = 3,
NODE_TEST_NS = 4,
NODE_TEST_NAME = 5
} xmlXPathTestVal;
typedef enum {
NODE_TYPE_NODE = 0,
NODE_TYPE_COMMENT = XML_COMMENT_NODE,
NODE_TYPE_TEXT = XML_TEXT_NODE,
NODE_TYPE_PI = XML_PI_NODE
} xmlXPathTypeVal;
typedef struct _xmlXPathStepOp xmlXPathStepOp;
typedef xmlXPathStepOp *xmlXPathStepOpPtr;
struct _xmlXPathStepOp {
xmlXPathOp op;
int ch1;
int ch2;
int value;
int value2;
int value3;
void *value4;
void *value5;
xmlXPathFunction cache;
void *cacheURI;
};
struct _xmlXPathCompExpr {
int nbStep;
int maxStep;
xmlXPathStepOp *steps;
int last;
xmlChar *expr;
xmlDictPtr dict;
#ifdef XPATH_STREAMING
xmlPatternPtr stream;
#endif
};
static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj);
static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj);
static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op, xmlNodePtr *first);
static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op,
int isPredicate);
static void
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name);
static xmlXPathCompExprPtr
xmlXPathNewCompExpr(void) {
xmlXPathCompExprPtr cur;
cur = (xmlXPathCompExprPtr) xmlMalloc(sizeof(xmlXPathCompExpr));
if (cur == NULL) {
xmlXPathErrMemory(NULL, "allocating component\n");
return(NULL);
}
memset(cur, 0, sizeof(xmlXPathCompExpr));
cur->maxStep = 10;
cur->nbStep = 0;
cur->steps = (xmlXPathStepOp *) xmlMalloc(cur->maxStep *
sizeof(xmlXPathStepOp));
if (cur->steps == NULL) {
xmlXPathErrMemory(NULL, "allocating steps\n");
xmlFree(cur);
return(NULL);
}
memset(cur->steps, 0, cur->maxStep * sizeof(xmlXPathStepOp));
cur->last = -1;
return(cur);
}
void
xmlXPathFreeCompExpr(xmlXPathCompExprPtr comp)
{
xmlXPathStepOpPtr op;
int i;
if (comp == NULL)
return;
if (comp->dict == NULL) {
for (i = 0; i < comp->nbStep; i++) {
op = &comp->steps[i];
if (op->value4 != NULL) {
if (op->op == XPATH_OP_VALUE)
xmlXPathFreeObject(op->value4);
else
xmlFree(op->value4);
}
if (op->value5 != NULL)
xmlFree(op->value5);
}
} else {
for (i = 0; i < comp->nbStep; i++) {
op = &comp->steps[i];
if (op->value4 != NULL) {
if (op->op == XPATH_OP_VALUE)
xmlXPathFreeObject(op->value4);
}
}
xmlDictFree(comp->dict);
}
if (comp->steps != NULL) {
xmlFree(comp->steps);
}
#ifdef XPATH_STREAMING
if (comp->stream != NULL) {
xmlFreePatternList(comp->stream);
}
#endif
if (comp->expr != NULL) {
xmlFree(comp->expr);
}
xmlFree(comp);
}
static int
xmlXPathCompExprAdd(xmlXPathParserContextPtr ctxt, int ch1, int ch2,
xmlXPathOp op, int value,
int value2, int value3, void *value4, void *value5) {
xmlXPathCompExprPtr comp = ctxt->comp;
if (comp->nbStep >= comp->maxStep) {
xmlXPathStepOp *real;
if (comp->maxStep >= XPATH_MAX_STEPS) {
xmlXPathPErrMemory(ctxt, "adding step\n");
return(-1);
}
comp->maxStep *= 2;
real = (xmlXPathStepOp *) xmlRealloc(comp->steps,
comp->maxStep * sizeof(xmlXPathStepOp));
if (real == NULL) {
comp->maxStep /= 2;
xmlXPathPErrMemory(ctxt, "adding step\n");
return(-1);
}
comp->steps = real;
}
comp->last = comp->nbStep;
comp->steps[comp->nbStep].ch1 = ch1;
comp->steps[comp->nbStep].ch2 = ch2;
comp->steps[comp->nbStep].op = op;
comp->steps[comp->nbStep].value = value;
comp->steps[comp->nbStep].value2 = value2;
comp->steps[comp->nbStep].value3 = value3;
if ((comp->dict != NULL) &&
((op == XPATH_OP_FUNCTION) || (op == XPATH_OP_VARIABLE) ||
(op == XPATH_OP_COLLECT))) {
if (value4 != NULL) {
comp->steps[comp->nbStep].value4 = (xmlChar *)
(void *)xmlDictLookup(comp->dict, value4, -1);
xmlFree(value4);
} else
comp->steps[comp->nbStep].value4 = NULL;
if (value5 != NULL) {
comp->steps[comp->nbStep].value5 = (xmlChar *)
(void *)xmlDictLookup(comp->dict, value5, -1);
xmlFree(value5);
} else
comp->steps[comp->nbStep].value5 = NULL;
} else {
comp->steps[comp->nbStep].value4 = value4;
comp->steps[comp->nbStep].value5 = value5;
}
comp->steps[comp->nbStep].cache = NULL;
return(comp->nbStep++);
}
static void
xmlXPathCompSwap(xmlXPathStepOpPtr op) {
int tmp;
#ifndef LIBXML_THREAD_ENABLED
if (xmlXPathDisableOptimizer)
return;
#endif
tmp = op->ch1;
op->ch1 = op->ch2;
op->ch2 = tmp;
}
#define PUSH_FULL_EXPR(op, op1, op2, val, val2, val3, val4, val5) \
xmlXPathCompExprAdd(ctxt, (op1), (op2), \
(op), (val), (val2), (val3), (val4), (val5))
#define PUSH_LONG_EXPR(op, val, val2, val3, val4, val5) \
xmlXPathCompExprAdd(ctxt, ctxt->comp->last, -1, \
(op), (val), (val2), (val3), (val4), (val5))
#define PUSH_LEAVE_EXPR(op, val, val2) \
xmlXPathCompExprAdd(ctxt, -1, -1, (op), (val), (val2), 0 ,NULL ,NULL)
#define PUSH_UNARY_EXPR(op, ch, val, val2) \
xmlXPathCompExprAdd(ctxt, (ch), -1, (op), (val), (val2), 0 ,NULL ,NULL)
#define PUSH_BINARY_EXPR(op, ch1, ch2, val, val2) \
xmlXPathCompExprAdd(ctxt, (ch1), (ch2), (op), \
(val), (val2), 0 ,NULL ,NULL)
#define XP_HAS_CACHE(c) ((c != NULL) && ((c)->cache != NULL))
typedef struct _xmlXPathContextCache xmlXPathContextCache;
typedef xmlXPathContextCache *xmlXPathContextCachePtr;
struct _xmlXPathContextCache {
xmlPointerListPtr nodesetObjs;
xmlPointerListPtr stringObjs;
xmlPointerListPtr booleanObjs;
xmlPointerListPtr numberObjs;
xmlPointerListPtr miscObjs;
int maxNodeset;
int maxString;
int maxBoolean;
int maxNumber;
int maxMisc;
};
#define STRANGE \
xmlGenericError(xmlGenericErrorContext, \
"Internal error at %s:%d\n", \
__FILE__, __LINE__);
#ifdef LIBXML_DEBUG_ENABLED
static void
xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
int i;
char shift[100];
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
if (cur == NULL) {
fprintf(output, "%s", shift);
fprintf(output, "Node is NULL !\n");
return;
}
if ((cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE)) {
fprintf(output, "%s", shift);
fprintf(output, " /\n");
} else if (cur->type == XML_ATTRIBUTE_NODE)
xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
else
xmlDebugDumpOneNode(output, cur, depth);
}
static void
xmlXPathDebugDumpNodeList(FILE *output, xmlNodePtr cur, int depth) {
xmlNodePtr tmp;
int i;
char shift[100];
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
if (cur == NULL) {
fprintf(output, "%s", shift);
fprintf(output, "Node is NULL !\n");
return;
}
while (cur != NULL) {
tmp = cur;
cur = cur->next;
xmlDebugDumpOneNode(output, tmp, depth);
}
}
static void
xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
int i;
char shift[100];
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
if (cur == NULL) {
fprintf(output, "%s", shift);
fprintf(output, "NodeSet is NULL !\n");
return;
}
if (cur != NULL) {
fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
for (i = 0;i < cur->nodeNr;i++) {
fprintf(output, "%s", shift);
fprintf(output, "%d", i + 1);
xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
}
}
}
static void
xmlXPathDebugDumpValueTree(FILE *output, xmlNodeSetPtr cur, int depth) {
int i;
char shift[100];
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
if ((cur == NULL) || (cur->nodeNr == 0) || (cur->nodeTab[0] == NULL)) {
fprintf(output, "%s", shift);
fprintf(output, "Value Tree is NULL !\n");
return;
}
fprintf(output, "%s", shift);
fprintf(output, "%d", i + 1);
xmlXPathDebugDumpNodeList(output, cur->nodeTab[0]->children, depth + 1);
}
#if defined(LIBXML_XPTR_LOCS_ENABLED)
static void
xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
int i;
char shift[100];
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
if (cur == NULL) {
fprintf(output, "%s", shift);
fprintf(output, "LocationSet is NULL !\n");
return;
}
for (i = 0;i < cur->locNr;i++) {
fprintf(output, "%s", shift);
fprintf(output, "%d : ", i + 1);
xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
}
}
#endif
void
xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
int i;
char shift[100];
if (output == NULL) return;
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
fprintf(output, "%s", shift);
if (cur == NULL) {
fprintf(output, "Object is empty (NULL)\n");
return;
}
switch(cur->type) {
case XPATH_UNDEFINED:
fprintf(output, "Object is uninitialized\n");
break;
case XPATH_NODESET:
fprintf(output, "Object is a Node Set :\n");
xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
break;
case XPATH_XSLT_TREE:
fprintf(output, "Object is an XSLT value tree :\n");
xmlXPathDebugDumpValueTree(output, cur->nodesetval, depth);
break;
case XPATH_BOOLEAN:
fprintf(output, "Object is a Boolean : ");
if (cur->boolval) fprintf(output, "true\n");
else fprintf(output, "false\n");
break;
case XPATH_NUMBER:
switch (xmlXPathIsInf(cur->floatval)) {
case 1:
fprintf(output, "Object is a number : Infinity\n");
break;
case -1:
fprintf(output, "Object is a number : -Infinity\n");
break;
default:
if (xmlXPathIsNaN(cur->floatval)) {
fprintf(output, "Object is a number : NaN\n");
} else if (cur->floatval == 0) {
fprintf(output, "Object is a number : 0\n");
} else {
fprintf(output, "Object is a number : %0g\n", cur->floatval);
}
}
break;
case XPATH_STRING:
fprintf(output, "Object is a string : ");
xmlDebugDumpString(output, cur->stringval);
fprintf(output, "\n");
break;
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
fprintf(output, "Object is a point : index %d in node", cur->index);
xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
fprintf(output, "\n");
break;
case XPATH_RANGE:
if ((cur->user2 == NULL) ||
((cur->user2 == cur->user) && (cur->index == cur->index2))) {
fprintf(output, "Object is a collapsed range :\n");
fprintf(output, "%s", shift);
if (cur->index >= 0)
fprintf(output, "index %d in ", cur->index);
fprintf(output, "node\n");
xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
depth + 1);
} else {
fprintf(output, "Object is a range :\n");
fprintf(output, "%s", shift);
fprintf(output, "From ");
if (cur->index >= 0)
fprintf(output, "index %d in ", cur->index);
fprintf(output, "node\n");
xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
depth + 1);
fprintf(output, "%s", shift);
fprintf(output, "To ");
if (cur->index2 >= 0)
fprintf(output, "index %d in ", cur->index2);
fprintf(output, "node\n");
xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
depth + 1);
fprintf(output, "\n");
}
break;
case XPATH_LOCATIONSET:
fprintf(output, "Object is a Location Set:\n");
xmlXPathDebugDumpLocationSet(output,
(xmlLocationSetPtr) cur->user, depth);
break;
#endif
case XPATH_USERS:
fprintf(output, "Object is user defined\n");
break;
}
}
static void
xmlXPathDebugDumpStepOp(FILE *output, xmlXPathCompExprPtr comp,
xmlXPathStepOpPtr op, int depth) {
int i;
char shift[100];
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
fprintf(output, "%s", shift);
if (op == NULL) {
fprintf(output, "Step is NULL\n");
return;
}
switch (op->op) {
case XPATH_OP_END:
fprintf(output, "END"); break;
case XPATH_OP_AND:
fprintf(output, "AND"); break;
case XPATH_OP_OR:
fprintf(output, "OR"); break;
case XPATH_OP_EQUAL:
if (op->value)
fprintf(output, "EQUAL =");
else
fprintf(output, "EQUAL !=");
break;
case XPATH_OP_CMP:
if (op->value)
fprintf(output, "CMP <");
else
fprintf(output, "CMP >");
if (!op->value2)
fprintf(output, "=");
break;
case XPATH_OP_PLUS:
if (op->value == 0)
fprintf(output, "PLUS -");
else if (op->value == 1)
fprintf(output, "PLUS +");
else if (op->value == 2)
fprintf(output, "PLUS unary -");
else if (op->value == 3)
fprintf(output, "PLUS unary - -");
break;
case XPATH_OP_MULT:
if (op->value == 0)
fprintf(output, "MULT *");
else if (op->value == 1)
fprintf(output, "MULT div");
else
fprintf(output, "MULT mod");
break;
case XPATH_OP_UNION:
fprintf(output, "UNION"); break;
case XPATH_OP_ROOT:
fprintf(output, "ROOT"); break;
case XPATH_OP_NODE:
fprintf(output, "NODE"); break;
case XPATH_OP_SORT:
fprintf(output, "SORT"); break;
case XPATH_OP_COLLECT: {
xmlXPathAxisVal axis = (xmlXPathAxisVal)op->value;
xmlXPathTestVal test = (xmlXPathTestVal)op->value2;
xmlXPathTypeVal type = (xmlXPathTypeVal)op->value3;
const xmlChar *prefix = op->value4;
const xmlChar *name = op->value5;
fprintf(output, "COLLECT ");
switch (axis) {
case AXIS_ANCESTOR:
fprintf(output, " 'ancestors' "); break;
case AXIS_ANCESTOR_OR_SELF:
fprintf(output, " 'ancestors-or-self' "); break;
case AXIS_ATTRIBUTE:
fprintf(output, " 'attributes' "); break;
case AXIS_CHILD:
fprintf(output, " 'child' "); break;
case AXIS_DESCENDANT:
fprintf(output, " 'descendant' "); break;
case AXIS_DESCENDANT_OR_SELF:
fprintf(output, " 'descendant-or-self' "); break;
case AXIS_FOLLOWING:
fprintf(output, " 'following' "); break;
case AXIS_FOLLOWING_SIBLING:
fprintf(output, " 'following-siblings' "); break;
case AXIS_NAMESPACE:
fprintf(output, " 'namespace' "); break;
case AXIS_PARENT:
fprintf(output, " 'parent' "); break;
case AXIS_PRECEDING:
fprintf(output, " 'preceding' "); break;
case AXIS_PRECEDING_SIBLING:
fprintf(output, " 'preceding-sibling' "); break;
case AXIS_SELF:
fprintf(output, " 'self' "); break;
}
switch (test) {
case NODE_TEST_NONE:
fprintf(output, "'none' "); break;
case NODE_TEST_TYPE:
fprintf(output, "'type' "); break;
case NODE_TEST_PI:
fprintf(output, "'PI' "); break;
case NODE_TEST_ALL:
fprintf(output, "'all' "); break;
case NODE_TEST_NS:
fprintf(output, "'namespace' "); break;
case NODE_TEST_NAME:
fprintf(output, "'name' "); break;
}
switch (type) {
case NODE_TYPE_NODE:
fprintf(output, "'node' "); break;
case NODE_TYPE_COMMENT:
fprintf(output, "'comment' "); break;
case NODE_TYPE_TEXT:
fprintf(output, "'text' "); break;
case NODE_TYPE_PI:
fprintf(output, "'PI' "); break;
}
if (prefix != NULL)
fprintf(output, "%s:", prefix);
if (name != NULL)
fprintf(output, "%s", (const char *) name);
break;
}
case XPATH_OP_VALUE: {
xmlXPathObjectPtr object = (xmlXPathObjectPtr) op->value4;
fprintf(output, "ELEM ");
xmlXPathDebugDumpObject(output, object, 0);
goto finish;
}
case XPATH_OP_VARIABLE: {
const xmlChar *prefix = op->value5;
const xmlChar *name = op->value4;
if (prefix != NULL)
fprintf(output, "VARIABLE %s:%s", prefix, name);
else
fprintf(output, "VARIABLE %s", name);
break;
}
case XPATH_OP_FUNCTION: {
int nbargs = op->value;
const xmlChar *prefix = op->value5;
const xmlChar *name = op->value4;
if (prefix != NULL)
fprintf(output, "FUNCTION %s:%s(%d args)",
prefix, name, nbargs);
else
fprintf(output, "FUNCTION %s(%d args)", name, nbargs);
break;
}
case XPATH_OP_ARG: fprintf(output, "ARG"); break;
case XPATH_OP_PREDICATE: fprintf(output, "PREDICATE"); break;
case XPATH_OP_FILTER: fprintf(output, "FILTER"); break;
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_OP_RANGETO: fprintf(output, "RANGETO"); break;
#endif
default:
fprintf(output, "UNKNOWN %d\n", op->op); return;
}
fprintf(output, "\n");
finish:
if (op->ch1 >= 0)
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch1], depth + 1);
if (op->ch2 >= 0)
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[op->ch2], depth + 1);
}
void
xmlXPathDebugDumpCompExpr(FILE *output, xmlXPathCompExprPtr comp,
int depth) {
int i;
char shift[100];
if ((output == NULL) || (comp == NULL)) return;
for (i = 0;((i < depth) && (i < 25));i++)
shift[2 * i] = shift[2 * i + 1] = ' ';
shift[2 * i] = shift[2 * i + 1] = 0;
fprintf(output, "%s", shift);
#ifdef XPATH_STREAMING
if (comp->stream) {
fprintf(output, "Streaming Expression\n");
} else
#endif
{
fprintf(output, "Compiled Expression : %d elements\n",
comp->nbStep);
i = comp->last;
xmlXPathDebugDumpStepOp(output, comp, &comp->steps[i], depth + 1);
}
}
#endif
static xmlXPathContextCachePtr
xmlXPathNewCache(void)
{
xmlXPathContextCachePtr ret;
ret = (xmlXPathContextCachePtr) xmlMalloc(sizeof(xmlXPathContextCache));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating object cache\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathContextCache));
ret->maxNodeset = 100;
ret->maxString = 100;
ret->maxBoolean = 100;
ret->maxNumber = 100;
ret->maxMisc = 100;
return(ret);
}
static void
xmlXPathCacheFreeObjectList(xmlPointerListPtr list)
{
int i;
xmlXPathObjectPtr obj;
if (list == NULL)
return;
for (i = 0; i < list->number; i++) {
obj = list->items[i];
if (obj->nodesetval != NULL) {
if (obj->nodesetval->nodeTab != NULL)
xmlFree(obj->nodesetval->nodeTab);
xmlFree(obj->nodesetval);
}
xmlFree(obj);
}
xmlPointerListFree(list);
}
static void
xmlXPathFreeCache(xmlXPathContextCachePtr cache)
{
if (cache == NULL)
return;
if (cache->nodesetObjs)
xmlXPathCacheFreeObjectList(cache->nodesetObjs);
if (cache->stringObjs)
xmlXPathCacheFreeObjectList(cache->stringObjs);
if (cache->booleanObjs)
xmlXPathCacheFreeObjectList(cache->booleanObjs);
if (cache->numberObjs)
xmlXPathCacheFreeObjectList(cache->numberObjs);
if (cache->miscObjs)
xmlXPathCacheFreeObjectList(cache->miscObjs);
xmlFree(cache);
}
int
xmlXPathContextSetCache(xmlXPathContextPtr ctxt,
int active,
int value,
int options)
{
if (ctxt == NULL)
return(-1);
if (active) {
xmlXPathContextCachePtr cache;
if (ctxt->cache == NULL) {
ctxt->cache = xmlXPathNewCache();
if (ctxt->cache == NULL)
return(-1);
}
cache = (xmlXPathContextCachePtr) ctxt->cache;
if (options == 0) {
if (value < 0)
value = 100;
cache->maxNodeset = value;
cache->maxString = value;
cache->maxNumber = value;
cache->maxBoolean = value;
cache->maxMisc = value;
}
} else if (ctxt->cache != NULL) {
xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
ctxt->cache = NULL;
}
return(0);
}
static xmlXPathObjectPtr
xmlXPathCacheWrapNodeSet(xmlXPathContextPtr ctxt, xmlNodeSetPtr val)
{
if ((ctxt != NULL) && (ctxt->cache != NULL)) {
xmlXPathContextCachePtr cache =
(xmlXPathContextCachePtr) ctxt->cache;
if ((cache->miscObjs != NULL) &&
(cache->miscObjs->number != 0))
{
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr)
cache->miscObjs->items[--cache->miscObjs->number];
ret->type = XPATH_NODESET;
ret->nodesetval = val;
return(ret);
}
}
return(xmlXPathWrapNodeSet(val));
}
static xmlXPathObjectPtr
xmlXPathCacheWrapString(xmlXPathContextPtr ctxt, xmlChar *val)
{
if ((ctxt != NULL) && (ctxt->cache != NULL)) {
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
if ((cache->stringObjs != NULL) &&
(cache->stringObjs->number != 0))
{
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr)
cache->stringObjs->items[--cache->stringObjs->number];
ret->type = XPATH_STRING;
ret->stringval = val;
return(ret);
} else if ((cache->miscObjs != NULL) &&
(cache->miscObjs->number != 0))
{
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr)
cache->miscObjs->items[--cache->miscObjs->number];
ret->type = XPATH_STRING;
ret->stringval = val;
return(ret);
}
}
return(xmlXPathWrapString(val));
}
static xmlXPathObjectPtr
xmlXPathCacheNewNodeSet(xmlXPathContextPtr ctxt, xmlNodePtr val)
{
if ((ctxt != NULL) && (ctxt->cache)) {
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
if ((cache->nodesetObjs != NULL) &&
(cache->nodesetObjs->number != 0))
{
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr)
cache->nodesetObjs->items[--cache->nodesetObjs->number];
ret->type = XPATH_NODESET;
ret->boolval = 0;
if (val) {
if ((ret->nodesetval->nodeMax == 0) ||
(val->type == XML_NAMESPACE_DECL))
{
xmlXPathNodeSetAddUnique(ret->nodesetval, val);
} else {
ret->nodesetval->nodeTab[0] = val;
ret->nodesetval->nodeNr = 1;
}
}
return(ret);
} else if ((cache->miscObjs != NULL) &&
(cache->miscObjs->number != 0))
{
xmlXPathObjectPtr ret;
xmlNodeSetPtr set;
set = xmlXPathNodeSetCreate(val);
if (set == NULL) {
ctxt->lastError.domain = XML_FROM_XPATH;
ctxt->lastError.code = XML_ERR_NO_MEMORY;
return(NULL);
}
ret = (xmlXPathObjectPtr)
cache->miscObjs->items[--cache->miscObjs->number];
ret->type = XPATH_NODESET;
ret->boolval = 0;
ret->nodesetval = set;
return(ret);
}
}
return(xmlXPathNewNodeSet(val));
}
static xmlXPathObjectPtr
xmlXPathCacheNewString(xmlXPathContextPtr ctxt, const xmlChar *val)
{
if ((ctxt != NULL) && (ctxt->cache)) {
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
if ((cache->stringObjs != NULL) &&
(cache->stringObjs->number != 0))
{
xmlXPathObjectPtr ret;
xmlChar *copy;
if (val == NULL)
val = BAD_CAST "";
copy = xmlStrdup(val);
if (copy == NULL) {
xmlXPathErrMemory(ctxt, NULL);
return(NULL);
}
ret = (xmlXPathObjectPtr)
cache->stringObjs->items[--cache->stringObjs->number];
ret->type = XPATH_STRING;
ret->stringval = copy;
return(ret);
} else if ((cache->miscObjs != NULL) &&
(cache->miscObjs->number != 0))
{
xmlXPathObjectPtr ret;
xmlChar *copy;
if (val == NULL)
val = BAD_CAST "";
copy = xmlStrdup(val);
if (copy == NULL) {
xmlXPathErrMemory(ctxt, NULL);
return(NULL);
}
ret = (xmlXPathObjectPtr)
cache->miscObjs->items[--cache->miscObjs->number];
ret->type = XPATH_STRING;
ret->stringval = copy;
return(ret);
}
}
return(xmlXPathNewString(val));
}
static xmlXPathObjectPtr
xmlXPathCacheNewCString(xmlXPathContextPtr ctxt, const char *val)
{
return xmlXPathCacheNewString(ctxt, BAD_CAST val);
}
static xmlXPathObjectPtr
xmlXPathCacheNewBoolean(xmlXPathContextPtr ctxt, int val)
{
if ((ctxt != NULL) && (ctxt->cache)) {
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
if ((cache->booleanObjs != NULL) &&
(cache->booleanObjs->number != 0))
{
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr)
cache->booleanObjs->items[--cache->booleanObjs->number];
ret->type = XPATH_BOOLEAN;
ret->boolval = (val != 0);
return(ret);
} else if ((cache->miscObjs != NULL) &&
(cache->miscObjs->number != 0))
{
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr)
cache->miscObjs->items[--cache->miscObjs->number];
ret->type = XPATH_BOOLEAN;
ret->boolval = (val != 0);
return(ret);
}
}
return(xmlXPathNewBoolean(val));
}
static xmlXPathObjectPtr
xmlXPathCacheNewFloat(xmlXPathContextPtr ctxt, double val)
{
if ((ctxt != NULL) && (ctxt->cache)) {
xmlXPathContextCachePtr cache = (xmlXPathContextCachePtr) ctxt->cache;
if ((cache->numberObjs != NULL) &&
(cache->numberObjs->number != 0))
{
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr)
cache->numberObjs->items[--cache->numberObjs->number];
ret->type = XPATH_NUMBER;
ret->floatval = val;
return(ret);
} else if ((cache->miscObjs != NULL) &&
(cache->miscObjs->number != 0))
{
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr)
cache->miscObjs->items[--cache->miscObjs->number];
ret->type = XPATH_NUMBER;
ret->floatval = val;
return(ret);
}
}
return(xmlXPathNewFloat(val));
}
static xmlXPathObjectPtr
xmlXPathCacheConvertString(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
xmlChar *res = NULL;
if (val == NULL)
return(xmlXPathCacheNewCString(ctxt, ""));
switch (val->type) {
case XPATH_UNDEFINED:
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
res = xmlXPathCastNodeSetToString(val->nodesetval);
break;
case XPATH_STRING:
return(val);
case XPATH_BOOLEAN:
res = xmlXPathCastBooleanToString(val->boolval);
break;
case XPATH_NUMBER:
res = xmlXPathCastNumberToString(val->floatval);
break;
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO;
break;
}
xmlXPathReleaseObject(ctxt, val);
if (res == NULL)
return(xmlXPathCacheNewCString(ctxt, ""));
return(xmlXPathCacheWrapString(ctxt, res));
}
static xmlXPathObjectPtr
xmlXPathCacheObjectCopy(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val)
{
if (val == NULL)
return(NULL);
if (XP_HAS_CACHE(ctxt)) {
switch (val->type) {
case XPATH_NODESET:
return(xmlXPathCacheWrapNodeSet(ctxt,
xmlXPathNodeSetMerge(NULL, val->nodesetval)));
case XPATH_STRING:
return(xmlXPathCacheNewString(ctxt, val->stringval));
case XPATH_BOOLEAN:
return(xmlXPathCacheNewBoolean(ctxt, val->boolval));
case XPATH_NUMBER:
return(xmlXPathCacheNewFloat(ctxt, val->floatval));
default:
break;
}
}
return(xmlXPathObjectCopy(val));
}
static xmlXPathObjectPtr
xmlXPathCacheConvertBoolean(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
xmlXPathObjectPtr ret;
if (val == NULL)
return(xmlXPathCacheNewBoolean(ctxt, 0));
if (val->type == XPATH_BOOLEAN)
return(val);
ret = xmlXPathCacheNewBoolean(ctxt, xmlXPathCastToBoolean(val));
xmlXPathReleaseObject(ctxt, val);
return(ret);
}
static xmlXPathObjectPtr
xmlXPathCacheConvertNumber(xmlXPathContextPtr ctxt, xmlXPathObjectPtr val) {
xmlXPathObjectPtr ret;
if (val == NULL)
return(xmlXPathCacheNewFloat(ctxt, 0.0));
if (val->type == XPATH_NUMBER)
return(val);
ret = xmlXPathCacheNewFloat(ctxt, xmlXPathCastToNumber(val));
xmlXPathReleaseObject(ctxt, val);
return(ret);
}
xmlXPathObjectPtr
valuePop(xmlXPathParserContextPtr ctxt)
{
xmlXPathObjectPtr ret;
if ((ctxt == NULL) || (ctxt->valueNr <= 0))
return (NULL);
ctxt->valueNr--;
if (ctxt->valueNr > 0)
ctxt->value = ctxt->valueTab[ctxt->valueNr - 1];
else
ctxt->value = NULL;
ret = ctxt->valueTab[ctxt->valueNr];
ctxt->valueTab[ctxt->valueNr] = NULL;
return (ret);
}
int
valuePush(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr value)
{
if (ctxt == NULL) return(-1);
if (value == NULL) {
ctxt->error = XPATH_MEMORY_ERROR;
return(-1);
}
if (ctxt->valueNr >= ctxt->valueMax) {
xmlXPathObjectPtr *tmp;
if (ctxt->valueMax >= XPATH_MAX_STACK_DEPTH) {
xmlXPathPErrMemory(ctxt, "XPath stack depth limit reached\n");
xmlXPathFreeObject(value);
return (-1);
}
tmp = (xmlXPathObjectPtr *) xmlRealloc(ctxt->valueTab,
2 * ctxt->valueMax *
sizeof(ctxt->valueTab[0]));
if (tmp == NULL) {
xmlXPathPErrMemory(ctxt, "pushing value\n");
xmlXPathFreeObject(value);
return (-1);
}
ctxt->valueMax *= 2;
ctxt->valueTab = tmp;
}
ctxt->valueTab[ctxt->valueNr] = value;
ctxt->value = value;
return (ctxt->valueNr++);
}
int
xmlXPathPopBoolean (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
int ret;
obj = valuePop(ctxt);
if (obj == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(0);
}
if (obj->type != XPATH_BOOLEAN)
ret = xmlXPathCastToBoolean(obj);
else
ret = obj->boolval;
xmlXPathReleaseObject(ctxt->context, obj);
return(ret);
}
double
xmlXPathPopNumber (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
double ret;
obj = valuePop(ctxt);
if (obj == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(0);
}
if (obj->type != XPATH_NUMBER)
ret = xmlXPathCastToNumber(obj);
else
ret = obj->floatval;
xmlXPathReleaseObject(ctxt->context, obj);
return(ret);
}
xmlChar *
xmlXPathPopString (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
xmlChar * ret;
obj = valuePop(ctxt);
if (obj == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(NULL);
}
ret = xmlXPathCastToString(obj);
if (obj->stringval == ret)
obj->stringval = NULL;
xmlXPathReleaseObject(ctxt->context, obj);
return(ret);
}
xmlNodeSetPtr
xmlXPathPopNodeSet (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
xmlNodeSetPtr ret;
if (ctxt == NULL) return(NULL);
if (ctxt->value == NULL) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(NULL);
}
if (!xmlXPathStackIsNodeSet(ctxt)) {
xmlXPathSetTypeError(ctxt);
return(NULL);
}
obj = valuePop(ctxt);
ret = obj->nodesetval;
#if 0
if (obj->boolval && obj->user != NULL)
xmlFreeNodeList((xmlNodePtr) obj->user);
#endif
obj->nodesetval = NULL;
xmlXPathReleaseObject(ctxt->context, obj);
return(ret);
}
void *
xmlXPathPopExternal (xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr obj;
void * ret;
if ((ctxt == NULL) || (ctxt->value == NULL)) {
xmlXPathSetError(ctxt, XPATH_INVALID_OPERAND);
return(NULL);
}
if (ctxt->value->type != XPATH_USERS) {
xmlXPathSetTypeError(ctxt);
return(NULL);
}
obj = valuePop(ctxt);
ret = obj->user;
obj->user = NULL;
xmlXPathReleaseObject(ctxt->context, obj);
return(ret);
}
#define CUR (*ctxt->cur)
#define SKIP(val) ctxt->cur += (val)
#define NXT(val) ctxt->cur[(val)]
#define CUR_PTR ctxt->cur
#define CUR_CHAR(l) xmlXPathCurrentChar(ctxt, &l)
#define COPY_BUF(l,b,i,v) \
if (l == 1) b[i++] = v; \
else i += xmlCopyChar(l,&b[i],v)
#define NEXTL(l) ctxt->cur += l
#define SKIP_BLANKS \
while (IS_BLANK_CH(*(ctxt->cur))) NEXT
#define CURRENT (*ctxt->cur)
#define NEXT ((*ctxt->cur) ? ctxt->cur++: ctxt->cur)
#ifndef DBL_DIG
#define DBL_DIG 16
#endif
#ifndef DBL_EPSILON
#define DBL_EPSILON 1E-9
#endif
#define UPPER_DOUBLE 1E9
#define LOWER_DOUBLE 1E-5
#define LOWER_DOUBLE_EXP 5
#define INTEGER_DIGITS DBL_DIG
#define FRACTION_DIGITS (DBL_DIG + 1 + (LOWER_DOUBLE_EXP))
#define EXPONENT_DIGITS (3 + 2)
static void
xmlXPathFormatNumber(double number, char buffer[], int buffersize)
{
switch (xmlXPathIsInf(number)) {
case 1:
if (buffersize > (int)sizeof("Infinity"))
snprintf(buffer, buffersize, "Infinity");
break;
case -1:
if (buffersize > (int)sizeof("-Infinity"))
snprintf(buffer, buffersize, "-Infinity");
break;
default:
if (xmlXPathIsNaN(number)) {
if (buffersize > (int)sizeof("NaN"))
snprintf(buffer, buffersize, "NaN");
} else if (number == 0) {
snprintf(buffer, buffersize, "0");
} else if ((number > INT_MIN) && (number < INT_MAX) &&
(number == (int) number)) {
char work[30];
char *ptr, *cur;
int value = (int) number;
ptr = &buffer[0];
if (value == 0) {
*ptr++ = '0';
} else {
snprintf(work, 29, "%d", value);
cur = &work[0];
while ((*cur) && (ptr - buffer < buffersize)) {
*ptr++ = *cur++;
}
}
if (ptr - buffer < buffersize) {
*ptr = 0;
} else if (buffersize > 0) {
ptr--;
*ptr = 0;
}
} else {
char work[DBL_DIG + EXPONENT_DIGITS + 3 + LOWER_DOUBLE_EXP];
int integer_place, fraction_place;
char *ptr;
char *after_fraction;
double absolute_value;
int size;
absolute_value = fabs(number);
if ( ((absolute_value > UPPER_DOUBLE) ||
(absolute_value < LOWER_DOUBLE)) &&
(absolute_value != 0.0) ) {
integer_place = DBL_DIG + EXPONENT_DIGITS + 1;
fraction_place = DBL_DIG - 1;
size = snprintf(work, sizeof(work),"%*.*e",
integer_place, fraction_place, number);
while ((size > 0) && (work[size] != 'e')) size--;
}
else {
if (absolute_value > 0.0) {
integer_place = (int)log10(absolute_value);
if (integer_place > 0)
fraction_place = DBL_DIG - integer_place - 1;
else
fraction_place = DBL_DIG - integer_place;
} else {
fraction_place = 1;
}
size = snprintf(work, sizeof(work), "%0.*f",
fraction_place, number);
}
while (work[0] == ' ') {
for (ptr = &work[0];(ptr[0] = ptr[1]);ptr++);
size--;
}
after_fraction = work + size;
ptr = after_fraction;
while (*(--ptr) == '0')
;
if (*ptr != '.')
ptr++;
while ((*ptr++ = *after_fraction++) != 0);
size = strlen(work) + 1;
if (size > buffersize) {
#if 0
work[buffersize - 1] = 0;
#endif
size = buffersize;
}
memmove(buffer, work, size);
}
break;
}
}
long
xmlXPathOrderDocElems(xmlDocPtr doc) {
ptrdiff_t 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);
}
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);
if (node1 == node2)
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) {
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);
if ((node1->type == XML_ELEMENT_NODE) &&
(node2->type == XML_ELEMENT_NODE) &&
(0 > (ptrdiff_t) node1->content) &&
(0 > (ptrdiff_t) node2->content) &&
(node1->doc == node2->doc)) {
ptrdiff_t l1, l2;
l1 = -((ptrdiff_t) node1->content);
l2 = -((ptrdiff_t) node2->content);
if (l1 < l2)
return(1);
if (l1 > l2)
return(-1);
}
for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
if (cur->parent == node1)
return(1);
depth2++;
}
root = cur;
for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
if (cur->parent == node2)
return(-1);
depth1++;
}
if (root != cur) {
return(-2);
}
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;
if ((node1 == NULL) || (node2 == NULL))
return(-2);
}
if (node1 == node2->prev)
return(1);
if (node1 == node2->next)
return(-1);
if ((node1->type == XML_ELEMENT_NODE) &&
(node2->type == XML_ELEMENT_NODE) &&
(0 > (ptrdiff_t) node1->content) &&
(0 > (ptrdiff_t) node2->content) &&
(node1->doc == node2->doc)) {
ptrdiff_t l1, l2;
l1 = -((ptrdiff_t) node1->content);
l2 = -((ptrdiff_t) 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);
}
void
xmlXPathNodeSetSort(xmlNodeSetPtr set) {
#ifndef WITH_TIM_SORT
int i, j, incr, len;
xmlNodePtr tmp;
#endif
if (set == NULL)
return;
#ifndef WITH_TIM_SORT
len = set->nodeNr;
for (incr = len / 2; incr > 0; incr /= 2) {
for (i = incr; i < len; i++) {
j = i - incr;
while (j >= 0) {
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
if (xmlXPathCmpNodesExt(set->nodeTab[j],
set->nodeTab[j + incr]) == -1)
#else
if (xmlXPathCmpNodes(set->nodeTab[j],
set->nodeTab[j + incr]) == -1)
#endif
{
tmp = set->nodeTab[j];
set->nodeTab[j] = set->nodeTab[j + incr];
set->nodeTab[j + incr] = tmp;
j -= incr;
} else
break;
}
}
}
#else
libxml_domnode_tim_sort(set->nodeTab, set->nodeNr);
#endif
}
#define XML_NODESET_DEFAULT 10
static xmlNodePtr
xmlXPathNodeSetDupNs(xmlNodePtr node, xmlNsPtr ns) {
xmlNsPtr cur;
if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
return(NULL);
if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
return((xmlNodePtr) ns);
cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
if (cur == NULL) {
xmlXPathErrMemory(NULL, "duplicating namespace\n");
return(NULL);
}
memset(cur, 0, sizeof(xmlNs));
cur->type = XML_NAMESPACE_DECL;
if (ns->href != NULL)
cur->href = xmlStrdup(ns->href);
if (ns->prefix != NULL)
cur->prefix = xmlStrdup(ns->prefix);
cur->next = (xmlNsPtr) node;
return((xmlNodePtr) cur);
}
void
xmlXPathNodeSetFreeNs(xmlNsPtr ns) {
if ((ns == NULL) || (ns->type != XML_NAMESPACE_DECL))
return;
if ((ns->next != NULL) && (ns->next->type != XML_NAMESPACE_DECL)) {
if (ns->href != NULL)
xmlFree((xmlChar *)ns->href);
if (ns->prefix != NULL)
xmlFree((xmlChar *)ns->prefix);
xmlFree(ns);
}
}
xmlNodeSetPtr
xmlXPathNodeSetCreate(xmlNodePtr val) {
xmlNodeSetPtr ret;
ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating nodeset\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlNodeSet));
if (val != NULL) {
ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
sizeof(xmlNodePtr));
if (ret->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "creating nodeset\n");
xmlFree(ret);
return(NULL);
}
memset(ret->nodeTab, 0 ,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
ret->nodeMax = XML_NODESET_DEFAULT;
if (val->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) val;
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
if (nsNode == NULL) {
xmlXPathFreeNodeSet(ret);
return(NULL);
}
ret->nodeTab[ret->nodeNr++] = nsNode;
} else
ret->nodeTab[ret->nodeNr++] = val;
}
return(ret);
}
int
xmlXPathNodeSetContains (xmlNodeSetPtr cur, xmlNodePtr val) {
int i;
if ((cur == NULL) || (val == NULL)) return(0);
if (val->type == XML_NAMESPACE_DECL) {
for (i = 0; i < cur->nodeNr; i++) {
if (cur->nodeTab[i]->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns1, ns2;
ns1 = (xmlNsPtr) val;
ns2 = (xmlNsPtr) cur->nodeTab[i];
if (ns1 == ns2)
return(1);
if ((ns1->next != NULL) && (ns2->next == ns1->next) &&
(xmlStrEqual(ns1->prefix, ns2->prefix)))
return(1);
}
}
} else {
for (i = 0; i < cur->nodeNr; i++) {
if (cur->nodeTab[i] == val)
return(1);
}
}
return(0);
}
int
xmlXPathNodeSetAddNs(xmlNodeSetPtr cur, xmlNodePtr node, xmlNsPtr ns) {
int i;
xmlNodePtr nsNode;
if ((cur == NULL) || (ns == NULL) || (node == NULL) ||
(ns->type != XML_NAMESPACE_DECL) ||
(node->type != XML_ELEMENT_NODE))
return(-1);
for (i = 0;i < cur->nodeNr;i++) {
if ((cur->nodeTab[i] != NULL) &&
(cur->nodeTab[i]->type == XML_NAMESPACE_DECL) &&
(((xmlNsPtr)cur->nodeTab[i])->next == (xmlNsPtr) node) &&
(xmlStrEqual(ns->prefix, ((xmlNsPtr)cur->nodeTab[i])->prefix)))
return(0);
}
if (cur->nodeMax == 0) {
cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
sizeof(xmlNodePtr));
if (cur->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "growing nodeset\n");
return(-1);
}
memset(cur->nodeTab, 0 ,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
cur->nodeMax = XML_NODESET_DEFAULT;
} 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(-1);
}
cur->nodeMax *= 2;
cur->nodeTab = temp;
}
nsNode = xmlXPathNodeSetDupNs(node, ns);
if(nsNode == NULL)
return(-1);
cur->nodeTab[cur->nodeNr++] = nsNode;
return(0);
}
int
xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
int i;
if ((cur == NULL) || (val == NULL)) return(-1);
for (i = 0;i < cur->nodeNr;i++)
if (cur->nodeTab[i] == val) return(0);
if (cur->nodeMax == 0) {
cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
sizeof(xmlNodePtr));
if (cur->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "growing nodeset\n");
return(-1);
}
memset(cur->nodeTab, 0 ,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
cur->nodeMax = XML_NODESET_DEFAULT;
} 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(-1);
}
cur->nodeMax *= 2;
cur->nodeTab = temp;
}
if (val->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) val;
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
if (nsNode == NULL)
return(-1);
cur->nodeTab[cur->nodeNr++] = nsNode;
} else
cur->nodeTab[cur->nodeNr++] = val;
return(0);
}
int
xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
if ((cur == NULL) || (val == NULL)) return(-1);
if (cur->nodeMax == 0) {
cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
sizeof(xmlNodePtr));
if (cur->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "growing nodeset\n");
return(-1);
}
memset(cur->nodeTab, 0 ,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
cur->nodeMax = XML_NODESET_DEFAULT;
} 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(-1);
}
cur->nodeTab = temp;
cur->nodeMax *= 2;
}
if (val->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) val;
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
if (nsNode == NULL)
return(-1);
cur->nodeTab[cur->nodeNr++] = nsNode;
} else
cur->nodeTab[cur->nodeNr++] = val;
return(0);
}
xmlNodeSetPtr
xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
int i, j, initNr, skip;
xmlNodePtr n1, n2;
if (val2 == NULL) return(val1);
if (val1 == NULL) {
val1 = xmlXPathNodeSetCreate(NULL);
if (val1 == NULL)
return (NULL);
}
initNr = val1->nodeNr;
for (i = 0;i < val2->nodeNr;i++) {
n2 = val2->nodeTab[i];
skip = 0;
for (j = 0; j < initNr; j++) {
n1 = val1->nodeTab[j];
if (n1 == n2) {
skip = 1;
break;
} else if ((n1->type == XML_NAMESPACE_DECL) &&
(n2->type == XML_NAMESPACE_DECL)) {
if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
(xmlStrEqual(((xmlNsPtr) n1)->prefix,
((xmlNsPtr) n2)->prefix)))
{
skip = 1;
break;
}
}
}
if (skip)
continue;
if (val1->nodeMax == 0) {
val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
sizeof(xmlNodePtr));
if (val1->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
goto error;
}
memset(val1->nodeTab, 0 ,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
val1->nodeMax = XML_NODESET_DEFAULT;
} else if (val1->nodeNr == val1->nodeMax) {
xmlNodePtr *temp;
if (val1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
goto error;
}
temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax * 2 *
sizeof(xmlNodePtr));
if (temp == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
goto error;
}
val1->nodeTab = temp;
val1->nodeMax *= 2;
}
if (n2->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) n2;
xmlNodePtr nsNode = xmlXPathNodeSetDupNs((xmlNodePtr) ns->next, ns);
if (nsNode == NULL)
goto error;
val1->nodeTab[val1->nodeNr++] = nsNode;
} else
val1->nodeTab[val1->nodeNr++] = n2;
}
return(val1);
error:
xmlXPathFreeNodeSet(val1);
return(NULL);
}
static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClear(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
{
{
int i, j, initNbSet1;
xmlNodePtr n1, n2;
initNbSet1 = set1->nodeNr;
for (i = 0;i < set2->nodeNr;i++) {
n2 = set2->nodeTab[i];
for (j = 0; j < initNbSet1; j++) {
n1 = set1->nodeTab[j];
if (n1 == n2) {
goto skip_node;
} else if ((n1->type == XML_NAMESPACE_DECL) &&
(n2->type == XML_NAMESPACE_DECL))
{
if ((((xmlNsPtr) n1)->next == ((xmlNsPtr) n2)->next) &&
(xmlStrEqual(((xmlNsPtr) n1)->prefix,
((xmlNsPtr) n2)->prefix)))
{
xmlXPathNodeSetFreeNs((xmlNsPtr) n2);
goto skip_node;
}
}
}
if (set1->nodeMax == 0) {
set1->nodeTab = (xmlNodePtr *) xmlMalloc(
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
if (set1->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
goto error;
}
memset(set1->nodeTab, 0,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
set1->nodeMax = XML_NODESET_DEFAULT;
} else if (set1->nodeNr >= set1->nodeMax) {
xmlNodePtr *temp;
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
goto error;
}
temp = (xmlNodePtr *) xmlRealloc(
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
if (temp == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
goto error;
}
set1->nodeTab = temp;
set1->nodeMax *= 2;
}
set1->nodeTab[set1->nodeNr++] = n2;
skip_node:
set2->nodeTab[i] = NULL;
}
}
set2->nodeNr = 0;
return(set1);
error:
xmlXPathFreeNodeSet(set1);
xmlXPathNodeSetClear(set2, 1);
return(NULL);
}
static xmlNodeSetPtr
xmlXPathNodeSetMergeAndClearNoDupls(xmlNodeSetPtr set1, xmlNodeSetPtr set2)
{
{
int i;
xmlNodePtr n2;
for (i = 0;i < set2->nodeNr;i++) {
n2 = set2->nodeTab[i];
if (set1->nodeMax == 0) {
set1->nodeTab = (xmlNodePtr *) xmlMalloc(
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
if (set1->nodeTab == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
goto error;
}
memset(set1->nodeTab, 0,
XML_NODESET_DEFAULT * sizeof(xmlNodePtr));
set1->nodeMax = XML_NODESET_DEFAULT;
} else if (set1->nodeNr >= set1->nodeMax) {
xmlNodePtr *temp;
if (set1->nodeMax >= XPATH_MAX_NODESET_LENGTH) {
xmlXPathErrMemory(NULL, "merging nodeset hit limit\n");
goto error;
}
temp = (xmlNodePtr *) xmlRealloc(
set1->nodeTab, set1->nodeMax * 2 * sizeof(xmlNodePtr));
if (temp == NULL) {
xmlXPathErrMemory(NULL, "merging nodeset\n");
goto error;
}
set1->nodeTab = temp;
set1->nodeMax *= 2;
}
set1->nodeTab[set1->nodeNr++] = n2;
set2->nodeTab[i] = NULL;
}
}
set2->nodeNr = 0;
return(set1);
error:
xmlXPathFreeNodeSet(set1);
xmlXPathNodeSetClear(set2, 1);
return(NULL);
}
void
xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
int i;
if (cur == NULL) return;
if (val == NULL) return;
for (i = 0;i < cur->nodeNr;i++)
if (cur->nodeTab[i] == val) break;
if (i >= cur->nodeNr) {
return;
}
if ((cur->nodeTab[i] != NULL) &&
(cur->nodeTab[i]->type == XML_NAMESPACE_DECL))
xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[i]);
cur->nodeNr--;
for (;i < cur->nodeNr;i++)
cur->nodeTab[i] = cur->nodeTab[i + 1];
cur->nodeTab[cur->nodeNr] = NULL;
}
void
xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
if (cur == NULL) return;
if (val >= cur->nodeNr) return;
if ((cur->nodeTab[val] != NULL) &&
(cur->nodeTab[val]->type == XML_NAMESPACE_DECL))
xmlXPathNodeSetFreeNs((xmlNsPtr) cur->nodeTab[val]);
cur->nodeNr--;
for (;val < cur->nodeNr;val++)
cur->nodeTab[val] = cur->nodeTab[val + 1];
cur->nodeTab[cur->nodeNr] = NULL;
}
void
xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
if (obj == NULL) return;
if (obj->nodeTab != NULL) {
int i;
for (i = 0;i < obj->nodeNr;i++)
if ((obj->nodeTab[i] != NULL) &&
(obj->nodeTab[i]->type == XML_NAMESPACE_DECL))
xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
xmlFree(obj->nodeTab);
}
xmlFree(obj);
}
static void
xmlXPathNodeSetClearFromPos(xmlNodeSetPtr set, int pos, int hasNsNodes)
{
if ((set == NULL) || (pos >= set->nodeNr))
return;
else if ((hasNsNodes)) {
int i;
xmlNodePtr node;
for (i = pos; i < set->nodeNr; i++) {
node = set->nodeTab[i];
if ((node != NULL) &&
(node->type == XML_NAMESPACE_DECL))
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
}
}
set->nodeNr = pos;
}
static void
xmlXPathNodeSetClear(xmlNodeSetPtr set, int hasNsNodes)
{
xmlXPathNodeSetClearFromPos(set, 0, hasNsNodes);
}
static void
xmlXPathNodeSetKeepLast(xmlNodeSetPtr set)
{
int i;
xmlNodePtr node;
if ((set == NULL) || (set->nodeNr <= 1))
return;
for (i = 0; i < set->nodeNr - 1; i++) {
node = set->nodeTab[i];
if ((node != NULL) &&
(node->type == XML_NAMESPACE_DECL))
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
}
set->nodeTab[0] = set->nodeTab[set->nodeNr-1];
set->nodeNr = 1;
}
static void
xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
int i;
if (obj == NULL) return;
if (obj->nodeTab != NULL) {
for (i = 0;i < obj->nodeNr;i++) {
if (obj->nodeTab[i] != NULL) {
if (obj->nodeTab[i]->type == XML_NAMESPACE_DECL) {
xmlXPathNodeSetFreeNs((xmlNsPtr) obj->nodeTab[i]);
} else {
xmlFreeNodeList(obj->nodeTab[i]);
}
}
}
xmlFree(obj->nodeTab);
}
xmlFree(obj);
}
xmlXPathObjectPtr
xmlXPathNewNodeSet(xmlNodePtr val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating nodeset\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
ret->type = XPATH_NODESET;
ret->boolval = 0;
ret->nodesetval = xmlXPathNodeSetCreate(val);
return(ret);
}
xmlXPathObjectPtr
xmlXPathNewValueTree(xmlNodePtr val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating result value tree\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
ret->type = XPATH_XSLT_TREE;
ret->boolval = 1;
ret->user = (void *) val;
ret->nodesetval = xmlXPathNodeSetCreate(val);
return(ret);
}
xmlXPathObjectPtr
xmlXPathNewNodeSetList(xmlNodeSetPtr val)
{
xmlXPathObjectPtr ret;
int i;
if (val == NULL)
ret = NULL;
else if (val->nodeTab == NULL)
ret = xmlXPathNewNodeSet(NULL);
else {
ret = xmlXPathNewNodeSet(val->nodeTab[0]);
if (ret) {
for (i = 1; i < val->nodeNr; ++i) {
if (xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i])
< 0) break;
}
}
}
return (ret);
}
xmlXPathObjectPtr
xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating node set object\n");
xmlXPathFreeNodeSet(val);
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
ret->type = XPATH_NODESET;
ret->nodesetval = val;
return(ret);
}
void
xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
if (obj == NULL) return;
xmlFree(obj);
}
xmlNodeSetPtr
xmlXPathDifference (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
xmlNodeSetPtr ret;
int i, l1;
xmlNodePtr cur;
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
ret = xmlXPathNodeSetCreate(NULL);
if (xmlXPathNodeSetIsEmpty(nodes1))
return(ret);
l1 = xmlXPathNodeSetGetLength(nodes1);
for (i = 0; i < l1; i++) {
cur = xmlXPathNodeSetItem(nodes1, i);
if (!xmlXPathNodeSetContains(nodes2, cur)) {
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
break;
}
}
return(ret);
}
xmlNodeSetPtr
xmlXPathIntersection (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
xmlNodeSetPtr ret = xmlXPathNodeSetCreate(NULL);
int i, l1;
xmlNodePtr cur;
if (ret == NULL)
return(ret);
if (xmlXPathNodeSetIsEmpty(nodes1))
return(ret);
if (xmlXPathNodeSetIsEmpty(nodes2))
return(ret);
l1 = xmlXPathNodeSetGetLength(nodes1);
for (i = 0; i < l1; i++) {
cur = xmlXPathNodeSetItem(nodes1, i);
if (xmlXPathNodeSetContains(nodes2, cur)) {
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
break;
}
}
return(ret);
}
xmlNodeSetPtr
xmlXPathDistinctSorted (xmlNodeSetPtr nodes) {
xmlNodeSetPtr ret;
xmlHashTablePtr hash;
int i, l;
xmlChar * strval;
xmlNodePtr cur;
if (xmlXPathNodeSetIsEmpty(nodes))
return(nodes);
ret = xmlXPathNodeSetCreate(NULL);
if (ret == NULL)
return(ret);
l = xmlXPathNodeSetGetLength(nodes);
hash = xmlHashCreate (l);
for (i = 0; i < l; i++) {
cur = xmlXPathNodeSetItem(nodes, i);
strval = xmlXPathCastNodeToString(cur);
if (xmlHashLookup(hash, strval) == NULL) {
if (xmlHashAddEntry(hash, strval, strval) < 0) {
xmlFree(strval);
goto error;
}
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
goto error;
} else {
xmlFree(strval);
}
}
xmlHashFree(hash, xmlHashDefaultDeallocator);
return(ret);
error:
xmlHashFree(hash, xmlHashDefaultDeallocator);
xmlXPathFreeNodeSet(ret);
return(NULL);
}
xmlNodeSetPtr
xmlXPathDistinct (xmlNodeSetPtr nodes) {
if (xmlXPathNodeSetIsEmpty(nodes))
return(nodes);
xmlXPathNodeSetSort(nodes);
return(xmlXPathDistinctSorted(nodes));
}
int
xmlXPathHasSameNodes (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
int i, l;
xmlNodePtr cur;
if (xmlXPathNodeSetIsEmpty(nodes1) ||
xmlXPathNodeSetIsEmpty(nodes2))
return(0);
l = xmlXPathNodeSetGetLength(nodes1);
for (i = 0; i < l; i++) {
cur = xmlXPathNodeSetItem(nodes1, i);
if (xmlXPathNodeSetContains(nodes2, cur))
return(1);
}
return(0);
}
xmlNodeSetPtr
xmlXPathNodeLeadingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
int i, l;
xmlNodePtr cur;
xmlNodeSetPtr ret;
if (node == NULL)
return(nodes);
ret = xmlXPathNodeSetCreate(NULL);
if (ret == NULL)
return(ret);
if (xmlXPathNodeSetIsEmpty(nodes) ||
(!xmlXPathNodeSetContains(nodes, node)))
return(ret);
l = xmlXPathNodeSetGetLength(nodes);
for (i = 0; i < l; i++) {
cur = xmlXPathNodeSetItem(nodes, i);
if (cur == node)
break;
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
break;
}
return(ret);
}
xmlNodeSetPtr
xmlXPathNodeLeading (xmlNodeSetPtr nodes, xmlNodePtr node) {
xmlXPathNodeSetSort(nodes);
return(xmlXPathNodeLeadingSorted(nodes, node));
}
xmlNodeSetPtr
xmlXPathLeadingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
return(xmlXPathNodeLeadingSorted(nodes1,
xmlXPathNodeSetItem(nodes2, 1)));
}
xmlNodeSetPtr
xmlXPathLeading (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
if (xmlXPathNodeSetIsEmpty(nodes1))
return(xmlXPathNodeSetCreate(NULL));
xmlXPathNodeSetSort(nodes1);
xmlXPathNodeSetSort(nodes2);
return(xmlXPathNodeLeadingSorted(nodes1,
xmlXPathNodeSetItem(nodes2, 1)));
}
xmlNodeSetPtr
xmlXPathNodeTrailingSorted (xmlNodeSetPtr nodes, xmlNodePtr node) {
int i, l;
xmlNodePtr cur;
xmlNodeSetPtr ret;
if (node == NULL)
return(nodes);
ret = xmlXPathNodeSetCreate(NULL);
if (ret == NULL)
return(ret);
if (xmlXPathNodeSetIsEmpty(nodes) ||
(!xmlXPathNodeSetContains(nodes, node)))
return(ret);
l = xmlXPathNodeSetGetLength(nodes);
for (i = l - 1; i >= 0; i--) {
cur = xmlXPathNodeSetItem(nodes, i);
if (cur == node)
break;
if (xmlXPathNodeSetAddUnique(ret, cur) < 0)
break;
}
xmlXPathNodeSetSort(ret);
return(ret);
}
xmlNodeSetPtr
xmlXPathNodeTrailing (xmlNodeSetPtr nodes, xmlNodePtr node) {
xmlXPathNodeSetSort(nodes);
return(xmlXPathNodeTrailingSorted(nodes, node));
}
xmlNodeSetPtr
xmlXPathTrailingSorted (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
return(xmlXPathNodeTrailingSorted(nodes1,
xmlXPathNodeSetItem(nodes2, 0)));
}
xmlNodeSetPtr
xmlXPathTrailing (xmlNodeSetPtr nodes1, xmlNodeSetPtr nodes2) {
if (xmlXPathNodeSetIsEmpty(nodes2))
return(nodes1);
if (xmlXPathNodeSetIsEmpty(nodes1))
return(xmlXPathNodeSetCreate(NULL));
xmlXPathNodeSetSort(nodes1);
xmlXPathNodeSetSort(nodes2);
return(xmlXPathNodeTrailingSorted(nodes1,
xmlXPathNodeSetItem(nodes2, 0)));
}
int
xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
xmlXPathFunction f) {
return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
}
int
xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri, xmlXPathFunction f) {
if (ctxt == NULL)
return(-1);
if (name == NULL)
return(-1);
if (ctxt->funcHash == NULL)
ctxt->funcHash = xmlHashCreate(0);
if (ctxt->funcHash == NULL)
return(-1);
if (f == NULL)
return(xmlHashRemoveEntry2(ctxt->funcHash, name, ns_uri, NULL));
XML_IGNORE_FPTR_CAST_WARNINGS
return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
XML_POP_WARNINGS
}
void
xmlXPathRegisterFuncLookup (xmlXPathContextPtr ctxt,
xmlXPathFuncLookupFunc f,
void *funcCtxt) {
if (ctxt == NULL)
return;
ctxt->funcLookupFunc = f;
ctxt->funcLookupData = funcCtxt;
}
xmlXPathFunction
xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
if (ctxt == NULL)
return (NULL);
if (ctxt->funcLookupFunc != NULL) {
xmlXPathFunction ret;
xmlXPathFuncLookupFunc f;
f = ctxt->funcLookupFunc;
ret = f(ctxt->funcLookupData, name, NULL);
if (ret != NULL)
return(ret);
}
return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
}
xmlXPathFunction
xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri) {
xmlXPathFunction ret;
if (ctxt == NULL)
return(NULL);
if (name == NULL)
return(NULL);
if (ctxt->funcLookupFunc != NULL) {
xmlXPathFuncLookupFunc f;
f = ctxt->funcLookupFunc;
ret = f(ctxt->funcLookupData, name, ns_uri);
if (ret != NULL)
return(ret);
}
if (ctxt->funcHash == NULL)
return(NULL);
XML_IGNORE_FPTR_CAST_WARNINGS
ret = (xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri);
XML_POP_WARNINGS
return(ret);
}
void
xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
if (ctxt == NULL)
return;
xmlHashFree(ctxt->funcHash, NULL);
ctxt->funcHash = NULL;
}
int
xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
xmlXPathObjectPtr value) {
return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
}
int
xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri,
xmlXPathObjectPtr value) {
if (ctxt == NULL)
return(-1);
if (name == NULL)
return(-1);
if (ctxt->varHash == NULL)
ctxt->varHash = xmlHashCreate(0);
if (ctxt->varHash == NULL)
return(-1);
if (value == NULL)
return(xmlHashRemoveEntry2(ctxt->varHash, name, ns_uri,
xmlXPathFreeObjectEntry));
return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
(void *) value, xmlXPathFreeObjectEntry));
}
void
xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
xmlXPathVariableLookupFunc f, void *data) {
if (ctxt == NULL)
return;
ctxt->varLookupFunc = f;
ctxt->varLookupData = data;
}
xmlXPathObjectPtr
xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
if (ctxt == NULL)
return(NULL);
if (ctxt->varLookupFunc != NULL) {
xmlXPathObjectPtr ret;
ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
(ctxt->varLookupData, name, NULL);
return(ret);
}
return(xmlXPathVariableLookupNS(ctxt, name, NULL));
}
xmlXPathObjectPtr
xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
const xmlChar *ns_uri) {
if (ctxt == NULL)
return(NULL);
if (ctxt->varLookupFunc != NULL) {
xmlXPathObjectPtr ret;
ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
(ctxt->varLookupData, name, ns_uri);
if (ret != NULL) return(ret);
}
if (ctxt->varHash == NULL)
return(NULL);
if (name == NULL)
return(NULL);
return(xmlXPathCacheObjectCopy(ctxt, (xmlXPathObjectPtr)
xmlHashLookup2(ctxt->varHash, name, ns_uri)));
}
void
xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
if (ctxt == NULL)
return;
xmlHashFree(ctxt->varHash, xmlXPathFreeObjectEntry);
ctxt->varHash = NULL;
}
int
xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
const xmlChar *ns_uri) {
xmlChar *copy;
if (ctxt == NULL)
return(-1);
if (prefix == NULL)
return(-1);
if (prefix[0] == 0)
return(-1);
if (ctxt->nsHash == NULL)
ctxt->nsHash = xmlHashCreate(10);
if (ctxt->nsHash == NULL)
return(-1);
if (ns_uri == NULL)
return(xmlHashRemoveEntry(ctxt->nsHash, prefix,
xmlHashDefaultDeallocator));
copy = xmlStrdup(ns_uri);
if (copy == NULL)
return(-1);
if (xmlHashUpdateEntry(ctxt->nsHash, prefix, copy,
xmlHashDefaultDeallocator) < 0) {
xmlFree(copy);
return(-1);
}
return(0);
}
const xmlChar *
xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
if (ctxt == NULL)
return(NULL);
if (prefix == NULL)
return(NULL);
#ifdef XML_XML_NAMESPACE
if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
return(XML_XML_NAMESPACE);
#endif
if (ctxt->namespaces != NULL) {
int i;
for (i = 0;i < ctxt->nsNr;i++) {
if ((ctxt->namespaces[i] != NULL) &&
(xmlStrEqual(ctxt->namespaces[i]->prefix, prefix)))
return(ctxt->namespaces[i]->href);
}
}
return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
}
void
xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
if (ctxt == NULL)
return;
xmlHashFree(ctxt->nsHash, xmlHashDefaultDeallocator);
ctxt->nsHash = NULL;
}
xmlXPathObjectPtr
xmlXPathNewFloat(double val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating float object\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
ret->type = XPATH_NUMBER;
ret->floatval = val;
return(ret);
}
xmlXPathObjectPtr
xmlXPathNewBoolean(int val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating boolean object\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
ret->type = XPATH_BOOLEAN;
ret->boolval = (val != 0);
return(ret);
}
xmlXPathObjectPtr
xmlXPathNewString(const xmlChar *val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating string object\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
ret->type = XPATH_STRING;
if (val == NULL)
val = BAD_CAST "";
ret->stringval = xmlStrdup(val);
if (ret->stringval == NULL) {
xmlFree(ret);
return(NULL);
}
return(ret);
}
xmlXPathObjectPtr
xmlXPathWrapString (xmlChar *val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating string object\n");
xmlFree(val);
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
ret->type = XPATH_STRING;
ret->stringval = val;
return(ret);
}
xmlXPathObjectPtr
xmlXPathNewCString(const char *val) {
return(xmlXPathNewString(BAD_CAST val));
}
xmlXPathObjectPtr
xmlXPathWrapCString (char * val) {
return(xmlXPathWrapString((xmlChar *)(val)));
}
xmlXPathObjectPtr
xmlXPathWrapExternal (void *val) {
xmlXPathObjectPtr ret;
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating user object\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathObject));
ret->type = XPATH_USERS;
ret->user = val;
return(ret);
}
xmlXPathObjectPtr
xmlXPathObjectCopy(xmlXPathObjectPtr val) {
xmlXPathObjectPtr ret;
if (val == NULL)
return(NULL);
ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "copying object\n");
return(NULL);
}
memcpy(ret, val , sizeof(xmlXPathObject));
switch (val->type) {
case XPATH_BOOLEAN:
case XPATH_NUMBER:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
#endif
break;
case XPATH_STRING:
ret->stringval = xmlStrdup(val->stringval);
if (ret->stringval == NULL) {
xmlFree(ret);
return(NULL);
}
break;
case XPATH_XSLT_TREE:
#if 0
if ((val->nodesetval != NULL) &&
(val->nodesetval->nodeTab != NULL)) {
xmlNodePtr cur, tmp;
xmlDocPtr top;
ret->boolval = 1;
top = xmlNewDoc(NULL);
top->name = (char *)
xmlStrdup(val->nodesetval->nodeTab[0]->name);
ret->user = top;
if (top != NULL) {
top->doc = top;
cur = val->nodesetval->nodeTab[0]->children;
while (cur != NULL) {
tmp = xmlDocCopyNode(cur, top, 1);
xmlAddChild((xmlNodePtr) top, tmp);
cur = cur->next;
}
}
ret->nodesetval = xmlXPathNodeSetCreate((xmlNodePtr) top);
} else
ret->nodesetval = xmlXPathNodeSetCreate(NULL);
break;
#endif
case XPATH_NODESET:
ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
ret->boolval = 0;
break;
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_LOCATIONSET:
{
xmlLocationSetPtr loc = val->user;
ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
break;
}
#endif
case XPATH_USERS:
ret->user = val->user;
break;
case XPATH_UNDEFINED:
xmlGenericError(xmlGenericErrorContext,
"xmlXPathObjectCopy: unsupported type %d\n",
val->type);
break;
}
return(ret);
}
void
xmlXPathFreeObject(xmlXPathObjectPtr obj) {
if (obj == NULL) return;
if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
if (obj->boolval) {
#if 0
if (obj->user != NULL) {
xmlXPathFreeNodeSet(obj->nodesetval);
xmlFreeNodeList((xmlNodePtr) obj->user);
} else
#endif
obj->type = XPATH_XSLT_TREE;
if (obj->nodesetval != NULL)
xmlXPathFreeValueTree(obj->nodesetval);
} else {
if (obj->nodesetval != NULL)
xmlXPathFreeNodeSet(obj->nodesetval);
}
#ifdef LIBXML_XPTR_LOCS_ENABLED
} else if (obj->type == XPATH_LOCATIONSET) {
if (obj->user != NULL)
xmlXPtrFreeLocationSet(obj->user);
#endif
} else if (obj->type == XPATH_STRING) {
if (obj->stringval != NULL)
xmlFree(obj->stringval);
}
xmlFree(obj);
}
static void
xmlXPathFreeObjectEntry(void *obj, const xmlChar *name ATTRIBUTE_UNUSED) {
xmlXPathFreeObject((xmlXPathObjectPtr) obj);
}
static void
xmlXPathReleaseObject(xmlXPathContextPtr ctxt, xmlXPathObjectPtr obj)
{
#define XP_CACHE_ADD(sl, o) if (sl == NULL) { \
sl = xmlPointerListCreate(10); if (sl == NULL) goto free_obj; } \
if (xmlPointerListAddSize(sl, obj, 0) == -1) goto free_obj;
#define XP_CACHE_WANTS(sl, n) ((sl == NULL) || ((sl)->number < n))
if (obj == NULL)
return;
if ((ctxt == NULL) || (ctxt->cache == NULL)) {
xmlXPathFreeObject(obj);
} else {
xmlXPathContextCachePtr cache =
(xmlXPathContextCachePtr) ctxt->cache;
switch (obj->type) {
case XPATH_NODESET:
case XPATH_XSLT_TREE:
if (obj->nodesetval != NULL) {
if (obj->boolval) {
obj->type = XPATH_XSLT_TREE;
xmlXPathFreeValueTree(obj->nodesetval);
obj->nodesetval = NULL;
} else if ((obj->nodesetval->nodeMax <= 40) &&
(XP_CACHE_WANTS(cache->nodesetObjs,
cache->maxNodeset)))
{
XP_CACHE_ADD(cache->nodesetObjs, obj);
goto obj_cached;
} else {
xmlXPathFreeNodeSet(obj->nodesetval);
obj->nodesetval = NULL;
}
}
break;
case XPATH_STRING:
if (obj->stringval != NULL)
xmlFree(obj->stringval);
if (XP_CACHE_WANTS(cache->stringObjs, cache->maxString)) {
XP_CACHE_ADD(cache->stringObjs, obj);
goto obj_cached;
}
break;
case XPATH_BOOLEAN:
if (XP_CACHE_WANTS(cache->booleanObjs, cache->maxBoolean)) {
XP_CACHE_ADD(cache->booleanObjs, obj);
goto obj_cached;
}
break;
case XPATH_NUMBER:
if (XP_CACHE_WANTS(cache->numberObjs, cache->maxNumber)) {
XP_CACHE_ADD(cache->numberObjs, obj);
goto obj_cached;
}
break;
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_LOCATIONSET:
if (obj->user != NULL) {
xmlXPtrFreeLocationSet(obj->user);
}
goto free_obj;
#endif
default:
goto free_obj;
}
if (XP_CACHE_WANTS(cache->miscObjs, cache->maxMisc)) {
XP_CACHE_ADD(cache->miscObjs, obj);
} else
goto free_obj;
obj_cached:
if (obj->nodesetval != NULL) {
xmlNodeSetPtr tmpset = obj->nodesetval;
if (tmpset->nodeNr > 1) {
int i;
xmlNodePtr node;
for (i = 0; i < tmpset->nodeNr; i++) {
node = tmpset->nodeTab[i];
if ((node != NULL) &&
(node->type == XML_NAMESPACE_DECL))
{
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
}
}
} else if (tmpset->nodeNr == 1) {
if ((tmpset->nodeTab[0] != NULL) &&
(tmpset->nodeTab[0]->type == XML_NAMESPACE_DECL))
xmlXPathNodeSetFreeNs((xmlNsPtr) tmpset->nodeTab[0]);
}
tmpset->nodeNr = 0;
memset(obj, 0, sizeof(xmlXPathObject));
obj->nodesetval = tmpset;
} else
memset(obj, 0, sizeof(xmlXPathObject));
return;
free_obj:
if (obj->nodesetval != NULL)
xmlXPathFreeNodeSet(obj->nodesetval);
xmlFree(obj);
}
return;
}
xmlChar *
xmlXPathCastBooleanToString (int val) {
xmlChar *ret;
if (val)
ret = xmlStrdup((const xmlChar *) "true");
else
ret = xmlStrdup((const xmlChar *) "false");
return(ret);
}
xmlChar *
xmlXPathCastNumberToString (double val) {
xmlChar *ret;
switch (xmlXPathIsInf(val)) {
case 1:
ret = xmlStrdup((const xmlChar *) "Infinity");
break;
case -1:
ret = xmlStrdup((const xmlChar *) "-Infinity");
break;
default:
if (xmlXPathIsNaN(val)) {
ret = xmlStrdup((const xmlChar *) "NaN");
} else if (val == 0) {
ret = xmlStrdup((const xmlChar *) "0");
} else {
char buf[100];
xmlXPathFormatNumber(val, buf, 99);
buf[99] = 0;
ret = xmlStrdup((const xmlChar *) buf);
}
}
return(ret);
}
xmlChar *
xmlXPathCastNodeToString (xmlNodePtr node) {
xmlChar *ret;
if ((ret = xmlNodeGetContent(node)) == NULL)
ret = xmlStrdup((const xmlChar *) "");
return(ret);
}
xmlChar *
xmlXPathCastNodeSetToString (xmlNodeSetPtr ns) {
if ((ns == NULL) || (ns->nodeNr == 0) || (ns->nodeTab == NULL))
return(xmlStrdup((const xmlChar *) ""));
if (ns->nodeNr > 1)
xmlXPathNodeSetSort(ns);
return(xmlXPathCastNodeToString(ns->nodeTab[0]));
}
xmlChar *
xmlXPathCastToString(xmlXPathObjectPtr val) {
xmlChar *ret = NULL;
if (val == NULL)
return(xmlStrdup((const xmlChar *) ""));
switch (val->type) {
case XPATH_UNDEFINED:
ret = xmlStrdup((const xmlChar *) "");
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
ret = xmlXPathCastNodeSetToString(val->nodesetval);
break;
case XPATH_STRING:
return(xmlStrdup(val->stringval));
case XPATH_BOOLEAN:
ret = xmlXPathCastBooleanToString(val->boolval);
break;
case XPATH_NUMBER: {
ret = xmlXPathCastNumberToString(val->floatval);
break;
}
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO
ret = xmlStrdup((const xmlChar *) "");
break;
}
return(ret);
}
xmlXPathObjectPtr
xmlXPathConvertString(xmlXPathObjectPtr val) {
xmlChar *res = NULL;
if (val == NULL)
return(xmlXPathNewCString(""));
switch (val->type) {
case XPATH_UNDEFINED:
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
res = xmlXPathCastNodeSetToString(val->nodesetval);
break;
case XPATH_STRING:
return(val);
case XPATH_BOOLEAN:
res = xmlXPathCastBooleanToString(val->boolval);
break;
case XPATH_NUMBER:
res = xmlXPathCastNumberToString(val->floatval);
break;
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO;
break;
}
xmlXPathFreeObject(val);
if (res == NULL)
return(xmlXPathNewCString(""));
return(xmlXPathWrapString(res));
}
double
xmlXPathCastBooleanToNumber(int val) {
if (val)
return(1.0);
return(0.0);
}
double
xmlXPathCastStringToNumber(const xmlChar * val) {
return(xmlXPathStringEvalNumber(val));
}
double
xmlXPathCastNodeToNumber (xmlNodePtr node) {
xmlChar *strval;
double ret;
if (node == NULL)
return(xmlXPathNAN);
strval = xmlXPathCastNodeToString(node);
if (strval == NULL)
return(xmlXPathNAN);
ret = xmlXPathCastStringToNumber(strval);
xmlFree(strval);
return(ret);
}
double
xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
xmlChar *str;
double ret;
if (ns == NULL)
return(xmlXPathNAN);
str = xmlXPathCastNodeSetToString(ns);
ret = xmlXPathCastStringToNumber(str);
xmlFree(str);
return(ret);
}
double
xmlXPathCastToNumber(xmlXPathObjectPtr val) {
double ret = 0.0;
if (val == NULL)
return(xmlXPathNAN);
switch (val->type) {
case XPATH_UNDEFINED:
ret = xmlXPathNAN;
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
ret = xmlXPathCastNodeSetToNumber(val->nodesetval);
break;
case XPATH_STRING:
ret = xmlXPathCastStringToNumber(val->stringval);
break;
case XPATH_NUMBER:
ret = val->floatval;
break;
case XPATH_BOOLEAN:
ret = xmlXPathCastBooleanToNumber(val->boolval);
break;
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO;
ret = xmlXPathNAN;
break;
}
return(ret);
}
xmlXPathObjectPtr
xmlXPathConvertNumber(xmlXPathObjectPtr val) {
xmlXPathObjectPtr ret;
if (val == NULL)
return(xmlXPathNewFloat(0.0));
if (val->type == XPATH_NUMBER)
return(val);
ret = xmlXPathNewFloat(xmlXPathCastToNumber(val));
xmlXPathFreeObject(val);
return(ret);
}
int
xmlXPathCastNumberToBoolean (double val) {
if (xmlXPathIsNaN(val) || (val == 0.0))
return(0);
return(1);
}
int
xmlXPathCastStringToBoolean (const xmlChar *val) {
if ((val == NULL) || (xmlStrlen(val) == 0))
return(0);
return(1);
}
int
xmlXPathCastNodeSetToBoolean (xmlNodeSetPtr ns) {
if ((ns == NULL) || (ns->nodeNr == 0))
return(0);
return(1);
}
int
xmlXPathCastToBoolean (xmlXPathObjectPtr val) {
int ret = 0;
if (val == NULL)
return(0);
switch (val->type) {
case XPATH_UNDEFINED:
ret = 0;
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
ret = xmlXPathCastNodeSetToBoolean(val->nodesetval);
break;
case XPATH_STRING:
ret = xmlXPathCastStringToBoolean(val->stringval);
break;
case XPATH_NUMBER:
ret = xmlXPathCastNumberToBoolean(val->floatval);
break;
case XPATH_BOOLEAN:
ret = val->boolval;
break;
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO;
ret = 0;
break;
}
return(ret);
}
xmlXPathObjectPtr
xmlXPathConvertBoolean(xmlXPathObjectPtr val) {
xmlXPathObjectPtr ret;
if (val == NULL)
return(xmlXPathNewBoolean(0));
if (val->type == XPATH_BOOLEAN)
return(val);
ret = xmlXPathNewBoolean(xmlXPathCastToBoolean(val));
xmlXPathFreeObject(val);
return(ret);
}
xmlXPathContextPtr
xmlXPathNewContext(xmlDocPtr doc) {
xmlXPathContextPtr ret;
ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
if (ret == NULL) {
xmlXPathErrMemory(NULL, "creating context\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathContext));
ret->doc = doc;
ret->node = NULL;
ret->varHash = NULL;
ret->nb_types = 0;
ret->max_types = 0;
ret->types = NULL;
ret->funcHash = xmlHashCreate(0);
ret->nb_axis = 0;
ret->max_axis = 0;
ret->axis = NULL;
ret->nsHash = NULL;
ret->user = NULL;
ret->contextSize = -1;
ret->proximityPosition = -1;
#ifdef XP_DEFAULT_CACHE_ON
if (xmlXPathContextSetCache(ret, 1, -1, 0) == -1) {
xmlXPathFreeContext(ret);
return(NULL);
}
#endif
xmlXPathRegisterAllFunctions(ret);
return(ret);
}
void
xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
if (ctxt == NULL) return;
if (ctxt->cache != NULL)
xmlXPathFreeCache((xmlXPathContextCachePtr) ctxt->cache);
xmlXPathRegisteredNsCleanup(ctxt);
xmlXPathRegisteredFuncsCleanup(ctxt);
xmlXPathRegisteredVariablesCleanup(ctxt);
xmlResetError(&ctxt->lastError);
xmlFree(ctxt);
}
#define CHECK_CTXT(ctxt) \
if (ctxt == NULL) { \
__xmlRaiseError(NULL, NULL, NULL, \
NULL, NULL, XML_FROM_XPATH, \
XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
__FILE__, __LINE__, \
NULL, NULL, NULL, 0, 0, \
"NULL context pointer\n"); \
return(NULL); \
} \
#define CHECK_CTXT_NEG(ctxt) \
if (ctxt == NULL) { \
__xmlRaiseError(NULL, NULL, NULL, \
NULL, NULL, XML_FROM_XPATH, \
XML_ERR_INTERNAL_ERROR, XML_ERR_FATAL, \
__FILE__, __LINE__, \
NULL, NULL, NULL, 0, 0, \
"NULL context pointer\n"); \
return(-1); \
} \
#define CHECK_CONTEXT(ctxt) \
if ((ctxt == NULL) || (ctxt->doc == NULL) || \
(ctxt->doc->children == NULL)) { \
xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_INVALID_CTXT); \
return(NULL); \
}
xmlXPathParserContextPtr
xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
xmlXPathParserContextPtr ret;
ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
if (ret == NULL) {
xmlXPathErrMemory(ctxt, "creating parser context\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathParserContext));
ret->cur = ret->base = str;
ret->context = ctxt;
ret->comp = xmlXPathNewCompExpr();
if (ret->comp == NULL) {
xmlFree(ret->valueTab);
xmlFree(ret);
return(NULL);
}
if ((ctxt != NULL) && (ctxt->dict != NULL)) {
ret->comp->dict = ctxt->dict;
xmlDictReference(ret->comp->dict);
}
return(ret);
}
static xmlXPathParserContextPtr
xmlXPathCompParserContext(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctxt) {
xmlXPathParserContextPtr ret;
ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
if (ret == NULL) {
xmlXPathErrMemory(ctxt, "creating evaluation context\n");
return(NULL);
}
memset(ret, 0 , sizeof(xmlXPathParserContext));
ret->valueTab = (xmlXPathObjectPtr *)
xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
if (ret->valueTab == NULL) {
xmlFree(ret);
xmlXPathErrMemory(ctxt, "creating evaluation context\n");
return(NULL);
}
ret->valueNr = 0;
ret->valueMax = 10;
ret->value = NULL;
ret->context = ctxt;
ret->comp = comp;
return(ret);
}
void
xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
int i;
if (ctxt->valueTab != NULL) {
for (i = 0; i < ctxt->valueNr; i++) {
if (ctxt->context)
xmlXPathReleaseObject(ctxt->context, ctxt->valueTab[i]);
else
xmlXPathFreeObject(ctxt->valueTab[i]);
}
xmlFree(ctxt->valueTab);
}
if (ctxt->comp != NULL) {
#ifdef XPATH_STREAMING
if (ctxt->comp->stream != NULL) {
xmlFreePatternList(ctxt->comp->stream);
ctxt->comp->stream = NULL;
}
#endif
xmlXPathFreeCompExpr(ctxt->comp);
}
xmlFree(ctxt);
}
static unsigned int
xmlXPathNodeValHash(xmlNodePtr node) {
int len = 2;
const xmlChar * string = NULL;
xmlNodePtr tmp = NULL;
unsigned int ret = 0;
if (node == NULL)
return(0);
if (node->type == XML_DOCUMENT_NODE) {
tmp = xmlDocGetRootElement((xmlDocPtr) node);
if (tmp == NULL)
node = node->children;
else
node = tmp;
if (node == NULL)
return(0);
}
switch (node->type) {
case XML_COMMENT_NODE:
case XML_PI_NODE:
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
string = node->content;
if (string == NULL)
return(0);
if (string[0] == 0)
return(0);
return(string[0] + (string[1] << 8));
case XML_NAMESPACE_DECL:
string = ((xmlNsPtr)node)->href;
if (string == NULL)
return(0);
if (string[0] == 0)
return(0);
return(string[0] + (string[1] << 8));
case XML_ATTRIBUTE_NODE:
tmp = ((xmlAttrPtr) node)->children;
break;
case XML_ELEMENT_NODE:
tmp = node->children;
break;
default:
return(0);
}
while (tmp != NULL) {
switch (tmp->type) {
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
string = tmp->content;
break;
default:
string = NULL;
break;
}
if ((string != NULL) && (string[0] != 0)) {
if (len == 1) {
return(ret + (string[0] << 8));
}
if (string[1] == 0) {
len = 1;
ret = string[0];
} else {
return(string[0] + (string[1] << 8));
}
}
if ((tmp->children != NULL) &&
(tmp->type != XML_DTD_NODE) &&
(tmp->type != XML_ENTITY_REF_NODE) &&
(tmp->children->type != XML_ENTITY_DECL)) {
tmp = tmp->children;
continue;
}
if (tmp == node)
break;
if (tmp->next != NULL) {
tmp = tmp->next;
continue;
}
do {
tmp = tmp->parent;
if (tmp == NULL)
break;
if (tmp == node) {
tmp = NULL;
break;
}
if (tmp->next != NULL) {
tmp = tmp->next;
break;
}
} while (tmp != NULL);
}
return(ret);
}
static unsigned int
xmlXPathStringHash(const xmlChar * string) {
if (string == NULL)
return(0);
if (string[0] == 0)
return(0);
return(string[0] + (string[1] << 8));
}
static int
xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
int i, ret = 0;
xmlNodeSetPtr ns;
xmlChar *str2;
if ((f == NULL) || (arg == NULL) ||
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
xmlXPathReleaseObject(ctxt->context, arg);
xmlXPathReleaseObject(ctxt->context, f);
return(0);
}
ns = arg->nodesetval;
if (ns != NULL) {
for (i = 0;i < ns->nodeNr;i++) {
str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
if (str2 != NULL) {
valuePush(ctxt,
xmlXPathCacheNewString(ctxt->context, str2));
xmlFree(str2);
xmlXPathNumberFunction(ctxt, 1);
valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, f));
ret = xmlXPathCompareValues(ctxt, inf, strict);
if (ret)
break;
}
}
}
xmlXPathReleaseObject(ctxt->context, arg);
xmlXPathReleaseObject(ctxt->context, f);
return(ret);
}
static int
xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
int i, ret = 0;
xmlNodeSetPtr ns;
xmlChar *str2;
if ((s == NULL) || (arg == NULL) ||
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
xmlXPathReleaseObject(ctxt->context, arg);
xmlXPathReleaseObject(ctxt->context, s);
return(0);
}
ns = arg->nodesetval;
if (ns != NULL) {
for (i = 0;i < ns->nodeNr;i++) {
str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
if (str2 != NULL) {
valuePush(ctxt,
xmlXPathCacheNewString(ctxt->context, str2));
xmlFree(str2);
valuePush(ctxt, xmlXPathCacheObjectCopy(ctxt->context, s));
ret = xmlXPathCompareValues(ctxt, inf, strict);
if (ret)
break;
}
}
}
xmlXPathReleaseObject(ctxt->context, arg);
xmlXPathReleaseObject(ctxt->context, s);
return(ret);
}
static int
xmlXPathCompareNodeSets(int inf, int strict,
xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
int i, j, init = 0;
double val1;
double *values2;
int ret = 0;
xmlNodeSetPtr ns1;
xmlNodeSetPtr ns2;
if ((arg1 == NULL) ||
((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE))) {
xmlXPathFreeObject(arg2);
return(0);
}
if ((arg2 == NULL) ||
((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE))) {
xmlXPathFreeObject(arg1);
xmlXPathFreeObject(arg2);
return(0);
}
ns1 = arg1->nodesetval;
ns2 = arg2->nodesetval;
if ((ns1 == NULL) || (ns1->nodeNr <= 0)) {
xmlXPathFreeObject(arg1);
xmlXPathFreeObject(arg2);
return(0);
}
if ((ns2 == NULL) || (ns2->nodeNr <= 0)) {
xmlXPathFreeObject(arg1);
xmlXPathFreeObject(arg2);
return(0);
}
values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
if (values2 == NULL) {
xmlXPathErrMemory(NULL, "comparing nodesets\n");
xmlXPathFreeObject(arg1);
xmlXPathFreeObject(arg2);
return(0);
}
for (i = 0;i < ns1->nodeNr;i++) {
val1 = xmlXPathCastNodeToNumber(ns1->nodeTab[i]);
if (xmlXPathIsNaN(val1))
continue;
for (j = 0;j < ns2->nodeNr;j++) {
if (init == 0) {
values2[j] = xmlXPathCastNodeToNumber(ns2->nodeTab[j]);
}
if (xmlXPathIsNaN(values2[j]))
continue;
if (inf && strict)
ret = (val1 < values2[j]);
else if (inf && !strict)
ret = (val1 <= values2[j]);
else if (!inf && strict)
ret = (val1 > values2[j]);
else if (!inf && !strict)
ret = (val1 >= values2[j]);
if (ret)
break;
}
if (ret)
break;
init = 1;
}
xmlFree(values2);
xmlXPathFreeObject(arg1);
xmlXPathFreeObject(arg2);
return(ret);
}
static int
xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
if ((val == NULL) || (arg == NULL) ||
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
return(0);
switch(val->type) {
case XPATH_NUMBER:
return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
case XPATH_NODESET:
case XPATH_XSLT_TREE:
return(xmlXPathCompareNodeSets(inf, strict, arg, val));
case XPATH_STRING:
return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
case XPATH_BOOLEAN:
valuePush(ctxt, arg);
xmlXPathBooleanFunction(ctxt, 1);
valuePush(ctxt, val);
return(xmlXPathCompareValues(ctxt, inf, strict));
default:
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompareNodeSetValue: Can't compare node set "
"and object of type %d\n",
val->type);
xmlXPathReleaseObject(ctxt->context, arg);
xmlXPathReleaseObject(ctxt->context, val);
XP_ERROR0(XPATH_INVALID_TYPE);
}
return(0);
}
static int
xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar * str, int neq)
{
int i;
xmlNodeSetPtr ns;
xmlChar *str2;
unsigned int hash;
if ((str == NULL) || (arg == NULL) ||
((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
return (0);
ns = arg->nodesetval;
if ((ns == NULL) || (ns->nodeNr <= 0) )
return (0);
hash = xmlXPathStringHash(str);
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 ((str2 == NULL) && (xmlStrEqual(str, BAD_CAST ""))) {
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);
}
static int
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);
ns = arg->nodesetval;
if (ns != NULL) {
for (i=0;i<ns->nodeNr;i++) {
str2 = xmlXPathCastNodeToString(ns->nodeTab[i]);
if (str2 != NULL) {
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, str2));
xmlFree(str2);
xmlXPathNumberFunction(ctxt, 1);
CHECK_ERROR0;
val = valuePop(ctxt);
v = val->floatval;
xmlXPathReleaseObject(ctxt->context, val);
if (!xmlXPathIsNaN(v)) {
if ((!neq) && (v==f)) {
ret = 1;
break;
} else if ((neq) && (v!=f)) {
ret = 1;
break;
}
} else {
if (neq)
ret = 1;
}
}
}
}
return(ret);
}
static int
xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2, int neq) {
int i, j;
unsigned int *hashs1;
unsigned int *hashs2;
xmlChar **values1;
xmlChar **values2;
int ret = 0;
xmlNodeSetPtr ns1;
xmlNodeSetPtr ns2;
if ((arg1 == NULL) ||
((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
return(0);
if ((arg2 == NULL) ||
((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
return(0);
ns1 = arg1->nodesetval;
ns2 = arg2->nodesetval;
if ((ns1 == NULL) || (ns1->nodeNr <= 0))
return(0);
if ((ns2 == NULL) || (ns2->nodeNr <= 0))
return(0);
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) {
xmlXPathErrMemory(NULL, "comparing nodesets\n");
return(0);
}
hashs1 = (unsigned int *) xmlMalloc(ns1->nodeNr * sizeof(unsigned int));
if (hashs1 == NULL) {
xmlXPathErrMemory(NULL, "comparing nodesets\n");
xmlFree(values1);
return(0);
}
memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
if (values2 == NULL) {
xmlXPathErrMemory(NULL, "comparing nodesets\n");
xmlFree(hashs1);
xmlFree(values1);
return(0);
}
hashs2 = (unsigned int *) xmlMalloc(ns2->nodeNr * sizeof(unsigned int));
if (hashs2 == NULL) {
xmlXPathErrMemory(NULL, "comparing nodesets\n");
xmlFree(hashs1);
xmlFree(values1);
xmlFree(values2);
return(0);
}
memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
for (i = 0;i < ns1->nodeNr;i++) {
hashs1[i] = xmlXPathNodeValHash(ns1->nodeTab[i]);
for (j = 0;j < ns2->nodeNr;j++) {
if (i == 0)
hashs2[j] = xmlXPathNodeValHash(ns2->nodeTab[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]) ^ neq;
if (ret)
break;
}
}
if (ret)
break;
}
for (i = 0;i < ns1->nodeNr;i++)
if (values1[i] != NULL)
xmlFree(values1[i]);
for (j = 0;j < ns2->nodeNr;j++)
if (values2[j] != NULL)
xmlFree(values2[j]);
xmlFree(values1);
xmlFree(values2);
xmlFree(hashs1);
xmlFree(hashs2);
return(ret);
}
static int
xmlXPathEqualValuesCommon(xmlXPathParserContextPtr ctxt,
xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
int ret = 0;
switch (arg1->type) {
case XPATH_UNDEFINED:
break;
case XPATH_BOOLEAN:
switch (arg2->type) {
case XPATH_UNDEFINED:
break;
case XPATH_BOOLEAN:
ret = (arg1->boolval == arg2->boolval);
break;
case XPATH_NUMBER:
ret = (arg1->boolval ==
xmlXPathCastNumberToBoolean(arg2->floatval));
break;
case XPATH_STRING:
if ((arg2->stringval == NULL) ||
(arg2->stringval[0] == 0)) ret = 0;
else
ret = 1;
ret = (arg1->boolval == ret);
break;
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
break;
}
break;
case XPATH_NUMBER:
switch (arg2->type) {
case XPATH_UNDEFINED:
break;
case XPATH_BOOLEAN:
ret = (arg2->boolval==
xmlXPathCastNumberToBoolean(arg1->floatval));
break;
case XPATH_STRING:
valuePush(ctxt, arg2);
xmlXPathNumberFunction(ctxt, 1);
arg2 = valuePop(ctxt);
if (ctxt->error)
break;
case XPATH_NUMBER:
if (xmlXPathIsNaN(arg1->floatval) ||
xmlXPathIsNaN(arg2->floatval)) {
ret = 0;
} else if (xmlXPathIsInf(arg1->floatval) == 1) {
if (xmlXPathIsInf(arg2->floatval) == 1)
ret = 1;
else
ret = 0;
} else if (xmlXPathIsInf(arg1->floatval) == -1) {
if (xmlXPathIsInf(arg2->floatval) == -1)
ret = 1;
else
ret = 0;
} else if (xmlXPathIsInf(arg2->floatval) == 1) {
if (xmlXPathIsInf(arg1->floatval) == 1)
ret = 1;
else
ret = 0;
} else if (xmlXPathIsInf(arg2->floatval) == -1) {
if (xmlXPathIsInf(arg1->floatval) == -1)
ret = 1;
else
ret = 0;
} else {
ret = (arg1->floatval == arg2->floatval);
}
break;
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
break;
}
break;
case XPATH_STRING:
switch (arg2->type) {
case XPATH_UNDEFINED:
break;
case XPATH_BOOLEAN:
if ((arg1->stringval == NULL) ||
(arg1->stringval[0] == 0)) ret = 0;
else
ret = 1;
ret = (arg2->boolval == ret);
break;
case XPATH_STRING:
ret = xmlStrEqual(arg1->stringval, arg2->stringval);
break;
case XPATH_NUMBER:
valuePush(ctxt, arg1);
xmlXPathNumberFunction(ctxt, 1);
arg1 = valuePop(ctxt);
if (ctxt->error)
break;
if (xmlXPathIsNaN(arg1->floatval) ||
xmlXPathIsNaN(arg2->floatval)) {
ret = 0;
} else if (xmlXPathIsInf(arg1->floatval) == 1) {
if (xmlXPathIsInf(arg2->floatval) == 1)
ret = 1;
else
ret = 0;
} else if (xmlXPathIsInf(arg1->floatval) == -1) {
if (xmlXPathIsInf(arg2->floatval) == -1)
ret = 1;
else
ret = 0;
} else if (xmlXPathIsInf(arg2->floatval) == 1) {
if (xmlXPathIsInf(arg1->floatval) == 1)
ret = 1;
else
ret = 0;
} else if (xmlXPathIsInf(arg2->floatval) == -1) {
if (xmlXPathIsInf(arg1->floatval) == -1)
ret = 1;
else
ret = 0;
} else {
ret = (arg1->floatval == arg2->floatval);
}
break;
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
break;
}
break;
case XPATH_USERS:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO
break;
case XPATH_NODESET:
case XPATH_XSLT_TREE:
break;
}
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
return(ret);
}
int
xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr arg1, arg2, argtmp;
int ret = 0;
if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
arg2 = valuePop(ctxt);
arg1 = valuePop(ctxt);
if ((arg1 == NULL) || (arg2 == NULL)) {
if (arg1 != NULL)
xmlXPathReleaseObject(ctxt->context, arg1);
else
xmlXPathReleaseObject(ctxt->context, arg2);
XP_ERROR0(XPATH_INVALID_OPERAND);
}
if (arg1 == arg2) {
xmlXPathFreeObject(arg1);
return(1);
}
if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
(arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
argtmp = arg2;
arg2 = arg1;
arg1 = argtmp;
}
switch (arg2->type) {
case XPATH_UNDEFINED:
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:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO
break;
}
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
return(ret);
}
return (xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
}
int
xmlXPathNotEqualValues(xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr arg1, arg2, argtmp;
int ret = 0;
if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
arg2 = valuePop(ctxt);
arg1 = valuePop(ctxt);
if ((arg1 == NULL) || (arg2 == NULL)) {
if (arg1 != NULL)
xmlXPathReleaseObject(ctxt->context, arg1);
else
xmlXPathReleaseObject(ctxt->context, arg2);
XP_ERROR0(XPATH_INVALID_OPERAND);
}
if (arg1 == arg2) {
xmlXPathReleaseObject(ctxt->context, arg1);
return(0);
}
if ((arg2->type == XPATH_NODESET) || (arg2->type == XPATH_XSLT_TREE) ||
(arg1->type == XPATH_NODESET) || (arg1->type == XPATH_XSLT_TREE)) {
if ((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)) {
argtmp = arg2;
arg2 = arg1;
arg1 = argtmp;
}
switch (arg2->type) {
case XPATH_UNDEFINED:
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:
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_POINT:
case XPATH_RANGE:
case XPATH_LOCATIONSET:
#endif
TODO
break;
}
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
return(ret);
}
return (!xmlXPathEqualValuesCommon(ctxt, arg1, arg2));
}
int
xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
int ret = 0, arg1i = 0, arg2i = 0;
xmlXPathObjectPtr arg1, arg2;
if ((ctxt == NULL) || (ctxt->context == NULL)) return(0);
arg2 = valuePop(ctxt);
arg1 = valuePop(ctxt);
if ((arg1 == NULL) || (arg2 == NULL)) {
if (arg1 != NULL)
xmlXPathReleaseObject(ctxt->context, arg1);
else
xmlXPathReleaseObject(ctxt->context, arg2);
XP_ERROR0(XPATH_INVALID_OPERAND);
}
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) || (arg1->type == XPATH_XSLT_TREE)) {
ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict,
arg1, arg2);
} else {
ret = xmlXPathCompareNodeSetValue(ctxt, !inf, strict,
arg2, arg1);
}
}
return(ret);
}
if (arg1->type != XPATH_NUMBER) {
valuePush(ctxt, arg1);
xmlXPathNumberFunction(ctxt, 1);
arg1 = valuePop(ctxt);
}
if (arg2->type != XPATH_NUMBER) {
valuePush(ctxt, arg2);
xmlXPathNumberFunction(ctxt, 1);
arg2 = valuePop(ctxt);
}
if (ctxt->error)
goto error;
if (xmlXPathIsNaN(arg1->floatval) || xmlXPathIsNaN(arg2->floatval)) {
ret=0;
} else {
arg1i=xmlXPathIsInf(arg1->floatval);
arg2i=xmlXPathIsInf(arg2->floatval);
if (inf && strict) {
if ((arg1i == -1 && arg2i != -1) ||
(arg2i == 1 && arg1i != 1)) {
ret = 1;
} else if (arg1i == 0 && arg2i == 0) {
ret = (arg1->floatval < arg2->floatval);
} else {
ret = 0;
}
}
else if (inf && !strict) {
if (arg1i == -1 || arg2i == 1) {
ret = 1;
} else if (arg1i == 0 && arg2i == 0) {
ret = (arg1->floatval <= arg2->floatval);
} else {
ret = 0;
}
}
else if (!inf && strict) {
if ((arg1i == 1 && arg2i != 1) ||
(arg2i == -1 && arg1i != -1)) {
ret = 1;
} else if (arg1i == 0 && arg2i == 0) {
ret = (arg1->floatval > arg2->floatval);
} else {
ret = 0;
}
}
else if (!inf && !strict) {
if (arg1i == 1 || arg2i == -1) {
ret = 1;
} else if (arg1i == 0 && arg2i == 0) {
ret = (arg1->floatval >= arg2->floatval);
} else {
ret = 0;
}
}
}
error:
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
return(ret);
}
void
xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return;
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
ctxt->value->floatval = -ctxt->value->floatval;
}
void
xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr arg;
double val;
arg = valuePop(ctxt);
if (arg == NULL)
XP_ERROR(XPATH_INVALID_OPERAND);
val = xmlXPathCastToNumber(arg);
xmlXPathReleaseObject(ctxt->context, arg);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
ctxt->value->floatval += val;
}
void
xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr arg;
double val;
arg = valuePop(ctxt);
if (arg == NULL)
XP_ERROR(XPATH_INVALID_OPERAND);
val = xmlXPathCastToNumber(arg);
xmlXPathReleaseObject(ctxt->context, arg);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
ctxt->value->floatval -= val;
}
void
xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr arg;
double val;
arg = valuePop(ctxt);
if (arg == NULL)
XP_ERROR(XPATH_INVALID_OPERAND);
val = xmlXPathCastToNumber(arg);
xmlXPathReleaseObject(ctxt->context, arg);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
ctxt->value->floatval *= val;
}
ATTRIBUTE_NO_SANITIZE("float-divide-by-zero")
void
xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr arg;
double val;
arg = valuePop(ctxt);
if (arg == NULL)
XP_ERROR(XPATH_INVALID_OPERAND);
val = xmlXPathCastToNumber(arg);
xmlXPathReleaseObject(ctxt->context, arg);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
ctxt->value->floatval /= val;
}
void
xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
xmlXPathObjectPtr arg;
double arg1, arg2;
arg = valuePop(ctxt);
if (arg == NULL)
XP_ERROR(XPATH_INVALID_OPERAND);
arg2 = xmlXPathCastToNumber(arg);
xmlXPathReleaseObject(ctxt->context, arg);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
arg1 = ctxt->value->floatval;
if (arg2 == 0)
ctxt->value->floatval = xmlXPathNAN;
else {
ctxt->value->floatval = fmod(arg1, arg2);
}
}
typedef xmlNodePtr (*xmlXPathTraversalFunction)
(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
typedef xmlNodePtr (*xmlXPathTraversalFunctionExt)
(xmlNodePtr cur, xmlNodePtr contextNode);
typedef xmlNodeSetPtr (*xmlXPathNodeSetMergeFunction)
(xmlNodeSetPtr, xmlNodeSetPtr);
xmlNodePtr
xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL)
return(ctxt->context->node);
return(NULL);
}
xmlNodePtr
xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL) {
if (ctxt->context->node == NULL) return(NULL);
switch (ctxt->context->node->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_NOTATION_NODE:
case XML_DTD_NODE:
return(ctxt->context->node->children);
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_TYPE_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_HTML_DOCUMENT_NODE:
return(((xmlDocPtr) ctxt->context->node)->children);
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_ENTITY_DECL:
case XML_ATTRIBUTE_NODE:
case XML_NAMESPACE_DECL:
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
return(NULL);
}
return(NULL);
}
if ((cur->type == XML_DOCUMENT_NODE) ||
(cur->type == XML_HTML_DOCUMENT_NODE))
return(NULL);
return(cur->next);
}
static xmlNodePtr
xmlXPathNextChildElement(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL) {
cur = ctxt->context->node;
if (cur == NULL) return(NULL);
switch (cur->type) {
case XML_ELEMENT_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_ENTITY_REF_NODE:
case XML_ENTITY_NODE:
cur = cur->children;
if (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE)
return(cur);
do {
cur = cur->next;
} while ((cur != NULL) &&
(cur->type != XML_ELEMENT_NODE));
return(cur);
}
return(NULL);
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
return(xmlDocGetRootElement((xmlDocPtr) cur));
default:
return(NULL);
}
return(NULL);
}
switch (cur->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_ENTITY_REF_NODE:
case XML_ENTITY_NODE:
case XML_CDATA_SECTION_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_XINCLUDE_END:
break;
default:
return(NULL);
}
if (cur->next != NULL) {
if (cur->next->type == XML_ELEMENT_NODE)
return(cur->next);
cur = cur->next;
do {
cur = cur->next;
} while ((cur != NULL) && (cur->type != XML_ELEMENT_NODE));
return(cur);
}
return(NULL);
}
#if 0
static xmlNodePtr
xmlXPathNextDescendantOrSelfElemParent(xmlNodePtr cur,
xmlNodePtr contextNode)
{
if (cur == NULL) {
if (contextNode == NULL)
return(NULL);
switch (contextNode->type) {
case XML_ELEMENT_NODE:
case XML_XINCLUDE_START:
case XML_DOCUMENT_FRAG_NODE:
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
return(contextNode);
default:
return(NULL);
}
return(NULL);
} else {
xmlNodePtr start = cur;
while (cur != NULL) {
switch (cur->type) {
case XML_ELEMENT_NODE:
case XML_XINCLUDE_START:
case XML_DOCUMENT_FRAG_NODE:
if (cur != start)
return(cur);
if (cur->children != NULL) {
cur = cur->children;
continue;
}
break;
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
if (cur != start)
return(cur);
return(xmlDocGetRootElement((xmlDocPtr) cur));
default:
break;
}
next_sibling:
if ((cur == NULL) || (cur == contextNode))
return(NULL);
if (cur->next != NULL) {
cur = cur->next;
} else {
cur = cur->parent;
goto next_sibling;
}
}
}
return(NULL);
}
#endif
xmlNodePtr
xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL) {
if (ctxt->context->node == NULL)
return(NULL);
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
(ctxt->context->node->type == XML_NAMESPACE_DECL))
return(NULL);
if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
return(ctxt->context->doc->children);
return(ctxt->context->node->children);
}
if (cur->type == XML_NAMESPACE_DECL)
return(NULL);
if (cur->children != NULL) {
if (cur->children->type != XML_ENTITY_DECL) {
cur = cur->children;
if (cur->type != XML_DTD_NODE)
return(cur);
}
}
if (cur == ctxt->context->node) return(NULL);
while (cur->next != NULL) {
cur = cur->next;
if ((cur->type != XML_ENTITY_DECL) &&
(cur->type != XML_DTD_NODE))
return(cur);
}
do {
cur = cur->parent;
if (cur == NULL) break;
if (cur == ctxt->context->node) return(NULL);
if (cur->next != NULL) {
cur = cur->next;
return(cur);
}
} while (cur != NULL);
return(cur);
}
xmlNodePtr
xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL)
return(ctxt->context->node);
if (ctxt->context->node == NULL)
return(NULL);
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
(ctxt->context->node->type == XML_NAMESPACE_DECL))
return(NULL);
return(xmlXPathNextDescendant(ctxt, cur));
}
xmlNodePtr
xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL) {
if (ctxt->context->node == NULL) return(NULL);
switch (ctxt->context->node->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_NOTATION_NODE:
case XML_DTD_NODE:
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
case XML_ENTITY_DECL:
if (ctxt->context->node->parent == NULL)
return((xmlNodePtr) ctxt->context->doc);
if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
((ctxt->context->node->parent->name[0] == ' ') ||
(xmlStrEqual(ctxt->context->node->parent->name,
BAD_CAST "fake node libxslt"))))
return(NULL);
return(ctxt->context->node->parent);
case XML_ATTRIBUTE_NODE: {
xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
return(att->parent);
}
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_TYPE_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_HTML_DOCUMENT_NODE:
return(NULL);
case XML_NAMESPACE_DECL: {
xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
if ((ns->next != NULL) &&
(ns->next->type != XML_NAMESPACE_DECL))
return((xmlNodePtr) ns->next);
return(NULL);
}
}
}
return(NULL);
}
xmlNodePtr
xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL) {
if (ctxt->context->node == NULL) return(NULL);
switch (ctxt->context->node->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_DTD_NODE:
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_ENTITY_DECL:
case XML_NOTATION_NODE:
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
if (ctxt->context->node->parent == NULL)
return((xmlNodePtr) ctxt->context->doc);
if ((ctxt->context->node->parent->type == XML_ELEMENT_NODE) &&
((ctxt->context->node->parent->name[0] == ' ') ||
(xmlStrEqual(ctxt->context->node->parent->name,
BAD_CAST "fake node libxslt"))))
return(NULL);
return(ctxt->context->node->parent);
case XML_ATTRIBUTE_NODE: {
xmlAttrPtr tmp = (xmlAttrPtr) ctxt->context->node;
return(tmp->parent);
}
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_TYPE_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_HTML_DOCUMENT_NODE:
return(NULL);
case XML_NAMESPACE_DECL: {
xmlNsPtr ns = (xmlNsPtr) ctxt->context->node;
if ((ns->next != NULL) &&
(ns->next->type != XML_NAMESPACE_DECL))
return((xmlNodePtr) ns->next);
return(NULL);
}
}
return(NULL);
}
if (cur == ctxt->context->doc->children)
return((xmlNodePtr) ctxt->context->doc);
if (cur == (xmlNodePtr) ctxt->context->doc)
return(NULL);
switch (cur->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_NOTATION_NODE:
case XML_DTD_NODE:
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_ENTITY_DECL:
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
if (cur->parent == NULL)
return(NULL);
if ((cur->parent->type == XML_ELEMENT_NODE) &&
((cur->parent->name[0] == ' ') ||
(xmlStrEqual(cur->parent->name,
BAD_CAST "fake node libxslt"))))
return(NULL);
return(cur->parent);
case XML_ATTRIBUTE_NODE: {
xmlAttrPtr att = (xmlAttrPtr) cur;
return(att->parent);
}
case XML_NAMESPACE_DECL: {
xmlNsPtr ns = (xmlNsPtr) cur;
if ((ns->next != NULL) &&
(ns->next->type != XML_NAMESPACE_DECL))
return((xmlNodePtr) ns->next);
return(NULL);
}
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_TYPE_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_HTML_DOCUMENT_NODE:
return(NULL);
}
return(NULL);
}
xmlNodePtr
xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL)
return(ctxt->context->node);
return(xmlXPathNextAncestor(ctxt, cur));
}
xmlNodePtr
xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
(ctxt->context->node->type == XML_NAMESPACE_DECL))
return(NULL);
if (cur == (xmlNodePtr) ctxt->context->doc)
return(NULL);
if (cur == NULL)
return(ctxt->context->node->next);
return(cur->next);
}
xmlNodePtr
xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
(ctxt->context->node->type == XML_NAMESPACE_DECL))
return(NULL);
if (cur == (xmlNodePtr) ctxt->context->doc)
return(NULL);
if (cur == NULL)
return(ctxt->context->node->prev);
if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE)) {
cur = cur->prev;
if (cur == NULL)
return(ctxt->context->node->prev);
}
return(cur->prev);
}
xmlNodePtr
xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if ((cur != NULL) && (cur->type != XML_ATTRIBUTE_NODE) &&
(cur->type != XML_NAMESPACE_DECL) && (cur->children != NULL))
return(cur->children);
if (cur == NULL) {
cur = ctxt->context->node;
if (cur->type == XML_ATTRIBUTE_NODE) {
cur = cur->parent;
} else if (cur->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) cur;
if ((ns->next == NULL) ||
(ns->next->type == XML_NAMESPACE_DECL))
return (NULL);
cur = (xmlNodePtr) ns->next;
}
}
if (cur == NULL) return(NULL) ;
if (cur->next != NULL) return(cur->next) ;
do {
cur = cur->parent;
if (cur == NULL) break;
if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
if (cur->next != NULL) return(cur->next);
} while (cur != NULL);
return(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);
if (ancestor->doc != node->doc) return(0);
if (ancestor == (xmlNodePtr) node->doc) return(1);
if (node == (xmlNodePtr) ancestor->doc) return(0);
while (node->parent != NULL) {
if (node->parent == ancestor)
return(1);
node = node->parent;
}
return(0);
}
xmlNodePtr
xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur)
{
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL) {
cur = ctxt->context->node;
if (cur->type == XML_ATTRIBUTE_NODE) {
cur = cur->parent;
} else if (cur->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) cur;
if ((ns->next == NULL) ||
(ns->next->type == XML_NAMESPACE_DECL))
return (NULL);
cur = (xmlNodePtr) ns->next;
}
}
if ((cur == NULL) || (cur->type == XML_NAMESPACE_DECL))
return (NULL);
if ((cur->prev != NULL) && (cur->prev->type == XML_DTD_NODE))
cur = cur->prev;
do {
if (cur->prev != NULL) {
for (cur = cur->prev; cur->last != NULL; cur = cur->last) ;
return (cur);
}
cur = cur->parent;
if (cur == NULL)
return (NULL);
if (cur == ctxt->context->doc->children)
return (NULL);
} while (xmlXPathIsAncestor(cur, ctxt->context->node));
return (cur);
}
static xmlNodePtr
xmlXPathNextPrecedingInternal(xmlXPathParserContextPtr ctxt,
xmlNodePtr cur)
{
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (cur == NULL) {
cur = ctxt->context->node;
if (cur == NULL)
return (NULL);
if (cur->type == XML_ATTRIBUTE_NODE) {
cur = cur->parent;
} else if (cur->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) cur;
if ((ns->next == NULL) ||
(ns->next->type == XML_NAMESPACE_DECL))
return (NULL);
cur = (xmlNodePtr) ns->next;
}
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) {
cur = cur->parent;
if (cur == NULL)
return (NULL);
if (cur == ctxt->context->doc->children)
return (NULL);
if (cur != ctxt->ancestor)
return (cur);
ctxt->ancestor = cur->parent;
}
cur = cur->prev;
while (cur->last != NULL)
cur = cur->last;
return (cur);
}
xmlNodePtr
xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
if (cur == NULL) {
if (ctxt->context->tmpNsList != NULL)
xmlFree(ctxt->context->tmpNsList);
ctxt->context->tmpNsList =
xmlGetNsList(ctxt->context->doc, ctxt->context->node);
ctxt->context->tmpNsNr = 0;
if (ctxt->context->tmpNsList != NULL) {
while (ctxt->context->tmpNsList[ctxt->context->tmpNsNr] != NULL) {
ctxt->context->tmpNsNr++;
}
}
return((xmlNodePtr) xmlXPathXMLNamespace);
}
if (ctxt->context->tmpNsNr > 0) {
return (xmlNodePtr)ctxt->context->tmpNsList[--ctxt->context->tmpNsNr];
} else {
if (ctxt->context->tmpNsList != NULL)
xmlFree(ctxt->context->tmpNsList);
ctxt->context->tmpNsList = NULL;
return(NULL);
}
}
xmlNodePtr
xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
if ((ctxt == NULL) || (ctxt->context == NULL)) return(NULL);
if (ctxt->context->node == NULL)
return(NULL);
if (ctxt->context->node->type != XML_ELEMENT_NODE)
return(NULL);
if (cur == NULL) {
if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
return(NULL);
return((xmlNodePtr)ctxt->context->node->properties);
}
return((xmlNodePtr)cur->next);
}
#define IS_FUNCTION 200
void
xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
if ((ctxt == NULL) || (ctxt->context == NULL))
return;
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
(xmlNodePtr) ctxt->context->doc));
}
void
xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(0);
if (ctxt->context->contextSize >= 0) {
valuePush(ctxt,
xmlXPathCacheNewFloat(ctxt->context,
(double) ctxt->context->contextSize));
} else {
XP_ERROR(XPATH_INVALID_CTXT_SIZE);
}
}
void
xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(0);
if (ctxt->context->proximityPosition >= 0) {
valuePush(ctxt,
xmlXPathCacheNewFloat(ctxt->context,
(double) ctxt->context->proximityPosition));
} else {
XP_ERROR(XPATH_INVALID_CTXT_POSITION);
}
}
void
xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur;
CHECK_ARITY(1);
if ((ctxt->value == NULL) ||
((ctxt->value->type != XPATH_NODESET) &&
(ctxt->value->type != XPATH_XSLT_TREE)))
XP_ERROR(XPATH_INVALID_TYPE);
cur = valuePop(ctxt);
if ((cur == NULL) || (cur->nodesetval == NULL))
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, (double) 0));
else
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
(double) cur->nodesetval->nodeNr));
xmlXPathReleaseObject(ctxt->context, cur);
}
static xmlNodeSetPtr
xmlXPathGetElementsByIds (xmlDocPtr doc, const xmlChar *ids) {
xmlNodeSetPtr ret;
const xmlChar *cur = ids;
xmlChar *ID;
xmlAttrPtr attr;
xmlNodePtr elem = NULL;
if (ids == NULL) return(NULL);
ret = xmlXPathNodeSetCreate(NULL);
if (ret == NULL)
return(ret);
while (IS_BLANK_CH(*cur)) cur++;
while (*cur != 0) {
while ((!IS_BLANK_CH(*cur)) && (*cur != 0))
cur++;
ID = xmlStrndup(ids, cur - ids);
if (ID != NULL) {
attr = xmlGetID(doc, ID);
if (attr != NULL) {
if (attr->type == XML_ATTRIBUTE_NODE)
elem = attr->parent;
else if (attr->type == XML_ELEMENT_NODE)
elem = (xmlNodePtr) attr;
else
elem = NULL;
if (elem != NULL)
xmlXPathNodeSetAdd(ret, elem);
}
xmlFree(ID);
}
while (IS_BLANK_CH(*cur)) cur++;
ids = cur;
}
return(ret);
}
void
xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlChar *tokens;
xmlNodeSetPtr ret;
xmlXPathObjectPtr obj;
CHECK_ARITY(1);
obj = valuePop(ctxt);
if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
if ((obj->type == XPATH_NODESET) || (obj->type == XPATH_XSLT_TREE)) {
xmlNodeSetPtr ns;
int i;
ret = xmlXPathNodeSetCreate(NULL);
if (obj->nodesetval != NULL) {
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
tokens =
xmlXPathCastNodeToString(obj->nodesetval->nodeTab[i]);
ns = xmlXPathGetElementsByIds(ctxt->context->doc, tokens);
ret = xmlXPathNodeSetMerge(ret, ns);
xmlXPathFreeNodeSet(ns);
if (tokens != NULL)
xmlFree(tokens);
}
}
xmlXPathReleaseObject(ctxt->context, obj);
valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
return;
}
obj = xmlXPathCacheConvertString(ctxt->context, obj);
if (obj == NULL) return;
ret = xmlXPathGetElementsByIds(ctxt->context->doc, obj->stringval);
valuePush(ctxt, xmlXPathCacheWrapNodeSet(ctxt->context, ret));
xmlXPathReleaseObject(ctxt->context, obj);
return;
}
void
xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur;
if (ctxt == NULL) return;
if (nargs == 0) {
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
nargs = 1;
}
CHECK_ARITY(1);
if ((ctxt->value == NULL) ||
((ctxt->value->type != XPATH_NODESET) &&
(ctxt->value->type != XPATH_XSLT_TREE)))
XP_ERROR(XPATH_INVALID_TYPE);
cur = valuePop(ctxt);
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
} else {
int i = 0;
switch (cur->nodesetval->nodeTab[i]->type) {
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
case XML_PI_NODE:
if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
else
valuePush(ctxt,
xmlXPathCacheNewString(ctxt->context,
cur->nodesetval->nodeTab[i]->name));
break;
case XML_NAMESPACE_DECL:
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
break;
default:
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
}
}
xmlXPathReleaseObject(ctxt->context, cur);
}
void
xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur;
if (ctxt == NULL) return;
if (nargs == 0) {
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
nargs = 1;
}
CHECK_ARITY(1);
if ((ctxt->value == NULL) ||
((ctxt->value->type != XPATH_NODESET) &&
(ctxt->value->type != XPATH_XSLT_TREE)))
XP_ERROR(XPATH_INVALID_TYPE);
cur = valuePop(ctxt);
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
} else {
int i = 0;
switch (cur->nodesetval->nodeTab[i]->type) {
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
if (cur->nodesetval->nodeTab[i]->ns == NULL)
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
else
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
cur->nodesetval->nodeTab[i]->ns->href));
break;
default:
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
}
}
xmlXPathReleaseObject(ctxt->context, cur);
}
static void
xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs)
{
xmlXPathObjectPtr cur;
if (nargs == 0) {
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
nargs = 1;
}
CHECK_ARITY(1);
if ((ctxt->value == NULL) ||
((ctxt->value->type != XPATH_NODESET) &&
(ctxt->value->type != XPATH_XSLT_TREE)))
XP_ERROR(XPATH_INVALID_TYPE);
cur = valuePop(ctxt);
if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr == 0)) {
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
} else {
int i = 0;
switch (cur->nodesetval->nodeTab[i]->type) {
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
if (cur->nodesetval->nodeTab[i]->name[0] == ' ')
valuePush(ctxt,
xmlXPathCacheNewCString(ctxt->context, ""));
else if ((cur->nodesetval->nodeTab[i]->ns == NULL) ||
(cur->nodesetval->nodeTab[i]->ns->prefix == NULL)) {
valuePush(ctxt,
xmlXPathCacheNewString(ctxt->context,
cur->nodesetval->nodeTab[i]->name));
} else {
xmlChar *fullname;
fullname = xmlBuildQName(cur->nodesetval->nodeTab[i]->name,
cur->nodesetval->nodeTab[i]->ns->prefix,
NULL, 0);
if (fullname == cur->nodesetval->nodeTab[i]->name)
fullname = xmlStrdup(cur->nodesetval->nodeTab[i]->name);
if (fullname == NULL)
xmlXPathPErrMemory(ctxt, NULL);
valuePush(ctxt, xmlXPathCacheWrapString(
ctxt->context, fullname));
}
break;
default:
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
cur->nodesetval->nodeTab[i]));
xmlXPathLocalNameFunction(ctxt, 1);
}
}
xmlXPathReleaseObject(ctxt->context, cur);
}
void
xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur;
if (ctxt == NULL) return;
if (nargs == 0) {
valuePush(ctxt,
xmlXPathCacheWrapString(ctxt->context,
xmlXPathCastNodeToString(ctxt->context->node)));
return;
}
CHECK_ARITY(1);
cur = valuePop(ctxt);
if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
valuePush(ctxt, xmlXPathCacheConvertString(ctxt->context, cur));
}
void
xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur;
if (nargs == 0) {
if ((ctxt == NULL) || (ctxt->context == NULL))
return;
if (ctxt->context->node == NULL) {
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0));
} else {
xmlChar *content;
content = xmlXPathCastNodeToString(ctxt->context->node);
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
xmlUTF8Strlen(content)));
xmlFree(content);
}
return;
}
CHECK_ARITY(1);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING);
cur = valuePop(ctxt);
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context,
xmlUTF8Strlen(cur->stringval)));
xmlXPathReleaseObject(ctxt->context, cur);
}
void
xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur, newobj;
xmlChar *tmp;
if (ctxt == NULL) return;
if (nargs < 2) {
CHECK_ARITY(2);
}
CAST_TO_STRING;
cur = valuePop(ctxt);
if ((cur == NULL) || (cur->type != XPATH_STRING)) {
xmlXPathReleaseObject(ctxt->context, cur);
return;
}
nargs--;
while (nargs > 0) {
CAST_TO_STRING;
newobj = valuePop(ctxt);
if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
xmlXPathReleaseObject(ctxt->context, newobj);
xmlXPathReleaseObject(ctxt->context, cur);
XP_ERROR(XPATH_INVALID_TYPE);
}
tmp = xmlStrcat(newobj->stringval, cur->stringval);
newobj->stringval = cur->stringval;
cur->stringval = tmp;
xmlXPathReleaseObject(ctxt->context, newobj);
nargs--;
}
valuePush(ctxt, cur);
}
void
xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr hay, needle;
CHECK_ARITY(2);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING);
needle = valuePop(ctxt);
CAST_TO_STRING;
hay = valuePop(ctxt);
if ((hay == NULL) || (hay->type != XPATH_STRING)) {
xmlXPathReleaseObject(ctxt->context, hay);
xmlXPathReleaseObject(ctxt->context, needle);
XP_ERROR(XPATH_INVALID_TYPE);
}
if (xmlStrstr(hay->stringval, needle->stringval))
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
else
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
xmlXPathReleaseObject(ctxt->context, hay);
xmlXPathReleaseObject(ctxt->context, needle);
}
void
xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr hay, needle;
int n;
CHECK_ARITY(2);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING);
needle = valuePop(ctxt);
CAST_TO_STRING;
hay = valuePop(ctxt);
if ((hay == NULL) || (hay->type != XPATH_STRING)) {
xmlXPathReleaseObject(ctxt->context, hay);
xmlXPathReleaseObject(ctxt->context, needle);
XP_ERROR(XPATH_INVALID_TYPE);
}
n = xmlStrlen(needle->stringval);
if (xmlStrncmp(hay->stringval, needle->stringval, n))
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
else
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
xmlXPathReleaseObject(ctxt->context, hay);
xmlXPathReleaseObject(ctxt->context, needle);
}
void
xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr str, start, len;
double le=0, in;
int i = 1, j = INT_MAX;
if (nargs < 2) {
CHECK_ARITY(2);
}
if (nargs > 3) {
CHECK_ARITY(3);
}
if (nargs == 3) {
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
len = valuePop(ctxt);
le = len->floatval;
xmlXPathReleaseObject(ctxt->context, len);
}
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
start = valuePop(ctxt);
in = start->floatval;
xmlXPathReleaseObject(ctxt->context, start);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING);
str = valuePop(ctxt);
if (!(in < INT_MAX)) {
i = INT_MAX;
} else if (in >= 1.0) {
i = (int)in;
if (in - floor(in) >= 0.5)
i += 1;
}
if (nargs == 3) {
double rin, rle, end;
rin = floor(in);
if (in - rin >= 0.5)
rin += 1.0;
rle = floor(le);
if (le - rle >= 0.5)
rle += 1.0;
end = rin + rle;
if (!(end >= 1.0)) {
j = 1;
} else if (end < INT_MAX) {
j = (int)end;
}
}
if (i < j) {
xmlChar *ret = xmlUTF8Strsub(str->stringval, i - 1, j - i);
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context, ret));
xmlFree(ret);
} else {
valuePush(ctxt, xmlXPathCacheNewCString(ctxt->context, ""));
}
xmlXPathReleaseObject(ctxt->context, str);
}
void
xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr str;
xmlXPathObjectPtr find;
xmlBufPtr target;
const xmlChar *point;
int offset;
CHECK_ARITY(2);
CAST_TO_STRING;
find = valuePop(ctxt);
CAST_TO_STRING;
str = valuePop(ctxt);
target = xmlBufCreate();
if (target) {
point = xmlStrstr(str->stringval, find->stringval);
if (point) {
offset = point - str->stringval;
xmlBufAdd(target, str->stringval, offset);
}
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
xmlBufContent(target)));
xmlBufFree(target);
}
xmlXPathReleaseObject(ctxt->context, str);
xmlXPathReleaseObject(ctxt->context, find);
}
void
xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr str;
xmlXPathObjectPtr find;
xmlBufPtr target;
const xmlChar *point;
int offset;
CHECK_ARITY(2);
CAST_TO_STRING;
find = valuePop(ctxt);
CAST_TO_STRING;
str = valuePop(ctxt);
target = xmlBufCreate();
if (target) {
point = xmlStrstr(str->stringval, find->stringval);
if (point) {
offset = point - str->stringval + xmlStrlen(find->stringval);
xmlBufAdd(target, &str->stringval[offset],
xmlStrlen(str->stringval) - offset);
}
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
xmlBufContent(target)));
xmlBufFree(target);
}
xmlXPathReleaseObject(ctxt->context, str);
xmlXPathReleaseObject(ctxt->context, find);
}
void
xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlChar *source, *target;
int blank;
if (ctxt == NULL) return;
if (nargs == 0) {
valuePush(ctxt,
xmlXPathCacheWrapString(ctxt->context,
xmlXPathCastNodeToString(ctxt->context->node)));
nargs = 1;
}
CHECK_ARITY(1);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING);
source = ctxt->value->stringval;
if (source == NULL)
return;
target = source;
while (IS_BLANK_CH(*source))
source++;
blank = 0;
while (*source) {
if (IS_BLANK_CH(*source)) {
blank = 1;
} else {
if (blank) {
*target++ = 0x20;
blank = 0;
}
*target++ = *source;
}
source++;
}
*target = 0;
}
void
xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr str;
xmlXPathObjectPtr from;
xmlXPathObjectPtr to;
xmlBufPtr target;
int offset, max;
int ch;
const xmlChar *point;
xmlChar *cptr;
CHECK_ARITY(3);
CAST_TO_STRING;
to = valuePop(ctxt);
CAST_TO_STRING;
from = valuePop(ctxt);
CAST_TO_STRING;
str = valuePop(ctxt);
target = xmlBufCreate();
if (target) {
max = xmlUTF8Strlen(to->stringval);
for (cptr = str->stringval; (ch=*cptr); ) {
offset = xmlUTF8Strloc(from->stringval, cptr);
if (offset >= 0) {
if (offset < max) {
point = xmlUTF8Strpos(to->stringval, offset);
if (point)
xmlBufAdd(target, point, xmlUTF8Strsize(point, 1));
}
} else
xmlBufAdd(target, cptr, xmlUTF8Strsize(cptr, 1));
cptr++;
if ( ch & 0x80 ) {
if ( (ch & 0xc0) != 0xc0 ) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathTranslateFunction: Invalid UTF8 string\n");
break;
}
while ( (ch <<= 1) & 0x80 )
if ( (*cptr++ & 0xc0) != 0x80 ) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathTranslateFunction: Invalid UTF8 string\n");
break;
}
if (ch & 0x80)
break;
}
}
}
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
xmlBufContent(target)));
xmlBufFree(target);
xmlXPathReleaseObject(ctxt->context, str);
xmlXPathReleaseObject(ctxt->context, from);
xmlXPathReleaseObject(ctxt->context, to);
}
void
xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur;
CHECK_ARITY(1);
cur = valuePop(ctxt);
if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
cur = xmlXPathCacheConvertBoolean(ctxt->context, cur);
valuePush(ctxt, cur);
}
void
xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(1);
CAST_TO_BOOLEAN;
CHECK_TYPE(XPATH_BOOLEAN);
ctxt->value->boolval = ! ctxt->value->boolval;
}
void
xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(0);
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 1));
}
void
xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(0);
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, 0));
}
void
xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr val = NULL;
const xmlChar *theLang = NULL;
const xmlChar *lang;
int ret = 0;
int i;
CHECK_ARITY(1);
CAST_TO_STRING;
CHECK_TYPE(XPATH_STRING);
val = valuePop(ctxt);
lang = val->stringval;
theLang = xmlNodeGetLang(ctxt->context->node);
if ((theLang != NULL) && (lang != NULL)) {
for (i = 0;lang[i] != 0;i++)
if (toupper(lang[i]) != toupper(theLang[i]))
goto not_equal;
if ((theLang[i] == 0) || (theLang[i] == '-'))
ret = 1;
}
not_equal:
if (theLang != NULL)
xmlFree((void *)theLang);
xmlXPathReleaseObject(ctxt->context, val);
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
}
void
xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur;
double res;
if (ctxt == NULL) return;
if (nargs == 0) {
if (ctxt->context->node == NULL) {
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, 0.0));
} else {
xmlChar* content = xmlNodeGetContent(ctxt->context->node);
res = xmlXPathStringEvalNumber(content);
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
xmlFree(content);
}
return;
}
CHECK_ARITY(1);
cur = valuePop(ctxt);
valuePush(ctxt, xmlXPathCacheConvertNumber(ctxt->context, cur));
}
void
xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr cur;
int i;
double res = 0.0;
CHECK_ARITY(1);
if ((ctxt->value == NULL) ||
((ctxt->value->type != XPATH_NODESET) &&
(ctxt->value->type != XPATH_XSLT_TREE)))
XP_ERROR(XPATH_INVALID_TYPE);
cur = valuePop(ctxt);
if ((cur->nodesetval != NULL) && (cur->nodesetval->nodeNr != 0)) {
for (i = 0; i < cur->nodesetval->nodeNr; i++) {
res += xmlXPathCastNodeToNumber(cur->nodesetval->nodeTab[i]);
}
}
valuePush(ctxt, xmlXPathCacheNewFloat(ctxt->context, res));
xmlXPathReleaseObject(ctxt->context, cur);
}
void
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(1);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
ctxt->value->floatval = floor(ctxt->value->floatval);
}
void
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
CHECK_ARITY(1);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
#ifdef _AIX
ctxt->value->floatval = copysign(ceil(ctxt->value->floatval), ctxt->value->floatval);
#else
ctxt->value->floatval = ceil(ctxt->value->floatval);
#endif
}
void
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
double f;
CHECK_ARITY(1);
CAST_TO_NUMBER;
CHECK_TYPE(XPATH_NUMBER);
f = ctxt->value->floatval;
if ((f >= -0.5) && (f < 0.5)) {
ctxt->value->floatval *= 0.0;
}
else {
double rounded = floor(f);
if (f - rounded >= 0.5)
rounded += 1.0;
ctxt->value->floatval = rounded;
}
}
static void xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort);
static void xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter);
static void xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt);
static void xmlXPathCompRelativeLocationPath(xmlXPathParserContextPtr ctxt);
static xmlChar * xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt,
int qualified);
static int
xmlXPathCurrentChar(xmlXPathParserContextPtr ctxt, int *len) {
unsigned char c;
unsigned int val;
const xmlChar *cur;
if (ctxt == NULL)
return(0);
cur = ctxt->cur;
c = *cur;
if (c & 0x80) {
if ((cur[1] & 0xc0) != 0x80)
goto encoding_error;
if ((c & 0xe0) == 0xe0) {
if ((cur[2] & 0xc0) != 0x80)
goto encoding_error;
if ((c & 0xf0) == 0xf0) {
if (((c & 0xf8) != 0xf0) ||
((cur[3] & 0xc0) != 0x80))
goto encoding_error;
*len = 4;
val = (cur[0] & 0x7) << 18;
val |= (cur[1] & 0x3f) << 12;
val |= (cur[2] & 0x3f) << 6;
val |= cur[3] & 0x3f;
} else {
*len = 3;
val = (cur[0] & 0xf) << 12;
val |= (cur[1] & 0x3f) << 6;
val |= cur[2] & 0x3f;
}
} else {
*len = 2;
val = (cur[0] & 0x1f) << 6;
val |= cur[1] & 0x3f;
}
if (!IS_CHAR(val)) {
XP_ERROR0(XPATH_INVALID_CHAR_ERROR);
}
return(val);
} else {
*len = 1;
return(*cur);
}
encoding_error:
*len = 0;
XP_ERROR0(XPATH_ENCODING_ERROR);
}
xmlChar *
xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
const xmlChar *in;
xmlChar *ret;
int count = 0;
if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
in = ctxt->cur;
if (((*in >= 0x61) && (*in <= 0x7A)) ||
((*in >= 0x41) && (*in <= 0x5A)) ||
(*in == '_')) {
in++;
while (((*in >= 0x61) && (*in <= 0x7A)) ||
((*in >= 0x41) && (*in <= 0x5A)) ||
((*in >= 0x30) && (*in <= 0x39)) ||
(*in == '_') || (*in == '.') ||
(*in == '-'))
in++;
if ((*in == ' ') || (*in == '>') || (*in == '/') ||
(*in == '[') || (*in == ']') || (*in == ':') ||
(*in == '@') || (*in == '*')) {
count = in - ctxt->cur;
if (count == 0)
return(NULL);
ret = xmlStrndup(ctxt->cur, count);
ctxt->cur = in;
return(ret);
}
}
return(xmlXPathParseNameComplex(ctxt, 0));
}
static xmlChar *
xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
xmlChar *ret = NULL;
*prefix = NULL;
ret = xmlXPathParseNCName(ctxt);
if (ret && CUR == ':') {
*prefix = ret;
NEXT;
ret = xmlXPathParseNCName(ctxt);
}
return(ret);
}
xmlChar *
xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
const xmlChar *in;
xmlChar *ret;
size_t count = 0;
if ((ctxt == NULL) || (ctxt->cur == NULL)) return(NULL);
in = ctxt->cur;
if (((*in >= 0x61) && (*in <= 0x7A)) ||
((*in >= 0x41) && (*in <= 0x5A)) ||
(*in == '_') || (*in == ':')) {
in++;
while (((*in >= 0x61) && (*in <= 0x7A)) ||
((*in >= 0x41) && (*in <= 0x5A)) ||
((*in >= 0x30) && (*in <= 0x39)) ||
(*in == '_') || (*in == '-') ||
(*in == ':') || (*in == '.'))
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);
}
}
return(xmlXPathParseNameComplex(ctxt, 1));
}
static xmlChar *
xmlXPathParseNameComplex(xmlXPathParserContextPtr ctxt, int qualified) {
xmlChar buf[XML_MAX_NAMELEN + 5];
int len = 0, l;
int c;
c = CUR_CHAR(l);
if ((c == ' ') || (c == '>') || (c == '/') ||
(c == '[') || (c == ']') || (c == '@') ||
(c == '*') ||
(!IS_LETTER(c) && (c != '_') &&
((!qualified) || (c != ':')))) {
return(NULL);
}
while ((c != ' ') && (c != '>') && (c != '/') &&
((IS_LETTER(c)) || (IS_DIGIT(c)) ||
(c == '.') || (c == '-') ||
(c == '_') || ((qualified) && (c == ':')) ||
(IS_COMBINING(c)) ||
(IS_EXTENDER(c)))) {
COPY_BUF(l,buf,len,c);
NEXTL(l);
c = CUR_CHAR(l);
if (len >= XML_MAX_NAMELEN) {
xmlChar *buffer;
int max = len * 2;
if (len > XML_MAX_NAME_LENGTH) {
XP_ERRORNULL(XPATH_EXPR_ERROR);
}
buffer = (xmlChar *) xmlMallocAtomic(max);
if (buffer == NULL) {
XP_ERRORNULL(XPATH_MEMORY_ERROR);
}
memcpy(buffer, buf, len);
while ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
(c == '.') || (c == '-') ||
(c == '_') || ((qualified) && (c == ':')) ||
(IS_COMBINING(c)) ||
(IS_EXTENDER(c))) {
if (len + 10 > max) {
xmlChar *tmp;
if (max > XML_MAX_NAME_LENGTH) {
xmlFree(buffer);
XP_ERRORNULL(XPATH_EXPR_ERROR);
}
max *= 2;
tmp = (xmlChar *) xmlRealloc(buffer, max);
if (tmp == NULL) {
xmlFree(buffer);
XP_ERRORNULL(XPATH_MEMORY_ERROR);
}
buffer = tmp;
}
COPY_BUF(l,buffer,len,c);
NEXTL(l);
c = CUR_CHAR(l);
}
buffer[len] = 0;
return(buffer);
}
}
if (len == 0)
return(NULL);
return(xmlStrndup(buf, len));
}
#define MAX_FRAC 20
double
xmlXPathStringEvalNumber(const xmlChar *str) {
const xmlChar *cur = str;
double ret;
int ok = 0;
int isneg = 0;
int exponent = 0;
int is_exponent_negative = 0;
#ifdef __GNUC__
unsigned long tmp = 0;
double temp;
#endif
if (cur == NULL) return(0);
while (IS_BLANK_CH(*cur)) cur++;
if (*cur == '-') {
isneg = 1;
cur++;
}
if ((*cur != '.') && ((*cur < '0') || (*cur > '9'))) {
return(xmlXPathNAN);
}
#ifdef __GNUC__
ret = 0;
while ((*cur >= '0') && (*cur <= '9')) {
ret = ret * 10;
tmp = (*cur - '0');
ok = 1;
cur++;
temp = (double) tmp;
ret = ret + temp;
}
#else
ret = 0;
while ((*cur >= '0') && (*cur <= '9')) {
ret = ret * 10 + (*cur - '0');
ok = 1;
cur++;
}
#endif
if (*cur == '.') {
int v, frac = 0, max;
double fraction = 0;
cur++;
if (((*cur < '0') || (*cur > '9')) && (!ok)) {
return(xmlXPathNAN);
}
while (*cur == '0') {
frac = frac + 1;
cur++;
}
max = frac + MAX_FRAC;
while (((*cur >= '0') && (*cur <= '9')) && (frac < max)) {
v = (*cur - '0');
fraction = fraction * 10 + v;
frac = frac + 1;
cur++;
}
fraction /= pow(10.0, frac);
ret = ret + fraction;
while ((*cur >= '0') && (*cur <= '9'))
cur++;
}
if ((*cur == 'e') || (*cur == 'E')) {
cur++;
if (*cur == '-') {
is_exponent_negative = 1;
cur++;
} else if (*cur == '+') {
cur++;
}
while ((*cur >= '0') && (*cur <= '9')) {
if (exponent < 1000000)
exponent = exponent * 10 + (*cur - '0');
cur++;
}
}
while (IS_BLANK_CH(*cur)) cur++;
if (*cur != 0) return(xmlXPathNAN);
if (isneg) ret = -ret;
if (is_exponent_negative) exponent = -exponent;
ret *= pow(10.0, (double)exponent);
return(ret);
}
static void
xmlXPathCompNumber(xmlXPathParserContextPtr ctxt)
{
double ret = 0.0;
int ok = 0;
int exponent = 0;
int is_exponent_negative = 0;
xmlXPathObjectPtr num;
#ifdef __GNUC__
unsigned long tmp = 0;
double temp;
#endif
CHECK_ERROR;
if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
XP_ERROR(XPATH_NUMBER_ERROR);
}
#ifdef __GNUC__
ret = 0;
while ((CUR >= '0') && (CUR <= '9')) {
ret = ret * 10;
tmp = (CUR - '0');
ok = 1;
NEXT;
temp = (double) tmp;
ret = ret + temp;
}
#else
ret = 0;
while ((CUR >= '0') && (CUR <= '9')) {
ret = ret * 10 + (CUR - '0');
ok = 1;
NEXT;
}
#endif
if (CUR == '.') {
int v, frac = 0, max;
double fraction = 0;
NEXT;
if (((CUR < '0') || (CUR > '9')) && (!ok)) {
XP_ERROR(XPATH_NUMBER_ERROR);
}
while (CUR == '0') {
frac = frac + 1;
NEXT;
}
max = frac + MAX_FRAC;
while ((CUR >= '0') && (CUR <= '9') && (frac < max)) {
v = (CUR - '0');
fraction = fraction * 10 + v;
frac = frac + 1;
NEXT;
}
fraction /= pow(10.0, frac);
ret = ret + fraction;
while ((CUR >= '0') && (CUR <= '9'))
NEXT;
}
if ((CUR == 'e') || (CUR == 'E')) {
NEXT;
if (CUR == '-') {
is_exponent_negative = 1;
NEXT;
} else if (CUR == '+') {
NEXT;
}
while ((CUR >= '0') && (CUR <= '9')) {
if (exponent < 1000000)
exponent = exponent * 10 + (CUR - '0');
NEXT;
}
if (is_exponent_negative)
exponent = -exponent;
ret *= pow(10.0, (double) exponent);
}
num = xmlXPathCacheNewFloat(ctxt->context, ret);
if (num == NULL) {
ctxt->error = XPATH_MEMORY_ERROR;
} else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_NUMBER, 0, 0, num,
NULL) == -1) {
xmlXPathReleaseObject(ctxt->context, num);
}
}
static xmlChar *
xmlXPathParseLiteral(xmlXPathParserContextPtr ctxt) {
const xmlChar *q;
xmlChar *ret = NULL;
if (CUR == '"') {
NEXT;
q = CUR_PTR;
while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
NEXT;
if (!IS_CHAR_CH(CUR)) {
XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
} else {
ret = xmlStrndup(q, CUR_PTR - q);
NEXT;
}
} else if (CUR == '\'') {
NEXT;
q = CUR_PTR;
while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
NEXT;
if (!IS_CHAR_CH(CUR)) {
XP_ERRORNULL(XPATH_UNFINISHED_LITERAL_ERROR);
} else {
ret = xmlStrndup(q, CUR_PTR - q);
NEXT;
}
} else {
XP_ERRORNULL(XPATH_START_LITERAL_ERROR);
}
return(ret);
}
static void
xmlXPathCompLiteral(xmlXPathParserContextPtr ctxt) {
const xmlChar *q;
xmlChar *ret = NULL;
xmlXPathObjectPtr lit;
if (CUR == '"') {
NEXT;
q = CUR_PTR;
while ((IS_CHAR_CH(CUR)) && (CUR != '"'))
NEXT;
if (!IS_CHAR_CH(CUR)) {
XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
} else {
ret = xmlStrndup(q, CUR_PTR - q);
NEXT;
}
} else if (CUR == '\'') {
NEXT;
q = CUR_PTR;
while ((IS_CHAR_CH(CUR)) && (CUR != '\''))
NEXT;
if (!IS_CHAR_CH(CUR)) {
XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
} else {
ret = xmlStrndup(q, CUR_PTR - q);
NEXT;
}
} else {
XP_ERROR(XPATH_START_LITERAL_ERROR);
}
if (ret == NULL) {
xmlXPathPErrMemory(ctxt, NULL);
return;
}
lit = xmlXPathCacheNewString(ctxt->context, ret);
if (lit == NULL) {
ctxt->error = XPATH_MEMORY_ERROR;
} else if (PUSH_LONG_EXPR(XPATH_OP_VALUE, XPATH_STRING, 0, 0, lit,
NULL) == -1) {
xmlXPathReleaseObject(ctxt->context, lit);
}
xmlFree(ret);
}
static void
xmlXPathCompVariableReference(xmlXPathParserContextPtr ctxt) {
xmlChar *name;
xmlChar *prefix;
SKIP_BLANKS;
if (CUR != '$') {
XP_ERROR(XPATH_VARIABLE_REF_ERROR);
}
NEXT;
name = xmlXPathParseQName(ctxt, &prefix);
if (name == NULL) {
xmlFree(prefix);
XP_ERROR(XPATH_VARIABLE_REF_ERROR);
}
ctxt->comp->last = -1;
if (PUSH_LONG_EXPR(XPATH_OP_VARIABLE, 0, 0, 0, name, prefix) == -1) {
xmlFree(prefix);
xmlFree(name);
}
SKIP_BLANKS;
if ((ctxt->context != NULL) && (ctxt->context->flags & XML_XPATH_NOVAR)) {
XP_ERROR(XPATH_FORBID_VARIABLE_ERROR);
}
}
int
xmlXPathIsNodeType(const xmlChar *name) {
if (name == NULL)
return(0);
if (xmlStrEqual(name, BAD_CAST "node"))
return(1);
if (xmlStrEqual(name, BAD_CAST "text"))
return(1);
if (xmlStrEqual(name, BAD_CAST "comment"))
return(1);
if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
return(1);
return(0);
}
static void
xmlXPathCompFunctionCall(xmlXPathParserContextPtr ctxt) {
xmlChar *name;
xmlChar *prefix;
int nbargs = 0;
int sort = 1;
name = xmlXPathParseQName(ctxt, &prefix);
if (name == NULL) {
xmlFree(prefix);
XP_ERROR(XPATH_EXPR_ERROR);
}
SKIP_BLANKS;
if (CUR != '(') {
xmlFree(name);
xmlFree(prefix);
XP_ERROR(XPATH_EXPR_ERROR);
}
NEXT;
SKIP_BLANKS;
if ((prefix == NULL) && (name[0] == 'c') &&
xmlStrEqual(name, BAD_CAST "count"))
{
sort = 0;
}
ctxt->comp->last = -1;
if (CUR != ')') {
while (CUR != 0) {
int op1 = ctxt->comp->last;
ctxt->comp->last = -1;
xmlXPathCompileExpr(ctxt, sort);
if (ctxt->error != XPATH_EXPRESSION_OK) {
xmlFree(name);
xmlFree(prefix);
return;
}
PUSH_BINARY_EXPR(XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
nbargs++;
if (CUR == ')') break;
if (CUR != ',') {
xmlFree(name);
xmlFree(prefix);
XP_ERROR(XPATH_EXPR_ERROR);
}
NEXT;
SKIP_BLANKS;
}
}
if (PUSH_LONG_EXPR(XPATH_OP_FUNCTION, nbargs, 0, 0, name, prefix) == -1) {
xmlFree(prefix);
xmlFree(name);
}
NEXT;
SKIP_BLANKS;
}
static void
xmlXPathCompPrimaryExpr(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
if (CUR == '$') xmlXPathCompVariableReference(ctxt);
else if (CUR == '(') {
NEXT;
SKIP_BLANKS;
xmlXPathCompileExpr(ctxt, 1);
CHECK_ERROR;
if (CUR != ')') {
XP_ERROR(XPATH_EXPR_ERROR);
}
NEXT;
SKIP_BLANKS;
} else if (IS_ASCII_DIGIT(CUR) || (CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
xmlXPathCompNumber(ctxt);
} else if ((CUR == '\'') || (CUR == '"')) {
xmlXPathCompLiteral(ctxt);
} else {
xmlXPathCompFunctionCall(ctxt);
}
SKIP_BLANKS;
}
static void
xmlXPathCompFilterExpr(xmlXPathParserContextPtr ctxt) {
xmlXPathCompPrimaryExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while (CUR == '[') {
xmlXPathCompPredicate(ctxt, 1);
SKIP_BLANKS;
}
}
static xmlChar *
xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
int l;
int c;
const xmlChar *cur;
xmlChar *ret;
cur = ctxt->cur;
c = CUR_CHAR(l);
if ((c == ' ') || (c == '>') || (c == '/') ||
(!IS_LETTER(c) && (c != '_') &&
(c != ':'))) {
return(NULL);
}
while ((c != ' ') && (c != '>') && (c != '/') &&
((IS_LETTER(c)) || (IS_DIGIT(c)) ||
(c == '.') || (c == '-') ||
(c == '_') || (c == ':') ||
(IS_COMBINING(c)) ||
(IS_EXTENDER(c)))) {
NEXTL(l);
c = CUR_CHAR(l);
}
ret = xmlStrndup(cur, ctxt->cur - cur);
ctxt->cur = cur;
return(ret);
}
static void
xmlXPathCompPathExpr(xmlXPathParserContextPtr ctxt) {
int lc = 1;
xmlChar *name = NULL;
SKIP_BLANKS;
if ((CUR == '$') || (CUR == '(') ||
(IS_ASCII_DIGIT(CUR)) ||
(CUR == '\'') || (CUR == '"') ||
(CUR == '.' && IS_ASCII_DIGIT(NXT(1)))) {
lc = 0;
} else if (CUR == '*') {
lc = 1;
} else if (CUR == '/') {
lc = 1;
} else if (CUR == '@') {
lc = 1;
} else if (CUR == '.') {
lc = 1;
} else {
SKIP_BLANKS;
name = xmlXPathScanName(ctxt);
if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
lc = 1;
xmlFree(name);
} else if (name != NULL) {
int len =xmlStrlen(name);
while (NXT(len) != 0) {
if (NXT(len) == '/') {
lc = 1;
break;
} else if (IS_BLANK_CH(NXT(len))) {
;
} else if (NXT(len) == ':') {
lc = 1;
break;
} else if ((NXT(len) == '(')) {
if (xmlXPathIsNodeType(name)) {
lc = 1;
#ifdef LIBXML_XPTR_LOCS_ENABLED
} else if (ctxt->xptr &&
xmlStrEqual(name, BAD_CAST "range-to")) {
lc = 1;
#endif
} else {
lc = 0;
}
break;
} else if ((NXT(len) == '[')) {
lc = 1;
break;
} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
(NXT(len) == '=')) {
lc = 1;
break;
} else {
lc = 1;
break;
}
len++;
}
if (NXT(len) == 0) {
lc = 1;
}
xmlFree(name);
} else {
XP_ERROR(XPATH_EXPR_ERROR);
}
}
if (lc) {
if (CUR == '/') {
PUSH_LEAVE_EXPR(XPATH_OP_ROOT, 0, 0);
} else {
PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
}
xmlXPathCompLocationPath(ctxt);
} else {
xmlXPathCompFilterExpr(ctxt);
CHECK_ERROR;
if ((CUR == '/') && (NXT(1) == '/')) {
SKIP(2);
SKIP_BLANKS;
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
xmlXPathCompRelativeLocationPath(ctxt);
} else if (CUR == '/') {
xmlXPathCompRelativeLocationPath(ctxt);
}
}
SKIP_BLANKS;
}
static void
xmlXPathCompUnionExpr(xmlXPathParserContextPtr ctxt) {
xmlXPathCompPathExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while (CUR == '|') {
int op1 = ctxt->comp->last;
PUSH_LEAVE_EXPR(XPATH_OP_NODE, 0, 0);
NEXT;
SKIP_BLANKS;
xmlXPathCompPathExpr(ctxt);
PUSH_BINARY_EXPR(XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
SKIP_BLANKS;
}
}
static void
xmlXPathCompUnaryExpr(xmlXPathParserContextPtr ctxt) {
int minus = 0;
int found = 0;
SKIP_BLANKS;
while (CUR == '-') {
minus = 1 - minus;
found = 1;
NEXT;
SKIP_BLANKS;
}
xmlXPathCompUnionExpr(ctxt);
CHECK_ERROR;
if (found) {
if (minus)
PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 2, 0);
else
PUSH_UNARY_EXPR(XPATH_OP_PLUS, ctxt->comp->last, 3, 0);
}
}
static void
xmlXPathCompMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
xmlXPathCompUnaryExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == '*') ||
((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
int op = -1;
int op1 = ctxt->comp->last;
if (CUR == '*') {
op = 0;
NEXT;
} else if (CUR == 'd') {
op = 1;
SKIP(3);
} else if (CUR == 'm') {
op = 2;
SKIP(3);
}
SKIP_BLANKS;
xmlXPathCompUnaryExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_MULT, op1, ctxt->comp->last, op, 0);
SKIP_BLANKS;
}
}
static void
xmlXPathCompAdditiveExpr(xmlXPathParserContextPtr ctxt) {
xmlXPathCompMultiplicativeExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == '+') || (CUR == '-')) {
int plus;
int op1 = ctxt->comp->last;
if (CUR == '+') plus = 1;
else plus = 0;
NEXT;
SKIP_BLANKS;
xmlXPathCompMultiplicativeExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_PLUS, op1, ctxt->comp->last, plus, 0);
SKIP_BLANKS;
}
}
static void
xmlXPathCompRelationalExpr(xmlXPathParserContextPtr ctxt) {
xmlXPathCompAdditiveExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == '<') || (CUR == '>')) {
int inf, strict;
int op1 = ctxt->comp->last;
if (CUR == '<') inf = 1;
else inf = 0;
if (NXT(1) == '=') strict = 0;
else strict = 1;
NEXT;
if (!strict) NEXT;
SKIP_BLANKS;
xmlXPathCompAdditiveExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_CMP, op1, ctxt->comp->last, inf, strict);
SKIP_BLANKS;
}
}
static void
xmlXPathCompEqualityExpr(xmlXPathParserContextPtr ctxt) {
xmlXPathCompRelationalExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
int eq;
int op1 = ctxt->comp->last;
if (CUR == '=') eq = 1;
else eq = 0;
NEXT;
if (!eq) NEXT;
SKIP_BLANKS;
xmlXPathCompRelationalExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
SKIP_BLANKS;
}
}
static void
xmlXPathCompAndExpr(xmlXPathParserContextPtr ctxt) {
xmlXPathCompEqualityExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
int op1 = ctxt->comp->last;
SKIP(3);
SKIP_BLANKS;
xmlXPathCompEqualityExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
SKIP_BLANKS;
}
}
static void
xmlXPathCompileExpr(xmlXPathParserContextPtr ctxt, int sort) {
xmlXPathContextPtr xpctxt = ctxt->context;
if (xpctxt != NULL) {
if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
xpctxt->depth += 10;
}
xmlXPathCompAndExpr(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while ((CUR == 'o') && (NXT(1) == 'r')) {
int op1 = ctxt->comp->last;
SKIP(2);
SKIP_BLANKS;
xmlXPathCompAndExpr(ctxt);
CHECK_ERROR;
PUSH_BINARY_EXPR(XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
SKIP_BLANKS;
}
if ((sort) && (ctxt->comp->steps[ctxt->comp->last].op != XPATH_OP_VALUE)) {
PUSH_UNARY_EXPR(XPATH_OP_SORT, ctxt->comp->last , 0, 0);
}
if (xpctxt != NULL)
xpctxt->depth -= 10;
}
static void
xmlXPathCompPredicate(xmlXPathParserContextPtr ctxt, int filter) {
int op1 = ctxt->comp->last;
SKIP_BLANKS;
if (CUR != '[') {
XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
}
NEXT;
SKIP_BLANKS;
ctxt->comp->last = -1;
if (! filter)
xmlXPathCompileExpr(ctxt, 0);
else
xmlXPathCompileExpr(ctxt, 1);
CHECK_ERROR;
if (CUR != ']') {
XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
}
if (filter)
PUSH_BINARY_EXPR(XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
else
PUSH_BINARY_EXPR(XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
NEXT;
SKIP_BLANKS;
}
static xmlChar *
xmlXPathCompNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
xmlXPathTypeVal *type, xmlChar **prefix,
xmlChar *name) {
int blanks;
if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
STRANGE;
return(NULL);
}
*type = (xmlXPathTypeVal) 0;
*test = (xmlXPathTestVal) 0;
*prefix = NULL;
SKIP_BLANKS;
if ((name == NULL) && (CUR == '*')) {
NEXT;
*test = NODE_TEST_ALL;
return(NULL);
}
if (name == NULL)
name = xmlXPathParseNCName(ctxt);
if (name == NULL) {
XP_ERRORNULL(XPATH_EXPR_ERROR);
}
blanks = IS_BLANK_CH(CUR);
SKIP_BLANKS;
if (CUR == '(') {
NEXT;
if (xmlStrEqual(name, BAD_CAST "comment"))
*type = NODE_TYPE_COMMENT;
else if (xmlStrEqual(name, BAD_CAST "node"))
*type = NODE_TYPE_NODE;
else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
*type = NODE_TYPE_PI;
else if (xmlStrEqual(name, BAD_CAST "text"))
*type = NODE_TYPE_TEXT;
else {
if (name != NULL)
xmlFree(name);
XP_ERRORNULL(XPATH_EXPR_ERROR);
}
*test = NODE_TEST_TYPE;
SKIP_BLANKS;
if (*type == NODE_TYPE_PI) {
if (name != NULL)
xmlFree(name);
name = NULL;
if (CUR != ')') {
name = xmlXPathParseLiteral(ctxt);
if (name == NULL) {
XP_ERRORNULL(XPATH_EXPR_ERROR);
}
*test = NODE_TEST_PI;
SKIP_BLANKS;
}
}
if (CUR != ')') {
if (name != NULL)
xmlFree(name);
XP_ERRORNULL(XPATH_UNCLOSED_ERROR);
}
NEXT;
return(name);
}
*test = NODE_TEST_NAME;
if ((!blanks) && (CUR == ':')) {
NEXT;
#if 0
*prefix = xmlXPathNsLookup(ctxt->context, name);
if (name != NULL)
xmlFree(name);
if (*prefix == NULL) {
XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
}
#else
*prefix = name;
#endif
if (CUR == '*') {
NEXT;
*test = NODE_TEST_ALL;
return(NULL);
}
name = xmlXPathParseNCName(ctxt);
if (name == NULL) {
XP_ERRORNULL(XPATH_EXPR_ERROR);
}
}
return(name);
}
static xmlXPathAxisVal
xmlXPathIsAxisName(const xmlChar *name) {
xmlXPathAxisVal ret = (xmlXPathAxisVal) 0;
switch (name[0]) {
case 'a':
if (xmlStrEqual(name, BAD_CAST "ancestor"))
ret = AXIS_ANCESTOR;
if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
ret = AXIS_ANCESTOR_OR_SELF;
if (xmlStrEqual(name, BAD_CAST "attribute"))
ret = AXIS_ATTRIBUTE;
break;
case 'c':
if (xmlStrEqual(name, BAD_CAST "child"))
ret = AXIS_CHILD;
break;
case 'd':
if (xmlStrEqual(name, BAD_CAST "descendant"))
ret = AXIS_DESCENDANT;
if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
ret = AXIS_DESCENDANT_OR_SELF;
break;
case 'f':
if (xmlStrEqual(name, BAD_CAST "following"))
ret = AXIS_FOLLOWING;
if (xmlStrEqual(name, BAD_CAST "following-sibling"))
ret = AXIS_FOLLOWING_SIBLING;
break;
case 'n':
if (xmlStrEqual(name, BAD_CAST "namespace"))
ret = AXIS_NAMESPACE;
break;
case 'p':
if (xmlStrEqual(name, BAD_CAST "parent"))
ret = AXIS_PARENT;
if (xmlStrEqual(name, BAD_CAST "preceding"))
ret = AXIS_PRECEDING;
if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
ret = AXIS_PRECEDING_SIBLING;
break;
case 's':
if (xmlStrEqual(name, BAD_CAST "self"))
ret = AXIS_SELF;
break;
}
return(ret);
}
static void
xmlXPathCompStep(xmlXPathParserContextPtr ctxt) {
#ifdef LIBXML_XPTR_LOCS_ENABLED
int rangeto = 0;
int op2 = -1;
#endif
SKIP_BLANKS;
if ((CUR == '.') && (NXT(1) == '.')) {
SKIP(2);
SKIP_BLANKS;
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_PARENT,
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
} else if (CUR == '.') {
NEXT;
SKIP_BLANKS;
} else {
xmlChar *name = NULL;
xmlChar *prefix = NULL;
xmlXPathTestVal test = (xmlXPathTestVal) 0;
xmlXPathAxisVal axis = (xmlXPathAxisVal) 0;
xmlXPathTypeVal type = (xmlXPathTypeVal) 0;
int op1;
#ifdef LIBXML_XPTR_LOCS_ENABLED
if (ctxt->xptr) {
name = xmlXPathParseNCName(ctxt);
if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
op2 = ctxt->comp->last;
xmlFree(name);
SKIP_BLANKS;
if (CUR != '(') {
XP_ERROR(XPATH_EXPR_ERROR);
}
NEXT;
SKIP_BLANKS;
xmlXPathCompileExpr(ctxt, 1);
CHECK_ERROR;
SKIP_BLANKS;
if (CUR != ')') {
XP_ERROR(XPATH_EXPR_ERROR);
}
NEXT;
rangeto = 1;
goto eval_predicates;
}
}
#endif
if (CUR == '*') {
axis = AXIS_CHILD;
} else {
if (name == NULL)
name = xmlXPathParseNCName(ctxt);
if (name != NULL) {
axis = xmlXPathIsAxisName(name);
if (axis != 0) {
SKIP_BLANKS;
if ((CUR == ':') && (NXT(1) == ':')) {
SKIP(2);
xmlFree(name);
name = NULL;
} else {
axis = AXIS_CHILD;
}
} else {
axis = AXIS_CHILD;
}
} else if (CUR == '@') {
NEXT;
axis = AXIS_ATTRIBUTE;
} else {
axis = AXIS_CHILD;
}
}
if (ctxt->error != XPATH_EXPRESSION_OK) {
xmlFree(name);
return;
}
name = xmlXPathCompNodeTest(ctxt, &test, &type, &prefix, name);
if (test == 0)
return;
if ((prefix != NULL) && (ctxt->context != NULL) &&
(ctxt->context->flags & XML_XPATH_CHECKNS)) {
if (xmlXPathNsLookup(ctxt->context, prefix) == NULL) {
xmlXPathErr(ctxt, XPATH_UNDEF_PREFIX_ERROR);
}
}
#ifdef LIBXML_XPTR_LOCS_ENABLED
eval_predicates:
#endif
op1 = ctxt->comp->last;
ctxt->comp->last = -1;
SKIP_BLANKS;
while (CUR == '[') {
xmlXPathCompPredicate(ctxt, 0);
}
#ifdef LIBXML_XPTR_LOCS_ENABLED
if (rangeto) {
PUSH_BINARY_EXPR(XPATH_OP_RANGETO, op2, op1, 0, 0);
} else
#endif
if (PUSH_FULL_EXPR(XPATH_OP_COLLECT, op1, ctxt->comp->last, axis,
test, type, (void *)prefix, (void *)name) == -1) {
xmlFree(prefix);
xmlFree(name);
}
}
}
static void
xmlXPathCompRelativeLocationPath
(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
if ((CUR == '/') && (NXT(1) == '/')) {
SKIP(2);
SKIP_BLANKS;
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
} else if (CUR == '/') {
NEXT;
SKIP_BLANKS;
}
xmlXPathCompStep(ctxt);
CHECK_ERROR;
SKIP_BLANKS;
while (CUR == '/') {
if ((CUR == '/') && (NXT(1) == '/')) {
SKIP(2);
SKIP_BLANKS;
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
xmlXPathCompStep(ctxt);
} else if (CUR == '/') {
NEXT;
SKIP_BLANKS;
xmlXPathCompStep(ctxt);
}
SKIP_BLANKS;
}
}
static void
xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
SKIP_BLANKS;
if (CUR != '/') {
xmlXPathCompRelativeLocationPath(ctxt);
} else {
while (CUR == '/') {
if ((CUR == '/') && (NXT(1) == '/')) {
SKIP(2);
SKIP_BLANKS;
PUSH_LONG_EXPR(XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF,
NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
xmlXPathCompRelativeLocationPath(ctxt);
} else if (CUR == '/') {
NEXT;
SKIP_BLANKS;
if ((CUR != 0) &&
((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
(CUR == '_') || (CUR == '.') ||
(CUR == '@') || (CUR == '*')))
xmlXPathCompRelativeLocationPath(ctxt);
}
CHECK_ERROR;
}
}
}
static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op);
static void
xmlXPathNodeSetFilter(xmlXPathParserContextPtr ctxt,
xmlNodeSetPtr set,
int filterOpIndex,
int minPos, int maxPos,
int hasNsNodes)
{
xmlXPathContextPtr xpctxt;
xmlNodePtr oldnode;
xmlDocPtr olddoc;
xmlXPathStepOpPtr filterOp;
int oldcs, oldpp;
int i, j, pos;
if ((set == NULL) || (set->nodeNr == 0))
return;
if (set->nodeNr < minPos) {
xmlXPathNodeSetClear(set, hasNsNodes);
return;
}
xpctxt = ctxt->context;
oldnode = xpctxt->node;
olddoc = xpctxt->doc;
oldcs = xpctxt->contextSize;
oldpp = xpctxt->proximityPosition;
filterOp = &ctxt->comp->steps[filterOpIndex];
xpctxt->contextSize = set->nodeNr;
for (i = 0, j = 0, pos = 1; i < set->nodeNr; i++) {
xmlNodePtr node = set->nodeTab[i];
int res;
xpctxt->node = node;
xpctxt->proximityPosition = i + 1;
if ((node->type != XML_NAMESPACE_DECL) &&
(node->doc != NULL))
xpctxt->doc = node->doc;
res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
if (ctxt->error != XPATH_EXPRESSION_OK)
break;
if (res < 0) {
xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
break;
}
if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
if (i != j) {
set->nodeTab[j] = node;
set->nodeTab[i] = NULL;
}
j += 1;
} else {
set->nodeTab[i] = NULL;
if (node->type == XML_NAMESPACE_DECL)
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
}
if (res != 0) {
if (pos == maxPos) {
i += 1;
break;
}
pos += 1;
}
}
if (hasNsNodes) {
for (; i < set->nodeNr; i++) {
xmlNodePtr node = set->nodeTab[i];
if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
xmlXPathNodeSetFreeNs((xmlNsPtr) node);
}
}
set->nodeNr = j;
if ((set->nodeMax > XML_NODESET_DEFAULT) &&
(set->nodeNr < set->nodeMax / 2)) {
xmlNodePtr *tmp;
int nodeMax = set->nodeNr;
if (nodeMax < XML_NODESET_DEFAULT)
nodeMax = XML_NODESET_DEFAULT;
tmp = (xmlNodePtr *) xmlRealloc(set->nodeTab,
nodeMax * sizeof(xmlNodePtr));
if (tmp == NULL) {
xmlXPathPErrMemory(ctxt, "shrinking nodeset\n");
} else {
set->nodeTab = tmp;
set->nodeMax = nodeMax;
}
}
xpctxt->node = oldnode;
xpctxt->doc = olddoc;
xpctxt->contextSize = oldcs;
xpctxt->proximityPosition = oldpp;
}
#ifdef LIBXML_XPTR_LOCS_ENABLED
static void
xmlXPathLocationSetFilter(xmlXPathParserContextPtr ctxt,
xmlLocationSetPtr locset,
int filterOpIndex,
int minPos, int maxPos)
{
xmlXPathContextPtr xpctxt;
xmlNodePtr oldnode;
xmlDocPtr olddoc;
xmlXPathStepOpPtr filterOp;
int oldcs, oldpp;
int i, j, pos;
if ((locset == NULL) || (locset->locNr == 0) || (filterOpIndex == -1))
return;
xpctxt = ctxt->context;
oldnode = xpctxt->node;
olddoc = xpctxt->doc;
oldcs = xpctxt->contextSize;
oldpp = xpctxt->proximityPosition;
filterOp = &ctxt->comp->steps[filterOpIndex];
xpctxt->contextSize = locset->locNr;
for (i = 0, j = 0, pos = 1; i < locset->locNr; i++) {
xmlNodePtr contextNode = locset->locTab[i]->user;
int res;
xpctxt->node = contextNode;
xpctxt->proximityPosition = i + 1;
if ((contextNode->type != XML_NAMESPACE_DECL) &&
(contextNode->doc != NULL))
xpctxt->doc = contextNode->doc;
res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
if (ctxt->error != XPATH_EXPRESSION_OK)
break;
if (res < 0) {
xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
break;
}
if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
if (i != j) {
locset->locTab[j] = locset->locTab[i];
locset->locTab[i] = NULL;
}
j += 1;
} else {
xmlXPathFreeObject(locset->locTab[i]);
locset->locTab[i] = NULL;
}
if (res != 0) {
if (pos == maxPos) {
i += 1;
break;
}
pos += 1;
}
}
for (; i < locset->locNr; i++)
xmlXPathFreeObject(locset->locTab[i]);
locset->locNr = j;
if ((locset->locMax > XML_NODESET_DEFAULT) &&
(locset->locNr < locset->locMax / 2)) {
xmlXPathObjectPtr *tmp;
int locMax = locset->locNr;
if (locMax < XML_NODESET_DEFAULT)
locMax = XML_NODESET_DEFAULT;
tmp = (xmlXPathObjectPtr *) xmlRealloc(locset->locTab,
locMax * sizeof(xmlXPathObjectPtr));
if (tmp == NULL) {
xmlXPathPErrMemory(ctxt, "shrinking locset\n");
} else {
locset->locTab = tmp;
locset->locMax = locMax;
}
}
xpctxt->node = oldnode;
xpctxt->doc = olddoc;
xpctxt->contextSize = oldcs;
xpctxt->proximityPosition = oldpp;
}
#endif
static void
xmlXPathCompOpEvalPredicate(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op,
xmlNodeSetPtr set,
int minPos, int maxPos,
int hasNsNodes)
{
if (op->ch1 != -1) {
xmlXPathCompExprPtr comp = ctxt->comp;
if (comp->steps[op->ch1].op != XPATH_OP_PREDICATE) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompOpEvalPredicate: Expected a predicate\n");
XP_ERROR(XPATH_INVALID_OPERAND);
}
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
xmlXPathCompOpEvalPredicate(ctxt, &comp->steps[op->ch1], set,
1, set->nodeNr, hasNsNodes);
ctxt->context->depth -= 1;
CHECK_ERROR;
}
if (op->ch2 != -1)
xmlXPathNodeSetFilter(ctxt, set, op->ch2, minPos, maxPos, hasNsNodes);
}
static int
xmlXPathIsPositionalPredicate(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op,
int *maxPos)
{
xmlXPathStepOpPtr exprOp;
if ((op->op != XPATH_OP_PREDICATE) && (op->op != XPATH_OP_FILTER))
return(0);
if (op->ch2 != -1) {
exprOp = &ctxt->comp->steps[op->ch2];
} else
return(0);
if ((exprOp != NULL) &&
(exprOp->op == XPATH_OP_VALUE) &&
(exprOp->value4 != NULL) &&
(((xmlXPathObjectPtr) exprOp->value4)->type == XPATH_NUMBER))
{
double floatval = ((xmlXPathObjectPtr) exprOp->value4)->floatval;
if ((floatval > INT_MIN) && (floatval < INT_MAX)) {
*maxPos = (int) floatval;
if (floatval == (double) *maxPos)
return(1);
}
}
return(0);
}
static int
xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op,
xmlNodePtr * first, xmlNodePtr * last,
int toBool)
{
#define XP_TEST_HIT \
if (hasAxisRange != 0) { \
if (++pos == maxPos) { \
if (addNode(seq, cur) < 0) \
ctxt->error = XPATH_MEMORY_ERROR; \
goto axis_range_end; } \
} else { \
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; \
if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
ctxt->error = XPATH_MEMORY_ERROR; \
goto axis_range_end; } \
} else { \
hasNsNodes = 1; \
if (xmlXPathNodeSetAddNs(seq, xpctxt->node, (xmlNsPtr) cur) < 0) \
ctxt->error = XPATH_MEMORY_ERROR; \
if (breakOnFirstHit) goto first_hit; }
xmlXPathAxisVal axis = (xmlXPathAxisVal) op->value;
xmlXPathTestVal test = (xmlXPathTestVal) op->value2;
xmlXPathTypeVal type = (xmlXPathTypeVal) op->value3;
const xmlChar *prefix = op->value4;
const xmlChar *name = op->value5;
const xmlChar *URI = NULL;
int total = 0, hasNsNodes = 0;
xmlXPathObjectPtr obj;
xmlNodeSetPtr contextSeq;
int contextIdx;
xmlNodePtr contextNode;
xmlNodeSetPtr outSeq;
xmlNodeSetPtr seq;
xmlNodePtr cur;
xmlXPathStepOpPtr predOp;
int maxPos;
int hasPredicateRange, hasAxisRange, pos;
int breakOnFirstHit;
xmlXPathTraversalFunction next = NULL;
int (*addNode) (xmlNodeSetPtr, xmlNodePtr);
xmlXPathNodeSetMergeFunction mergeAndClear;
xmlNodePtr oldContextNode;
xmlXPathContextPtr xpctxt = ctxt->context;
CHECK_TYPE0(XPATH_NODESET);
obj = valuePop(ctxt);
if (prefix != NULL) {
URI = xmlXPathNsLookup(xpctxt, prefix);
if (URI == NULL) {
xmlXPathReleaseObject(xpctxt, obj);
XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
}
}
mergeAndClear = xmlXPathNodeSetMergeAndClear;
switch (axis) {
case AXIS_ANCESTOR:
first = NULL;
next = xmlXPathNextAncestor;
break;
case AXIS_ANCESTOR_OR_SELF:
first = NULL;
next = xmlXPathNextAncestorOrSelf;
break;
case AXIS_ATTRIBUTE:
first = NULL;
last = NULL;
next = xmlXPathNextAttribute;
mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
break;
case AXIS_CHILD:
last = NULL;
if (((test == NODE_TEST_NAME) || (test == NODE_TEST_ALL)) &&
(type == NODE_TYPE_NODE))
{
next = xmlXPathNextChildElement;
} else
next = xmlXPathNextChild;
mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
break;
case AXIS_DESCENDANT:
last = NULL;
next = xmlXPathNextDescendant;
break;
case AXIS_DESCENDANT_OR_SELF:
last = NULL;
next = xmlXPathNextDescendantOrSelf;
break;
case AXIS_FOLLOWING:
last = NULL;
next = xmlXPathNextFollowing;
break;
case AXIS_FOLLOWING_SIBLING:
last = NULL;
next = xmlXPathNextFollowingSibling;
break;
case AXIS_NAMESPACE:
first = NULL;
last = NULL;
next = (xmlXPathTraversalFunction) xmlXPathNextNamespace;
mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
break;
case AXIS_PARENT:
first = NULL;
next = xmlXPathNextParent;
break;
case AXIS_PRECEDING:
first = NULL;
next = xmlXPathNextPrecedingInternal;
break;
case AXIS_PRECEDING_SIBLING:
first = NULL;
next = xmlXPathNextPrecedingSibling;
break;
case AXIS_SELF:
first = NULL;
last = NULL;
next = xmlXPathNextSelf;
mergeAndClear = xmlXPathNodeSetMergeAndClearNoDupls;
break;
}
if (next == NULL) {
xmlXPathReleaseObject(xpctxt, obj);
return(0);
}
contextSeq = obj->nodesetval;
if ((contextSeq == NULL) || (contextSeq->nodeNr <= 0)) {
xmlXPathReleaseObject(xpctxt, obj);
valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, NULL));
return(0);
}
maxPos = 0;
predOp = NULL;
hasPredicateRange = 0;
hasAxisRange = 0;
if (op->ch2 != -1) {
predOp = &ctxt->comp->steps[op->ch2];
if (xmlXPathIsPositionalPredicate(ctxt, predOp, &maxPos)) {
if (predOp->ch1 != -1) {
predOp = &ctxt->comp->steps[predOp->ch1];
hasPredicateRange = 1;
} else {
predOp = NULL;
hasAxisRange = 1;
}
}
}
breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
oldContextNode = xpctxt->node;
addNode = xmlXPathNodeSetAddUnique;
outSeq = NULL;
seq = NULL;
contextNode = NULL;
contextIdx = 0;
while (((contextIdx < contextSeq->nodeNr) || (contextNode != NULL)) &&
(ctxt->error == XPATH_EXPRESSION_OK)) {
xpctxt->node = contextSeq->nodeTab[contextIdx++];
if (seq == NULL) {
seq = xmlXPathNodeSetCreate(NULL);
if (seq == NULL) {
total = 0;
goto error;
}
}
pos = 0;
cur = NULL;
hasNsNodes = 0;
do {
if (OP_LIMIT_EXCEEDED(ctxt, 1))
goto error;
cur = next(ctxt, cur);
if (cur == NULL)
break;
if ((first != NULL) && (*first != NULL)) {
if (*first == cur)
break;
if (((total % 256) == 0) &&
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
(xmlXPathCmpNodesExt(*first, cur) >= 0))
#else
(xmlXPathCmpNodes(*first, cur) >= 0))
#endif
{
break;
}
}
if ((last != NULL) && (*last != NULL)) {
if (*last == cur)
break;
if (((total % 256) == 0) &&
#ifdef XP_OPTIMIZED_NON_ELEM_COMPARISON
(xmlXPathCmpNodesExt(cur, *last) >= 0))
#else
(xmlXPathCmpNodes(cur, *last) >= 0))
#endif
{
break;
}
}
total++;
switch (test) {
case NODE_TEST_NONE:
total = 0;
STRANGE
goto error;
case NODE_TEST_TYPE:
if (type == NODE_TYPE_NODE) {
switch (cur->type) {
case XML_DOCUMENT_NODE:
case XML_HTML_DOCUMENT_NODE:
case XML_ELEMENT_NODE:
case XML_ATTRIBUTE_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
XP_TEST_HIT
break;
case XML_NAMESPACE_DECL: {
if (axis == AXIS_NAMESPACE) {
XP_TEST_HIT_NS
} else {
hasNsNodes = 1;
XP_TEST_HIT
}
break;
}
default:
break;
}
} else if (cur->type == (xmlElementType) type) {
if (cur->type == XML_NAMESPACE_DECL)
XP_TEST_HIT_NS
else
XP_TEST_HIT
} else if ((type == NODE_TYPE_TEXT) &&
(cur->type == XML_CDATA_SECTION_NODE))
{
XP_TEST_HIT
}
break;
case NODE_TEST_PI:
if ((cur->type == XML_PI_NODE) &&
((name == NULL) || xmlStrEqual(name, cur->name)))
{
XP_TEST_HIT
}
break;
case NODE_TEST_ALL:
if (axis == AXIS_ATTRIBUTE) {
if (cur->type == XML_ATTRIBUTE_NODE)
{
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)
{
XP_TEST_HIT_NS
}
} else {
if (cur->type == XML_ELEMENT_NODE) {
if (prefix == NULL)
{
XP_TEST_HIT
} else if ((cur->ns != NULL) &&
(xmlStrEqual(URI, cur->ns->href)))
{
XP_TEST_HIT
}
}
}
break;
case NODE_TEST_NS:{
TODO;
break;
}
case NODE_TEST_NAME:
if (axis == AXIS_ATTRIBUTE) {
if (cur->type != XML_ATTRIBUTE_NODE)
break;
} else if (axis == AXIS_NAMESPACE) {
if (cur->type != XML_NAMESPACE_DECL)
break;
} else {
if (cur->type != XML_ELEMENT_NODE)
break;
}
switch (cur->type) {
case XML_ELEMENT_NODE:
if (xmlStrEqual(name, cur->name)) {
if (prefix == NULL) {
if (cur->ns == NULL)
{
XP_TEST_HIT
}
} else {
if ((cur->ns != NULL) &&
(xmlStrEqual(URI, cur->ns->href)))
{
XP_TEST_HIT
}
}
}
break;
case XML_ATTRIBUTE_NODE:{
xmlAttrPtr attr = (xmlAttrPtr) cur;
if (xmlStrEqual(name, attr->name)) {
if (prefix == NULL) {
if ((attr->ns == NULL) ||
(attr->ns->prefix == NULL))
{
XP_TEST_HIT
}
} else {
if ((attr->ns != NULL) &&
(xmlStrEqual(URI,
attr->ns->href)))
{
XP_TEST_HIT
}
}
}
break;
}
case XML_NAMESPACE_DECL:
if (cur->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns = (xmlNsPtr) cur;
if ((ns->prefix != NULL) && (name != NULL)
&& (xmlStrEqual(ns->prefix, name)))
{
XP_TEST_HIT_NS
}
}
break;
default:
break;
}
break;
}
} while ((cur != NULL) && (ctxt->error == XPATH_EXPRESSION_OK));
goto apply_predicates;
axis_range_end:
if (outSeq == NULL) {
outSeq = seq;
seq = NULL;
} else
outSeq = mergeAndClear(outSeq, seq);
if (toBool)
break;
continue;
first_hit:
if (outSeq == NULL) {
outSeq = seq;
seq = NULL;
} else
outSeq = mergeAndClear(outSeq, seq);
break;
apply_predicates:
if (ctxt->error != XPATH_EXPRESSION_OK)
goto error;
if ((predOp != NULL) && (seq->nodeNr > 0)) {
if (hasPredicateRange != 0)
xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, maxPos, maxPos,
hasNsNodes);
else
xmlXPathCompOpEvalPredicate(ctxt, predOp, seq, 1, seq->nodeNr,
hasNsNodes);
if (ctxt->error != XPATH_EXPRESSION_OK) {
total = 0;
goto error;
}
}
if (seq->nodeNr > 0) {
if (outSeq == NULL) {
outSeq = seq;
seq = NULL;
} else {
outSeq = mergeAndClear(outSeq, seq);
}
if (toBool)
break;
}
}
error:
if ((obj->boolval) && (obj->user != NULL)) {
ctxt->value->boolval = 1;
ctxt->value->user = obj->user;
obj->user = NULL;
obj->boolval = 0;
}
xmlXPathReleaseObject(xpctxt, obj);
if (outSeq == NULL) {
if ((seq != NULL) && (seq->nodeNr == 0))
outSeq = seq;
else
outSeq = xmlXPathNodeSetCreate(NULL);
}
if ((seq != NULL) && (seq != outSeq)) {
xmlXPathFreeNodeSet(seq);
}
valuePush(ctxt, xmlXPathCacheWrapNodeSet(xpctxt, outSeq));
xpctxt->node = oldContextNode;
if (xpctxt->tmpNsList != NULL) {
xmlFree(xpctxt->tmpNsList);
xpctxt->tmpNsList = NULL;
}
return(total);
}
static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op, xmlNodePtr * first);
static int
xmlXPathCompOpEvalFirst(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op, xmlNodePtr * first)
{
int total = 0, cur;
xmlXPathCompExprPtr comp;
xmlXPathObjectPtr arg1, arg2;
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
break;
case XPATH_OP_UNION:
total =
xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
first);
CHECK_ERROR0;
if ((ctxt->value != NULL)
&& (ctxt->value->type == XPATH_NODESET)
&& (ctxt->value->nodesetval != NULL)
&& (ctxt->value->nodesetval->nodeNr >= 1)) {
if (ctxt->value->nodesetval->nodeNr > 1)
xmlXPathNodeSetSort(ctxt->value->nodesetval);
*first = ctxt->value->nodesetval->nodeTab[0];
}
cur =
xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch2],
first);
CHECK_ERROR0;
arg2 = valuePop(ctxt);
arg1 = valuePop(ctxt);
if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
(arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
XP_ERROR0(XPATH_INVALID_TYPE);
}
if ((ctxt->context->opLimit != 0) &&
(((arg1->nodesetval != NULL) &&
(xmlXPathCheckOpLimit(ctxt,
arg1->nodesetval->nodeNr) < 0)) ||
((arg2->nodesetval != NULL) &&
(xmlXPathCheckOpLimit(ctxt,
arg2->nodesetval->nodeNr) < 0)))) {
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
break;
}
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
arg2->nodesetval);
valuePush(ctxt, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
if (total > cur)
xmlXPathCompSwap(op);
total += cur;
break;
case XPATH_OP_ROOT:
xmlXPathRoot(ctxt);
break;
case XPATH_OP_NODE:
if (op->ch1 != -1)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
if (op->ch2 != -1)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
break;
case XPATH_OP_COLLECT:{
if (op->ch1 == -1)
break;
total = xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathNodeCollectAndTest(ctxt, op, first, NULL, 0);
break;
}
case XPATH_OP_VALUE:
valuePush(ctxt,
xmlXPathCacheObjectCopy(ctxt->context,
(xmlXPathObjectPtr) op->value4));
break;
case XPATH_OP_SORT:
if (op->ch1 != -1)
total +=
xmlXPathCompOpEvalFirst(ctxt, &comp->steps[op->ch1],
first);
CHECK_ERROR0;
if ((ctxt->value != NULL)
&& (ctxt->value->type == XPATH_NODESET)
&& (ctxt->value->nodesetval != NULL)
&& (ctxt->value->nodesetval->nodeNr > 1))
xmlXPathNodeSetSort(ctxt->value->nodesetval);
break;
#ifdef XP_OPTIMIZED_FILTER_FIRST
case XPATH_OP_FILTER:
total += xmlXPathCompOpEvalFilterFirst(ctxt, op, first);
break;
#endif
default:
total += xmlXPathCompOpEval(ctxt, op);
break;
}
ctxt->context->depth -= 1;
return(total);
}
static int
xmlXPathCompOpEvalLast(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op,
xmlNodePtr * last)
{
int total = 0, cur;
xmlXPathCompExprPtr comp;
xmlXPathObjectPtr arg1, arg2;
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
break;
case XPATH_OP_UNION:
total =
xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1], last);
CHECK_ERROR0;
if ((ctxt->value != NULL)
&& (ctxt->value->type == XPATH_NODESET)
&& (ctxt->value->nodesetval != NULL)
&& (ctxt->value->nodesetval->nodeNr >= 1)) {
if (ctxt->value->nodesetval->nodeNr > 1)
xmlXPathNodeSetSort(ctxt->value->nodesetval);
*last =
ctxt->value->nodesetval->nodeTab[ctxt->value->
nodesetval->nodeNr -
1];
}
cur =
xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch2], last);
CHECK_ERROR0;
if ((ctxt->value != NULL)
&& (ctxt->value->type == XPATH_NODESET)
&& (ctxt->value->nodesetval != NULL)
&& (ctxt->value->nodesetval->nodeNr >= 1)) {
}
arg2 = valuePop(ctxt);
arg1 = valuePop(ctxt);
if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
(arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
XP_ERROR0(XPATH_INVALID_TYPE);
}
if ((ctxt->context->opLimit != 0) &&
(((arg1->nodesetval != NULL) &&
(xmlXPathCheckOpLimit(ctxt,
arg1->nodesetval->nodeNr) < 0)) ||
((arg2->nodesetval != NULL) &&
(xmlXPathCheckOpLimit(ctxt,
arg2->nodesetval->nodeNr) < 0)))) {
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
break;
}
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
arg2->nodesetval);
valuePush(ctxt, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
if (total > cur)
xmlXPathCompSwap(op);
total += cur;
break;
case XPATH_OP_ROOT:
xmlXPathRoot(ctxt);
break;
case XPATH_OP_NODE:
if (op->ch1 != -1)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
if (op->ch2 != -1)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
break;
case XPATH_OP_COLLECT:{
if (op->ch1 == -1)
break;
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, last, 0);
break;
}
case XPATH_OP_VALUE:
valuePush(ctxt,
xmlXPathCacheObjectCopy(ctxt->context,
(xmlXPathObjectPtr) op->value4));
break;
case XPATH_OP_SORT:
if (op->ch1 != -1)
total +=
xmlXPathCompOpEvalLast(ctxt, &comp->steps[op->ch1],
last);
CHECK_ERROR0;
if ((ctxt->value != NULL)
&& (ctxt->value->type == XPATH_NODESET)
&& (ctxt->value->nodesetval != NULL)
&& (ctxt->value->nodesetval->nodeNr > 1))
xmlXPathNodeSetSort(ctxt->value->nodesetval);
break;
default:
total += xmlXPathCompOpEval(ctxt, op);
break;
}
ctxt->context->depth -= 1;
return (total);
}
#ifdef XP_OPTIMIZED_FILTER_FIRST
static int
xmlXPathCompOpEvalFilterFirst(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op, xmlNodePtr * first)
{
int total = 0;
xmlXPathCompExprPtr comp;
xmlXPathObjectPtr obj;
xmlNodeSetPtr set;
CHECK_ERROR0;
comp = ctxt->comp;
if ((op->ch1 != -1) && (op->ch2 != -1) &&
(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
int f = comp->steps[op->ch2].ch1;
if ((f != -1) &&
(comp->steps[f].op == XPATH_OP_FUNCTION) &&
(comp->steps[f].value5 == NULL) &&
(comp->steps[f].value == 0) &&
(comp->steps[f].value4 != NULL) &&
(xmlStrEqual
(comp->steps[f].value4, BAD_CAST "last"))) {
xmlNodePtr last = NULL;
total +=
xmlXPathCompOpEvalLast(ctxt,
&comp->steps[op->ch1],
&last);
CHECK_ERROR0;
if ((ctxt->value != NULL) &&
(ctxt->value->type == XPATH_NODESET) &&
(ctxt->value->nodesetval != NULL) &&
(ctxt->value->nodesetval->nodeTab != NULL) &&
(ctxt->value->nodesetval->nodeNr > 1)) {
xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
*first = *(ctxt->value->nodesetval->nodeTab);
}
return (total);
}
}
if (op->ch1 != -1)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
if (op->ch2 == -1)
return (total);
if (ctxt->value == NULL)
return (total);
#ifdef LIBXML_XPTR_LOCS_ENABLED
if (ctxt->value->type == XPATH_LOCATIONSET) {
xmlLocationSetPtr locset = ctxt->value->user;
if (locset != NULL) {
xmlXPathLocationSetFilter(ctxt, locset, op->ch2, 1, 1);
if (locset->locNr > 0)
*first = (xmlNodePtr) locset->locTab[0]->user;
}
return (total);
}
#endif
CHECK_TYPE0(XPATH_NODESET);
obj = valuePop(ctxt);
set = obj->nodesetval;
if (set != NULL) {
xmlXPathNodeSetFilter(ctxt, set, op->ch2, 1, 1, 1);
if (set->nodeNr > 0)
*first = set->nodeTab[0];
}
valuePush(ctxt, obj);
return (total);
}
#endif
static int
xmlXPathCompOpEval(xmlXPathParserContextPtr ctxt, xmlXPathStepOpPtr op)
{
int total = 0;
int equal, ret;
xmlXPathCompExprPtr comp;
xmlXPathObjectPtr arg1, arg2;
CHECK_ERROR0;
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
if (ctxt->context->depth >= XPATH_MAX_RECURSION_DEPTH)
XP_ERROR0(XPATH_RECURSION_LIMIT_EXCEEDED);
ctxt->context->depth += 1;
comp = ctxt->comp;
switch (op->op) {
case XPATH_OP_END:
break;
case XPATH_OP_AND:
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
xmlXPathBooleanFunction(ctxt, 1);
if ((ctxt->value == NULL) || (ctxt->value->boolval == 0))
break;
arg2 = valuePop(ctxt);
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
if (ctxt->error) {
xmlXPathFreeObject(arg2);
break;
}
xmlXPathBooleanFunction(ctxt, 1);
if (ctxt->value != NULL)
ctxt->value->boolval &= arg2->boolval;
xmlXPathReleaseObject(ctxt->context, arg2);
break;
case XPATH_OP_OR:
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
xmlXPathBooleanFunction(ctxt, 1);
if ((ctxt->value == NULL) || (ctxt->value->boolval == 1))
break;
arg2 = valuePop(ctxt);
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
if (ctxt->error) {
xmlXPathFreeObject(arg2);
break;
}
xmlXPathBooleanFunction(ctxt, 1);
if (ctxt->value != NULL)
ctxt->value->boolval |= arg2->boolval;
xmlXPathReleaseObject(ctxt->context, arg2);
break;
case XPATH_OP_EQUAL:
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
if (op->value)
equal = xmlXPathEqualValues(ctxt);
else
equal = xmlXPathNotEqualValues(ctxt);
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, equal));
break;
case XPATH_OP_CMP:
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
ret = xmlXPathCompareValues(ctxt, op->value, op->value2);
valuePush(ctxt, xmlXPathCacheNewBoolean(ctxt->context, ret));
break;
case XPATH_OP_PLUS:
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
if (op->ch2 != -1) {
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
}
CHECK_ERROR0;
if (op->value == 0)
xmlXPathSubValues(ctxt);
else if (op->value == 1)
xmlXPathAddValues(ctxt);
else if (op->value == 2)
xmlXPathValueFlipSign(ctxt);
else if (op->value == 3) {
CAST_TO_NUMBER;
CHECK_TYPE0(XPATH_NUMBER);
}
break;
case XPATH_OP_MULT:
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
if (op->value == 0)
xmlXPathMultValues(ctxt);
else if (op->value == 1)
xmlXPathDivValues(ctxt);
else if (op->value == 2)
xmlXPathModValues(ctxt);
break;
case XPATH_OP_UNION:
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
arg2 = valuePop(ctxt);
arg1 = valuePop(ctxt);
if ((arg1 == NULL) || (arg1->type != XPATH_NODESET) ||
(arg2 == NULL) || (arg2->type != XPATH_NODESET)) {
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
XP_ERROR0(XPATH_INVALID_TYPE);
}
if ((ctxt->context->opLimit != 0) &&
(((arg1->nodesetval != NULL) &&
(xmlXPathCheckOpLimit(ctxt,
arg1->nodesetval->nodeNr) < 0)) ||
((arg2->nodesetval != NULL) &&
(xmlXPathCheckOpLimit(ctxt,
arg2->nodesetval->nodeNr) < 0)))) {
xmlXPathReleaseObject(ctxt->context, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
break;
}
if ((arg1->nodesetval == NULL) ||
((arg2->nodesetval != NULL) &&
(arg2->nodesetval->nodeNr != 0)))
{
arg1->nodesetval = xmlXPathNodeSetMerge(arg1->nodesetval,
arg2->nodesetval);
}
valuePush(ctxt, arg1);
xmlXPathReleaseObject(ctxt->context, arg2);
break;
case XPATH_OP_ROOT:
xmlXPathRoot(ctxt);
break;
case XPATH_OP_NODE:
if (op->ch1 != -1)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
if (op->ch2 != -1)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
valuePush(ctxt, xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node));
break;
case XPATH_OP_COLLECT:{
if (op->ch1 == -1)
break;
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
total += xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 0);
break;
}
case XPATH_OP_VALUE:
valuePush(ctxt,
xmlXPathCacheObjectCopy(ctxt->context,
(xmlXPathObjectPtr) op->value4));
break;
case XPATH_OP_VARIABLE:{
xmlXPathObjectPtr val;
if (op->ch1 != -1)
total +=
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
if (op->value5 == NULL) {
val = xmlXPathVariableLookup(ctxt->context, op->value4);
if (val == NULL)
XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
valuePush(ctxt, val);
} else {
const xmlChar *URI;
URI = xmlXPathNsLookup(ctxt->context, op->value5);
if (URI == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompOpEval: variable %s bound to undefined prefix %s\n",
(char *) op->value4, (char *)op->value5);
ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
break;
}
val = xmlXPathVariableLookupNS(ctxt->context,
op->value4, URI);
if (val == NULL)
XP_ERROR0(XPATH_UNDEF_VARIABLE_ERROR);
valuePush(ctxt, val);
}
break;
}
case XPATH_OP_FUNCTION:{
xmlXPathFunction func;
const xmlChar *oldFunc, *oldFuncURI;
int i;
int frame;
frame = ctxt->valueNr;
if (op->ch1 != -1) {
total +=
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
if (ctxt->error != XPATH_EXPRESSION_OK)
break;
}
if (ctxt->valueNr < frame + op->value) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompOpEval: parameter error\n");
ctxt->error = XPATH_INVALID_OPERAND;
break;
}
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;
break;
}
}
if (op->cache != NULL)
func = op->cache;
else {
const xmlChar *URI = NULL;
if (op->value5 == NULL)
func =
xmlXPathFunctionLookup(ctxt->context,
op->value4);
else {
URI = xmlXPathNsLookup(ctxt->context, op->value5);
if (URI == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompOpEval: function %s bound to undefined prefix %s\n",
(char *)op->value4, (char *)op->value5);
ctxt->error = XPATH_UNDEF_PREFIX_ERROR;
break;
}
func = xmlXPathFunctionLookupNS(ctxt->context,
op->value4, URI);
}
if (func == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompOpEval: function %s not found\n",
(char *)op->value4);
XP_ERROR0(XPATH_UNKNOWN_FUNC_ERROR);
}
op->cache = func;
op->cacheURI = (void *) URI;
}
oldFunc = ctxt->context->function;
oldFuncURI = ctxt->context->functionURI;
ctxt->context->function = op->value4;
ctxt->context->functionURI = op->cacheURI;
func(ctxt, op->value);
ctxt->context->function = oldFunc;
ctxt->context->functionURI = oldFuncURI;
if ((ctxt->error == XPATH_EXPRESSION_OK) &&
(ctxt->valueNr != frame + 1))
XP_ERROR0(XPATH_STACK_ERROR);
break;
}
case XPATH_OP_ARG:
if (op->ch1 != -1) {
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
}
if (op->ch2 != -1) {
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch2]);
CHECK_ERROR0;
}
break;
case XPATH_OP_PREDICATE:
case XPATH_OP_FILTER:{
xmlXPathObjectPtr obj;
xmlNodeSetPtr set;
if ((op->ch1 != -1) && (op->ch2 != -1) &&
#ifdef XP_OPTIMIZED_FILTER_FIRST
((comp->steps[op->ch1].op == XPATH_OP_SORT) ||
(comp->steps[op->ch1].op == XPATH_OP_FILTER)) &&
#else
(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
#endif
(comp->steps[op->ch2].op == XPATH_OP_VALUE)) {
xmlXPathObjectPtr val;
val = comp->steps[op->ch2].value4;
if ((val != NULL) && (val->type == XPATH_NUMBER) &&
(val->floatval == 1.0)) {
xmlNodePtr first = NULL;
total +=
xmlXPathCompOpEvalFirst(ctxt,
&comp->steps[op->ch1],
&first);
CHECK_ERROR0;
if ((ctxt->value != NULL) &&
(ctxt->value->type == XPATH_NODESET) &&
(ctxt->value->nodesetval != NULL) &&
(ctxt->value->nodesetval->nodeNr > 1))
xmlXPathNodeSetClearFromPos(ctxt->value->nodesetval,
1, 1);
break;
}
}
if ((op->ch1 != -1) && (op->ch2 != -1) &&
(comp->steps[op->ch1].op == XPATH_OP_SORT) &&
(comp->steps[op->ch2].op == XPATH_OP_SORT)) {
int f = comp->steps[op->ch2].ch1;
if ((f != -1) &&
(comp->steps[f].op == XPATH_OP_FUNCTION) &&
(comp->steps[f].value5 == NULL) &&
(comp->steps[f].value == 0) &&
(comp->steps[f].value4 != NULL) &&
(xmlStrEqual
(comp->steps[f].value4, BAD_CAST "last"))) {
xmlNodePtr last = NULL;
total +=
xmlXPathCompOpEvalLast(ctxt,
&comp->steps[op->ch1],
&last);
CHECK_ERROR0;
if ((ctxt->value != NULL) &&
(ctxt->value->type == XPATH_NODESET) &&
(ctxt->value->nodesetval != NULL) &&
(ctxt->value->nodesetval->nodeTab != NULL) &&
(ctxt->value->nodesetval->nodeNr > 1))
xmlXPathNodeSetKeepLast(ctxt->value->nodesetval);
break;
}
}
if (op->ch1 != -1)
total +=
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
if (op->ch2 == -1)
break;
if (ctxt->value == NULL)
break;
#ifdef LIBXML_XPTR_LOCS_ENABLED
if (ctxt->value->type == XPATH_LOCATIONSET) {
xmlLocationSetPtr locset = ctxt->value->user;
xmlXPathLocationSetFilter(ctxt, locset, op->ch2,
1, locset->locNr);
break;
}
#endif
CHECK_TYPE0(XPATH_NODESET);
obj = valuePop(ctxt);
set = obj->nodesetval;
if (set != NULL)
xmlXPathNodeSetFilter(ctxt, set, op->ch2,
1, set->nodeNr, 1);
valuePush(ctxt, obj);
break;
}
case XPATH_OP_SORT:
if (op->ch1 != -1)
total += xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
if ((ctxt->value != NULL) &&
(ctxt->value->type == XPATH_NODESET) &&
(ctxt->value->nodesetval != NULL) &&
(ctxt->value->nodesetval->nodeNr > 1))
{
xmlXPathNodeSetSort(ctxt->value->nodesetval);
}
break;
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_OP_RANGETO:{
xmlXPathObjectPtr range;
xmlXPathObjectPtr res, obj;
xmlXPathObjectPtr tmp;
xmlLocationSetPtr newlocset = NULL;
xmlLocationSetPtr oldlocset;
xmlNodeSetPtr oldset;
xmlNodePtr oldnode = ctxt->context->node;
int oldcs = ctxt->context->contextSize;
int oldpp = ctxt->context->proximityPosition;
int i, j;
if (op->ch1 != -1) {
total +=
xmlXPathCompOpEval(ctxt, &comp->steps[op->ch1]);
CHECK_ERROR0;
}
if (ctxt->value == NULL) {
XP_ERROR0(XPATH_INVALID_OPERAND);
}
if (op->ch2 == -1)
break;
if (ctxt->value->type == XPATH_LOCATIONSET) {
CHECK_TYPE0(XPATH_LOCATIONSET);
if ((ctxt->value->user == NULL) ||
(((xmlLocationSetPtr) ctxt->value->user)->locNr == 0))
break;
obj = valuePop(ctxt);
oldlocset = obj->user;
newlocset = xmlXPtrLocationSetCreate(NULL);
for (i = 0; i < oldlocset->locNr; i++) {
ctxt->context->node = oldlocset->locTab[i]->user;
ctxt->context->contextSize = oldlocset->locNr;
ctxt->context->proximityPosition = i + 1;
tmp = xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node);
valuePush(ctxt, tmp);
if (op->ch2 != -1)
total +=
xmlXPathCompOpEval(ctxt,
&comp->steps[op->ch2]);
if (ctxt->error != XPATH_EXPRESSION_OK) {
xmlXPtrFreeLocationSet(newlocset);
goto rangeto_error;
}
res = valuePop(ctxt);
if (res->type == XPATH_LOCATIONSET) {
xmlLocationSetPtr rloc =
(xmlLocationSetPtr)res->user;
for (j=0; j<rloc->locNr; j++) {
range = xmlXPtrNewRange(
oldlocset->locTab[i]->user,
oldlocset->locTab[i]->index,
rloc->locTab[j]->user2,
rloc->locTab[j]->index2);
if (range != NULL) {
xmlXPtrLocationSetAdd(newlocset, range);
}
}
} else {
range = xmlXPtrNewRangeNodeObject(
(xmlNodePtr)oldlocset->locTab[i]->user, res);
if (range != NULL) {
xmlXPtrLocationSetAdd(newlocset,range);
}
}
if (res != NULL) {
xmlXPathReleaseObject(ctxt->context, res);
}
if (ctxt->value == tmp) {
res = valuePop(ctxt);
xmlXPathReleaseObject(ctxt->context, res);
}
}
} else {
CHECK_TYPE0(XPATH_NODESET);
obj = valuePop(ctxt);
oldset = obj->nodesetval;
newlocset = xmlXPtrLocationSetCreate(NULL);
if (oldset != NULL) {
for (i = 0; i < oldset->nodeNr; i++) {
ctxt->context->node = oldset->nodeTab[i];
tmp = xmlXPathCacheNewNodeSet(ctxt->context,
ctxt->context->node);
valuePush(ctxt, tmp);
if (op->ch2 != -1)
total +=
xmlXPathCompOpEval(ctxt,
&comp->steps[op->ch2]);
if (ctxt->error != XPATH_EXPRESSION_OK) {
xmlXPtrFreeLocationSet(newlocset);
goto rangeto_error;
}
res = valuePop(ctxt);
range =
xmlXPtrNewRangeNodeObject(oldset->nodeTab[i],
res);
if (range != NULL) {
xmlXPtrLocationSetAdd(newlocset, range);
}
if (res != NULL) {
xmlXPathReleaseObject(ctxt->context, res);
}
if (ctxt->value == tmp) {
res = valuePop(ctxt);
xmlXPathReleaseObject(ctxt->context, res);
}
}
}
}
valuePush(ctxt, xmlXPtrWrapLocationSet(newlocset));
rangeto_error:
xmlXPathReleaseObject(ctxt->context, obj);
ctxt->context->node = oldnode;
ctxt->context->contextSize = oldcs;
ctxt->context->proximityPosition = oldpp;
break;
}
#endif
default:
xmlGenericError(xmlGenericErrorContext,
"XPath: unknown precompiled operation %d\n", op->op);
ctxt->error = XPATH_INVALID_OPERAND;
break;
}
ctxt->context->depth -= 1;
return (total);
}
static int
xmlXPathCompOpEvalToBoolean(xmlXPathParserContextPtr ctxt,
xmlXPathStepOpPtr op,
int isPredicate)
{
xmlXPathObjectPtr resObj = NULL;
start:
if (OP_LIMIT_EXCEEDED(ctxt, 1))
return(0);
switch (op->op) {
case XPATH_OP_END:
return (0);
case XPATH_OP_VALUE:
resObj = (xmlXPathObjectPtr) op->value4;
if (isPredicate)
return(xmlXPathEvaluatePredicateResult(ctxt, resObj));
return(xmlXPathCastToBoolean(resObj));
case XPATH_OP_SORT:
if (op->ch1 != -1) {
op = &ctxt->comp->steps[op->ch1];
goto start;
}
return(0);
case XPATH_OP_COLLECT:
if (op->ch1 == -1)
return(0);
xmlXPathCompOpEval(ctxt, &ctxt->comp->steps[op->ch1]);
if (ctxt->error != XPATH_EXPRESSION_OK)
return(-1);
xmlXPathNodeCollectAndTest(ctxt, op, NULL, NULL, 1);
if (ctxt->error != XPATH_EXPRESSION_OK)
return(-1);
resObj = valuePop(ctxt);
if (resObj == NULL)
return(-1);
break;
default:
xmlXPathCompOpEval(ctxt, op);
if (ctxt->error != XPATH_EXPRESSION_OK)
return(-1);
resObj = valuePop(ctxt);
if (resObj == NULL)
return(-1);
break;
}
if (resObj) {
int res;
if (resObj->type == XPATH_BOOLEAN) {
res = resObj->boolval;
} else if (isPredicate) {
res = xmlXPathEvaluatePredicateResult(ctxt, resObj);
} else {
res = xmlXPathCastToBoolean(resObj);
}
xmlXPathReleaseObject(ctxt->context, resObj);
return(res);
}
return(0);
}
#ifdef XPATH_STREAMING
static int
xmlXPathRunStreamEval(xmlXPathContextPtr ctxt, xmlPatternPtr comp,
xmlXPathObjectPtr *resultSeq, int toBool)
{
int max_depth, min_depth;
int from_root;
int ret, depth;
int eval_all_nodes;
xmlNodePtr cur = NULL, limit = NULL;
xmlStreamCtxtPtr patstream = NULL;
if ((ctxt == NULL) || (comp == NULL))
return(-1);
max_depth = xmlPatternMaxDepth(comp);
if (max_depth == -1)
return(-1);
if (max_depth == -2)
max_depth = 10000;
min_depth = xmlPatternMinDepth(comp);
if (min_depth == -1)
return(-1);
from_root = xmlPatternFromRoot(comp);
if (from_root < 0)
return(-1);
#if 0
printf("stream eval: depth %d from root %d\n", max_depth, from_root);
#endif
if (! toBool) {
if (resultSeq == NULL)
return(-1);
*resultSeq = xmlXPathCacheNewNodeSet(ctxt, NULL);
if (*resultSeq == NULL)
return(-1);
}
if (min_depth == 0) {
if (from_root) {
if (toBool)
return(1);
xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval,
(xmlNodePtr) ctxt->doc);
} else {
if (toBool)
return(1);
xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, ctxt->node);
}
}
if (max_depth == 0) {
return(0);
}
if (from_root) {
cur = (xmlNodePtr)ctxt->doc;
} else if (ctxt->node != NULL) {
switch (ctxt->node->type) {
case XML_ELEMENT_NODE:
case XML_DOCUMENT_NODE:
case XML_DOCUMENT_FRAG_NODE:
case XML_HTML_DOCUMENT_NODE:
cur = ctxt->node;
break;
case XML_ATTRIBUTE_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_ENTITY_REF_NODE:
case XML_ENTITY_NODE:
case XML_PI_NODE:
case XML_COMMENT_NODE:
case XML_NOTATION_NODE:
case XML_DTD_NODE:
case XML_DOCUMENT_TYPE_NODE:
case XML_ELEMENT_DECL:
case XML_ATTRIBUTE_DECL:
case XML_ENTITY_DECL:
case XML_NAMESPACE_DECL:
case XML_XINCLUDE_START:
case XML_XINCLUDE_END:
break;
}
limit = cur;
}
if (cur == NULL) {
return(0);
}
patstream = xmlPatternGetStreamCtxt(comp);
if (patstream == NULL) {
return(0);
}
eval_all_nodes = xmlStreamWantsAnyNode(patstream);
if (from_root) {
ret = xmlStreamPush(patstream, NULL, NULL);
if (ret < 0) {
} else if (ret == 1) {
if (toBool)
goto return_1;
xmlXPathNodeSetAddUnique((*resultSeq)->nodesetval, cur);
}
}
depth = 0;
goto scan_children;
next_node:
do {
if (ctxt->opLimit != 0) {
if (ctxt->opCount >= ctxt->opLimit) {
xmlGenericError(xmlGenericErrorContext,
"XPath operation limit exceeded\n");
xmlFreeStreamCtxt(patstream);
return(-1);
}
ctxt->opCount++;
}
switch (cur->type) {
case XML_ELEMENT_NODE:
case XML_TEXT_NODE:
case XML_CDATA_SECTION_NODE:
case XML_COMMENT_NODE:
case XML_PI_NODE:
if (cur->type == XML_ELEMENT_NODE) {
ret = xmlStreamPush(patstream, cur->name,
(cur->ns ? cur->ns->href : NULL));
} else if (eval_all_nodes)
ret = xmlStreamPushNode(patstream, NULL, NULL, cur->type);
else
break;
if (ret < 0) {
} else if (ret == 1) {
if (toBool)
goto return_1;
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);
while (cur->next != NULL) {
cur = cur->next;
if ((cur->type != XML_ENTITY_DECL) &&
(cur->type != XML_DTD_NODE))
goto next_node;
}
}
default:
break;
}
scan_children:
if (cur->type == XML_NAMESPACE_DECL) break;
if ((cur->children != NULL) && (depth < max_depth)) {
if (cur->children->type != XML_ENTITY_DECL) {
cur = cur->children;
depth++;
if (cur->type != XML_DTD_NODE)
continue;
}
}
if (cur == limit)
break;
while (cur->next != NULL) {
cur = cur->next;
if ((cur->type != XML_ENTITY_DECL) &&
(cur->type != XML_DTD_NODE))
goto next_node;
}
do {
cur = cur->parent;
depth--;
if ((cur == NULL) || (cur == limit) ||
(cur->type == XML_DOCUMENT_NODE))
goto done;
if (cur->type == XML_ELEMENT_NODE) {
ret = xmlStreamPop(patstream);
} else if ((eval_all_nodes) &&
((cur->type == XML_TEXT_NODE) ||
(cur->type == XML_CDATA_SECTION_NODE) ||
(cur->type == XML_COMMENT_NODE) ||
(cur->type == XML_PI_NODE)))
{
ret = xmlStreamPop(patstream);
}
if (cur->next != NULL) {
cur = cur->next;
break;
}
} while (cur != NULL);
} while ((cur != NULL) && (depth >= 0));
done:
if (patstream)
xmlFreeStreamCtxt(patstream);
return(0);
return_1:
if (patstream)
xmlFreeStreamCtxt(patstream);
return(1);
}
#endif
static int
xmlXPathRunEval(xmlXPathParserContextPtr ctxt, int toBool)
{
xmlXPathCompExprPtr comp;
int oldDepth;
if ((ctxt == NULL) || (ctxt->comp == NULL))
return(-1);
if (ctxt->valueTab == NULL) {
ctxt->valueTab = (xmlXPathObjectPtr *)
xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
if (ctxt->valueTab == NULL) {
xmlXPathPErrMemory(ctxt, "creating evaluation context\n");
return(-1);
}
ctxt->valueNr = 0;
ctxt->valueMax = 10;
ctxt->value = NULL;
}
#ifdef XPATH_STREAMING
if (ctxt->comp->stream) {
int res;
if (toBool) {
res = xmlXPathRunStreamEval(ctxt->context,
ctxt->comp->stream, NULL, 1);
if (res != -1)
return(res);
} else {
xmlXPathObjectPtr resObj = NULL;
res = xmlXPathRunStreamEval(ctxt->context,
ctxt->comp->stream, &resObj, 0);
if ((res != -1) && (resObj != NULL)) {
valuePush(ctxt, resObj);
return(0);
}
if (resObj != NULL)
xmlXPathReleaseObject(ctxt->context, resObj);
}
}
#endif
comp = ctxt->comp;
if (comp->last < 0) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathRunEval: last is less than zero\n");
return(-1);
}
oldDepth = ctxt->context->depth;
if (toBool)
return(xmlXPathCompOpEvalToBoolean(ctxt,
&comp->steps[comp->last], 0));
else
xmlXPathCompOpEval(ctxt, &comp->steps[comp->last]);
ctxt->context->depth = oldDepth;
return(0);
}
int
xmlXPathEvalPredicate(xmlXPathContextPtr ctxt, xmlXPathObjectPtr res) {
if ((ctxt == NULL) || (res == NULL)) return(0);
switch (res->type) {
case XPATH_BOOLEAN:
return(res->boolval);
case XPATH_NUMBER:
return(res->floatval == ctxt->proximityPosition);
case XPATH_NODESET:
case XPATH_XSLT_TREE:
if (res->nodesetval == NULL)
return(0);
return(res->nodesetval->nodeNr != 0);
case XPATH_STRING:
return((res->stringval != NULL) &&
(xmlStrlen(res->stringval) != 0));
default:
STRANGE
}
return(0);
}
int
xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt,
xmlXPathObjectPtr res) {
if ((ctxt == NULL) || (res == NULL)) return(0);
switch (res->type) {
case XPATH_BOOLEAN:
return(res->boolval);
case XPATH_NUMBER:
#if defined(__BORLANDC__) || (defined(_MSC_VER) && (_MSC_VER == 1200))
return((res->floatval == ctxt->context->proximityPosition) &&
(!xmlXPathIsNaN(res->floatval)));
#else
return(res->floatval == ctxt->context->proximityPosition);
#endif
case XPATH_NODESET:
case XPATH_XSLT_TREE:
if (res->nodesetval == NULL)
return(0);
return(res->nodesetval->nodeNr != 0);
case XPATH_STRING:
return((res->stringval != NULL) && (res->stringval[0] != 0));
#ifdef LIBXML_XPTR_LOCS_ENABLED
case XPATH_LOCATIONSET:{
xmlLocationSetPtr ptr = res->user;
if (ptr == NULL)
return(0);
return (ptr->locNr != 0);
}
#endif
default:
STRANGE
}
return(0);
}
#ifdef XPATH_STREAMING
static xmlXPathCompExprPtr
xmlXPathTryStreamCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
xmlPatternPtr stream;
xmlXPathCompExprPtr comp;
xmlDictPtr dict = NULL;
const xmlChar **namespaces = NULL;
xmlNsPtr ns;
int i, j;
if ((!xmlStrchr(str, '[')) && (!xmlStrchr(str, '(')) &&
(!xmlStrchr(str, '@'))) {
const xmlChar *tmp;
tmp = xmlStrchr(str, ':');
if ((tmp != NULL) &&
((ctxt == NULL) || (ctxt->nsNr == 0) || (tmp[1] == ':')))
return(NULL);
if (ctxt != NULL) {
dict = ctxt->dict;
if (ctxt->nsNr > 0) {
namespaces = xmlMalloc(2 * (ctxt->nsNr + 1) * sizeof(xmlChar*));
if (namespaces == NULL) {
xmlXPathErrMemory(ctxt, "allocating namespaces array\n");
return(NULL);
}
for (i = 0, j = 0; (j < ctxt->nsNr); j++) {
ns = ctxt->namespaces[j];
namespaces[i++] = ns->href;
namespaces[i++] = ns->prefix;
}
namespaces[i++] = NULL;
namespaces[i] = NULL;
}
}
stream = xmlPatterncompile(str, dict, XML_PATTERN_XPATH, namespaces);
if (namespaces != NULL) {
xmlFree((xmlChar **)namespaces);
}
if ((stream != NULL) && (xmlPatternStreamable(stream) == 1)) {
comp = xmlXPathNewCompExpr();
if (comp == NULL) {
xmlXPathErrMemory(ctxt, "allocating streamable expression\n");
xmlFreePattern(stream);
return(NULL);
}
comp->stream = stream;
comp->dict = dict;
if (comp->dict)
xmlDictReference(comp->dict);
return(comp);
}
xmlFreePattern(stream);
}
return(NULL);
}
#endif
static void
xmlXPathOptimizeExpression(xmlXPathParserContextPtr pctxt,
xmlXPathStepOpPtr op)
{
xmlXPathCompExprPtr comp = pctxt->comp;
xmlXPathContextPtr ctxt;
if ((op->op == XPATH_OP_COLLECT ) &&
(op->ch1 != -1) &&
(op->ch2 == -1 ))
{
xmlXPathStepOpPtr prevop = &comp->steps[op->ch1];
if ((prevop->op == XPATH_OP_COLLECT ) &&
((xmlXPathAxisVal) prevop->value ==
AXIS_DESCENDANT_OR_SELF) &&
(prevop->ch2 == -1) &&
((xmlXPathTestVal) prevop->value2 == NODE_TEST_TYPE) &&
((xmlXPathTypeVal) prevop->value3 == NODE_TYPE_NODE))
{
switch ((xmlXPathAxisVal) op->value) {
case AXIS_CHILD:
case AXIS_DESCENDANT:
op->ch1 = prevop->ch1;
op->value = AXIS_DESCENDANT;
break;
case AXIS_SELF:
case AXIS_DESCENDANT_OR_SELF:
op->ch1 = prevop->ch1;
op->value = AXIS_DESCENDANT_OR_SELF;
break;
default:
break;
}
}
}
if (op->op == XPATH_OP_VALUE)
return;
ctxt = pctxt->context;
if (ctxt != NULL) {
if (ctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
return;
ctxt->depth += 1;
}
if (op->ch1 != -1)
xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch1]);
if (op->ch2 != -1)
xmlXPathOptimizeExpression(pctxt, &comp->steps[op->ch2]);
if (ctxt != NULL)
ctxt->depth -= 1;
}
xmlXPathCompExprPtr
xmlXPathCtxtCompile(xmlXPathContextPtr ctxt, const xmlChar *str) {
xmlXPathParserContextPtr pctxt;
xmlXPathCompExprPtr comp;
int oldDepth = 0;
#ifdef XPATH_STREAMING
comp = xmlXPathTryStreamCompile(ctxt, str);
if (comp != NULL)
return(comp);
#endif
xmlInitParser();
pctxt = xmlXPathNewParserContext(str, ctxt);
if (pctxt == NULL)
return NULL;
if (ctxt != NULL)
oldDepth = ctxt->depth;
xmlXPathCompileExpr(pctxt, 1);
if (ctxt != NULL)
ctxt->depth = oldDepth;
if( pctxt->error != XPATH_EXPRESSION_OK )
{
xmlXPathFreeParserContext(pctxt);
return(NULL);
}
if (*pctxt->cur != 0) {
xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
comp = NULL;
} else {
comp = pctxt->comp;
if ((comp->nbStep > 1) && (comp->last >= 0)) {
if (ctxt != NULL)
oldDepth = ctxt->depth;
xmlXPathOptimizeExpression(pctxt, &comp->steps[comp->last]);
if (ctxt != NULL)
ctxt->depth = oldDepth;
}
pctxt->comp = NULL;
}
xmlXPathFreeParserContext(pctxt);
if (comp != NULL) {
comp->expr = xmlStrdup(str);
}
return(comp);
}
xmlXPathCompExprPtr
xmlXPathCompile(const xmlChar *str) {
return(xmlXPathCtxtCompile(NULL, str));
}
static int
xmlXPathCompiledEvalInternal(xmlXPathCompExprPtr comp,
xmlXPathContextPtr ctxt,
xmlXPathObjectPtr *resObjPtr,
int toBool)
{
xmlXPathParserContextPtr pctxt;
xmlXPathObjectPtr resObj;
#ifndef LIBXML_THREAD_ENABLED
static int reentance = 0;
#endif
int res;
CHECK_CTXT_NEG(ctxt)
if (comp == NULL)
return(-1);
xmlInitParser();
#ifndef LIBXML_THREAD_ENABLED
reentance++;
if (reentance > 1)
xmlXPathDisableOptimizer = 1;
#endif
pctxt = xmlXPathCompParserContext(comp, ctxt);
if (pctxt == NULL)
return(-1);
res = xmlXPathRunEval(pctxt, toBool);
if (pctxt->error != XPATH_EXPRESSION_OK) {
resObj = NULL;
} else {
resObj = valuePop(pctxt);
if (resObj == NULL) {
if (!toBool)
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompiledEval: No result on the stack.\n");
} else if (pctxt->valueNr > 0) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompiledEval: %d object(s) left on the stack.\n",
pctxt->valueNr);
}
}
if (resObjPtr)
*resObjPtr = resObj;
else
xmlXPathReleaseObject(ctxt, resObj);
pctxt->comp = NULL;
xmlXPathFreeParserContext(pctxt);
#ifndef LIBXML_THREAD_ENABLED
reentance--;
#endif
return(res);
}
xmlXPathObjectPtr
xmlXPathCompiledEval(xmlXPathCompExprPtr comp, xmlXPathContextPtr ctx)
{
xmlXPathObjectPtr res = NULL;
xmlXPathCompiledEvalInternal(comp, ctx, &res, 0);
return(res);
}
int
xmlXPathCompiledEvalToBoolean(xmlXPathCompExprPtr comp,
xmlXPathContextPtr ctxt)
{
return(xmlXPathCompiledEvalInternal(comp, ctxt, NULL, 1));
}
void
xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
#ifdef XPATH_STREAMING
xmlXPathCompExprPtr comp;
#endif
int oldDepth = 0;
if (ctxt == NULL) return;
#ifdef XPATH_STREAMING
comp = xmlXPathTryStreamCompile(ctxt->context, ctxt->base);
if (comp != NULL) {
if (ctxt->comp != NULL)
xmlXPathFreeCompExpr(ctxt->comp);
ctxt->comp = comp;
} else
#endif
{
if (ctxt->context != NULL)
oldDepth = ctxt->context->depth;
xmlXPathCompileExpr(ctxt, 1);
if (ctxt->context != NULL)
ctxt->context->depth = oldDepth;
CHECK_ERROR;
if (*ctxt->cur != 0)
XP_ERROR(XPATH_EXPR_ERROR);
if ((ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) {
if (ctxt->context != NULL)
oldDepth = ctxt->context->depth;
xmlXPathOptimizeExpression(ctxt,
&ctxt->comp->steps[ctxt->comp->last]);
if (ctxt->context != NULL)
ctxt->context->depth = oldDepth;
}
}
xmlXPathRunEval(ctxt, 0);
}
xmlXPathObjectPtr
xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
xmlXPathParserContextPtr ctxt;
xmlXPathObjectPtr res;
CHECK_CTXT(ctx)
xmlInitParser();
ctxt = xmlXPathNewParserContext(str, ctx);
if (ctxt == NULL)
return NULL;
xmlXPathEvalExpr(ctxt);
if (ctxt->error != XPATH_EXPRESSION_OK) {
res = NULL;
} else {
res = valuePop(ctxt);
if (res == NULL) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompiledEval: No result on the stack.\n");
} else if (ctxt->valueNr > 0) {
xmlGenericError(xmlGenericErrorContext,
"xmlXPathCompiledEval: %d object(s) left on the stack.\n",
ctxt->valueNr);
}
}
xmlXPathFreeParserContext(ctxt);
return(res);
}
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);
}
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));
}
xmlXPathObjectPtr
xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
return(xmlXPathEval(str, ctxt));
}
static void
xmlXPathEscapeUriFunction(xmlXPathParserContextPtr ctxt, int nargs) {
xmlXPathObjectPtr str;
int escape_reserved;
xmlBufPtr target;
xmlChar *cptr;
xmlChar escape[4];
CHECK_ARITY(2);
escape_reserved = xmlXPathPopBoolean(ctxt);
CAST_TO_STRING;
str = valuePop(ctxt);
target = xmlBufCreate();
escape[0] = '%';
escape[3] = 0;
if (target) {
for (cptr = str->stringval; *cptr; cptr++) {
if ((*cptr >= 'A' && *cptr <= 'Z') ||
(*cptr >= 'a' && *cptr <= 'z') ||
(*cptr >= '0' && *cptr <= '9') ||
*cptr == '-' || *cptr == '_' || *cptr == '.' ||
*cptr == '!' || *cptr == '~' || *cptr == '*' ||
*cptr == '\''|| *cptr == '(' || *cptr == ')' ||
(*cptr == '%' &&
((cptr[1] >= 'A' && cptr[1] <= 'F') ||
(cptr[1] >= 'a' && cptr[1] <= 'f') ||
(cptr[1] >= '0' && cptr[1] <= '9')) &&
((cptr[2] >= 'A' && cptr[2] <= 'F') ||
(cptr[2] >= 'a' && cptr[2] <= 'f') ||
(cptr[2] >= '0' && cptr[2] <= '9'))) ||
(!escape_reserved &&
(*cptr == ';' || *cptr == '/' || *cptr == '?' ||
*cptr == ':' || *cptr == '@' || *cptr == '&' ||
*cptr == '=' || *cptr == '+' || *cptr == '$' ||
*cptr == ','))) {
xmlBufAdd(target, cptr, 1);
} else {
if ((*cptr >> 4) < 10)
escape[1] = '0' + (*cptr >> 4);
else
escape[1] = 'A' - 10 + (*cptr >> 4);
if ((*cptr & 0xF) < 10)
escape[2] = '0' + (*cptr & 0xF);
else
escape[2] = 'A' - 10 + (*cptr & 0xF);
xmlBufAdd(target, &escape[0], 3);
}
}
}
valuePush(ctxt, xmlXPathCacheNewString(ctxt->context,
xmlBufContent(target)));
xmlBufFree(target);
xmlXPathReleaseObject(ctxt->context, str);
}
void
xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
{
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
xmlXPathBooleanFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
xmlXPathCeilingFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
xmlXPathCountFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
xmlXPathConcatFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
xmlXPathContainsFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
xmlXPathIdFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
xmlXPathFalseFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
xmlXPathFloorFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
xmlXPathLastFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
xmlXPathLangFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
xmlXPathLocalNameFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
xmlXPathNotFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
xmlXPathNameFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
xmlXPathNamespaceURIFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
xmlXPathNormalizeFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
xmlXPathNumberFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
xmlXPathPositionFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
xmlXPathRoundFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
xmlXPathStringFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
xmlXPathStringLengthFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
xmlXPathStartsWithFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
xmlXPathSubstringFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
xmlXPathSubstringBeforeFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
xmlXPathSubstringAfterFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
xmlXPathSumFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
xmlXPathTrueFunction);
xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
xmlXPathTranslateFunction);
xmlXPathRegisterFuncNS(ctxt, (const xmlChar *)"escape-uri",
(const xmlChar *)"http://www.w3.org/2002/08/xquery-functions",
xmlXPathEscapeUriFunction);
}
#endif